Version 2.13.0-220.0.dev

Merge commit '579ae24fcd0af1162aebdb287bfd46b658f61890' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9dcfa0f..d9b7267 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 2.14.0
+
+### Core libraries
+
+#### `dart:core`
+
+*   The native `DateTime` class now better handles local time around
+    daylight saving changes that are not precisely one hour.
+    (No change on the Web which uses the JavaScript `Date` object.)
+
 ## 2.13.0
 
 ### Language
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index bf501a0..a8af89d 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -379,6 +379,8 @@
   /// Return `true` if the current state is reachable.
   bool get isReachable;
 
+  TypeOperations<Variable, Type> get typeOperations;
+
   /// Call this method after visiting an "as" expression.
   ///
   /// [subExpression] should be the expression to which the "as" check was
@@ -1005,6 +1007,9 @@
       _wrap('isReachable', () => _wrapped.isReachable, isQuery: true);
 
   @override
+  TypeOperations<Variable, Type> get typeOperations => _wrapped.typeOperations;
+
+  @override
   void asExpression_end(Expression subExpression, Type type) {
     _wrap('asExpression_end($subExpression, $type)',
         () => _wrapped.asExpression_end(subExpression, type));
@@ -3407,6 +3412,7 @@
         Expression extends Object, Variable extends Object, Type extends Object>
     implements FlowAnalysis<Node, Statement, Expression, Variable, Type> {
   /// The [TypeOperations], used to access types, and check subtyping.
+  @override
   final TypeOperations<Variable, Type> typeOperations;
 
   /// Stack of [_FlowContext] objects representing the statements and
@@ -4403,6 +4409,9 @@
   bool get isReachable => true;
 
   @override
+  TypeOperations<Variable, Type> get typeOperations => _typeOperations;
+
+  @override
   void asExpression_end(Expression subExpression, Type type) {}
 
   @override
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index fd0db4b..a43f4ac 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -163,7 +163,7 @@
 /// Representation of an expression in the pseudo-Dart language used for flow
 /// analysis testing.  Methods in this class may be used to create more complex
 /// expressions based on this one.
-abstract class Expression extends Node implements _Visitable<Type> {
+abstract class Expression extends Node {
   Expression() : super._();
 
   /// If `this` is an expression `x`, creates the expression `x!`.
@@ -244,6 +244,10 @@
   Expression whyNotPromoted(
           void Function(Map<Type, NonPromotionReason>) callback) =>
       new _WhyNotPromoted(this, callback);
+
+  void _preVisit(AssignedVariables<Node, Var> assignedVariables);
+
+  Type _visit(Harness h);
 }
 
 /// Test harness for creating flow analysis tests.  This class implements all
@@ -367,6 +371,8 @@
     'num* - Object': Type('Never'),
   };
 
+  late final FlowAnalysis<Node, Statement, Expression, Var, Type> _flow;
+
   final bool legacy;
 
   final Type? thisType;
@@ -471,13 +477,13 @@
     var assignedVariables = AssignedVariables<Node, Var>();
     var b = block(statements);
     b._preVisit(assignedVariables);
-    var flow = legacy
+    _flow = legacy
         ? FlowAnalysis<Node, Statement, Expression, Var, Type>.legacy(
             this, assignedVariables)
         : FlowAnalysis<Node, Statement, Expression, Var, Type>(
             this, assignedVariables);
-    b._visit(this, flow);
-    flow.finish();
+    b._visit(this);
+    _flow.finish();
   }
 
   @override
@@ -532,13 +538,12 @@
     }
   }
 
-  void _visitLoopBody(Statement loop, Statement body,
-      FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+  void _visitLoopBody(Statement loop, Statement body) {
     var previousBreakTarget = _currentBreakTarget;
     var previousContinueTarget = _currentContinueTarget;
     _currentBreakTarget = loop;
     _currentContinueTarget = loop;
-    body._visit(this, flow);
+    body._visit(this);
     _currentBreakTarget = previousBreakTarget;
     _currentContinueTarget = previousContinueTarget;
   }
@@ -558,11 +563,10 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.labeledStatement_begin(this);
-    _body._visit(h, flow);
-    flow.labeledStatement_end();
+  void _visit(Harness h) {
+    h._flow.labeledStatement_begin(this);
+    _body._visit(h);
+    h._flow.labeledStatement_end();
   }
 }
 
@@ -579,8 +583,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables,
       {_LValueDisposition disposition});
 
-  void _visitWrite(FlowAnalysis<Node, Statement, Expression, Var, Type> flow,
-      Expression assignmentExpression, Type writtenType, Expression? rhs);
+  void _visitWrite(Harness h, Expression assignmentExpression, Type writtenType,
+      Expression? rhs);
 }
 
 /// Representation of an expression or statement in the pseudo-Dart language
@@ -609,7 +613,7 @@
 
 /// Representation of a statement in the pseudo-Dart language used for flow
 /// analysis testing.
-abstract class Statement extends Node implements _Visitable<void> {
+abstract class Statement extends Node {
   Statement._() : super._();
 
   /// If `this` is a statement `x`, creates a pseudo-expression that models
@@ -617,11 +621,15 @@
   /// test that flow analysis is in the correct state before an expression is
   /// visited.
   Expression thenExpr(Expression expr) => _WrappedExpression(this, expr, null);
+
+  void _preVisit(AssignedVariables<Node, Var> assignedVariables);
+
+  void _visit(Harness h);
 }
 
 /// Representation of a single case clause in a switch statement.  Use [case_]
 /// to create instances of this class.
-class SwitchCase implements _Visitable<void> {
+class SwitchCase {
   final bool _hasLabel;
   final _Block _body;
 
@@ -637,10 +645,9 @@
     _body._preVisit(assignedVariables);
   }
 
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.switchStatement_beginCase(_hasLabel, h._currentSwitch!);
-    _body._visit(h, flow);
+  void _visit(Harness h) {
+    h._flow.switchStatement_beginCase(_hasLabel, h._currentSwitch!);
+    _body._visit(h);
   }
 }
 
@@ -693,10 +700,9 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    target._visit(h, flow);
-    flow.asExpression_end(target, type);
+  Type _visit(Harness h) {
+    target._visit(h);
+    h._flow.asExpression_end(target, type);
     return type;
   }
 }
@@ -718,12 +724,11 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.assert_begin();
-    flow.assert_afterCondition(condition.._visit(h, flow));
-    message?._visit(h, flow);
-    flow.assert_end();
+  void _visit(Harness h) {
+    h._flow.assert_begin();
+    h._flow.assert_afterCondition(condition.._visit(h));
+    message?._visit(h);
+    h._flow.assert_end();
   }
 }
 
@@ -744,10 +749,9 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+  void _visit(Harness h) {
     for (var statement in statements) {
-      statement._visit(h, flow);
+      statement._visit(h);
     }
   }
 }
@@ -764,9 +768,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.booleanLiteral(this, value);
+  Type _visit(Harness h) {
+    h._flow.booleanLiteral(this, value);
     return Type('bool');
   }
 }
@@ -783,15 +786,14 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.handleBreak(target ?? h._currentBreakTarget!);
+  void _visit(Harness h) {
+    h._flow.handleBreak(target ?? h._currentBreakTarget!);
   }
 }
 
 /// Representation of a single catch clause in a try/catch statement.  Use
 /// [catch_] to create instances of this class.
-class _CatchClause implements _Visitable<void> {
+class _CatchClause {
   final Statement _body;
   final Var? _exception;
   final Var? _stackTrace;
@@ -814,11 +816,10 @@
     _body._preVisit(assignedVariables);
   }
 
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.tryCatchStatement_catchBegin(_exception, _stackTrace);
-    _body._visit(h, flow);
-    flow.tryCatchStatement_catchEnd();
+  void _visit(Harness h) {
+    h._flow.tryCatchStatement_catchBegin(_exception, _stackTrace);
+    _body._visit(h);
+    h._flow.tryCatchStatement_catchEnd();
   }
 }
 
@@ -838,9 +839,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    expect(flow.isAssigned(variable), expectedAssignedState);
+  void _visit(Harness h) {
+    expect(h._flow.isAssigned(variable), expectedAssignedState);
   }
 }
 
@@ -863,9 +863,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var promotedType = flow.promotedType(variable);
+  void _visit(Harness h) {
+    var promotedType = h._flow.promotedType(variable);
     expect(promotedType?.type, expectedTypeStr, reason: '$_creationTrace');
   }
 }
@@ -882,9 +881,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    expect(flow.isReachable, expectedReachable);
+  void _visit(Harness h) {
+    expect(h._flow.isReachable, expectedReachable);
   }
 }
 
@@ -904,9 +902,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    expect(flow.isUnassigned(variable), expectedUnassignedState);
+  void _visit(Harness h) {
+    expect(h._flow.isUnassigned(variable), expectedUnassignedState);
   }
 }
 
@@ -930,14 +927,13 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.conditional_conditionBegin();
-    flow.conditional_thenBegin(condition.._visit(h, flow), this);
-    var ifTrueType = ifTrue._visit(h, flow);
-    flow.conditional_elseBegin(ifTrue);
-    var ifFalseType = ifFalse._visit(h, flow);
-    flow.conditional_end(this, ifFalse);
+  Type _visit(Harness h) {
+    h._flow.conditional_conditionBegin();
+    h._flow.conditional_thenBegin(condition.._visit(h), this);
+    var ifTrueType = ifTrue._visit(h);
+    h._flow.conditional_elseBegin(ifTrue);
+    var ifFalseType = ifFalse._visit(h);
+    h._flow.conditional_end(this, ifFalse);
     return h._lub(ifTrueType, ifFalseType);
   }
 }
@@ -952,9 +948,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.handleContinue(h._currentContinueTarget!);
+  void _visit(Harness h) {
+    h._flow.handleContinue(h._currentContinueTarget!);
   }
 }
 
@@ -981,15 +976,14 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+  void _visit(Harness h) {
     var initializer = this.initializer;
     if (initializer == null) {
-      flow.declare(variable, false);
+      h._flow.declare(variable, false);
     } else {
-      var initializerType = initializer._visit(h, flow);
-      flow.declare(variable, true);
-      flow.initialize(variable, initializerType, initializer,
+      var initializerType = initializer._visit(h);
+      h._flow.declare(variable, true);
+      h._flow.initialize(variable, initializerType, initializer,
           isFinal: isFinal, isLate: isLate);
     }
   }
@@ -1013,13 +1007,12 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.doStatement_bodyBegin(this);
-    h._visitLoopBody(this, body, flow);
-    flow.doStatement_conditionBegin();
-    condition._visit(h, flow);
-    flow.doStatement_end(condition);
+  void _visit(Harness h) {
+    h._flow.doStatement_bodyBegin(this);
+    h._visitLoopBody(this, body);
+    h._flow.doStatement_conditionBegin();
+    condition._visit(h);
+    h._flow.doStatement_end(condition);
   }
 }
 
@@ -1040,12 +1033,11 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var lhsType = lhs._visit(h, flow);
-    flow.equalityOp_rightBegin(lhs, lhsType);
-    var rhsType = rhs._visit(h, flow);
-    flow.equalityOp_end(this, rhs, rhsType, notEqual: isInverted);
+  Type _visit(Harness h) {
+    var lhsType = lhs._visit(h);
+    h._flow.equalityOp_rightBegin(lhs, lhsType);
+    var rhsType = rhs._visit(h);
+    h._flow.equalityOp_end(this, rhs, rhsType, notEqual: isInverted);
     return Type('bool');
   }
 }
@@ -1064,9 +1056,8 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    expr._visit(h, flow);
+  void _visit(Harness h) {
+    expr._visit(h);
   }
 }
 
@@ -1112,16 +1103,15 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    initializer?._visit(h, flow);
-    flow.for_conditionBegin(this);
-    condition?._visit(h, flow);
-    flow.for_bodyBegin(forCollection ? null : this, condition);
-    h._visitLoopBody(this, body, flow);
-    flow.for_updaterBegin();
-    updater?._visit(h, flow);
-    flow.for_end();
+  void _visit(Harness h) {
+    initializer?._visit(h);
+    h._flow.for_conditionBegin(this);
+    condition?._visit(h);
+    h._flow.for_bodyBegin(forCollection ? null : this, condition);
+    h._visitLoopBody(this, body);
+    h._flow.for_updaterBegin();
+    updater?._visit(h);
+    h._flow.for_end();
   }
 }
 
@@ -1163,16 +1153,15 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var iteratedType = h._getIteratedType(iterable._visit(h, flow));
-    flow.forEach_bodyBegin(this);
+  void _visit(Harness h) {
+    var iteratedType = h._getIteratedType(iterable._visit(h));
+    h._flow.forEach_bodyBegin(this);
     var variable = this.variable;
     if (variable != null && !declaresVariable) {
-      flow.write(this, variable, iteratedType, null);
+      h._flow.write(this, variable, iteratedType, null);
     }
-    h._visitLoopBody(this, body, flow);
-    flow.forEach_end();
+    h._visitLoopBody(this, body);
+    h._flow.forEach_end();
   }
 }
 
@@ -1189,11 +1178,10 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var type = target._visit(h, flow);
-    flow.forwardExpression(this, target);
-    callback(flow.expressionInfoForTesting(this));
+  Type _visit(Harness h) {
+    var type = target._visit(h);
+    h._flow.forwardExpression(this, target);
+    callback(h._flow.expressionInfoForTesting(this));
     return type;
   }
 }
@@ -1207,9 +1195,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    callback(SsaNodeHarness(flow));
+  void _visit(Harness h) {
+    callback(SsaNodeHarness(h._flow));
   }
 }
 
@@ -1234,17 +1221,16 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.ifStatement_conditionBegin();
-    flow.ifStatement_thenBegin(condition.._visit(h, flow), this);
-    ifTrue._visit(h, flow);
+  void _visit(Harness h) {
+    h._flow.ifStatement_conditionBegin();
+    h._flow.ifStatement_thenBegin(condition.._visit(h), this);
+    ifTrue._visit(h);
     if (ifFalse == null) {
-      flow.ifStatement_end(false);
+      h._flow.ifStatement_end(false);
     } else {
-      flow.ifStatement_elseBegin();
-      ifFalse!._visit(h, flow);
-      flow.ifStatement_end(true);
+      h._flow.ifStatement_elseBegin();
+      ifFalse!._visit(h);
+      h._flow.ifStatement_end(true);
     }
   }
 }
@@ -1265,12 +1251,11 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var lhsType = lhs._visit(h, flow);
-    flow.ifNullExpression_rightBegin(lhs, lhsType);
-    var rhsType = rhs._visit(h, flow);
-    flow.ifNullExpression_end();
+  Type _visit(Harness h) {
+    var lhsType = lhs._visit(h);
+    h._flow.ifNullExpression_rightBegin(lhs, lhsType);
+    var rhsType = rhs._visit(h);
+    h._flow.ifNullExpression_end();
     return h._lub(h.promoteToNonNull(lhsType), rhsType);
   }
 }
@@ -1291,9 +1276,8 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.isExpression_end(this, target.._visit(h, flow), isInverted, type);
+  Type _visit(Harness h) {
+    h._flow.isExpression_end(this, target.._visit(h), isInverted, type);
     return Type('bool');
   }
 }
@@ -1314,11 +1298,10 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.functionExpression_begin(this);
-    body._visit(h, flow);
-    flow.functionExpression_end();
+  void _visit(Harness h) {
+    h._flow.functionExpression_begin(this);
+    body._visit(h);
+    h._flow.functionExpression_end();
   }
 }
 
@@ -1341,11 +1324,10 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.logicalBinaryOp_begin();
-    flow.logicalBinaryOp_rightBegin(lhs.._visit(h, flow), this, isAnd: isAnd);
-    flow.logicalBinaryOp_end(this, rhs.._visit(h, flow), isAnd: isAnd);
+  Type _visit(Harness h) {
+    h._flow.logicalBinaryOp_begin();
+    h._flow.logicalBinaryOp_rightBegin(lhs.._visit(h), this, isAnd: isAnd);
+    h._flow.logicalBinaryOp_end(this, rhs.._visit(h), isAnd: isAnd);
     return Type('bool');
   }
 }
@@ -1380,10 +1362,9 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var type = operand._visit(h, flow);
-    flow.nonNullAssert_end(operand);
+  Type _visit(Harness h) {
+    var type = operand._visit(h);
+    h._flow.nonNullAssert_end(operand);
     return h.promoteToNonNull(type);
   }
 }
@@ -1402,9 +1383,8 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.logicalNot_end(this, operand.._visit(h, flow));
+  Type _visit(Harness h) {
+    h._flow.logicalNot_end(this, operand.._visit(h));
     return Type('bool');
   }
 }
@@ -1426,12 +1406,11 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var lhsType = lhs._visit(h, flow);
-    flow.nullAwareAccess_rightBegin(isCascaded ? null : lhs, lhsType);
-    var rhsType = rhs._visit(h, flow);
-    flow.nullAwareAccess_end();
+  Type _visit(Harness h) {
+    var lhsType = lhs._visit(h);
+    h._flow.nullAwareAccess_rightBegin(isCascaded ? null : lhs, lhsType);
+    var rhsType = rhs._visit(h);
+    h._flow.nullAwareAccess_end();
     return h._lub(rhsType, Type('Null'));
   }
 }
@@ -1446,9 +1425,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.nullLiteral(this);
+  Type _visit(Harness h) {
+    h._flow.nullLiteral(this);
     return Type('Null');
   }
 }
@@ -1467,10 +1445,9 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var type = expr._visit(h, flow);
-    flow.parenthesizedExpression(this, expr);
+  Type _visit(Harness h) {
+    var type = expr._visit(h);
+    h._flow.parenthesizedExpression(this, expr);
     return type;
   }
 }
@@ -1487,9 +1464,7 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  Type _visit(Harness h,
-          FlowAnalysis<Node, Statement, Expression, Var, Type> flow) =>
-      type;
+  Type _visit(Harness h) => type;
 }
 
 class _Property extends LValue {
@@ -1506,17 +1481,16 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var targetType = target._visit(h, flow);
+  Type _visit(Harness h) {
+    var targetType = target._visit(h);
     var propertyType = h.getMember(targetType, propertyName);
-    flow.propertyGet(this, target, propertyName, propertyName, propertyType);
+    h._flow.propertyGet(this, target, propertyName, propertyName, propertyType);
     return propertyType;
   }
 
   @override
-  void _visitWrite(FlowAnalysis<Node, Statement, Expression, Var, Type> flow,
-      Expression assignmentExpression, Type writtenType, Expression? rhs) {
+  void _visitWrite(Harness h, Expression assignmentExpression, Type writtenType,
+      Expression? rhs) {
     // No flow analysis impact
   }
 }
@@ -1531,9 +1505,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.handleExit();
+  void _visit(Harness h) {
+    h._flow.handleExit();
   }
 }
 
@@ -1568,20 +1541,19 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    expression._visit(h, flow);
-    flow.switchStatement_expressionEnd(this);
+  void _visit(Harness h) {
+    expression._visit(h);
+    h._flow.switchStatement_expressionEnd(this);
     var oldSwitch = h._currentSwitch;
     var previousBreakTarget = h._currentBreakTarget;
     h._currentSwitch = this;
     h._currentBreakTarget = this;
     for (var case_ in cases) {
-      case_._visit(h, flow);
+      case_._visit(h);
     }
     h._currentSwitch = oldSwitch;
     h._currentBreakTarget = previousBreakTarget;
-    flow.switchStatement_end(isExhaustive);
+    h._flow.switchStatement_end(isExhaustive);
   }
 }
 
@@ -1593,10 +1565,9 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+  Type _visit(Harness h) {
     var thisType = h.thisType!;
-    flow.thisOrSuper(this, thisType);
+    h._flow.thisOrSuper(this, thisType);
     return thisType;
   }
 }
@@ -1612,9 +1583,8 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.thisOrSuperPropertyGet(this, propertyName, propertyName, type);
+  Type _visit(Harness h) {
+    h._flow.thisOrSuperPropertyGet(this, propertyName, propertyName, type);
     return type;
   }
 }
@@ -1633,10 +1603,9 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    operand._visit(h, flow);
-    flow.handleExit();
+  Type _visit(Harness h) {
+    operand._visit(h);
+    h._flow.handleExit();
     return Type('Never');
   }
 }
@@ -1685,27 +1654,26 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+  void _visit(Harness h) {
     if (_finally != null) {
-      flow.tryFinallyStatement_bodyBegin();
+      h._flow.tryFinallyStatement_bodyBegin();
     }
     if (_catches.isNotEmpty) {
-      flow.tryCatchStatement_bodyBegin();
+      h._flow.tryCatchStatement_bodyBegin();
     }
-    _body._visit(h, flow);
+    _body._visit(h);
     if (_catches.isNotEmpty) {
-      flow.tryCatchStatement_bodyEnd(_bodyNode);
+      h._flow.tryCatchStatement_bodyEnd(_bodyNode);
       for (var catch_ in _catches) {
-        catch_._visit(h, flow);
+        catch_._visit(h);
       }
-      flow.tryCatchStatement_end();
+      h._flow.tryCatchStatement_end();
     }
     if (_finally != null) {
-      flow.tryFinallyStatement_finallyBegin(
+      h._flow.tryFinallyStatement_finallyBegin(
           _catches.isNotEmpty ? this : _bodyNode);
-      _finally!._visit(h, flow);
-      flow.tryFinallyStatement_end();
+      _finally!._visit(h);
+      h._flow.tryFinallyStatement_end();
     }
   }
 }
@@ -1732,27 +1700,19 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var readResult = flow.variableRead(this, variable);
+  Type _visit(Harness h) {
+    var readResult = h._flow.variableRead(this, variable);
     callback?.call(readResult);
     return readResult ?? variable.type;
   }
 
   @override
-  void _visitWrite(FlowAnalysis<Node, Statement, Expression, Var, Type> flow,
-      Expression assignmentExpression, Type writtenType, Expression? rhs) {
-    flow.write(assignmentExpression, variable, writtenType, rhs);
+  void _visitWrite(Harness h, Expression assignmentExpression, Type writtenType,
+      Expression? rhs) {
+    h._flow.write(assignmentExpression, variable, writtenType, rhs);
   }
 }
 
-abstract class _Visitable<T> {
-  void _preVisit(AssignedVariables<Node, Var> assignedVariables);
-
-  T _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow);
-}
-
 class _While extends Statement {
   final Expression condition;
   final Statement body;
@@ -1771,13 +1731,12 @@
   }
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    flow.whileStatement_conditionBegin(this);
-    condition._visit(h, flow);
-    flow.whileStatement_bodyBegin(this, condition);
-    h._visitLoopBody(this, body, flow);
-    flow.whileStatement_end();
+  void _visit(Harness h) {
+    h._flow.whileStatement_conditionBegin(this);
+    condition._visit(h);
+    h._flow.whileStatement_bodyBegin(this, condition);
+    h._visitLoopBody(this, body);
+    h._flow.whileStatement_end();
   }
 }
 
@@ -1797,12 +1756,11 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    var type = target._visit(h, flow);
-    flow.forwardExpression(this, target);
+  Type _visit(Harness h) {
+    var type = target._visit(h);
+    h._flow.forwardExpression(this, target);
     Type.withComparisonsAllowed(() {
-      callback(flow.whyNotPromoted(this)());
+      callback(h._flow.whyNotPromoted(this)());
     });
     return type;
   }
@@ -1822,10 +1780,9 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {}
 
   @override
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+  void _visit(Harness h) {
     Type.withComparisonsAllowed(() {
-      callback(flow.whyNotPromotedImplicitThis(staticType)());
+      callback(h._flow.whyNotPromotedImplicitThis(staticType)());
     });
   }
 }
@@ -1859,12 +1816,11 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    before?._visit(h, flow);
-    var type = expr._visit(h, flow);
-    after?._visit(h, flow);
-    flow.forwardExpression(this, expr);
+  Type _visit(Harness h) {
+    before?._visit(h);
+    var type = expr._visit(h);
+    after?._visit(h);
+    h._flow.forwardExpression(this, expr);
     return type;
   }
 }
@@ -1888,18 +1844,17 @@
   }
 
   @override
-  Type _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+  Type _visit(Harness h) {
     var rhs = this.rhs;
     Type type;
     if (rhs == null) {
       // We are simulating an increment/decrement operation.
       // TODO(paulberry): Make a separate node type for this.
-      type = lhs._visit(h, flow);
+      type = lhs._visit(h);
     } else {
-      type = rhs._visit(h, flow);
+      type = rhs._visit(h);
     }
-    lhs._visitWrite(flow, this, type, rhs);
+    lhs._visitWrite(h, this, type, rhs);
     return type;
   }
 }
diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
index f8bdd41..25d3548 100644
--- a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
@@ -6,7 +6,7 @@
 /// entities.
 import 'package:analysis_server/src/protocol_server.dart';
 import 'package:analyzer/dart/element/element.dart' as engine;
-import 'package:path/path.dart' as pathos;
+import 'package:path/path.dart' as path;
 
 /// Return a protocol [Element] corresponding to the given [engine.Element].
 Element convertElement(engine.Element element) {
@@ -122,7 +122,7 @@
 
 String getElementDisplayName(engine.Element element) {
   if (element is engine.CompilationUnitElement) {
-    return pathos.basename(element.source.fullName);
+    return path.basename(element.source.fullName);
   } else {
     return element.displayName;
   }
diff --git a/pkg/analysis_server/lib/src/computer/computer_folding.dart b/pkg/analysis_server/lib/src/computer/computer_folding.dart
index a279dfb..ccfb4e3 100644
--- a/pkg/analysis_server/lib/src/computer/computer_folding.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_folding.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
@@ -15,7 +13,7 @@
   final LineInfo _lineInfo;
   final CompilationUnit _unit;
 
-  Directive _firstDirective, _lastDirective;
+  Directive? _firstDirective, _lastDirective;
   final List<FoldingRegion> _foldingRegions = [];
 
   DartUnitFoldingComputer(this._lineInfo, this._unit);
@@ -33,14 +31,17 @@
     //     if (cond) { [...] } else { [...] }
     //
     // So these types of blocks should have their folding regions end at the
-    // end of the preceeding statement.
+    // end of the preceding statement.
 
     final start = block.leftBracket.end;
-    if (block.endToken.precedingComments != null) {
+    Token? comment = block.endToken.precedingComments;
+    if (comment != null) {
+      var lastComment = comment;
       // If there are comments before the end token, use the last of those.
-      var lastComment = block.endToken.precedingComments;
-      while (lastComment.next != null) {
-        lastComment = lastComment.next;
+      var nextComment = lastComment.next;
+      while (nextComment != null) {
+        lastComment = nextComment;
+        nextComment = nextComment.next;
       }
       _addRegion(start, lastComment.end, FoldingKind.BLOCK);
     } else if (block.statements.isNotEmpty) {
@@ -53,13 +54,15 @@
   List<FoldingRegion> compute() {
     _unit.accept(_DartUnitFoldingComputerVisitor(this));
 
-    if (_firstDirective != null &&
-        _lastDirective != null &&
-        _firstDirective != _lastDirective) {
+    var firstDirective = _firstDirective;
+    var lastDirective = _lastDirective;
+    if (firstDirective != null &&
+        lastDirective != null &&
+        firstDirective != lastDirective) {
       _foldingRegions.add(FoldingRegion(
           FoldingKind.DIRECTIVES,
-          _firstDirective.keyword.end,
-          _lastDirective.end - _firstDirective.keyword.end));
+          firstDirective.keyword.end,
+          lastDirective.end - firstDirective.keyword.end));
     }
 
     _addCommentRegions();
@@ -67,18 +70,19 @@
     return _foldingRegions;
   }
 
-  /// Create a folding region for the provided comment, reading forwards if neccesary.
+  /// Create a folding region for the provided comment, reading forwards if
+  /// necessary.
   ///
   /// If [mayBeFileHeader] is true, the token will be considered a file header
   /// if comment is a single-line-comment and there is a blank line or another
   /// comment type after it.
   ///
-  /// Returns the next comment to be processed or null if there are no more comments
-  /// to process in the chain.
-  Token _addCommentRegion(Token commentToken, {bool mayBeFileHeader = false}) {
+  /// Returns the next comment to be processed or null if there are no more
+  /// comments to process in the chain.
+  Token? _addCommentRegion(Token commentToken, {bool mayBeFileHeader = false}) {
     int offset, end;
     var isFileHeader = false;
-    Token nextComment;
+    Token? nextComment;
 
     if (commentToken.type == TokenType.MULTI_LINE_COMMENT) {
       // Multiline comments already span all of their lines but the folding
@@ -128,13 +132,13 @@
   }
 
   void _addCommentRegions() {
-    var token = _unit.beginToken;
+    Token? token = _unit.beginToken;
     if (token.type == TokenType.SCRIPT_TAG) {
       token = token.next;
     }
     var isFirstToken = true;
     while (token != null) {
-      Token commentToken = token.precedingComments;
+      Token? commentToken = token.precedingComments;
       while (commentToken != null) {
         commentToken =
             _addCommentRegion(commentToken, mayBeFileHeader: isFirstToken);
@@ -150,8 +154,8 @@
   }
 
   void _addRegion(int startOffset, int endOffset, FoldingKind kind) {
-    final CharacterLocation start = _lineInfo.getLocation(startOffset);
-    final CharacterLocation end = _lineInfo.getLocation(endOffset);
+    var start = _lineInfo.getLocation(startOffset);
+    var end = _lineInfo.getLocation(endOffset);
 
     if (start.lineNumber != end.lineNumber) {
       _foldingRegions
@@ -167,8 +171,8 @@
   }
 
   bool _hasBlankLineBetween(int offset, int end) {
-    final CharacterLocation firstLoc = _lineInfo.getLocation(offset);
-    final CharacterLocation secondLoc = _lineInfo.getLocation(end);
+    var firstLoc = _lineInfo.getLocation(offset);
+    var secondLoc = _lineInfo.getLocation(end);
     return secondLoc.lineNumber - firstLoc.lineNumber > 1;
   }
 
@@ -221,8 +225,9 @@
 
   @override
   void visitDoStatement(DoStatement node) {
-    if (node.body is Block) {
-      _computer.addRegionForConditionalBlock(node.body);
+    var body = node.body;
+    if (body is Block) {
+      _computer.addRegionForConditionalBlock(body);
     }
     super.visitDoStatement(node);
   }
@@ -262,11 +267,13 @@
 
   @override
   void visitIfStatement(IfStatement node) {
-    if (node.thenStatement is Block) {
-      _computer.addRegionForConditionalBlock(node.thenStatement);
+    var thenStatement = node.thenStatement;
+    if (thenStatement is Block) {
+      _computer.addRegionForConditionalBlock(thenStatement);
     }
-    if (node.elseStatement is Block) {
-      _computer.addRegionForConditionalBlock(node.elseStatement);
+    var elseStatement = node.elseStatement;
+    if (elseStatement is Block) {
+      _computer.addRegionForConditionalBlock(elseStatement);
     }
     super.visitIfStatement(node);
   }
@@ -340,8 +347,9 @@
 
   @override
   void visitWhileStatement(WhileStatement node) {
-    if (node.body is Block) {
-      _computer.addRegionForConditionalBlock(node.body);
+    var body = node.body;
+    if (body is Block) {
+      _computer.addRegionForConditionalBlock(body);
     }
     super.visitWhileStatement(node);
   }
@@ -350,13 +358,13 @@
 extension _CommentTokenExtensions on Token {
   static final _newlinePattern = RegExp(r'[\r\n]');
 
-  /// The offset of the first eol character or null
-  /// if no newlines were found.
-  int get eolOffset {
+  /// Return the offset of the first eol character or `null` if no newlines were
+  /// found.
+  int? get eolOffset {
     final offset = lexeme.indexOf(_newlinePattern);
     return offset != -1 ? offset : null;
   }
 
-  /// Whether this comment is a triple-slash single line comment.
+  /// Return `true` if this comment is a triple-slash single line comment.
   bool get isTripleSlash => lexeme.startsWith('///');
 }
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index 53ff8df..ab3ef83 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/protocol/protocol_generated.dart'
     show HoverInformation;
 import 'package:analysis_server/src/computer/computer_overrides.dart';
@@ -25,23 +23,24 @@
   DartUnitHoverComputer(this._dartdocInfo, this._unit, this._offset);
 
   bool get _isNonNullableByDefault {
-    return _unit.declaredElement.library.isNonNullableByDefault;
+    return _unit.declaredElement?.library.isNonNullableByDefault ?? false;
   }
 
   /// Returns the computed hover, maybe `null`.
-  HoverInformation compute() {
+  HoverInformation? compute() {
     var node = NodeLocator(_offset).searchWithin(_unit);
     if (node == null) {
       return null;
     }
-    if (node.parent is TypeName &&
-        node.parent.parent is ConstructorName &&
-        node.parent.parent.parent is InstanceCreationExpression) {
-      node = node.parent.parent.parent;
-    }
-    if (node.parent is ConstructorName &&
-        node.parent.parent is InstanceCreationExpression) {
-      node = node.parent.parent;
+    var parent = node.parent;
+    var grandParent = parent?.parent;
+    if (parent is TypeName &&
+        grandParent is ConstructorName &&
+        grandParent.parent is InstanceCreationExpression) {
+      node = grandParent.parent;
+    } else if (parent is ConstructorName &&
+        grandParent is InstanceCreationExpression) {
+      node = grandParent;
     }
     if (node is Expression) {
       var expression = node;
@@ -59,16 +58,18 @@
       if (element != null) {
         // variable, if synthetic accessor
         if (element is PropertyAccessorElement) {
-          PropertyAccessorElement accessor = element;
-          if (accessor.isSynthetic) {
-            element = accessor.variable;
+          if (element.isSynthetic) {
+            element = element.variable;
           }
         }
         // description
-        hover.elementDescription = _elementDisplayString(element);
-        if (node is InstanceCreationExpression && node.keyword == null) {
+        var description = _elementDisplayString(element);
+        hover.elementDescription = description;
+        if (description != null &&
+            node is InstanceCreationExpression &&
+            node.keyword == null) {
           var prefix = node.isConst ? '(const) ' : '(new) ';
-          hover.elementDescription = prefix + hover.elementDescription;
+          hover.elementDescription = prefix + description;
         }
         hover.elementKind = element.kind.displayName;
         hover.isDeprecated = element.hasDeprecated;
@@ -83,9 +84,9 @@
           var library = element.library;
           if (library != null) {
             var uri = library.source.uri;
-            if (uri.scheme != '' && uri.scheme == 'file') {
+            var analysisSession = _unit.declaredElement?.session;
+            if (uri.scheme == 'file' && analysisSession != null) {
               // for 'file:' URIs, use the path after the project root
-              var analysisSession = _unit.declaredElement.session;
               var context = analysisSession.resourceProvider.pathContext;
               var projectRootDir =
                   analysisSession.analysisContext.contextRoot.root.path;
@@ -113,7 +114,7 @@
       // types
       {
         var parent = expression.parent;
-        DartType staticType;
+        DartType? staticType;
         if (element == null || element is VariableElement) {
           staticType = _getTypeOfDeclarationOrReference(node);
         }
@@ -132,22 +133,23 @@
     return null;
   }
 
-  String _elementDisplayString(Element element) {
+  String? _elementDisplayString(Element? element) {
     return element?.getDisplayString(
       withNullability: _isNonNullableByDefault,
     );
   }
 
-  String _typeDisplayString(DartType type) {
+  String? _typeDisplayString(DartType? type) {
     return type?.getDisplayString(withNullability: _isNonNullableByDefault);
   }
 
-  static String computeDocumentation(
-      DartdocDirectiveInfo dartdocInfo, Element element) {
+  static String? computeDocumentation(
+      DartdocDirectiveInfo dartdocInfo, Element elementBeingDocumented) {
     // TODO(dantup) We're reusing this in parameter information - move it
     // somewhere shared?
+    Element? element = elementBeingDocumented;
     if (element is FieldFormalParameterElement) {
-      element = (element as FieldFormalParameterElement).field;
+      element = element.field;
     }
     if (element is ParameterElement) {
       element = element.enclosingElement;
@@ -158,8 +160,8 @@
       return null;
     }
 
-    Element documentedElement;
-    Element documentedGetter;
+    Element? documentedElement;
+    Element? documentedGetter;
 
     // Look for documentation comments of overridden members
     var overridden = findOverriddenElements(element);
@@ -189,24 +191,28 @@
     }
 
     var rawDoc = documentedElement.documentationComment;
+    if (rawDoc == null) {
+      return null;
+    }
     var result = dartdocInfo.processDartdoc(rawDoc);
 
     var documentedElementClass = documentedElement.enclosingElement;
-    if (documentedElementClass != element.enclosingElement) {
+    if (documentedElementClass != null &&
+        documentedElementClass != element.enclosingElement) {
       result += '\n\nCopied from `${documentedElementClass.displayName}`.';
     }
 
     return result;
   }
 
-  static DartType _getTypeOfDeclarationOrReference(Expression node) {
+  static DartType? _getTypeOfDeclarationOrReference(Expression node) {
     if (node is SimpleIdentifier) {
       var element = node.staticElement;
       if (element is VariableElement) {
         if (node.inDeclarationContext()) {
           return element.type;
         }
-        var parent2 = node.parent.parent;
+        var parent2 = node.parent?.parent;
         if (parent2 is NamedExpression && parent2.name.label == node) {
           return element.type;
         }
diff --git a/pkg/analysis_server/lib/src/computer/computer_overrides.dart b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
index 505abac..b3e7bc3 100644
--- a/pkg/analysis_server/lib/src/computer/computer_overrides.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/protocol_server.dart' as proto;
 import 'package:analyzer/dart/ast/ast.dart';
@@ -11,7 +9,7 @@
 
 /// Return the elements that the given [element] overrides.
 OverriddenElements findOverriddenElements(Element element) {
-  if (element?.enclosingElement is ClassElement) {
+  if (element.enclosingElement is ClassElement) {
     return _OverriddenElementsFinder(element).find();
   }
   return OverriddenElements(element, <Element>[], <Element>[]);
@@ -53,19 +51,21 @@
   /// Add a new [Override] for the declaration with the given name [node].
   void _addOverride(SimpleIdentifier node) {
     var element = node.staticElement;
-    var overridesResult = _OverriddenElementsFinder(element).find();
-    var superElements = overridesResult.superElements;
-    var interfaceElements = overridesResult.interfaceElements;
-    if (superElements.isNotEmpty || interfaceElements.isNotEmpty) {
-      var superMember = superElements.isNotEmpty
-          ? proto.newOverriddenMember_fromEngine(superElements.first)
-          : null;
-      var interfaceMembers = interfaceElements
-          .map((member) => proto.newOverriddenMember_fromEngine(member))
-          .toList();
-      _overrides.add(proto.Override(node.offset, node.length,
-          superclassMember: superMember,
-          interfaceMembers: nullIfEmpty(interfaceMembers)));
+    if (element != null) {
+      var overridesResult = _OverriddenElementsFinder(element).find();
+      var superElements = overridesResult.superElements;
+      var interfaceElements = overridesResult.interfaceElements;
+      if (superElements.isNotEmpty || interfaceElements.isNotEmpty) {
+        var superMember = superElements.isNotEmpty
+            ? proto.newOverriddenMember_fromEngine(superElements.first)
+            : null;
+        var interfaceMembers = interfaceElements
+            .map((member) => proto.newOverriddenMember_fromEngine(member))
+            .toList();
+        _overrides.add(proto.Override(node.offset, node.length,
+            superclassMember: superMember,
+            interfaceMembers: nullIfEmpty(interfaceMembers)));
+      }
     }
   }
 }
@@ -117,20 +117,24 @@
   final List<Element> _interfaceElements = <Element>[];
   final Set<ClassElement> _visited = <ClassElement>{};
 
-  _OverriddenElementsFinder(Element seed) {
-    _seed = seed;
-    _class = seed.enclosingElement;
-    _library = _class.library;
-    _name = seed.displayName;
+  factory _OverriddenElementsFinder(Element seed) {
+    var class_ = seed.enclosingElement as ClassElement;
+    var library = class_.library;
+    var name = seed.displayName;
+    List<ElementKind> kinds;
     if (seed is MethodElement) {
-      _kinds = METHOD_KINDS;
+      kinds = METHOD_KINDS;
     } else if (seed is PropertyAccessorElement) {
-      _kinds = seed.isGetter ? GETTER_KINDS : SETTER_KINDS;
+      kinds = seed.isGetter ? GETTER_KINDS : SETTER_KINDS;
     } else {
-      _kinds = FIELD_KINDS;
+      kinds = FIELD_KINDS;
     }
+    return _OverriddenElementsFinder._(seed, library, class_, name, kinds);
   }
 
+  _OverriddenElementsFinder._(
+      this._seed, this._library, this._class, this._name, this._kinds);
+
   /// Add the [OverriddenElements] for this element.
   OverriddenElements find() {
     _visited.clear();
@@ -141,7 +145,7 @@
     return OverriddenElements(_seed, _superElements, _interfaceElements);
   }
 
-  void _addInterfaceOverrides(ClassElement class_, bool checkType) {
+  void _addInterfaceOverrides(ClassElement? class_, bool checkType) {
     if (class_ == null) {
       return;
     }
@@ -163,7 +167,7 @@
     _addInterfaceOverrides(class_.supertype?.element, checkType);
   }
 
-  void _addSuperOverrides(ClassElement class_, {bool withThisType = true}) {
+  void _addSuperOverrides(ClassElement? class_, {bool withThisType = true}) {
     if (class_ == null) {
       return;
     }
@@ -187,11 +191,8 @@
     }
   }
 
-  Element _lookupMember(ClassElement classElement) {
-    if (classElement == null) {
-      return null;
-    }
-    Element member;
+  Element? _lookupMember(ClassElement classElement) {
+    Element? member;
     // method
     if (_kinds.contains(ElementKind.METHOD)) {
       member = classElement.lookUpMethod(_name, _library);
diff --git a/pkg/analysis_server/lib/src/computer/imported_elements_computer.dart b/pkg/analysis_server/lib/src/computer/imported_elements_computer.dart
index a53a891..85352f0 100644
--- a/pkg/analysis_server/lib/src/computer/imported_elements_computer.dart
+++ b/pkg/analysis_server/lib/src/computer/imported_elements_computer.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
@@ -86,22 +84,26 @@
       if (nodeElement != null &&
           nodeElement.enclosingElement is CompilationUnitElement) {
         var nodeLibrary = nodeElement.library;
-        var path = nodeLibrary.definingCompilationUnit.source.fullName;
+        var path = nodeLibrary?.definingCompilationUnit.source.fullName;
+        if (path == null) {
+          return;
+        }
         var prefix = '';
         var parent = node.parent;
         if (parent is PrefixedIdentifier && parent.identifier == node) {
           prefix = _getPrefixFrom(parent.prefix);
-        } else if (parent is MethodInvocation &&
-            parent.methodName == node &&
-            parent.target is SimpleIdentifier) {
-          prefix = _getPrefixFrom(parent.target);
+        } else if (parent is MethodInvocation && parent.methodName == node) {
+          var target = parent.target;
+          if (target is SimpleIdentifier) {
+            prefix = _getPrefixFrom(target);
+          }
         }
         var key = '$prefix;$path';
         var elements = importedElements.putIfAbsent(
             key, () => ImportedElements(path, prefix, <String>[]));
         var elementNames = elements.elements;
         var elementName = nodeElement.name;
-        if (!elementNames.contains(elementName)) {
+        if (elementName != null && !elementNames.contains(elementName)) {
           elementNames.add(elementName);
         }
       }
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 108e4c63..72a096e 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -32,7 +32,7 @@
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol;
 import 'package:analyzer_plugin/utilities/analyzer_converter.dart';
 import 'package:meta/meta.dart';
-import 'package:path/path.dart' as pathos;
+import 'package:path/path.dart' as path;
 import 'package:watcher/watcher.dart';
 import 'package:yaml/yaml.dart';
 
@@ -163,7 +163,7 @@
   AnalysisContextCollectionImpl _collection;
 
   /// The context used to work with file system paths.
-  pathos.Context pathContext;
+  path.Context pathContext;
 
   /// The list of excluded paths (folders and files) most recently passed to
   /// [setRoots].
@@ -254,6 +254,10 @@
 
   @override
   void setRoots(List<String> includedPaths, List<String> excludedPaths) {
+    if (_rootsAreUnchanged(includedPaths, excludedPaths)) {
+      return;
+    }
+
     this.includedPaths = includedPaths;
     this.excludedPaths = excludedPaths;
 
@@ -588,6 +592,21 @@
     return resourceProvider.getFile(path).readAsStringSync();
   }
 
+  /// Checks whether the current roots were built using the same paths as
+  /// [includedPaths]/[excludedPaths].
+  bool _rootsAreUnchanged(
+      List<String> includedPaths, List<String> excludedPaths) {
+    if (includedPaths.length != this.includedPaths.length ||
+        excludedPaths.length != this.excludedPaths.length) {
+      return false;
+    }
+    final existingIncludedSet = this.includedPaths.toSet();
+    final existingExcludedSet = this.excludedPaths.toSet();
+
+    return existingIncludedSet.containsAll(includedPaths) &&
+        existingExcludedSet.containsAll(excludedPaths);
+  }
+
   /// Listens to files generated by Bazel that were found or searched for.
   ///
   /// This is handled specially because the files are outside the package
diff --git a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
index 3058da5..424cb0d 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -15,7 +13,7 @@
   List<protocol.ImplementedClass> classes = <protocol.ImplementedClass>[];
   List<protocol.ImplementedMember> members = <protocol.ImplementedMember>[];
 
-  Set<String> subtypeMembers;
+  Set<String>? subtypeMembers;
 
   ImplementedComputer(this.searchEngine, this.unitElement);
 
@@ -71,7 +69,7 @@
 
   bool _hasOverride(Element element) {
     var name = element.displayName;
-    return subtypeMembers.contains(name);
+    return subtypeMembers!.contains(name);
   }
 
   /// Return `true` if the given [element] is a static element.
diff --git a/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart b/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart
index 5a10351..295d92c 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/occurrences.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/plugin/analysis/occurrences/occurrences_core.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 
diff --git a/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
index 441e949..353bbc8 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/plugin/analysis/occurrences/occurrences_core.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analyzer/dart/ast/ast.dart';
@@ -36,25 +34,25 @@
   }
 
   void _addOccurrence(Element element, int offset) {
-    element = _canonicalizeElement(element);
-    if (element == null || element == DynamicElementImpl.instance) {
+    var canonicalElement = _canonicalizeElement(element);
+    if (canonicalElement == null || element == DynamicElementImpl.instance) {
       return;
     }
-    var offsets = elementsOffsets[element];
+    var offsets = elementsOffsets[canonicalElement];
     if (offsets == null) {
       offsets = <int>[];
-      elementsOffsets[element] = offsets;
+      elementsOffsets[canonicalElement] = offsets;
     }
     offsets.add(offset);
   }
 
-  Element _canonicalizeElement(Element element) {
-    if (element is FieldFormalParameterElement) {
-      element = (element as FieldFormalParameterElement).field;
+  Element? _canonicalizeElement(Element element) {
+    Element? canonicalElement = element;
+    if (canonicalElement is FieldFormalParameterElement) {
+      canonicalElement = canonicalElement.field;
+    } else if (canonicalElement is PropertyAccessorElement) {
+      canonicalElement = canonicalElement.variable;
     }
-    if (element is PropertyAccessorElement) {
-      element = (element as PropertyAccessorElement).variable;
-    }
-    return element?.declaration;
+    return canonicalElement?.declaration;
   }
 }
diff --git a/pkg/analysis_server/lib/src/domains/completion/available_suggestions.dart b/pkg/analysis_server/lib/src/domains/completion/available_suggestions.dart
index 8440c7d..7c029d8 100644
--- a/pkg/analysis_server/lib/src/domains/completion/available_suggestions.dart
+++ b/pkg/analysis_server/lib/src/domains/completion/available_suggestions.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -26,7 +24,7 @@
   var context = tracker.getContext(analysisContext);
   if (context == null) return;
 
-  var librariesObject = context.getLibraries(resolvedUnit.path);
+  var librariesObject = context.getLibraries(resolvedUnit.path!);
 
   var importedUriSet = resolvedUnit.libraryElement.importedLibraries
       .map((importedLibrary) => importedLibrary.source.uri)
@@ -170,11 +168,10 @@
     case DeclarationKind.VARIABLE:
       return protocol.ElementKind.TOP_LEVEL_VARIABLE;
   }
-  return protocol.ElementKind.UNKNOWN;
 }
 
 /// Computes the best URI to import [what] into the [unit] library.
-String _getRelativeFileUri(ResolvedUnitResult unit, Uri what) {
+String? _getRelativeFileUri(ResolvedUnitResult unit, Uri what) {
   if (what.scheme == 'file') {
     var pathContext = unit.session.resourceProvider.pathContext;
 
@@ -188,42 +185,37 @@
   return null;
 }
 
-protocol.AvailableSuggestion _protocolAvailableSuggestion(
+protocol.AvailableSuggestion? _protocolAvailableSuggestion(
     Declaration declaration) {
   var label = declaration.name;
-  if (declaration.parent != null) {
+  var parent = declaration.parent;
+  if (parent != null) {
     if (declaration.kind == DeclarationKind.CONSTRUCTOR) {
-      label = declaration.parent.name;
+      label = parent.name;
       if (declaration.name.isNotEmpty) {
         label += '.${declaration.name}';
       }
     } else if (declaration.kind == DeclarationKind.ENUM_CONSTANT) {
-      label = '${declaration.parent.name}.${declaration.name}';
+      label = '${parent.name}.${declaration.name}';
     } else if (declaration.kind == DeclarationKind.GETTER &&
         declaration.isStatic) {
-      label = '${declaration.parent.name}.${declaration.name}';
+      label = '${parent.name}.${declaration.name}';
     } else if (declaration.kind == DeclarationKind.FIELD &&
         declaration.isStatic) {
-      label = '${declaration.parent.name}.${declaration.name}';
+      label = '${parent.name}.${declaration.name}';
     } else {
       return null;
     }
   }
 
   String declaringLibraryUri;
-  if (declaration.parent == null) {
+  if (parent == null) {
     declaringLibraryUri = '${declaration.locationLibraryUri}';
   } else {
-    declaringLibraryUri = '${declaration.parent.locationLibraryUri}';
+    declaringLibraryUri = '${parent.locationLibraryUri}';
   }
 
-  List<String> relevanceTags;
-  if (declaration.relevanceTags == null) {
-    relevanceTags = null;
-  } else {
-    relevanceTags = List<String>.from(declaration.relevanceTags);
-    relevanceTags.add(declaration.name);
-  }
+  var relevanceTags = declaration.relevanceTags.toList()..add(declaration.name);
 
   return protocol.AvailableSuggestion(
     label,
@@ -321,12 +313,13 @@
 
   /// When the completion domain subscribes for changes, we start redirecting
   /// changes to this listener.
-  void Function(LibraryChange) _listener;
+  void Function(LibraryChange)? _listener;
 
   DeclarationsTrackerData(this._tracker) {
     _tracker.changes.listen((change) {
-      if (_listener != null) {
-        _listener(change);
+      var listener = _listener;
+      if (listener != null) {
+        listener(change);
       } else {
         for (var library in change.changed) {
           _idToLibrary[library.id] = library;
@@ -383,10 +376,10 @@
   List<int> get uriList => map.keys.map((e) => e.uri).toList();
 
   int indexOf(_UniqueImportedStrings strings, Element element) {
-    var uriStr = '${element.librarySource.uri}';
+    var uriStr = '${element.librarySource!.uri}';
     var wrapper = _ImportedElement(
       strings.indexOf(uriStr),
-      strings.indexOf(element.name),
+      strings.indexOf(element.name!),
     );
     var index = map[wrapper];
     if (index == null) {
diff --git a/pkg/analysis_server/lib/src/flutter/flutter_outline_computer.dart b/pkg/analysis_server/lib/src/flutter/flutter_outline_computer.dart
index 5f79173..d216445 100644
--- a/pkg/analysis_server/lib/src/flutter/flutter_outline_computer.dart
+++ b/pkg/analysis_server/lib/src/flutter/flutter_outline_computer.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/computer/computer_outline.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analysis_server/src/utilities/flutter.dart';
@@ -33,15 +31,15 @@
 
     // Create outlines for widgets.
     var visitor = _FlutterOutlineBuilder(this);
-    resolvedUnit.unit.accept(visitor);
+    resolvedUnit.unit!.accept(visitor);
 
     // Associate Flutter outlines with Dart outlines.
     for (var outline in visitor.outlines) {
       for (var parent in _depthFirstOrder) {
         if (parent.offset < outline.offset &&
             outline.offset + outline.length < parent.offset + parent.length) {
-          parent.children ??= <protocol.FlutterOutline>[];
-          parent.children.add(outline);
+          var children = parent.children ??= <protocol.FlutterOutline>[];
+          children.add(outline);
           break;
         }
       }
@@ -53,30 +51,29 @@
   /// If the given [argument] for the [parameter] can be represented as a
   /// Flutter attribute, add it to the [attributes].
   void _addAttribute(List<protocol.FlutterOutlineAttribute> attributes,
-      Expression argument, ParameterElement parameter) {
+      Expression argument, ParameterElement? parameter) {
     if (parameter == null) {
       return;
     }
 
-    protocol.Location nameLocation;
+    protocol.Location? nameLocation;
     if (argument is NamedExpression) {
-      NamedExpression namedExpression = argument;
-      nameLocation = protocol.newLocation_fromNode(namedExpression.name.label);
-      argument = namedExpression.expression;
+      nameLocation = protocol.newLocation_fromNode(argument.name.label);
+      argument = argument.expression;
     }
 
     var valueLocation = protocol.newLocation_fromNode(argument);
 
     var name = parameter.displayName;
 
-    var label = resolvedUnit.content.substring(argument.offset, argument.end);
+    var label = resolvedUnit.content!.substring(argument.offset, argument.end);
     if (label.contains('\n')) {
       label = '…';
     }
 
-    bool literalValueBoolean;
-    int literalValueInteger;
-    String literalValueString;
+    bool? literalValueBoolean;
+    int? literalValueInteger;
+    String? literalValueString;
     if (argument is BooleanLiteral) {
       literalValueBoolean = argument.value;
     } else if (argument is IntegerLiteral) {
@@ -85,8 +82,9 @@
       literalValueString = argument.stringValue;
     } else {
       if (argument is FunctionExpression) {
-        var hasParameters = argument.parameters != null &&
-            argument.parameters.parameters.isNotEmpty;
+        var parameters = argument.parameters;
+        var hasParameters =
+            parameters != null && parameters.parameters.isNotEmpty;
         if (argument.body is ExpressionFunctionBody) {
           label = hasParameters ? '(…) => …' : '() => …';
         } else {
@@ -118,8 +116,9 @@
         dartOutline.codeOffset,
         dartOutline.codeLength,
         dartElement: dartOutline.element);
-    if (dartOutline.children != null) {
-      flutterOutline.children = dartOutline.children.map(_convert).toList();
+    var children = dartOutline.children;
+    if (children != null) {
+      flutterOutline.children = children.map(_convert).toList();
     }
 
     _depthFirstOrder.add(flutterOutline);
@@ -130,22 +129,23 @@
   /// outline item for it. If the node is not a widget creation, but its type
   /// is a Flutter Widget class subtype, and [withGeneric] is `true`, return
   /// a widget reference outline item.
-  protocol.FlutterOutline _createOutline(Expression node, bool withGeneric) {
+  protocol.FlutterOutline? _createOutline(Expression node, bool withGeneric) {
     var type = node.staticType;
-    if (!_flutter.isWidgetType(type)) {
+    if (type == null || !_flutter.isWidgetType(type)) {
       return null;
     }
-    var className = type.element.displayName;
+    var className = type.element!.displayName;
 
     if (node is InstanceCreationExpression) {
       var attributes = <protocol.FlutterOutlineAttribute>[];
       var children = <protocol.FlutterOutline>[];
       for (var argument in node.argumentList.arguments) {
-        var isWidgetArgument = _flutter.isWidgetType(argument.staticType);
+        var argumentType = argument.staticType;
+        var isWidgetArgument = _flutter.isWidgetType(argumentType);
         var isWidgetListArgument =
-            _flutter.isListOfWidgetsType(argument.staticType);
+            argumentType != null && _flutter.isListOfWidgetsType(argumentType);
 
-        String parentAssociationLabel;
+        String? parentAssociationLabel;
         Expression childrenExpression;
 
         if (argument is NamedExpression) {
@@ -155,7 +155,7 @@
           childrenExpression = argument;
         }
 
-        void addChildrenFrom(CollectionElement element) {
+        void addChildrenFrom(CollectionElement? element) {
           if (element is ConditionalExpression) {
             addChildrenFrom(element.thenExpression);
             addChildrenFrom(element.elseExpression);
@@ -212,13 +212,13 @@
     if (withGeneric) {
       var kind = protocol.FlutterOutlineKind.GENERIC;
 
-      String variableName;
+      String? variableName;
       if (node is SimpleIdentifier) {
         kind = protocol.FlutterOutlineKind.VARIABLE;
         variableName = node.name;
       }
 
-      String label;
+      String? label;
       if (kind == protocol.FlutterOutlineKind.GENERIC) {
         label = _getShortLabel(node);
       }
@@ -235,14 +235,15 @@
     if (node is MethodInvocation) {
       var buffer = StringBuffer();
 
-      if (node.target != null) {
-        buffer.write(_getShortLabel(node.target));
+      var target = node.target;
+      if (target != null) {
+        buffer.write(_getShortLabel(target));
         buffer.write('.');
       }
 
       buffer.write(node.methodName.name);
 
-      if (node.argumentList == null || node.argumentList.arguments.isEmpty) {
+      if (node.argumentList.arguments.isEmpty) {
         buffer.write('()');
       } else {
         buffer.write('(…)');
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart
index 857fcb3..cf360d1 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart
@@ -40,7 +40,7 @@
         ?.map((wf) => Uri.parse(wf.uri).toFilePath())
         ?.toList();
 
-    server.updateAnalysisRoots(added, removed);
+    server.updateWorkspaceFolders(added, removed);
 
     return success();
   }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart
index 462e933..98922d8 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart
@@ -33,7 +33,7 @@
     await server.fetchClientConfigurationAndPerformDynamicRegistration();
 
     if (!server.initializationOptions.onlyAnalyzeProjectsWithOpenFiles) {
-      server.updateAnalysisRoots(openWorkspacePaths, const []);
+      server.updateWorkspaceFolders(openWorkspacePaths, const []);
     }
 
     return success();
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
index f703d18..c6addff 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
@@ -11,28 +11,6 @@
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
 import 'package:analysis_server/src/lsp/mapping.dart';
 import 'package:analysis_server/src/lsp/source_edits.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/util/file_paths.dart' as file_paths;
-import 'package:path/path.dart' show dirname, join;
-
-/// Finds the nearest ancestor to [filePath] that contains a pubspec/.packages/build file.
-String _findProjectFolder(ResourceProvider resourceProvider, String filePath) {
-  // TODO(dantup): Is there something we can reuse for this?
-  var folder = dirname(filePath);
-  while (folder != dirname(folder)) {
-    final pubspec =
-        resourceProvider.getFile(join(folder, file_paths.pubspecYaml));
-    final packages =
-        resourceProvider.getFile(join(folder, file_paths.dotPackages));
-    final build = resourceProvider.getFile(join(folder, 'BUILD'));
-
-    if (pubspec.exists || packages.exists || build.exists) {
-      return folder;
-    }
-    folder = dirname(folder);
-  }
-  return null;
-}
 
 class TextDocumentChangeHandler
     extends MessageHandler<DidChangeTextDocumentParams, void> {
@@ -95,7 +73,6 @@
       server.removePriorityFile(path);
       server.documentVersions.remove(path);
       server.onOverlayDestroyed(path);
-      server.removeTemporaryAnalysisRoot(path);
 
       return success();
     });
@@ -127,22 +104,9 @@
       );
       server.onOverlayCreated(path, doc.text);
 
-      final driver = server.getAnalysisDriver(path);
       // If the file did not exist, and is "overlay only", it still should be
       // analyzed. Add it to driver to which it should have been added.
-
-      driver?.addFile(path);
-
-      // Figure out the best analysis root for this file and register it as a temporary
-      // analysis root. We need to register it even if we found a driver, so that if
-      // the driver existed only because of another open file, it will not be removed
-      // when that file is closed.
-      final analysisRoot = driver?.analysisContext?.contextRoot?.root?.path ??
-          _findProjectFolder(server.resourceProvider, path) ??
-          dirname(path);
-      if (analysisRoot != null) {
-        server.addTemporaryAnalysisRoot(path, analysisRoot);
-      }
+      server.contextManager.getDriverFor(path)?.addFile(path);
 
       server.addPriorityFile(path);
 
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index afb577f..076172d 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -37,6 +37,7 @@
 import 'package:analysis_server/src/services/completion/completion_performance.dart'
     show CompletionPerformance;
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
+import 'package:analyzer/dart/analysis/context_locator.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -50,6 +51,7 @@
 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
 import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
 import 'package:http/http.dart' as http;
+import 'package:meta/meta.dart';
 import 'package:watcher/watcher.dart';
 
 /// Instances of the class [LspAnalysisServer] implement an LSP-based server
@@ -104,29 +106,15 @@
 
   StreamSubscription _pluginChangeSubscription;
 
-  /// Temporary analysis roots for open files.
-  ///
-  /// When a file is opened and there is no driver available (for example no
-  /// folder was opened in the editor, so the set of analysis roots is empty)
-  /// we add temporary roots for the project (or containing) folder. When the
-  /// file is closed, it is removed from this map and if no other open file
-  /// uses that root, it will be removed from the set of analysis roots.
-  ///
-  /// key: file path of the open file
-  /// value: folder to be used as a root.
-  final _temporaryAnalysisRoots = <String, String>{};
-
-  /// The set of analysis roots explicitly added to the workspace.
-  final _explicitAnalysisRoots = <String>{};
+  /// The current workspace folders provided by the client. Used as analysis roots.
+  final _workspaceFolders = <String>{};
 
   /// A progress reporter for analysis status.
   ProgressReporter analyzingProgressReporter;
 
-  /// The last paths that were set as included analysis roots.
-  Set<String> _lastIncludedRootPaths;
-
-  /// The last paths that were set as excluded analysis roots.
-  Set<String> _lastExcludedRootPaths;
+  /// The number of times contexts have been created/recreated.
+  @visibleForTesting
+  int contextBuilds = 0;
 
   /// Initialize a newly created server to send and receive messages to the
   /// given [channel].
@@ -204,15 +192,10 @@
     assert(didAdd);
     if (didAdd) {
       _updateDriversAndPluginsPriorityFiles();
+      _refreshAnalysisRoots();
     }
   }
 
-  /// Adds a temporary analysis root for an open file.
-  void addTemporaryAnalysisRoot(String filePath, String folderPath) {
-    _temporaryAnalysisRoots[filePath] = folderPath;
-    _refreshAnalysisRoots();
-  }
-
   /// The socket from which messages are being read has been closed.
   void done() {}
 
@@ -479,15 +462,10 @@
     assert(didRemove);
     if (didRemove) {
       _updateDriversAndPluginsPriorityFiles();
+      _refreshAnalysisRoots();
     }
   }
 
-  /// Removes any temporary analysis root for a file that was closed.
-  void removeTemporaryAnalysisRoot(String filePath) {
-    _temporaryAnalysisRoots.remove(filePath);
-    _refreshAnalysisRoots();
-  }
-
   void sendErrorResponse(Message message, ResponseError error) {
     if (message is RequestMessage) {
       channel.sendResponse(ResponseMessage(
@@ -651,10 +629,11 @@
     sendServerErrorNotification('Socket error', error, stack);
   }
 
-  void updateAnalysisRoots(List<String> addedPaths, List<String> removedPaths) {
+  void updateWorkspaceFolders(
+      List<String> addedPaths, List<String> removedPaths) {
     // TODO(dantup): This is currently case-sensitive!
 
-    _explicitAnalysisRoots
+    _workspaceFolders
       ..addAll(addedPaths ?? const [])
       ..removeAll(removedPaths ?? const []);
 
@@ -671,14 +650,40 @@
     notifyFlutterWidgetDescriptions(path);
   }
 
+  /// Computes analysis roots for a set of open files.
+  ///
+  /// This is used when there are no workspace folders open directly.
+  List<String> _getRootsForOpenFiles() {
+    final openFiles = priorityFiles.toList();
+    final contextLocator = ContextLocator(resourceProvider: resourceProvider);
+    final roots = contextLocator.locateRoots(includedPaths: openFiles);
+
+    // For files in folders that don't have pubspecs, a root would be
+    // produced for the root of the drive which we do not want, so filter those out.
+    roots.removeWhere((root) => root.root.isRoot);
+
+    // Find any files that are no longer covered by roots because of the above
+    // removal.
+    final additionalFiles =
+        openFiles.where((file) => !roots.any((root) => root.isAnalyzed(file)));
+
+    return [
+      ...roots.map((root) => root.root.path),
+      ...additionalFiles,
+    ];
+  }
+
   void _onPluginsChanged() {
     capabilitiesComputer.performDynamicRegistration();
   }
 
   void _refreshAnalysisRoots() {
-    // Always include any temporary analysis roots for open files.
-    final includedPaths = _explicitAnalysisRoots.toSet()
-      ..addAll(_temporaryAnalysisRoots.values);
+    // When there are open folders, they are always the roots. If there are no
+    // open workspace folders, then we use the open (priority) files to compute
+    // roots.
+    final includedPaths = _workspaceFolders.isNotEmpty
+        ? _workspaceFolders.toSet()
+        : _getRootsForOpenFiles();
 
     final excludedPaths = clientConfiguration.analysisExcludedFolders
         .expand((excludePath) => resourceProvider.pathContext
@@ -688,25 +693,10 @@
             // TODO(dantup): Consider supporting per-workspace config by
             // calling workspace/configuration whenever workspace folders change
             // and caching the config for each one.
-            : _explicitAnalysisRoots.map(
+            : _workspaceFolders.map(
                 (root) => resourceProvider.pathContext.join(root, excludePath)))
         .toSet();
 
-    // If the roots didn't actually change from the last time they were set
-    // (this can happen a lot as temporary roots are collected for open files)
-    // we can avoid doing expensive work like discarding/re-scanning the
-    // declarations.
-    final rootsChanged =
-        includedPaths.length != _lastIncludedRootPaths?.length ||
-            !includedPaths.every(_lastIncludedRootPaths.contains) ||
-            excludedPaths.length != _lastExcludedRootPaths?.length ||
-            !excludedPaths.every(_lastExcludedRootPaths.contains);
-
-    if (!rootsChanged) return;
-
-    _lastIncludedRootPaths = includedPaths;
-    _lastExcludedRootPaths = excludedPaths;
-
     notificationManager.setAnalysisRoots(
         includedPaths.toList(), excludedPaths.toList());
     contextManager.setRoots(includedPaths.toList(), excludedPaths.toList());
@@ -780,6 +770,7 @@
 
   @override
   void afterContextsCreated() {
+    analysisServer.contextBuilds++;
     analysisServer.addContextsToDeclarationsTracker();
   }
 
diff --git a/pkg/analysis_server/lib/src/server/crash_reporting.dart b/pkg/analysis_server/lib/src/server/crash_reporting.dart
index b5c775e..b585a03 100644
--- a/pkg/analysis_server/lib/src/server/crash_reporting.dart
+++ b/pkg/analysis_server/lib/src/server/crash_reporting.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/instrumentation/noop_service.dart';
 import 'package:analyzer/instrumentation/plugin_data.dart';
@@ -17,9 +15,11 @@
   CrashReportingInstrumentation(this.serverReporter);
 
   @override
-  void logException(dynamic exception,
-      [StackTrace stackTrace,
-      List<InstrumentationServiceAttachment> attachments = const []]) {
+  void logException(
+    Object exception, [
+    StackTrace? stackTrace,
+    List<InstrumentationServiceAttachment>? attachments,
+  ]) {
     var crashReportAttachments = (attachments ?? []).map((e) {
       return CrashReportAttachment.string(
         field: 'attachment_${e.id}',
@@ -30,9 +30,14 @@
     if (exception is CaughtException) {
       // Get the root CaughtException, which matters most for debugging.
       var root = exception.rootCaughtException;
-
-      _sendServerReport(root.exception, root.stackTrace,
-          attachments: crashReportAttachments, comment: root.message);
+      var message = root.message;
+      if (message == null) {
+        _sendServerReport(root.exception, root.stackTrace,
+            attachments: crashReportAttachments);
+      } else {
+        _sendServerReport(root.exception, root.stackTrace,
+            attachments: crashReportAttachments, comment: message);
+      }
     } else {
       _sendServerReport(exception, stackTrace ?? StackTrace.current,
           attachments: crashReportAttachments);
@@ -41,18 +46,16 @@
 
   @override
   void logPluginException(
-    PluginData plugin,
-    dynamic exception,
-    StackTrace stackTrace,
-  ) {
-    _sendServerReport(exception, stackTrace, comment: 'plugin: ${plugin.name}');
+      PluginData plugin, Object exception, StackTrace? stackTrace) {
+    _sendServerReport(exception, stackTrace ?? StackTrace.current,
+        comment: 'plugin: ${plugin.name}');
   }
 
-  void _sendServerReport(Object exception, Object stackTrace,
-      {String comment, List<CrashReportAttachment> attachments}) {
+  void _sendServerReport(Object exception, StackTrace stackTrace,
+      {String? comment, List<CrashReportAttachment>? attachments}) {
     serverReporter
         .sendReport(exception, stackTrace,
-            attachments: attachments, comment: comment)
+            attachments: attachments ?? const [], comment: comment)
         .catchError((error) {
       // We silently ignore errors sending crash reports (network issues, ...).
     });
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
index 425dc82..a39cc31 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
@@ -293,6 +293,12 @@
   }
 }
 
+abstract class CorrectionProducerWithDiagnostic extends CorrectionProducer {
+  /// TODO(migration) Consider providing it via constructor.
+  @override
+  Diagnostic get diagnostic => super.diagnostic!;
+}
+
 /// An object that can dynamically compute multiple corrections (fixes or
 /// assists).
 abstract class MultiCorrectionProducer extends _AbstractCorrectionProducer {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_await.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_await.dart
index 7acd73c..6e72eae 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_await.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_await.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart
index d4b2642..84311ad 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -19,15 +17,14 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    var node = this.node;
+    AstNode? node = this.node;
     if (node is SimpleIdentifier) {
       node = node.parent;
     }
     if (node is ConstructorDeclaration) {
+      var node_final = node;
       await builder.addDartFileEdit(file, (builder) {
-        final offset = (node as ConstructorDeclaration)
-            .firstTokenAfterCommentAndMetadata
-            .offset;
+        final offset = node_final.firstTokenAfterCommentAndMetadata.offset;
         builder.addSimpleInsertion(offset, 'const ');
       });
       return;
@@ -39,9 +36,10 @@
       node = node.parent;
     }
     if (node is InstanceCreationExpression) {
-      if ((node as InstanceCreationExpression).keyword == null) {
+      if (node.keyword == null) {
+        var node_final = node;
         await builder.addDartFileEdit(file, (builder) {
-          builder.addSimpleInsertion(node.offset, 'const ');
+          builder.addSimpleInsertion(node_final.offset, 'const ');
         });
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_diagnostic_property_reference.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_diagnostic_property_reference.dart
index 649cfbc..7dd8989 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_diagnostic_property_reference.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_diagnostic_property_reference.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
@@ -14,7 +12,6 @@
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
-import 'package:meta/meta.dart';
 
 class AddDiagnosticPropertyReference extends CorrectionProducer {
   @override
@@ -36,12 +33,11 @@
 
     var classDeclaration = node.thisOrAncestorOfType<ClassOrMixinDeclaration>();
     if (classDeclaration == null ||
-        !flutter.isDiagnosticable(classDeclaration.declaredElement.thisType)) {
+        !flutter.isDiagnosticable(classDeclaration.declaredElement!.thisType)) {
       return;
     }
 
-    SimpleIdentifier name = node;
-    final parent = node.parent;
+    final parent = node.parent!;
 
     var type = _getReturnType(parent);
     if (type == null) {
@@ -49,7 +45,7 @@
     }
 
     String constructorId;
-    List<DartType> typeArgs;
+    List<DartType>? typeArgs;
     var constructorName = '';
 
     if (type is FunctionType) {
@@ -81,8 +77,8 @@
 
     void writePropertyReference(
       DartEditBuilder builder, {
-      @required String prefix,
-      @required String builderName,
+      required String prefix,
+      required String builderName,
     }) {
       builder.write('$prefix$builderName.add($constructorId');
       if (typeArgs != null) {
@@ -90,7 +86,7 @@
         builder.writeTypes(typeArgs);
         builder.write('>');
       } else if (type.isDynamic) {
-        TypeAnnotation declType;
+        TypeAnnotation? declType;
         final decl = node.thisOrAncestorOfType<VariableDeclarationList>();
         if (decl != null) {
           declType = decl.type;
@@ -108,14 +104,18 @@
           }
         }
       }
-      builder.writeln("$constructorName('${name.name}', ${name.name}));");
+      builder.writeln("$constructorName('${node.name}', ${node.name}));");
     }
 
     final debugFillProperties =
         classDeclaration.getMethod('debugFillProperties');
     if (debugFillProperties == null) {
-      final insertOffset =
-          utils.prepareNewMethodLocation(classDeclaration).offset;
+      var location = utils.prepareNewMethodLocation(classDeclaration);
+      if (location == null) {
+        return;
+      }
+
+      final insertOffset = location.offset;
       await builder.addDartFileEdit(file, (builder) {
         builder.addInsertion(utils.getLineNext(insertOffset), (builder) {
           final declPrefix =
@@ -149,14 +149,19 @@
         prefix = utils.getLinePrefix(offset);
       }
 
-      var parameters = debugFillProperties.parameters.parameters;
-      String propertiesBuilderName;
-      for (var parameter in parameters) {
+      var parameterList = debugFillProperties.parameters;
+      if (parameterList == null) {
+        return;
+      }
+
+      String? propertiesBuilderName;
+      for (var parameter in parameterList.parameters) {
         if (parameter is SimpleFormalParameter) {
           final type = parameter.type;
-          if (type is TypeName) {
+          final identifier = parameter.identifier;
+          if (type is TypeName && identifier != null) {
             if (type.name.name == 'DiagnosticPropertiesBuilder') {
-              propertiesBuilderName = parameter.identifier.name;
+              propertiesBuilderName = identifier.name;
               break;
             }
           }
@@ -166,17 +171,18 @@
         return null;
       }
 
+      final final_propertiesBuilderName = propertiesBuilderName;
       await builder.addDartFileEdit(file, (builder) {
         builder.addInsertion(utils.getLineNext(offset), (builder) {
           writePropertyReference(builder,
-              prefix: prefix, builderName: propertiesBuilderName);
+              prefix: prefix, builderName: final_propertiesBuilderName);
         });
       });
     }
   }
 
   /// Return the return type of the given [node].
-  DartType _getReturnType(AstNode node) {
+  DartType? _getReturnType(AstNode node) {
     if (node is MethodDeclaration) {
       // Getter.
       var element = node.declaredElement;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_explicit_cast.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_explicit_cast.dart
index aaaf687..612635d 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_explicit_cast.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_explicit_cast.dart
@@ -2,14 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/utilities/extensions/ast.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/precedence.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 
@@ -19,14 +18,12 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    Expression target;
-    if (coveredNode is Expression) {
-      target = coveredNode;
-    } else {
+    var target = coveredNode;
+    if (target is! Expression) {
       return;
     }
 
-    var fromType = target.staticType;
+    var fromType = target.typeOrThrow;
     if (fromType == typeProvider.nullType) {
       // There would only be a diagnostic if the `toType` is not nullable, in
       // which case a cast won't fix the problem.
@@ -39,9 +36,9 @@
       parent = target.parent;
     }
     if (parent is AssignmentExpression && target == parent.rightHandSide) {
-      toType = parent.writeType;
+      toType = parent.writeType!;
     } else if (parent is VariableDeclaration && target == parent.initializer) {
-      toType = parent.declaredElement.type;
+      toType = parent.declaredElement!.type;
     } else {
       // TODO(brianwilkerson) Handle function arguments.
       return;
@@ -56,7 +53,7 @@
     if (target.isToListMethodInvocation) {
       var targetTarget = (target as MethodInvocation).target;
       if (targetTarget != null) {
-        var targetTargetType = targetTarget.staticType;
+        var targetTargetType = targetTarget.typeOrThrow;
         if (targetTargetType.isDartCoreIterable ||
             targetTargetType.isDartCoreList ||
             targetTargetType.isDartCoreMap ||
@@ -70,55 +67,65 @@
       // TODO(brianwilkerson) Consider updating the right operand.
       return;
     }
+
+    final target_final = target;
+
     var needsParentheses = target.precedence < Precedence.postfix;
     if (((fromType.isDartCoreIterable || fromType.isDartCoreList) &&
+            toType is InterfaceType &&
             toType.isDartCoreList) ||
-        (fromType.isDartCoreSet && toType.isDartCoreSet)) {
+        (fromType.isDartCoreSet &&
+            toType is InterfaceType &&
+            toType.isDartCoreSet)) {
       if (target.isCastMethodInvocation) {
         // TODO(brianwilkerson) Consider updating the type arguments to the
         // `cast` invocation.
         return;
       }
+      final toType_final = toType;
       await builder.addDartFileEdit(file, (builder) {
         if (needsParentheses) {
-          builder.addSimpleInsertion(target.offset, '(');
+          builder.addSimpleInsertion(target_final.offset, '(');
         }
-        builder.addInsertion(target.end, (builder) {
+        builder.addInsertion(target_final.end, (builder) {
           if (needsParentheses) {
             builder.write(')');
           }
           builder.write('.cast<');
-          builder.writeType((toType as InterfaceType).typeArguments[0]);
+          builder.writeType(toType_final.typeArguments[0]);
           builder.write('>()');
         });
       });
-    } else if (fromType.isDartCoreMap && toType.isDartCoreMap) {
+    } else if (fromType.isDartCoreMap &&
+        toType is InterfaceType &&
+        toType.isDartCoreMap) {
       if (target.isCastMethodInvocation) {
         // TODO(brianwilkerson) Consider updating the type arguments to the
         // `cast` invocation.
         return;
       }
+      final toType_final = toType;
       await builder.addDartFileEdit(file, (builder) {
         if (needsParentheses) {
-          builder.addSimpleInsertion(target.offset, '(');
+          builder.addSimpleInsertion(target_final.offset, '(');
         }
-        builder.addInsertion(target.end, (builder) {
+        builder.addInsertion(target_final.end, (builder) {
           if (needsParentheses) {
             builder.write(')');
           }
           builder.write('.cast<');
-          builder.writeType((toType as InterfaceType).typeArguments[0]);
+          builder.writeType(toType_final.typeArguments[0]);
           builder.write(', ');
-          builder.writeType((toType as InterfaceType).typeArguments[1]);
+          builder.writeType(toType_final.typeArguments[1]);
           builder.write('>()');
         });
       });
     } else {
       await builder.addDartFileEdit(file, (builder) {
         if (needsParentheses) {
-          builder.addSimpleInsertion(target.offset, '(');
+          builder.addSimpleInsertion(target_final.offset, '(');
         }
-        builder.addInsertion(target.end, (builder) {
+        builder.addInsertion(target_final.end, (builder) {
           if (needsParentheses) {
             builder.write(')');
           }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_field_formal_parameters.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_field_formal_parameters.dart
index e4ef282..4a1c1e4 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_field_formal_parameters.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_field_formal_parameters.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -18,14 +16,21 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    if (node is! SimpleIdentifier || node.parent is! ConstructorDeclaration) {
+    var constructor = node.parent;
+    if (node is! SimpleIdentifier || constructor is! ConstructorDeclaration) {
       return;
     }
-    ConstructorDeclaration constructor = node.parent;
     List<FormalParameter> parameters = constructor.parameters.parameters;
 
-    ClassDeclaration classNode = constructor.parent;
-    var superType = classNode.declaredElement.supertype;
+    var classNode = constructor.parent;
+    if (classNode is! ClassDeclaration) {
+      return;
+    }
+
+    var superType = classNode.declaredElement!.supertype;
+    if (superType == null) {
+      return;
+    }
 
     // Compute uninitialized final fields.
     var fields = ErrorVerifier.computeNotInitializedFields(constructor);
@@ -51,7 +56,7 @@
     }
 
     // Prepare the last required parameter.
-    FormalParameter lastRequiredParameter;
+    FormalParameter? lastRequiredParameter;
     for (var parameter in parameters) {
       if (parameter.isRequiredPositional) {
         lastRequiredParameter = parameter;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_late.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_late.dart
index 06bb9e0..cc3293b 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_late.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_late.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -25,14 +23,15 @@
     }
     var node = this.node;
     if (node is SimpleIdentifier) {
-      if (node.parent is VariableDeclaration &&
-          node.parent.parent is VariableDeclarationList) {
-        var list = node.parent.parent as VariableDeclarationList;
-        if (!list.isLate) {
-          if (list.type == null) {
-            var keyword = list.keyword;
+      var variable = node.parent;
+      var variableList = variable?.parent;
+      if (variable is VariableDeclaration &&
+          variableList is VariableDeclarationList) {
+        if (!variableList.isLate) {
+          if (variableList.type == null) {
+            var keyword = variableList.keyword;
             if (keyword == null) {
-              await _insertAt(builder, list.variables[0].offset);
+              await _insertAt(builder, variableList.variables[0].offset);
               // TODO(brianwilkerson) Consider converting this into an assist and
               //  expand it to support converting `var` to `late` as well as
               //  working anywhere a non-late local variable or field is selected.
@@ -41,14 +40,14 @@
 //              builder.addSimpleReplacement(range.token(keyword), 'late');
 //            });
             } else if (keyword.type != Keyword.CONST) {
-              await _insertAt(builder, list.variables[0].offset);
+              await _insertAt(builder, variableList.variables[0].offset);
             }
           } else {
-            var keyword = list.keyword;
+            var keyword = variableList.keyword;
             if (keyword != null) {
               await _insertAt(builder, keyword.offset);
             } else {
-              var type = list.type;
+              var type = variableList.type;
               if (type != null) {
                 await _insertAt(builder, type.offset);
               }
@@ -65,13 +64,17 @@
             getter.enclosingElement is ClassElement) {
           var declarationResult =
               await sessionHelper.getElementDeclaration(getter.variable);
+          if (declarationResult == null) {
+            return;
+          }
           var variable = declarationResult.node;
+          var variableList = variable.parent;
           if (variable is VariableDeclaration &&
-              variable.parent is VariableDeclarationList &&
-              variable.parent.parent is FieldDeclaration) {
-            VariableDeclarationList declarationList = variable.parent;
-            var keywordToken = declarationList.keyword;
-            if (declarationList.variables.length == 1 &&
+              variableList is VariableDeclarationList &&
+              variableList.parent is FieldDeclaration) {
+            var keywordToken = variableList.keyword;
+            if (variableList.variables.length == 1 &&
+                keywordToken != null &&
                 keywordToken.keyword == Keyword.FINAL) {
               await _insertAt(builder, keywordToken.offset,
                   source: declarationResult.element.source);
@@ -83,7 +86,7 @@
   }
 
   Future<void> _insertAt(ChangeBuilder builder, int offset,
-      {Source source}) async {
+      {Source? source}) async {
     await builder.addDartFileEdit(source?.fullName ?? file, (builder) {
       builder.addSimpleInsertion(offset, 'late ');
     });
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_missing_enum_case_clauses.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_missing_enum_case_clauses.dart
index b4825c1..434f13d 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_missing_enum_case_clauses.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_missing_enum_case_clauses.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -23,7 +21,7 @@
     }
     var statement = node as SwitchStatement;
 
-    String enumName;
+    String? enumName;
     var enumConstantNames = <String>[];
     var expressionType = statement.expression.staticType;
     if (expressionType is InterfaceType) {
@@ -58,13 +56,14 @@
     var statementIndent = utils.getLinePrefix(statement.offset);
     var singleIndent = utils.getIndent(1);
 
+    final enumName_final = enumName;
     await builder.addDartFileEdit(file, (builder) {
       builder.addInsertion(utils.getLineThis(statement.end), (builder) {
         for (var constantName in enumConstantNames) {
           builder.write(statementIndent);
           builder.write(singleIndent);
           builder.write('case ');
-          builder.write(enumName);
+          builder.write(enumName_final);
           builder.write('.');
           builder.write(constantName);
           builder.writeln(':');
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_missing_parameter.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_missing_parameter.dart
index 4d7c4db..1f11731 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_missing_parameter.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_missing_parameter.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/executable_parameters.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
@@ -15,11 +13,17 @@
   @override
   Iterable<CorrectionProducer> get producers sync* {
     // node is the unmatched argument.
-    if (node.parent is! ArgumentList) {
+    var argumentList = node.parent;
+    if (argumentList is! ArgumentList) {
       return;
     }
-    var context =
-        ExecutableParameters.forInvocation(sessionHelper, node.parent.parent);
+
+    var invocation = argumentList.parent;
+    if (invocation == null) {
+      return;
+    }
+
+    var context = ExecutableParameters.forInvocation(sessionHelper, invocation);
     if (context == null) {
       return;
     }
@@ -54,7 +58,7 @@
       await _addParameter(builder, prevNode?.end, prefix, ']');
     } else {
       var parameterList = await context.getParameterList();
-      var offset = parameterList?.leftParenthesis?.end;
+      var offset = parameterList?.leftParenthesis.end;
       await _addParameter(builder, offset, prefix, ']');
     }
   }
@@ -68,9 +72,12 @@
   _AddMissingParameter(this.context);
 
   Future<void> _addParameter(
-      ChangeBuilder builder, int offset, String prefix, String suffix) async {
+      ChangeBuilder builder, int? offset, String prefix, String suffix) async {
     // node is the unmatched argument.
-    ArgumentList argumentList = node.parent;
+    var argumentList = node.parent;
+    if (argumentList is! ArgumentList) {
+      return;
+    }
     List<Expression> arguments = argumentList.arguments;
     var numRequired = context.required.length;
     if (numRequired >= arguments.length) {
@@ -106,7 +113,7 @@
       await _addParameter(builder, prevNode?.end, ', ', '');
     } else {
       var parameterList = await context.getParameterList();
-      var offset = parameterList?.leftParenthesis?.end;
+      var offset = parameterList?.leftParenthesis.end;
       var suffix = context.executable.parameters.isNotEmpty ? ', ' : '';
       await _addParameter(builder, offset, '', suffix);
     }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_missing_parameter_named.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_missing_parameter_named.dart
index cc53b3f..da82a33 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_missing_parameter_named.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_missing_parameter_named.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/executable_parameters.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
@@ -12,7 +10,7 @@
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 
 class AddMissingParameterNamed extends CorrectionProducer {
-  String _parameterName;
+  String _parameterName = '';
 
   @override
   List<Object> get fixArguments => [_parameterName];
@@ -23,23 +21,23 @@
   @override
   Future<void> compute(ChangeBuilder builder) async {
     // Prepare the name of the missing parameter.
-    if (this.node is! SimpleIdentifier) {
+    var node = this.node;
+    if (node is! SimpleIdentifier) {
       return;
     }
-    SimpleIdentifier node = this.node;
     _parameterName = node.name;
 
     // We expect that the node is part of a NamedExpression.
-    if (node.parent?.parent is! NamedExpression) {
+    var namedExpression = node.parent?.parent;
+    if (namedExpression is! NamedExpression) {
       return;
     }
-    NamedExpression namedExpression = node.parent.parent;
 
     // We should be in an ArgumentList.
-    if (namedExpression.parent is! ArgumentList) {
+    var argumentList = namedExpression.parent;
+    if (argumentList is! ArgumentList) {
       return;
     }
-    var argumentList = namedExpression.parent;
 
     // Prepare the invoked element.
     var context =
@@ -53,7 +51,7 @@
       return;
     }
 
-    Future<void> addParameter(int offset, String prefix, String suffix) async {
+    Future<void> addParameter(int? offset, String prefix, String suffix) async {
       if (offset != null) {
         await builder.addDartFileEdit(context.file, (builder) {
           builder.addInsertion(offset, (builder) {
@@ -74,7 +72,7 @@
       await addParameter(prevNode?.end, ', {', '}');
     } else {
       var parameterList = await context.getParameterList();
-      await addParameter(parameterList?.leftParenthesis?.end, '{', '}');
+      await addParameter(parameterList?.leftParenthesis.end, '{', '}');
     }
   }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart
index cd75a2b..d5facaf 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/analysis/features.dart';
@@ -12,7 +10,7 @@
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 
-class AddNeNull extends CorrectionProducer {
+class AddNeNull extends CorrectionProducerWithDiagnostic {
   @override
   FixKind get fixKind => DartFixKind.ADD_NE_NULL;
 
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_not_null_assert.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_not_null_assert.dart
index fe5c8f6..ac57617 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_not_null_assert.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_not_null_assert.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'dart:math';
 
 import 'package:_fe_analyzer_shared/src/scanner/token.dart';
@@ -20,53 +18,63 @@
   @override
   Future<void> compute(ChangeBuilder builder) async {
     final identifier = node;
-    if (identifier is SimpleIdentifier) {
-      if (identifier.parent is FormalParameter) {
-        final exp = identifier.parent.thisOrAncestorMatching(
-            (node) => node is FunctionExpression || node is MethodDeclaration);
-        FunctionBody body;
-        if (exp is FunctionExpression) {
-          body = exp.body;
-        } else if (exp is MethodDeclaration) {
-          body = exp.body;
-        }
-        if (body is BlockFunctionBody) {
-          var blockBody = body;
-          // Check for an obvious pre-existing assertion.
-          for (var statement in blockBody.block.statements) {
-            if (statement is AssertStatement) {
-              final condition = statement.condition;
-              if (condition is BinaryExpression) {
-                final leftOperand = condition.leftOperand;
-                if (leftOperand is SimpleIdentifier) {
-                  if (leftOperand.staticElement == identifier.staticElement &&
-                      condition.operator.type == TokenType.BANG_EQ &&
-                      condition.rightOperand is NullLiteral) {
-                    return;
-                  }
-                }
+    if (identifier is! SimpleIdentifier) {
+      return;
+    }
+
+    var formalParameter = identifier.parent;
+    if (formalParameter is! FormalParameter) {
+      return;
+    }
+
+    final executable = formalParameter.thisOrAncestorMatching(
+        (node) => node is FunctionExpression || node is MethodDeclaration);
+    if (executable == null) {
+      return;
+    }
+
+    FunctionBody? body;
+    if (executable is FunctionExpression) {
+      body = executable.body;
+    } else if (executable is MethodDeclaration) {
+      body = executable.body;
+    }
+
+    if (body is BlockFunctionBody) {
+      // Check for an obvious pre-existing assertion.
+      for (var statement in body.block.statements) {
+        if (statement is AssertStatement) {
+          final condition = statement.condition;
+          if (condition is BinaryExpression) {
+            final leftOperand = condition.leftOperand;
+            if (leftOperand is SimpleIdentifier) {
+              if (leftOperand.staticElement == identifier.staticElement &&
+                  condition.operator.type == TokenType.BANG_EQ &&
+                  condition.rightOperand is NullLiteral) {
+                return;
               }
             }
           }
-
-          await builder.addDartFileEdit(file, (builder) {
-            final id = identifier.name;
-            final prefix = utils.getNodePrefix(exp);
-            final indent = utils.getIndent(1);
-            // todo (pq): follow-ups:
-            // 1. if the end token is on the same line as the body
-            // we should add an `eol` before the assert as well.
-            // 2. also, consider asking the block for the list of statements and
-            // adding the statement to the beginning of the list, special casing
-            // when there are no statements (or when there's a single statement
-            // and the whole block is on the same line).
-            var offset = min(utils.getLineNext(blockBody.beginToken.offset),
-                blockBody.endToken.offset);
-            builder.addSimpleInsertion(
-                offset, '$prefix${indent}assert($id != null);$eol');
-          });
         }
       }
+
+      final body_final = body;
+      await builder.addDartFileEdit(file, (builder) {
+        final id = identifier.name;
+        final prefix = utils.getNodePrefix(executable);
+        final indent = utils.getIndent(1);
+        // todo (pq): follow-ups:
+        // 1. if the end token is on the same line as the body
+        // we should add an `eol` before the assert as well.
+        // 2. also, consider asking the block for the list of statements and
+        // adding the statement to the beginning of the list, special casing
+        // when there are no statements (or when there's a single statement
+        // and the whole block is on the same line).
+        var offset = min(utils.getLineNext(body_final.beginToken.offset),
+            body_final.endToken.offset);
+        builder.addSimpleInsertion(
+            offset, '$prefix${indent}assert($id != null);$eol');
+      });
     }
   }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
index b7b4810..11bf784 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
@@ -2,14 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/precedence.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 
@@ -23,8 +22,9 @@
       // Don't suggest a feature that isn't supported.
       return;
     }
-    Expression target;
-    var coveredNodeParent = coveredNode.parent;
+    Expression? target;
+    var coveredNode = this.coveredNode;
+    var coveredNodeParent = coveredNode?.parent;
     if (coveredNode is SimpleIdentifier) {
       if (coveredNodeParent is MethodInvocation) {
         target = coveredNodeParent.realTarget;
@@ -38,59 +38,66 @@
         target = coveredNode;
       }
     } else if (coveredNode is IndexExpression) {
-      target = (coveredNode as IndexExpression).realTarget;
-    } else if (coveredNodeParent is FunctionExpressionInvocation) {
+      target = coveredNode.realTarget;
+    } else if (coveredNode is Expression &&
+        coveredNodeParent is FunctionExpressionInvocation) {
       target = coveredNode;
     } else if (coveredNodeParent is AssignmentExpression) {
       target = coveredNodeParent.rightHandSide;
     } else if (coveredNode is PostfixExpression) {
-      target = (coveredNode as PostfixExpression).operand;
+      target = coveredNode.operand;
     } else if (coveredNode is PrefixExpression) {
-      target = (coveredNode as PrefixExpression).operand;
+      target = coveredNode.operand;
     } else if (coveredNode is BinaryExpression) {
-      target = (coveredNode as BinaryExpression).leftOperand;
-    } else {
+      target = coveredNode.leftOperand;
+    }
+
+    if (target == null) {
       return;
     }
 
     var fromType = target.staticType;
+    if (fromType == null) {
+      return;
+    }
+
     if (fromType == typeProvider.nullType) {
       // Adding a null check after an explicit `null` is pointless.
       return;
     }
-    DartType toType;
+    DartType? toType;
     var parent = target.parent;
     if (parent is AssignmentExpression && target == parent.rightHandSide) {
       toType = parent.writeType;
     } else if (parent is VariableDeclaration && target == parent.initializer) {
-      toType = parent.declaredElement.type;
+      toType = parent.declaredElement?.type;
     } else if (parent is ArgumentList) {
-      toType = target.staticParameterElement.type;
+      toType = target.staticParameterElement?.type;
     } else if (parent is IndexExpression) {
-      toType = parent.realTarget.staticType;
+      toType = parent.realTarget.typeOrThrow;
     } else if (parent is ForEachPartsWithDeclaration) {
       toType =
-          typeProvider.iterableType(parent.loopVariable.declaredElement.type);
+          typeProvider.iterableType(parent.loopVariable.declaredElement!.type);
     } else if (parent is ForEachPartsWithIdentifier) {
-      toType = typeProvider.iterableType(parent.identifier.staticType);
+      toType = typeProvider.iterableType(parent.identifier.typeOrThrow);
     } else if (parent is SpreadElement) {
       var literal = parent.thisOrAncestorOfType<TypedLiteral>();
       if (literal is ListLiteral) {
-        toType = literal.staticType.asInstanceOf(typeProvider.iterableElement);
+        toType = literal.typeOrThrow.asInstanceOf(typeProvider.iterableElement);
       } else if (literal is SetOrMapLiteral) {
-        toType = literal.staticType.isDartCoreSet
-            ? literal.staticType.asInstanceOf(typeProvider.iterableElement)
-            : literal.staticType.asInstanceOf(typeProvider.mapElement);
+        toType = literal.typeOrThrow.isDartCoreSet
+            ? literal.typeOrThrow.asInstanceOf(typeProvider.iterableElement)
+            : literal.typeOrThrow.asInstanceOf(typeProvider.mapElement);
       }
     } else if (parent is YieldStatement) {
       var enclosingExecutable =
-          parent.thisOrAncestorOfType<FunctionBody>().parent;
+          parent.thisOrAncestorOfType<FunctionBody>()?.parent;
       if (enclosingExecutable is FunctionDeclaration) {
         toType = enclosingExecutable.returnType?.type;
       } else if (enclosingExecutable is MethodDeclaration) {
         toType = enclosingExecutable.returnType?.type;
       } else if (enclosingExecutable is FunctionExpression) {
-        toType = enclosingExecutable.declaredElement.returnType;
+        toType = enclosingExecutable.declaredElement!.returnType;
       }
     } else if ((parent is PrefixedIdentifier && target == parent.prefix) ||
         parent is PostfixExpression ||
@@ -113,12 +120,14 @@
       // problem.
       return;
     }
+
+    final target_final = target;
     var needsParentheses = target.precedence < Precedence.postfix;
     await builder.addDartFileEdit(file, (builder) {
       if (needsParentheses) {
-        builder.addSimpleInsertion(target.offset, '(');
+        builder.addSimpleInsertion(target_final.offset, '(');
       }
-      builder.addInsertion(target.end, (builder) {
+      builder.addInsertion(target_final.end, (builder) {
         if (needsParentheses) {
           builder.write(')');
         }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_override.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_override.dart
index 5f066c3..22c6924 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_override.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_override.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:_fe_analyzer_shared/src/scanner/token.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
@@ -32,7 +30,7 @@
     // Handle doc comments.
     var token = member.beginToken;
     if (token is CommentToken) {
-      token = (token as CommentToken).parent;
+      token = token.parent!;
     }
 
     var exitPosition = Position(file, token.offset - 1);
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_required.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_required.dart
index 81a242b..0f61891 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_required.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_required.dart
@@ -2,10 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 
@@ -18,9 +17,12 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    await builder.addDartFileEdit(file, (builder) {
-      builder.addSimpleInsertion(node.parent.offset, '@required ');
-    });
+    var parameter = node.parent;
+    if (parameter is FormalParameter) {
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addSimpleInsertion(parameter.offset, '@required ');
+      });
+    }
   }
 
   /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_required_keyword.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_required_keyword.dart
index 4160520..cf83196 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_required_keyword.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_required_keyword.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -18,24 +16,27 @@
   @override
   Future<void> compute(ChangeBuilder builder) async {
     await builder.addDartFileEdit(file, (builder) {
-      var insertOffset = node.parent.offset;
-
-      var parent = node.parent;
-      if (parent is FormalParameter) {
-        var metadata = parent.metadata;
-        // Check for redundant `@required` annotations.
-        if (metadata.isNotEmpty) {
-          for (var annotation in metadata) {
-            if (annotation.elementAnnotation.isRequired) {
-              var length = annotation.endToken.next.offset -
-                  annotation.beginToken.offset;
-              builder.addDeletion(SourceRange(annotation.offset, length));
-              break;
-            }
-          }
-          insertOffset = metadata.endToken.next.offset;
-        }
+      var parameter = node.parent;
+      if (parameter is! FormalParameter) {
+        return;
       }
+
+      var insertOffset = parameter.offset;
+
+      // Check for redundant `@required` annotations.
+      var metadata = parameter.metadata;
+      if (metadata.isNotEmpty) {
+        for (var annotation in metadata) {
+          if (annotation.elementAnnotation!.isRequired) {
+            var length =
+                annotation.endToken.next!.offset - annotation.beginToken.offset;
+            builder.addDeletion(SourceRange(annotation.offset, length));
+            break;
+          }
+        }
+        insertOffset = metadata.endToken!.next!.offset;
+      }
+
       builder.addSimpleInsertion(insertOffset, 'required ');
     });
   }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_return_type.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_return_type.dart
index dbc3d8d..7e49c67 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_return_type.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_return_type.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
@@ -13,6 +11,7 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_system.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
@@ -26,8 +25,8 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    SyntacticEntity insertBeforeEntity;
-    FunctionBody body;
+    SyntacticEntity? insertBeforeEntity;
+    FunctionBody? body;
     if (node is SimpleIdentifier) {
       var executable = node.parent;
       if (executable is MethodDeclaration && executable.name == node) {
@@ -55,13 +54,18 @@
       }
     }
 
+    if (insertBeforeEntity == null || body == null) {
+      return;
+    }
+
     var returnType = _inferReturnType(body);
     if (returnType == null) {
       return null;
     }
 
+    final insertBeforeEntity_final = insertBeforeEntity;
     await builder.addDartFileEdit(file, (builder) {
-      builder.addInsertion(insertBeforeEntity.offset, (builder) {
+      builder.addInsertion(insertBeforeEntity_final.offset, (builder) {
         if (returnType.isDynamic) {
           builder.write('dynamic');
         } else {
@@ -74,10 +78,10 @@
 
   /// Return the type of value returned by the function [body], or `null` if a
   /// type can't be inferred.
-  DartType _inferReturnType(FunctionBody body) {
-    DartType baseType;
+  DartType? _inferReturnType(FunctionBody body) {
+    DartType? baseType;
     if (body is ExpressionFunctionBody) {
-      baseType = body.expression.staticType;
+      baseType = body.expression.typeOrThrow;
     } else if (body is BlockFunctionBody) {
       var computer = _ReturnTypeComputer(resolvedResult.typeSystem);
       body.block.accept(computer);
@@ -124,7 +128,7 @@
 class _ReturnTypeComputer extends RecursiveAstVisitor<void> {
   final TypeSystem typeSystem;
 
-  DartType returnType;
+  DartType? returnType;
 
   /// A flag indicating whether at least one return statement was found.
   bool hasReturn = false;
@@ -143,18 +147,19 @@
       return;
     }
     // prepare type
-    var type = expression.staticType;
+    var type = expression.typeOrThrow;
     if (type.isBottom) {
       return;
     }
     // combine types
-    if (returnType == null) {
+    var current = returnType;
+    if (current == null) {
       returnType = type;
     } else {
-      if (returnType is InterfaceType && type is InterfaceType) {
-        returnType = InterfaceType.getSmartLeastUpperBound(returnType, type);
+      if (current is InterfaceType && type is InterfaceType) {
+        returnType = InterfaceType.getSmartLeastUpperBound(current, type);
       } else {
-        returnType = typeSystem.leastUpperBound(returnType, type);
+        returnType = typeSystem.leastUpperBound(current, type);
       }
     }
   }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_static.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_static.dart
index f165efc..4ee5960 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_static.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_static.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_super_constructor_invocation.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_super_constructor_invocation.dart
index cce07f3..092f566 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_super_constructor_invocation.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_super_constructor_invocation.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
@@ -16,14 +14,22 @@
 class AddSuperConstructorInvocation extends MultiCorrectionProducer {
   @override
   Iterable<CorrectionProducer> get producers sync* {
-    if (node.parent is! ConstructorDeclaration ||
-        node.parent.parent is! ClassDeclaration) {
+    var targetConstructor = node.parent;
+    if (targetConstructor is! ConstructorDeclaration) {
       return;
     }
-    var targetConstructor = node.parent as ConstructorDeclaration;
-    var targetClassNode = targetConstructor.parent as ClassDeclaration;
-    var targetClassElement = targetClassNode.declaredElement;
+
+    var targetClassNode = targetConstructor.parent;
+    if (targetClassNode is! ClassDeclaration) {
+      return;
+    }
+
+    var targetClassElement = targetClassNode.declaredElement!;
     var superType = targetClassElement.supertype;
+    if (superType == null) {
+      return;
+    }
+
     var initializers = targetConstructor.initializers;
     int insertOffset;
     String prefix;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_type_annotation.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_type_annotation.dart
index ef04b02..08bd321 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_type_annotation.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_type_annotation.dart
@@ -2,12 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:_fe_analyzer_shared/src/scanner/token.dart';
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/utilities/extensions/ast.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart';
@@ -36,7 +35,8 @@
         return;
       }
     }
-    while (node != null) {
+
+    for (var node in this.node.withParents) {
       if (node is VariableDeclarationList) {
         await _forVariableDeclaration(builder, node);
         return;
@@ -47,8 +47,7 @@
         var forLoopParts = node.forLoopParts;
         if (forLoopParts is ForEachParts) {
           var offset = this.node.offset;
-          if (forLoopParts.iterable != null &&
-              offset < forLoopParts.iterable.offset) {
+          if (offset < forLoopParts.iterable.offset) {
             if (forLoopParts is ForEachPartsWithDeclaration) {
               await _forDeclaredIdentifier(builder, forLoopParts.loopVariable);
             }
@@ -56,7 +55,6 @@
         }
         return;
       }
-      node = node.parent;
     }
   }
 
@@ -78,7 +76,7 @@
     if (declaredIdentifier.type != null) {
       return;
     }
-    var type = declaredIdentifier.declaredElement.type;
+    var type = declaredIdentifier.declaredElement!.type;
     if (type is! InterfaceType && type is! FunctionType) {
       return;
     }
@@ -88,7 +86,7 @@
       var validChange = true;
       await builder.addDartFileEdit(file, (builder) {
         var keyword = declaredIdentifier.keyword;
-        if (keyword.keyword == Keyword.VAR) {
+        if (keyword != null && keyword.keyword == Keyword.VAR) {
           builder.addReplacement(range.token(keyword), (builder) {
             validChange = builder.writeType(type);
           });
@@ -114,7 +112,7 @@
       return;
     }
     // Prepare the type.
-    var type = parameter.declaredElement.type;
+    var type = parameter.declaredElement!.type;
     // TODO(scheglov) If the parameter is in a method declaration, and if the
     // method overrides a method that has a type for the corresponding
     // parameter, it would be nice to copy down the type from the overridden
@@ -175,7 +173,7 @@
       var validChange = true;
       await builder.addDartFileEdit(file, (builder) {
         var keyword = declarationList.keyword;
-        if (keyword?.keyword == Keyword.VAR) {
+        if (keyword != null && keyword.keyword == Keyword.VAR) {
           builder.addReplacement(range.token(keyword), (builder) {
             validChange = builder.writeType(type);
           });
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/assign_to_local_variable.dart b/pkg/analysis_server/lib/src/services/correction/dart/assign_to_local_variable.dart
index 54e77cf..5aa14c3 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/assign_to_local_variable.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/assign_to_local_variable.dart
@@ -2,13 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/protocol_server.dart';
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/name_suggestion.dart';
+import 'package:analysis_server/src/utilities/extensions/ast.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -20,8 +20,8 @@
   @override
   Future<void> compute(ChangeBuilder builder) async {
     // prepare enclosing ExpressionStatement
-    ExpressionStatement expressionStatement;
-    for (var node = this.node; node != null; node = node.parent) {
+    ExpressionStatement? expressionStatement;
+    for (var node in this.node.withParents) {
       if (node is ExpressionStatement) {
         expressionStatement = node;
         break;
@@ -41,7 +41,7 @@
     var expression = expressionStatement.expression;
     var offset = expression.offset;
     // prepare expression type
-    var type = expression.staticType;
+    var type = expression.typeOrThrow;
     if (type.isVoid) {
       return;
     }
@@ -78,9 +78,9 @@
       var index = statements.indexOf(statement);
       if (index > 0) {
         var precedingStatement = statements[index - 1];
-        if (precedingStatement is ExpressionStatement &&
-            precedingStatement.semicolon.isSynthetic) {
-          return true;
+        if (precedingStatement is ExpressionStatement) {
+          var semicolon = precedingStatement.semicolon;
+          return semicolon != null && semicolon.isSynthetic;
         } else if (precedingStatement is VariableDeclarationStatement &&
             precedingStatement.semicolon.isSynthetic) {
           return true;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/change_argument_name.dart b/pkg/analysis_server/lib/src/services/correction/dart/change_argument_name.dart
index c7ff25f..75c187f 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/change_argument_name.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/change_argument_name.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/executable_parameters.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
@@ -20,18 +18,25 @@
 
   @override
   Iterable<CorrectionProducer> get producers sync* {
-    var names = _getNamedParameterNames();
-    if (names == null || names.isEmpty) {
+    var namedContext = _getNamedParameterNames();
+    if (namedContext == null) {
       return;
     }
-    SimpleIdentifier argumentName = node;
-    var invalidName = argumentName.name;
+
+    var names = namedContext.names;
+    if (names.isEmpty) {
+      return;
+    }
+
+    var currentNameNode = namedContext.identifier;
+    var currentName = currentNameNode.name;
+
     for (var proposedName in names) {
-      var distance = _computeDistance(invalidName, proposedName);
+      var distance = _computeDistance(currentName, proposedName);
       if (distance <= _maxDistance) {
         // TODO(brianwilkerson) Create a way to use the distance as part of the
         //  computation of the priority (so that closer names sort first).
-        yield _ChangeName(argumentName, proposedName);
+        yield _ChangeName(currentNameNode, proposedName);
       }
     }
   }
@@ -47,15 +52,20 @@
     return levenshtein(current, proposal, _maxDistance, caseSensitive: false);
   }
 
-  List<String> _getNamedParameterNames() {
-    var namedExpression = node?.parent?.parent;
+  _NamedExpressionContext? _getNamedParameterNames() {
+    var node = this.node;
+    var namedExpression = node.parent?.parent;
     if (node is SimpleIdentifier &&
         namedExpression is NamedExpression &&
-        namedExpression.name == node.parent &&
-        namedExpression.parent is ArgumentList) {
-      var parameters = ExecutableParameters.forInvocation(
-          sessionHelper, namedExpression.parent.parent);
-      return parameters?.namedNames;
+        namedExpression.name == node.parent) {
+      var argumentList = namedExpression.parent;
+      if (argumentList is ArgumentList) {
+        var parameters = ExecutableParameters.forInvocation(
+            sessionHelper, argumentList.parent);
+        if (parameters != null) {
+          return _NamedExpressionContext(node, parameters.namedNames);
+        }
+      }
     }
     return null;
   }
@@ -88,3 +98,10 @@
     });
   }
 }
+
+class _NamedExpressionContext {
+  final SimpleIdentifier identifier;
+  final List<String> names;
+
+  _NamedExpressionContext(this.identifier, this.names);
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/change_to.dart b/pkg/analysis_server/lib/src/services/correction/dart/change_to.dart
index 7ba2aa2..0f81d93 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/change_to.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/change_to.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/correction/levenshtein.dart';
@@ -23,7 +21,7 @@
   final _ReplacementKind _kind;
 
   /// The name to which the undefined name will be changed.
-  String _proposedName;
+  String _proposedName = '';
 
   /// Initialize a newly created instance that will propose elements of the
   /// given [_kind].
@@ -58,7 +56,7 @@
     var node = this.node;
     if (node is Annotation) {
       var name = node.name;
-      if (name != null && name.staticElement == null) {
+      if (name.staticElement == null) {
         if (node.arguments != null) {
           await _proposeClassOrMixin(builder, name);
         }
@@ -68,12 +66,12 @@
 
   Future<void> _proposeClassOrMixin(ChangeBuilder builder, AstNode node) async {
     // Prepare the optional import prefix name.
-    String prefixName;
+    String? prefixName;
     if (node is PrefixedIdentifier &&
         node.parent is TypeName &&
         node.prefix.staticElement is PrefixElement) {
-      prefixName = (node as PrefixedIdentifier).prefix.name;
-      node = (node as PrefixedIdentifier).identifier;
+      prefixName = node.prefix.name;
+      node = node.identifier;
     }
     // Process if looks like a type.
     if (mightBeTypeIdentifier(node)) {
@@ -95,34 +93,34 @@
         }
       }
       // If we have a close enough element, suggest to use it.
-      if (finder._element != null) {
-        _proposedName = finder._element.name;
-        if (_proposedName != null) {
-          await builder.addDartFileEdit(file, (builder) {
-            builder.addSimpleReplacement(range.node(node), _proposedName);
-          });
-        }
+      var foundElementName = finder._element?.name;
+      if (foundElementName != null) {
+        _proposedName = foundElementName;
+        await builder.addDartFileEdit(file, (builder) {
+          builder.addSimpleReplacement(range.node(node), _proposedName);
+        });
       }
     }
   }
 
   Future<void> _proposeClassOrMixinMember(ChangeBuilder builder,
-      Expression target, _ElementPredicate predicate) async {
+      Expression? target, _ElementPredicate predicate) async {
+    var node = this.node;
+    var targetIdentifierElement =
+        target is Identifier ? target.staticElement : null;
     if (node is SimpleIdentifier) {
-      var name = (node as SimpleIdentifier).name;
-      var finder = _ClosestElementFinder(name, predicate);
+      var finder = _ClosestElementFinder(node.name, predicate);
       // unqualified invocation
       if (target == null) {
         var clazz = node.thisOrAncestorOfType<ClassDeclaration>();
         if (clazz != null) {
-          var classElement = clazz.declaredElement;
+          var classElement = clazz.declaredElement!;
           _updateFinderWithClassMembers(finder, classElement);
         }
       } else if (target is ExtensionOverride) {
         _updateFinderWithExtensionMembers(finder, target.staticElement);
-      } else if (target is Identifier &&
-          target.staticElement is ExtensionElement) {
-        _updateFinderWithExtensionMembers(finder, target.staticElement);
+      } else if (targetIdentifierElement is ExtensionElement) {
+        _updateFinderWithExtensionMembers(finder, targetIdentifierElement);
       } else {
         var classElement = getTargetClassElement(target);
         if (classElement != null) {
@@ -130,8 +128,9 @@
         }
       }
       // if we have close enough element, suggest to use it
-      if (finder._element != null) {
-        _proposedName = finder._element.displayName;
+      var foundElementName = finder._element?.displayName;
+      if (foundElementName != null) {
+        _proposedName = foundElementName;
         await builder.addDartFileEdit(file, (builder) {
           builder.addSimpleReplacement(range.node(node), _proposedName);
         });
@@ -143,7 +142,7 @@
     var node = this.node;
     if (node is SimpleIdentifier) {
       // Prepare the optional import prefix name.
-      String prefixName;
+      String? prefixName;
       {
         var invocation = node.parent;
         if (invocation is MethodInvocation && invocation.methodName == node) {
@@ -171,8 +170,9 @@
         }
       }
       // If we have a close enough element, suggest to use it.
-      if (finder._element != null) {
-        _proposedName = finder._element.name;
+      var foundElementName = finder._element?.name;
+      if (foundElementName != null) {
+        _proposedName = foundElementName;
         await builder.addDartFileEdit(file, (builder) {
           builder.addSimpleReplacement(range.node(node), _proposedName);
         });
@@ -184,11 +184,12 @@
     var node = this.node;
     if (node is SimpleIdentifier) {
       // prepare target
-      Expression target;
-      if (node.parent is PrefixedIdentifier) {
-        target = (node.parent as PrefixedIdentifier).prefix;
-      } else if (node.parent is PropertyAccess) {
-        target = (node.parent as PropertyAccess).target;
+      Expression? target;
+      var parent = node.parent;
+      if (parent is PrefixedIdentifier) {
+        target = parent.prefix;
+      } else if (parent is PropertyAccess) {
+        target = parent.target;
       }
       // find getter or setter
       var wantGetter = node.inGetterContext();
@@ -216,14 +217,12 @@
 
   void _updateFinderWithClassMembers(
       _ClosestElementFinder finder, ClassElement clazz) {
-    if (clazz != null) {
-      var members = getMembers(clazz);
-      finder._updateList(members);
-    }
+    var members = getMembers(clazz);
+    finder._updateList(members);
   }
 
   void _updateFinderWithExtensionMembers(
-      _ClosestElementFinder finder, ExtensionElement element) {
+      _ClosestElementFinder finder, ExtensionElement? element) {
     if (element != null) {
       finder._updateList(getExtensionMembers(element));
     }
@@ -265,16 +264,19 @@
 
   int _distance = _maxDistance;
 
-  Element _element;
+  Element? _element;
 
   _ClosestElementFinder(this._targetName, this._predicate);
 
   void _update(Element element) {
     if (_predicate(element)) {
-      var memberDistance = levenshtein(element.name, _targetName, _distance);
-      if (memberDistance < _distance) {
-        _element = element;
-        _distance = memberDistance;
+      var name = element.name;
+      if (name != null) {
+        var memberDistance = levenshtein(name, _targetName, _distance);
+        if (memberDistance < _distance) {
+          _element = element;
+          _distance = memberDistance;
+        }
       }
     }
   }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/change_to_nearest_precise_value.dart b/pkg/analysis_server/lib/src/services/correction/dart/change_to_nearest_precise_value.dart
index ef2e3ba..4cd612f 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/change_to_nearest_precise_value.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/change_to_nearest_precise_value.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -24,7 +22,11 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    IntegerLiteral integer = node;
+    var integer = node;
+    if (integer is! IntegerLiteral) {
+      return;
+    }
+
     var lexeme = integer.literal.lexeme;
     var precise = BigInt.from(IntegerLiteralImpl.nearestValidDouble(lexeme));
     _correction = lexeme.toLowerCase().contains('x')
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/change_to_static_access.dart b/pkg/analysis_server/lib/src/services/correction/dart/change_to_static_access.dart
index 69aad4b..d6b1d16 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/change_to_static_access.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/change_to_static_access.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -13,7 +11,7 @@
 import 'package:analyzer_plugin/utilities/range_factory.dart';
 
 class ChangeToStaticAccess extends CorrectionProducer {
-  String _className;
+  String _className = '';
 
   @override
   List<Object> get fixArguments => [_className];
@@ -23,31 +21,48 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    Expression target;
-    Element invokedElement;
-    if (node is SimpleIdentifier && node.parent is MethodInvocation) {
-      var invocation = node.parent as MethodInvocation;
-      if (invocation.methodName == node) {
-        target = invocation.target;
-        invokedElement = invocation.methodName.staticElement;
-      }
-    } else if (node is SimpleIdentifier && node.parent is PrefixedIdentifier) {
-      var prefixed = node.parent as PrefixedIdentifier;
-      if (prefixed.identifier == node) {
-        target = prefixed.prefix;
-        invokedElement = prefixed.identifier.staticElement;
+    Expression? target;
+    Element? invokedElement;
+    var identifier = node;
+    if (identifier is SimpleIdentifier) {
+      var parent = identifier.parent;
+      if (parent is MethodInvocation) {
+        if (parent.methodName == identifier) {
+          target = parent.target;
+          invokedElement = identifier.staticElement;
+        }
+      } else if (parent is PrefixedIdentifier) {
+        if (parent.identifier == identifier) {
+          target = parent.prefix;
+          invokedElement = identifier.staticElement;
+        }
       }
     }
-    if (target == null) {
+    if (target == null || invokedElement is! ExecutableElement) {
       return;
     }
+
+    final target_final = target;
     var declaringElement = invokedElement.enclosingElement;
-    await builder.addDartFileEdit(file, (builder) {
-      builder.addReplacement(range.node(target), (builder) {
-        builder.writeReference(declaringElement);
+
+    if (declaringElement is ClassElement) {
+      _className = declaringElement.name;
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addReplacement(range.node(target_final), (builder) {
+          builder.writeReference(declaringElement);
+        });
       });
-    });
-    _className = declaringElement.name;
+    } else if (declaringElement is ExtensionElement) {
+      var extensionName = declaringElement.name;
+      if (extensionName != null) {
+        _className = extensionName;
+        await builder.addDartFileEdit(file, (builder) {
+          builder.addReplacement(range.node(target_final), (builder) {
+            builder.writeReference(declaringElement);
+          });
+        });
+      }
+    }
   }
 
   /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/change_type_annotation.dart b/pkg/analysis_server/lib/src/services/correction/dart/change_type_annotation.dart
index 9aef73e..f1e0afd 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/change_type_annotation.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/change_type_annotation.dart
@@ -2,12 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
@@ -26,24 +25,29 @@
   @override
   Future<void> compute(ChangeBuilder builder) async {
     var declaration = coveredNode?.parent;
-    if (declaration is VariableDeclaration &&
-        declaration.initializer == coveredNode) {
-      var variableList = declaration.parent;
-      if (variableList is VariableDeclarationList &&
-          variableList.variables.length == 1) {
-        var typeNode = variableList.type;
-        if (typeNode != null) {
-          Expression initializer = coveredNode;
-          var newType = initializer.staticType;
-          if (newType is InterfaceType || newType is FunctionType) {
-            _oldAnnotation = displayStringForType(typeNode.type);
-            _newAnnotation = displayStringForType(newType);
-            await builder.addDartFileEdit(file, (builder) {
-              builder.addReplacement(range.node(typeNode), (builder) {
-                builder.writeType(newType);
-              });
+    if (declaration is! VariableDeclaration) {
+      return;
+    }
+
+    var initializer = declaration.initializer;
+    if (initializer == null || initializer != coveredNode) {
+      return;
+    }
+
+    var variableList = declaration.parent;
+    if (variableList is VariableDeclarationList &&
+        variableList.variables.length == 1) {
+      var typeNode = variableList.type;
+      if (typeNode != null) {
+        var newType = initializer.typeOrThrow;
+        if (newType is InterfaceType || newType is FunctionType) {
+          _oldAnnotation = displayStringForType(typeNode.typeOrThrow);
+          _newAnnotation = displayStringForType(newType);
+          await builder.addDartFileEdit(file, (builder) {
+            builder.addReplacement(range.node(typeNode), (builder) {
+              builder.writeType(newType);
             });
-          }
+          });
         }
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_add_all_to_spread.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_add_all_to_spread.dart
index 06de8b9..c4fcbab 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_add_all_to_spread.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_add_all_to_spread.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:_fe_analyzer_shared/src/scanner/token.dart';
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
@@ -16,7 +14,7 @@
 
 class ConvertAddAllToSpread extends CorrectionProducer {
   /// The arguments used to compose the message.
-  List<String> _args;
+  List<String> _args = [];
 
   /// A flag indicating whether the change that was built is one that inlines
   /// the elements of another list into the target list.
@@ -45,22 +43,31 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    var node = this.node;
-    if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
+    var name = node;
+    if (name is! SimpleIdentifier) {
       return;
     }
-    SimpleIdentifier name = node;
-    MethodInvocation invocation = node.parent;
+
+    var invocation = name.parent;
+    if (invocation is! MethodInvocation) {
+      return;
+    }
+
     if (name != invocation.methodName ||
         name.name != 'addAll' ||
         !invocation.isCascaded ||
         invocation.argumentList.arguments.length != 1) {
       return;
     }
+
     var cascade = invocation.thisOrAncestorOfType<CascadeExpression>();
+    if (cascade == null) {
+      return;
+    }
+
     var sections = cascade.cascadeSections;
-    var target = cascade.target;
-    if (target is! ListLiteral || sections[0] != invocation) {
+    var targetList = cascade.target;
+    if (targetList is! ListLiteral || sections[0] != invocation) {
       // TODO(brianwilkerson) Consider extending this to handle set literals.
       return;
     }
@@ -68,9 +75,8 @@
     bool isEmptyListLiteral(Expression expression) =>
         expression is ListLiteral && expression.elements.isEmpty;
 
-    ListLiteral list = target;
     var argument = invocation.argumentList.arguments[0];
-    String elementText;
+    String? elementText;
     if (argument is BinaryExpression &&
         argument.operator.type == TokenType.QUESTION_QUESTION) {
       var right = argument.rightOperand;
@@ -105,13 +111,20 @@
     }
     elementText ??= '...${utils.getNodeText(argument)}';
 
+    final elementText_final = elementText;
     await builder.addDartFileEdit(file, (builder) {
-      if (list.elements.isNotEmpty) {
+      if (targetList.elements.isNotEmpty) {
         // ['a']..addAll(['b', 'c']);
-        builder.addSimpleInsertion(list.elements.last.end, ', $elementText');
+        builder.addSimpleInsertion(
+          targetList.elements.last.end,
+          ', $elementText_final',
+        );
       } else {
         // []..addAll(['b', 'c']);
-        builder.addSimpleInsertion(list.leftBracket.end, elementText);
+        builder.addSimpleInsertion(
+          targetList.leftBracket.end,
+          elementText_final,
+        );
       }
       builder.addDeletion(range.node(invocation));
     });
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_class_to_mixin.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_class_to_mixin.dart
index d54b755..f3184e4 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_class_to_mixin.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_class_to_mixin.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -38,7 +36,7 @@
     var superclassConstraints = <InterfaceType>[];
     var interfaces = <InterfaceType>[];
 
-    var classElement = classDeclaration.declaredElement;
+    var classElement = classDeclaration.declaredElement!;
     for (var type in classElement.mixins) {
       if (referencedClasses.contains(type.element)) {
         superclassConstraints.add(type);
@@ -46,12 +44,13 @@
         interfaces.add(type);
       }
     }
-    var extendsClause = classDeclaration.extendsClause;
-    if (extendsClause != null) {
+
+    var superType = classElement.supertype;
+    if (classDeclaration.extendsClause != null && superType != null) {
       if (referencedClasses.length > superclassConstraints.length) {
-        superclassConstraints.insert(0, classElement.supertype);
+        superclassConstraints.insert(0, superType);
       } else {
-        interfaces.insert(0, classElement.supertype);
+        interfaces.insert(0, superType);
       }
     }
     interfaces.addAll(classElement.interfaces);
@@ -63,8 +62,7 @@
               classDeclaration.leftBracket), (builder) {
         builder.write('mixin ');
         builder.write(classDeclaration.name.name);
-        builder.writeTypeParameters(
-            classDeclaration.declaredElement.typeParameters);
+        builder.writeTypeParameters(classElement.typeParameters);
         builder.writeTypes(superclassConstraints, prefix: ' on ');
         builder.writeTypes(interfaces, prefix: ' implements ');
         builder.write(' ');
@@ -100,7 +98,7 @@
     return super.visitSuperExpression(node);
   }
 
-  void _addElement(Element element) {
+  void _addElement(Element? element) {
     if (element is ExecutableElement) {
       var enclosingElement = element.enclosingElement;
       if (enclosingElement is ClassElement) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_conditional_expression_to_if_element.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_conditional_expression_to_if_element.dart
index 64feabda..e6294e5 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_conditional_expression_to_if_element.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_conditional_expression_to_if_element.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
@@ -25,18 +23,19 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    AstNode node = this.node.thisOrAncestorOfType<ConditionalExpression>();
-    if (node == null) {
+    var conditional = node.thisOrAncestorOfType<ConditionalExpression>();
+    if (conditional == null) {
       return null;
     }
-    var nodeToReplace = node;
-    var parent = node.parent;
+
+    AstNode nodeToReplace = conditional;
+    var parent = conditional.parent;
     while (parent is ParenthesizedExpression) {
       nodeToReplace = parent;
       parent = parent.parent;
     }
-    if (parent is ListLiteral || (parent is SetOrMapLiteral && parent.isSet)) {
-      ConditionalExpression conditional = node;
+
+    if (parent is ListLiteral || parent is SetOrMapLiteral && parent.isSet) {
       var condition = conditional.condition.unParenthesized;
       var thenExpression = conditional.thenExpression.unParenthesized;
       var elseExpression = conditional.elseExpression.unParenthesized;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_block.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_block.dart
index d3e57cf..7068e136 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_block.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_block.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:_fe_analyzer_shared/src/scanner/token.dart';
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart
index 5b7b37a..f82eeca 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:_fe_analyzer_shared/src/scanner/token.dart';
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_flutter_child.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_flutter_child.dart
index b767896..3556de0 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_flutter_child.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_flutter_child.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_flutter_children.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_flutter_children.dart
index 5e29768..c105653 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_flutter_children.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_flutter_children.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -17,26 +15,26 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    var node = this.node;
-    if (node is SimpleIdentifier &&
-        node.name == 'children' &&
-        node.parent?.parent is NamedExpression) {
-      NamedExpression named = node.parent?.parent;
-      var expression = named.expression;
-      if (expression is ListLiteral && expression.elements.length == 1) {
-        var widget = expression.elements[0];
-        if (flutter.isWidgetExpression(widget)) {
-          var widgetText = utils.getNodeText(widget);
-          var indentOld = utils.getLinePrefix(widget.offset);
-          var indentNew = utils.getLinePrefix(named.offset);
-          widgetText = _replaceSourceIndent(widgetText, indentOld, indentNew);
+    var identifier = node;
+    if (identifier is SimpleIdentifier && identifier.name == 'children') {
+      var namedExpression = identifier.parent?.parent;
+      if (namedExpression is NamedExpression) {
+        var expression = namedExpression.expression;
+        if (expression is ListLiteral && expression.elements.length == 1) {
+          var widget = expression.elements[0];
+          if (flutter.isWidgetExpression(widget)) {
+            var widgetText = utils.getNodeText(widget);
+            var indentOld = utils.getLinePrefix(widget.offset);
+            var indentNew = utils.getLinePrefix(namedExpression.offset);
+            widgetText = _replaceSourceIndent(widgetText, indentOld, indentNew);
 
-          await builder.addDartFileEdit(file, (builder) {
-            builder.addReplacement(range.node(named), (builder) {
-              builder.write('child: ');
-              builder.write(widgetText);
+            await builder.addDartFileEdit(file, (builder) {
+              builder.addReplacement(range.node(namedExpression), (builder) {
+                builder.write('child: ');
+                builder.write(widgetText);
+              });
             });
-          });
+          }
         }
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart
index 5373777..1ccaff4 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analyzer/dart/ast/ast.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_block_body.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_block_body.dart
index 20c3d7c..d674907 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_block_body.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_block_body.dart
@@ -2,11 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
@@ -23,7 +22,7 @@
       return;
     }
 
-    var returnValue = (body as ExpressionFunctionBody).expression;
+    var returnValue = body.expression;
 
     // Return expressions can be quite large, e.g. Flutter build() methods.
     // It is surprising to see this Quick Assist deep in the function body.
@@ -31,10 +30,10 @@
       return;
     }
 
-    var returnValueType = returnValue.staticType;
+    var returnValueType = returnValue.typeOrThrow;
     var returnValueCode = utils.getNodeText(returnValue);
     // prepare prefix
-    var prefix = utils.getNodePrefix(body.parent);
+    var prefix = utils.getNodePrefix(body.parent!);
     var indent = utils.getIndent(1);
 
     await builder.addDartFileEdit(file, (builder) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_final_field.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_final_field.dart
index 0cd856c..4e9ee8e 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_final_field.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_final_field.dart
@@ -2,10 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/utilities/extensions/ast.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
@@ -19,8 +18,8 @@
   @override
   Future<void> compute(ChangeBuilder builder) async {
     // Find the enclosing getter.
-    MethodDeclaration getter;
-    for (var n = node; n != null; n = n.parent) {
+    MethodDeclaration? getter;
+    for (var n in node.withParents) {
       if (n is MethodDeclaration) {
         getter = n;
         break;
@@ -32,9 +31,15 @@
       }
       break;
     }
-    if (getter == null || !getter.isGetter) {
+    if (getter == null) {
       return;
     }
+
+    var propertyKeywordGet = getter.propertyKeywordGet;
+    if (propertyKeywordGet == null) {
+      return;
+    }
+
     // Check that there is no corresponding setter.
     {
       var element = getter.declaredElement;
@@ -49,7 +54,7 @@
       }
     }
     // Try to find the returned expression.
-    Expression expression;
+    Expression? expression;
     {
       var body = getter.body;
       if (body is ExpressionFunctionBody) {
@@ -66,9 +71,10 @@
     }
     // Use the returned expression as the field initializer.
     if (expression != null) {
+      var returnType = getter.returnType;
       var code = 'final';
-      if (getter.returnType != null) {
-        code += ' ' + utils.getNodeText(getter.returnType);
+      if (returnType != null) {
+        code += ' ' + utils.getNodeText(returnType);
       }
       code += ' ' + utils.getNodeText(getter.name);
       if (expression is! NullLiteral) {
@@ -76,7 +82,7 @@
       }
       code += ';';
       var replacementRange =
-          range.startEnd(getter.returnType ?? getter.propertyKeyword, getter);
+          range.startEnd(returnType ?? propertyKeywordGet, getter);
       await builder.addDartFileEdit(file, (builder) {
         builder.addSimpleReplacement(replacementRange, code);
       });
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_for_index.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_for_index.dart
index 39c4e84..f7df358 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_for_index.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_for_index.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -20,15 +18,18 @@
   @override
   Future<void> compute(ChangeBuilder builder) async {
     // find enclosing ForEachStatement
-    var forEachStatement = node.thisOrAncestorMatching(
-            (node) => node is ForStatement && node.forLoopParts is ForEachParts)
-        as ForStatement;
-    if (forEachStatement == null) {
+    var forStatement = node.thisOrAncestorOfType<ForStatement>();
+    if (forStatement is! ForStatement) {
       return;
     }
-    ForEachParts forEachParts = forEachStatement.forLoopParts;
-    if (selectionOffset < forEachStatement.offset ||
-        forEachStatement.rightParenthesis.end < selectionOffset) {
+
+    var forEachParts = forStatement.forLoopParts;
+    if (forEachParts is! ForEachParts) {
+      return;
+    }
+
+    if (selectionOffset < forStatement.offset ||
+        forStatement.rightParenthesis.end < selectionOffset) {
       return;
     }
     // loop should declare variable
@@ -56,15 +57,15 @@
       }
     }
     // body should be Block
-    if (forEachStatement.body is! Block) {
+    var body = forStatement.body;
+    if (body is! Block) {
       return;
     }
-    Block body = forEachStatement.body;
     // prepare a name for the index variable
     String indexName;
     {
       var conflicts =
-          utils.findPossibleLocalVariableConflicts(forEachStatement.offset);
+          utils.findPossibleLocalVariableConflicts(forStatement.offset);
       if (!conflicts.contains('i')) {
         indexName = 'i';
       } else if (!conflicts.contains('j')) {
@@ -76,14 +77,14 @@
       }
     }
     // prepare environment
-    var prefix = utils.getNodePrefix(forEachStatement);
+    var prefix = utils.getNodePrefix(forStatement);
     var indent = utils.getIndent(1);
     var firstBlockLine = utils.getLineContentEnd(body.leftBracket.end);
     // add change
     await builder.addDartFileEdit(file, (builder) {
       // TODO(brianwilkerson) Create linked positions for the loop variable.
       builder.addSimpleReplacement(
-          range.startEnd(forEachStatement, forEachStatement.rightParenthesis),
+          range.startEnd(forStatement, forStatement.rightParenthesis),
           'for (int $indexName = 0; $indexName < $listName.length; $indexName++)');
       builder.addSimpleInsertion(firstBlockLine,
           '$prefix$indent$loopVariable = $listName[$indexName];$eol');
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_getter.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_getter.dart
index 75b47ca..a1f4d53 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_getter.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_getter.dart
@@ -2,10 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/utilities/extensions/ast.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -18,8 +17,8 @@
   @override
   Future<void> compute(ChangeBuilder builder) async {
     // Find the enclosing field declaration.
-    FieldDeclaration fieldDeclaration;
-    for (var n = node; n != null; n = n.parent) {
+    FieldDeclaration? fieldDeclaration;
+    for (var n in node.withParents) {
       if (n is FieldDeclaration) {
         fieldDeclaration = n;
         break;
@@ -38,7 +37,8 @@
     }
     // The field must be final and has only one variable.
     var fieldList = fieldDeclaration.fields;
-    if (!fieldList.isFinal || fieldList.variables.length != 1) {
+    var finalKeyword = fieldList.keyword;
+    if (finalKeyword == null || fieldList.variables.length != 1) {
       return;
     }
     var field = fieldList.variables.first;
@@ -49,14 +49,15 @@
     }
     // Add proposal.
     var code = '';
-    if (fieldList.type != null) {
-      code += utils.getNodeText(fieldList.type) + ' ';
+    var typeAnnotation = fieldList.type;
+    if (typeAnnotation != null) {
+      code += utils.getNodeText(typeAnnotation) + ' ';
     }
     code += 'get';
     code += ' ' + utils.getNodeText(field.name);
     code += ' => ' + utils.getNodeText(initializer);
     code += ';';
-    var replacementRange = range.startEnd(fieldList.keyword, fieldDeclaration);
+    var replacementRange = range.startEnd(finalKeyword, fieldDeclaration);
     await builder.addDartFileEdit(file, (builder) {
       builder.addSimpleReplacement(replacementRange, code);
     });
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_is_not.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_is_not.dart
index d39a67d..e84c81f 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_is_not.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_is_not.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
@@ -26,13 +24,17 @@
       var node = this.node;
       if (node is PrefixExpression) {
         var operand = node.operand;
-        if (operand is ParenthesizedExpression &&
-            operand.expression is IsExpression) {
-          isExpression = operand.expression as IsExpression;
+        if (operand is ParenthesizedExpression) {
+          var expression = operand.expression;
+          if (expression is IsExpression) {
+            isExpression = expression;
+          }
         }
-      } else if (node is ParenthesizedExpression &&
-          node.expression is IsExpression) {
-        isExpression = node.expression as IsExpression;
+      } else if (node is ParenthesizedExpression) {
+        var expression = node.expression;
+        if (expression is IsExpression) {
+          isExpression = expression;
+        }
       }
     }
     if (isExpression == null) {
@@ -42,21 +44,20 @@
       return;
     }
     // prepare enclosing ()
-    var parent = isExpression.parent;
-    if (parent is! ParenthesizedExpression) {
+    var parExpression = isExpression.parent;
+    if (parExpression is! ParenthesizedExpression) {
       return;
     }
-    var parExpression = parent as ParenthesizedExpression;
     // prepare enclosing !()
-    var parent2 = parent.parent;
-    if (parent2 is! PrefixExpression) {
+    var prefExpression = parExpression.parent;
+    if (prefExpression is! PrefixExpression) {
       return;
     }
-    var prefExpression = parent2 as PrefixExpression;
     if (prefExpression.operator.type != TokenType.BANG) {
       return;
     }
 
+    final isExpression_final = isExpression;
     await builder.addDartFileEdit(file, (builder) {
       if (getExpressionParentPrecedence(prefExpression) >=
           Precedence.relational) {
@@ -67,7 +68,7 @@
         builder.addDeletion(
             range.startEnd(parExpression.rightParenthesis, prefExpression));
       }
-      builder.addSimpleInsertion(isExpression.isOperator.end, '!');
+      builder.addSimpleInsertion(isExpression_final.isOperator.end, '!');
     });
   }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_is_not_empty.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_is_not_empty.dart
index e236dea..2e7cecb 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_is_not_empty.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_is_not_empty.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:_fe_analyzer_shared/src/scanner/token.dart';
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
@@ -20,8 +18,8 @@
   @override
   Future<void> compute(ChangeBuilder builder) async {
     // prepare "expr.isEmpty"
-    AstNode isEmptyAccess;
-    SimpleIdentifier isEmptyIdentifier;
+    SimpleIdentifier? isEmptyIdentifier;
+    AstNode? isEmptyAccess;
     if (node is SimpleIdentifier) {
       var identifier = node as SimpleIdentifier;
       var parent = identifier.parent;
@@ -36,7 +34,7 @@
         isEmptyAccess = parent;
       }
     }
-    if (isEmptyIdentifier == null) {
+    if (isEmptyIdentifier == null || isEmptyAccess == null) {
       return;
     }
     // should be "isEmpty"
@@ -60,10 +58,12 @@
       return;
     }
 
+    final isEmptyIdentifier_final = isEmptyIdentifier;
     await builder.addDartFileEdit(file, (builder) {
       builder.addDeletion(
           range.startStart(prefixExpression, prefixExpression.operand));
-      builder.addSimpleReplacement(range.node(isEmptyIdentifier), 'isNotEmpty');
+      builder.addSimpleReplacement(
+          range.node(isEmptyIdentifier_final), 'isNotEmpty');
     });
   }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_map_from_iterable_to_for_literal.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_map_from_iterable_to_for_literal.dart
index 20985e4..c6b8268 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_map_from_iterable_to_for_literal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_map_from_iterable_to_for_literal.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
@@ -51,41 +49,10 @@
     var secondArg = arguments[1];
     var thirdArg = arguments[2];
 
-    Expression extractBody(FunctionExpression expression) {
-      var body = expression.body;
-      if (body is ExpressionFunctionBody) {
-        return body.expression;
-      } else if (body is BlockFunctionBody) {
-        var statements = body.block.statements;
-        if (statements.length == 1) {
-          var statement = statements[0];
-          if (statement is ReturnStatement) {
-            return statement.expression;
-          }
-        }
-      }
-      return null;
-    }
-
-    FunctionExpression extractClosure(String name, Expression argument) {
-      if (argument is NamedExpression && argument.name.label.name == name) {
-        var expression = argument.expression.unParenthesized;
-        if (expression is FunctionExpression) {
-          var parameters = expression.parameters.parameters;
-          if (parameters.length == 1 && parameters[0].isRequiredPositional) {
-            if (extractBody(expression) != null) {
-              return expression;
-            }
-          }
-        }
-      }
-      return null;
-    }
-
     var keyClosure =
-        extractClosure('key', secondArg) ?? extractClosure('key', thirdArg);
-    var valueClosure =
-        extractClosure('value', thirdArg) ?? extractClosure('value', secondArg);
+        _extractClosure('key', secondArg) ?? _extractClosure('key', thirdArg);
+    var valueClosure = _extractClosure('value', thirdArg) ??
+        _extractClosure('value', secondArg);
     if (keyClosure == null || valueClosure == null) {
       return null;
     }
@@ -93,26 +60,23 @@
     // Compute the loop variable name and convert the key and value closures if
     // necessary.
     //
-    SimpleFormalParameter keyParameter = keyClosure.parameters.parameters[0];
-    var keyParameterName = keyParameter.identifier.name;
-    SimpleFormalParameter valueParameter =
-        valueClosure.parameters.parameters[0];
-    var valueParameterName = valueParameter.identifier.name;
-    var keyBody = extractBody(keyClosure);
-    var keyExpressionText = utils.getNodeText(keyBody);
-    var valueBody = extractBody(valueClosure);
-    var valueExpressionText = utils.getNodeText(valueBody);
+    var keyParameter = keyClosure.parameter;
+    var keyParameterName = keyClosure.parameterIdentifier.name;
+    var valueParameter = valueClosure.parameter;
+    var valueParameterName = valueClosure.parameterIdentifier.name;
+    var keyExpressionText = utils.getNodeText(keyClosure.body);
+    var valueExpressionText = utils.getNodeText(valueClosure.body);
 
     String loopVariableName;
     if (keyParameterName == valueParameterName) {
       loopVariableName = keyParameterName;
     } else {
-      var keyFinder = _ParameterReferenceFinder(keyParameter.declaredElement);
-      keyBody.accept(keyFinder);
+      var keyFinder = _ParameterReferenceFinder(keyParameter.declaredElement!);
+      keyClosure.body.accept(keyFinder);
 
       var valueFinder =
-          _ParameterReferenceFinder(valueParameter.declaredElement);
-      valueBody.accept(valueFinder);
+          _ParameterReferenceFinder(valueParameter.declaredElement!);
+      valueClosure.body.accept(valueFinder);
 
       String computeUnusedVariableName() {
         var candidate = 'e';
@@ -131,7 +95,7 @@
           // referenced in the value expression.
           loopVariableName = computeUnusedVariableName();
           keyExpressionText = keyFinder.replaceName(
-              keyExpressionText, loopVariableName, keyBody.offset);
+              keyExpressionText, loopVariableName, keyClosure.body.offset);
         } else {
           loopVariableName = keyParameterName;
         }
@@ -142,7 +106,7 @@
           // referenced in the key expression.
           loopVariableName = computeUnusedVariableName();
           valueExpressionText = valueFinder.replaceName(
-              valueExpressionText, loopVariableName, valueBody.offset);
+              valueExpressionText, loopVariableName, valueClosure.body.offset);
         } else {
           loopVariableName = valueParameterName;
         }
@@ -152,9 +116,9 @@
         // either the key or value expressions.
         loopVariableName = computeUnusedVariableName();
         keyExpressionText = keyFinder.replaceName(
-            keyExpressionText, loopVariableName, keyBody.offset);
+            keyExpressionText, loopVariableName, keyClosure.body.offset);
         valueExpressionText = valueFinder.replaceName(
-            valueExpressionText, loopVariableName, valueBody.offset);
+            valueExpressionText, loopVariableName, valueClosure.body.offset);
       }
     }
     //
@@ -178,6 +142,56 @@
   /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
   static ConvertMapFromIterableToForLiteral newInstance() =>
       ConvertMapFromIterableToForLiteral();
+
+  static Expression? _extractBody(FunctionExpression expression) {
+    var body = expression.body;
+    if (body is ExpressionFunctionBody) {
+      return body.expression;
+    } else if (body is BlockFunctionBody) {
+      var statements = body.block.statements;
+      if (statements.length == 1) {
+        var statement = statements[0];
+        if (statement is ReturnStatement) {
+          return statement.expression;
+        }
+      }
+    }
+    return null;
+  }
+
+  static _Closure? _extractClosure(String name, Expression argument) {
+    if (argument is NamedExpression && argument.name.label.name == name) {
+      var expression = argument.expression.unParenthesized;
+      if (expression is FunctionExpression) {
+        var parameterList = expression.parameters;
+        if (parameterList != null) {
+          var parameters = parameterList.parameters;
+          if (parameters.length == 1) {
+            var parameter = parameters[0];
+            if (parameter is SimpleFormalParameter &&
+                parameter.isRequiredPositional) {
+              var parameterIdentifier = parameter.identifier;
+              if (parameterIdentifier != null) {
+                var body = _extractBody(expression);
+                if (body != null) {
+                  return _Closure(parameter, parameterIdentifier, body);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    return null;
+  }
+}
+
+class _Closure {
+  final SimpleFormalParameter parameter;
+  final SimpleIdentifier parameterIdentifier;
+  final Expression body;
+
+  _Closure(this.parameter, this.parameterIdentifier, this.body);
 }
 
 /// A visitor that can be used to find references to a parameter.
@@ -195,7 +209,7 @@
   final Set<String> otherNames = <String>{};
 
   /// Initialize a newly created finder to find references to the [parameter].
-  _ParameterReferenceFinder(this.parameter) : assert(parameter != null);
+  _ParameterReferenceFinder(this.parameter);
 
   /// Return `true` if the parameter is unreferenced in the nodes that have been
   /// visited.
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_part_of_to_uri.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_part_of_to_uri.dart
index e532273..0f22239 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_part_of_to_uri.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_part_of_to_uri.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -19,14 +17,20 @@
   @override
   Future<void> compute(ChangeBuilder builder) async {
     var directive = node.thisOrAncestorOfType<PartOfDirective>();
-    if (directive == null || directive.libraryName == null) {
+    if (directive == null) {
       return;
     }
+
+    var libraryName = directive.libraryName;
+    if (libraryName == null) {
+      return;
+    }
+
     var libraryPath = resolvedResult.libraryElement.source.fullName;
-    var partPath = resolvedResult.path;
+    var partPath = resolvedResult.path!;
     var relativePath = relative(libraryPath, from: dirname(partPath));
     var uri = Uri.file(relativePath).toString();
-    var replacementRange = range.node(directive.libraryName);
+    var replacementRange = range.node(libraryName);
     await builder.addDartFileEdit(file, (builder) {
       builder.addSimpleReplacement(replacementRange, "'$uri'");
     });
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_quotes.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_quotes.dart
index c853070..5e45165 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_quotes.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_quotes.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
@@ -22,56 +20,72 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
+    var node = this.node;
     if (node is SimpleStringLiteral) {
-      SimpleStringLiteral literal = node;
-      if (_fromDouble ? !literal.isSingleQuoted : literal.isSingleQuoted) {
-        var newQuote = literal.isMultiline
-            ? (_fromDouble ? "'''" : '"""')
-            : (_fromDouble ? "'" : '"');
-        var quoteLength = literal.isMultiline ? 3 : 1;
-        var token = literal.literal;
-        if (!token.isSynthetic && !token.lexeme.contains(newQuote)) {
-          await builder.addDartFileEdit(file, (builder) {
-            builder.addSimpleReplacement(
-                SourceRange(
-                    literal.offset + (literal.isRaw ? 1 : 0), quoteLength),
-                newQuote);
-            builder.addSimpleReplacement(
-                SourceRange(literal.end - quoteLength, quoteLength), newQuote);
-          });
-        }
-      }
-    } else if (node is InterpolationString || node is StringInterpolation) {
-      StringInterpolation stringNode =
-          node is StringInterpolation ? node : node.parent;
-      if (_fromDouble
-          ? !stringNode.isSingleQuoted
-          : stringNode.isSingleQuoted) {
-        var newQuote = stringNode.isMultiline
-            ? (_fromDouble ? "'''" : '"""')
-            : (_fromDouble ? "'" : '"');
-        var quoteLength = stringNode.isMultiline ? 3 : 1;
-        var elements = stringNode.elements;
-        for (var i = 0; i < elements.length; i++) {
-          var element = elements[i];
-          if (element is InterpolationString) {
-            var token = element.contents;
-            if (token.isSynthetic || token.lexeme.contains(newQuote)) {
-              return null;
-            }
-          }
-        }
+      await _simpleStringLiteral(builder, node);
+    } else if (node is StringInterpolation) {
+      await _stringInterpolation(builder, node);
+    } else if (node is InterpolationString) {
+      await _stringInterpolation(builder, node.parent as StringInterpolation);
+    }
+  }
+
+  Future<void> _simpleStringLiteral(
+    ChangeBuilder builder,
+    SimpleStringLiteral node,
+  ) async {
+    if (_fromDouble ? !node.isSingleQuoted : node.isSingleQuoted) {
+      var newQuote = node.isMultiline
+          ? (_fromDouble ? "'''" : '"""')
+          : (_fromDouble ? "'" : '"');
+      var quoteLength = node.isMultiline ? 3 : 1;
+      var token = node.literal;
+      if (!token.isSynthetic && !token.lexeme.contains(newQuote)) {
         await builder.addDartFileEdit(file, (builder) {
           builder.addSimpleReplacement(
-              SourceRange(
-                  stringNode.offset + (stringNode.isRaw ? 1 : 0), quoteLength),
-              newQuote);
+            SourceRange(node.offset + (node.isRaw ? 1 : 0), quoteLength),
+            newQuote,
+          );
           builder.addSimpleReplacement(
-              SourceRange(stringNode.end - quoteLength, quoteLength), newQuote);
+            SourceRange(node.end - quoteLength, quoteLength),
+            newQuote,
+          );
         });
       }
     }
   }
+
+  Future<void> _stringInterpolation(
+    ChangeBuilder builder,
+    StringInterpolation node,
+  ) async {
+    if (_fromDouble ? !node.isSingleQuoted : node.isSingleQuoted) {
+      var newQuote = node.isMultiline
+          ? (_fromDouble ? "'''" : '"""')
+          : (_fromDouble ? "'" : '"');
+      var quoteLength = node.isMultiline ? 3 : 1;
+      var elements = node.elements;
+      for (var i = 0; i < elements.length; i++) {
+        var element = elements[i];
+        if (element is InterpolationString) {
+          var token = element.contents;
+          if (token.isSynthetic || token.lexeme.contains(newQuote)) {
+            return;
+          }
+        }
+      }
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addSimpleReplacement(
+          SourceRange(node.offset + (node.isRaw ? 1 : 0), quoteLength),
+          newQuote,
+        );
+        builder.addSimpleReplacement(
+          SourceRange(node.end - quoteLength, quoteLength),
+          newQuote,
+        );
+      });
+    }
+  }
 }
 
 class ConvertToDoubleQuotes extends ConvertQuotes {
diff --git a/pkg/analysis_server/lib/src/services/correction/executable_parameters.dart b/pkg/analysis_server/lib/src/services/correction/executable_parameters.dart
index 30c2497..7200eec 100644
--- a/pkg/analysis_server/lib/src/services/correction/executable_parameters.dart
+++ b/pkg/analysis_server/lib/src/services/correction/executable_parameters.dart
@@ -67,7 +67,7 @@
   }
 
   static ExecutableParameters? forInvocation(
-      AnalysisSessionHelper sessionHelper, AstNode invocation) {
+      AnalysisSessionHelper sessionHelper, AstNode? invocation) {
     Element? element;
     // This doesn't handle FunctionExpressionInvocation.
     if (invocation is Annotation) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/manifest/fix_generator.dart b/pkg/analysis_server/lib/src/services/correction/fix/manifest/fix_generator.dart
index 1cc8e81..ea85122 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/manifest/fix_generator.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/manifest/fix_generator.dart
@@ -7,7 +7,6 @@
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
 import 'package:analysis_server/src/utilities/strings.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/manifest/manifest_warning_code.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart b/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart
index f21a745..2a96fb7 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart
@@ -7,7 +7,6 @@
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
 import 'package:analysis_server/src/utilities/strings.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/pubspec/pubspec_warning_code.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index e69df10..7480d17 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -28,7 +28,7 @@
     show SourceChange, SourceEdit;
 import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
-import 'package:path/path.dart' as pathos;
+import 'package:path/path.dart' as path;
 
 /// Adds edits to the given [change] that ensure that all the [libraries] are
 /// imported into the given [targetLibrary].
@@ -317,7 +317,7 @@
 
 /// Computes the best URI to import [what] into [from].
 String getLibrarySourceUri(
-    pathos.Context pathContext, LibraryElement from, Uri what) {
+    path.Context pathContext, LibraryElement from, Uri what) {
   if (what.scheme == 'file') {
     var fromFolder = pathContext.dirname(from.source.fullName);
     var relativeFile = pathContext.relative(what.path, from: fromFolder);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart b/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart
index 735bed9..79bf48c 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Keyword;
 import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/utilities/strings.dart';
@@ -21,7 +19,7 @@
 /// - OK if the name is valid;
 /// - WARNING if the name is discouraged;
 /// - FATAL if the name is illegal.
-RefactoringStatus validateConstructorName(String name) {
+RefactoringStatus validateConstructorName(String? name) {
   if (name != null && name.isEmpty) {
     return RefactoringStatus();
   }
@@ -48,7 +46,7 @@
 /// - OK if the name is valid;
 /// - WARNING if the name is discouraged;
 /// - FATAL if the name is illegal.
-RefactoringStatus validateImportPrefixName(String name) {
+RefactoringStatus validateImportPrefixName(String? name) {
   if (name != null && name.isEmpty) {
     return RefactoringStatus();
   }
@@ -67,7 +65,7 @@
 /// - OK if the name is valid;
 /// - WARNING if the name is discouraged;
 /// - FATAL if the name is illegal.
-RefactoringStatus validateLibraryName(String name) {
+RefactoringStatus validateLibraryName(String? name) {
   // null
   if (name == null) {
     return RefactoringStatus.fatal('Library name must not be null.');
@@ -182,7 +180,7 @@
 }
 
 /// Validates [identifier], should be lower camel case.
-RefactoringStatus _validateLowerCamelCase(String identifier, String desc,
+RefactoringStatus _validateLowerCamelCase(String? identifier, String desc,
     {bool allowBuiltIn = false}) {
   desc += ' name';
   // null
@@ -215,7 +213,7 @@
 }
 
 /// Validate the given identifier, which should be upper camel case.
-RefactoringStatus _validateUpperCamelCase(String identifier, String desc) {
+RefactoringStatus _validateUpperCamelCase(String? identifier, String desc) {
   desc += ' name';
   // null
   if (identifier == null) {
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/ast.dart b/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
index c6d2078..3448861 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/src/utilities/extensions/element.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 
 extension AstNodeExtensions on AstNode {
@@ -102,3 +103,19 @@
       this is EmptyFunctionBody ||
       (this is BlockFunctionBody && beginToken.isSynthetic);
 }
+
+extension MethodDeclarationExtension on MethodDeclaration {
+  Token? get propertyKeywordGet {
+    var propertyKeyword = this.propertyKeyword;
+    return propertyKeyword != null && propertyKeyword.keyword == Keyword.GET
+        ? propertyKeyword
+        : null;
+  }
+}
+
+extension VariableDeclarationListExtension on VariableDeclarationList {
+  Token? get finalKeyword {
+    var keyword = this.keyword;
+    return keyword != null && keyword.keyword == Keyword.FINAL ? keyword : null;
+  }
+}
diff --git a/pkg/analysis_server/test/integration/support/integration_tests.dart b/pkg/analysis_server/test/integration/support/integration_tests.dart
index 5b1c58d..827f06d 100644
--- a/pkg/analysis_server/test/integration/support/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/support/integration_tests.dart
@@ -11,8 +11,7 @@
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
-import 'package:path/path.dart';
-import 'package:path/path.dart' as pkg_path;
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 
 import 'integration_test_methods.dart';
@@ -213,7 +212,8 @@
   /// relative to [sourceDirectory].  On Windows any forward slashes in
   /// [relativePath] are converted to backslashes.
   String sourcePath(String relativePath) {
-    return join(sourceDirectory.path, relativePath.replaceAll('/', separator));
+    return path.join(
+        sourceDirectory.path, relativePath.replaceAll('/', path.separator));
   }
 
   /// Send the server an 'analysis.setAnalysisRoots' command directing it to
@@ -254,20 +254,20 @@
   ///
   /// Return a normalized path to the file (with symbolic links resolved).
   String writeFile(String pathname, String contents) {
-    Directory(dirname(pathname)).createSync(recursive: true);
+    Directory(path.dirname(pathname)).createSync(recursive: true);
     var file = File(pathname);
     file.writeAsStringSync(contents);
     return file.resolveSymbolicLinksSync();
   }
 
   void writePackageConfig(
-    String path, {
+    String pathname, {
     required PackageConfigFileBuilder config,
   }) {
     writeFile(
-      path,
+      pathname,
       config.toContent(
-        toUriStr: (path) => '${pkg_path.toUri(path)}',
+        toUriStr: (p) => '${path.toUri(p)}',
       ),
     );
   }
@@ -483,14 +483,14 @@
   /// Find the root directory of the analysis_server package by proceeding
   /// upward to the 'test' dir, and then going up one more directory.
   String findRoot(String pathname) {
-    while (!['benchmark', 'test'].contains(basename(pathname))) {
-      var parent = dirname(pathname);
+    while (!['benchmark', 'test'].contains(path.basename(pathname))) {
+      var parent = path.dirname(pathname);
       if (parent.length >= pathname.length) {
         throw Exception("Can't find root directory");
       }
       pathname = parent;
     }
-    return dirname(pathname);
+    return path.dirname(pathname);
   }
 
   /// Return a future that will complete when all commands that have been sent
@@ -620,18 +620,24 @@
 
     if (useSnapshot) {
       // Look for snapshots/analysis_server.dart.snapshot.
-      serverPath = normalize(join(dirname(Platform.resolvedExecutable),
-          'snapshots', 'analysis_server.dart.snapshot'));
+      serverPath = path.normalize(path.join(
+          path.dirname(Platform.resolvedExecutable),
+          'snapshots',
+          'analysis_server.dart.snapshot'));
 
       if (!FileSystemEntity.isFileSync(serverPath)) {
         // Look for dart-sdk/bin/snapshots/analysis_server.dart.snapshot.
-        serverPath = normalize(join(dirname(Platform.resolvedExecutable),
-            'dart-sdk', 'bin', 'snapshots', 'analysis_server.dart.snapshot'));
+        serverPath = path.normalize(path.join(
+            path.dirname(Platform.resolvedExecutable),
+            'dart-sdk',
+            'bin',
+            'snapshots',
+            'analysis_server.dart.snapshot'));
       }
     } else {
       var rootDir =
           findRoot(Platform.script.toFilePath(windows: Platform.isWindows));
-      serverPath = normalize(join(rootDir, 'bin', 'server.dart'));
+      serverPath = path.normalize(path.join(rootDir, 'bin', 'server.dart'));
     }
 
     var arguments = <String>[
diff --git a/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart b/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
index 9bec4ca..6d7431c 100644
--- a/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
+++ b/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
@@ -26,9 +26,17 @@
     workspaceFolder1Path = convertPath('/workspace1');
     workspaceFolder2Path = convertPath('/workspace2');
     workspaceFolder3Path = convertPath('/workspace3');
+    newFolder(workspaceFolder1Path);
+    newFolder(workspaceFolder2Path);
+    newFolder(workspaceFolder3Path);
+
     workspaceFolder1Uri = Uri.file(workspaceFolder1Path);
     workspaceFolder2Uri = Uri.file(workspaceFolder2Path);
     workspaceFolder3Uri = Uri.file(workspaceFolder3Path);
+
+    newFile(join(workspaceFolder1Path, 'pubspec.yaml'));
+    newFile(join(workspaceFolder2Path, 'pubspec.yaml'));
+    newFile(join(workspaceFolder3Path, 'pubspec.yaml'));
   }
 
   Future<void> test_changeWorkspaceFolders_add() async {
@@ -75,23 +83,27 @@
     // Expect implicit root for the open file.
     expect(
       server.contextManager.includedPaths,
-      unorderedEquals([nestedFolderPath]),
+      unorderedEquals([workspaceFolder1Path]),
     );
 
-    // Add the real project root to the workspace (which should become an
-    // explicit root).
+    // Add the real project root to the workspace (which will become an
+    // explicit root but not change anything or rebuild contexts).
+    resetContextBuildCounter();
     await changeWorkspaceFolders(add: [workspaceFolder1Uri]);
     expect(
       server.contextManager.includedPaths,
-      unorderedEquals([workspaceFolder1Path, nestedFolderPath]),
+      unorderedEquals([workspaceFolder1Path]),
     );
+    expectNoContextBuilds();
 
-    // Closing the file should not result in the project being removed.
+    // Closing the file should not change roots nor trigger a rebuild.
+    resetContextBuildCounter();
     await closeFile(nestedFileUri);
     expect(
       server.contextManager.includedPaths,
       unorderedEquals([workspaceFolder1Path]),
     );
+    expectNoContextBuilds();
   }
 
   Future<void>
@@ -108,24 +120,28 @@
     // Expect implicit root for the open file.
     expect(
       server.contextManager.includedPaths,
-      unorderedEquals([nestedFolderPath]),
+      unorderedEquals([workspaceFolder1Path]),
     );
 
-    // Add the real project root to the workspace (which should become an
-    // explicit root).
+    // Add the real project root to the workspace (which will become an
+    // explicit root but not change anything or rebuild contexts).
+    resetContextBuildCounter();
     await changeWorkspaceFolders(add: [workspaceFolder1Uri]);
     expect(
       server.contextManager.includedPaths,
-      unorderedEquals([workspaceFolder1Path, nestedFolderPath]),
+      unorderedEquals([workspaceFolder1Path]),
     );
+    expectNoContextBuilds();
 
-    // Removing the workspace folder should result in falling back to just the
-    // nested folder.
-    await changeWorkspaceFolders(remove: [workspaceFolder1Uri]);
+    // Removing the workspace folder should not change roots nor trigger a
+    // rebuild because the root is still the implicit root for the open file.
+    resetContextBuildCounter();
+    await closeFile(nestedFileUri);
     expect(
       server.contextManager.includedPaths,
-      unorderedEquals([nestedFolderPath]),
+      unorderedEquals([workspaceFolder1Path]),
     );
+    expectNoContextBuilds();
   }
 
   Future<void>
@@ -144,20 +160,23 @@
       unorderedEquals([workspaceFolder1Path]),
     );
 
-    // Open a file, though no new root is expected as it was mapped to the existing
-    // open folder.
+    // An open file should not trigger any changes or rebuilds.
+    resetContextBuildCounter();
     await openFile(nestedFileUri, '');
     expect(
       server.contextManager.includedPaths,
       unorderedEquals([workspaceFolder1Path]),
     );
+    expectNoContextBuilds();
 
-    // Closing the file should not result in the project being removed.
+    // Closing the file should also not trigger any changes.
+    resetContextBuildCounter();
     await closeFile(nestedFileUri);
     expect(
       server.contextManager.includedPaths,
       unorderedEquals([workspaceFolder1Path]),
     );
+    expectNoContextBuilds();
   }
 
   Future<void>
@@ -176,32 +195,61 @@
       unorderedEquals([workspaceFolder1Path]),
     );
 
-    // Open a file, though no new root is expected as it was mapped to the existing
-    // open folder.
+    // Open a file, though no new root (or rebuild) is expected as it was mapped
+    // to the existing open project folder.
+    resetContextBuildCounter();
     await openFile(nestedFileUri, '');
     expect(
       server.contextManager.includedPaths,
       unorderedEquals([workspaceFolder1Path]),
     );
+    expectNoContextBuilds();
 
     // Removing the workspace folder will retain the workspace folder, as that's
-    // the folder we picked when the file was opened since there was already
-    // a root for it.
+    // the project root.
+    resetContextBuildCounter();
     await changeWorkspaceFolders(remove: [workspaceFolder1Uri]);
     expect(
       server.contextManager.includedPaths,
       unorderedEquals([workspaceFolder1Path]),
     );
+    expectNoContextBuilds();
+  }
+
+  Future<void> test_changeWorkspaceFolders_implicitFile_noProject() async {
+    final nestedFolderPath =
+        join(workspaceFolder1Path, 'nested', 'deeply', 'in', 'folders');
+    final nestedFilePath = join(nestedFolderPath, 'test.dart');
+    final nestedFileUri = Uri.file(nestedFilePath);
+    newFile(nestedFilePath);
+    deleteFile(join(
+        workspaceFolder1Path, 'pubspec.yaml')); // Ensure no pubspecs in tree.
+
+    await initialize(allowEmptyRootUri: true);
+    await openFile(nestedFileUri, '');
+
+    // Because there is no pubspec in the tree and we don't locate a root, we
+    // expect the file to be analyzed solo.
+    expect(
+      server.contextManager.includedPaths,
+      unorderedEquals([nestedFilePath]),
+    );
+
+    // Adding the parent folder will switch to using that as the root and rebuild
+    // the root.
+    resetContextBuildCounter();
+    await changeWorkspaceFolders(add: [workspaceFolder1Uri]);
+    expect(
+      server.contextManager.includedPaths,
+      unorderedEquals([workspaceFolder1Path]),
+    );
+    expectContextBuilds();
   }
 
   Future<void> test_changeWorkspaceFolders_openFileOutsideRoot() async {
     // When a file is opened that is outside of the analysis roots, the first
-    // analysis driver will be used (see [AbstractAnalysisServer.getAnalysisDriver]).
-    // This means as long as there is already an analysis root, the implicit root
-    // will be the original root and not the path of the opened file.
-    // For example, Go-to-Definition into a file in PubCache must *not* result in
-    // the pub cache folder being added as an analysis root, it should be analyzed
-    // by the existing project's driver.
+    // analysis driver will be used (see [AbstractAnalysisServer.getAnalysisDriver])
+    // and no new root will be created.
     final workspace1FilePath = join(workspaceFolder1Path, 'test.dart');
     newFile(workspace1FilePath);
     final workspace2FilePath = join(workspaceFolder2Path, 'test.dart');
@@ -216,19 +264,24 @@
       unorderedEquals([workspaceFolder1Path]),
     );
 
-    // Open a file in workspaceFolder2 (which is not in the analysis roots).
+    // Open a file in workspaceFolder2 which will reuse the existing driver for
+    // workspace1 so not change roots/trigger a rebuild.
+    resetContextBuildCounter();
     await openFile(workspace2FileUri, '');
     expect(
       server.contextManager.includedPaths,
       unorderedEquals([workspaceFolder1Path]),
     );
+    expectNoContextBuilds();
 
-    // Closing the file should not result in the project being removed.
+    // Closing the file will also not trigger any changes.
+    resetContextBuildCounter();
     await closeFile(workspace2FileUri);
     expect(
       server.contextManager.includedPaths,
       unorderedEquals([workspaceFolder1Path]),
     );
+    expectNoContextBuilds();
   }
 
   Future<void> test_changeWorkspaceFolders_remove() async {
diff --git a/pkg/analysis_server/test/lsp/configuration_test.dart b/pkg/analysis_server/test/lsp/configuration_test.dart
index 980af42..bf57ef4 100644
--- a/pkg/analysis_server/test/lsp/configuration_test.dart
+++ b/pkg/analysis_server/test/lsp/configuration_test.dart
@@ -58,7 +58,7 @@
       {}, // Empty config
     );
 
-    // Ensure the roots are as expected before we udpate the config.
+    // Ensure the roots are as expected before we update the config.
     expect(server.contextManager.includedPaths, equals([projectFolderPath]));
     expect(server.contextManager.excludedPaths, isEmpty);
 
diff --git a/pkg/analysis_server/test/lsp/diagnostic_test.dart b/pkg/analysis_server/test/lsp/diagnostic_test.dart
index 46ace8a..a380a07 100644
--- a/pkg/analysis_server/test/lsp/diagnostic_test.dart
+++ b/pkg/analysis_server/test/lsp/diagnostic_test.dart
@@ -285,6 +285,28 @@
     expect(diagnostic.range.end.character, equals(12));
   }
 
+  Future<void> test_looseFile_withoutPubpsec() async {
+    await initialize(allowEmptyRootUri: true);
+
+    // Opening the file should trigger diagnostics.
+    {
+      final diagnosticsUpdate = waitForDiagnostics(mainFileUri);
+      await openFile(mainFileUri, 'final a = Bad();');
+      final diagnostics = await diagnosticsUpdate;
+      expect(diagnostics, hasLength(1));
+      final diagnostic = diagnostics.first;
+      expect(diagnostic.message, contains("The function 'Bad' isn't defined"));
+    }
+
+    // Closing the file should remove the diagnostics.
+    {
+      final diagnosticsUpdate = waitForDiagnostics(mainFileUri);
+      await closeFile(mainFileUri);
+      final diagnostics = await diagnosticsUpdate;
+      expect(diagnostics, hasLength(0));
+    }
+  }
+
   Future<void> test_todos() async {
     // TODOs only show up if there's also some code in the file.
     const contents = '''
diff --git a/pkg/analysis_server/test/lsp/document_changes_test.dart b/pkg/analysis_server/test/lsp/document_changes_test.dart
index 0c8f181..361ee23 100644
--- a/pkg/analysis_server/test/lsp/document_changes_test.dart
+++ b/pkg/analysis_server/test/lsp/document_changes_test.dart
@@ -102,6 +102,25 @@
         equals({mainFilePath: RemoveContentOverlay()}));
   }
 
+  Future<void>
+      test_documentOpen_addsOverlayOnlyToDriver_onlyIfInsideRoots() async {
+    // Ensures that opening a file doesn't add it to the driver if it's outside
+    // of the drivers root.
+    final fileInsideRootPath = mainFilePath;
+    final fileOutsideRootPath = convertPath('/home/unrelated/main.dart');
+    await initialize();
+    await openFile(Uri.file(fileInsideRootPath), content);
+    await openFile(Uri.file(fileOutsideRootPath), content);
+
+    // Expect both files return the same driver
+    final driverForInside = server.getAnalysisDriver(fileInsideRootPath);
+    final driverForOutside = server.getAnalysisDriver(fileOutsideRootPath);
+    expect(driverForInside, equals(driverForOutside));
+    // But that only the file inside the root was added.
+    expect(driverForInside.addedFiles, contains(fileInsideRootPath));
+    expect(driverForInside.addedFiles, isNot(contains(fileOutsideRootPath)));
+  }
+
   Future<void> test_documentOpen_createsOverlay() async {
     await _initializeAndOpen();
 
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index 032df8d..0bd91e3 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -10,7 +10,6 @@
 import 'package:analysis_server/src/lsp/json_parsing.dart';
 import 'package:analysis_server/src/lsp/server_capabilities_computer.dart';
 import 'package:analysis_server/src/plugin/plugin_manager.dart';
-import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -299,15 +298,22 @@
 
     // Closing only one of the files should not remove the project folder
     // since there are still open files.
+    resetContextBuildCounter();
     await closeFile(file1Uri);
     expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+    expectNoContextBuilds();
 
-    // Closing the last file should remove the project folder.
+    // Closing the last file should remove the project folder and remove
+    // the context.
+    resetContextBuildCounter();
     await closeFile(file2Uri);
     expect(server.contextManager.includedPaths, equals([]));
+    expect(server.contextManager.driverMap, hasLength(0));
+    expectContextBuilds();
   }
 
   Future<void> test_emptyAnalysisRoots_projectWithoutPubspec() async {
+    projectFolderPath = '/home/empty';
     final nestedFilePath = join(
         projectFolderPath, 'nested', 'deeply', 'in', 'folders', 'test.dart');
     final nestedFileUri = Uri.file(nestedFilePath);
@@ -317,10 +323,9 @@
     await initialize(allowEmptyRootUri: true);
     expect(server.contextManager.includedPaths, equals([]));
 
-    // Opening the file should trigger the immediate parent folder to be added.
+    // Opening the file will add a root for it.
     await openFile(nestedFileUri, '');
-    expect(server.contextManager.includedPaths,
-        equals([path.dirname(nestedFilePath)]));
+    expect(server.contextManager.includedPaths, equals([nestedFilePath]));
   }
 
   Future<void> test_emptyAnalysisRoots_projectWithPubspec() async {
@@ -510,18 +515,26 @@
     await openFile(file1Uri, '');
     await openFile(file2Uri, '');
     expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+    expect(server.contextManager.driverMap, hasLength(1));
 
-    // Closing only one of the files should not remove the project folder
-    // since there are still open files.
+    // Closing only one of the files should not remove the root or rebuild the context.
+    resetContextBuildCounter();
     await closeFile(file1Uri);
     expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+    expect(server.contextManager.driverMap, hasLength(1));
+    expectNoContextBuilds();
 
-    // Closing the last file should remove the project folder.
+    // Closing the last file should remove the project folder and remove
+    // the context.
+    resetContextBuildCounter();
     await closeFile(file2Uri);
     expect(server.contextManager.includedPaths, equals([]));
+    expect(server.contextManager.driverMap, hasLength(0));
+    expectContextBuilds();
   }
 
   Future<void> test_onlyAnalyzeProjectsWithOpenFiles_withoutPubpsec() async {
+    projectFolderPath = '/home/empty';
     final nestedFilePath = join(
         projectFolderPath, 'nested', 'deeply', 'in', 'folders', 'test.dart');
     final nestedFileUri = Uri.file(nestedFilePath);
@@ -534,10 +547,9 @@
     );
     expect(server.contextManager.includedPaths, equals([]));
 
-    // Opening the file should trigger the immediate parent folder to be added.
+    // Opening the file should trigger it to be added.
     await openFile(nestedFileUri, '');
-    expect(server.contextManager.includedPaths,
-        equals([path.dirname(nestedFilePath)]));
+    expect(server.contextManager.includedPaths, equals([nestedFilePath]));
   }
 
   Future<void> test_onlyAnalyzeProjectsWithOpenFiles_withPubpsec() async {
@@ -555,7 +567,8 @@
     );
     expect(server.contextManager.includedPaths, equals([]));
 
-    // Opening a file nested within the project should add the project folder.
+    // Opening a file nested within the project should cause the project folder
+    // to be added
     await openFile(nestedFileUri, '');
     expect(server.contextManager.includedPaths, equals([projectFolderPath]));
 
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 1f18e72..b99c4fe 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -56,6 +56,10 @@
   LspAnalysisServer server;
   MockHttpClient httpClient;
 
+  /// The number of context builds that had already occurred the last time
+  /// resetContextBuildCounter() was called.
+  int _previousContextBuilds = 0;
+
   AnalysisServerOptions get serverOptions => AnalysisServerOptions();
 
   @override
@@ -84,6 +88,14 @@
     return info;
   }
 
+  void expectContextBuilds() =>
+      expect(server.contextBuilds - _previousContextBuilds, greaterThan(0),
+          reason: 'Contexts should have been rebuilt');
+
+  void expectNoContextBuilds() =>
+      expect(server.contextBuilds - _previousContextBuilds, equals(0),
+          reason: 'Contexts should not have been rebuilt');
+
   /// Sends a request to the server and unwraps the result. Throws if the
   /// response was not successful or returned an error.
   @override
@@ -106,6 +118,10 @@
         orElse: () => null);
   }
 
+  void resetContextBuildCounter() {
+    _previousContextBuilds = server.contextBuilds;
+  }
+
   @override
   Future sendNotificationToServer(NotificationMessage notification) async {
     channel.sendNotificationToServer(notification);
diff --git a/pkg/analysis_server/test/services/correction/test_all.dart b/pkg/analysis_server/test/services/correction/test_all.dart
index de358b6..0b289d9 100644
--- a/pkg/analysis_server/test/services/correction/test_all.dart
+++ b/pkg/analysis_server/test/services/correction/test_all.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'change_test.dart' as change_test;
diff --git a/pkg/analysis_server/test/src/computer/folding_computer_test.dart b/pkg/analysis_server/test/src/computer/folding_computer_test.dart
index 6f1df02..2ef0286 100644
--- a/pkg/analysis_server/test/src/computer/folding_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/folding_computer_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/computer/computer_folding.dart';
 import 'package:analysis_server/src/protocol_server.dart';
 import 'package:test/test.dart';
@@ -25,7 +23,7 @@
     FoldingKind.DOCUMENTATION_COMMENT
   };
 
-  String sourcePath;
+  late String sourcePath;
 
   @override
   void setUp() {
@@ -515,7 +513,7 @@
   ///
   /// If [onlyKinds] is supplied only regions of that type will be compared.
   void _compareRegions(List<FoldingRegion> regions, String content,
-      [Set<FoldingKind> onlyKinds]) {
+      [Set<FoldingKind>? onlyKinds]) {
     // Find all numeric markers for region starts.
     final regex = RegExp(r'/\*(\d+):(INC|EXC)\*/');
     final expectedRegions = regex.allMatches(content);
@@ -535,7 +533,8 @@
       final i = m.group(1);
       final inclusiveStart = m.group(2) == 'INC';
       // Find the end marker.
-      final endMatch = RegExp('/\\*$i:(INC|EXC):(.+?)\\*/').firstMatch(content);
+      final endMatch =
+          RegExp('/\\*$i:(INC|EXC):(.+?)\\*/').firstMatch(content)!;
 
       final inclusiveEnd = endMatch.group(1) == 'INC';
       final expectedKindString = endMatch.group(2);
@@ -557,7 +556,7 @@
   Future<List<FoldingRegion>> _computeRegions(String sourceContent) async {
     newFile(sourcePath, content: sourceContent);
     var result = await session.getResolvedUnit(sourcePath);
-    var computer = DartUnitFoldingComputer(result.lineInfo, result.unit);
+    var computer = DartUnitFoldingComputer(result.lineInfo, result.unit!);
     return computer.compute();
   }
 }
diff --git a/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart b/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart
index da859cb..cad89c1 100644
--- a/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart
+++ b/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:analysis_server/src/flutter/flutter_outline_computer.dart';
 import 'package:analysis_server/src/protocol_server.dart';
 import 'package:analyzer/dart/analysis/results.dart';
@@ -20,10 +18,10 @@
 
 @reflectiveTest
 class FlutterOutlineComputerTest extends AbstractContextTest {
-  String testPath;
-  String testCode;
-  ResolvedUnitResult resolveResult;
-  FlutterOutlineComputer computer;
+  late String testPath;
+  late String testCode;
+  late ResolvedUnitResult resolveResult;
+  late FlutterOutlineComputer computer;
 
   @override
   void setUp() {
@@ -46,15 +44,15 @@
   WidgetA({int value});
 }
 ''');
-    var main = unitOutline.children[0];
-    var widget = main.children[0];
+    var main = unitOutline.children![0];
+    var widget = main.children![0];
     expect(widget.attributes, hasLength(1));
 
-    var attribute = widget.attributes[0];
+    var attribute = widget.attributes![0];
     expect(attribute.name, 'value');
     expect(attribute.label, '42');
-    _assertLocation(attribute.nameLocation, 75, 5);
-    _assertLocation(attribute.valueLocation, 82, 2);
+    _assertLocation(attribute.nameLocation!, 75, 5);
+    _assertLocation(attribute.valueLocation!, 82, 2);
   }
 
   Future<void> test_attributes_bool() async {
@@ -125,13 +123,13 @@
   }
 }
 ''');
-    var myWidget = unitOutline.children[0];
-    var build = myWidget.children[0];
-    var textOutline = build.children[0];
+    var myWidget = unitOutline.children![0];
+    var build = myWidget.children![0];
+    var textOutline = build.children![0];
 
     expect(textOutline.attributes, hasLength(1));
 
-    var attribute = textOutline.attributes[0];
+    var attribute = textOutline.attributes![0];
     expect(attribute.name, 'data');
     expect(attribute.label, r"'Hello, $name!'");
     expect(attribute.literalValueString, isNull);
@@ -154,10 +152,10 @@
   }
 }
 ''');
-    var myWidget = unitOutline.children[0];
-    var build = myWidget.children[0];
+    var myWidget = unitOutline.children![0];
+    var build = myWidget.children![0];
 
-    var rowOutline = build.children[0];
+    var rowOutline = build.children![0];
     expect(rowOutline.attributes, isEmpty);
   }
 
@@ -207,10 +205,10 @@
       Text
       Text
 ''');
-    var myWidget = unitOutline.children[0];
-    var build = myWidget.children[0];
+    var myWidget = unitOutline.children![0];
+    var build = myWidget.children![0];
 
-    var columnOutline = build.children[0];
+    var columnOutline = build.children![0];
     {
       var offset = testCode.indexOf('new Column');
       var length = testCode.indexOf('; // Column') - offset;
@@ -219,7 +217,7 @@
     }
 
     {
-      var textOutline = columnOutline.children[0];
+      var textOutline = columnOutline.children![0];
       var text = "const Text('aaa')";
       var offset = testCode.indexOf(text);
       expect(textOutline.offset, offset);
@@ -227,7 +225,7 @@
     }
 
     {
-      var textOutline = columnOutline.children[1];
+      var textOutline = columnOutline.children![1];
       var text = "const Text('bbb')";
       var offset = testCode.indexOf(text);
       expect(textOutline.offset, offset);
@@ -369,19 +367,19 @@
   }
 }
 ''');
-    var myWidget = unitOutline.children[0];
+    var myWidget = unitOutline.children![0];
     expect(myWidget.offset, 40);
     expect(myWidget.length, 137);
     expect(myWidget.codeOffset, 52);
     expect(myWidget.codeLength, 125);
 
-    var build = myWidget.children[0];
+    var build = myWidget.children![0];
     expect(build.offset, 95);
     expect(build.length, 80);
     expect(build.codeOffset, 107);
     expect(build.codeLength, 68);
 
-    var container = build.children[0];
+    var container = build.children![0];
     expect(container.offset, 155);
     expect(container.length, 15);
     expect(container.codeOffset, 155);
@@ -413,31 +411,31 @@
   static Text createMyText() => new Text('');
 }
 ''');
-    var myWidget = unitOutline.children[0];
-    var build = myWidget.children[0];
+    var myWidget = unitOutline.children![0];
+    var build = myWidget.children![0];
     expect(build.children, hasLength(1));
 
-    var row = build.children[0];
+    var row = build.children![0];
     expect(row.kind, FlutterOutlineKind.NEW_INSTANCE);
     expect(row.className, 'Row');
     expect(row.children, hasLength(3));
 
     {
-      var text = row.children[0];
+      var text = row.children![0];
       expect(text.kind, FlutterOutlineKind.GENERIC);
       expect(text.className, 'Text');
       expect(text.label, 'createText(…)');
     }
 
     {
-      var text = row.children[1];
+      var text = row.children![1];
       expect(text.kind, FlutterOutlineKind.GENERIC);
       expect(text.className, 'Text');
       expect(text.label, 'createEmptyText()');
     }
 
     {
-      var text = row.children[2];
+      var text = row.children![2];
       expect(text.kind, FlutterOutlineKind.GENERIC);
       expect(text.className, 'Text');
       expect(text.label, 'WidgetFactory.createMyText()');
@@ -490,20 +488,20 @@
   }
 }
 ''');
-    var myWidget = unitOutline.children[0];
-    var build = myWidget.children[0];
+    var myWidget = unitOutline.children![0];
+    var build = myWidget.children![0];
     expect(build.children, hasLength(2));
 
-    var textNew = build.children[0];
+    var textNew = build.children![0];
     expect(textNew.kind, FlutterOutlineKind.NEW_INSTANCE);
     expect(textNew.className, 'Text');
 
-    var center = build.children[1];
+    var center = build.children![1];
     expect(center.kind, FlutterOutlineKind.NEW_INSTANCE);
     expect(center.className, 'Center');
     expect(center.children, hasLength(1));
 
-    var textRef = center.children[0];
+    var textRef = center.children![0];
     expect(textRef.kind, FlutterOutlineKind.VARIABLE);
     expect(textRef.className, 'Text');
     expect(textRef.variableName, 'text');
@@ -541,15 +539,15 @@
   }
 }
 ''');
-    var main = unitOutline.children[0];
-    var newMyWidget = main.children[0];
+    var main = unitOutline.children![0];
+    var newMyWidget = main.children![0];
 
     expect(newMyWidget.attributes, hasLength(1));
 
-    var attribute = newMyWidget.attributes[0];
+    var attribute = newMyWidget.attributes![0];
     expect(attribute.name, name);
     expect(attribute.nameLocation, isNull);
-    _assertLocation(attribute.valueLocation, 64, value.length);
+    _assertLocation(attribute.valueLocation!, 64, value.length);
 
     return attribute;
   }
@@ -562,7 +560,7 @@
 
       if (outline.kind == FlutterOutlineKind.DART_ELEMENT) {
         buffer.write('(D) ');
-        buffer.writeln(outline.dartElement.name);
+        buffer.writeln(outline.dartElement!.name);
       } else {
         if (outline.kind == FlutterOutlineKind.NEW_INSTANCE) {
           if (outline.parentAssociationLabel != null) {
@@ -576,13 +574,13 @@
       }
 
       if (outline.children != null) {
-        for (var child in outline.children) {
+        for (var child in outline.children!) {
           writeOutline(child, '$indent  ');
         }
       }
     }
 
-    for (var child in outline.children) {
+    for (var child in outline.children!) {
       writeOutline(child, '');
     }
     return buffer.toString();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
index eaeb488..44c8028 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
@@ -249,9 +249,7 @@
     await resolveTestCode('''
 f(int? i) => i++;
 ''');
-    await assertHasFix('''
-f(int? i) => i!++;
-''');
+    await assertNoFix();
   }
 
   Future<void> test_prefixedIdentifier() async {
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index 2f679b1..e70af29 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -17,9 +17,13 @@
 
 Note: In LSP the client makes the first request so there is no obvious confirmation that the server is working correctly until the client sends an `initialize` request. Unlike standard JSON RPC, [LSP requires that headers are sent](https://microsoft.github.io/language-server-protocol/specification).
 
+## Handling of "Loose" Files
+
+When there are no open workspace folders (or if the initialization option `onlyAnalyzeProjectsWithOpenFiles` is set to `true`), analysis will be performed based on project folders located by the open files. For each open file, the project root will be located, and that whole project analyzed. If the file does not have a project (eg. there is no pubspec.yaml in its ancestor folders) then the file will be analyzed in isolation.
+
 ## Initialization Options
 
-- `onlyAnalyzeProjectsWithOpenFiles`: When set to `true`, analysis will only be performed for projects that have open files rather than the root workspace folder. Defaults to `false`.
+- `onlyAnalyzeProjectsWithOpenFiles`: When set to `true`, workspace folders will be ignored and analysis will be performed based on the open files, as if no workspace was open at all. This allows opening large folders without causing them to be completely analyzed. Defaults to `false`.
 - `suggestFromUnimportedLibraries`: When set to `false`, completion will not include synbols that are not already imported into the current file. Defaults to `true`, though the client must additionally support `workspace/applyEdit` for these completions to be included.
 - `closingLabels`: When set to `true`, `dart/textDocument/publishClosingLabels` notifications will be sent with information to render editor closing labels.
 - `outline`: When set to `true`, `dart/textDocument/publishOutline` notifications will be sent with outline information for open files.
diff --git a/pkg/analyzer/lib/instrumentation/noop_service.dart b/pkg/analyzer/lib/instrumentation/noop_service.dart
index 90be197..7daa465 100644
--- a/pkg/analyzer/lib/instrumentation/noop_service.dart
+++ b/pkg/analyzer/lib/instrumentation/noop_service.dart
@@ -34,7 +34,7 @@
 
   @override
   void logPluginException(
-      PluginData plugin, dynamic exception, StackTrace? stackTrace) {}
+      PluginData plugin, Object exception, StackTrace? stackTrace) {}
 
   @override
   void logPluginNotification(String pluginId, String notification) {}
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 480cbea..a9766f0 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -15,7 +15,6 @@
 import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/analysis/results.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/interner.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
diff --git a/pkg/analyzer_plugin/CHANGELOG.md b/pkg/analyzer_plugin/CHANGELOG.md
index 0fec00f..a2d2707 100644
--- a/pkg/analyzer_plugin/CHANGELOG.md
+++ b/pkg/analyzer_plugin/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.6.0
+- Bug fixes to the protocol.
+
 ## 0.5.0
 - Changed the support version range of the analyzer to `^1.3.0`.
 - Removed `Plugin.fileContentOverlay`, instead `Plugin.resourceProvider` is
diff --git a/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart b/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
index 40f3d2e..cb31eac 100644
--- a/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
+++ b/pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
@@ -8,7 +8,6 @@
 import 'package:analyzer/error/error.dart' as analyzer;
 import 'package:analyzer/exception/exception.dart' as analyzer;
 import 'package:analyzer/source/error_processor.dart' as analyzer;
-import 'package:analyzer/source/line_info.dart' as analyzer;
 import 'package:analyzer/src/generated/engine.dart' as analyzer;
 import 'package:analyzer/src/generated/source.dart' as analyzer;
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index 2572cff..083c022 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -1,6 +1,6 @@
 name: analyzer_plugin
 description: A framework and support code for building plugins for the analysis server.
-version: 0.5.0
+version: 0.6.0
 author: Dart Team <misc@dartlang.org>
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_plugin
 
@@ -8,7 +8,7 @@
   sdk: '>=2.12.0 <3.0.0'
 
 dependencies:
-  analyzer: ^1.3.0
+  analyzer: ^1.4.0
   collection: ^1.15.0
   dart_style: ^2.0.0
   pub_semver: ^2.0.0
diff --git a/pkg/compiler/lib/src/io/code_output.dart b/pkg/compiler/lib/src/io/code_output.dart
index d7342ef..70ad22c 100644
--- a/pkg/compiler/lib/src/io/code_output.dart
+++ b/pkg/compiler/lib/src/io/code_output.dart
@@ -143,6 +143,10 @@
 }
 
 abstract class AbstractCodeOutput extends CodeOutput {
+  final List<CodeOutputListener> _listeners;
+
+  AbstractCodeOutput([this._listeners]);
+
   Map<String, _SourceLocationsImpl> sourceLocationsMap =
       <String, _SourceLocationsImpl>{};
   @override
@@ -150,12 +154,17 @@
 
   void _addInternal(String text);
 
+  void _add(String text) {
+    _addInternal(text);
+    _listeners?.forEach((listener) => listener.onText(text));
+  }
+
   @override
   void add(String text) {
     if (isClosed) {
       throw new StateError("Code output is closed. Trying to write '$text'.");
     }
-    _addInternal(text);
+    _add(text);
   }
 
   @override
@@ -166,7 +175,7 @@
     if (!other.isClosed) {
       other.close();
     }
-    _addInternal(other.getText());
+    _add(other.getText());
   }
 
   @override
@@ -175,6 +184,7 @@
       throw new StateError("Code output is already closed.");
     }
     isClosed = true;
+    _listeners?.forEach((listener) => listener.onDone(length));
   }
 
   @override
@@ -194,6 +204,8 @@
 class CodeBuffer extends AbstractCodeOutput implements BufferedCodeOutput {
   StringBuffer buffer = new StringBuffer();
 
+  CodeBuffer([List<CodeOutputListener> listeners]) : super(listeners);
+
   @override
   void _addInternal(String text) {
     buffer.write(text);
@@ -218,25 +230,19 @@
   @override
   int length = 0;
   final OutputSink output;
-  final List<CodeOutputListener> _listeners;
 
-  StreamCodeOutput(this.output, [this._listeners]);
+  StreamCodeOutput(this.output, [List<CodeOutputListener> listeners])
+      : super(listeners);
 
   @override
   void _addInternal(String text) {
     output.add(text);
     length += text.length;
-    if (_listeners != null) {
-      _listeners.forEach((listener) => listener.onText(text));
-    }
   }
 
   @override
   void close() {
     output.close();
     super.close();
-    if (_listeners != null) {
-      _listeners.forEach((listener) => listener.onDone(length));
-    }
   }
 }
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index dd31e3b..4518521 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -9,7 +9,7 @@
 import '../common.dart';
 import '../options.dart';
 import '../dump_info.dart' show DumpInfoTask;
-import '../io/code_output.dart' show CodeBuffer;
+import '../io/code_output.dart' show CodeBuffer, CodeOutputListener;
 import 'js_source_mapping.dart';
 
 export 'package:js_ast/js_ast.dart';
@@ -38,12 +38,13 @@
     JavaScriptSourceInformationStrategy sourceInformationStrategy,
     {DumpInfoTask monitor,
     bool allowVariableMinification: true,
-    Renamer renamerForNames: JavaScriptPrintingOptions.identityRenamer}) {
+    Renamer renamerForNames: JavaScriptPrintingOptions.identityRenamer,
+    List<CodeOutputListener> listeners: const []}) {
   JavaScriptPrintingOptions options = new JavaScriptPrintingOptions(
       shouldCompressOutput: compilerOptions.enableMinification,
       minifyLocalVariables: allowVariableMinification,
       renamerForNames: renamerForNames);
-  CodeBuffer outBuffer = new CodeBuffer();
+  CodeBuffer outBuffer = new CodeBuffer(listeners);
   SourceInformationProcessor sourceInformationProcessor =
       sourceInformationStrategy.createProcessor(
           new SourceMapperProviderImpl(outBuffer),
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index b85031c..ac5714b 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -1894,11 +1894,16 @@
   void finalizeDeferredLoadingData(
       Map<String, List<CodeFragment>> codeFragmentsToLoad,
       Map<CodeFragment, FinalizedFragment> codeFragmentMap,
-      Map<FinalizedFragment, String> deferredLoadHashes,
+      Map<CodeFragment, String> deferredLoadHashes,
       DeferredLoadingState deferredLoadingState) {
     if (codeFragmentsToLoad.isEmpty) return;
 
-    Map<FinalizedFragment, int> fragmentIndexes = {};
+    // We store a map of indices to uris and hashes. Because multiple
+    // [CodeFragments] can map to a single file, a uri may appear multiple times
+    // in [fragmentUris] once per [CodeFragment] reference in that file.
+    // TODO(joshualitt): Use a string table to avoid duplicating part file
+    // names.
+    Map<CodeFragment, int> fragmentIndexes = {};
     List<String> fragmentUris = [];
     List<String> fragmentHashes = [];
 
@@ -1909,14 +1914,14 @@
       List<js.Expression> indexes = [];
       for (var codeFragment in codeFragments) {
         var fragment = codeFragmentMap[codeFragment];
-        String fragmentHash = deferredLoadHashes[fragment];
-        if (fragmentHash == null) continue;
-        int index = fragmentIndexes[fragment];
+        String codeFragmentHash = deferredLoadHashes[codeFragment];
+        if (codeFragmentHash == null) continue;
+        int index = fragmentIndexes[codeFragment];
         if (index == null) {
-          index = fragmentIndexes[fragment] = fragmentIndexes.length;
+          index = fragmentIndexes[codeFragment] = fragmentIndexes.length;
           fragmentUris.add(
               "${fragment.outputFileName}.${ModelEmitter.deferredExtension}");
-          fragmentHashes.add(fragmentHash);
+          fragmentHashes.add(codeFragmentHash);
         }
         indexes.add(js.number(index));
       }
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
index 8eefc10..3174eb4 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
@@ -165,7 +165,8 @@
   final Set<PreFragment> predecessors = {};
   FinalizedFragment finalizedFragment;
   int size = 0;
-  bool shouldInterleave = true;
+  // TODO(joshualitt): interleave dynamically when it makes sense.
+  bool shouldInterleave = false;
 
   PreFragment(
       this.outputFileName, EmittedOutputUnit emittedOutputUnit, this.size) {
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 97b7f0d..2b23a2c 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -270,22 +270,20 @@
     // Finalize and emit fragments.
     Map<OutputUnit, CodeFragment> outputUnitMap = {};
     Map<CodeFragment, FinalizedFragment> codeFragmentMap = {};
-    Map<FinalizedFragment, EmittedCodeFragment> deferredFragmentsCode = {};
+    Map<FinalizedFragment, List<EmittedCodeFragment>> deferredFragmentsCode =
+        {};
     for (var preDeferredFragment in preDeferredFragments) {
       var finalizedFragment =
           preDeferredFragment.finalize(program, outputUnitMap, codeFragmentMap);
-      // TODO(joshualitt): Support bundling.
-      assert(finalizedFragment.codeFragments.length == 1);
-      var codeFragment = finalizedFragment.codeFragments.single;
-      js.Expression fragmentCode =
-          fragmentEmitter.emitCodeFragment(codeFragment, program.holders);
-      if (fragmentCode != null) {
-        deferredFragmentsCode[finalizedFragment] =
-            EmittedCodeFragment(codeFragment, fragmentCode);
-      } else {
-        finalizedFragment.codeFragments.forEach((codeFragment) {
+      for (var codeFragment in finalizedFragment.codeFragments) {
+        js.Expression fragmentCode =
+            fragmentEmitter.emitCodeFragment(codeFragment, program.holders);
+        if (fragmentCode != null) {
+          (deferredFragmentsCode[finalizedFragment] ??= [])
+              .add(EmittedCodeFragment(codeFragment, fragmentCode));
+        } else {
           omittedOutputUnits.addAll(codeFragment.outputUnits);
-        });
+        }
       }
     }
 
@@ -306,9 +304,11 @@
 
     // Count tokens and run finalizers.
     js.TokenCounter counter = new js.TokenCounter();
-    deferredFragmentsCode.values.forEach((emittedCodeFragment) {
-      counter.countTokens(emittedCodeFragment.code);
-    });
+    for (var emittedFragments in deferredFragmentsCode.values) {
+      for (var emittedFragment in emittedFragments) {
+        counter.countTokens(emittedFragment.code);
+      }
+    }
     counter.countTokens(mainCode);
 
     program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens());
@@ -317,15 +317,15 @@
     // deferred ASTs inside the parts) have any contents. We should wait until
     // this point to decide if a part is empty.
 
-    Map<FinalizedFragment, String> hunkHashes =
+    Map<CodeFragment, String> codeFragmentHashes =
         _task.measureSubtask('write fragments', () {
-      return writeDeferredFragments(deferredFragmentsCode);
+      return writeFinalizedFragments(deferredFragmentsCode);
     });
 
     // Now that we have written the deferred hunks, we can create the deferred
     // loading data.
-    fragmentEmitter.finalizeDeferredLoadingData(
-        codeFragmentsToLoad, codeFragmentMap, hunkHashes, deferredLoadingState);
+    fragmentEmitter.finalizeDeferredLoadingData(codeFragmentsToLoad,
+        codeFragmentMap, codeFragmentHashes, deferredLoadingState);
 
     _task.measureSubtask('write fragments', () {
       writeMainFragment(mainFragment, mainCode,
@@ -362,25 +362,6 @@
     return new js.Comment(generatedBy(_options, flavor: '$flavor'));
   }
 
-  /// Writes all deferred fragment's code into files.
-  ///
-  /// Returns a map from fragment to its hashcode (as used for the deferred
-  /// library code).
-  ///
-  /// Updates the shared [outputBuffers] field with the output.
-  Map<FinalizedFragment, String> writeDeferredFragments(
-      Map<FinalizedFragment, EmittedCodeFragment> fragmentsCode) {
-    Map<FinalizedFragment, String> hunkHashes = {};
-
-    fragmentsCode.forEach(
-        (FinalizedFragment fragment, EmittedCodeFragment emittedCodeFragment) {
-      hunkHashes[fragment] =
-          writeDeferredFragment(fragment, emittedCodeFragment.code);
-    });
-
-    return hunkHashes;
-  }
-
   js.Statement buildDeferredInitializerGlobal() {
     return js.js.statement(
         'self.#deferredInitializers = '
@@ -445,16 +426,24 @@
     }
   }
 
-  // Writes the given [fragment]'s [code] into a file.
-  //
-  // Returns the deferred fragment's hash.
-  //
-  // Updates the shared [outputBuffers] field with the output.
-  String writeDeferredFragment(FinalizedFragment fragment, js.Expression code) {
-    List<CodeOutputListener> outputListeners = [];
-    Hasher hasher = new Hasher();
-    outputListeners.add(hasher);
+  /// Writes all [FinalizedFragments] to files, returning a map of
+  /// [CodeFragment] to their initialization hashes.
+  Map<CodeFragment, String> writeFinalizedFragments(
+      Map<FinalizedFragment, List<EmittedCodeFragment>> fragmentsCode) {
+    Map<CodeFragment, String> fragmentHashes = {};
+    fragmentsCode.forEach((fragment, code) {
+      writeFinalizedFragment(fragment, code, fragmentHashes);
+    });
+    return fragmentHashes;
+  }
 
+  /// Writes a single [FinalizedFragment] and all of its [CodeFragments] to
+  /// file, updating the [fragmentHashes] map as necessary.
+  void writeFinalizedFragment(
+      FinalizedFragment fragment,
+      List<EmittedCodeFragment> fragmentCode,
+      Map<CodeFragment, String> fragmentHashes) {
+    List<CodeOutputListener> outputListeners = [];
     LocationCollector locationCollector;
     if (_shouldGenerateSourceMap) {
       _task.measureSubtask('source-maps', () {
@@ -463,55 +452,21 @@
       });
     }
 
-    String hunkPrefix = fragment.outputFileName;
-
-    CodeOutput output = new StreamCodeOutput(
+    String outputFileName = fragment.outputFileName;
+    CodeOutput output = StreamCodeOutput(
         _outputProvider.createOutputSink(
-            hunkPrefix, deferredExtension, OutputType.jsPart),
+            outputFileName, deferredExtension, OutputType.jsPart),
         outputListeners);
 
-    // TODO(joshualitt): This breaks dump_info when we merge, but fixing it will
-    // require updating the schema.
-    emittedOutputBuffers[fragment.canonicalOutputUnit] = output;
-
-    // The [code] contains the function that must be invoked when the deferred
-    // hunk is loaded.
-    // That function must be in a map from its hashcode to the function. Since
-    // we don't know the hash before we actually emit the code we store the
-    // function in a temporary field first:
-    //
-    //   deferredInitializer.current = <pretty-printed code>;
-    //   deferredInitializer[<hash>] = deferredInitializer.current;
-
-    js.Program program = new js.Program([
-      buildGeneratedBy(),
-      buildDeferredInitializerGlobal(),
-      js.js.statement('$deferredInitializersGlobal.current = #', code)
-    ]);
-
-    CodeBuffer buffer = js.createCodeBuffer(
-        program, _options, _sourceInformationStrategy,
-        monitor: _dumpInfoTask);
-    _task.measureSubtask('emit buffers', () {
-      output.addBuffer(buffer);
-    });
-
-    // Make a unique hash of the code (before the sourcemaps are added)
-    // This will be used to retrieve the initializing function from the global
-    // variable.
-    String hash = hasher.getHash();
-
-    // Now we copy the deferredInitializer.current into its correct hash.
-    output.add('\n${deferredInitializersGlobal}["$hash"] = '
-        '${deferredInitializersGlobal}.current');
+    writeCodeFragments(fragmentCode, fragmentHashes, output);
 
     if (_shouldGenerateSourceMap) {
       _task.measureSubtask('source-maps', () {
         Uri mapUri, partUri;
         Uri sourceMapUri = _options.sourceMapUri;
         Uri outputUri = _options.outputUri;
-        String partName = "$hunkPrefix.$partExtension";
-        String hunkFileName = "$hunkPrefix.$deferredExtension";
+        String partName = "$outputFileName.$partExtension";
+        String hunkFileName = "$outputFileName.$deferredExtension";
 
         if (sourceMapUri != null) {
           String mapFileName = hunkFileName + ".map";
@@ -534,7 +489,61 @@
     } else {
       output.close();
     }
+  }
 
+  /// Writes a list of [CodeFragments] to [CodeOutput].
+  void writeCodeFragments(List<EmittedCodeFragment> fragmentCode,
+      Map<CodeFragment, String> fragmentHashes, CodeOutput output) {
+    bool isFirst = true;
+    for (var emittedCodeFragment in fragmentCode) {
+      var codeFragment = emittedCodeFragment.codeFragment;
+      var code = emittedCodeFragment.code;
+      for (var outputUnit in codeFragment.outputUnits) {
+        emittedOutputBuffers[outputUnit] = output;
+      }
+      fragmentHashes[codeFragment] = writeCodeFragment(output, code, isFirst);
+      isFirst = false;
+    }
+  }
+
+  // Writes the given [fragment]'s [code] into a file.
+  //
+  // Returns the deferred fragment's hash.
+  //
+  // Updates the shared [outputBuffers] field with the output.
+  String writeCodeFragment(
+      CodeOutput output, js.Expression code, bool isFirst) {
+    // The [code] contains the function that must be invoked when the deferred
+    // hunk is loaded.
+    // That function must be in a map from its hashcode to the function. Since
+    // we don't know the hash before we actually emit the code we store the
+    // function in a temporary field first:
+    //
+    //   deferredInitializer.current = <pretty-printed code>;
+    //   deferredInitializer[<hash>] = deferredInitializer.current;
+
+    js.Program program = new js.Program([
+      if (isFirst) buildGeneratedBy(),
+      if (isFirst) buildDeferredInitializerGlobal(),
+      js.js.statement('$deferredInitializersGlobal.current = #', code)
+    ]);
+
+    Hasher hasher = new Hasher();
+    CodeBuffer buffer = js.createCodeBuffer(
+        program, _options, _sourceInformationStrategy,
+        monitor: _dumpInfoTask, listeners: [hasher]);
+    _task.measureSubtask('emit buffers', () {
+      output.addBuffer(buffer);
+    });
+
+    // Make a unique hash of the code (before the sourcemaps are added)
+    // This will be used to retrieve the initializing function from the global
+    // variable.
+    String hash = hasher.getHash();
+
+    // Now we copy the deferredInitializer.current into its correct hash.
+    output.add('\n${deferredInitializersGlobal}["$hash"] = '
+        '${deferredInitializersGlobal}.current\n');
     return hash;
   }
 
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 81f1761..f6928ab 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -414,8 +414,7 @@
       assert(graph.isValid(), 'Graph not valid after ${phase.name}');
     }
 
-    runPhase(
-        new SsaInstructionSelection(_options, _closedWorld, _interceptorData));
+    runPhase(new SsaInstructionSelection(_options, _closedWorld));
     runPhase(new SsaTypeKnownRemover());
     runPhase(new SsaTrustedCheckRemover(_options));
     runPhase(new SsaAssignmentChaining(_closedWorld));
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index d643936..5bf162b 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -5,7 +5,6 @@
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../inferrer/abstract_value_domain.dart';
-import '../js_backend/interceptor_data.dart';
 import '../options.dart';
 import '../universe/selector.dart' show Selector;
 import '../world.dart' show JClosedWorld;
@@ -27,21 +26,14 @@
 ///
 /// - Remove NullChecks where the next instruction would fail on the operand.
 ///
-/// - Dummy receiver optimization.
-///
-/// - One-shot interceptor optimization.
-///
 /// - Combine read/modify/write sequences into HReadModifyWrite instructions to
 ///   simplify codegen of expressions like `a.x += y`.
-
 class SsaInstructionSelection extends HBaseVisitor with CodegenPhase {
   final JClosedWorld _closedWorld;
-  final InterceptorData _interceptorData;
   final CompilerOptions _options;
   HGraph graph;
 
-  SsaInstructionSelection(
-      this._options, this._closedWorld, this._interceptorData);
+  SsaInstructionSelection(this._options, this._closedWorld);
 
   AbstractValueDomain get _abstractValueDomain =>
       _closedWorld.abstractValueDomain;
@@ -229,128 +221,6 @@
       .isPotentiallyTrue;
 
   @override
-  HInstruction visitInvokeDynamic(HInvokeDynamic node) {
-    if (!node.isInterceptedCall) return node;
-
-    tryReplaceExplicitReceiverWithDummy(
-        node, node.selector, node.element, node.receiverType);
-
-    // Try to replace
-    //
-    //     getInterceptor(o).method(o, ...)
-    //
-    // with a 'one shot interceptor' which is a call to a synthesized static
-    // helper function that combines the two operations.
-    //
-    //     oneShotMethod(o, 1, 2)
-    //
-    // This saves code size and makes the receiver of an intercepted call a
-    // candidate for being generated at use site.
-    //
-    // Avoid combining a hoisted interceptor back into a loop, and the faster
-    // almost-constant kind of interceptor.
-
-    HInstruction interceptor = node.inputs[0];
-    if (interceptor is HInterceptor &&
-        interceptor.usedBy.length == 1 &&
-        !interceptor.isConditionalConstantInterceptor &&
-        interceptor.hasSameLoopHeaderAs(node)) {
-      // Copy inputs and replace interceptor with `null`.
-      List<HInstruction> inputs = List.of(node.inputs);
-      inputs[0] = graph.addConstantNull(_closedWorld);
-
-      HOneShotInterceptor oneShot = HOneShotInterceptor(
-          node.selector,
-          node.receiverType,
-          inputs,
-          node.instructionType,
-          node.typeArguments,
-          interceptor.interceptedClasses);
-      oneShot.sourceInformation = node.sourceInformation;
-      oneShot.sourceElement = node.sourceElement;
-      oneShot.sideEffects.setTo(node.sideEffects);
-
-      HBasicBlock block = node.block;
-      block.addAfter(node, oneShot);
-      block.rewrite(node, oneShot);
-      block.remove(node);
-      interceptor.block.remove(interceptor);
-      return null;
-    }
-
-    return node;
-  }
-
-  @override
-  HInstruction visitInvokeSuper(HInvokeSuper node) {
-    tryReplaceExplicitReceiverWithDummy(
-        node, node.selector, node.element, null);
-    return node;
-  }
-
-  @override
-  HInstruction visitOneShotInterceptor(HOneShotInterceptor node) {
-    throw StateError('Should not see HOneShotInterceptor: $node');
-  }
-
-  void tryReplaceExplicitReceiverWithDummy(HInvoke node, Selector selector,
-      MemberEntity target, AbstractValue mask) {
-    // Calls of the form
-    //
-    //     a.foo$1(a, x)
-    //
-    // where the interceptor calling convention is used come from recognizing
-    // that 'a' is a 'self-interceptor'.  If the selector matches only methods
-    // that ignore the explicit receiver parameter, replace occurrences of the
-    // receiver argument with a dummy receiver '0':
-    //
-    //     a.foo$1(a, x)   --->   a.foo$1(0, x)
-    //
-    // This often reduces the number of references to 'a' to one, allowing 'a'
-    // to be generated at use to avoid a temporary, e.g.
-    //
-    //     t1 = b.get$thing();
-    //     t1.foo$1(t1, x)
-    // --->
-    //     b.get$thing().foo$1(0, x)
-    //
-    assert(target != null || mask != null);
-
-    if (!node.isInterceptedCall) return;
-
-    // TODO(15933): Make automatically generated property extraction closures
-    // work with the dummy receiver optimization.
-    if (selector.isGetter) return;
-
-    // This assignment of inputs is uniform for HInvokeDynamic and HInvokeSuper.
-    HInstruction interceptor = node.inputs[0];
-    HInstruction receiverArgument = node.inputs[1];
-
-    // A 'self-interceptor'?
-    if (interceptor.nonCheck() != receiverArgument.nonCheck()) return;
-
-    // TODO(sra): Should this be an assert?
-    if (!_interceptorData.isInterceptedSelector(selector)) return;
-
-    if (target != null) {
-      // A call that resolves to a single instance method (element) requires the
-      // calling convention consistent with the method.
-      ClassEntity cls = target.enclosingClass;
-      assert(_interceptorData.isInterceptedMethod(target));
-      if (_interceptorData.isInterceptedClass(cls)) return;
-    } else if (_interceptorData.isInterceptedMixinSelector(
-        selector, mask, _closedWorld)) {
-      return;
-    }
-
-    ConstantValue constant = DummyInterceptorConstantValue();
-    HConstant dummy = graph.addConstant(constant, _closedWorld);
-    receiverArgument.usedBy.remove(node);
-    node.inputs[1] = dummy;
-    dummy.usedBy.add(node);
-  }
-
-  @override
   HInstruction visitFieldSet(HFieldSet setter) {
     // Pattern match
     //     t1 = x.f; t2 = t1 + 1; x.f = t2; use(t2)   -->  ++x.f
diff --git a/pkg/compiler/lib/src/ssa/interceptor_finalizer.dart b/pkg/compiler/lib/src/ssa/interceptor_finalizer.dart
new file mode 100644
index 0000000..fc51912
--- /dev/null
+++ b/pkg/compiler/lib/src/ssa/interceptor_finalizer.dart
@@ -0,0 +1,250 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../constants/values.dart';
+import '../elements/entities.dart';
+import '../inferrer/abstract_value_domain.dart';
+import '../js_backend/interceptor_data.dart';
+import '../universe/selector.dart' show Selector;
+import '../world.dart' show JClosedWorld;
+import 'nodes.dart';
+import 'optimize.dart';
+
+/// SsaFinalizeInterceptors makes adjustments for the interceptor calling
+/// convention.
+///
+/// 1. If the method cannot be invoked with an intercepted receiver, the
+///    receiver and interceptor are the same. In this case ignore the explicit
+///    receiver argument and use the interceptor (this) as the receiver.
+///
+/// 2. The call-site dual of the above is if a method ignores the explicit
+///    receiver, it can be replaced with a dummy value, i.e. a dummy receiver
+///    optimization.
+///
+/// 3. If an interceptor is used once for a call, replace the
+///    getInterceptor-call pair with a call to a 'one-shot interceptor' outlined
+///    method.
+///
+class SsaFinalizeInterceptors extends HBaseVisitor
+    implements OptimizationPhase {
+  @override
+  String get name => "SsaFinalizeInterceptors";
+  final JClosedWorld _closedWorld;
+  HGraph _graph;
+
+  SsaFinalizeInterceptors(this._closedWorld);
+
+  InterceptorData get _interceptorData => _closedWorld.interceptorData;
+
+  @override
+  void visitGraph(HGraph graph) {
+    _graph = graph;
+    MemberEntity element = graph.element;
+
+    if (usesSelfInterceptor(element)) {
+      _redirectReceiver();
+    }
+    visitDominatorTree(graph);
+  }
+
+  @override
+  visitBasicBlock(HBasicBlock node) {
+    HInstruction instruction = node.first;
+    while (instruction != null) {
+      final next = instruction.next;
+      instruction.accept(this);
+      instruction = next;
+    }
+  }
+
+  /// Returns `true` if [element] is an instance method that uses the
+  /// interceptor calling convention but the instance and interceptor arguments
+  /// will always be the same value.
+  bool usesSelfInterceptor(MemberEntity element) {
+    if (!_interceptorData.isInterceptedMethod(element)) return false;
+    ClassEntity cls = element.enclosingClass;
+    return !_interceptorData.isInterceptedClass(cls);
+  }
+
+  void _redirectReceiver() {
+    // The entry block contains the parameters in order, starting with `this`,
+    // and then the explicit receiver. There are other instructions in the
+    // block, like constants, which we ignore.
+    HThis thisParameter;
+    HParameterValue receiverParameter;
+    for (HInstruction node = _graph.entry.first;
+        node != null;
+        node = node.next) {
+      if (node is HParameterValue) {
+        if (node is HThis) {
+          thisParameter = node;
+        } else {
+          receiverParameter = node;
+          break;
+        }
+      }
+    }
+    assert(thisParameter != null,
+        '`this` parameter should be before other parameters');
+    assert(receiverParameter != null,
+        'Intercepted convention requires explicit receiver');
+    thisParameter.instructionType = receiverParameter.instructionType;
+    receiverParameter.block.rewrite(receiverParameter, thisParameter);
+    receiverParameter.sourceElement = const _RenameToUnderscore();
+  }
+
+  @override
+  void visitInvokeDynamic(HInvokeDynamic node) {
+    if (!node.isInterceptedCall) return;
+
+    if (_interceptorIsReceiver(node)) {
+      if (node.element != null) {
+        tryReplaceExplicitReceiverForTargetWithDummy(
+            node, node.selector, node.element);
+      } else {
+        tryReplaceExplicitReceiverForSelectorWithDummy(
+            node, node.selector, node.receiverType);
+      }
+      return;
+    }
+
+    // Try to replace
+    //
+    //     getInterceptor(o).method(o, ...)
+    //
+    // with a 'one shot interceptor' which is a call to a synthesized static
+    // helper function that combines the two operations.
+    //
+    //     oneShotMethod(o, 1, 2)
+    //
+    // This saves code size and makes the receiver of an intercepted call a
+    // candidate for being generated at use site.
+    //
+    // Avoid combining a hoisted interceptor back into a loop, and the faster
+    // almost-constant kind of interceptor.
+
+    HInstruction interceptor = node.inputs[0];
+    if (interceptor is HInterceptor &&
+        interceptor.usedBy.length == 1 &&
+        !interceptor.isConditionalConstantInterceptor &&
+        interceptor.hasSameLoopHeaderAs(node)) {
+      // Copy inputs and replace interceptor with `null`.
+      List<HInstruction> inputs = List.of(node.inputs);
+      inputs[0] = _graph.addConstantNull(_closedWorld);
+
+      HOneShotInterceptor oneShot = HOneShotInterceptor(
+          node.selector,
+          node.receiverType,
+          inputs,
+          node.instructionType,
+          node.typeArguments,
+          interceptor.interceptedClasses);
+      oneShot.sourceInformation = node.sourceInformation;
+      oneShot.sourceElement = node.sourceElement;
+      oneShot.sideEffects.setTo(node.sideEffects);
+
+      HBasicBlock block = node.block;
+      block.addAfter(node, oneShot);
+      block.rewrite(node, oneShot);
+      block.remove(node);
+      interceptor.block.remove(interceptor);
+    }
+  }
+
+  @override
+  void visitInvokeSuper(HInvokeSuper node) {
+    if (!node.isInterceptedCall) return;
+    if (_interceptorIsReceiver(node)) {
+      tryReplaceExplicitReceiverForTargetWithDummy(
+          node, node.selector, node.element);
+    }
+  }
+
+  @override
+  void visitInvokeGeneratorBody(HInvokeGeneratorBody node) {
+    // [HInvokeGeneratorBody] does not have an accurate [isInterceptorCall].
+    // Test the target first to ensure there are enough inputs.
+    if (usesSelfInterceptor(node.element) && _interceptorIsReceiver(node)) {
+      tryReplaceExplicitReceiverForTargetWithDummy(node, null, node.element);
+    }
+  }
+
+  @override
+  void visitOneShotInterceptor(HOneShotInterceptor node) {
+    throw StateError('Should not see HOneShotInterceptor: $node');
+  }
+
+  bool _interceptorIsReceiver(HInvoke node) {
+    // This assignment of inputs is uniform for HInvokeDynamic, HInvokeSuper and
+    // HInvokeGeneratorBody.
+    HInstruction interceptor = node.inputs[0];
+    HInstruction receiverArgument = node.inputs[1];
+    return interceptor.nonCheck() == receiverArgument.nonCheck();
+  }
+
+  void tryReplaceExplicitReceiverForTargetWithDummy(
+      HInvoke node, Selector selector, MemberEntity target) {
+    assert(target != null);
+
+    // TODO(15933): Make automatically generated property extraction closures
+    // work with the dummy receiver optimization.
+    if (selector != null && selector.isGetter) return;
+
+    if (usesSelfInterceptor(target)) {
+      _replaceReceiverArgumentWithDummy(node, 1);
+    }
+  }
+
+  void tryReplaceExplicitReceiverForSelectorWithDummy(
+      HInvoke node, Selector selector, AbstractValue mask) {
+    assert(mask != null);
+    // Calls of the form
+    //
+    //     a.foo$1(a, x)
+    //
+    // where the interceptor calling convention is used come from recognizing
+    // that 'a' is a 'self-interceptor'.  If the selector matches only methods
+    // that ignore the explicit receiver parameter, replace occurrences of the
+    // receiver argument with a dummy receiver '0':
+    //
+    //     a.foo$1(a, x)   --->   a.foo$1(0, x)
+    //
+    // This often reduces the number of references to 'a' to one, allowing 'a'
+    // to be generated at use to avoid a temporary, e.g.
+    //
+    //     t1 = b.get$thing();
+    //     t1.foo$1(t1, x)
+    // --->
+    //     b.get$thing().foo$1(0, x)
+    //
+
+    // TODO(15933): Make automatically generated property extraction closures
+    // work with the dummy receiver optimization.
+    if (selector.isGetter) return;
+
+    // TODO(sra): Should this be an assert?
+    if (!_interceptorData.isInterceptedSelector(selector)) return;
+
+    if (!_interceptorData.isInterceptedMixinSelector(
+        selector, mask, _closedWorld)) {
+      _replaceReceiverArgumentWithDummy(node, 1);
+    }
+  }
+
+  void _replaceReceiverArgumentWithDummy(HInvoke node, int receiverIndex) {
+    HInstruction receiverArgument = node.inputs[receiverIndex];
+    ConstantValue constant = DummyInterceptorConstantValue();
+    HConstant dummy = _graph.addConstant(constant, _closedWorld);
+    receiverArgument.usedBy.remove(node);
+    node.inputs[receiverIndex] = dummy;
+    dummy.usedBy.add(node);
+  }
+}
+
+/// A simple Entity to rename the unused receiver to `_` in non-minified code.
+class _RenameToUnderscore implements Entity {
+  const _RenameToUnderscore();
+  @override
+  String get name => '_';
+}
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index 968cf4f..c0b6254 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -12,20 +12,16 @@
 import 'nodes.dart';
 import 'optimize.dart';
 
-/// This phase simplifies interceptors in multiple ways:
+/// This phase computes the set of classes dispatched by an interceptor, and
+/// simplifies interceptors in multiple ways:
 ///
 /// 1) If the interceptor is for an object whose type is known, it
-/// tries to use a constant interceptor instead.
+///    tries to use a constant interceptor instead.
 ///
 /// 2) Interceptors are specialized based on the selector it is used with.
 ///
 /// 3) If we know the object is not intercepted, we just use the object
-/// instead.
-///
-/// 4) Single use interceptors at dynamic invoke sites are replaced with 'one
-/// shot interceptors' which are synthesized static helper functions that fetch
-/// the interceptor and then call the method.  This saves code size and makes the
-/// receiver of an intercepted call a candidate for being generated at use site.
+///    instead.
 ///
 class SsaSimplifyInterceptors extends HBaseVisitor
     implements OptimizationPhase {
diff --git a/pkg/compiler/lib/src/ssa/locals_handler.dart b/pkg/compiler/lib/src/ssa/locals_handler.dart
index ea01915..502d335 100644
--- a/pkg/compiler/lib/src/ssa/locals_handler.dart
+++ b/pkg/compiler/lib/src/ssa/locals_handler.dart
@@ -288,9 +288,7 @@
         element.isGenerativeConstructor &&
         _nativeData.isNativeOrExtendsNative(cls);
     if (_interceptorData.isInterceptedMethod(element)) {
-      bool isInterceptedClass = _interceptorData.isInterceptedClass(cls);
-      String name = isInterceptedClass ? 'receiver' : '_';
-      SyntheticLocal parameter = createLocal(name);
+      SyntheticLocal parameter = createLocal('receiver');
       HParameterValue value = new HParameterValue(parameter, getTypeOfThis());
       builder.graph.explicitReceiverParameter = value;
       builder.graph.entry.addAfter(directLocals[scopeInfo.thisLocal], value);
@@ -298,10 +296,7 @@
         // If this is the first parameter inserted, make sure it stays first.
         builder.lastAddedParameter = value;
       }
-      if (isInterceptedClass) {
-        // Only use the extra parameter in intercepted classes.
-        directLocals[scopeInfo.thisLocal] = value;
-      }
+      directLocals[scopeInfo.thisLocal] = value;
     } else if (isNativeUpgradeFactory) {
       SyntheticLocal parameter = createLocal('receiver');
       // Unlike `this`, receiver is nullable since direct calls to generative
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index e0f7369..8a819a1 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -34,6 +34,7 @@
 import '../util/util.dart';
 import '../world.dart' show JClosedWorld;
 import 'interceptor_simplifier.dart';
+import 'interceptor_finalizer.dart';
 import 'logging.dart';
 import 'nodes.dart';
 import 'types.dart';
@@ -129,9 +130,9 @@
       ];
       phases.forEach(runPhase);
 
-      // Simplifying interceptors is not strictly just an optimization, it is
-      // required for implementation correctness because the code generator
-      // assumes it is always performed.
+      // Simplifying interceptors is just an optimization, it is required for
+      // implementation correctness because the code generator assumes it is
+      // always performed to compute the intercepted classes sets.
       runPhase(new SsaSimplifyInterceptors(closedWorld, member.enclosingClass));
 
       SsaDeadCodeEliminator dce = new SsaDeadCodeEliminator(closedWorld, this);
@@ -163,6 +164,13 @@
       }
       phases.forEach(runPhase);
     });
+
+    // SsaFinalizeInterceptors must always be run to ensure consistent calling
+    // conventions between SSA-generated code and other code fragments generated
+    // by the emitter.
+    // TODO(sra): Generate these other fragments via SSA, then this phase
+    // becomes an opt-in optimization.
+    runPhase(SsaFinalizeInterceptors(closedWorld));
   }
 }
 
diff --git a/pkg/compiler/test/deferred_loading/data/components/main.dart b/pkg/compiler/test/deferred_loading/data/components/main.dart
index d5ac645..c576a7d 100644
--- a/pkg/compiler/test/deferred_loading/data/components/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/components/main.dart
@@ -32,8 +32,8 @@
   p3: {units: [3{libB, libC, libD, libE}, 6{libE}], usedBy: [], needs: [p2]}],
  b_finalized_fragments=[
   f1: [1{libA}],
-  f2: [5{libD}+4{libC}+2{libB}],
-  f3: [3{libB, libC, libD, libE}+6{libE}]],
+  f2: [5{libD}, 4{libC}, 2{libB}],
+  f3: [3{libB, libC, libD, libE}, 6{libE}]],
  c_steps=[
   libA=(f1),
   libB=(f3, f2),
@@ -50,8 +50,8 @@
   p4: {units: [3{libB, libC, libD, libE}], usedBy: [], needs: [p2, p3]}],
  b_finalized_fragments=[
   f1: [1{libA}],
-  f2: [4{libC}+2{libB}],
-  f3: [6{libE}+5{libD}],
+  f2: [4{libC}, 2{libB}],
+  f3: [6{libE}, 5{libD}],
   f4: [3{libB, libC, libD, libE}]],
  c_steps=[
   libA=(f1),
diff --git a/pkg/compiler/test/deferred_loading/data/dont_inline_deferred_constants/main.dart b/pkg/compiler/test/deferred_loading/data/dont_inline_deferred_constants/main.dart
index 8a5fa12..e9ddf00 100644
--- a/pkg/compiler/test/deferred_loading/data/dont_inline_deferred_constants/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/dont_inline_deferred_constants/main.dart
@@ -36,7 +36,7 @@
   p2: {units: [2{lib1, lib2}, 3{lib2}], usedBy: [], needs: [p1]}],
  b_finalized_fragments=[
   f1: [1{lib1}],
-  f2: [2{lib1, lib2}+3{lib2}]],
+  f2: [2{lib1, lib2}, 3{lib2}]],
  c_steps=[
   lib1=(f2, f1),
   lib2=(f2)]
diff --git a/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart b/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart
index 2efbbd6..a5d40ab 100644
--- a/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/lazy_types/main.dart
@@ -14,8 +14,6 @@
   f1: [6{libA}],
   f2: [1{libB}],
   f3: [2{libC}],
-  f4: [],
-  f5: [],
   f6: [3{libA, libB, libC}]],
  c_steps=[
   libA=(f6, f1),
@@ -29,12 +27,12 @@
   p2: {units: [5{libB, libC}, 4{libA, libC}, 2{libC}], usedBy: [p3], needs: [p1]},
   p3: {units: [3{libA, libB, libC}], usedBy: [], needs: [p2]}],
  b_finalized_fragments=[
-  f1: [1{libB}+6{libA}],
-  f2: [5{libB, libC}+4{libA, libC}+2{libC}],
+  f1: [1{libB}, 6{libA}],
+  f2: [2{libC}],
   f3: [3{libA, libB, libC}]],
  c_steps=[
-  libA=(f3, f2, f1),
-  libB=(f3, f2, f1),
+  libA=(f3, f1),
+  libB=(f3, f1),
   libC=(f3, f2)]
 */
 
@@ -48,7 +46,7 @@
   f1: [6{libA}],
   f2: [1{libB}],
   f3: [2{libC}],
-  f4: [3{libA, libB, libC}+5{libB, libC}+4{libA, libC}]],
+  f4: [3{libA, libB, libC}]],
  c_steps=[
   libA=(f4, f1),
   libB=(f4, f2),
diff --git a/pkg/compiler/test/deferred_loading/data/many_parts/main.dart b/pkg/compiler/test/deferred_loading/data/many_parts/main.dart
index 9471cc9..3dfb374 100644
--- a/pkg/compiler/test/deferred_loading/data/many_parts/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/many_parts/main.dart
@@ -82,9 +82,9 @@
   p3: {units: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}], usedBy: [p4], needs: [p2]},
   p4: {units: [1{b1, b2, b3, b4, b5}], usedBy: [], needs: [p2, p3]}],
  b_finalized_fragments=[
-  f1: [26{b3, b4}+21{b2, b5}+19{b2, b4}+18{b2, b3}+10{b1, b5}+6{b1, b4}+4{b1, b3}+3{b1, b2}+31{b5}+29{b4}+25{b3}+17{b2}+2{b1}],
-  f2: [9{b1, b2, b3, b4}+28{b3, b4, b5}+23{b2, b4, b5}+22{b2, b3, b5}+20{b2, b3, b4}+14{b1, b4, b5}+12{b1, b3, b5}+8{b1, b3, b4}+11{b1, b2, b5}+7{b1, b2, b4}+5{b1, b2, b3}+30{b4, b5}+27{b3, b5}],
-  f3: [24{b2, b3, b4, b5}+16{b1, b3, b4, b5}+15{b1, b2, b4, b5}+13{b1, b2, b3, b5}],
+  f1: [26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 2{b1}],
+  f2: [9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}, 12{b1, b3, b5}, 8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}],
+  f3: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}],
   f4: [1{b1, b2, b3, b4, b5}]],
  c_steps=[
   b1=(f4, f3, f2, f1),
@@ -100,8 +100,8 @@
   p2: {units: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}, 9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}, 12{b1, b3, b5}], usedBy: [p3], needs: [p1]},
   p3: {units: [1{b1, b2, b3, b4, b5}], usedBy: [], needs: [p2]}],
  b_finalized_fragments=[
-  f1: [8{b1, b3, b4}+11{b1, b2, b5}+7{b1, b2, b4}+5{b1, b2, b3}+30{b4, b5}+27{b3, b5}+26{b3, b4}+21{b2, b5}+19{b2, b4}+18{b2, b3}+10{b1, b5}+6{b1, b4}+4{b1, b3}+3{b1, b2}+31{b5}+29{b4}+25{b3}+17{b2}+2{b1}],
-  f2: [24{b2, b3, b4, b5}+16{b1, b3, b4, b5}+15{b1, b2, b4, b5}+13{b1, b2, b3, b5}+9{b1, b2, b3, b4}+28{b3, b4, b5}+23{b2, b4, b5}+22{b2, b3, b5}+20{b2, b3, b4}+14{b1, b4, b5}+12{b1, b3, b5}],
+  f1: [8{b1, b3, b4}, 11{b1, b2, b5}, 7{b1, b2, b4}, 5{b1, b2, b3}, 30{b4, b5}, 27{b3, b5}, 26{b3, b4}, 21{b2, b5}, 19{b2, b4}, 18{b2, b3}, 10{b1, b5}, 6{b1, b4}, 4{b1, b3}, 3{b1, b2}, 31{b5}, 29{b4}, 25{b3}, 17{b2}, 2{b1}],
+  f2: [24{b2, b3, b4, b5}, 16{b1, b3, b4, b5}, 15{b1, b2, b4, b5}, 13{b1, b2, b3, b5}, 9{b1, b2, b3, b4}, 28{b3, b4, b5}, 23{b2, b4, b5}, 22{b2, b3, b5}, 20{b2, b3, b4}, 14{b1, b4, b5}, 12{b1, b3, b5}],
   f3: [1{b1, b2, b3, b4, b5}]],
  c_steps=[
   b1=(f3, f2, f1),
diff --git a/pkg/compiler/test/deferred_loading/data/shadowed_types/main.dart b/pkg/compiler/test/deferred_loading/data/shadowed_types/main.dart
index 92732f9..d32f920 100644
--- a/pkg/compiler/test/deferred_loading/data/shadowed_types/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/shadowed_types/main.dart
@@ -9,8 +9,7 @@
   p3: {units: [2{libb, liba}], usedBy: [], needs: []}],
  b_finalized_fragments=[
   f1: [3{liba}],
-  f2: [1{libb}],
-  f3: []],
+  f2: [1{libb}]],
  c_steps=[
   liba=(f1),
   libb=(f2)]
@@ -23,8 +22,7 @@
   p3: {units: [2{libb, liba}], usedBy: [], needs: [p1, p2]}],
  b_finalized_fragments=[
   f1: [3{liba}],
-  f2: [1{libb}],
-  f3: []],
+  f2: [1{libb}]],
  c_steps=[
   liba=(f1),
   libb=(f2)]
diff --git a/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart b/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart
index 367329a..6703cb1 100644
--- a/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart
+++ b/pkg/compiler/test/deferred_loading/data/type_arguments/main.dart
@@ -9,8 +9,7 @@
   p3: {units: [3{lib1, lib3}], usedBy: [], needs: []}],
  b_finalized_fragments=[
   f1: [1{lib1}],
-  f2: [2{lib3}],
-  f3: []],
+  f2: [2{lib3}]],
  c_steps=[
   lib1=(f1),
   lib3=(f2)]
@@ -23,8 +22,7 @@
   p3: {units: [3{lib1, lib3}], usedBy: [], needs: [p1, p2]}],
  b_finalized_fragments=[
   f1: [1{lib1}],
-  f2: [2{lib3}],
-  f3: []],
+  f2: [2{lib3}]],
  c_steps=[
   lib1=(f1),
   lib3=(f2)]
diff --git a/pkg/compiler/test/deferred_loading/deferred_loading_test.dart b/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
index 342c07f..621ba83 100644
--- a/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
+++ b/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
@@ -245,7 +245,9 @@
             outputUnitStrings.add(outputUnitString(outputUnit));
           }
         }
-        supplied.add(outputUnitStrings.join('+'));
+        if (outputUnitStrings.isNotEmpty) {
+          supplied.add(outputUnitStrings.join('+'));
+        }
       }
 
       if (supplied.isNotEmpty) {
diff --git a/pkg/test_runner/bin/package_testing_support.dart b/pkg/test_runner/bin/package_testing_support.dart
index 0f01485..00322d9 100644
--- a/pkg/test_runner/bin/package_testing_support.dart
+++ b/pkg/test_runner/bin/package_testing_support.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE.md file.
 
-import 'package:test_runner/src/configuration.dart';
 import 'package:test_runner/src/options.dart';
 import 'package:test_runner/src/repository.dart';
 import 'package:test_runner/src/test_configurations.dart';
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index b002c93..96be311 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -5,7 +5,6 @@
 import 'dart:convert';
 import 'dart:io';
 
-import 'package:smith/smith.dart';
 import 'package:test_runner/src/test_configurations.dart';
 import 'package:path/path.dart' as path;
 
diff --git a/pkg/vm/lib/transformations/pragma.dart b/pkg/vm/lib/transformations/pragma.dart
index cde363a..d27f3d8 100644
--- a/pkg/vm/lib/transformations/pragma.dart
+++ b/pkg/vm/lib/transformations/pragma.dart
@@ -13,7 +13,6 @@
 const kResultTypeUsesPassedTypeArguments =
     "result-type-uses-passed-type-arguments";
 const kRecognizedPragmaName = "vm:recognized";
-const kDisableUnboxedParametetersPragmaName = "vm:disable-unboxed-parameters";
 
 abstract class ParsedPragma {}
 
@@ -47,10 +46,6 @@
   ParsedRecognized(this.type);
 }
 
-class ParsedDisableUnboxedParameters extends ParsedPragma {
-  ParsedDisableUnboxedParameters();
-}
-
 abstract class PragmaAnnotationParser {
   /// May return 'null' if the annotation does not represent a recognized
   /// @pragma.
@@ -147,8 +142,6 @@
               "pragma: $options";
         }
         return new ParsedRecognized(type);
-      case kDisableUnboxedParametetersPragmaName:
-        return new ParsedDisableUnboxedParameters();
       default:
         return null;
     }
diff --git a/pkg/vm/lib/transformations/type_flow/native_code.dart b/pkg/vm/lib/transformations/type_flow/native_code.dart
index e24408b..7375c51 100644
--- a/pkg/vm/lib/transformations/type_flow/native_code.dart
+++ b/pkg/vm/lib/transformations/type_flow/native_code.dart
@@ -233,19 +233,6 @@
         (expectedTypes == null || expectedTypes.contains(type));
   }
 
-  bool hasDisableUnboxedParameters(Member member) {
-    for (var annotation in member.annotations) {
-      ParsedPragma pragma = _matcher.parsePragma(annotation);
-      if (pragma is ParsedDisableUnboxedParameters) {
-        if (member.enclosingLibrary.importUri.scheme != "dart") {
-          throw "ERROR: Cannot use @pragma(vm:disable-unboxed-parameters) outside core libraries.";
-        }
-        return true;
-      }
-    }
-    return false;
-  }
-
   /// Simulate the execution of a native method by adding its entry points
   /// using [entryPointsListener]. Returns result type of the native method.
   TypeExpr handleNativeProcedure(
diff --git a/pkg/vm/lib/transformations/type_flow/unboxing_info.dart b/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
index 03f7ef2..792dc99 100644
--- a/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
+++ b/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
@@ -203,8 +203,7 @@
         _nativeCodeOracle.isRecognized(member, const [
           PragmaRecognizedType.AsmIntrinsic,
           PragmaRecognizedType.Other
-        ]) ||
-        _nativeCodeOracle.hasDisableUnboxedParameters(member);
+        ]);
   }
 
   bool _isNative(Member member) => getExternalName(member) != null;
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index a0ee87a..ef05e6d 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -5664,7 +5664,9 @@
   // Handle modulo/division by zero exception on slow path.
   if (slow_path->has_divide_by_zero()) {
     __ CompareRegisters(right, ZR);
-    __ b(slow_path->entry_label(), EQ);
+    __ b(compiler->intrinsic_mode() ? compiler->intrinsic_slow_path_label()
+                                    : slow_path->entry_label(),
+         EQ);
   }
 
   // Perform actual operation
@@ -5677,12 +5679,14 @@
     // For the % operator, the sdiv instruction does not
     // quite do what we want. Adjust for sign on slow path.
     __ CompareRegisters(out, ZR);
-    __ b(slow_path->adjust_sign_label(), LT);
+    __ b(compiler->intrinsic_mode() ? compiler->intrinsic_slow_path_label()
+                                    : slow_path->adjust_sign_label(),
+         LT);
   } else {
     __ sdiv(out, left, right);
   }
 
-  if (slow_path->is_needed()) {
+  if (!compiler->intrinsic_mode() && slow_path->is_needed()) {
     __ Bind(slow_path->exit_label());
     compiler->AddSlowPathCode(slow_path);
   }
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 9eaa60c..109b09e 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -6117,14 +6117,18 @@
   // Handle modulo/division by zero exception on slow path.
   if (slow_path->has_divide_by_zero()) {
     __ testq(right, right);
-    __ j(EQUAL, slow_path->entry_label());
+    __ j(EQUAL, compiler->intrinsic_mode()
+                    ? compiler->intrinsic_slow_path_label()
+                    : slow_path->entry_label());
   }
 
   // Handle modulo/division by minus one explicitly on slow path
   // (to avoid arithmetic exception on 0x8000000000000000 / -1).
   if (slow_path->has_divide_by_minus_one()) {
     __ cmpq(right, compiler::Immediate(-1));
-    __ j(EQUAL, slow_path->div_by_minus_one_label());
+    __ j(EQUAL, compiler->intrinsic_mode()
+                    ? compiler->intrinsic_slow_path_label()
+                    : slow_path->div_by_minus_one_label());
   }
 
   // Perform actual operation
@@ -6163,13 +6167,15 @@
     // For the % operator, again the idiv instruction does
     // not quite do what we want. Adjust for sign on slow path.
     __ testq(out, out);
-    __ j(LESS, slow_path->adjust_sign_label());
+    __ j(LESS, compiler->intrinsic_mode()
+                   ? compiler->intrinsic_slow_path_label()
+                   : slow_path->adjust_sign_label());
   } else {
     ASSERT(out == RAX);
     ASSERT(tmp == RDX);
   }
 
-  if (slow_path->is_needed()) {
+  if (!compiler->intrinsic_mode() && slow_path->is_needed()) {
     __ Bind(slow_path->exit_label());
     compiler->AddSlowPathCode(slow_path);
   }
diff --git a/runtime/vm/compiler/ffi/native_calling_convention_test.cc b/runtime/vm/compiler/ffi/native_calling_convention_test.cc
index 0ac5e3f..9d4b672 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention_test.cc
+++ b/runtime/vm/compiler/ffi/native_calling_convention_test.cc
@@ -95,8 +95,7 @@
   member_types.Add(&int8type);
   member_types.Add(&int8type);
   member_types.Add(&int8type);
-  const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, member_types);
+  const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
 
   auto& arguments = *new (Z) NativeTypes(Z, 10);
   arguments.Add(&struct_type);
@@ -138,8 +137,7 @@
   member_types.Add(&float_type);
   member_types.Add(&float_type);
   member_types.Add(&float_type);
-  const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, member_types);
+  const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
 
   auto& arguments = *new (Z) NativeTypes(Z, 13);
   arguments.Add(&struct_type);
@@ -174,14 +172,13 @@
   auto& full_float_member_types = *new (Z) NativeTypes(Z, 1);
   full_float_member_types.Add(&float_2_array_type);
   const auto& float_array_struct_type =
-      NativeCompoundType::FromNativeTypes(Z, full_float_member_types);
+      NativeStructType::FromNativeTypes(Z, full_float_member_types);
 
   auto& member_types = *new (Z) NativeTypes(Z, 3);
   member_types.Add(&float_1_array_type);
   member_types.Add(&float_array_struct_type);
   member_types.Add(&float_type);
-  const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, member_types);
+  const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
 
   auto& arguments = *new (Z) NativeTypes(Z, 13);
   arguments.Add(&struct_type);
@@ -203,6 +200,55 @@
   RunSignatureTest(Z, "struct16bytesHomogenousx10", arguments, struct_type);
 }
 
+// Test with homogenous union.
+//
+// Even though the number of floats nested is different, this is still laid
+// out as a homogeneous aggregate in arm64 and arm hardfp.
+//
+// Even though the member sizes are different, these unions are still passed in
+// xmm registers on Linux/MacOS x64.
+//
+// See the *.expect in ./unit_tests for this behavior.
+UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_union16bytesHomogenousx10) {
+  const auto& float_type = *new (Z) NativePrimitiveType(kFloat);
+  const auto& int8type = *new (Z) NativePrimitiveType(kInt8);
+
+  const auto& float_array_type = *new (Z) NativeArrayType(float_type, 3);
+
+  auto& struct_member_types = *new (Z) NativeTypes(Z, 4);
+  struct_member_types.Add(&float_type);
+  struct_member_types.Add(&float_type);
+  struct_member_types.Add(&float_type);
+  struct_member_types.Add(&float_type);
+  const auto& struct_type =
+      NativeStructType::FromNativeTypes(Z, struct_member_types);
+
+  auto& member_types = *new (Z) NativeTypes(Z, 2);
+  member_types.Add(&float_array_type);
+  member_types.Add(&struct_type);
+  const auto& union_type = NativeUnionType::FromNativeTypes(Z, member_types);
+
+  EXPECT_EQ(16, union_type.SizeInBytes());
+  EXPECT(union_type.ContainsHomogenuousFloats());
+
+  auto& arguments = *new (Z) NativeTypes(Z, 13);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&int8type);    // Check integer register back filling, if any.
+  arguments.Add(&union_type);  // Check stack alignment of struct.
+
+  // Identical expectation files as previous test, struct contains the same
+  // members, but nested in arrays and nested structs.
+  RunSignatureTest(Z, "union16bytesHomogenousx10", arguments, union_type);
+}
+
 // A fairly big struct.
 //
 // On arm, split up in 8-byte chunks. The first chunk goes into two registers,
@@ -237,8 +283,7 @@
   member_types.Add(&int64_type);
   member_types.Add(&int64_type);
   member_types.Add(&int64_type);
-  const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, member_types);
+  const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
 
   auto& arguments = *new (Z) NativeTypes(Z, 2);
   arguments.Add(&struct_type);
@@ -260,8 +305,7 @@
   member_types.Add(&float_type);
   member_types.Add(&int32_type);
   member_types.Add(&int32_type);
-  const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, member_types);
+  const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
 
   auto& arguments = *new (Z) NativeTypes(Z, 11);
   arguments.Add(&struct_type);
@@ -291,8 +335,7 @@
   member_types.Add(&float_type);
   member_types.Add(&int32_type);
   member_types.Add(&int32_type);
-  const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, member_types);
+  const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
 
   auto& arguments = *new (Z) NativeTypes(Z, 15);
   arguments.Add(&float_type);
@@ -342,20 +385,19 @@
   half_float_member_types.Add(&int32_type);
   half_float_member_types.Add(&float_type);
   const auto& half_float_type =
-      NativeCompoundType::FromNativeTypes(Z, half_float_member_types);
+      NativeStructType::FromNativeTypes(Z, half_float_member_types);
 
   const auto& float_array_type = *new (Z) NativeArrayType(float_type, 1);
   auto& full_float_member_types = *new (Z) NativeTypes(Z, 1);
   full_float_member_types.Add(&float_array_type);
   const auto& full_float_type =
-      NativeCompoundType::FromNativeTypes(Z, full_float_member_types);
+      NativeStructType::FromNativeTypes(Z, full_float_member_types);
 
   auto& member_types = *new (Z) NativeTypes(Z, 3);
   member_types.Add(&int32_type);
   member_types.Add(&half_float_type);
   member_types.Add(&full_float_type);
-  const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, member_types);
+  const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
 
   auto& arguments = *new (Z) NativeTypes(Z, 11);
   arguments.Add(&struct_type);
@@ -389,8 +431,7 @@
   member_types.Add(&int8type);
   member_types.Add(&int8type);
   member_types.Add(&int8type);
-  const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, member_types);
+  const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
 
   auto& arguments = *new (Z) NativeTypes(Z, 1);
   arguments.Add(&struct_type);
@@ -418,7 +459,7 @@
   member_types.Add(&int8_type);
   member_types.Add(&int8_type);
   const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, member_types, /*packing=*/1);
+      NativeStructType::FromNativeTypes(Z, member_types, /*packing=*/1);
   EXPECT_EQ(8, struct_type.SizeInBytes());
   EXPECT(struct_type.ContainsUnalignedMembers());
 
@@ -456,7 +497,7 @@
   member_types.Add(&int8_type);
   member_types.Add(&double_type);
   const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, member_types, /*packing=*/1);
+      NativeStructType::FromNativeTypes(Z, member_types, /*packing=*/1);
   EXPECT_EQ(9, struct_type.SizeInBytes());
   EXPECT(struct_type.ContainsUnalignedMembers());
 
@@ -469,6 +510,51 @@
   RunSignatureTest(Z, "structPacked", arguments, struct_type);
 }
 
+// The union is only 5 bytes because it's members are packed.
+//
+// Many calling conventions pass this struct in single registers or less
+// stack slots because of this.
+//
+// Non-windows x64 passes this struct on the stack instead of in a single
+// CPU register, because it contains a mis-aligned member.
+//
+// See the *.expect in ./unit_tests for this behavior.
+UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_union5bytesPackedx10) {
+  const auto& uint8_type = *new (Z) NativePrimitiveType(kUint8);
+  const auto& uint32_type = *new (Z) NativePrimitiveType(kUint32);
+
+  auto& inner_members = *new (Z) NativeTypes(Z, 2);
+  inner_members.Add(&uint8_type);
+  inner_members.Add(&uint32_type);
+  const intptr_t packing = 1;
+  const auto& struct_type =
+      NativeStructType::FromNativeTypes(Z, inner_members, packing);
+
+  const auto& array_type = *new (Z) NativeArrayType(uint8_type, 5);
+
+  auto& member_types = *new (Z) NativeTypes(Z, 2);
+  member_types.Add(&array_type);
+  member_types.Add(&struct_type);
+  const auto& union_type = NativeUnionType::FromNativeTypes(Z, member_types);
+
+  EXPECT_EQ(5, union_type.SizeInBytes());
+  EXPECT_EQ(1, union_type.AlignmentInBytesField());
+
+  auto& arguments = *new (Z) NativeTypes(Z, 10);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+  arguments.Add(&union_type);
+
+  RunSignatureTest(Z, "union5bytesPackedx10", arguments, union_type);
+}
+
 }  // namespace ffi
 }  // namespace compiler
 }  // namespace dart
diff --git a/runtime/vm/compiler/ffi/native_type.cc b/runtime/vm/compiler/ffi/native_type.cc
index cd4cbbb..b78b206 100644
--- a/runtime/vm/compiler/ffi/native_type.cc
+++ b/runtime/vm/compiler/ffi/native_type.cc
@@ -162,10 +162,9 @@
 
 // Keep consistent with
 // pkg/vm/lib/transformations/ffi_definitions.dart:StructLayout:_calculateLayout.
-NativeCompoundType& NativeCompoundType::FromNativeTypes(
-    Zone* zone,
-    const NativeTypes& members,
-    intptr_t member_packing) {
+NativeStructType& NativeStructType::FromNativeTypes(Zone* zone,
+                                                    const NativeTypes& members,
+                                                    intptr_t member_packing) {
   intptr_t offset = 0;
 
   const intptr_t kAtLeast1ByteAligned = 1;
@@ -211,8 +210,37 @@
   }
   const intptr_t size = Utils::RoundUp(offset, alignment_field);
 
-  return *new (zone) NativeCompoundType(members, member_offsets, size,
-                                        alignment_field, alignment_stack);
+  return *new (zone) NativeStructType(members, member_offsets, size,
+                                      alignment_field, alignment_stack);
+}
+
+// Keep consistent with
+// pkg/vm/lib/transformations/ffi_definitions.dart:StructLayout:_calculateLayout.
+NativeUnionType& NativeUnionType::FromNativeTypes(Zone* zone,
+                                                  const NativeTypes& members) {
+  intptr_t size = 0;
+
+  const intptr_t kAtLeast1ByteAligned = 1;
+  // If this union is nested in a struct, it should be aligned to the
+  // largest alignment of its members.
+  intptr_t alignment_field = kAtLeast1ByteAligned;
+  // If this union is passed on the stack, it should be aligned to the largest
+  // alignment of its members when passing those members on the stack.
+  intptr_t alignment_stack = kAtLeast1ByteAligned;
+
+  for (intptr_t i = 0; i < members.length(); i++) {
+    const NativeType& member = *members[i];
+    const intptr_t member_size = member.SizeInBytes();
+    const intptr_t member_align_field = member.AlignmentInBytesField();
+    const intptr_t member_align_stack = member.AlignmentInBytesStack();
+    size = Utils::Maximum(size, member_size);
+    alignment_field = Utils::Maximum(alignment_field, member_align_field);
+    alignment_stack = Utils::Maximum(alignment_stack, member_align_stack);
+  }
+  size = Utils::RoundUp(size, alignment_field);
+
+  return *new (zone)
+      NativeUnionType(members, size, alignment_field, alignment_stack);
 }
 
 #if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
@@ -371,6 +399,11 @@
 
   // User-defined structs.
   const auto& cls = Class::Handle(zone, type.type_class());
+  const auto& superClass = Class::Handle(zone, cls.SuperClass());
+  const bool is_struct = String::Handle(zone, superClass.UserVisibleName())
+                             .Equals(Symbols::Struct());
+  ASSERT(is_struct || String::Handle(zone, superClass.UserVisibleName())
+                          .Equals(Symbols::Union()));
 
   auto& pragmas = Object::Handle(zone);
   Library::FindPragma(dart::Thread::Current(), /*only_core=*/false, cls,
@@ -454,8 +487,12 @@
     }
   }
 
-  return NativeCompoundType::FromNativeTypes(zone, field_native_types,
+  if (is_struct) {
+    return NativeStructType::FromNativeTypes(zone, field_native_types,
                                              member_packing);
+  } else {
+    return NativeUnionType::FromNativeTypes(zone, field_native_types);
+  }
 }
 #endif
 
@@ -560,7 +597,8 @@
 void NativeCompoundType::PrintTo(BaseTextBuffer* f,
                                  bool multi_line,
                                  bool verbose) const {
-  f->AddString("Compound(");
+  PrintCompoundType(f);
+  f->AddString("(");
   f->Printf("size: %" Pd "", SizeInBytes());
   if (verbose) {
     f->Printf(", field alignment: %" Pd ", ", AlignmentInBytesField());
@@ -577,7 +615,7 @@
           f->AddString(", ");
         }
       }
-      f->Printf("%" Pd ": ", member_offsets_[i]);
+      PrintMemberOffset(f, i);
       members_[i]->PrintTo(f);
     }
     if (multi_line) {
@@ -591,6 +629,19 @@
   }
 }
 
+void NativeStructType::PrintCompoundType(BaseTextBuffer* f) const {
+  f->AddString("Struct");
+}
+
+void NativeUnionType::PrintCompoundType(BaseTextBuffer* f) const {
+  f->AddString("Union");
+}
+
+void NativeStructType::PrintMemberOffset(BaseTextBuffer* f,
+                                         intptr_t member_index) const {
+  f->Printf("%" Pd ": ", member_offsets_[member_index]);
+}
+
 #if !defined(FFI_UNIT_TESTS)
 const char* NativeFunctionType::ToCString() const {
   return ToCString(Thread::Current()->zone());
@@ -617,7 +668,7 @@
   return element_type_.NumPrimitiveMembersRecursive() * length_;
 }
 
-intptr_t NativeCompoundType::NumPrimitiveMembersRecursive() const {
+intptr_t NativeStructType::NumPrimitiveMembersRecursive() const {
   intptr_t count = 0;
   for (intptr_t i = 0; i < members_.length(); i++) {
     count += members_[i]->NumPrimitiveMembersRecursive();
@@ -625,6 +676,14 @@
   return count;
 }
 
+intptr_t NativeUnionType::NumPrimitiveMembersRecursive() const {
+  intptr_t count = 0;
+  for (intptr_t i = 0; i < members_.length(); i++) {
+    count = Utils::Maximum(count, members_[i]->NumPrimitiveMembersRecursive());
+  }
+  return count;
+}
+
 const NativePrimitiveType& NativePrimitiveType::FirstPrimitiveMember() const {
   return *this;
 }
@@ -695,7 +754,7 @@
   return true;
 }
 
-bool NativeCompoundType::ContainsOnlyFloats(Range range) const {
+bool NativeStructType::ContainsOnlyFloats(Range range) const {
   const auto this_range = Range::StartAndEnd(0, SizeInBytes());
   ASSERT(this_range.Contains(range));
 
@@ -721,6 +780,21 @@
   return true;
 }
 
+bool NativeUnionType::ContainsOnlyFloats(Range range) const {
+  for (intptr_t i = 0; i < members_.length(); i++) {
+    const auto& member = *members_[i];
+    const intptr_t member_size = member.SizeInBytes();
+    const auto member_range = Range::StartAndLength(0, member_size);
+    if (member_range.Overlaps(range)) {
+      const auto member_range_clipped = member_range.Intersect(range);
+      if (!member.ContainsOnlyFloats(member_range_clipped)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
 intptr_t NativeCompoundType::NumberOfWordSizeChunksOnlyFloat() const {
   // O(n^2) implementation, but only invoked for small structs.
   ASSERT(SizeInBytes() <= 16);
@@ -767,7 +841,7 @@
   return false;
 }
 
-bool NativeCompoundType::ContainsUnalignedMembers(intptr_t offset) const {
+bool NativeStructType::ContainsUnalignedMembers(intptr_t offset) const {
   for (intptr_t i = 0; i < members_.length(); i++) {
     const auto& member = *members_.At(i);
     const intptr_t member_offset = member_offsets_.At(i);
@@ -778,6 +852,16 @@
   return false;
 }
 
+bool NativeUnionType::ContainsUnalignedMembers(intptr_t offset) const {
+  for (intptr_t i = 0; i < members_.length(); i++) {
+    const auto& member = *members_.At(i);
+    if (member.ContainsUnalignedMembers(offset)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 static void ContainsHomogenuousFloatsRecursive(const NativeTypes& types,
                                                bool* only_float,
                                                bool* only_double) {
diff --git a/runtime/vm/compiler/ffi/native_type.h b/runtime/vm/compiler/ffi/native_type.h
index e7a156e..de69bd5 100644
--- a/runtime/vm/compiler/ffi/native_type.h
+++ b/runtime/vm/compiler/ffi/native_type.h
@@ -257,20 +257,10 @@
 
 using NativeTypes = ZoneGrowableArray<const NativeType*>;
 
-// Struct
-//
-// TODO(dartbug.com/38491): Support unions.
+// Compound native types: native arrays and native structs.
 class NativeCompoundType : public NativeType {
  public:
-  static NativeCompoundType& FromNativeTypes(
-      Zone* zone,
-      const NativeTypes& members,
-      intptr_t member_packing = kMaxInt32);
-
   const NativeTypes& members() const { return members_; }
-  const ZoneGrowableArray<intptr_t>& member_offsets() const {
-    return member_offsets_;
-  }
 
   virtual bool IsCompound() const { return true; }
 
@@ -285,7 +275,7 @@
                        bool verbose = true) const;
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-  virtual bool ContainsOnlyFloats(Range range) const;
+  virtual bool ContainsOnlyFloats(Range range) const = 0;
 
   // Returns how many word-sized chuncks _only_ contain floats.
   //
@@ -298,7 +288,7 @@
   intptr_t NumberOfWordSizeChunksNotOnlyFloat() const;
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
-  virtual bool ContainsUnalignedMembers(intptr_t offset = 0) const;
+  virtual bool ContainsUnalignedMembers(intptr_t offset = 0) const = 0;
 
   // Whether this type has only same-size floating point members.
   //
@@ -306,26 +296,88 @@
   // and arm64.
   bool ContainsHomogenuousFloats() const;
 
-  virtual intptr_t NumPrimitiveMembersRecursive() const;
+  virtual intptr_t NumPrimitiveMembersRecursive() const = 0;
   virtual const NativePrimitiveType& FirstPrimitiveMember() const;
 
- private:
+ protected:
   NativeCompoundType(const NativeTypes& members,
-                     const ZoneGrowableArray<intptr_t>& member_offsets,
                      intptr_t size,
                      intptr_t alignment_field,
                      intptr_t alignment_stack)
       : members_(members),
-        member_offsets_(member_offsets),
         size_(size),
         alignment_field_(alignment_field),
         alignment_stack_(alignment_stack) {}
 
   const NativeTypes& members_;
-  const ZoneGrowableArray<intptr_t>& member_offsets_;
   const intptr_t size_;
   const intptr_t alignment_field_;
   const intptr_t alignment_stack_;
+
+  virtual void PrintCompoundType(BaseTextBuffer* f) const = 0;
+  virtual void PrintMemberOffset(BaseTextBuffer* f,
+                                 intptr_t member_index) const {}
+};
+
+// Native structs.
+class NativeStructType : public NativeCompoundType {
+ public:
+  static NativeStructType& FromNativeTypes(Zone* zone,
+                                           const NativeTypes& members,
+                                           intptr_t member_packing = kMaxInt32);
+
+  const ZoneGrowableArray<intptr_t>& member_offsets() const {
+    return member_offsets_;
+  }
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  virtual bool ContainsOnlyFloats(Range range) const;
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
+
+  virtual bool ContainsUnalignedMembers(intptr_t offset = 0) const;
+
+  virtual intptr_t NumPrimitiveMembersRecursive() const;
+
+ protected:
+  virtual void PrintCompoundType(BaseTextBuffer* f) const;
+  virtual void PrintMemberOffset(BaseTextBuffer* f,
+                                 intptr_t member_index) const;
+
+ private:
+  NativeStructType(const NativeTypes& members,
+                   const ZoneGrowableArray<intptr_t>& member_offsets,
+                   intptr_t size,
+                   intptr_t alignment_field,
+                   intptr_t alignment_stack)
+      : NativeCompoundType(members, size, alignment_field, alignment_stack),
+        member_offsets_(member_offsets) {}
+
+  const ZoneGrowableArray<intptr_t>& member_offsets_;
+};
+
+// Native unions.
+class NativeUnionType : public NativeCompoundType {
+ public:
+  static NativeUnionType& FromNativeTypes(Zone* zone,
+                                          const NativeTypes& members);
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  virtual bool ContainsOnlyFloats(Range range) const;
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
+
+  virtual bool ContainsUnalignedMembers(intptr_t offset = 0) const;
+
+  virtual intptr_t NumPrimitiveMembersRecursive() const;
+
+ protected:
+  virtual void PrintCompoundType(BaseTextBuffer* f) const;
+
+ private:
+  NativeUnionType(const NativeTypes& members,
+                  intptr_t size,
+                  intptr_t alignment_field,
+                  intptr_t alignment_stack)
+      : NativeCompoundType(members, size, alignment_field, alignment_stack) {}
 };
 
 class NativeFunctionType : public ZoneAllocated {
diff --git a/runtime/vm/compiler/ffi/native_type_test.cc b/runtime/vm/compiler/ffi/native_type_test.cc
index 63cc7b4..d132b91 100644
--- a/runtime/vm/compiler/ffi/native_type_test.cc
+++ b/runtime/vm/compiler/ffi/native_type_test.cc
@@ -17,7 +17,7 @@
                                         const NativeTypes& member_types,
                                         intptr_t packing = kMaxInt32) {
   const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(zone, member_types, packing);
+      NativeStructType::FromNativeTypes(zone, member_types, packing);
 
   const char* test_result = struct_type.ToCString(zone, /*multi_line=*/true);
 
@@ -181,7 +181,7 @@
   auto& inner_struct_members = *new (Z) NativeTypes(Z, 1);
   inner_struct_members.Add(&inner_array_type);
   const auto& inner_struct =
-      NativeCompoundType::FromNativeTypes(Z, inner_struct_members);
+      NativeStructType::FromNativeTypes(Z, inner_struct_members);
 
   const auto& array_type = *new (Z) NativeArrayType(inner_struct, 2);
 
@@ -207,7 +207,7 @@
   const intptr_t packing = 1;
 
   const auto& struct_type =
-      NativeCompoundType::FromNativeTypes(Z, members, packing);
+      NativeStructType::FromNativeTypes(Z, members, packing);
 
   // Should be 3 bytes on every platform.
   EXPECT_EQ(3, struct_type.SizeInBytes());
@@ -223,7 +223,7 @@
   inner_members.Add(&uint8_type);
   const intptr_t packing = 1;
   const auto& inner_struct_type =
-      NativeCompoundType::FromNativeTypes(Z, inner_members, packing);
+      NativeStructType::FromNativeTypes(Z, inner_members, packing);
 
   EXPECT_EQ(3, inner_struct_type.SizeInBytes());
   // Non-windows x64 considers this struct as all members aligned, even though
@@ -234,7 +234,7 @@
 
   auto& members = *new (Z) NativeTypes(Z, 1);
   members.Add(&array_type);
-  const auto& struct_type = NativeCompoundType::FromNativeTypes(Z, members);
+  const auto& struct_type = NativeStructType::FromNativeTypes(Z, members);
 
   EXPECT_EQ(6, struct_type.SizeInBytes());
   // Non-windows x64 passes this as a struct with unaligned members, because
@@ -251,7 +251,7 @@
   inner_members.Add(&uint8_type);
   const intptr_t packing = 1;
   const auto& inner_struct_type =
-      NativeCompoundType::FromNativeTypes(Z, inner_members, packing);
+      NativeStructType::FromNativeTypes(Z, inner_members, packing);
 
   EXPECT_EQ(5, inner_struct_type.SizeInBytes());
   // Non-windows x64 considers this struct as all members aligned, even though
@@ -261,7 +261,7 @@
   auto& members = *new (Z) NativeTypes(Z, 2);
   members.Add(&uint8_type);
   members.Add(&inner_struct_type);
-  const auto& struct_type = NativeCompoundType::FromNativeTypes(Z, members);
+  const auto& struct_type = NativeStructType::FromNativeTypes(Z, members);
 
   EXPECT_EQ(6, struct_type.SizeInBytes());
   // Non-windows x64 passes this as a struct with unaligned members, even
@@ -269,6 +269,76 @@
   EXPECT(struct_type.ContainsUnalignedMembers());
 }
 
+UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_union_size) {
+  const auto& uint8_type = *new (Z) NativePrimitiveType(kUint8);
+  const auto& uint32_type = *new (Z) NativePrimitiveType(kUint32);
+
+  const auto& array8_bytes = *new (Z) NativeArrayType(uint32_type, 2);
+  const auto& array9_bytes = *new (Z) NativeArrayType(uint8_type, 9);
+
+  auto& members = *new (Z) NativeTypes(Z, 2);
+  members.Add(&array8_bytes);
+  members.Add(&array9_bytes);
+  const auto& union_type = NativeUnionType::FromNativeTypes(Z, members);
+
+  // The alignment requirements of the first member and the size of the second
+  // member force the size to be rounded up to 12.
+  EXPECT_EQ(12, union_type.SizeInBytes());
+
+  EXPECT(!union_type.ContainsUnalignedMembers());
+}
+
+UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_union_primitive_members) {
+  const auto& float_type = *new (Z) NativePrimitiveType(kFloat);
+
+  const auto& float_array_type = *new (Z) NativeArrayType(float_type, 3);
+
+  auto& struct_member_types = *new (Z) NativeTypes(Z, 4);
+  struct_member_types.Add(&float_type);
+  struct_member_types.Add(&float_type);
+  struct_member_types.Add(&float_type);
+  struct_member_types.Add(&float_type);
+  const auto& struct_type =
+      NativeStructType::FromNativeTypes(Z, struct_member_types);
+
+  auto& member_types = *new (Z) NativeTypes(Z, 2);
+  member_types.Add(&float_array_type);
+  member_types.Add(&struct_type);
+  const auto& union_type = NativeUnionType::FromNativeTypes(Z, member_types);
+
+  EXPECT_EQ(16, union_type.SizeInBytes());
+
+  EXPECT_EQ(4, union_type.NumPrimitiveMembersRecursive());
+  EXPECT(union_type.FirstPrimitiveMember().Equals(float_type));
+  EXPECT(union_type.ContainsHomogenuousFloats());
+
+  EXPECT(!union_type.ContainsUnalignedMembers());
+}
+
+UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_union_unaligned) {
+  const auto& uint8_type = *new (Z) NativePrimitiveType(kUint8);
+  const auto& uint32_type = *new (Z) NativePrimitiveType(kUint32);
+
+  auto& inner_members = *new (Z) NativeTypes(Z, 2);
+  inner_members.Add(&uint8_type);
+  inner_members.Add(&uint32_type);
+  const intptr_t packing = 1;
+  const auto& struct_type =
+      NativeStructType::FromNativeTypes(Z, inner_members, packing);
+
+  const auto& array_type = *new (Z) NativeArrayType(uint8_type, 5);
+
+  auto& member_types = *new (Z) NativeTypes(Z, 2);
+  member_types.Add(&array_type);
+  member_types.Add(&struct_type);
+  const auto& union_type = NativeUnionType::FromNativeTypes(Z, member_types);
+
+  EXPECT_EQ(5, union_type.SizeInBytes());
+  EXPECT_EQ(1, union_type.AlignmentInBytesField());
+
+  EXPECT(union_type.ContainsUnalignedMembers());
+}
+
 }  // namespace ffi
 }  // namespace compiler
 }  // namespace dart
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_android.expect
index 1170c02..19a9509 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_android.expect
@@ -1,4 +1,4 @@
-P(r0 int64) Compound(size: 128)
+P(r0 int64) Struct(size: 128)
 r1 int32
 =>
-P(r8 int64) Compound(size: 128)
+P(r8 int64) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_ios.expect
index 1170c02..19a9509 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_ios.expect
@@ -1,4 +1,4 @@
-P(r0 int64) Compound(size: 128)
+P(r0 int64) Struct(size: 128)
 r1 int32
 =>
-P(r8 int64) Compound(size: 128)
+P(r8 int64) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_linux.expect
index 1170c02..19a9509 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_linux.expect
@@ -1,4 +1,4 @@
-P(r0 int64) Compound(size: 128)
+P(r0 int64) Struct(size: 128)
 r1 int32
 =>
-P(r8 int64) Compound(size: 128)
+P(r8 int64) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_macos.expect
index 1170c02..19a9509 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_macos.expect
@@ -1,4 +1,4 @@
-P(r0 int64) Compound(size: 128)
+P(r0 int64) Struct(size: 128)
 r1 int32
 =>
-P(r8 int64) Compound(size: 128)
+P(r8 int64) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_android.expect
index 230a6ab..7acd015 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_android.expect
@@ -1,4 +1,4 @@
-M((r2, r3) int64, S+0 int64, S+8 int64, S+16 int64, S+24 int64, S+32 int64, S+40 int64, S+48 int64, S+56 int64, S+64 int64, S+72 int64, S+80 int64, S+88 int64, S+96 int64, S+104 int64, S+112 int64) Compound(size: 128)
+M((r2, r3) int64, S+0 int64, S+8 int64, S+16 int64, S+24 int64, S+32 int64, S+40 int64, S+48 int64, S+56 int64, S+64 int64, S+72 int64, S+80 int64, S+88 int64, S+96 int64, S+104 int64, S+112 int64) Struct(size: 128)
 S+120 int32
 =>
-P(r0 uint32) Compound(size: 128)
+P(r0 uint32) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_ios.expect
index 230a6ab..7acd015 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_ios.expect
@@ -1,4 +1,4 @@
-M((r2, r3) int64, S+0 int64, S+8 int64, S+16 int64, S+24 int64, S+32 int64, S+40 int64, S+48 int64, S+56 int64, S+64 int64, S+72 int64, S+80 int64, S+88 int64, S+96 int64, S+104 int64, S+112 int64) Compound(size: 128)
+M((r2, r3) int64, S+0 int64, S+8 int64, S+16 int64, S+24 int64, S+32 int64, S+40 int64, S+48 int64, S+56 int64, S+64 int64, S+72 int64, S+80 int64, S+88 int64, S+96 int64, S+104 int64, S+112 int64) Struct(size: 128)
 S+120 int32
 =>
-P(r0 uint32) Compound(size: 128)
+P(r0 uint32) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_linux.expect
index 230a6ab..7acd015 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm_linux.expect
@@ -1,4 +1,4 @@
-M((r2, r3) int64, S+0 int64, S+8 int64, S+16 int64, S+24 int64, S+32 int64, S+40 int64, S+48 int64, S+56 int64, S+64 int64, S+72 int64, S+80 int64, S+88 int64, S+96 int64, S+104 int64, S+112 int64) Compound(size: 128)
+M((r2, r3) int64, S+0 int64, S+8 int64, S+16 int64, S+24 int64, S+32 int64, S+40 int64, S+48 int64, S+56 int64, S+64 int64, S+72 int64, S+80 int64, S+88 int64, S+96 int64, S+104 int64, S+112 int64) Struct(size: 128)
 S+120 int32
 =>
-P(r0 uint32) Compound(size: 128)
+P(r0 uint32) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_android.expect
index c765e39..cc93dfd 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_android.expect
@@ -1,4 +1,4 @@
-S+4 Compound(size: 128)
+S+4 Struct(size: 128)
 S+132 int32
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 128)
+P(S+0 uint32, ret:eax uint32) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_linux.expect
index c765e39..cc93dfd 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_linux.expect
@@ -1,4 +1,4 @@
-S+4 Compound(size: 128)
+S+4 Struct(size: 128)
 S+132 int32
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 128)
+P(S+0 uint32, ret:eax uint32) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_win.expect
index c765e39..cc93dfd 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_win.expect
@@ -1,4 +1,4 @@
-S+4 Compound(size: 128)
+S+4 Struct(size: 128)
 S+132 int32
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 128)
+P(S+0 uint32, ret:eax uint32) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_ios.expect
index f5ce3da..c918afa 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_ios.expect
@@ -1,4 +1,4 @@
-S+0 Compound(size: 128)
+S+0 Struct(size: 128)
 rsi int32
 =>
-P(rdi int64, ret:rax int64) Compound(size: 128)
+P(rdi int64, ret:rax int64) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_linux.expect
index f5ce3da..c918afa 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_linux.expect
@@ -1,4 +1,4 @@
-S+0 Compound(size: 128)
+S+0 Struct(size: 128)
 rsi int32
 =>
-P(rdi int64, ret:rax int64) Compound(size: 128)
+P(rdi int64, ret:rax int64) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_macos.expect
index f5ce3da..c918afa 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_macos.expect
@@ -1,4 +1,4 @@
-S+0 Compound(size: 128)
+S+0 Struct(size: 128)
 rsi int32
 =>
-P(rdi int64, ret:rax int64) Compound(size: 128)
+P(rdi int64, ret:rax int64) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_win.expect
index ff78425..754e049 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_win.expect
@@ -1,4 +1,4 @@
-P(rdx int64) Compound(size: 128)
+P(rdx int64) Struct(size: 128)
 r8 int32
 =>
-P(rcx int64, ret:rax int64) Compound(size: 128)
+P(rcx int64, ret:rax int64) Struct(size: 128)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_android.expect
index f4b87ed..123cea6 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_android.expect
@@ -1,15 +1,15 @@
-M(v0 float, v1 float, v2 float, v3 float) Compound(size: 16)
+M(v0 float, v1 float, v2 float, v3 float) Struct(size: 16)
 v4 float
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
-S+96 Compound(size: 16)
-S+112 Compound(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
+S+96 Struct(size: 16)
+S+112 Struct(size: 16)
 S+128 float
 r0 int8
-S+136 Compound(size: 16)
+S+136 Struct(size: 16)
 =>
-M(v0 float, v1 float, v2 float, v3 float) Compound(size: 16)
+M(v0 float, v1 float, v2 float, v3 float) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_ios.expect
index 70977c2..e62e479 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_ios.expect
@@ -1,15 +1,15 @@
-M(v0 float, v1 float, v2 float, v3 float) Compound(size: 16)
+M(v0 float, v1 float, v2 float, v3 float) Struct(size: 16)
 v4 float
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
-S+96 Compound(size: 16)
-S+112 Compound(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
+S+96 Struct(size: 16)
+S+112 Struct(size: 16)
 S+128 float
 r0 int32[int8]
-S+132 Compound(size: 16)
+S+132 Struct(size: 16)
 =>
-M(v0 float, v1 float, v2 float, v3 float) Compound(size: 16)
+M(v0 float, v1 float, v2 float, v3 float) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_linux.expect
index f4b87ed..123cea6 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_linux.expect
@@ -1,15 +1,15 @@
-M(v0 float, v1 float, v2 float, v3 float) Compound(size: 16)
+M(v0 float, v1 float, v2 float, v3 float) Struct(size: 16)
 v4 float
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
-S+96 Compound(size: 16)
-S+112 Compound(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
+S+96 Struct(size: 16)
+S+112 Struct(size: 16)
 S+128 float
 r0 int8
-S+136 Compound(size: 16)
+S+136 Struct(size: 16)
 =>
-M(v0 float, v1 float, v2 float, v3 float) Compound(size: 16)
+M(v0 float, v1 float, v2 float, v3 float) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_macos.expect
index f4b87ed..123cea6 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_macos.expect
@@ -1,15 +1,15 @@
-M(v0 float, v1 float, v2 float, v3 float) Compound(size: 16)
+M(v0 float, v1 float, v2 float, v3 float) Struct(size: 16)
 v4 float
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
-S+96 Compound(size: 16)
-S+112 Compound(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
+S+96 Struct(size: 16)
+S+112 Struct(size: 16)
 S+128 float
 r0 int8
-S+136 Compound(size: 16)
+S+136 Struct(size: 16)
 =>
-M(v0 float, v1 float, v2 float, v3 float) Compound(size: 16)
+M(v0 float, v1 float, v2 float, v3 float) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_android.expect
index 24fce41..cf17311 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_android.expect
@@ -1,15 +1,15 @@
-M(r1 int32, r2 int32, r3 int32, S+0 int32) Compound(size: 16)
+M(r1 int32, r2 int32, r3 int32, S+0 int32) Struct(size: 16)
 S+4 float
-M(S+8 int32, S+12 int32, S+16 int32, S+20 int32) Compound(size: 16)
-M(S+24 int32, S+28 int32, S+32 int32, S+36 int32) Compound(size: 16)
-M(S+40 int32, S+44 int32, S+48 int32, S+52 int32) Compound(size: 16)
-M(S+56 int32, S+60 int32, S+64 int32, S+68 int32) Compound(size: 16)
-M(S+72 int32, S+76 int32, S+80 int32, S+84 int32) Compound(size: 16)
-M(S+88 int32, S+92 int32, S+96 int32, S+100 int32) Compound(size: 16)
-M(S+104 int32, S+108 int32, S+112 int32, S+116 int32) Compound(size: 16)
-M(S+120 int32, S+124 int32, S+128 int32, S+132 int32) Compound(size: 16)
+M(S+8 int32, S+12 int32, S+16 int32, S+20 int32) Struct(size: 16)
+M(S+24 int32, S+28 int32, S+32 int32, S+36 int32) Struct(size: 16)
+M(S+40 int32, S+44 int32, S+48 int32, S+52 int32) Struct(size: 16)
+M(S+56 int32, S+60 int32, S+64 int32, S+68 int32) Struct(size: 16)
+M(S+72 int32, S+76 int32, S+80 int32, S+84 int32) Struct(size: 16)
+M(S+88 int32, S+92 int32, S+96 int32, S+100 int32) Struct(size: 16)
+M(S+104 int32, S+108 int32, S+112 int32, S+116 int32) Struct(size: 16)
+M(S+120 int32, S+124 int32, S+128 int32, S+132 int32) Struct(size: 16)
 S+136 float
 S+140 int32[int8]
-M(S+144 int32, S+148 int32, S+152 int32, S+156 int32) Compound(size: 16)
+M(S+144 int32, S+148 int32, S+152 int32, S+156 int32) Struct(size: 16)
 =>
-P(r0 uint32) Compound(size: 16)
+P(r0 uint32) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_ios.expect
index 124f1cd..4ca7812 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_ios.expect
@@ -1,15 +1,15 @@
-M(s0 float, s1 float, s2 float, s3 float) Compound(size: 16)
+M(s0 float, s1 float, s2 float, s3 float) Struct(size: 16)
 s4 float
-M(s5 float, s6 float, s7 float, s8 float) Compound(size: 16)
-M(s9 float, s10 float, s11 float, s12 float) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
+M(s5 float, s6 float, s7 float, s8 float) Struct(size: 16)
+M(s9 float, s10 float, s11 float, s12 float) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
 S+96 float
 r0 int32[int8]
-S+100 Compound(size: 16)
+S+100 Struct(size: 16)
 =>
-M(s0 float, s1 float, s2 float, s3 float) Compound(size: 16)
+M(s0 float, s1 float, s2 float, s3 float) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_linux.expect
index 124f1cd..4ca7812 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm_linux.expect
@@ -1,15 +1,15 @@
-M(s0 float, s1 float, s2 float, s3 float) Compound(size: 16)
+M(s0 float, s1 float, s2 float, s3 float) Struct(size: 16)
 s4 float
-M(s5 float, s6 float, s7 float, s8 float) Compound(size: 16)
-M(s9 float, s10 float, s11 float, s12 float) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
+M(s5 float, s6 float, s7 float, s8 float) Struct(size: 16)
+M(s9 float, s10 float, s11 float, s12 float) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
 S+96 float
 r0 int32[int8]
-S+100 Compound(size: 16)
+S+100 Struct(size: 16)
 =>
-M(s0 float, s1 float, s2 float, s3 float) Compound(size: 16)
+M(s0 float, s1 float, s2 float, s3 float) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_android.expect
index 3c127f9..9c4467a 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_android.expect
@@ -1,15 +1,15 @@
-S+4 Compound(size: 16)
+S+4 Struct(size: 16)
 S+20 float
-S+24 Compound(size: 16)
-S+40 Compound(size: 16)
-S+56 Compound(size: 16)
-S+72 Compound(size: 16)
-S+88 Compound(size: 16)
-S+104 Compound(size: 16)
-S+120 Compound(size: 16)
-S+136 Compound(size: 16)
+S+24 Struct(size: 16)
+S+40 Struct(size: 16)
+S+56 Struct(size: 16)
+S+72 Struct(size: 16)
+S+88 Struct(size: 16)
+S+104 Struct(size: 16)
+S+120 Struct(size: 16)
+S+136 Struct(size: 16)
 S+152 float
 S+156 int32[int8]
-S+160 Compound(size: 16)
+S+160 Struct(size: 16)
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 16)
+P(S+0 uint32, ret:eax uint32) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_linux.expect
index 3c127f9..9c4467a 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_linux.expect
@@ -1,15 +1,15 @@
-S+4 Compound(size: 16)
+S+4 Struct(size: 16)
 S+20 float
-S+24 Compound(size: 16)
-S+40 Compound(size: 16)
-S+56 Compound(size: 16)
-S+72 Compound(size: 16)
-S+88 Compound(size: 16)
-S+104 Compound(size: 16)
-S+120 Compound(size: 16)
-S+136 Compound(size: 16)
+S+24 Struct(size: 16)
+S+40 Struct(size: 16)
+S+56 Struct(size: 16)
+S+72 Struct(size: 16)
+S+88 Struct(size: 16)
+S+104 Struct(size: 16)
+S+120 Struct(size: 16)
+S+136 Struct(size: 16)
 S+152 float
 S+156 int32[int8]
-S+160 Compound(size: 16)
+S+160 Struct(size: 16)
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 16)
+P(S+0 uint32, ret:eax uint32) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_win.expect
index 3c127f9..9c4467a 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_win.expect
@@ -1,15 +1,15 @@
-S+4 Compound(size: 16)
+S+4 Struct(size: 16)
 S+20 float
-S+24 Compound(size: 16)
-S+40 Compound(size: 16)
-S+56 Compound(size: 16)
-S+72 Compound(size: 16)
-S+88 Compound(size: 16)
-S+104 Compound(size: 16)
-S+120 Compound(size: 16)
-S+136 Compound(size: 16)
+S+24 Struct(size: 16)
+S+40 Struct(size: 16)
+S+56 Struct(size: 16)
+S+72 Struct(size: 16)
+S+88 Struct(size: 16)
+S+104 Struct(size: 16)
+S+120 Struct(size: 16)
+S+136 Struct(size: 16)
 S+152 float
 S+156 int32[int8]
-S+160 Compound(size: 16)
+S+160 Struct(size: 16)
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 16)
+P(S+0 uint32, ret:eax uint32) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_ios.expect
index 991a252..4e2829c 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_ios.expect
@@ -1,15 +1,15 @@
-M(xmm0 double, xmm1 double) Compound(size: 16)
+M(xmm0 double, xmm1 double) Struct(size: 16)
 xmm2 float
-M(xmm3 double, xmm4 double) Compound(size: 16)
-M(xmm5 double, xmm6 double) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
+M(xmm3 double, xmm4 double) Struct(size: 16)
+M(xmm5 double, xmm6 double) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
 xmm7 float
 rdi int32[int8]
-S+96 Compound(size: 16)
+S+96 Struct(size: 16)
 =>
-M(xmm0 double, xmm1 double) Compound(size: 16)
+M(xmm0 double, xmm1 double) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_linux.expect
index 991a252..4e2829c 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_linux.expect
@@ -1,15 +1,15 @@
-M(xmm0 double, xmm1 double) Compound(size: 16)
+M(xmm0 double, xmm1 double) Struct(size: 16)
 xmm2 float
-M(xmm3 double, xmm4 double) Compound(size: 16)
-M(xmm5 double, xmm6 double) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
+M(xmm3 double, xmm4 double) Struct(size: 16)
+M(xmm5 double, xmm6 double) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
 xmm7 float
 rdi int32[int8]
-S+96 Compound(size: 16)
+S+96 Struct(size: 16)
 =>
-M(xmm0 double, xmm1 double) Compound(size: 16)
+M(xmm0 double, xmm1 double) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_macos.expect
index 991a252..4e2829c 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_macos.expect
@@ -1,15 +1,15 @@
-M(xmm0 double, xmm1 double) Compound(size: 16)
+M(xmm0 double, xmm1 double) Struct(size: 16)
 xmm2 float
-M(xmm3 double, xmm4 double) Compound(size: 16)
-M(xmm5 double, xmm6 double) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
+M(xmm3 double, xmm4 double) Struct(size: 16)
+M(xmm5 double, xmm6 double) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
 xmm7 float
 rdi int32[int8]
-S+96 Compound(size: 16)
+S+96 Struct(size: 16)
 =>
-M(xmm0 double, xmm1 double) Compound(size: 16)
+M(xmm0 double, xmm1 double) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_win.expect
index 8e31945..1a06314 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_win.expect
@@ -1,15 +1,15 @@
-P(rdx int64) Compound(size: 16)
+P(rdx int64) Struct(size: 16)
 xmm2 float
-P(r9 int64) Compound(size: 16)
-P(S+0 int64) Compound(size: 16)
-P(S+8 int64) Compound(size: 16)
-P(S+16 int64) Compound(size: 16)
-P(S+24 int64) Compound(size: 16)
-P(S+32 int64) Compound(size: 16)
-P(S+40 int64) Compound(size: 16)
-P(S+48 int64) Compound(size: 16)
+P(r9 int64) Struct(size: 16)
+P(S+0 int64) Struct(size: 16)
+P(S+8 int64) Struct(size: 16)
+P(S+16 int64) Struct(size: 16)
+P(S+24 int64) Struct(size: 16)
+P(S+32 int64) Struct(size: 16)
+P(S+40 int64) Struct(size: 16)
+P(S+48 int64) Struct(size: 16)
 S+56 float
 S+64 int8
-P(S+72 int64) Compound(size: 16)
+P(S+72 int64) Struct(size: 16)
 =>
-P(rcx int64, ret:rax int64) Compound(size: 16)
+P(rcx int64, ret:rax int64) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_ios.expect
index 2b50280..62ce615 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_ios.expect
@@ -1,13 +1,13 @@
-M(xmm0 double, rdi int64) Compound(size: 16)
-M(xmm1 double, rsi int64) Compound(size: 16)
-M(xmm2 double, rdx int64) Compound(size: 16)
-M(xmm3 double, rcx int64) Compound(size: 16)
-M(xmm4 double, r8 int64) Compound(size: 16)
-M(xmm5 double, r9 int64) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
+M(xmm0 double, rdi int64) Struct(size: 16)
+M(xmm1 double, rsi int64) Struct(size: 16)
+M(xmm2 double, rdx int64) Struct(size: 16)
+M(xmm3 double, rcx int64) Struct(size: 16)
+M(xmm4 double, r8 int64) Struct(size: 16)
+M(xmm5 double, r9 int64) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
 xmm6 float
 =>
-M(xmm0 double, rax int64) Compound(size: 16)
+M(xmm0 double, rax int64) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_linux.expect
index 2b50280..62ce615 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_linux.expect
@@ -1,13 +1,13 @@
-M(xmm0 double, rdi int64) Compound(size: 16)
-M(xmm1 double, rsi int64) Compound(size: 16)
-M(xmm2 double, rdx int64) Compound(size: 16)
-M(xmm3 double, rcx int64) Compound(size: 16)
-M(xmm4 double, r8 int64) Compound(size: 16)
-M(xmm5 double, r9 int64) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
+M(xmm0 double, rdi int64) Struct(size: 16)
+M(xmm1 double, rsi int64) Struct(size: 16)
+M(xmm2 double, rdx int64) Struct(size: 16)
+M(xmm3 double, rcx int64) Struct(size: 16)
+M(xmm4 double, r8 int64) Struct(size: 16)
+M(xmm5 double, r9 int64) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
 xmm6 float
 =>
-M(xmm0 double, rax int64) Compound(size: 16)
+M(xmm0 double, rax int64) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_macos.expect
index 2b50280..62ce615 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_macos.expect
@@ -1,13 +1,13 @@
-M(xmm0 double, rdi int64) Compound(size: 16)
-M(xmm1 double, rsi int64) Compound(size: 16)
-M(xmm2 double, rdx int64) Compound(size: 16)
-M(xmm3 double, rcx int64) Compound(size: 16)
-M(xmm4 double, r8 int64) Compound(size: 16)
-M(xmm5 double, r9 int64) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
+M(xmm0 double, rdi int64) Struct(size: 16)
+M(xmm1 double, rsi int64) Struct(size: 16)
+M(xmm2 double, rdx int64) Struct(size: 16)
+M(xmm3 double, rcx int64) Struct(size: 16)
+M(xmm4 double, r8 int64) Struct(size: 16)
+M(xmm5 double, r9 int64) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
 xmm6 float
 =>
-M(xmm0 double, rax int64) Compound(size: 16)
+M(xmm0 double, rax int64) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_win.expect
index d21ee2b..d237e6e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_win.expect
@@ -1,13 +1,13 @@
-P(rdx int64) Compound(size: 16)
-P(r8 int64) Compound(size: 16)
-P(r9 int64) Compound(size: 16)
-P(S+0 int64) Compound(size: 16)
-P(S+8 int64) Compound(size: 16)
-P(S+16 int64) Compound(size: 16)
-P(S+24 int64) Compound(size: 16)
-P(S+32 int64) Compound(size: 16)
-P(S+40 int64) Compound(size: 16)
-P(S+48 int64) Compound(size: 16)
+P(rdx int64) Struct(size: 16)
+P(r8 int64) Struct(size: 16)
+P(r9 int64) Struct(size: 16)
+P(S+0 int64) Struct(size: 16)
+P(S+8 int64) Struct(size: 16)
+P(S+16 int64) Struct(size: 16)
+P(S+24 int64) Struct(size: 16)
+P(S+32 int64) Struct(size: 16)
+P(S+40 int64) Struct(size: 16)
+P(S+48 int64) Struct(size: 16)
 S+56 float
 =>
-P(rcx int64, ret:rax int64) Compound(size: 16)
+P(rcx int64, ret:rax int64) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_ios.expect
index bcdf3b5..71af233 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_ios.expect
@@ -2,16 +2,16 @@
 xmm1 float
 xmm2 float
 xmm3 float
-M(xmm4 double, rdi int64) Compound(size: 16)
-M(xmm5 double, rsi int64) Compound(size: 16)
-M(xmm6 double, rdx int64) Compound(size: 16)
-M(xmm7 double, rcx int64) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
+M(xmm4 double, rdi int64) Struct(size: 16)
+M(xmm5 double, rsi int64) Struct(size: 16)
+M(xmm6 double, rdx int64) Struct(size: 16)
+M(xmm7 double, rcx int64) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
 r8 int32
 =>
-M(xmm0 double, rax int64) Compound(size: 16)
+M(xmm0 double, rax int64) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_linux.expect
index bcdf3b5..71af233 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_linux.expect
@@ -2,16 +2,16 @@
 xmm1 float
 xmm2 float
 xmm3 float
-M(xmm4 double, rdi int64) Compound(size: 16)
-M(xmm5 double, rsi int64) Compound(size: 16)
-M(xmm6 double, rdx int64) Compound(size: 16)
-M(xmm7 double, rcx int64) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
+M(xmm4 double, rdi int64) Struct(size: 16)
+M(xmm5 double, rsi int64) Struct(size: 16)
+M(xmm6 double, rdx int64) Struct(size: 16)
+M(xmm7 double, rcx int64) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
 r8 int32
 =>
-M(xmm0 double, rax int64) Compound(size: 16)
+M(xmm0 double, rax int64) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_macos.expect
index bcdf3b5..71af233 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_macos.expect
@@ -2,16 +2,16 @@
 xmm1 float
 xmm2 float
 xmm3 float
-M(xmm4 double, rdi int64) Compound(size: 16)
-M(xmm5 double, rsi int64) Compound(size: 16)
-M(xmm6 double, rdx int64) Compound(size: 16)
-M(xmm7 double, rcx int64) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
-S+64 Compound(size: 16)
-S+80 Compound(size: 16)
+M(xmm4 double, rdi int64) Struct(size: 16)
+M(xmm5 double, rsi int64) Struct(size: 16)
+M(xmm6 double, rdx int64) Struct(size: 16)
+M(xmm7 double, rcx int64) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
+S+64 Struct(size: 16)
+S+80 Struct(size: 16)
 r8 int32
 =>
-M(xmm0 double, rax int64) Compound(size: 16)
+M(xmm0 double, rax int64) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_win.expect
index bb695c2..51dae2a 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_win.expect
@@ -2,16 +2,16 @@
 xmm2 float
 xmm3 float
 S+0 float
-P(S+8 int64) Compound(size: 16)
-P(S+16 int64) Compound(size: 16)
-P(S+24 int64) Compound(size: 16)
-P(S+32 int64) Compound(size: 16)
-P(S+40 int64) Compound(size: 16)
-P(S+48 int64) Compound(size: 16)
-P(S+56 int64) Compound(size: 16)
-P(S+64 int64) Compound(size: 16)
-P(S+72 int64) Compound(size: 16)
-P(S+80 int64) Compound(size: 16)
+P(S+8 int64) Struct(size: 16)
+P(S+16 int64) Struct(size: 16)
+P(S+24 int64) Struct(size: 16)
+P(S+32 int64) Struct(size: 16)
+P(S+40 int64) Struct(size: 16)
+P(S+48 int64) Struct(size: 16)
+P(S+56 int64) Struct(size: 16)
+P(S+64 int64) Struct(size: 16)
+P(S+72 int64) Struct(size: 16)
+P(S+80 int64) Struct(size: 16)
 S+88 int32
 =>
-P(rcx int64, ret:rax int64) Compound(size: 16)
+P(rcx int64, ret:rax int64) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_ios.expect
index a9ed4cd..e3119e6 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_ios.expect
@@ -1,13 +1,13 @@
-M(rdi int64, xmm0 double) Compound(size: 16)
-M(rsi int64, xmm1 double) Compound(size: 16)
-M(rdx int64, xmm2 double) Compound(size: 16)
-M(rcx int64, xmm3 double) Compound(size: 16)
-M(r8 int64, xmm4 double) Compound(size: 16)
-M(r9 int64, xmm5 double) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
+M(rdi int64, xmm0 double) Struct(size: 16)
+M(rsi int64, xmm1 double) Struct(size: 16)
+M(rdx int64, xmm2 double) Struct(size: 16)
+M(rcx int64, xmm3 double) Struct(size: 16)
+M(r8 int64, xmm4 double) Struct(size: 16)
+M(r9 int64, xmm5 double) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
 xmm6 float
 =>
-M(rax int64, xmm0 double) Compound(size: 16)
+M(rax int64, xmm0 double) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_linux.expect
index a9ed4cd..e3119e6 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_linux.expect
@@ -1,13 +1,13 @@
-M(rdi int64, xmm0 double) Compound(size: 16)
-M(rsi int64, xmm1 double) Compound(size: 16)
-M(rdx int64, xmm2 double) Compound(size: 16)
-M(rcx int64, xmm3 double) Compound(size: 16)
-M(r8 int64, xmm4 double) Compound(size: 16)
-M(r9 int64, xmm5 double) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
+M(rdi int64, xmm0 double) Struct(size: 16)
+M(rsi int64, xmm1 double) Struct(size: 16)
+M(rdx int64, xmm2 double) Struct(size: 16)
+M(rcx int64, xmm3 double) Struct(size: 16)
+M(r8 int64, xmm4 double) Struct(size: 16)
+M(r9 int64, xmm5 double) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
 xmm6 float
 =>
-M(rax int64, xmm0 double) Compound(size: 16)
+M(rax int64, xmm0 double) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_macos.expect
index a9ed4cd..e3119e6 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_macos.expect
@@ -1,13 +1,13 @@
-M(rdi int64, xmm0 double) Compound(size: 16)
-M(rsi int64, xmm1 double) Compound(size: 16)
-M(rdx int64, xmm2 double) Compound(size: 16)
-M(rcx int64, xmm3 double) Compound(size: 16)
-M(r8 int64, xmm4 double) Compound(size: 16)
-M(r9 int64, xmm5 double) Compound(size: 16)
-S+0 Compound(size: 16)
-S+16 Compound(size: 16)
-S+32 Compound(size: 16)
-S+48 Compound(size: 16)
+M(rdi int64, xmm0 double) Struct(size: 16)
+M(rsi int64, xmm1 double) Struct(size: 16)
+M(rdx int64, xmm2 double) Struct(size: 16)
+M(rcx int64, xmm3 double) Struct(size: 16)
+M(r8 int64, xmm4 double) Struct(size: 16)
+M(r9 int64, xmm5 double) Struct(size: 16)
+S+0 Struct(size: 16)
+S+16 Struct(size: 16)
+S+32 Struct(size: 16)
+S+48 Struct(size: 16)
 xmm6 float
 =>
-M(rax int64, xmm0 double) Compound(size: 16)
+M(rax int64, xmm0 double) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_win.expect
index d21ee2b..d237e6e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_win.expect
@@ -1,13 +1,13 @@
-P(rdx int64) Compound(size: 16)
-P(r8 int64) Compound(size: 16)
-P(r9 int64) Compound(size: 16)
-P(S+0 int64) Compound(size: 16)
-P(S+8 int64) Compound(size: 16)
-P(S+16 int64) Compound(size: 16)
-P(S+24 int64) Compound(size: 16)
-P(S+32 int64) Compound(size: 16)
-P(S+40 int64) Compound(size: 16)
-P(S+48 int64) Compound(size: 16)
+P(rdx int64) Struct(size: 16)
+P(r8 int64) Struct(size: 16)
+P(r9 int64) Struct(size: 16)
+P(S+0 int64) Struct(size: 16)
+P(S+8 int64) Struct(size: 16)
+P(S+16 int64) Struct(size: 16)
+P(S+24 int64) Struct(size: 16)
+P(S+32 int64) Struct(size: 16)
+P(S+40 int64) Struct(size: 16)
+P(S+48 int64) Struct(size: 16)
 S+56 float
 =>
-P(rcx int64, ret:rax int64) Compound(size: 16)
+P(rcx int64, ret:rax int64) Struct(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_android.expect
index 121dccb..0eb0d54 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_android.expect
@@ -1,12 +1,12 @@
-M(r0 int64) Compound(size: 3)
-M(r1 int64) Compound(size: 3)
-M(r2 int64) Compound(size: 3)
-M(r3 int64) Compound(size: 3)
-M(r4 int64) Compound(size: 3)
-M(r5 int64) Compound(size: 3)
-M(r6 int64) Compound(size: 3)
-M(r7 int64) Compound(size: 3)
-M(S+0 int64) Compound(size: 3)
-M(S+8 int64) Compound(size: 3)
+M(r0 int64) Struct(size: 3)
+M(r1 int64) Struct(size: 3)
+M(r2 int64) Struct(size: 3)
+M(r3 int64) Struct(size: 3)
+M(r4 int64) Struct(size: 3)
+M(r5 int64) Struct(size: 3)
+M(r6 int64) Struct(size: 3)
+M(r7 int64) Struct(size: 3)
+M(S+0 int64) Struct(size: 3)
+M(S+8 int64) Struct(size: 3)
 =>
-M(r0 int64) Compound(size: 3)
+M(r0 int64) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_ios.expect
index 121dccb..0eb0d54 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_ios.expect
@@ -1,12 +1,12 @@
-M(r0 int64) Compound(size: 3)
-M(r1 int64) Compound(size: 3)
-M(r2 int64) Compound(size: 3)
-M(r3 int64) Compound(size: 3)
-M(r4 int64) Compound(size: 3)
-M(r5 int64) Compound(size: 3)
-M(r6 int64) Compound(size: 3)
-M(r7 int64) Compound(size: 3)
-M(S+0 int64) Compound(size: 3)
-M(S+8 int64) Compound(size: 3)
+M(r0 int64) Struct(size: 3)
+M(r1 int64) Struct(size: 3)
+M(r2 int64) Struct(size: 3)
+M(r3 int64) Struct(size: 3)
+M(r4 int64) Struct(size: 3)
+M(r5 int64) Struct(size: 3)
+M(r6 int64) Struct(size: 3)
+M(r7 int64) Struct(size: 3)
+M(S+0 int64) Struct(size: 3)
+M(S+8 int64) Struct(size: 3)
 =>
-M(r0 int64) Compound(size: 3)
+M(r0 int64) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_linux.expect
index 121dccb..0eb0d54 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_linux.expect
@@ -1,12 +1,12 @@
-M(r0 int64) Compound(size: 3)
-M(r1 int64) Compound(size: 3)
-M(r2 int64) Compound(size: 3)
-M(r3 int64) Compound(size: 3)
-M(r4 int64) Compound(size: 3)
-M(r5 int64) Compound(size: 3)
-M(r6 int64) Compound(size: 3)
-M(r7 int64) Compound(size: 3)
-M(S+0 int64) Compound(size: 3)
-M(S+8 int64) Compound(size: 3)
+M(r0 int64) Struct(size: 3)
+M(r1 int64) Struct(size: 3)
+M(r2 int64) Struct(size: 3)
+M(r3 int64) Struct(size: 3)
+M(r4 int64) Struct(size: 3)
+M(r5 int64) Struct(size: 3)
+M(r6 int64) Struct(size: 3)
+M(r7 int64) Struct(size: 3)
+M(S+0 int64) Struct(size: 3)
+M(S+8 int64) Struct(size: 3)
 =>
-M(r0 int64) Compound(size: 3)
+M(r0 int64) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_macos.expect
index 121dccb..0eb0d54 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_macos.expect
@@ -1,12 +1,12 @@
-M(r0 int64) Compound(size: 3)
-M(r1 int64) Compound(size: 3)
-M(r2 int64) Compound(size: 3)
-M(r3 int64) Compound(size: 3)
-M(r4 int64) Compound(size: 3)
-M(r5 int64) Compound(size: 3)
-M(r6 int64) Compound(size: 3)
-M(r7 int64) Compound(size: 3)
-M(S+0 int64) Compound(size: 3)
-M(S+8 int64) Compound(size: 3)
+M(r0 int64) Struct(size: 3)
+M(r1 int64) Struct(size: 3)
+M(r2 int64) Struct(size: 3)
+M(r3 int64) Struct(size: 3)
+M(r4 int64) Struct(size: 3)
+M(r5 int64) Struct(size: 3)
+M(r6 int64) Struct(size: 3)
+M(r7 int64) Struct(size: 3)
+M(S+0 int64) Struct(size: 3)
+M(S+8 int64) Struct(size: 3)
 =>
-M(r0 int64) Compound(size: 3)
+M(r0 int64) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_android.expect
index 572a779..d976ee3 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_android.expect
@@ -1,12 +1,12 @@
-M(r0 int32) Compound(size: 3)
-M(r1 int32) Compound(size: 3)
-M(r2 int32) Compound(size: 3)
-M(r3 int32) Compound(size: 3)
-M(S+0 int32) Compound(size: 3)
-M(S+4 int32) Compound(size: 3)
-M(S+8 int32) Compound(size: 3)
-M(S+12 int32) Compound(size: 3)
-M(S+16 int32) Compound(size: 3)
-M(S+20 int32) Compound(size: 3)
+M(r0 int32) Struct(size: 3)
+M(r1 int32) Struct(size: 3)
+M(r2 int32) Struct(size: 3)
+M(r3 int32) Struct(size: 3)
+M(S+0 int32) Struct(size: 3)
+M(S+4 int32) Struct(size: 3)
+M(S+8 int32) Struct(size: 3)
+M(S+12 int32) Struct(size: 3)
+M(S+16 int32) Struct(size: 3)
+M(S+20 int32) Struct(size: 3)
 =>
-M(r0 uint32) Compound(size: 3)
+M(r0 uint32) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_ios.expect
index 572a779..d976ee3 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_ios.expect
@@ -1,12 +1,12 @@
-M(r0 int32) Compound(size: 3)
-M(r1 int32) Compound(size: 3)
-M(r2 int32) Compound(size: 3)
-M(r3 int32) Compound(size: 3)
-M(S+0 int32) Compound(size: 3)
-M(S+4 int32) Compound(size: 3)
-M(S+8 int32) Compound(size: 3)
-M(S+12 int32) Compound(size: 3)
-M(S+16 int32) Compound(size: 3)
-M(S+20 int32) Compound(size: 3)
+M(r0 int32) Struct(size: 3)
+M(r1 int32) Struct(size: 3)
+M(r2 int32) Struct(size: 3)
+M(r3 int32) Struct(size: 3)
+M(S+0 int32) Struct(size: 3)
+M(S+4 int32) Struct(size: 3)
+M(S+8 int32) Struct(size: 3)
+M(S+12 int32) Struct(size: 3)
+M(S+16 int32) Struct(size: 3)
+M(S+20 int32) Struct(size: 3)
 =>
-M(r0 uint32) Compound(size: 3)
+M(r0 uint32) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_linux.expect
index 572a779..d976ee3 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm_linux.expect
@@ -1,12 +1,12 @@
-M(r0 int32) Compound(size: 3)
-M(r1 int32) Compound(size: 3)
-M(r2 int32) Compound(size: 3)
-M(r3 int32) Compound(size: 3)
-M(S+0 int32) Compound(size: 3)
-M(S+4 int32) Compound(size: 3)
-M(S+8 int32) Compound(size: 3)
-M(S+12 int32) Compound(size: 3)
-M(S+16 int32) Compound(size: 3)
-M(S+20 int32) Compound(size: 3)
+M(r0 int32) Struct(size: 3)
+M(r1 int32) Struct(size: 3)
+M(r2 int32) Struct(size: 3)
+M(r3 int32) Struct(size: 3)
+M(S+0 int32) Struct(size: 3)
+M(S+4 int32) Struct(size: 3)
+M(S+8 int32) Struct(size: 3)
+M(S+12 int32) Struct(size: 3)
+M(S+16 int32) Struct(size: 3)
+M(S+20 int32) Struct(size: 3)
 =>
-M(r0 uint32) Compound(size: 3)
+M(r0 uint32) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_android.expect
index 91c0595..e42b5c2 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_android.expect
@@ -1,12 +1,12 @@
-S+4 Compound(size: 3)
-S+8 Compound(size: 3)
-S+12 Compound(size: 3)
-S+16 Compound(size: 3)
-S+20 Compound(size: 3)
-S+24 Compound(size: 3)
-S+28 Compound(size: 3)
-S+32 Compound(size: 3)
-S+36 Compound(size: 3)
-S+40 Compound(size: 3)
+S+4 Struct(size: 3)
+S+8 Struct(size: 3)
+S+12 Struct(size: 3)
+S+16 Struct(size: 3)
+S+20 Struct(size: 3)
+S+24 Struct(size: 3)
+S+28 Struct(size: 3)
+S+32 Struct(size: 3)
+S+36 Struct(size: 3)
+S+40 Struct(size: 3)
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 3)
+P(S+0 uint32, ret:eax uint32) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_linux.expect
index 91c0595..e42b5c2 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_linux.expect
@@ -1,12 +1,12 @@
-S+4 Compound(size: 3)
-S+8 Compound(size: 3)
-S+12 Compound(size: 3)
-S+16 Compound(size: 3)
-S+20 Compound(size: 3)
-S+24 Compound(size: 3)
-S+28 Compound(size: 3)
-S+32 Compound(size: 3)
-S+36 Compound(size: 3)
-S+40 Compound(size: 3)
+S+4 Struct(size: 3)
+S+8 Struct(size: 3)
+S+12 Struct(size: 3)
+S+16 Struct(size: 3)
+S+20 Struct(size: 3)
+S+24 Struct(size: 3)
+S+28 Struct(size: 3)
+S+32 Struct(size: 3)
+S+36 Struct(size: 3)
+S+40 Struct(size: 3)
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 3)
+P(S+0 uint32, ret:eax uint32) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_win.expect
index 91c0595..e42b5c2 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_win.expect
@@ -1,12 +1,12 @@
-S+4 Compound(size: 3)
-S+8 Compound(size: 3)
-S+12 Compound(size: 3)
-S+16 Compound(size: 3)
-S+20 Compound(size: 3)
-S+24 Compound(size: 3)
-S+28 Compound(size: 3)
-S+32 Compound(size: 3)
-S+36 Compound(size: 3)
-S+40 Compound(size: 3)
+S+4 Struct(size: 3)
+S+8 Struct(size: 3)
+S+12 Struct(size: 3)
+S+16 Struct(size: 3)
+S+20 Struct(size: 3)
+S+24 Struct(size: 3)
+S+28 Struct(size: 3)
+S+32 Struct(size: 3)
+S+36 Struct(size: 3)
+S+40 Struct(size: 3)
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 3)
+P(S+0 uint32, ret:eax uint32) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_ios.expect
index 7f90b7a..cbc1757 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_ios.expect
@@ -1,12 +1,12 @@
-M(rdi int64) Compound(size: 3)
-M(rsi int64) Compound(size: 3)
-M(rdx int64) Compound(size: 3)
-M(rcx int64) Compound(size: 3)
-M(r8 int64) Compound(size: 3)
-M(r9 int64) Compound(size: 3)
-S+0 Compound(size: 3)
-S+8 Compound(size: 3)
-S+16 Compound(size: 3)
-S+24 Compound(size: 3)
+M(rdi int64) Struct(size: 3)
+M(rsi int64) Struct(size: 3)
+M(rdx int64) Struct(size: 3)
+M(rcx int64) Struct(size: 3)
+M(r8 int64) Struct(size: 3)
+M(r9 int64) Struct(size: 3)
+S+0 Struct(size: 3)
+S+8 Struct(size: 3)
+S+16 Struct(size: 3)
+S+24 Struct(size: 3)
 =>
-M(rax int64) Compound(size: 3)
+M(rax int64) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_linux.expect
index 7f90b7a..cbc1757 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_linux.expect
@@ -1,12 +1,12 @@
-M(rdi int64) Compound(size: 3)
-M(rsi int64) Compound(size: 3)
-M(rdx int64) Compound(size: 3)
-M(rcx int64) Compound(size: 3)
-M(r8 int64) Compound(size: 3)
-M(r9 int64) Compound(size: 3)
-S+0 Compound(size: 3)
-S+8 Compound(size: 3)
-S+16 Compound(size: 3)
-S+24 Compound(size: 3)
+M(rdi int64) Struct(size: 3)
+M(rsi int64) Struct(size: 3)
+M(rdx int64) Struct(size: 3)
+M(rcx int64) Struct(size: 3)
+M(r8 int64) Struct(size: 3)
+M(r9 int64) Struct(size: 3)
+S+0 Struct(size: 3)
+S+8 Struct(size: 3)
+S+16 Struct(size: 3)
+S+24 Struct(size: 3)
 =>
-M(rax int64) Compound(size: 3)
+M(rax int64) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_macos.expect
index 7f90b7a..cbc1757 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_macos.expect
@@ -1,12 +1,12 @@
-M(rdi int64) Compound(size: 3)
-M(rsi int64) Compound(size: 3)
-M(rdx int64) Compound(size: 3)
-M(rcx int64) Compound(size: 3)
-M(r8 int64) Compound(size: 3)
-M(r9 int64) Compound(size: 3)
-S+0 Compound(size: 3)
-S+8 Compound(size: 3)
-S+16 Compound(size: 3)
-S+24 Compound(size: 3)
+M(rdi int64) Struct(size: 3)
+M(rsi int64) Struct(size: 3)
+M(rdx int64) Struct(size: 3)
+M(rcx int64) Struct(size: 3)
+M(r8 int64) Struct(size: 3)
+M(r9 int64) Struct(size: 3)
+S+0 Struct(size: 3)
+S+8 Struct(size: 3)
+S+16 Struct(size: 3)
+S+24 Struct(size: 3)
 =>
-M(rax int64) Compound(size: 3)
+M(rax int64) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_win.expect
index 4b80330..59e786e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_win.expect
@@ -1,12 +1,12 @@
-P(rdx int64) Compound(size: 3)
-P(r8 int64) Compound(size: 3)
-P(r9 int64) Compound(size: 3)
-P(S+0 int64) Compound(size: 3)
-P(S+8 int64) Compound(size: 3)
-P(S+16 int64) Compound(size: 3)
-P(S+24 int64) Compound(size: 3)
-P(S+32 int64) Compound(size: 3)
-P(S+40 int64) Compound(size: 3)
-P(S+48 int64) Compound(size: 3)
+P(rdx int64) Struct(size: 3)
+P(r8 int64) Struct(size: 3)
+P(r9 int64) Struct(size: 3)
+P(S+0 int64) Struct(size: 3)
+P(S+8 int64) Struct(size: 3)
+P(S+16 int64) Struct(size: 3)
+P(S+24 int64) Struct(size: 3)
+P(S+32 int64) Struct(size: 3)
+P(S+40 int64) Struct(size: 3)
+P(S+48 int64) Struct(size: 3)
 =>
-P(rcx int64, ret:rax int64) Compound(size: 3)
+P(rcx int64, ret:rax int64) Struct(size: 3)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_android.expect
index e7b7d6e..0857db5 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_android.expect
@@ -1,12 +1,12 @@
-M(r0 int64) Compound(size: 8)
-M(r1 int64) Compound(size: 8)
-M(r2 int64) Compound(size: 8)
-M(r3 int64) Compound(size: 8)
-M(r4 int64) Compound(size: 8)
-M(r5 int64) Compound(size: 8)
-M(r6 int64) Compound(size: 8)
-M(r7 int64) Compound(size: 8)
-S+0 Compound(size: 8)
-S+8 Compound(size: 8)
+M(r0 int64) Struct(size: 8)
+M(r1 int64) Struct(size: 8)
+M(r2 int64) Struct(size: 8)
+M(r3 int64) Struct(size: 8)
+M(r4 int64) Struct(size: 8)
+M(r5 int64) Struct(size: 8)
+M(r6 int64) Struct(size: 8)
+M(r7 int64) Struct(size: 8)
+S+0 Struct(size: 8)
+S+8 Struct(size: 8)
 =>
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_ios.expect
index e7b7d6e..0857db5 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_ios.expect
@@ -1,12 +1,12 @@
-M(r0 int64) Compound(size: 8)
-M(r1 int64) Compound(size: 8)
-M(r2 int64) Compound(size: 8)
-M(r3 int64) Compound(size: 8)
-M(r4 int64) Compound(size: 8)
-M(r5 int64) Compound(size: 8)
-M(r6 int64) Compound(size: 8)
-M(r7 int64) Compound(size: 8)
-S+0 Compound(size: 8)
-S+8 Compound(size: 8)
+M(r0 int64) Struct(size: 8)
+M(r1 int64) Struct(size: 8)
+M(r2 int64) Struct(size: 8)
+M(r3 int64) Struct(size: 8)
+M(r4 int64) Struct(size: 8)
+M(r5 int64) Struct(size: 8)
+M(r6 int64) Struct(size: 8)
+M(r7 int64) Struct(size: 8)
+S+0 Struct(size: 8)
+S+8 Struct(size: 8)
 =>
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_linux.expect
index e7b7d6e..0857db5 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_linux.expect
@@ -1,12 +1,12 @@
-M(r0 int64) Compound(size: 8)
-M(r1 int64) Compound(size: 8)
-M(r2 int64) Compound(size: 8)
-M(r3 int64) Compound(size: 8)
-M(r4 int64) Compound(size: 8)
-M(r5 int64) Compound(size: 8)
-M(r6 int64) Compound(size: 8)
-M(r7 int64) Compound(size: 8)
-S+0 Compound(size: 8)
-S+8 Compound(size: 8)
+M(r0 int64) Struct(size: 8)
+M(r1 int64) Struct(size: 8)
+M(r2 int64) Struct(size: 8)
+M(r3 int64) Struct(size: 8)
+M(r4 int64) Struct(size: 8)
+M(r5 int64) Struct(size: 8)
+M(r6 int64) Struct(size: 8)
+M(r7 int64) Struct(size: 8)
+S+0 Struct(size: 8)
+S+8 Struct(size: 8)
 =>
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_macos.expect
index e7b7d6e..0857db5 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_macos.expect
@@ -1,12 +1,12 @@
-M(r0 int64) Compound(size: 8)
-M(r1 int64) Compound(size: 8)
-M(r2 int64) Compound(size: 8)
-M(r3 int64) Compound(size: 8)
-M(r4 int64) Compound(size: 8)
-M(r5 int64) Compound(size: 8)
-M(r6 int64) Compound(size: 8)
-M(r7 int64) Compound(size: 8)
-S+0 Compound(size: 8)
-S+8 Compound(size: 8)
+M(r0 int64) Struct(size: 8)
+M(r1 int64) Struct(size: 8)
+M(r2 int64) Struct(size: 8)
+M(r3 int64) Struct(size: 8)
+M(r4 int64) Struct(size: 8)
+M(r5 int64) Struct(size: 8)
+M(r6 int64) Struct(size: 8)
+M(r7 int64) Struct(size: 8)
+S+0 Struct(size: 8)
+S+8 Struct(size: 8)
 =>
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_android.expect
index 49e6d40..e6b29f1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_android.expect
@@ -1,12 +1,12 @@
-M(r1 int32, r2 int32) Compound(size: 8)
-M(r3 int32, S+0 int32) Compound(size: 8)
-M(S+4 int32, S+8 int32) Compound(size: 8)
-M(S+12 int32, S+16 int32) Compound(size: 8)
-M(S+20 int32, S+24 int32) Compound(size: 8)
-M(S+28 int32, S+32 int32) Compound(size: 8)
-M(S+36 int32, S+40 int32) Compound(size: 8)
-M(S+44 int32, S+48 int32) Compound(size: 8)
-M(S+52 int32, S+56 int32) Compound(size: 8)
-M(S+60 int32, S+64 int32) Compound(size: 8)
+M(r1 int32, r2 int32) Struct(size: 8)
+M(r3 int32, S+0 int32) Struct(size: 8)
+M(S+4 int32, S+8 int32) Struct(size: 8)
+M(S+12 int32, S+16 int32) Struct(size: 8)
+M(S+20 int32, S+24 int32) Struct(size: 8)
+M(S+28 int32, S+32 int32) Struct(size: 8)
+M(S+36 int32, S+40 int32) Struct(size: 8)
+M(S+44 int32, S+48 int32) Struct(size: 8)
+M(S+52 int32, S+56 int32) Struct(size: 8)
+M(S+60 int32, S+64 int32) Struct(size: 8)
 =>
-P(r0 uint32) Compound(size: 8)
+P(r0 uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_ios.expect
index 49e6d40..e6b29f1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_ios.expect
@@ -1,12 +1,12 @@
-M(r1 int32, r2 int32) Compound(size: 8)
-M(r3 int32, S+0 int32) Compound(size: 8)
-M(S+4 int32, S+8 int32) Compound(size: 8)
-M(S+12 int32, S+16 int32) Compound(size: 8)
-M(S+20 int32, S+24 int32) Compound(size: 8)
-M(S+28 int32, S+32 int32) Compound(size: 8)
-M(S+36 int32, S+40 int32) Compound(size: 8)
-M(S+44 int32, S+48 int32) Compound(size: 8)
-M(S+52 int32, S+56 int32) Compound(size: 8)
-M(S+60 int32, S+64 int32) Compound(size: 8)
+M(r1 int32, r2 int32) Struct(size: 8)
+M(r3 int32, S+0 int32) Struct(size: 8)
+M(S+4 int32, S+8 int32) Struct(size: 8)
+M(S+12 int32, S+16 int32) Struct(size: 8)
+M(S+20 int32, S+24 int32) Struct(size: 8)
+M(S+28 int32, S+32 int32) Struct(size: 8)
+M(S+36 int32, S+40 int32) Struct(size: 8)
+M(S+44 int32, S+48 int32) Struct(size: 8)
+M(S+52 int32, S+56 int32) Struct(size: 8)
+M(S+60 int32, S+64 int32) Struct(size: 8)
 =>
-P(r0 uint32) Compound(size: 8)
+P(r0 uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_linux.expect
index 49e6d40..e6b29f1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm_linux.expect
@@ -1,12 +1,12 @@
-M(r1 int32, r2 int32) Compound(size: 8)
-M(r3 int32, S+0 int32) Compound(size: 8)
-M(S+4 int32, S+8 int32) Compound(size: 8)
-M(S+12 int32, S+16 int32) Compound(size: 8)
-M(S+20 int32, S+24 int32) Compound(size: 8)
-M(S+28 int32, S+32 int32) Compound(size: 8)
-M(S+36 int32, S+40 int32) Compound(size: 8)
-M(S+44 int32, S+48 int32) Compound(size: 8)
-M(S+52 int32, S+56 int32) Compound(size: 8)
-M(S+60 int32, S+64 int32) Compound(size: 8)
+M(r1 int32, r2 int32) Struct(size: 8)
+M(r3 int32, S+0 int32) Struct(size: 8)
+M(S+4 int32, S+8 int32) Struct(size: 8)
+M(S+12 int32, S+16 int32) Struct(size: 8)
+M(S+20 int32, S+24 int32) Struct(size: 8)
+M(S+28 int32, S+32 int32) Struct(size: 8)
+M(S+36 int32, S+40 int32) Struct(size: 8)
+M(S+44 int32, S+48 int32) Struct(size: 8)
+M(S+52 int32, S+56 int32) Struct(size: 8)
+M(S+60 int32, S+64 int32) Struct(size: 8)
 =>
-P(r0 uint32) Compound(size: 8)
+P(r0 uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_android.expect
index 004cbab..252af49 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_android.expect
@@ -1,12 +1,12 @@
-S+4 Compound(size: 8)
-S+12 Compound(size: 8)
-S+20 Compound(size: 8)
-S+28 Compound(size: 8)
-S+36 Compound(size: 8)
-S+44 Compound(size: 8)
-S+52 Compound(size: 8)
-S+60 Compound(size: 8)
-S+68 Compound(size: 8)
-S+76 Compound(size: 8)
+S+4 Struct(size: 8)
+S+12 Struct(size: 8)
+S+20 Struct(size: 8)
+S+28 Struct(size: 8)
+S+36 Struct(size: 8)
+S+44 Struct(size: 8)
+S+52 Struct(size: 8)
+S+60 Struct(size: 8)
+S+68 Struct(size: 8)
+S+76 Struct(size: 8)
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 8)
+P(S+0 uint32, ret:eax uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_linux.expect
index 004cbab..252af49 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_linux.expect
@@ -1,12 +1,12 @@
-S+4 Compound(size: 8)
-S+12 Compound(size: 8)
-S+20 Compound(size: 8)
-S+28 Compound(size: 8)
-S+36 Compound(size: 8)
-S+44 Compound(size: 8)
-S+52 Compound(size: 8)
-S+60 Compound(size: 8)
-S+68 Compound(size: 8)
-S+76 Compound(size: 8)
+S+4 Struct(size: 8)
+S+12 Struct(size: 8)
+S+20 Struct(size: 8)
+S+28 Struct(size: 8)
+S+36 Struct(size: 8)
+S+44 Struct(size: 8)
+S+52 Struct(size: 8)
+S+60 Struct(size: 8)
+S+68 Struct(size: 8)
+S+76 Struct(size: 8)
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 8)
+P(S+0 uint32, ret:eax uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_win.expect
index 632981b..a58c7e6 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_win.expect
@@ -1,12 +1,12 @@
-S+0 Compound(size: 8)
-S+8 Compound(size: 8)
-S+16 Compound(size: 8)
-S+24 Compound(size: 8)
-S+32 Compound(size: 8)
-S+40 Compound(size: 8)
-S+48 Compound(size: 8)
-S+56 Compound(size: 8)
-S+64 Compound(size: 8)
-S+72 Compound(size: 8)
+S+0 Struct(size: 8)
+S+8 Struct(size: 8)
+S+16 Struct(size: 8)
+S+24 Struct(size: 8)
+S+32 Struct(size: 8)
+S+40 Struct(size: 8)
+S+48 Struct(size: 8)
+S+56 Struct(size: 8)
+S+64 Struct(size: 8)
+S+72 Struct(size: 8)
 =>
-M(eax uint32, edx uint32) Compound(size: 8)
+M(eax uint32, edx uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_ios.expect
index b121f02..fab8720 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_ios.expect
@@ -1,12 +1,12 @@
-S+0 Compound(size: 8)
-S+8 Compound(size: 8)
-S+16 Compound(size: 8)
-S+24 Compound(size: 8)
-S+32 Compound(size: 8)
-S+40 Compound(size: 8)
-S+48 Compound(size: 8)
-S+56 Compound(size: 8)
-S+64 Compound(size: 8)
-S+72 Compound(size: 8)
+S+0 Struct(size: 8)
+S+8 Struct(size: 8)
+S+16 Struct(size: 8)
+S+24 Struct(size: 8)
+S+32 Struct(size: 8)
+S+40 Struct(size: 8)
+S+48 Struct(size: 8)
+S+56 Struct(size: 8)
+S+64 Struct(size: 8)
+S+72 Struct(size: 8)
 =>
-P(rdi int64, ret:rax int64) Compound(size: 8)
+P(rdi int64, ret:rax int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_linux.expect
index b121f02..fab8720 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_linux.expect
@@ -1,12 +1,12 @@
-S+0 Compound(size: 8)
-S+8 Compound(size: 8)
-S+16 Compound(size: 8)
-S+24 Compound(size: 8)
-S+32 Compound(size: 8)
-S+40 Compound(size: 8)
-S+48 Compound(size: 8)
-S+56 Compound(size: 8)
-S+64 Compound(size: 8)
-S+72 Compound(size: 8)
+S+0 Struct(size: 8)
+S+8 Struct(size: 8)
+S+16 Struct(size: 8)
+S+24 Struct(size: 8)
+S+32 Struct(size: 8)
+S+40 Struct(size: 8)
+S+48 Struct(size: 8)
+S+56 Struct(size: 8)
+S+64 Struct(size: 8)
+S+72 Struct(size: 8)
 =>
-P(rdi int64, ret:rax int64) Compound(size: 8)
+P(rdi int64, ret:rax int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_macos.expect
index b121f02..fab8720 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_macos.expect
@@ -1,12 +1,12 @@
-S+0 Compound(size: 8)
-S+8 Compound(size: 8)
-S+16 Compound(size: 8)
-S+24 Compound(size: 8)
-S+32 Compound(size: 8)
-S+40 Compound(size: 8)
-S+48 Compound(size: 8)
-S+56 Compound(size: 8)
-S+64 Compound(size: 8)
-S+72 Compound(size: 8)
+S+0 Struct(size: 8)
+S+8 Struct(size: 8)
+S+16 Struct(size: 8)
+S+24 Struct(size: 8)
+S+32 Struct(size: 8)
+S+40 Struct(size: 8)
+S+48 Struct(size: 8)
+S+56 Struct(size: 8)
+S+64 Struct(size: 8)
+S+72 Struct(size: 8)
 =>
-P(rdi int64, ret:rax int64) Compound(size: 8)
+P(rdi int64, ret:rax int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_win.expect
index 3504b4a..0b192e9 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_win.expect
@@ -1,12 +1,12 @@
-M(rcx int64) Compound(size: 8)
-M(rdx int64) Compound(size: 8)
-M(r8 int64) Compound(size: 8)
-M(r9 int64) Compound(size: 8)
-S+0 Compound(size: 8)
-S+8 Compound(size: 8)
-S+16 Compound(size: 8)
-S+24 Compound(size: 8)
-S+32 Compound(size: 8)
-S+40 Compound(size: 8)
+M(rcx int64) Struct(size: 8)
+M(rdx int64) Struct(size: 8)
+M(r8 int64) Struct(size: 8)
+M(r9 int64) Struct(size: 8)
+S+0 Struct(size: 8)
+S+8 Struct(size: 8)
+S+16 Struct(size: 8)
+S+24 Struct(size: 8)
+S+32 Struct(size: 8)
+S+40 Struct(size: 8)
 =>
-M(rax int64) Compound(size: 8)
+M(rax int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_android.expect
index aae2f45..a6404ed 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_android.expect
@@ -1,3 +1,3 @@
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
 =>
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_ios.expect
index aae2f45..a6404ed 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_ios.expect
@@ -1,3 +1,3 @@
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
 =>
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_linux.expect
index aae2f45..a6404ed 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_linux.expect
@@ -1,3 +1,3 @@
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
 =>
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_macos.expect
index aae2f45..a6404ed 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_macos.expect
@@ -1,3 +1,3 @@
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
 =>
-M(r0 int64) Compound(size: 8)
+M(r0 int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_android.expect
index 0dac74d..39b6e97 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_android.expect
@@ -1,3 +1,3 @@
-M(r1 int32, r2 int32) Compound(size: 8)
+M(r1 int32, r2 int32) Struct(size: 8)
 =>
-P(r0 uint32) Compound(size: 8)
+P(r0 uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_ios.expect
index 0dac74d..39b6e97 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_ios.expect
@@ -1,3 +1,3 @@
-M(r1 int32, r2 int32) Compound(size: 8)
+M(r1 int32, r2 int32) Struct(size: 8)
 =>
-P(r0 uint32) Compound(size: 8)
+P(r0 uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_linux.expect
index 0dac74d..39b6e97 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm_linux.expect
@@ -1,3 +1,3 @@
-M(r1 int32, r2 int32) Compound(size: 8)
+M(r1 int32, r2 int32) Struct(size: 8)
 =>
-P(r0 uint32) Compound(size: 8)
+P(r0 uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_android.expect
index b6e748c..9917c5d 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_android.expect
@@ -1,3 +1,3 @@
-S+4 Compound(size: 8)
+S+4 Struct(size: 8)
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 8)
+P(S+0 uint32, ret:eax uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_linux.expect
index b6e748c..9917c5d 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_linux.expect
@@ -1,3 +1,3 @@
-S+4 Compound(size: 8)
+S+4 Struct(size: 8)
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 8)
+P(S+0 uint32, ret:eax uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_win.expect
index 3778ea7..c2beded 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_win.expect
@@ -1,3 +1,3 @@
-S+0 Compound(size: 8)
+S+0 Struct(size: 8)
 =>
-M(eax uint32, edx uint32) Compound(size: 8)
+M(eax uint32, edx uint32) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_ios.expect
index 80d98b3..fa9bb3c 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_ios.expect
@@ -1,3 +1,3 @@
-M(rdi int64) Compound(size: 8)
+M(rdi int64) Struct(size: 8)
 =>
-M(rax int64) Compound(size: 8)
+M(rax int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_linux.expect
index 80d98b3..fa9bb3c 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_linux.expect
@@ -1,3 +1,3 @@
-M(rdi int64) Compound(size: 8)
+M(rdi int64) Struct(size: 8)
 =>
-M(rax int64) Compound(size: 8)
+M(rax int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_macos.expect
index 80d98b3..fa9bb3c 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_macos.expect
@@ -1,3 +1,3 @@
-M(rdi int64) Compound(size: 8)
+M(rdi int64) Struct(size: 8)
 =>
-M(rax int64) Compound(size: 8)
+M(rax int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_win.expect
index 5610272..cf79ebb 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_win.expect
@@ -1,3 +1,3 @@
-M(rcx int64) Compound(size: 8)
+M(rcx int64) Struct(size: 8)
 =>
-M(rax int64) Compound(size: 8)
+M(rax int64) Struct(size: 8)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_android.expect
index 020f65e..0af60bd 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_android.expect
@@ -1,6 +1,6 @@
-M(r0 int64, r1 int64) Compound(size: 9)
-M(r2 int64, r3 int64) Compound(size: 9)
+M(r0 int64, r1 int64) Struct(size: 9)
+M(r2 int64, r3 int64) Struct(size: 9)
 r4 int8
 v0 double
 =>
-M(r0 int64, r1 int64) Compound(size: 9)
+M(r0 int64, r1 int64) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_ios.expect
index 0d23426..975b441 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_ios.expect
@@ -1,6 +1,6 @@
-M(r0 int64, r1 int64) Compound(size: 9)
-M(r2 int64, r3 int64) Compound(size: 9)
+M(r0 int64, r1 int64) Struct(size: 9)
+M(r2 int64, r3 int64) Struct(size: 9)
 r4 int32[int8]
 v0 double
 =>
-M(r0 int64, r1 int64) Compound(size: 9)
+M(r0 int64, r1 int64) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_linux.expect
index 020f65e..0af60bd 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_linux.expect
@@ -1,6 +1,6 @@
-M(r0 int64, r1 int64) Compound(size: 9)
-M(r2 int64, r3 int64) Compound(size: 9)
+M(r0 int64, r1 int64) Struct(size: 9)
+M(r2 int64, r3 int64) Struct(size: 9)
 r4 int8
 v0 double
 =>
-M(r0 int64, r1 int64) Compound(size: 9)
+M(r0 int64, r1 int64) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_macos.expect
index 020f65e..0af60bd 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_macos.expect
@@ -1,6 +1,6 @@
-M(r0 int64, r1 int64) Compound(size: 9)
-M(r2 int64, r3 int64) Compound(size: 9)
+M(r0 int64, r1 int64) Struct(size: 9)
+M(r2 int64, r3 int64) Struct(size: 9)
 r4 int8
 v0 double
 =>
-M(r0 int64, r1 int64) Compound(size: 9)
+M(r0 int64, r1 int64) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_android.expect
index d52d63e..dedbb93 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_android.expect
@@ -1,6 +1,6 @@
-M(r1 int32, r2 int32, r3 int32) Compound(size: 9)
-M(S+0 int32, S+4 int32, S+8 int32) Compound(size: 9)
+M(r1 int32, r2 int32, r3 int32) Struct(size: 9)
+M(S+0 int32, S+4 int32, S+8 int32) Struct(size: 9)
 S+12 int32[int8]
 S+16 double
 =>
-P(r0 uint32) Compound(size: 9)
+P(r0 uint32) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_ios.expect
index 17492a2..f362c98 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_ios.expect
@@ -1,6 +1,6 @@
-M(r1 int32, r2 int32, r3 int32) Compound(size: 9)
-M(S+0 int32, S+4 int32, S+8 int32) Compound(size: 9)
+M(r1 int32, r2 int32, r3 int32) Struct(size: 9)
+M(S+0 int32, S+4 int32, S+8 int32) Struct(size: 9)
 S+12 int32[int8]
 d0 double
 =>
-P(r0 uint32) Compound(size: 9)
+P(r0 uint32) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_linux.expect
index 17492a2..f362c98 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/arm_linux.expect
@@ -1,6 +1,6 @@
-M(r1 int32, r2 int32, r3 int32) Compound(size: 9)
-M(S+0 int32, S+4 int32, S+8 int32) Compound(size: 9)
+M(r1 int32, r2 int32, r3 int32) Struct(size: 9)
+M(S+0 int32, S+4 int32, S+8 int32) Struct(size: 9)
 S+12 int32[int8]
 d0 double
 =>
-P(r0 uint32) Compound(size: 9)
+P(r0 uint32) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_android.expect
index 33bf360..8a22e1d 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_android.expect
@@ -1,6 +1,6 @@
-S+4 Compound(size: 9)
-S+16 Compound(size: 9)
+S+4 Struct(size: 9)
+S+16 Struct(size: 9)
 S+28 int32[int8]
 S+32 double
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 9)
+P(S+0 uint32, ret:eax uint32) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_linux.expect
index 33bf360..8a22e1d 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_linux.expect
@@ -1,6 +1,6 @@
-S+4 Compound(size: 9)
-S+16 Compound(size: 9)
+S+4 Struct(size: 9)
+S+16 Struct(size: 9)
 S+28 int32[int8]
 S+32 double
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 9)
+P(S+0 uint32, ret:eax uint32) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_win.expect
index 33bf360..8a22e1d 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_win.expect
@@ -1,6 +1,6 @@
-S+4 Compound(size: 9)
-S+16 Compound(size: 9)
+S+4 Struct(size: 9)
+S+16 Struct(size: 9)
 S+28 int32[int8]
 S+32 double
 =>
-P(S+0 uint32, ret:eax uint32) Compound(size: 9)
+P(S+0 uint32, ret:eax uint32) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_ios.expect
index c4e54aa..5753935 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_ios.expect
@@ -1,6 +1,6 @@
-S+0 Compound(size: 9)
-S+16 Compound(size: 9)
+S+0 Struct(size: 9)
+S+16 Struct(size: 9)
 rsi int32[int8]
 xmm0 double
 =>
-P(rdi int64, ret:rax int64) Compound(size: 9)
+P(rdi int64, ret:rax int64) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_linux.expect
index c4e54aa..5753935 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_linux.expect
@@ -1,6 +1,6 @@
-S+0 Compound(size: 9)
-S+16 Compound(size: 9)
+S+0 Struct(size: 9)
+S+16 Struct(size: 9)
 rsi int32[int8]
 xmm0 double
 =>
-P(rdi int64, ret:rax int64) Compound(size: 9)
+P(rdi int64, ret:rax int64) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_macos.expect
index c4e54aa..5753935 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_macos.expect
@@ -1,6 +1,6 @@
-S+0 Compound(size: 9)
-S+16 Compound(size: 9)
+S+0 Struct(size: 9)
+S+16 Struct(size: 9)
 rsi int32[int8]
 xmm0 double
 =>
-P(rdi int64, ret:rax int64) Compound(size: 9)
+P(rdi int64, ret:rax int64) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_win.expect
index b4ebbc6..3311a61 100644
--- a/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_win.expect
@@ -1,6 +1,6 @@
-P(rdx int64) Compound(size: 9)
-P(r8 int64) Compound(size: 9)
+P(rdx int64) Struct(size: 9)
+P(r8 int64) Struct(size: 9)
 r9 int8
 S+0 double
 =>
-P(rcx int64, ret:rax int64) Compound(size: 9)
+P(rcx int64, ret:rax int64) Struct(size: 9)
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_android.expect
index ca69b6c..59f05bb1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_android.expect
@@ -1,4 +1,4 @@
-Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+Struct(size: 88, field alignment: 8, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_ios.expect
index ca69b6c..59f05bb1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_ios.expect
@@ -1,4 +1,4 @@
-Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+Struct(size: 88, field alignment: 8, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_linux.expect
index ca69b6c..59f05bb1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+Struct(size: 88, field alignment: 8, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_macos.expect
index ca69b6c..59f05bb1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_macos.expect
@@ -1,4 +1,4 @@
-Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+Struct(size: 88, field alignment: 8, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_android.expect
index 124e769..e8eafe5 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_android.expect
@@ -1,4 +1,4 @@
-Compound(size: 72, field alignment: 8, stack alignment: 8, members: {
+Struct(size: 72, field alignment: 8, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_ios.expect
index 44136f8..848833c 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_ios.expect
@@ -1,4 +1,4 @@
-Compound(size: 64, field alignment: 4, stack alignment: 8, members: {
+Struct(size: 64, field alignment: 4, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_linux.expect
index 124e769..e8eafe5 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 72, field alignment: 8, stack alignment: 8, members: {
+Struct(size: 72, field alignment: 8, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_android.expect
index 24fa174..8c39a9d 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_android.expect
@@ -1,4 +1,4 @@
-Compound(size: 64, field alignment: 4, stack alignment: 4, members: {
+Struct(size: 64, field alignment: 4, stack alignment: 4, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_linux.expect
index 24fa174..8c39a9d 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 64, field alignment: 4, stack alignment: 4, members: {
+Struct(size: 64, field alignment: 4, stack alignment: 4, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_win.expect
index e0bd22c..bcaefe3 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_win.expect
@@ -1,4 +1,4 @@
-Compound(size: 72, field alignment: 8, stack alignment: 4, members: {
+Struct(size: 72, field alignment: 8, stack alignment: 4, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_ios.expect
index ca69b6c..59f05bb1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_ios.expect
@@ -1,4 +1,4 @@
-Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+Struct(size: 88, field alignment: 8, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_linux.expect
index ca69b6c..59f05bb1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+Struct(size: 88, field alignment: 8, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_macos.expect
index ca69b6c..59f05bb1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_macos.expect
@@ -1,4 +1,4 @@
-Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+Struct(size: 88, field alignment: 8, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_win.expect
index ca69b6c..59f05bb1 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_win.expect
@@ -1,4 +1,4 @@
-Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+Struct(size: 88, field alignment: 8, stack alignment: 8, members: {
   0: int8,
   2: int16,
   4: int32,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_android.expect
index 025106d..728e016 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_android.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_ios.expect
index 71313bc..21f9c56 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_ios.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_linux.expect
index 025106d..728e016 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_linux.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_macos.expect
index 025106d..728e016 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_macos.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_android.expect
index 71313bc..21f9c56 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_android.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_ios.expect
index 71313bc..21f9c56 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_ios.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_linux.expect
index 71313bc..21f9c56 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm_linux.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_android.expect
index 71313bc..21f9c56 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_android.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_linux.expect
index 71313bc..21f9c56 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_linux.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_win.expect
index 71313bc..21f9c56 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_win.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 4, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_ios.expect
index 025106d..728e016 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_ios.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_linux.expect
index 025106d..728e016 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_linux.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_macos.expect
index 025106d..728e016 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_macos.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_win.expect
index 025106d..728e016 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_win.expect
@@ -1,3 +1,3 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
-  0: Array(element type: Compound(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
+  0: Array(element type: Struct(size: 8, field alignment: 4, stack alignment: 8, members: {0: Array(element type: float, length: 2)}), length: 2)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_android.expect
index 025609f..c065867 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_android.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_ios.expect
index db47a46..a753409 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_ios.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_linux.expect
index 025609f..c065867 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_macos.expect
index 025609f..c065867 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_macos.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_android.expect
index db47a46..a753409 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_android.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_ios.expect
index db47a46..a753409 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_ios.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_linux.expect
index db47a46..a753409 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_android.expect
index db47a46..a753409 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_android.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_linux.expect
index db47a46..a753409 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_win.expect
index db47a46..a753409 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_win.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 4, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_ios.expect
index 025609f..c065867 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_ios.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_linux.expect
index 025609f..c065867 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_macos.expect
index 025609f..c065867 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_macos.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_win.expect
index 025609f..c065867 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_win.expect
@@ -1,4 +1,4 @@
-Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+Struct(size: 16, field alignment: 4, stack alignment: 8, members: {
   0: float,
   4: float,
   8: float,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_android.expect
index a44e66b..02a0124 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_android.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 8, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_ios.expect
index a44e66b..02a0124 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_ios.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 8, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_linux.expect
index a44e66b..02a0124 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_linux.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 8, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_macos.expect
index a44e66b..02a0124 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_macos.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 8, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_android.expect
index 879e00f..bf40a47 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_android.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 4, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_ios.expect
index 879e00f..bf40a47 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_ios.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 4, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_linux.expect
index 879e00f..bf40a47 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm_linux.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 4, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_android.expect
index 879e00f..bf40a47 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_android.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 4, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_linux.expect
index 879e00f..bf40a47 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_linux.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 4, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_win.expect
index 879e00f..bf40a47 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_win.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 4, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_ios.expect
index a44e66b..02a0124 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_ios.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 8, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_linux.expect
index a44e66b..02a0124 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_linux.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 8, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_macos.expect
index a44e66b..02a0124 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_macos.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 8, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_win.expect
index a44e66b..02a0124 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_win.expect
@@ -1,3 +1,3 @@
-Compound(size: 8, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 8, field alignment: 1, stack alignment: 8, members: {
   0: Array(element type: int8, length: 8)
 })
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_android.expect
index 146893d..e2ae57e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_android.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 8, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_ios.expect
index 146893d..e2ae57e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_ios.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 8, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_linux.expect
index 146893d..e2ae57e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 8, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_macos.expect
index 146893d..e2ae57e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_macos.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 8, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_android.expect
index c7c2467..c11d2ed 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_android.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 4, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_ios.expect
index c7c2467..c11d2ed 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_ios.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 4, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_linux.expect
index c7c2467..c11d2ed 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 4, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_android.expect
index c7c2467..c11d2ed 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_android.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_android.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 4, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_linux.expect
index c7c2467..c11d2ed 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 4, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_win.expect
index c7c2467..c11d2ed 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_win.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 4, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_ios.expect
index 146893d..e2ae57e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_ios.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_ios.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 8, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_linux.expect
index 146893d..e2ae57e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_linux.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_linux.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 8, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_macos.expect
index 146893d..e2ae57e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_macos.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_macos.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 8, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_win.expect
index 146893d..e2ae57e 100644
--- a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_win.expect
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_win.expect
@@ -1,4 +1,4 @@
-Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+Struct(size: 10, field alignment: 1, stack alignment: 8, members: {
   0: int8,
   1: int8,
   2: int8,
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_android.expect
new file mode 100644
index 0000000..c2dcf8c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_android.expect
@@ -0,0 +1,13 @@
+M(v0 float, v1 float, v2 float, v3 float) Union(size: 16)
+M(v4 float, v5 float, v6 float, v7 float) Union(size: 16)
+S+0 Union(size: 16)
+S+16 Union(size: 16)
+S+32 Union(size: 16)
+S+48 Union(size: 16)
+S+64 Union(size: 16)
+S+80 Union(size: 16)
+S+96 Union(size: 16)
+r0 int8
+S+112 Union(size: 16)
+=>
+M(v0 float, v1 float, v2 float, v3 float) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_ios.expect
new file mode 100644
index 0000000..198d331
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_ios.expect
@@ -0,0 +1,13 @@
+M(v0 float, v1 float, v2 float, v3 float) Union(size: 16)
+M(v4 float, v5 float, v6 float, v7 float) Union(size: 16)
+S+0 Union(size: 16)
+S+16 Union(size: 16)
+S+32 Union(size: 16)
+S+48 Union(size: 16)
+S+64 Union(size: 16)
+S+80 Union(size: 16)
+S+96 Union(size: 16)
+r0 int32[int8]
+S+112 Union(size: 16)
+=>
+M(v0 float, v1 float, v2 float, v3 float) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_linux.expect
new file mode 100644
index 0000000..c2dcf8c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_linux.expect
@@ -0,0 +1,13 @@
+M(v0 float, v1 float, v2 float, v3 float) Union(size: 16)
+M(v4 float, v5 float, v6 float, v7 float) Union(size: 16)
+S+0 Union(size: 16)
+S+16 Union(size: 16)
+S+32 Union(size: 16)
+S+48 Union(size: 16)
+S+64 Union(size: 16)
+S+80 Union(size: 16)
+S+96 Union(size: 16)
+r0 int8
+S+112 Union(size: 16)
+=>
+M(v0 float, v1 float, v2 float, v3 float) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_macos.expect
new file mode 100644
index 0000000..c2dcf8c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_macos.expect
@@ -0,0 +1,13 @@
+M(v0 float, v1 float, v2 float, v3 float) Union(size: 16)
+M(v4 float, v5 float, v6 float, v7 float) Union(size: 16)
+S+0 Union(size: 16)
+S+16 Union(size: 16)
+S+32 Union(size: 16)
+S+48 Union(size: 16)
+S+64 Union(size: 16)
+S+80 Union(size: 16)
+S+96 Union(size: 16)
+r0 int8
+S+112 Union(size: 16)
+=>
+M(v0 float, v1 float, v2 float, v3 float) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm_android.expect
new file mode 100644
index 0000000..4b1f92d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm_android.expect
@@ -0,0 +1,13 @@
+M(r1 int32, r2 int32, r3 int32, S+0 int32) Union(size: 16)
+M(S+4 int32, S+8 int32, S+12 int32, S+16 int32) Union(size: 16)
+M(S+20 int32, S+24 int32, S+28 int32, S+32 int32) Union(size: 16)
+M(S+36 int32, S+40 int32, S+44 int32, S+48 int32) Union(size: 16)
+M(S+52 int32, S+56 int32, S+60 int32, S+64 int32) Union(size: 16)
+M(S+68 int32, S+72 int32, S+76 int32, S+80 int32) Union(size: 16)
+M(S+84 int32, S+88 int32, S+92 int32, S+96 int32) Union(size: 16)
+M(S+100 int32, S+104 int32, S+108 int32, S+112 int32) Union(size: 16)
+M(S+116 int32, S+120 int32, S+124 int32, S+128 int32) Union(size: 16)
+S+132 int32[int8]
+M(S+136 int32, S+140 int32, S+144 int32, S+148 int32) Union(size: 16)
+=>
+P(r0 uint32) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm_ios.expect
new file mode 100644
index 0000000..29cf3ce
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm_ios.expect
@@ -0,0 +1,13 @@
+M(s0 float, s1 float, s2 float, s3 float) Union(size: 16)
+M(s4 float, s5 float, s6 float, s7 float) Union(size: 16)
+M(s8 float, s9 float, s10 float, s11 float) Union(size: 16)
+M(s12 float, s13 float, s14 float, s15 float) Union(size: 16)
+S+0 Union(size: 16)
+S+16 Union(size: 16)
+S+32 Union(size: 16)
+S+48 Union(size: 16)
+S+64 Union(size: 16)
+r0 int32[int8]
+S+80 Union(size: 16)
+=>
+M(s0 float, s1 float, s2 float, s3 float) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm_linux.expect
new file mode 100644
index 0000000..29cf3ce
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm_linux.expect
@@ -0,0 +1,13 @@
+M(s0 float, s1 float, s2 float, s3 float) Union(size: 16)
+M(s4 float, s5 float, s6 float, s7 float) Union(size: 16)
+M(s8 float, s9 float, s10 float, s11 float) Union(size: 16)
+M(s12 float, s13 float, s14 float, s15 float) Union(size: 16)
+S+0 Union(size: 16)
+S+16 Union(size: 16)
+S+32 Union(size: 16)
+S+48 Union(size: 16)
+S+64 Union(size: 16)
+r0 int32[int8]
+S+80 Union(size: 16)
+=>
+M(s0 float, s1 float, s2 float, s3 float) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/ia32_android.expect
new file mode 100644
index 0000000..8725ee5
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/ia32_android.expect
@@ -0,0 +1,13 @@
+S+4 Union(size: 16)
+S+20 Union(size: 16)
+S+36 Union(size: 16)
+S+52 Union(size: 16)
+S+68 Union(size: 16)
+S+84 Union(size: 16)
+S+100 Union(size: 16)
+S+116 Union(size: 16)
+S+132 Union(size: 16)
+S+148 int32[int8]
+S+152 Union(size: 16)
+=>
+P(S+0 uint32, ret:eax uint32) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/ia32_linux.expect
new file mode 100644
index 0000000..8725ee5
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/ia32_linux.expect
@@ -0,0 +1,13 @@
+S+4 Union(size: 16)
+S+20 Union(size: 16)
+S+36 Union(size: 16)
+S+52 Union(size: 16)
+S+68 Union(size: 16)
+S+84 Union(size: 16)
+S+100 Union(size: 16)
+S+116 Union(size: 16)
+S+132 Union(size: 16)
+S+148 int32[int8]
+S+152 Union(size: 16)
+=>
+P(S+0 uint32, ret:eax uint32) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/ia32_win.expect
new file mode 100644
index 0000000..8725ee5
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/ia32_win.expect
@@ -0,0 +1,13 @@
+S+4 Union(size: 16)
+S+20 Union(size: 16)
+S+36 Union(size: 16)
+S+52 Union(size: 16)
+S+68 Union(size: 16)
+S+84 Union(size: 16)
+S+100 Union(size: 16)
+S+116 Union(size: 16)
+S+132 Union(size: 16)
+S+148 int32[int8]
+S+152 Union(size: 16)
+=>
+P(S+0 uint32, ret:eax uint32) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_ios.expect
new file mode 100644
index 0000000..1b1354d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_ios.expect
@@ -0,0 +1,13 @@
+M(xmm0 double, xmm1 double) Union(size: 16)
+M(xmm2 double, xmm3 double) Union(size: 16)
+M(xmm4 double, xmm5 double) Union(size: 16)
+M(xmm6 double, xmm7 double) Union(size: 16)
+S+0 Union(size: 16)
+S+16 Union(size: 16)
+S+32 Union(size: 16)
+S+48 Union(size: 16)
+S+64 Union(size: 16)
+rdi int32[int8]
+S+80 Union(size: 16)
+=>
+M(xmm0 double, xmm1 double) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_linux.expect
new file mode 100644
index 0000000..1b1354d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_linux.expect
@@ -0,0 +1,13 @@
+M(xmm0 double, xmm1 double) Union(size: 16)
+M(xmm2 double, xmm3 double) Union(size: 16)
+M(xmm4 double, xmm5 double) Union(size: 16)
+M(xmm6 double, xmm7 double) Union(size: 16)
+S+0 Union(size: 16)
+S+16 Union(size: 16)
+S+32 Union(size: 16)
+S+48 Union(size: 16)
+S+64 Union(size: 16)
+rdi int32[int8]
+S+80 Union(size: 16)
+=>
+M(xmm0 double, xmm1 double) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_macos.expect
new file mode 100644
index 0000000..1b1354d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_macos.expect
@@ -0,0 +1,13 @@
+M(xmm0 double, xmm1 double) Union(size: 16)
+M(xmm2 double, xmm3 double) Union(size: 16)
+M(xmm4 double, xmm5 double) Union(size: 16)
+M(xmm6 double, xmm7 double) Union(size: 16)
+S+0 Union(size: 16)
+S+16 Union(size: 16)
+S+32 Union(size: 16)
+S+48 Union(size: 16)
+S+64 Union(size: 16)
+rdi int32[int8]
+S+80 Union(size: 16)
+=>
+M(xmm0 double, xmm1 double) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_win.expect
new file mode 100644
index 0000000..c8e96a4
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_win.expect
@@ -0,0 +1,13 @@
+P(rdx int64) Union(size: 16)
+P(r8 int64) Union(size: 16)
+P(r9 int64) Union(size: 16)
+P(S+0 int64) Union(size: 16)
+P(S+8 int64) Union(size: 16)
+P(S+16 int64) Union(size: 16)
+P(S+24 int64) Union(size: 16)
+P(S+32 int64) Union(size: 16)
+P(S+40 int64) Union(size: 16)
+S+48 int8
+P(S+56 int64) Union(size: 16)
+=>
+P(rcx int64, ret:rax int64) Union(size: 16)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_android.expect
new file mode 100644
index 0000000..5e76e36
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_android.expect
@@ -0,0 +1,12 @@
+M(r0 int64) Union(size: 5)
+M(r1 int64) Union(size: 5)
+M(r2 int64) Union(size: 5)
+M(r3 int64) Union(size: 5)
+M(r4 int64) Union(size: 5)
+M(r5 int64) Union(size: 5)
+M(r6 int64) Union(size: 5)
+M(r7 int64) Union(size: 5)
+M(S+0 int64) Union(size: 5)
+M(S+8 int64) Union(size: 5)
+=>
+M(r0 int64) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_ios.expect
new file mode 100644
index 0000000..5e76e36
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_ios.expect
@@ -0,0 +1,12 @@
+M(r0 int64) Union(size: 5)
+M(r1 int64) Union(size: 5)
+M(r2 int64) Union(size: 5)
+M(r3 int64) Union(size: 5)
+M(r4 int64) Union(size: 5)
+M(r5 int64) Union(size: 5)
+M(r6 int64) Union(size: 5)
+M(r7 int64) Union(size: 5)
+M(S+0 int64) Union(size: 5)
+M(S+8 int64) Union(size: 5)
+=>
+M(r0 int64) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_linux.expect
new file mode 100644
index 0000000..5e76e36
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_linux.expect
@@ -0,0 +1,12 @@
+M(r0 int64) Union(size: 5)
+M(r1 int64) Union(size: 5)
+M(r2 int64) Union(size: 5)
+M(r3 int64) Union(size: 5)
+M(r4 int64) Union(size: 5)
+M(r5 int64) Union(size: 5)
+M(r6 int64) Union(size: 5)
+M(r7 int64) Union(size: 5)
+M(S+0 int64) Union(size: 5)
+M(S+8 int64) Union(size: 5)
+=>
+M(r0 int64) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_macos.expect
new file mode 100644
index 0000000..5e76e36
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_macos.expect
@@ -0,0 +1,12 @@
+M(r0 int64) Union(size: 5)
+M(r1 int64) Union(size: 5)
+M(r2 int64) Union(size: 5)
+M(r3 int64) Union(size: 5)
+M(r4 int64) Union(size: 5)
+M(r5 int64) Union(size: 5)
+M(r6 int64) Union(size: 5)
+M(r7 int64) Union(size: 5)
+M(S+0 int64) Union(size: 5)
+M(S+8 int64) Union(size: 5)
+=>
+M(r0 int64) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm_android.expect
new file mode 100644
index 0000000..395d3f5
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm_android.expect
@@ -0,0 +1,12 @@
+M(r1 int32, r2 int32) Union(size: 5)
+M(r3 int32, S+0 int32) Union(size: 5)
+M(S+4 int32, S+8 int32) Union(size: 5)
+M(S+12 int32, S+16 int32) Union(size: 5)
+M(S+20 int32, S+24 int32) Union(size: 5)
+M(S+28 int32, S+32 int32) Union(size: 5)
+M(S+36 int32, S+40 int32) Union(size: 5)
+M(S+44 int32, S+48 int32) Union(size: 5)
+M(S+52 int32, S+56 int32) Union(size: 5)
+M(S+60 int32, S+64 int32) Union(size: 5)
+=>
+P(r0 uint32) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm_ios.expect
new file mode 100644
index 0000000..395d3f5
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm_ios.expect
@@ -0,0 +1,12 @@
+M(r1 int32, r2 int32) Union(size: 5)
+M(r3 int32, S+0 int32) Union(size: 5)
+M(S+4 int32, S+8 int32) Union(size: 5)
+M(S+12 int32, S+16 int32) Union(size: 5)
+M(S+20 int32, S+24 int32) Union(size: 5)
+M(S+28 int32, S+32 int32) Union(size: 5)
+M(S+36 int32, S+40 int32) Union(size: 5)
+M(S+44 int32, S+48 int32) Union(size: 5)
+M(S+52 int32, S+56 int32) Union(size: 5)
+M(S+60 int32, S+64 int32) Union(size: 5)
+=>
+P(r0 uint32) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm_linux.expect
new file mode 100644
index 0000000..395d3f5
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm_linux.expect
@@ -0,0 +1,12 @@
+M(r1 int32, r2 int32) Union(size: 5)
+M(r3 int32, S+0 int32) Union(size: 5)
+M(S+4 int32, S+8 int32) Union(size: 5)
+M(S+12 int32, S+16 int32) Union(size: 5)
+M(S+20 int32, S+24 int32) Union(size: 5)
+M(S+28 int32, S+32 int32) Union(size: 5)
+M(S+36 int32, S+40 int32) Union(size: 5)
+M(S+44 int32, S+48 int32) Union(size: 5)
+M(S+52 int32, S+56 int32) Union(size: 5)
+M(S+60 int32, S+64 int32) Union(size: 5)
+=>
+P(r0 uint32) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/ia32_android.expect
new file mode 100644
index 0000000..3aa4075
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/ia32_android.expect
@@ -0,0 +1,12 @@
+S+4 Union(size: 5)
+S+12 Union(size: 5)
+S+20 Union(size: 5)
+S+28 Union(size: 5)
+S+36 Union(size: 5)
+S+44 Union(size: 5)
+S+52 Union(size: 5)
+S+60 Union(size: 5)
+S+68 Union(size: 5)
+S+76 Union(size: 5)
+=>
+P(S+0 uint32, ret:eax uint32) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/ia32_linux.expect
new file mode 100644
index 0000000..3aa4075
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/ia32_linux.expect
@@ -0,0 +1,12 @@
+S+4 Union(size: 5)
+S+12 Union(size: 5)
+S+20 Union(size: 5)
+S+28 Union(size: 5)
+S+36 Union(size: 5)
+S+44 Union(size: 5)
+S+52 Union(size: 5)
+S+60 Union(size: 5)
+S+68 Union(size: 5)
+S+76 Union(size: 5)
+=>
+P(S+0 uint32, ret:eax uint32) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/ia32_win.expect
new file mode 100644
index 0000000..3aa4075
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/ia32_win.expect
@@ -0,0 +1,12 @@
+S+4 Union(size: 5)
+S+12 Union(size: 5)
+S+20 Union(size: 5)
+S+28 Union(size: 5)
+S+36 Union(size: 5)
+S+44 Union(size: 5)
+S+52 Union(size: 5)
+S+60 Union(size: 5)
+S+68 Union(size: 5)
+S+76 Union(size: 5)
+=>
+P(S+0 uint32, ret:eax uint32) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_ios.expect
new file mode 100644
index 0000000..5119d88
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_ios.expect
@@ -0,0 +1,12 @@
+S+0 Union(size: 5)
+S+8 Union(size: 5)
+S+16 Union(size: 5)
+S+24 Union(size: 5)
+S+32 Union(size: 5)
+S+40 Union(size: 5)
+S+48 Union(size: 5)
+S+56 Union(size: 5)
+S+64 Union(size: 5)
+S+72 Union(size: 5)
+=>
+P(rdi int64, ret:rax int64) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_linux.expect
new file mode 100644
index 0000000..5119d88
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_linux.expect
@@ -0,0 +1,12 @@
+S+0 Union(size: 5)
+S+8 Union(size: 5)
+S+16 Union(size: 5)
+S+24 Union(size: 5)
+S+32 Union(size: 5)
+S+40 Union(size: 5)
+S+48 Union(size: 5)
+S+56 Union(size: 5)
+S+64 Union(size: 5)
+S+72 Union(size: 5)
+=>
+P(rdi int64, ret:rax int64) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_macos.expect
new file mode 100644
index 0000000..5119d88
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_macos.expect
@@ -0,0 +1,12 @@
+S+0 Union(size: 5)
+S+8 Union(size: 5)
+S+16 Union(size: 5)
+S+24 Union(size: 5)
+S+32 Union(size: 5)
+S+40 Union(size: 5)
+S+48 Union(size: 5)
+S+56 Union(size: 5)
+S+64 Union(size: 5)
+S+72 Union(size: 5)
+=>
+P(rdi int64, ret:rax int64) Union(size: 5)
diff --git a/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_win.expect
new file mode 100644
index 0000000..b11d58d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_win.expect
@@ -0,0 +1,12 @@
+P(rdx int64) Union(size: 5)
+P(r8 int64) Union(size: 5)
+P(r9 int64) Union(size: 5)
+P(S+0 int64) Union(size: 5)
+P(S+8 int64) Union(size: 5)
+P(S+16 int64) Union(size: 5)
+P(S+24 int64) Union(size: 5)
+P(S+32 int64) Union(size: 5)
+P(S+40 int64) Union(size: 5)
+P(S+48 int64) Union(size: 5)
+=>
+P(rcx int64, ret:rax int64) Union(size: 5)
diff --git a/runtime/vm/compiler/graph_intrinsifier.cc b/runtime/vm/compiler/graph_intrinsifier.cc
index d0ca36b..cfc5023 100644
--- a/runtime/vm/compiler/graph_intrinsifier.cc
+++ b/runtime/vm/compiler/graph_intrinsifier.cc
@@ -201,6 +201,19 @@
   }
 }
 
+static Definition* CreateUnboxedParameterIfNeeded(BlockBuilder* builder,
+                                                  Definition* value,
+                                                  Representation representation,
+                                                  intptr_t arg_index) {
+  const auto& function = builder->function();
+  if (!function.is_unboxed_parameter_at(arg_index)) {
+    return builder->AddUnboxInstr(representation, new Value(value),
+                                  /* is_checked = */ false);
+  } else {
+    return value;
+  }
+}
+
 static Definition* CreateBoxedResultIfNeeded(BlockBuilder* builder,
                                              Definition* value,
                                              Representation representation) {
@@ -920,96 +933,129 @@
   return true;
 }
 
-static bool BuildUnarySmiOp(FlowGraph* flow_graph, Token::Kind op_kind) {
-  ASSERT(!flow_graph->function().has_unboxed_return());
-  ASSERT(!flow_graph->function().is_unboxed_parameter_at(0));
+static bool BuildUnaryIntegerOp(FlowGraph* flow_graph, Token::Kind op_kind) {
   GraphEntryInstr* graph_entry = flow_graph->graph_entry();
   auto normal_entry = graph_entry->normal_entry();
   BlockBuilder builder(flow_graph, normal_entry);
   Definition* left = builder.AddParameter(0, /*with_frame=*/false);
-  builder.AddInstruction(
-      new CheckSmiInstr(new Value(left), DeoptId::kNone, builder.Source()));
-  Definition* result = builder.AddDefinition(
-      new UnarySmiOpInstr(op_kind, new Value(left), DeoptId::kNone));
+  Definition* result;
+  if (flow_graph->function().HasUnboxedParameters() ||
+      flow_graph->function().HasUnboxedReturnValue()) {
+    left = CreateUnboxedParameterIfNeeded(&builder, left, kUnboxedInt64, 0);
+    result = builder.AddDefinition(
+        new UnaryInt64OpInstr(op_kind, new Value(left), DeoptId::kNone));
+    result = CreateBoxedResultIfNeeded(&builder, result, kUnboxedInt64);
+  } else {
+    builder.AddInstruction(
+        new CheckSmiInstr(new Value(left), DeoptId::kNone, builder.Source()));
+    result = builder.AddDefinition(
+        new UnarySmiOpInstr(op_kind, new Value(left), DeoptId::kNone));
+  }
   builder.AddReturn(new Value(result));
   return true;
 }
 
 bool GraphIntrinsifier::Build_Smi_bitNegate(FlowGraph* flow_graph) {
-  return BuildUnarySmiOp(flow_graph, Token::kBIT_NOT);
+  return BuildUnaryIntegerOp(flow_graph, Token::kBIT_NOT);
 }
 
 bool GraphIntrinsifier::Build_Integer_negate(FlowGraph* flow_graph) {
-  return BuildUnarySmiOp(flow_graph, Token::kNEGATE);
+  return BuildUnaryIntegerOp(flow_graph, Token::kNEGATE);
 }
 
-static bool BuildBinarySmiOp(FlowGraph* flow_graph, Token::Kind op_kind) {
-  ASSERT(!flow_graph->function().has_unboxed_return());
-  ASSERT(!flow_graph->function().is_unboxed_parameter_at(0));
-  ASSERT(!flow_graph->function().is_unboxed_parameter_at(1));
+static bool BuildBinaryIntegerOp(FlowGraph* flow_graph,
+                                 Token::Kind op_kind,
+                                 bool force_boxed = false) {
   GraphEntryInstr* graph_entry = flow_graph->graph_entry();
   auto normal_entry = graph_entry->normal_entry();
   BlockBuilder builder(flow_graph, normal_entry);
   Definition* left = builder.AddParameter(0, /*with_frame=*/false);
   Definition* right = builder.AddParameter(1, /*with_frame=*/false);
-  builder.AddInstruction(
-      new CheckSmiInstr(new Value(left), DeoptId::kNone, builder.Source()));
-  builder.AddInstruction(
-      new CheckSmiInstr(new Value(right), DeoptId::kNone, builder.Source()));
-  Definition* result = builder.AddDefinition(new BinarySmiOpInstr(
-      op_kind, new Value(left), new Value(right), DeoptId::kNone));
+  Definition* result;
+  if (!force_boxed && (flow_graph->function().HasUnboxedParameters() ||
+                       flow_graph->function().HasUnboxedReturnValue())) {
+    left = CreateUnboxedParameterIfNeeded(&builder, left, kUnboxedInt64, 0);
+    right = CreateUnboxedParameterIfNeeded(&builder, right, kUnboxedInt64, 1);
+    switch (op_kind) {
+      case Token::kSHL:
+      case Token::kSHR:
+      case Token::kUSHR:
+        result = builder.AddDefinition(new ShiftInt64OpInstr(
+            op_kind, new Value(left), new Value(right), DeoptId::kNone));
+        break;
+      default:
+        result = builder.AddDefinition(new BinaryInt64OpInstr(
+            op_kind, new Value(left), new Value(right), DeoptId::kNone));
+        break;
+    }
+    result = CreateBoxedResultIfNeeded(&builder, result, kUnboxedInt64);
+  } else {
+    left = CreateBoxedParameterIfNeeded(&builder, left, kUnboxedInt64, 0);
+    right = CreateBoxedParameterIfNeeded(&builder, right, kUnboxedInt64, 1);
+    builder.AddInstruction(
+        new CheckSmiInstr(new Value(left), DeoptId::kNone, builder.Source()));
+    builder.AddInstruction(
+        new CheckSmiInstr(new Value(right), DeoptId::kNone, builder.Source()));
+    result = builder.AddDefinition(new BinarySmiOpInstr(
+        op_kind, new Value(left), new Value(right), DeoptId::kNone));
+    result = CreateUnboxedResultIfNeeded(&builder, result);
+  }
   builder.AddReturn(new Value(result));
   return true;
 }
 
 bool GraphIntrinsifier::Build_Integer_add(FlowGraph* flow_graph) {
-  return BuildBinarySmiOp(flow_graph, Token::kADD);
+  return BuildBinaryIntegerOp(flow_graph, Token::kADD);
 }
 
 bool GraphIntrinsifier::Build_Integer_sub(FlowGraph* flow_graph) {
-  return BuildBinarySmiOp(flow_graph, Token::kSUB);
+  return BuildBinaryIntegerOp(flow_graph, Token::kSUB);
 }
 
 bool GraphIntrinsifier::Build_Integer_mul(FlowGraph* flow_graph) {
-  return BuildBinarySmiOp(flow_graph, Token::kMUL);
+  return BuildBinaryIntegerOp(flow_graph, Token::kMUL);
 }
 
 bool GraphIntrinsifier::Build_Integer_mod(FlowGraph* flow_graph) {
+  bool force_boxed = false;
 #if defined(TARGET_ARCH_ARM)
   if (!TargetCPUFeatures::can_divide()) {
     return false;
   }
+  force_boxed = true;  // BinaryInt64Op(kMOD) not implemented
 #endif
-  return BuildBinarySmiOp(flow_graph, Token::kMOD);
+  return BuildBinaryIntegerOp(flow_graph, Token::kMOD, force_boxed);
 }
 
 bool GraphIntrinsifier::Build_Integer_truncDivide(FlowGraph* flow_graph) {
+  bool force_boxed = false;
 #if defined(TARGET_ARCH_ARM)
   if (!TargetCPUFeatures::can_divide()) {
     return false;
   }
+  force_boxed = true;  // BinaryInt64Op(kTRUNCDIV) not implemented
 #endif
-  return BuildBinarySmiOp(flow_graph, Token::kTRUNCDIV);
+  return BuildBinaryIntegerOp(flow_graph, Token::kTRUNCDIV, force_boxed);
 }
 
 bool GraphIntrinsifier::Build_Integer_bitAnd(FlowGraph* flow_graph) {
-  return BuildBinarySmiOp(flow_graph, Token::kBIT_AND);
+  return BuildBinaryIntegerOp(flow_graph, Token::kBIT_AND);
 }
 
 bool GraphIntrinsifier::Build_Integer_bitOr(FlowGraph* flow_graph) {
-  return BuildBinarySmiOp(flow_graph, Token::kBIT_OR);
+  return BuildBinaryIntegerOp(flow_graph, Token::kBIT_OR);
 }
 
 bool GraphIntrinsifier::Build_Integer_bitXor(FlowGraph* flow_graph) {
-  return BuildBinarySmiOp(flow_graph, Token::kBIT_XOR);
+  return BuildBinaryIntegerOp(flow_graph, Token::kBIT_XOR);
 }
 
 bool GraphIntrinsifier::Build_Integer_sar(FlowGraph* flow_graph) {
-  return BuildBinarySmiOp(flow_graph, Token::kSHR);
+  return BuildBinaryIntegerOp(flow_graph, Token::kSHR);
 }
 
 bool GraphIntrinsifier::Build_Integer_shr(FlowGraph* flow_graph) {
-  return BuildBinarySmiOp(flow_graph, Token::kUSHR);
+  return BuildBinaryIntegerOp(flow_graph, Token::kUSHR);
 }
 
 static Definition* ConvertOrUnboxDoubleParameter(BlockBuilder* builder,
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index fa9e3e8..8a2fbbc 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -263,7 +263,7 @@
   V(_IntegerImplementation, <, Integer_lessThan, 0x39643178)                   \
   V(_IntegerImplementation, <=, Integer_lessEqualThan, 0x73d2a9f5)             \
   V(_IntegerImplementation, >=, Integer_greaterEqualThan, 0xbc280c13)          \
-  V(_IntegerImplementation, <<, Integer_shl, 0x766f04a6)                       \
+  V(_IntegerImplementation, <<, Integer_shl, 0x766f00e5)                       \
   V(_Double, toInt, DoubleToInteger, 0x676f1ce8)                               \
 
 #define MATH_LIB_INTRINSIC_LIST(V)                                             \
@@ -351,18 +351,18 @@
     0x17f90910)                                                                \
   V(_ExternalTwoByteString, codeUnitAt, ExternalTwoByteStringCodeUnitAt,       \
     0x17f90910)                                                                \
-  V(_Smi, ~, Smi_bitNegate, 0x8254f8dc)                                        \
-  V(_IntegerImplementation, +, Integer_add, 0xd5610450)                        \
-  V(_IntegerImplementation, -, Integer_sub, 0xc96a1341)                        \
-  V(_IntegerImplementation, *, Integer_mul, 0xacd967de)                        \
-  V(_IntegerImplementation, %, Integer_mod, 0xfcf7cfd4)                        \
-  V(_IntegerImplementation, ~/, Integer_truncDivide, 0xdda4a240)               \
-  V(_IntegerImplementation, unary-, Integer_negate, 0xf7a9aa57)                \
-  V(_IntegerImplementation, &, Integer_bitAnd, 0x8b9d7ff4)                     \
-  V(_IntegerImplementation, |, Integer_bitOr, 0x8f47f9ac)                      \
-  V(_IntegerImplementation, ^, Integer_bitXor, 0xd838c2b3)                     \
-  V(_IntegerImplementation, >>, Integer_sar, 0x931fbf4b)                       \
-  V(_IntegerImplementation, >>>, Integer_shr, 0x7495fbad)                      \
+  V(_Smi, ~, Smi_bitNegate, 0x8254f51b)                                        \
+  V(_IntegerImplementation, +, Integer_add, 0xd561008f)                        \
+  V(_IntegerImplementation, -, Integer_sub, 0xc96a0f80)                        \
+  V(_IntegerImplementation, *, Integer_mul, 0xacd9641d)                        \
+  V(_IntegerImplementation, %, Integer_mod, 0xfcf7cc13)                        \
+  V(_IntegerImplementation, ~/, Integer_truncDivide, 0xdda49e7f)               \
+  V(_IntegerImplementation, unary-, Integer_negate, 0xf7a9a696)                \
+  V(_IntegerImplementation, &, Integer_bitAnd, 0x8b9d7c33)                     \
+  V(_IntegerImplementation, |, Integer_bitOr, 0x8f47f5eb)                      \
+  V(_IntegerImplementation, ^, Integer_bitXor, 0xd838bef2)                     \
+  V(_IntegerImplementation, >>, Integer_sar, 0x931fbb8a)                       \
+  V(_IntegerImplementation, >>>, Integer_shr, 0x7495f7ec)                      \
   V(_Double, unary-, DoubleFlipSignBit, 0x3d39082b)                            \
   V(_Double, truncateToDouble, DoubleTruncate, 0x62d48298)                     \
   V(_Double, roundToDouble, DoubleRound, 0x5649c63f)                           \
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index fa89ba0..dc6d663 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -291,6 +291,7 @@
   V(Uint8ClampedList, "Uint8ClampedList")                                      \
   V(Uint8List, "Uint8List")                                                    \
   V(UnaryMinus, "unary-")                                                      \
+  V(Union, "Union")                                                            \
   V(UnsignedRightShiftOperator, ">>>")                                         \
   V(UnhandledException, "UnhandledException")                                  \
   V(UnlinkedCall, "UnlinkedCall")                                              \
diff --git a/sdk/lib/_internal/vm/lib/date_patch.dart b/sdk/lib/_internal/vm/lib/date_patch.dart
index 3d35087..5485c90 100644
--- a/sdk/lib/_internal/vm/lib/date_patch.dart
+++ b/sdk/lib/_internal/vm/lib/date_patch.dart
@@ -17,6 +17,7 @@
   static int _timeZoneOffsetInSecondsForClampedSeconds(int secondsSinceEpoch)
       native "DateTime_timeZoneOffsetInSeconds";
 
+  // Daylight-savings independent adjustment for the local time zone.
   static int _localTimeZoneAdjustmentInSeconds()
       native "DateTime_localTimeZoneAdjustmentInSeconds";
 
@@ -304,47 +305,19 @@
         millisecond * Duration.microsecondsPerMillisecond +
         microsecond;
 
-    // Since [_timeZoneOffsetInSeconds] will crash if the input is far out of
-    // the valid range we do a preliminary test that weeds out values that can
-    // not become valid even with timezone adjustments.
-    // The timezone adjustment is always less than a day, so adding a security
-    // margin of one day should be enough.
-    if (microsecondsSinceEpoch.abs() >
-        _maxMillisecondsSinceEpoch * 1000 + Duration.microsecondsPerDay) {
-      return null;
-    }
-
     if (!isUtc) {
-      // Note that we can't literally follow the ECMAScript spec (which this
-      // code is based on), because it leads to incorrect computations at
-      // the DST transition points.
-      //
-      // See V8's comment here:
-      // https://github.com/v8/v8/blob/089dd7d2447d6eaf57c8ba6d8f37957f3a269777/src/date.h#L118
+      // Since [_timeZoneOffsetInSeconds] will crash if the input is far out of
+      // the valid range we do a preliminary test that weeds out values that can
+      // not become valid even with timezone adjustments.
+      // The timezone adjustment is always less than a day, so adding a security
+      // margin of one day should be enough.
+      if (microsecondsSinceEpoch.abs() >
+          _maxMillisecondsSinceEpoch * Duration.microsecondsPerMillisecond +
+              Duration.microsecondsPerDay) {
+        return null;
+      }
 
-      // We need to remove the local timezone adjustment before asking for the
-      // correct zone offset.
-      int adjustment =
-          _localTimeZoneAdjustmentInSeconds() * Duration.microsecondsPerSecond;
-      // The adjustment is independent of the actual date and of the daylight
-      // saving time. It is positive east of the Prime Meridian and negative
-      // west of it, e.g. -28800 sec for America/Los_Angeles timezone.
-
-      // We remove one hour to ensure that we have the correct offset at
-      // DST transitioning points. This is a temporary solution and only
-      // correct in timezones that shift for exactly one hour.
-      adjustment += Duration.microsecondsPerHour;
-      int zoneOffset =
-          _timeZoneOffsetInSeconds(microsecondsSinceEpoch - adjustment);
-
-      // The zoneOffset depends on the actual date and reflects any daylight
-      // saving time and/or historical deviation relative to UTC time.
-      // It is positive east of the Prime Meridian and negative west of it,
-      // e.g. -25200 sec for America/Los_Angeles timezone during DST.
-      microsecondsSinceEpoch -= zoneOffset * Duration.microsecondsPerSecond;
-      // The resulting microsecondsSinceEpoch value is therefore the calculated
-      // UTC value decreased by a (positive if east of GMT) timezone adjustment
-      // and decreased by typically one hour if DST is in effect.
+      microsecondsSinceEpoch -= _toLocalTimeOffset(microsecondsSinceEpoch);
     }
     if (microsecondsSinceEpoch.abs() >
         _maxMillisecondsSinceEpoch * Duration.microsecondsPerMillisecond) {
@@ -443,4 +416,108 @@
     int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch);
     return _timeZoneNameForClampedSeconds(equivalentSeconds);
   }
+
+  /// Finds the local time corresponding to a UTC date and time.
+  ///
+  /// The [microsecondsSinceEpoch] represents a particular
+  /// calendar date and clock time in UTC.
+  /// This methods returns a (usually different) point in time
+  /// where the local time had the same calendar date and clock
+  /// time (if such a time exists, otherwise it finds the "best"
+  /// substitute).
+  ///
+  /// A valid result is a point in time `microsecondsSinceEpoch - offset`
+  /// where the local time zone offset is `+offset`.
+  ///
+  /// In some cases there are two valid results, due to a time zone
+  /// change setting the clock back (for example exiting from daylight
+  /// saving time). In that case, we return the *earliest* valid result.
+  ///
+  /// In some cases there are no valid results, due to a time zone
+  /// change setting the clock forward (for example entering daylight
+  /// saving time). In that case, we return the time which would have
+  /// been correct in the earlier time zone (so asking for 2:30 AM
+  /// when clocks move directly from 2:00 to 3:00 will give the
+  /// time that *would have been* 2:30 in the earlier time zone,
+  /// which is now 3:30 in the local time zone).
+  ///
+  /// Returns the point in time as a number of microseconds since epoch.
+  static int _toLocalTimeOffset(int microsecondsSinceEpoch) {
+    // Argument is the UTC time corresponding to the desired
+    // calendar date/wall time.
+    // We now need to find an UTC time where the difference
+    // from `microsecondsSinceEpoch` is the same as the
+    // local time offset at that time. That is, we want to
+    // find `adjustment` in microseconds such that:
+    //
+    //  _timeZoneOffsetInSeconds(microsecondsSinceEpoch - offset)
+    //      * Duration.microsecondsPerSecond == offset
+    //
+    // Such an offset might not exist, if that wall time
+    // is skipped when a time zone change moves the clock forwards.
+    // In that case we pick a time after the switch which would be
+    // correct in the previous time zone.
+    // Also, there might be more than one solution if a time zone
+    // change moves the clock backwards and the same wall clock
+    // time occurs twice in the same day.
+    // In that case we pick the one in the time zone prior to
+    // the switch.
+
+    // Start with the time zone at the current microseconds since
+    // epoch. It's within one day of the real time we're looking for.
+
+    int offset = _timeZoneOffsetInSeconds(microsecondsSinceEpoch) *
+        Duration.microsecondsPerSecond;
+
+    // If offset is 0 (we're right around the UTC+0, and)
+    // we have found one solution.
+    if (offset != 0) {
+      // If not, try to find an actual solution in the time zone
+      // we just discovered.
+      int offset2 = _timeZoneOffsetInSeconds(microsecondsSinceEpoch - offset) *
+          Duration.microsecondsPerSecond;
+      if (offset2 != offset) {
+        // Also not a solution. We have found a second time zone
+        // within the same day. We assume that's all there are.
+        // Try again with the new time zone.
+        int offset3 =
+            _timeZoneOffsetInSeconds(microsecondsSinceEpoch - offset2) *
+                Duration.microsecondsPerSecond;
+        // Either offset3 is a solution (equal to offset2),
+        // or we have found two different time zones and no solution.
+        // In the latter case we choose the lower offset (latter time).
+        return (offset2 <= offset3 ? offset2 : offset3);
+      }
+      // We have found one solution and one time zone.
+      offset = offset2;
+    }
+    // Try to see if there is an earlier time zone which also
+    // has a solution.
+    // Pretends time zone changes are always at most two hours.
+    // (Double daylight saving happened, fx, in part of Canada in 1988).
+    int offset4 = _timeZoneOffsetInSeconds(microsecondsSinceEpoch -
+            offset -
+            2 * Duration.microsecondsPerHour) *
+        Duration.microsecondsPerSecond;
+    if (offset4 > offset) {
+      // The time zone at the earlier time had a greater
+      // offset, so it's possible that the desired wall clock
+      // occurs in that time zone too.
+      if (offset4 == offset + 2 * Duration.microsecondsPerHour) {
+        // A second and earlier solution, so use that.
+        return offset4;
+      }
+      // The time zone differs one hour earlier, but not by one
+      // hour, so check again in that time zone.
+      int offset5 = _timeZoneOffsetInSeconds(microsecondsSinceEpoch - offset4) *
+          Duration.microsecondsPerSecond;
+      if (offset5 == offset4) {
+        // Found a second solution earlier than the first solution, so use that.
+        return offset4;
+      }
+    }
+    // Did not find a solution in the earlier time
+    // zone, so just use the original result.
+    return offset;
+  }
 }
diff --git a/sdk/lib/_internal/vm/lib/integers.dart b/sdk/lib/_internal/vm/lib/integers.dart
index 95e3826..8ca2964 100644
--- a/sdk/lib/_internal/vm/lib/integers.dart
+++ b/sdk/lib/_internal/vm/lib/integers.dart
@@ -8,23 +8,19 @@
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   num operator +(num other) => other._addFromInteger(this);
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   num operator -(num other) => other._subFromInteger(this);
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   num operator *(num other) => other._mulFromInteger(this);
 
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   int operator ~/(num other) {
     if ((other is int) && (other == 0)) {
       throw const IntegerDivisionByZeroException();
@@ -39,7 +35,6 @@
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   num operator %(num other) {
     if ((other is int) && (other == 0)) {
       throw const IntegerDivisionByZeroException();
@@ -50,7 +45,6 @@
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   int operator -() {
     // Issue(https://dartbug.com/39639): The analyzer incorrectly reports the
     // result type as `num`.
@@ -60,17 +54,14 @@
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   int operator &(int other) => other._bitAndFromInteger(this);
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   int operator |(int other) => other._bitOrFromInteger(this);
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   int operator ^(int other) => other._bitXorFromInteger(this);
 
   num remainder(num other) {
@@ -108,17 +99,14 @@
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   int operator >>(int other) => other._shrFromInteger(this);
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   int operator >>>(int other) => other._ushrFromInteger(this);
   @pragma("vm:recognized", "asm-intrinsic")
   @pragma("vm:non-nullable-result-type")
   @pragma("vm:never-inline")
-  @pragma("vm:disable-unboxed-parameters")
   int operator <<(int other) => other._shlFromInteger(this);
 
   @pragma("vm:recognized", "asm-intrinsic")
@@ -556,7 +544,6 @@
   int get _identityHashCode => this;
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:exact-result-type", "dart:core#_Smi")
-  @pragma("vm:disable-unboxed-parameters")
   int operator ~() native "Smi_bitNegate";
   @pragma("vm:recognized", "asm-intrinsic")
   @pragma("vm:exact-result-type", "dart:core#_Smi")
diff --git a/tests/corelib/local_date_time_test.dart b/tests/corelib/local_date_time_test.dart
new file mode 100644
index 0000000..bfa717b
--- /dev/null
+++ b/tests/corelib/local_date_time_test.dart
@@ -0,0 +1,190 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Tests that local DateTime constructor works correctly around
+// time zone changes.
+
+void main() {
+  // Find two points in time with different time zones.
+  // Search linearly back from 2020-01-01 in steps of 60 days.
+  // Stop if reaching 1970-01-01 (epoch) without finding anything.
+  var time = DateTime.utc(2020, 1, 1).millisecondsSinceEpoch;
+  var offset =
+      DateTime.fromMillisecondsSinceEpoch(time).timeZoneOffset.inMilliseconds;
+  var time2 = time;
+  var offset2 = offset;
+  // Whether the first change found moved the clock forward.
+  bool changeForward = false;
+  // 60 days.
+  const delta = 60 * Duration.millisecondsPerDay;
+  while (time2 > 0) {
+    time2 -= delta;
+    offset2 = DateTime.fromMillisecondsSinceEpoch(time2)
+        .timeZoneOffset
+        .inMilliseconds;
+    if (verbose) {
+      print("Search: ${tz(time2, offset2)} - ${tz(time, offset)}");
+    }
+    if (offset2 != offset) {
+      // Two different time zones found. Now find the precise (to the minute)
+      // time where a change happened, and test that.
+      test(findChange(time2, time));
+      // Remeber if the change moved the clock forward or backward.
+      changeForward = offset2 < offset;
+      break;
+    }
+  }
+  time = time2;
+  // Find a change in the other direction.
+  // Keep iterating backwards to find another time zone
+  // where the change was in the other direction.
+  while (time > 0) {
+    time -= delta;
+    offset =
+        DateTime.fromMillisecondsSinceEpoch(time).timeZoneOffset.inMilliseconds;
+    if (verbose) {
+      print("Search: ${tz(time2, offset2)} - ${tz(time, offset)}");
+    }
+    if (offset != offset2) {
+      if ((offset < offset2) != changeForward) {
+        test(findChange(time, time2));
+        break;
+      } else {
+        // Another change in the same direction.
+        // Probably rare, but move use this time
+        // as end-point instead, so the binary search will be shorter.
+        time2 = time;
+        offset2 = offset;
+      }
+    }
+  }
+}
+
+/// Tests that a local time zone change is correctly represented
+/// by local time [DateTime] objects created from date-time values.
+void test(TimeZoneChange change) {
+  if (verbose) print("Test of $change");
+  // Sanity check. The time zones match the [change] one second
+  // before and after the change.
+  var before = DateTime.fromMillisecondsSinceEpoch(
+      change.msSinceEpoch - Duration.millisecondsPerSecond);
+  Expect.equals(change.msOffsetBefore, before.timeZoneOffset.inMilliseconds);
+  var after = DateTime.fromMillisecondsSinceEpoch(
+      change.msSinceEpoch + Duration.millisecondsPerSecond);
+  Expect.equals(change.msOffsetAfter, after.timeZoneOffset.inMilliseconds);
+
+  if (verbose) print("From MS    : ${dtz(before)} --- ${dtz(after)}");
+
+  // Create local DateTime objects for the same YMDHMS as the
+  // values above. See that we pick the correct local time for them.
+
+  // One second before the change, even if clock moves backwards,
+  // we pick a value that is in the earlier time zone.
+  var localBefore = DateTime(before.year, before.month, before.day, before.hour,
+      before.minute, before.second);
+  Expect.equals(before, localBefore);
+
+  // Asking for a calendar date one second after the change.
+  var localAfter = DateTime(after.year, after.month, after.day, after.hour,
+      after.minute, after.second);
+  if (verbose) print("From YMDHMS: ${dtz(localBefore)} --- ${dtz(localAfter)}");
+  if (before.timeZoneOffset < after.timeZoneOffset) {
+    // Clock moved forwards.
+    // We're asking for a clock time which doesn't exist.
+    if (verbose) {
+      print("Forward: ${dtz(after)} vs ${dtz(localAfter)}");
+    }
+    Expect.equals(after, localAfter);
+  } else {
+    // Clock moved backwards.
+    // We're asking for a clock time which exists more than once.
+    // Should be in the former time zone.
+    Expect.equals(before.timeZoneOffset, localAfter.timeZoneOffset);
+  }
+}
+
+/// Finds a time zone change between [before] and [after].
+///
+/// The [before] time must be before [after],
+/// and the local time zone at the two points must be different.
+///
+/// Finds the point in time, with one minute precision,
+/// where the time zone changed, and returns this point,
+/// as well as the time zone offset before and after the change.
+TimeZoneChange findChange(int before, int after) {
+  var min = Duration.millisecondsPerMinute;
+  assert(before % min == 0);
+  assert(after % min == 0);
+  var offsetBefore =
+      DateTime.fromMillisecondsSinceEpoch(before).timeZoneOffset.inMilliseconds;
+  var offsetAfter =
+      DateTime.fromMillisecondsSinceEpoch(after).timeZoneOffset.inMilliseconds;
+  // Binary search for the precise (to 1 minute increments)
+  // time where the change happened.
+  while (after - before > min) {
+    var mid = before + (after - before) ~/ 2;
+    mid -= mid % min;
+    var offsetMid =
+        DateTime.fromMillisecondsSinceEpoch(mid).timeZoneOffset.inMilliseconds;
+    if (verbose) {
+      print(
+          "Bsearch: ${tz(before, offsetBefore)} - ${tz(mid, offsetMid)} - ${tz(after, offsetAfter)}");
+    }
+    if (offsetMid == offsetBefore) {
+      before = mid;
+    } else if (offsetMid == offsetAfter) {
+      after = mid;
+    } else {
+      // Third timezone in the middle. Probably rare.
+      // Use that as either before or after.
+      // Keep the direction of the time zone change.
+      var forwardChange = offsetAfter > offsetBefore;
+      if ((offsetMid > offsetBefore) == forwardChange) {
+        after = mid;
+        offsetAfter = offsetMid;
+      } else {
+        before = mid;
+        offsetBefore = offsetMid;
+      }
+    }
+  }
+  return TimeZoneChange(after, offsetBefore, offsetAfter);
+}
+
+/// A local time zone change.
+class TimeZoneChange {
+  /// The point in time where the clocks were adjusted.
+  final int msSinceEpoch;
+
+  /// The time zone offset before the change.
+  final int msOffsetBefore;
+
+  /// The time zone offset since the change.
+  final int msOffsetAfter;
+  TimeZoneChange(this.msSinceEpoch, this.msOffsetBefore, this.msOffsetAfter);
+  String toString() {
+    var local = DateTime.fromMillisecondsSinceEpoch(msSinceEpoch);
+    var offsetBefore = Duration(milliseconds: msOffsetBefore);
+    var offsetAfter = Duration(milliseconds: msOffsetAfter);
+    return "$local (${ltz(offsetBefore)} -> ${ltz(offsetAfter)})";
+  }
+}
+
+// Helpers when printing timezones.
+
+/// Point in time in ms since epoch, and known offset in ms.
+String tz(int ms, int offset) => "${DateTime.fromMillisecondsSinceEpoch(ms)}"
+    "${ltz(Duration(milliseconds: offset))}";
+
+/// Time plus Zone from DateTime
+String dtz(DateTime dt) => "$dt${dt.isUtc ? "" : ltz(dt.timeZoneOffset)}";
+
+/// Time zone from duration ("+h:ss" format).
+String ltz(Duration d) => "${d.isNegative ? "-" : "+"}${d.inHours}"
+    ":${(d.inMinutes % 60).toString().padLeft(2, "0")}";
+
+/// Set to true if debugging.
+const bool verbose = false;
diff --git a/tests/corelib_2/local_date_time_test.dart b/tests/corelib_2/local_date_time_test.dart
new file mode 100644
index 0000000..bfa717b
--- /dev/null
+++ b/tests/corelib_2/local_date_time_test.dart
@@ -0,0 +1,190 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Tests that local DateTime constructor works correctly around
+// time zone changes.
+
+void main() {
+  // Find two points in time with different time zones.
+  // Search linearly back from 2020-01-01 in steps of 60 days.
+  // Stop if reaching 1970-01-01 (epoch) without finding anything.
+  var time = DateTime.utc(2020, 1, 1).millisecondsSinceEpoch;
+  var offset =
+      DateTime.fromMillisecondsSinceEpoch(time).timeZoneOffset.inMilliseconds;
+  var time2 = time;
+  var offset2 = offset;
+  // Whether the first change found moved the clock forward.
+  bool changeForward = false;
+  // 60 days.
+  const delta = 60 * Duration.millisecondsPerDay;
+  while (time2 > 0) {
+    time2 -= delta;
+    offset2 = DateTime.fromMillisecondsSinceEpoch(time2)
+        .timeZoneOffset
+        .inMilliseconds;
+    if (verbose) {
+      print("Search: ${tz(time2, offset2)} - ${tz(time, offset)}");
+    }
+    if (offset2 != offset) {
+      // Two different time zones found. Now find the precise (to the minute)
+      // time where a change happened, and test that.
+      test(findChange(time2, time));
+      // Remeber if the change moved the clock forward or backward.
+      changeForward = offset2 < offset;
+      break;
+    }
+  }
+  time = time2;
+  // Find a change in the other direction.
+  // Keep iterating backwards to find another time zone
+  // where the change was in the other direction.
+  while (time > 0) {
+    time -= delta;
+    offset =
+        DateTime.fromMillisecondsSinceEpoch(time).timeZoneOffset.inMilliseconds;
+    if (verbose) {
+      print("Search: ${tz(time2, offset2)} - ${tz(time, offset)}");
+    }
+    if (offset != offset2) {
+      if ((offset < offset2) != changeForward) {
+        test(findChange(time, time2));
+        break;
+      } else {
+        // Another change in the same direction.
+        // Probably rare, but move use this time
+        // as end-point instead, so the binary search will be shorter.
+        time2 = time;
+        offset2 = offset;
+      }
+    }
+  }
+}
+
+/// Tests that a local time zone change is correctly represented
+/// by local time [DateTime] objects created from date-time values.
+void test(TimeZoneChange change) {
+  if (verbose) print("Test of $change");
+  // Sanity check. The time zones match the [change] one second
+  // before and after the change.
+  var before = DateTime.fromMillisecondsSinceEpoch(
+      change.msSinceEpoch - Duration.millisecondsPerSecond);
+  Expect.equals(change.msOffsetBefore, before.timeZoneOffset.inMilliseconds);
+  var after = DateTime.fromMillisecondsSinceEpoch(
+      change.msSinceEpoch + Duration.millisecondsPerSecond);
+  Expect.equals(change.msOffsetAfter, after.timeZoneOffset.inMilliseconds);
+
+  if (verbose) print("From MS    : ${dtz(before)} --- ${dtz(after)}");
+
+  // Create local DateTime objects for the same YMDHMS as the
+  // values above. See that we pick the correct local time for them.
+
+  // One second before the change, even if clock moves backwards,
+  // we pick a value that is in the earlier time zone.
+  var localBefore = DateTime(before.year, before.month, before.day, before.hour,
+      before.minute, before.second);
+  Expect.equals(before, localBefore);
+
+  // Asking for a calendar date one second after the change.
+  var localAfter = DateTime(after.year, after.month, after.day, after.hour,
+      after.minute, after.second);
+  if (verbose) print("From YMDHMS: ${dtz(localBefore)} --- ${dtz(localAfter)}");
+  if (before.timeZoneOffset < after.timeZoneOffset) {
+    // Clock moved forwards.
+    // We're asking for a clock time which doesn't exist.
+    if (verbose) {
+      print("Forward: ${dtz(after)} vs ${dtz(localAfter)}");
+    }
+    Expect.equals(after, localAfter);
+  } else {
+    // Clock moved backwards.
+    // We're asking for a clock time which exists more than once.
+    // Should be in the former time zone.
+    Expect.equals(before.timeZoneOffset, localAfter.timeZoneOffset);
+  }
+}
+
+/// Finds a time zone change between [before] and [after].
+///
+/// The [before] time must be before [after],
+/// and the local time zone at the two points must be different.
+///
+/// Finds the point in time, with one minute precision,
+/// where the time zone changed, and returns this point,
+/// as well as the time zone offset before and after the change.
+TimeZoneChange findChange(int before, int after) {
+  var min = Duration.millisecondsPerMinute;
+  assert(before % min == 0);
+  assert(after % min == 0);
+  var offsetBefore =
+      DateTime.fromMillisecondsSinceEpoch(before).timeZoneOffset.inMilliseconds;
+  var offsetAfter =
+      DateTime.fromMillisecondsSinceEpoch(after).timeZoneOffset.inMilliseconds;
+  // Binary search for the precise (to 1 minute increments)
+  // time where the change happened.
+  while (after - before > min) {
+    var mid = before + (after - before) ~/ 2;
+    mid -= mid % min;
+    var offsetMid =
+        DateTime.fromMillisecondsSinceEpoch(mid).timeZoneOffset.inMilliseconds;
+    if (verbose) {
+      print(
+          "Bsearch: ${tz(before, offsetBefore)} - ${tz(mid, offsetMid)} - ${tz(after, offsetAfter)}");
+    }
+    if (offsetMid == offsetBefore) {
+      before = mid;
+    } else if (offsetMid == offsetAfter) {
+      after = mid;
+    } else {
+      // Third timezone in the middle. Probably rare.
+      // Use that as either before or after.
+      // Keep the direction of the time zone change.
+      var forwardChange = offsetAfter > offsetBefore;
+      if ((offsetMid > offsetBefore) == forwardChange) {
+        after = mid;
+        offsetAfter = offsetMid;
+      } else {
+        before = mid;
+        offsetBefore = offsetMid;
+      }
+    }
+  }
+  return TimeZoneChange(after, offsetBefore, offsetAfter);
+}
+
+/// A local time zone change.
+class TimeZoneChange {
+  /// The point in time where the clocks were adjusted.
+  final int msSinceEpoch;
+
+  /// The time zone offset before the change.
+  final int msOffsetBefore;
+
+  /// The time zone offset since the change.
+  final int msOffsetAfter;
+  TimeZoneChange(this.msSinceEpoch, this.msOffsetBefore, this.msOffsetAfter);
+  String toString() {
+    var local = DateTime.fromMillisecondsSinceEpoch(msSinceEpoch);
+    var offsetBefore = Duration(milliseconds: msOffsetBefore);
+    var offsetAfter = Duration(milliseconds: msOffsetAfter);
+    return "$local (${ltz(offsetBefore)} -> ${ltz(offsetAfter)})";
+  }
+}
+
+// Helpers when printing timezones.
+
+/// Point in time in ms since epoch, and known offset in ms.
+String tz(int ms, int offset) => "${DateTime.fromMillisecondsSinceEpoch(ms)}"
+    "${ltz(Duration(milliseconds: offset))}";
+
+/// Time plus Zone from DateTime
+String dtz(DateTime dt) => "$dt${dt.isUtc ? "" : ltz(dt.timeZoneOffset)}";
+
+/// Time zone from duration ("+h:ss" format).
+String ltz(Duration d) => "${d.isNegative ? "-" : "+"}${d.inHours}"
+    ":${(d.inMinutes % 60).toString().padLeft(2, "0")}";
+
+/// Set to true if debugging.
+const bool verbose = false;
diff --git a/tests/web/deferred/deferred_overlapping_test.dart b/tests/web/deferred/deferred_overlapping_test.dart
index f626d58..fc4238f 100644
--- a/tests/web/deferred/deferred_overlapping_test.dart
+++ b/tests/web/deferred/deferred_overlapping_test.dart
@@ -10,9 +10,9 @@
 // will fail because the base class does not exist.
 void main() {
   lib1.loadLibrary().then((_) {
-    var a = new lib1.C1();
+    print(new lib1.C1());
     lib2.loadLibrary().then((_) {
-      var b = new lib2.C2();
+      print(new lib2.C2());
     });
   });
 }
diff --git a/tools/VERSION b/tools/VERSION
index 6a92dc7..9472fdb 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 219
+PRERELEASE 220
 PRERELEASE_PATCH 0
\ No newline at end of file