Version 2.17.0-250.0.dev

Merge commit 'd4f0796619ebf8eaa0e181d5abb214fa000f20ae' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/fuzzy_filter_sort.dart b/pkg/analysis_server/lib/src/services/completion/dart/fuzzy_filter_sort.dart
index 59a5f61..69e49fe 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/fuzzy_filter_sort.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/fuzzy_filter_sort.dart
@@ -6,6 +6,8 @@
 import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
 import 'package:analysis_server/src/services/completion/filtering/fuzzy_matcher.dart';
 
+final _identifierPattern = RegExp(r'([_a-zA-Z][_a-zA-Z0-9]*)');
+
 /// Filters and scores [suggestions] according to how well they match the
 /// [pattern]. Sorts [suggestions] by the score, relevance, and name.
 List<CompletionSuggestionBuilder> fuzzyFilterSort({
@@ -15,16 +17,18 @@
   var matcher = FuzzyMatcher(pattern, matchStyle: MatchStyle.SYMBOL);
 
   double score(CompletionSuggestionBuilder suggestion) {
-    var suggestionTextToMatch = suggestion.completion;
+    var textToMatch = suggestion.completion;
 
-    if (suggestion.kind == CompletionSuggestionKind.NAMED_ARGUMENT) {
-      var index = suggestionTextToMatch.indexOf(':');
-      if (index != -1) {
-        suggestionTextToMatch = suggestionTextToMatch.substring(0, index);
+    if (suggestion.kind == CompletionSuggestionKind.KEYWORD ||
+        suggestion.kind == CompletionSuggestionKind.NAMED_ARGUMENT) {
+      var identifier = _identifierPattern.matchAsPrefix(textToMatch)?.group(1);
+      if (identifier == null) {
+        return -1;
       }
+      textToMatch = identifier;
     }
 
-    return matcher.score(suggestionTextToMatch);
+    return matcher.score(textToMatch);
   }
 
   var scored = suggestions
diff --git a/pkg/analysis_server/test/services/completion/dart/location/compilation_unit_test.dart b/pkg/analysis_server/test/services/completion/dart/location/compilation_unit_test.dart
new file mode 100644
index 0000000..d5130d5
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/location/compilation_unit_test.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2022, 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:analyzer_utilities/check/check.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../../client/completion_driver_test.dart';
+import '../completion_check.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(CompilationUnitTest1);
+    defineReflectiveTests(CompilationUnitTest2);
+  });
+}
+
+@reflectiveTest
+class CompilationUnitTest1 extends AbstractCompletionDriverTest
+    with CompilationUnitTestCases {
+  @override
+  TestingCompletionProtocol get protocol => TestingCompletionProtocol.version1;
+}
+
+@reflectiveTest
+class CompilationUnitTest2 extends AbstractCompletionDriverTest
+    with CompilationUnitTestCases {
+  @override
+  TestingCompletionProtocol get protocol => TestingCompletionProtocol.version2;
+}
+
+mixin CompilationUnitTestCases on AbstractCompletionDriverTest {
+  Future<void> test_definingUnit_export() async {
+    var response = await getTestCodeSuggestions('''
+exp^
+''');
+
+    check(response).suggestions.includesAll([
+      (suggestion) => suggestion
+        ..completion.isEqualTo("export '';")
+        ..kind.isKeyword
+        ..hasSelection(offset: 8),
+    ]);
+
+    if (isProtocolVersion2) {
+      check(response).suggestions.excludesAll([
+        (suggestion) => suggestion.completion.startsWith('import'),
+      ]);
+    }
+  }
+
+  Future<void> test_definingUnit_import() async {
+    var response = await getTestCodeSuggestions('''
+imp^
+''');
+
+    check(response).suggestions.includesAll([
+      (suggestion) => suggestion
+        ..completion.isEqualTo("import '';")
+        ..kind.isKeyword
+        ..hasSelection(offset: 8),
+    ]);
+
+    if (isProtocolVersion2) {
+      check(response).suggestions.excludesAll([
+        (suggestion) => suggestion.completion.startsWith('export'),
+      ]);
+    }
+  }
+
+  Future<void> test_definingUnit_part() async {
+    var response = await getTestCodeSuggestions('''
+par^
+''');
+
+    check(response).suggestions.includesAll([
+      (suggestion) => suggestion
+        ..completion.isEqualTo("part '';")
+        ..kind.isKeyword
+        ..hasSelection(offset: 6),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/location/test_all.dart b/pkg/analysis_server/test/services/completion/dart/location/test_all.dart
index 5fc5401..b0fe488 100644
--- a/pkg/analysis_server/test/services/completion/dart/location/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/dart/location/test_all.dart
@@ -5,6 +5,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'class_body_test.dart' as class_body;
+import 'compilation_unit_test.dart' as compilation_unit;
 import 'enum_constant_test.dart' as enum_constant;
 import 'enum_test.dart' as enum_;
 import 'field_formal_parameter_test.dart' as field_formal_parameter;
@@ -15,6 +16,7 @@
 void main() {
   defineReflectiveSuite(() {
     class_body.main();
+    compilation_unit.main();
     enum_constant.main();
     enum_.main();
     field_formal_parameter.main();
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index da1e123..7c3815a 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -924,9 +924,14 @@
   FunctionType? staticInvokeType;
 
   /// Initialize a newly created binary expression.
-  BinaryExpressionImpl(this._leftOperand, this.operator, this._rightOperand) {
-    _becomeParentOf(_leftOperand);
-    _becomeParentOf(_rightOperand);
+  BinaryExpressionImpl({
+    required ExpressionImpl leftOperand,
+    required this.operator,
+    required ExpressionImpl rightOperand,
+  })  : _leftOperand = leftOperand,
+        _rightOperand = rightOperand {
+    _becomeParentOf(leftOperand);
+    _becomeParentOf(rightOperand);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index b937129..7a31a07 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -93,11 +93,15 @@
           Token awaitKeyword, Expression expression) =>
       AwaitExpressionImpl(awaitKeyword, expression as ExpressionImpl);
 
+  @Deprecated('Use the constructor instead.')
   @override
   BinaryExpressionImpl binaryExpression(
           Expression leftOperand, Token operator, Expression rightOperand) =>
-      BinaryExpressionImpl(leftOperand as ExpressionImpl, operator,
-          rightOperand as ExpressionImpl);
+      BinaryExpressionImpl(
+        leftOperand: leftOperand as ExpressionImpl,
+        operator: operator,
+        rightOperand: rightOperand as ExpressionImpl,
+      );
 
   @override
   BlockImpl block(
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index dd78df6..263dcde 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -1696,10 +1696,10 @@
   @override
   bool visitBinaryExpression(covariant BinaryExpressionImpl node) {
     if (identical(node.leftOperand, _oldNode)) {
-      node.leftOperand = _newNode as Expression;
+      node.leftOperand = _newNode as ExpressionImpl;
       return true;
     } else if (identical(node.rightOperand, _oldNode)) {
-      node.rightOperand = _newNode as Expression;
+      node.rightOperand = _newNode as ExpressionImpl;
       return true;
     }
     return visitNode(node);
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 20996fa..612e610 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -60,23 +60,7 @@
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
-import 'package:analyzer/src/dart/ast/ast.dart'
-    show
-        ArgumentListImpl,
-        ClassDeclarationImpl,
-        CompilationUnitImpl,
-        ConstructorNameImpl,
-        ConstructorSelectorImpl,
-        EnumConstantArgumentsImpl,
-        EnumConstantDeclarationImpl,
-        EnumDeclarationImpl,
-        ExtensionDeclarationImpl,
-        ImportDirectiveImpl,
-        MethodInvocationImpl,
-        MixinDeclarationImpl,
-        SimpleIdentifierImpl,
-        TypeArgumentListImpl,
-        TypeParameterImpl;
+import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/ast_factory.dart';
 import 'package:analyzer/src/fasta/error_converter.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -739,10 +723,16 @@
         identical("?..", operatorToken.stringValue)) {
       doDotExpression(operatorToken);
     } else {
-      var right = pop() as Expression;
-      var left = pop() as Expression;
+      var right = pop() as ExpressionImpl;
+      var left = pop() as ExpressionImpl;
       reportErrorIfSuper(right);
-      push(ast.binaryExpression(left, operatorToken, right));
+      push(
+        BinaryExpressionImpl(
+          leftOperand: left,
+          operator: operatorToken,
+          rightOperand: right,
+        ),
+      );
       if (!enableTripleShift && operatorToken.type == TokenType.GT_GT_GT) {
         var feature = ExperimentalFeatures.triple_shift;
         handleRecoverableError(
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
index 34986e6..1264004 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
@@ -126,11 +126,6 @@
           TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, "await"),
           expression);
 
-  static BinaryExpressionImpl binaryExpression(Expression leftOperand,
-          TokenType operator, Expression rightOperand) =>
-      astFactory.binaryExpression(
-          leftOperand, TokenFactory.tokenFromType(operator), rightOperand);
-
   static BlockImpl block([List<Statement> statements = const []]) =>
       astFactory.block(
           TokenFactory.tokenFromType(TokenType.OPEN_CURLY_BRACKET),
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index df1bb2d..be75c39 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -270,13 +270,13 @@
   }
 
   BinaryExpression _readBinaryExpression() {
-    var leftOperand = readNode() as Expression;
-    var rightOperand = readNode() as Expression;
+    var leftOperand = readNode() as ExpressionImpl;
+    var rightOperand = readNode() as ExpressionImpl;
     var operatorType = UnlinkedTokenType.values[_readByte()];
-    var node = astFactory.binaryExpression(
-      leftOperand,
-      Tokens.fromType(operatorType),
-      rightOperand,
+    var node = BinaryExpressionImpl(
+      leftOperand: leftOperand,
+      operator: Tokens.fromType(operatorType),
+      rightOperand: rightOperand,
     );
     node.staticElement = _reader.readElement() as MethodElement?;
     node.staticInvokeType = _reader.readOptionalFunctionType();
diff --git a/pkg/analyzer/test/dart/ast/ast_test.dart b/pkg/analyzer/test/dart/ast/ast_test.dart
index d010025..a29e78d 100644
--- a/pkg/analyzer/test/dart/ast/ast_test.dart
+++ b/pkg/analyzer/test/dart/ast/ast_test.dart
@@ -5,14 +5,17 @@
 import 'package:analyzer/dart/analysis/utilities.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/ast_factory.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../../generated/parser_test_base.dart' show ParserTestCase;
+import '../../util/feature_sets.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -237,7 +240,7 @@
 }
 
 @reflectiveTest
-class IndexExpressionTest {
+class IndexExpressionTest extends _AstTest {
   void test_inGetterContext_assignment_compound_left() {
     IndexExpression expression = AstTestFactory.indexExpression(
       target: AstTestFactory.identifier3("a"),
@@ -261,14 +264,10 @@
   }
 
   void test_inGetterContext_nonAssignment() {
-    IndexExpression expression = AstTestFactory.indexExpression(
-      target: AstTestFactory.identifier3("a"),
-      index: AstTestFactory.identifier3("b"),
-    );
-    // a[b] + c
-    AstTestFactory.binaryExpression(
-        expression, TokenType.PLUS, AstTestFactory.identifier3("c"));
-    expect(expression.inGetterContext(), isTrue);
+    var node = _parseStringToNode<IndexExpression>(r'''
+var v = ^a[b] + c;
+''');
+    expect(node.inGetterContext(), isTrue);
   }
 
   void test_inSetterContext_assignment_compound_left() {
@@ -316,14 +315,10 @@
   }
 
   void test_inSetterContext_nonAssignment() {
-    IndexExpression expression = AstTestFactory.indexExpression(
-      target: AstTestFactory.identifier3("a"),
-      index: AstTestFactory.identifier3("b"),
-    );
-    AstTestFactory.binaryExpression(
-        expression, TokenType.PLUS, AstTestFactory.identifier3("c"));
-    // a[b] + cc
-    expect(expression.inSetterContext(), isFalse);
+    var node = _parseStringToNode<IndexExpression>(r'''
+var v = ^a[b] + c;
+''');
+    expect(node.inSetterContext(), isFalse);
   }
 
   void test_inSetterContext_postfix_bang() {
@@ -1053,7 +1048,7 @@
 }
 
 @reflectiveTest
-class SimpleIdentifierTest extends ParserTestCase {
+class SimpleIdentifierTest extends _AstTest {
   void test_inGetterContext() {
     for (_WrapperKind wrapper in _WrapperKind.values) {
       for (_AssignmentKind assignment in _AssignmentKind.values) {
@@ -1200,8 +1195,8 @@
 
   SimpleIdentifier _createIdentifier(
       _WrapperKind wrapper, _AssignmentKind assignment) {
-    SimpleIdentifier identifier = AstTestFactory.identifier3("a");
-    Expression expression = identifier;
+    var identifier = AstTestFactory.identifier3("a");
+    ExpressionImpl expression = identifier;
     while (true) {
       if (wrapper == _WrapperKind.PREFIXED_LEFT) {
         expression = AstTestFactory.identifier(
@@ -1221,8 +1216,11 @@
     }
     while (true) {
       if (assignment == _AssignmentKind.BINARY) {
-        AstTestFactory.binaryExpression(
-            expression, TokenType.PLUS, AstTestFactory.identifier3("_"));
+        BinaryExpressionImpl(
+          leftOperand: expression,
+          operator: TokenFactory.tokenFromType(TokenType.PLUS),
+          rightOperand: AstTestFactory.identifier3("_"),
+        );
       } else if (assignment == _AssignmentKind.COMPOUND_LEFT) {
         AstTestFactory.assignmentExpression(
             expression, TokenType.PLUS_EQ, AstTestFactory.identifier3("_"));
@@ -1787,6 +1785,37 @@
   String toString() => name;
 }
 
+class _AstTest {
+  T _parseStringToNode<T extends AstNode>(String codeWithMark) {
+    var offset = codeWithMark.indexOf('^');
+    expect(offset, isNot(equals(-1)), reason: 'missing ^');
+
+    var nextOffset = codeWithMark.indexOf('^', offset + 1);
+    expect(nextOffset, equals(-1), reason: 'too many ^');
+
+    var codeBefore = codeWithMark.substring(0, offset);
+    var codeAfter = codeWithMark.substring(offset + 1);
+    var code = codeBefore + codeAfter;
+
+    var parseResult = parseString(
+      content: code,
+      featureSet: FeatureSets.latestWithExperiments,
+    );
+
+    var node = NodeLocator2(offset).searchWithin(parseResult.unit);
+    if (node == null) {
+      throw StateError('No node at $offset:\n$code');
+    }
+
+    var result = node.thisOrAncestorOfType<T>();
+    if (result == null) {
+      throw StateError('No node of $T at $offset:\n$code');
+    }
+
+    return result;
+  }
+}
+
 class _WrapperKind {
   static const _WrapperKind PREFIXED_LEFT = _WrapperKind('PREFIXED_LEFT', 0);
 
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index bb1b5fb..2aac19c 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -93,20 +93,23 @@
   }
 
   void test_visitBinaryExpression() {
+    var findNode = _parseStringToFindNode(r'''
+var v = a + b;
+''');
     _assertSource(
-        "a + b",
-        AstTestFactory.binaryExpression(AstTestFactory.identifier3("a"),
-            TokenType.PLUS, AstTestFactory.identifier3("b")));
+      'a + b',
+      findNode.binary('a + b'),
+    );
   }
 
   void test_visitBinaryExpression_precedence() {
-    var a = AstTestFactory.identifier3('a');
-    var b = AstTestFactory.identifier3('b');
-    var c = AstTestFactory.identifier3('c');
+    var findNode = _parseStringToFindNode(r'''
+var v = a * (b + c);
+''');
     _assertSource(
-        'a * (b + c)',
-        AstTestFactory.binaryExpression(a, TokenType.STAR,
-            AstTestFactory.binaryExpression(b, TokenType.PLUS, c)));
+      'a * (b + c)',
+      findNode.binary('a *'),
+    );
   }
 
   void test_visitBlock_empty() {
@@ -2787,12 +2790,13 @@
   }
 
   void test_visitPrefixExpression_precedence() {
-    var a = AstTestFactory.identifier3('a');
-    var b = AstTestFactory.identifier3('b');
+    var findNode = _parseStringToFindNode(r'''
+var v = !(a == b);
+''');
     _assertSource(
-        '!(a == b)',
-        AstTestFactory.prefixExpression(TokenType.BANG,
-            AstTestFactory.binaryExpression(a, TokenType.EQ_EQ, b)));
+      '!(a == b)',
+      findNode.prefix('!'),
+    );
   }
 
   void test_visitPropertyAccess() {
diff --git a/pkg/compiler/test/analyses/dart2js_allowed.json b/pkg/compiler/test/analyses/dart2js_allowed.json
index da1fbe1..4d58ce5 100644
--- a/pkg/compiler/test/analyses/dart2js_allowed.json
+++ b/pkg/compiler/test/analyses/dart2js_allowed.json
@@ -114,16 +114,8 @@
     "Dynamic access of 'name'.": 1,
     "Dynamic invocation of '-'.": 1
   },
-  "pkg/js_ast/lib/src/builder.dart": {
-    "Dynamic invocation of 'call'.": 2
-  },
   "pkg/js_ast/lib/src/template.dart": {
-    "Dynamic access of 'keys'.": 1,
-    "Dynamic access of 'length'.": 1,
     "Dynamic invocation of '[]'.": 9,
-    "Dynamic invocation of 'containsKey'.": 2,
-    "Dynamic invocation of 'join'.": 1,
-    "Dynamic invocation of 'toStatement'.": 3,
-    "Dynamic invocation of 'where'.": 1
+    "Dynamic invocation of 'toStatement'.": 1
   }
 }
\ No newline at end of file
diff --git a/pkg/dev_compiler/lib/src/js_ast/characters.dart b/pkg/dev_compiler/lib/src/js_ast/characters.dart
index 1ce0d48..e3382c3 100644
--- a/pkg/dev_compiler/lib/src/js_ast/characters.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/characters.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
-
 const int $EOF = 0;
 const int $STX = 2;
 const int $BS = 8;
diff --git a/pkg/dev_compiler/lib/src/js_ast/nodes.dart b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
index 70ff407..cb6c11d 100644
--- a/pkg/dev_compiler/lib/src/js_ast/nodes.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/nodes.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
-
 // ignore_for_file: always_declare_return_types
 // ignore_for_file: always_require_non_null_named_parameters
 // ignore_for_file: omit_local_variable_types
@@ -90,7 +88,6 @@
   T visitExportDeclaration(ExportDeclaration node);
   T visitExportClause(ExportClause node);
   T visitNameSpecifier(NameSpecifier node);
-  T visitModule(Module node);
 
   T visitComment(Comment node);
   T visitCommentExpression(CommentExpression node);
@@ -256,8 +253,6 @@
   T visitExportClause(ExportClause node) => visitNode(node);
   @override
   T visitNameSpecifier(NameSpecifier node) => visitNode(node);
-  @override
-  T visitModule(Module node) => visitNode(node);
 
   T visitInterpolatedNode(InterpolatedNode node) => visitNode(node);
 
@@ -322,7 +317,7 @@
 abstract class Node {
   /// Sets the source location of this node. For performance reasons, we allow
   /// setting this after construction.
-  Object sourceInformation;
+  Object? sourceInformation;
 
   T accept<T>(NodeVisitor<T> visitor);
   void visitChildren(NodeVisitor visitor);
@@ -371,7 +366,7 @@
 // TODO(jmesserly): rename to Module.
 class Program extends Node {
   /// Script tag hash-bang, e.g. `#!/usr/bin/env node`.
-  final String scriptTag;
+  final String? scriptTag;
 
   /// Top-level statements in the program.
   final List<ModuleItem> body;
@@ -379,7 +374,7 @@
   /// The module's own name.
   ///
   /// This is not used in ES6, but is provided to allow module lowering.
-  final String name;
+  final String? name;
 
   Program(this.body, {this.scriptTag, this.name});
 
@@ -439,9 +434,8 @@
   /// True to preserve this [Block] for scoping reasons.
   final bool isScope;
 
-  Block(this.statements, {this.isScope = false}) {
-    assert(statements.every((s) => s is Statement));
-  }
+  Block(this.statements, {this.isScope = false});
+
   Block.empty()
       : statements = <Statement>[],
         isScope = false;
@@ -516,13 +510,13 @@
   final Statement otherwise;
 
   If(this.condition, this.then, this.otherwise);
-  If.noElse(this.condition, this.then) : this.otherwise = null;
+  If.noElse(this.condition, this.then) : this.otherwise = EmptyStatement();
 
   @override
   bool get alwaysReturns =>
       hasElse && then.alwaysReturns && otherwise.alwaysReturns;
 
-  bool get hasElse => otherwise != null;
+  bool get hasElse => otherwise is! EmptyStatement;
 
   @override
   T accept<T>(NodeVisitor<T> visitor) => visitor.visitIf(this);
@@ -531,7 +525,7 @@
   void visitChildren(NodeVisitor visitor) {
     condition.accept(visitor);
     then.accept(visitor);
-    otherwise?.accept(visitor);
+    otherwise.accept(visitor);
   }
 
   @override
@@ -544,9 +538,9 @@
 }
 
 class For extends Loop {
-  final Expression init;
-  final Expression condition;
-  final Expression update;
+  final Expression? init;
+  final Expression? condition;
+  final Expression? update;
 
   For(this.init, this.condition, this.update, Statement body) : super(body);
 
@@ -646,7 +640,8 @@
 }
 
 class Continue extends Statement {
-  final String targetLabel; // Can be null.
+  /// Name of the label L for `continue L;` or `null` for `continue;`.
+  final String? targetLabel;
 
   Continue(this.targetLabel);
 
@@ -660,7 +655,8 @@
 }
 
 class Break extends Statement {
-  final String targetLabel; // Can be null.
+  /// Name of the label L for `break L;` or `null` for `break;`.
+  final String? targetLabel;
 
   Break(this.targetLabel);
 
@@ -674,7 +670,7 @@
 }
 
 class Return extends Statement {
-  final Expression value; // Can be null.
+  final Expression? value;
 
   Return([this.value]);
 
@@ -736,8 +732,8 @@
 
 class Try extends Statement {
   final Block body;
-  final Catch catchPart; // Can be null if [finallyPart] is non-null.
-  final Block finallyPart; // Can be null if [catchPart] is non-null.
+  final Catch? catchPart; // Can be null if [finallyPart] is non-null.
+  final Block? finallyPart; // Can be null if [catchPart] is non-null.
 
   Try(this.body, this.catchPart, this.finallyPart) {
     assert(catchPart != null || finallyPart != null);
@@ -912,11 +908,11 @@
   Expression();
 
   factory Expression.binary(List<Expression> exprs, String op) {
-    Expression comma;
+    Expression? comma;
     for (var node in exprs) {
       comma = (comma == null) ? node : Binary(op, comma, node);
     }
-    return comma;
+    return comma!;
   }
 
   int get precedenceLevel;
@@ -931,7 +927,7 @@
       ExpressionStatement(Yield(this, star: star));
 
   Expression toVoidExpression() => this;
-  Expression toAssignExpression(Expression left, [String op]) =>
+  Expression toAssignExpression(Expression left, [String? op]) =>
       Assignment.compound(left, op, this);
 
   // TODO(jmesserly): make this work for more cases?
@@ -963,7 +959,9 @@
 class VariableDeclarationList extends Expression {
   /// The `var` or `let` or `const` keyword used for this variable declaration
   /// list.
-  final String keyword;
+  ///
+  /// Can be null in the case of non-static field declarations.
+  final String? keyword;
   final List<VariableInitialization> declarations;
 
   VariableDeclarationList(this.keyword, this.declarations);
@@ -1000,10 +998,12 @@
 
 class Assignment extends Expression {
   final Expression leftHandSide;
-  final String op; // Null, if the assignment is not compound.
+  final String? op; // `null` if the assignment is not compound.
   final Expression value;
 
   Assignment(this.leftHandSide, this.value) : op = null;
+
+  // If `this.op == null` this will be a non-compound assignment.
   Assignment.compound(this.leftHandSide, this.op, this.value);
 
   @override
@@ -1017,7 +1017,7 @@
   @override
   void visitChildren(NodeVisitor visitor) {
     leftHandSide.accept(visitor);
-    value?.accept(visitor);
+    value.accept(visitor);
   }
 
   @override
@@ -1026,9 +1026,9 @@
 
 class VariableInitialization extends Expression {
   final VariableBinding declaration;
-  final Expression value; // May be null.
+  // The initializing value can be missing, e.g. for `a` in `var a, b=1;`.
+  final Expression? value;
 
-  /// [value] may be null.
   VariableInitialization(this.declaration, this.value);
 
   @override
@@ -1067,20 +1067,16 @@
   ///     console.log(foo); // "bar"
   ///
   // TODO(jmesserly): parser does not support this feature.
-  final Expression property;
-
-  final BindingPattern structure;
-  final Expression defaultValue;
+  final Expression? property;
+  final BindingPattern? structure;
+  final Expression? defaultValue;
 
   DestructuredVariable(
-      {this.name, this.property, this.structure, this.defaultValue}) {
-    assert(name != null || structure != null);
-  }
+      {required this.name, this.property, this.structure, this.defaultValue});
 
   @override
   bool shadows(Set<String> names) {
-    return (name?.shadows(names) ?? false) ||
-        (structure?.shadows(names) ?? false);
+    return name.shadows(names) || (structure?.shadows(names) ?? false);
   }
 
   @override
@@ -1088,7 +1084,7 @@
       visitor.visitDestructuredVariable(this);
   @override
   void visitChildren(NodeVisitor visitor) {
-    name?.accept(visitor);
+    name.accept(visitor);
     structure?.accept(visitor);
     defaultValue?.accept(visitor);
   }
@@ -1850,7 +1846,7 @@
 
 // TODO(jmesserly): parser does not support this yet.
 class Yield extends Expression {
-  final Expression value; // Can be null.
+  final Expression? value;
 
   /// Whether this yield expression is a `yield*` that iterates each item in
   /// [value].
@@ -1888,7 +1884,7 @@
 
 class ClassExpression extends Expression {
   final Identifier name;
-  final Expression heritage; // Can be null.
+  final Expression? heritage;
   final List<Method> methods;
 
   ClassExpression(this.name, this.heritage, this.methods);
@@ -2215,26 +2211,24 @@
 abstract class ModuleItem extends Node {}
 
 class ImportDeclaration extends ModuleItem {
-  final Identifier defaultBinding; // Can be null.
+  final Identifier? defaultBinding;
 
-  // Can be null, a single specifier of `* as name`, or a list.
-  final List<NameSpecifier> namedImports;
+  // Can be `null`, a single specifier of `* as name`, or a list.
+  final List<NameSpecifier>? namedImports;
 
   final LiteralString from;
 
-  ImportDeclaration({this.defaultBinding, this.namedImports, this.from}) {
-    assert(from != null);
-  }
+  ImportDeclaration(
+      {this.defaultBinding, this.namedImports, required this.from});
 
   /// The `import "name.js"` form of import.
   ImportDeclaration.all(LiteralString module) : this(from: module);
 
   /// If this import has `* as name` returns the name, otherwise null.
-  Identifier get importStarAs {
-    if (namedImports != null &&
-        namedImports.length == 1 &&
-        namedImports[0].isStar) {
-      return namedImports[0].asName;
+  Identifier? get importStarAs {
+    var imports = namedImports;
+    if (imports != null && imports.length == 1 && imports[0].isStar) {
+      return imports[0].asName;
     }
     return null;
   }
@@ -2243,8 +2237,9 @@
   T accept<T>(NodeVisitor<T> visitor) => visitor.visitImportDeclaration(this);
   @override
   void visitChildren(NodeVisitor visitor) {
-    if (namedImports != null) {
-      for (NameSpecifier name in namedImports) {
+    var imports = namedImports;
+    if (imports != null) {
+      for (NameSpecifier name in imports) {
         name.accept(visitor);
       }
     }
@@ -2279,7 +2274,7 @@
   /// if this is an `export *`.
   ///
   /// This can be useful for lowering to other module formats.
-  List<NameSpecifier> get exportedNames {
+  List<NameSpecifier>? get exportedNames {
     if (isDefault) return [NameSpecifier(Identifier('default'))];
 
     var exported = this.exported;
@@ -2310,7 +2305,7 @@
 
 class ExportClause extends Node {
   final List<NameSpecifier> exports;
-  final LiteralString from; // Can be null.
+  final LiteralString? from;
 
   ExportClause(this.exports, {this.from});
 
@@ -2337,8 +2332,8 @@
 
 /// An import or export specifier.
 class NameSpecifier extends Node {
-  final Identifier name;
-  final Identifier asName; // Can be null.
+  final Identifier? name;
+  final Identifier? asName;
 
   NameSpecifier(this.name, {this.asName});
   NameSpecifier.star() : this(null);
@@ -2353,26 +2348,3 @@
   @override
   NameSpecifier _clone() => NameSpecifier(name, asName: asName);
 }
-
-// TODO(jmesserly): should this be related to [Program]?
-class Module extends Node {
-  /// The module's name.
-  // TODO(jmesserly): this is not declared in ES6, but is known by the loader.
-  // We use this because some ES5 desugarings require it.
-  final String name;
-
-  final List<ModuleItem> body;
-  Module(this.body, {this.name});
-
-  @override
-  T accept<T>(NodeVisitor<T> visitor) => visitor.visitModule(this);
-  @override
-  void visitChildren(NodeVisitor visitor) {
-    for (ModuleItem item in body) {
-      item.accept(visitor);
-    }
-  }
-
-  @override
-  Module _clone() => Module(body);
-}
diff --git a/pkg/dev_compiler/lib/src/js_ast/precedence.dart b/pkg/dev_compiler/lib/src/js_ast/precedence.dart
index 50f69ed..f149dc2 100644
--- a/pkg/dev_compiler/lib/src/js_ast/precedence.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/precedence.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
-
 const EXPRESSION = 0;
 // TODO(nshahan) No longer used for the spread operator.
 // All precedence levels need to be updated to be more accurate.
diff --git a/pkg/dev_compiler/lib/src/js_ast/printer.dart b/pkg/dev_compiler/lib/src/js_ast/printer.dart
index 1c5767b..adddaae 100644
--- a/pkg/dev_compiler/lib/src/js_ast/printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/printer.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
-
 // ignore_for_file: always_declare_return_types
 // ignore_for_file: library_prefixes
 // ignore_for_file: omit_local_variable_types
@@ -58,7 +56,7 @@
   /// Callback after printing the last character representing [node].
   void exitNode(Node node) {}
 
-  Printer printer;
+  late Printer printer;
 }
 
 /// A simple implementation of [JavaScriptPrintingContext] suitable for tests.
@@ -100,7 +98,7 @@
   static final expressionContinuationRegExp = RegExp(r'^[-+([]');
 
   Printer(JavaScriptPrintingOptions options, JavaScriptPrintingContext context,
-      {LocalNamer localNamer})
+      {LocalNamer? localNamer})
       : options = options,
         context = context,
         shouldCompressOutput = options.shouldCompressOutput,
@@ -110,7 +108,7 @@
   }
 
   static LocalNamer determineRenamer(
-      LocalNamer localNamer, JavaScriptPrintingOptions options) {
+      LocalNamer? localNamer, JavaScriptPrintingOptions options) {
     if (localNamer != null) return localNamer;
     return (options.shouldCompressOutput && options.minifyLocalVariables)
         ? MinifyRenamer()
@@ -148,9 +146,9 @@
     if (!shouldCompressOutput) out(" ");
   }
 
-  String lastAddedString;
+  String lastAddedString = '\u0000';
+
   int get lastCharCode {
-    if (lastAddedString == null) return 0;
     assert(lastAddedString.isNotEmpty);
     return lastAddedString.codeUnitAt(lastAddedString.length - 1);
   }
@@ -236,7 +234,7 @@
   }
 
   visitCommaSeparated(List<Expression> nodes, int hasRequiredType,
-      {bool newInForInit, bool newAtStatementBegin}) {
+      {required bool newInForInit, required bool newAtStatementBegin}) {
     for (int i = 0; i < nodes.length; i++) {
       if (i != 0) {
         atStatementBegin = false;
@@ -260,10 +258,11 @@
     visitAll(program.body);
   }
 
-  bool blockBody(Node body, {bool needsSeparation, bool needsNewline}) {
+  bool blockBody(Node body,
+      {required bool needsSeparation, required bool needsNewline}) {
     if (body is Block) {
       spaceOut();
-      blockOut(body, false, needsNewline);
+      blockOut(body, shouldIndent: false, needsNewline: needsNewline);
       return true;
     }
     if (shouldCompressOutput && needsSeparation) {
@@ -290,7 +289,8 @@
     }
   }
 
-  void blockOut(Block node, bool shouldIndent, bool needsNewline) {
+  void blockOut(Block node,
+      {required bool shouldIndent, required bool needsNewline}) {
     if (shouldIndent) indent();
     context.enterNode(node);
     out("{");
@@ -306,7 +306,7 @@
 
   @override
   visitBlock(Block block) {
-    blockOut(block, true, true);
+    blockOut(block, shouldIndent: true, needsNewline: true);
   }
 
   @override
@@ -387,19 +387,19 @@
     spaceOut();
     out("(");
     if (loop.init != null) {
-      visitNestedExpression(loop.init, EXPRESSION,
+      visitNestedExpression(loop.init!, EXPRESSION,
           newInForInit: true, newAtStatementBegin: false);
     }
     out(";");
     if (loop.condition != null) {
       spaceOut();
-      visitNestedExpression(loop.condition, EXPRESSION,
+      visitNestedExpression(loop.condition!, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
     }
     out(";");
     if (loop.update != null) {
       spaceOut();
-      visitNestedExpression(loop.update, EXPRESSION,
+      visitNestedExpression(loop.update!, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
     }
     out(")");
@@ -491,7 +491,7 @@
     } else {
       outIndent("return");
       pendingSpace = true;
-      visitNestedExpression(node.value, EXPRESSION,
+      visitNestedExpression(node.value!, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
     }
     outSemicolonLn();
@@ -524,12 +524,12 @@
     outIndent("try");
     blockBody(node.body, needsSeparation: true, needsNewline: false);
     if (node.catchPart != null) {
-      visit(node.catchPart);
+      visit(node.catchPart!);
     }
     if (node.finallyPart != null) {
       spaceOut();
       out("finally");
-      blockBody(node.finallyPart, needsSeparation: true, needsNewline: true);
+      blockBody(node.finallyPart!, needsSeparation: true, needsNewline: true);
     } else {
       lineOut();
     }
@@ -593,7 +593,7 @@
     blockBody(node.body, needsSeparation: false, needsNewline: true);
   }
 
-  void functionOut(Fun fun, Identifier name) {
+  void functionOut(Fun fun, Identifier? name) {
     out("function");
     if (fun.isGenerator) out("*");
     if (name != null) {
@@ -604,10 +604,10 @@
     }
     localNamer.enterScope(fun);
     out("(");
-    if (fun.params != null) {
-      visitCommaSeparated(fun.params, PRIMARY,
-          newInForInit: false, newAtStatementBegin: false);
-    }
+
+    visitCommaSeparated(fun.params, PRIMARY,
+        newInForInit: false, newAtStatementBegin: false);
+
     out(")");
     switch (fun.asyncModifier) {
       case const AsyncModifier.sync():
@@ -637,7 +637,7 @@
   }
 
   visitNestedExpression(Expression node, int requiredPrecedence,
-      {bool newInForInit, bool newAtStatementBegin}) {
+      {required bool newInForInit, required bool newAtStatementBegin}) {
     int nodePrecedence = node.precedenceLevel;
     bool needsParentheses =
         // a - (b + c).
@@ -669,7 +669,7 @@
   visitVariableDeclarationList(VariableDeclarationList list) {
     // Note: keyword can be null for non-static field declarations.
     if (list.keyword != null) {
-      out(list.keyword);
+      out(list.keyword!);
       out(" ");
     }
     visitCommaSeparated(list.declarations, ASSIGNMENT,
@@ -696,16 +696,15 @@
   visitDestructuredVariable(DestructuredVariable node) {
     var name = node.name;
     var property = node.property;
-    if (name != null) {
-      visit(node.name);
-    } else if (property != null) {
+    visit(name);
+    if (property != null) {
       out("[");
-      visit(node.property);
+      visit(property);
       out("]");
     }
     var structure = node.structure;
     if (structure != null) {
-      if (name != null || property != null) {
+      if (property != null) {
         out(":");
         spaceOut();
       }
@@ -730,26 +729,24 @@
   visitAssignment(Assignment assignment) {
     visitNestedExpression(assignment.leftHandSide, LEFT_HAND_SIDE,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
-    if (assignment.value != null) {
-      spaceOut();
-      String op = assignment.op;
-      if (op != null) out(op);
-      out("=");
-      spaceOut();
-      visitNestedExpression(assignment.value, ASSIGNMENT,
-          newInForInit: inForInit, newAtStatementBegin: false);
-    }
+    spaceOut();
+    String? op = assignment.op;
+    if (op != null) out(op);
+    out("=");
+    spaceOut();
+    visitNestedExpression(assignment.value, ASSIGNMENT,
+        newInForInit: inForInit, newAtStatementBegin: false);
   }
 
   @override
-  visitVariableInitialization(VariableInitialization init) {
-    visitNestedExpression(init.declaration, LEFT_HAND_SIDE,
+  visitVariableInitialization(VariableInitialization initialization) {
+    visitNestedExpression(initialization.declaration, LEFT_HAND_SIDE,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
-    if (init.value != null) {
+    if (initialization.value != null) {
       spaceOut();
       out("=");
       spaceOut();
-      visitNestedExpression(init.value, ASSIGNMENT,
+      visitNestedExpression(initialization.value!, ASSIGNMENT,
           newInForInit: inForInit, newAtStatementBegin: false);
     }
   }
@@ -874,6 +871,8 @@
         rightPrecedenceRequirement = UNARY;
         break;
       default:
+        leftPrecedenceRequirement = EXPRESSION;
+        rightPrecedenceRequirement = EXPRESSION;
         context.error("Forgot operator: $op");
     }
 
@@ -932,7 +931,7 @@
     out(yield.star ? "yield*" : "yield");
     if (yield.value == null) return;
     out(" ");
-    visitNestedExpression(yield.value, yield.precedenceLevel,
+    visitNestedExpression(yield.value!, yield.precedenceLevel,
         newInForInit: inForInit, newAtStatementBegin: false);
   }
 
@@ -1195,7 +1194,7 @@
     visit(node.name);
     if (node.heritage != null) {
       out(' extends ');
-      visit(node.heritage);
+      visit(node.heritage!);
     }
     spaceOut();
     if (node.methods.isNotEmpty) {
@@ -1233,10 +1232,8 @@
     var fun = node.function;
     localNamer.enterScope(fun);
     out("(");
-    if (fun.params != null) {
-      visitCommaSeparated(fun.params, SPREAD,
-          newInForInit: false, newAtStatementBegin: false);
-    }
+    visitCommaSeparated(fun.params, SPREAD,
+        newInForInit: false, newAtStatementBegin: false);
     out(")");
     // TODO(jmesserly): async modifiers
     if (fun.body.statements.isEmpty) {
@@ -1244,7 +1241,7 @@
       out("{}");
     } else {
       spaceOut();
-      blockOut(fun.body, false, false);
+      blockOut(fun.body, shouldIndent: false, needsNewline: false);
     }
     localNamer.leaveScope();
   }
@@ -1281,13 +1278,15 @@
     indent();
     out('import ');
     if (node.defaultBinding != null) {
-      visit(node.defaultBinding);
+      visit(node.defaultBinding!);
       if (node.namedImports != null) {
         out(',');
         spaceOut();
       }
     }
-    nameSpecifierListOut(node.namedImports, false);
+    if (node.namedImports != null) {
+      nameSpecifierListOut(node.namedImports!, false);
+    }
     fromClauseOut(node.from);
     outSemicolonLn();
   }
@@ -1305,13 +1304,13 @@
   @override
   visitExportClause(ExportClause node) {
     nameSpecifierListOut(node.exports, true);
-    fromClauseOut(node.from);
+    if (node.from != null) {
+      fromClauseOut(node.from!);
+    }
   }
 
   nameSpecifierListOut(List<NameSpecifier> names, bool export) {
-    if (names == null) return;
-
-    if (names.length == 1 && names[0].name.name == '*') {
+    if (names.length == 1 && names[0].name!.name == '*') {
       nameSpecifierOut(names[0], export);
       return;
     }
@@ -1330,11 +1329,9 @@
   }
 
   fromClauseOut(LiteralString from) {
-    if (from != null) {
-      out(' from');
-      spaceOut();
-      out("'${from.valueWithoutQuotes}.js'");
-    }
+    out(' from');
+    spaceOut();
+    out("'${from.valueWithoutQuotes}.js'");
   }
 
   /// This is unused, see [nameSpecifierOut].
@@ -1347,11 +1344,13 @@
     if (node.isStar) {
       out('*');
     } else {
-      var localName = localNamer.getName(node.name);
+      assert(node.name != null);
+      var nodeName = node.name!;
+      var localName = localNamer.getName(nodeName);
       if (node.asName == null) {
         // If our local was renamed, generate an implicit "as".
         // This is a convenience feature so imports and exports can be renamed.
-        var name = node.name.name;
+        var name = nodeName.name;
         if (localName != name) {
           out(export ? localName : name);
           out(' as ');
@@ -1363,16 +1362,11 @@
     }
     if (node.asName != null) {
       out(' as ');
-      visitIdentifier(node.asName);
+      visitIdentifier(node.asName!);
     }
   }
 
   @override
-  visitModule(Module node) {
-    visitAll(node.body);
-  }
-
-  @override
   visitLiteralExpression(LiteralExpression node) {
     out(node.template);
   }
@@ -1467,12 +1461,10 @@
   void collectVarsInFunction(FunctionExpression fun) {
     if (!nested) {
       nested = true;
-      if (fun.params != null) {
-        for (var param in fun.params) {
-          // TODO(jmesserly): add ES6 support. Currently not needed because
-          // dart2js does not emit ES6 rest param or destructuring.
-          params.add((param as Identifier).name);
-        }
+      for (var param in fun.params) {
+        // TODO(jmesserly): add ES6 support. Currently not needed because
+        // dart2js does not emit ES6 rest param or destructuring.
+        params.add((param as Identifier).name);
       }
       fun.body.accept(this);
       nested = false;
@@ -1587,9 +1579,9 @@
   @override
   bool visitTry(Try node) {
     if (node.finallyPart != null) {
-      return node.finallyPart.accept(this);
+      return node.finallyPart!.accept(this);
     } else {
-      return node.catchPart.accept(this);
+      return node.catchPart!.accept(this);
     }
   }
 
@@ -1782,7 +1774,7 @@
   @override
   visitDestructuredVariable(DestructuredVariable node) {
     var name = node.name;
-    if (name is Identifier) _scanVariableBinding(name);
+    _scanVariableBinding(name);
     super.visitDestructuredVariable(node);
   }
 
diff --git a/pkg/dev_compiler/lib/src/js_ast/template.dart b/pkg/dev_compiler/lib/src/js_ast/template.dart
index 792d32b..71b7662 100644
--- a/pkg/dev_compiler/lib/src/js_ast/template.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/template.dart
@@ -774,9 +774,6 @@
     return (a) => Await(makeExpr(a));
   }
 
-  // Note: these are not supported yet in the interpolation grammar.
-  @override
-  Instantiator visitModule(Module node) => throw UnimplementedError();
   @override
   Instantiator visitNameSpecifier(NameSpecifier node) =>
       throw UnimplementedError();
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index adb167d..bd0d2d8 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -4379,8 +4379,12 @@
 
   @override
   js_ast.Statement visitIfStatement(IfStatement node) {
-    return js_ast.If(_visitTest(node.condition), _visitScope(node.then),
-        _visitScope(node.otherwise));
+    var condition = _visitTest(node.condition);
+    var then = _visitScope(node.then);
+    if (node.otherwise != null) {
+      return js_ast.If(condition, then, _visitScope(node.otherwise));
+    }
+    return js_ast.If.noElse(condition, then);
   }
 
   /// Visits a statement, and ensures the resulting AST handles block scope
diff --git a/pkg/js_ast/lib/src/builder.dart b/pkg/js_ast/lib/src/builder.dart
index d5771ee..cd92fab 100644
--- a/pkg/js_ast/lib/src/builder.dart
+++ b/pkg/js_ast/lib/src/builder.dart
@@ -2,6 +2,8 @@
 // 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.15
+
 /// Utilities for building JS ASTs at runtime. Contains a builder class and a
 /// parser that parses part of the language.
 library js_ast.builder;
@@ -198,19 +200,19 @@
   /// '#' signs.
   Expression call(String source, [var arguments]) {
     Template template = _findExpressionTemplate(source);
-    if (arguments == null) return template.instantiate([]);
+    arguments ??= [];
     // We allow a single argument to be given directly.
     if (arguments is! List && arguments is! Map) arguments = [arguments];
-    return template.instantiate(arguments);
+    return template.instantiate(arguments) as Expression;
   }
 
   /// Parses a JavaScript Statement, otherwise just like [call].
   Statement statement(String source, [var arguments]) {
     Template template = _findStatementTemplate(source);
-    if (arguments == null) return template.instantiate([]);
+    arguments ??= [];
     // We allow a single argument to be given directly.
     if (arguments is! List && arguments is! Map) arguments = [arguments];
-    return template.instantiate(arguments);
+    return template.instantiate(arguments) as Statement;
   }
 
   /// Parses JavaScript written in the `JS` foreign instruction.
@@ -229,7 +231,7 @@
   }
 
   Template _findExpressionTemplate(String source) {
-    Template template = templateManager.lookupExpressionTemplate(source);
+    Template? template = templateManager.lookupExpressionTemplate(source);
     if (template == null) {
       MiniJsParser parser = MiniJsParser(source);
       Expression expression = parser.expression();
@@ -239,7 +241,7 @@
   }
 
   Template _findStatementTemplate(String source) {
-    Template template = templateManager.lookupStatementTemplate(source);
+    Template? template = templateManager.lookupStatementTemplate(source);
     if (template == null) {
       MiniJsParser parser = MiniJsParser(source);
       Statement statement = parser.statement();
@@ -272,11 +274,11 @@
   /// Create an Expression template which has [ast] as the result. This is used
   /// to wrap a generated AST in a zero-argument Template so it can be passed to
   /// context that expects a template.
-  Template expressionTemplateYielding(Node ast) {
+  Template expressionTemplateYielding(Expression ast) {
     return Template.withExpressionResult(ast);
   }
 
-  Template statementTemplateYielding(Node ast) {
+  Template statementTemplateYielding(Statement ast) {
     return Template.withStatementResult(ast);
   }
 
@@ -739,7 +741,7 @@
         if (lastToken == '=>') {
           lastCategory = ARROW;
         } else {
-          int binaryPrecedence = BINARY_PRECEDENCE[lastToken];
+          int? binaryPrecedence = BINARY_PRECEDENCE[lastToken];
           if (binaryPrecedence == null &&
               !UNARY_OPERATORS.contains(lastToken)) {
             error("Unknown operator");
@@ -791,7 +793,7 @@
     return false;
   }
 
-  void error(message) {
+  Never error(message) {
     throw MiniJsParserError(this, message);
   }
 
@@ -850,7 +852,7 @@
         expectCategory(COMMA);
       }
       return ArrayInitializer(values);
-    } else if (last != null && last.startsWith("/")) {
+    } else if (last.startsWith("/")) {
       String regexp = getRegExp(lastPosition);
       getToken();
       String flags = lastToken;
@@ -865,7 +867,6 @@
       return expression;
     } else {
       error("Expected primary expression");
-      return null;
     }
   }
 
@@ -877,7 +878,7 @@
     return parseFun();
   }
 
-  Expression parseFun() {
+  Fun parseFun() {
     List<Parameter> params = [];
     expectCategory(LPAREN);
     if (!acceptCategory(RPAREN)) {
@@ -951,7 +952,7 @@
       Expression value = parseAssignment();
       return Property(propertyName, value);
     } else {
-      Expression fun = parseFun();
+      final fun = parseFun();
       return MethodDefinition(propertyName, fun);
     }
   }
@@ -1066,27 +1067,29 @@
 
   Expression parseBinary(int maxPrecedence) {
     Expression lhs = parseUnaryLow();
-    int minPrecedence;
-    String lastSymbol;
-    Expression rhs; // This is null first time around.
+    Expression? rhs; // This is null first time around.
+    late int minPrecedence;
+    late String lastSymbol;
+
     while (true) {
-      String symbol = lastToken;
-      if (lastCategory != SYMBOL ||
-          !BINARY_PRECEDENCE.containsKey(symbol) ||
-          BINARY_PRECEDENCE[symbol] > maxPrecedence) {
-        break;
-      }
+      final symbol = lastToken;
+      if (lastCategory != SYMBOL) break;
+      final symbolPrecedence = BINARY_PRECEDENCE[symbol];
+      if (symbolPrecedence == null) break;
+      if (symbolPrecedence > maxPrecedence) break;
+
       expectCategory(SYMBOL);
-      if (rhs == null || BINARY_PRECEDENCE[symbol] >= minPrecedence) {
+      if (rhs == null || symbolPrecedence >= minPrecedence) {
         if (rhs != null) lhs = Binary(lastSymbol, lhs, rhs);
-        minPrecedence = BINARY_PRECEDENCE[symbol];
+        minPrecedence = symbolPrecedence;
         rhs = parseUnaryLow();
         lastSymbol = symbol;
       } else {
-        Expression higher = parseBinary(BINARY_PRECEDENCE[symbol]);
+        Expression higher = parseBinary(symbolPrecedence);
         rhs = Binary(symbol, rhs, higher);
       }
     }
+
     if (rhs == null) return lhs;
     return Binary(lastSymbol, lhs, rhs);
   }
@@ -1173,7 +1176,7 @@
     var initialization = <VariableInitialization>[];
 
     void declare(Declaration declaration) {
-      Expression initializer = null;
+      Expression? initializer = null;
       if (acceptString("=")) {
         initializer = parseAssignment();
       }
@@ -1318,7 +1321,7 @@
     return Throw(expression);
   }
 
-  Statement parseBreakOrContinue(constructor) {
+  Statement parseBreakOrContinue(Statement Function(String?) constructor) {
     var identifier = lastToken;
     if (!skippedNewline && acceptCategory(ALPHA)) {
       expectSemicolon();
@@ -1349,13 +1352,13 @@
     //
     //     for (var variable in Expression) Statement
     //
-    Statement finishFor(Expression init) {
-      Expression condition = null;
+    Statement finishFor(Expression? init) {
+      Expression? condition = null;
       if (!acceptCategory(SEMICOLON)) {
         condition = parseExpression();
         expectCategory(SEMICOLON);
       }
-      Expression update = null;
+      Expression? update = null;
       if (!acceptCategory(RPAREN)) {
         update = parseExpression();
         expectCategory(RPAREN);
@@ -1407,16 +1410,16 @@
 
   Statement parseFunctionDeclaration() {
     Declaration name = parseVariableDeclaration();
-    Expression fun = parseFun();
+    Fun fun = parseFun();
     return FunctionDeclaration(name, fun);
   }
 
   Statement parseTry() {
     expectCategory(LBRACE);
     Block body = parseBlock();
-    Catch catchPart = null;
+    Catch? catchPart = null;
     if (acceptString('catch')) catchPart = parseCatch();
-    Block finallyPart = null;
+    Block? finallyPart = null;
     if (acceptString('finally')) {
       expectCategory(LBRACE);
       finallyPart = parseBlock();
@@ -1427,7 +1430,7 @@
   }
 
   SwitchClause parseSwitchClause() {
-    Expression expression = null;
+    Expression? expression = null;
     if (acceptString('case')) {
       expression = parseExpression();
       expectCategory(COLON);
@@ -1437,7 +1440,7 @@
       }
       expectCategory(COLON);
     }
-    List statements = <Statement>[];
+    List<Statement> statements = [];
     while (lastCategory != RBRACE &&
         lastToken != 'case' &&
         lastToken != 'default') {
diff --git a/pkg/js_ast/lib/src/template.dart b/pkg/js_ast/lib/src/template.dart
index bbf759e..662ff13 100644
--- a/pkg/js_ast/lib/src/template.dart
+++ b/pkg/js_ast/lib/src/template.dart
@@ -2,6 +2,8 @@
 // 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.15
+
 library js_ast.template;
 
 import 'nodes.dart';
@@ -12,7 +14,7 @@
 
   TemplateManager();
 
-  Template lookupExpressionTemplate(String source) {
+  Template? lookupExpressionTemplate(String source) {
     return expressionTemplates[source];
   }
 
@@ -23,7 +25,7 @@
     return template;
   }
 
-  Template lookupStatementTemplate(String source) {
+  Template? lookupStatementTemplate(String source) {
     return statementTemplates[source];
   }
 
@@ -41,66 +43,75 @@
 /// The [instantiate] method creates an AST that looks like the original with
 /// the placeholders replaced by the arguments to [instantiate].
 class Template {
-  final String source;
+  final String? source;
   final bool isExpression;
   final bool forceCopy;
   final Node ast;
 
-  Instantiator instantiator;
+  final Instantiator instantiator;
 
-  int positionalArgumentCount = -1;
+  final int positionalArgumentCount;
 
-  // Null, unless there are named holes.
-  List<String> holeNames;
-  bool get isPositional => holeNames == null;
+  // Names of named holes, empty if there are no named holes.
+  final List<String> holeNames;
 
-  Template(this.source, this.ast,
-      {this.isExpression = true, this.forceCopy = false}) {
-    assert(this.isExpression ? ast is Expression : ast is Statement);
-    _compile();
+  bool get isPositional => holeNames.isEmpty;
+
+  Template._(this.source, this.ast,
+      {required this.instantiator,
+      required this.isExpression,
+      required this.forceCopy,
+      required this.positionalArgumentCount,
+      this.holeNames = const []});
+
+  factory Template(String? source, Node ast,
+      {bool isExpression = true, bool forceCopy = false}) {
+    assert(isExpression ? ast is Expression : ast is Statement);
+
+    final generator = InstantiatorGeneratorVisitor(forceCopy);
+    final instantiator = generator.compile(ast);
+    final positionalArgumentCount = generator.analysis.count;
+    final names = generator.analysis.holeNames;
+    final holeNames = names.toList(growable: false);
+
+    return Template._(source, ast,
+        instantiator: instantiator,
+        isExpression: isExpression,
+        forceCopy: forceCopy,
+        positionalArgumentCount: positionalArgumentCount,
+        holeNames: holeNames);
   }
 
-  Template.withExpressionResult(this.ast)
-      : source = null,
-        isExpression = true,
-        forceCopy = false {
-    assert(ast is Expression);
-    assert(_checkNoPlaceholders());
-    positionalArgumentCount = 0;
-    instantiator = (arguments) => ast;
+  factory Template.withExpressionResult(Expression ast) {
+    assert(_checkNoPlaceholders(ast));
+    return Template._(null, ast,
+        instantiator: (arguments) => ast,
+        isExpression: true,
+        forceCopy: false,
+        positionalArgumentCount: 0);
   }
 
-  Template.withStatementResult(this.ast)
-      : source = null,
-        isExpression = false,
-        forceCopy = false {
-    assert(ast is Statement);
-    assert(_checkNoPlaceholders());
-    positionalArgumentCount = 0;
-    instantiator = (arguments) => ast;
+  factory Template.withStatementResult(Statement ast) {
+    assert(_checkNoPlaceholders(ast));
+    return Template._(null, ast,
+        instantiator: (arguments) => ast,
+        isExpression: false,
+        forceCopy: false,
+        positionalArgumentCount: 0);
   }
 
-  bool _checkNoPlaceholders() {
+  static bool _checkNoPlaceholders(Node ast) {
     InstantiatorGeneratorVisitor generator =
         InstantiatorGeneratorVisitor(false);
     generator.compile(ast);
     return generator.analysis.count == 0;
   }
 
-  void _compile() {
-    InstantiatorGeneratorVisitor generator =
-        InstantiatorGeneratorVisitor(forceCopy);
-    instantiator = generator.compile(ast);
-    positionalArgumentCount = generator.analysis.count;
-    Set<String> names = generator.analysis.holeNames;
-    holeNames = names.toList(growable: false);
-  }
-
   /// Instantiates the template with the given [arguments].
   ///
   /// This method fills in the holes with the given arguments. The [arguments]
   /// must be either a [List] or a [Map].
-  Node instantiate(var arguments) {
+  Node instantiate(Object arguments) {
     if (arguments is List) {
       if (arguments.length != positionalArgumentCount) {
         throw 'Wrong number of template arguments, given ${arguments.length}, '
@@ -109,20 +120,23 @@
       }
       return instantiator(arguments);
     }
-    assert(arguments is Map);
-    if (holeNames.length < arguments.length) {
-      // This search is in O(n), but we only do it in case of an error, and the
-      // number of holes should be quite limited.
-      String unusedNames =
-          arguments.keys.where((name) => !holeNames.contains(name)).join(", ");
-      throw "Template arguments has unused mappings: $unusedNames";
+    if (arguments is Map) {
+      if (holeNames.length < arguments.length) {
+        // This search is in O(n), but we only do it in case of an error, and the
+        // number of holes should be quite limited.
+        String unusedNames = arguments.keys
+            .where((name) => !holeNames.contains(name))
+            .join(", ");
+        throw "Template arguments has unused mappings: $unusedNames";
+      }
+      if (!holeNames.every((String name) => arguments.containsKey(name))) {
+        String notFound =
+            holeNames.where((name) => !arguments.containsKey(name)).join(", ");
+        throw "Template arguments is missing mappings for: $notFound";
+      }
+      return instantiator(arguments);
     }
-    if (!holeNames.every((String name) => arguments.containsKey(name))) {
-      String notFound =
-          holeNames.where((name) => !arguments.containsKey(name)).join(", ");
-      throw "Template arguments is missing mappings for: $notFound";
-    }
-    return instantiator(arguments);
+    throw ArgumentError.value(arguments, 'arguments', 'Must be a List or Map');
   }
 }
 
@@ -149,12 +163,12 @@
     return result;
   }
 
-  static error(String message) {
+  static Never error(String message) {
     throw message;
   }
 
   static Instantiator same(Node node) => (arguments) => node;
-  static Node makeNull(arguments) => null;
+  static Null makeNull(arguments) => null;
 
   Instantiator visit(Node node) {
     if (forceCopy || analysis.containsInterpolatedNodes(node)) {
@@ -163,7 +177,7 @@
     return same(node);
   }
 
-  Instantiator visitNullable(Node node) {
+  Instantiator visitNullable(Node? node) {
     if (node == null) return makeNull;
     return visit(node);
   }
@@ -310,44 +324,34 @@
     List<Instantiator> instantiators =
         node.body.map(visitSplayableStatement).toList();
     return (arguments) {
-      List<Statement> statements = [];
-      void add(node) {
-        if (node is EmptyStatement) return;
-        if (node is Iterable) {
-          statements.addAll(node);
-        } else {
-          statements.add(node.toStatement());
-        }
-      }
-
-      for (Instantiator instantiator in instantiators) {
-        add(instantiator(arguments));
-      }
-      return Program(statements);
+      return Program(splayStatements(instantiators, arguments));
     };
   }
 
+  List<Statement> splayStatements(List<Instantiator> instantiators, arguments) {
+    var statements = <Statement>[];
+    for (var instantiator in instantiators) {
+      final node = instantiator(arguments);
+      if (node is EmptyStatement) continue;
+      if (node is Iterable) {
+        statements.addAll(node as Iterable<Statement>);
+      } else if (node is Block /*&& !node.isScope*/) {
+        statements.addAll(node.statements);
+      } else if (node is Statement) {
+        statements.add(node);
+      } else {
+        error('Not splayable as statement: $node');
+      }
+    }
+    return statements;
+  }
+
   @override
   Instantiator visitBlock(Block node) {
     List<Instantiator> instantiators =
         node.statements.map(visitSplayableStatement).toList();
     return (arguments) {
-      List<Statement> statements = [];
-      void add(node) {
-        if (node is EmptyStatement) return;
-        if (node is Iterable) {
-          statements.addAll(node);
-        } else if (node is Block) {
-          statements.addAll(node.statements);
-        } else {
-          statements.add(node.toStatement());
-        }
-      }
-
-      for (Instantiator instantiator in instantiators) {
-        add(instantiator(arguments));
-      }
-      return Block(statements);
+      return Block(splayStatements(instantiators, arguments));
     };
   }
 
@@ -365,40 +369,35 @@
 
   @override
   Instantiator visitIf(If node) {
-    if (node.condition is InterpolatedExpression) {
-      return visitIfConditionalCompilation(node);
+    final condition = node.condition;
+    if (condition is InterpolatedExpression) {
+      return visitIfConditionalCompilation(node, condition);
     } else {
       return visitIfNormal(node);
     }
   }
 
-  Instantiator visitIfConditionalCompilation(If node) {
-    // Special version of visitInterpolatedExpression that permits bools.
-    compileCondition(InterpolatedExpression node) {
-      var nameOrPosition = node.nameOrPosition;
-      return (arguments) {
-        var value = arguments[nameOrPosition];
-        if (value is bool) return value;
-        if (value is Expression) return value;
-        if (value is String) return convertStringToVariableUse(value);
-        throw error('Interpolated value #$nameOrPosition '
-            'is not an Expression: $value');
-      };
-    }
-
-    var makeCondition = compileCondition(node.condition);
+  Instantiator visitIfConditionalCompilation(
+      If node, InterpolatedExpression condition) {
+    final nameOrPosition = condition.nameOrPosition;
     Instantiator makeThen = visit(node.then);
     Instantiator makeOtherwise = visit(node.otherwise);
     return (arguments) {
-      var condition = makeCondition(arguments);
-      if (condition is bool) {
-        if (condition == true) {
-          return makeThen(arguments);
-        } else {
-          return makeOtherwise(arguments);
-        }
+      // Allow booleans to be used for conditional compilation.
+      var value = arguments[nameOrPosition];
+      if (value is bool) {
+        return value ? makeThen(arguments) : makeOtherwise(arguments);
       }
-      return If(condition, makeThen(arguments), makeOtherwise(arguments));
+      Expression newCondition;
+      if (value is Expression) {
+        newCondition = value;
+      } else if (value is String) {
+        newCondition = convertStringToVariableUse(value);
+      } else {
+        error('Interpolated value #$nameOrPosition '
+            'is not an Expression: $value');
+      }
+      return If(newCondition, makeThen(arguments), makeOtherwise(arguments));
     };
   }
 
@@ -567,8 +566,8 @@
   @override
   Instantiator visitAssignment(Assignment node) {
     Instantiator makeLeftHandSide = visit(node.leftHandSide);
-    String op = node.op;
-    Instantiator makeValue = visitNullable(node.value);
+    String? op = node.op;
+    Instantiator makeValue = visit(node.value);
     return (arguments) {
       return Assignment.compound(
           makeLeftHandSide(arguments), op, makeValue(arguments));
@@ -611,15 +610,7 @@
     // copying.
     return (arguments) {
       Node target = makeTarget(arguments);
-      List<Expression> callArguments = [];
-      for (Instantiator instantiator in argumentMakers) {
-        var result = instantiator(arguments);
-        if (result is Iterable) {
-          callArguments.addAll(result);
-        } else {
-          callArguments.add(result);
-        }
-      }
+      List<Expression> callArguments = splay(argumentMakers, arguments);
       return finish(target, callArguments.toList(growable: false));
     };
   }
@@ -683,16 +674,8 @@
     Instantiator makeBody = visit(node.body);
     // TODO(sra): Avoid copying params if no interpolation or forced copying.
     return (arguments) {
-      List<Parameter> params = [];
-      for (Instantiator instantiator in paramMakers) {
-        var result = instantiator(arguments);
-        if (result is Iterable) {
-          params.addAll(result);
-        } else {
-          params.add(result);
-        }
-      }
-      Statement body = makeBody(arguments);
+      List<Parameter> params = splayParameters(paramMakers, arguments);
+      Block body = makeBody(arguments);
       return Fun(params, body);
     };
   }
@@ -703,21 +686,34 @@
     Instantiator makeBody = visit(node.body);
     // TODO(sra): Avoid copying params if no interpolation or forced copying.
     return (arguments) {
-      List<Parameter> params = [];
-      for (Instantiator instantiator in paramMakers) {
-        var result = instantiator(arguments);
-        if (result is Iterable) {
-          params.addAll(result);
-        } else {
-          params.add(result);
-        }
-      }
+      List<Parameter> params = splayParameters(paramMakers, arguments);
       // Either a Block or Expression.
       Node body = makeBody(arguments);
       return ArrowFunction(params, body);
     };
   }
 
+  List<Parameter> splayParameters(List<Instantiator> instantiators, arguments) {
+    // TODO(sra): This will be different when parameters include destructuring
+    // and default values.
+    return splay<Parameter>(instantiators, arguments);
+  }
+
+  List<T> splay<T>(Iterable<Instantiator> instantiators, arguments) {
+    List<T> results = [];
+    for (Instantiator instantiator in instantiators) {
+      var result = instantiator(arguments);
+      if (result is Iterable) {
+        for (final item in result) {
+          results.add(item as T);
+        }
+      } else {
+        results.add(result as T);
+      }
+    }
+    return results;
+  }
+
   @override
   Instantiator visitDeferredExpression(DeferredExpression node) => same(node);
 
@@ -751,9 +747,10 @@
     List<Instantiator> partMakers =
         node.parts.map(visit).toList(growable: false);
     return (arguments) {
-      List<Literal> parts = partMakers
-          .map((Instantiator instantiator) => instantiator(arguments))
-          .toList(growable: false);
+      List<Literal> parts = [
+        for (final instantiator in partMakers)
+          instantiator(arguments) as Literal
+      ];
       return StringConcatenation(parts);
     };
   }
@@ -795,15 +792,7 @@
         node.properties.map(visitSplayable).toList();
     bool isOneLiner = node.isOneLiner;
     return (arguments) {
-      List<Property> properties = [];
-      for (Instantiator instantiator in propertyMakers) {
-        var result = instantiator(arguments);
-        if (result is Iterable) {
-          properties.addAll(result);
-        } else {
-          properties.add(result);
-        }
-      }
+      List<Property> properties = splay(propertyMakers, arguments);
       return ObjectInitializer(properties, isOneLiner: isOneLiner);
     };
   }
diff --git a/runtime/vm/heap/gc_shared.h b/runtime/vm/heap/gc_shared.h
index b7aac40..1a0d98d7 100644
--- a/runtime/vm/heap/gc_shared.h
+++ b/runtime/vm/heap/gc_shared.h
@@ -129,7 +129,7 @@
                       raw_finalizer->untag(), callback, peer);
     }
     raw_entry.untag()->set_token(raw_entry);
-    callback(peer);
+    (*callback)(peer);
     if (external_size > 0) {
       if (FLAG_trace_finalizers) {
         TRACE_FINALIZER("Clearing external size %" Pd " bytes in %s space",
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 11bda3c..e042e93 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -5043,7 +5043,8 @@
 
 #undef FINALIZER_CROSS_GEN_TEST_CASE
 
-void NativeFinalizer_TwoEntriesCrossGen_Finalizer(intptr_t* token) {
+void NativeFinalizer_TwoEntriesCrossGen_Finalizer(void* peer) {
+  intptr_t* token = reinterpret_cast<intptr_t*>(peer);
   (*token)++;
 }
 
diff --git a/sdk/lib/ffi/c_type.dart b/sdk/lib/ffi/c_type.dart
index f6b7d8c..cb9d386 100644
--- a/sdk/lib/ffi/c_type.dart
+++ b/sdk/lib/ffi/c_type.dart
@@ -24,19 +24,19 @@
 @AbiSpecificIntegerMapping({
   Abi.androidArm: Uint8(),
   Abi.androidArm64: Uint8(),
-  Abi.androidIA32: Uint8(),
-  Abi.androidX64: Uint8(),
-  Abi.fuchsiaArm64: Int8(),
+  Abi.androidIA32: Int8(),
+  Abi.androidX64: Int8(),
+  Abi.fuchsiaArm64: Uint8(),
   Abi.fuchsiaX64: Int8(),
-  Abi.iosArm: Uint8(),
+  Abi.iosArm: Int8(),
   Abi.iosArm64: Int8(),
   Abi.iosX64: Int8(),
   Abi.linuxArm: Uint8(),
-  Abi.linuxArm64: Int8(),
+  Abi.linuxArm64: Uint8(),
   Abi.linuxIA32: Int8(),
   Abi.linuxX64: Int8(),
-  Abi.linuxRiscv32: Int8(),
-  Abi.linuxRiscv64: Int8(),
+  Abi.linuxRiscv32: Uint8(),
+  Abi.linuxRiscv64: Uint8(),
   Abi.macosArm64: Int8(),
   Abi.macosX64: Int8(),
   Abi.windowsArm64: Int8(),
diff --git a/tools/VERSION b/tools/VERSION
index c15e757..6c0f1d1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 249
+PRERELEASE 250
 PRERELEASE_PATCH 0
\ No newline at end of file