Version 2.17.0-267.0.dev

Merge commit '471fcee0795acfa9c20b8e980ac7db9cd8d336bc' into 'dev'
diff --git a/DEPS b/DEPS
index c8310ef..fa7dad3 100644
--- a/DEPS
+++ b/DEPS
@@ -176,7 +176,7 @@
   "webkit_inspection_protocol_rev": "dd6fb5d8b536e19cedb384d0bbf1f5631923f1e8",
   "yaml_edit_rev": "4fadb43801b07f90b3f0c6065dbce4efc6d8d55e",
   "yaml_rev": "ad0779d1baa25c6b10a192d080efc45de02b6a32",
-  "zlib_rev": "bf44340d1b6be1af8950bbdf664fec0cf5a831cc",
+  "zlib_rev": "faff052b6b6edcd6dd548513fe44ac0941427bf0",
   "crashpad_rev": "bf327d8ceb6a669607b0dbab5a83a275d03f99ed",
   "minichromium_rev": "8d641e30a8b12088649606b912c2bc4947419ccc",
   "googletest_rev": "f854f1d27488996dc8a6db3c9453f80b02585e12",
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor/message_grouper.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor/message_grouper.dart
index 382dd81..0c03646 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor/message_grouper.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor/message_grouper.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
+import 'dart:math' as math;
 import 'dart:typed_data';
 
 /// Collects messages from an input stream of bytes.
@@ -19,16 +20,24 @@
   /// If reading raw data, buffer for the data.
   _FixedBuffer? _messageBuffer;
 
-  late StreamController<Uint8List> _messageStreamController =
+  late final StreamController<Uint8List> _messageStreamController =
       new StreamController<Uint8List>(onCancel: () {
     _inputStreamSubscription.cancel();
   });
+
   Stream<Uint8List> get messageStream => _messageStreamController.stream;
 
   MessageGrouper(Stream<List<int>> inputStream) {
     _inputStreamSubscription = inputStream.listen(_handleBytes, onDone: cancel);
   }
 
+  /// Stop listening to the input stream for further updates, and close the
+  /// output stream.
+  void cancel() {
+    _inputStreamSubscription.cancel();
+    _messageStreamController.close();
+  }
+
   void _handleBytes(List<int> bytes, [int offset = 0]) {
     final _FixedBuffer? messageBuffer = _messageBuffer;
     if (messageBuffer == null) {
@@ -51,9 +60,7 @@
       }
     } else {
       // Read the data from `bytes`.
-      while (offset < bytes.length && !messageBuffer.isReady) {
-        messageBuffer.addByte(bytes[offset++]);
-      }
+      offset += messageBuffer.addBytes(bytes, offset);
 
       // If we completed a message, add it to the output stream.
       if (messageBuffer.isReady) {
@@ -64,13 +71,6 @@
       }
     }
   }
-
-  /// Stop listening to the input stream for further updates, and close the
-  /// output stream.
-  void cancel() {
-    _inputStreamSubscription.cancel();
-    _messageStreamController.close();
-  }
 }
 
 /// A buffer of fixed length.
@@ -91,6 +91,15 @@
     bytes[_offset++] = byte;
   }
 
+  /// Consume at most as many bytes from [source] as required by fill [bytes].
+  /// Return the number of consumed bytes.
+  int addBytes(List<int> source, int offset) {
+    int toConsume = math.min(source.length - offset, bytes.length - _offset);
+    bytes.setRange(_offset, _offset + toConsume, source, offset);
+    _offset += toConsume;
+    return toConsume;
+  }
+
   /// Reset the number of added bytes to zero.
   void reset() {
     _offset = 0;
diff --git a/pkg/analysis_server/lib/src/lsp/channel/lsp_byte_stream_channel.dart b/pkg/analysis_server/lib/src/lsp/channel/lsp_byte_stream_channel.dart
index a86e794..506a745 100644
--- a/pkg/analysis_server/lib/src/lsp/channel/lsp_byte_stream_channel.dart
+++ b/pkg/analysis_server/lib/src/lsp/channel/lsp_byte_stream_channel.dart
@@ -48,9 +48,9 @@
   }
 
   @override
-  void listen(void Function(Message message) onMessage,
+  StreamSubscription<void> listen(void Function(Message message) onMessage,
       {Function? onError, void Function()? onDone}) {
-    _input.transform(LspPacketTransformer()).listen(
+    return _input.transform(LspPacketTransformer()).listen(
       (String data) => _readMessage(data, onMessage),
       onError: onError,
       onDone: () {
diff --git a/pkg/analysis_server/lib/src/lsp/channel/lsp_channel.dart b/pkg/analysis_server/lib/src/lsp/channel/lsp_channel.dart
index 8d488b6..d6fa717 100644
--- a/pkg/analysis_server/lib/src/lsp/channel/lsp_channel.dart
+++ b/pkg/analysis_server/lib/src/lsp/channel/lsp_channel.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.
 
+import 'dart:async';
+
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
 
@@ -20,7 +22,7 @@
   /// the socket, invoke the [onError] function. If the socket is closed by the
   /// client, invoke the [onDone] function.
   /// Only one listener is allowed per channel.
-  void listen(void Function(Message message) onMessage,
+  StreamSubscription<void> listen(void Function(Message message) onMessage,
       {Function onError, void Function() onDone});
 
   /// Send the given [notification] to the client.
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index fed7a76..8ceaad2 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -61,108 +61,131 @@
     final triggerCharacter = params.context?.triggerCharacter;
     final pos = params.position;
     final path = pathOfDoc(params.textDocument);
-    final unit = await path.mapResult(requireResolvedUnit);
 
-    final lineInfo = await unit.map(
-      // If we don't have a unit, we can still try to obtain the line info from
-      // the server (this could be because the file is non-Dart, such as YAML or
-      // another handled by a plugin).
-      (error) => path.mapResult(getLineInfo),
-      (unit) => success(unit.lineInfo),
-    );
-    final offset =
-        await lineInfo.mapResult((lineInfo) => toOffset(lineInfo, pos));
-
-    return offset.mapResult((offset) async {
-      Future<ErrorOr<CompletionList>>? serverResultsFuture;
-      final pathContext = server.resourceProvider.pathContext;
-      final fileExtension = pathContext.extension(path.result);
-
-      final maxResults = server.clientConfiguration
-          .forResource(path.result)
-          .maxCompletionItems;
-
-      CompletionPerformance? completionPerformance;
-      if (fileExtension == '.dart' && !unit.isError) {
-        final result = unit.result;
-        var performanceOperation = OperationPerformanceImpl('<root>');
-        completionPerformance = CompletionPerformance(
-          operation: performanceOperation,
-          path: result.path,
-          content: result.content,
-          offset: offset,
-        );
-        server.performanceStats.completion.add(completionPerformance);
-
-        serverResultsFuture = _getServerDartItems(
-          clientCapabilities,
-          result,
-          completionPerformance,
-          performanceOperation,
-          offset,
-          triggerCharacter,
-          token,
-          maxResults: maxResults,
-        );
-      } else if (fileExtension == '.yaml') {
-        YamlCompletionGenerator? generator;
-        if (file_paths.isAnalysisOptionsYaml(pathContext, path.result)) {
-          generator = AnalysisOptionsGenerator(server.resourceProvider);
-        } else if (file_paths.isFixDataYaml(pathContext, path.result)) {
-          generator = FixDataGenerator(server.resourceProvider);
-        } else if (file_paths.isPubspecYaml(pathContext, path.result)) {
-          generator = PubspecGenerator(
-              server.resourceProvider, server.pubPackageService);
-        }
-        if (generator != null) {
-          serverResultsFuture = _getServerYamlItems(
-            generator,
-            clientCapabilities,
-            path.result,
-            lineInfo.result,
-            offset,
-            token,
-          );
-        }
-      }
-
-      serverResultsFuture ??=
-          Future.value(success(CompletionList(isIncomplete: false, items: [])));
-
-      final pluginResultsFuture = _getPluginResults(
-          clientCapabilities, lineInfo.result, path.result, offset);
-
-      // Await both server + plugin results together to allow async/IO to
-      // overlap.
-      final serverAndPluginResults =
-          await Future.wait([serverResultsFuture, pluginResultsFuture]);
-      final serverResults = serverAndPluginResults[0];
-      final pluginResults = serverAndPluginResults[1];
-
-      if (serverResults.isError) return serverResults;
-      if (pluginResults.isError) return pluginResults;
-
-      final untruncatedItems = serverResults.result.items
-          .followedBy(pluginResults.result.items)
-          .toList();
-
-      final truncatedItems = untruncatedItems.length > maxResults
-          ? (untruncatedItems..sort(sortTextComparer)).sublist(0, maxResults)
-          : untruncatedItems;
-
-      // If we're tracing performance (only Dart), record the number of results
-      // after truncation.
-      completionPerformance?.transmittedSuggestionCount = truncatedItems.length;
-
-      return success(CompletionList(
-        // If any set of the results is incomplete, the whole batch must be
-        // marked as such.
-        isIncomplete: serverResults.result.isIncomplete ||
-            pluginResults.result.isIncomplete ||
-            truncatedItems.length != untruncatedItems.length,
-        items: truncatedItems,
-      ));
+    // IMPORTANT:
+    // This handler is frequently called while the user is typing, which means
+    // during any `await` there is a good chance of the file contents being
+    // updated, but we must return results consistent with the file at the time
+    // this request started so that the client can compensate for any typing
+    // in the meantime.
+    //
+    // To do this, tell the server to lock requests until we have a resolved
+    // unit and LineInfo.
+    late ErrorOr<LineInfo> lineInfo;
+    late ErrorOr<ResolvedUnitResult> unit;
+    await server.lockRequestsWhile(() async {
+      unit = await path.mapResult(requireResolvedUnit);
+      lineInfo = await unit.map(
+        // If we don't have a unit, we can still try to obtain the line info from
+        // the server (this could be because the file is non-Dart, such as YAML or
+        // another handled by a plugin).
+        (error) => path.mapResult(getLineInfo),
+        (unit) => success(unit.lineInfo),
+      );
     });
+
+    if (token.isCancellationRequested) {
+      return cancelled();
+    }
+
+    // Map the offset, propagating the previous failure if we didn't have a
+    // valid LineInfo.
+    final offsetResult = !lineInfo.isError
+        ? toOffset(lineInfo.result, pos)
+        : failure<int>(lineInfo);
+
+    if (offsetResult.isError) {
+      return failure(offsetResult);
+    }
+    final offset = offsetResult.result;
+
+    Future<ErrorOr<CompletionList>>? serverResultsFuture;
+    final pathContext = server.resourceProvider.pathContext;
+    final fileExtension = pathContext.extension(path.result);
+
+    final maxResults =
+        server.clientConfiguration.forResource(path.result).maxCompletionItems;
+
+    CompletionPerformance? completionPerformance;
+    if (fileExtension == '.dart' && !unit.isError) {
+      final result = unit.result;
+      var performanceOperation = OperationPerformanceImpl('<root>');
+      completionPerformance = CompletionPerformance(
+        operation: performanceOperation,
+        path: result.path,
+        content: result.content,
+        offset: offset,
+      );
+      server.performanceStats.completion.add(completionPerformance);
+
+      serverResultsFuture = _getServerDartItems(
+        clientCapabilities,
+        unit.result,
+        completionPerformance,
+        performanceOperation,
+        offset,
+        triggerCharacter,
+        token,
+        maxResults: maxResults,
+      );
+    } else if (fileExtension == '.yaml') {
+      YamlCompletionGenerator? generator;
+      if (file_paths.isAnalysisOptionsYaml(pathContext, path.result)) {
+        generator = AnalysisOptionsGenerator(server.resourceProvider);
+      } else if (file_paths.isFixDataYaml(pathContext, path.result)) {
+        generator = FixDataGenerator(server.resourceProvider);
+      } else if (file_paths.isPubspecYaml(pathContext, path.result)) {
+        generator =
+            PubspecGenerator(server.resourceProvider, server.pubPackageService);
+      }
+      if (generator != null) {
+        serverResultsFuture = _getServerYamlItems(
+          generator,
+          clientCapabilities,
+          path.result,
+          lineInfo.result,
+          offset,
+          token,
+        );
+      }
+    }
+
+    serverResultsFuture ??=
+        Future.value(success(CompletionList(isIncomplete: false, items: [])));
+
+    final pluginResultsFuture = _getPluginResults(
+        clientCapabilities, lineInfo.result, path.result, offset);
+
+    // Await both server + plugin results together to allow async/IO to
+    // overlap.
+    final serverAndPluginResults =
+        await Future.wait([serverResultsFuture, pluginResultsFuture]);
+    final serverResults = serverAndPluginResults[0];
+    final pluginResults = serverAndPluginResults[1];
+
+    if (serverResults.isError) return serverResults;
+    if (pluginResults.isError) return pluginResults;
+
+    final untruncatedItems = serverResults.result.items
+        .followedBy(pluginResults.result.items)
+        .toList();
+
+    final truncatedItems = untruncatedItems.length > maxResults
+        ? (untruncatedItems..sort(sortTextComparer)).sublist(0, maxResults)
+        : untruncatedItems;
+
+    // If we're tracing performance (only Dart), record the number of results
+    // after truncation.
+    completionPerformance?.transmittedSuggestionCount = truncatedItems.length;
+
+    return success(CompletionList(
+      // If any set of the results is incomplete, the whole batch must be
+      // marked as such.
+      isIncomplete: serverResults.result.isIncomplete ||
+          pluginResults.result.isIncomplete ||
+          truncatedItems.length != untruncatedItems.length,
+      items: truncatedItems,
+    ));
   }
 
   /// Build a list of existing imports so we can filter out any suggestions
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 12284b0..6674c4c 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -118,6 +118,9 @@
   @visibleForTesting
   int contextBuilds = 0;
 
+  /// The subscription to the stream of incoming messages from the client.
+  late StreamSubscription<void> _channelSubscription;
+
   /// Initialize a newly created server to send and receive messages to the
   /// given [channel].
   LspAnalysisServer(
@@ -155,7 +158,8 @@
     analysisDriverScheduler.status.listen(sendStatusNotification);
     analysisDriverScheduler.start();
 
-    channel.listen(handleMessage, onDone: done, onError: socketError);
+    _channelSubscription =
+        channel.listen(handleMessage, onDone: done, onError: socketError);
     _pluginChangeSubscription =
         pluginManager.pluginsChanged.listen((_) => _onPluginsChanged());
   }
@@ -382,6 +386,36 @@
     }, socketError);
   }
 
+  /// Locks the server from processing incoming messages until [operation]
+  /// completes.
+  ///
+  /// This can be used to obtain analysis results/resolved units consistent with
+  /// the state of a file at the time this method was called, preventing
+  /// changes by incoming file modifications.
+  ///
+  /// The contents of [operation] should be kept as short as possible and since
+  /// cancellation requests will also be blocked for the duration of this
+  /// operation, handles should generally check the cancellation flag
+  /// immediately after this function returns.
+  FutureOr<T> lockRequestsWhile<T>(FutureOr<T> Function() operation) async {
+    final completer = Completer<void>();
+
+    // Pause handling incoming messages until `operation` completes.
+    //
+    // If this method is called multiple times, the pauses will stack, meaning
+    // the subscription will not resume until all operations complete.
+    _channelSubscription.pause(completer.future);
+
+    try {
+      // `await` here is imported to ensure `finally` doesn't execute until
+      // `operation()` completes (`whenComplete` is not available on
+      // `FutureOr`).
+      return await operation();
+    } finally {
+      completer.complete();
+    }
+  }
+
   /// Logs the error on the client using window/logMessage.
   void logErrorToClient(String message) {
     channel.sendNotification(NotificationMessage(
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
index daa7ef1..e2ed9a99 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
@@ -52,23 +52,26 @@
       }
     }
 
-    var enclosingClass = constructor.thisOrAncestorOfType<ClassDeclaration>();
+    ClassElement? enclosingClass;
+    var constructorParent = constructor.parent;
+    if (constructorParent is ClassDeclaration) {
+      enclosingClass = constructorParent.declaredElement;
+    } else if (constructorParent is EnumDeclaration) {
+      enclosingClass = constructorParent.declaredElement;
+    } else {
+      return;
+    }
     if (enclosingClass == null) {
       return;
     }
 
     // Add suggestions for fields that are not already referenced.
-    for (var member in enclosingClass.members) {
-      if (member is FieldDeclaration && !member.isStatic) {
-        for (var variable in member.fields.variables) {
-          var field = variable.name.staticElement;
-          if (field is FieldElement) {
-            var fieldName = field.name;
-            if (fieldName.isNotEmpty) {
-              if (!referencedFields.contains(fieldName)) {
-                builder.suggestFieldFormalParameter(field);
-              }
-            }
+    for (var field in enclosingClass.fields) {
+      if (!field.isSynthetic && !field.isEnumConstant && !field.isStatic) {
+        var fieldName = field.name;
+        if (fieldName.isNotEmpty) {
+          if (!referencedFields.contains(fieldName)) {
+            builder.suggestFieldFormalParameter(field);
           }
         }
       }
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index a9f8b35..d2f7ccd 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -707,9 +707,8 @@
 CompileTimeErrorCode.NON_BOOL_OPERAND:
   status: needsEvaluation
 CompileTimeErrorCode.NON_CONST_GENERATIVE_ENUM_CONSTRUCTOR:
-  status: needsFix
+  status: hasFix
   since: 2.17
-  issue: https://github.com/dart-lang/sdk/issues/48479
 CompileTimeErrorCode.NON_CONST_MAP_AS_EXPRESSION_STATEMENT:
   status: needsEvaluation
 CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR:
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index a4e4594a..f70b314 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -995,6 +995,9 @@
     CompileTimeErrorCode.NON_BOOL_CONDITION: [
       AddNeNull.newInstance,
     ],
+    CompileTimeErrorCode.NON_CONST_GENERATIVE_ENUM_CONSTRUCTOR: [
+      AddConst.newInstance,
+    ],
     CompileTimeErrorCode.NON_TYPE_AS_TYPE_ARGUMENT: [
       CreateClass.newInstance,
       CreateMixin.newInstance,
diff --git a/pkg/analysis_server/test/mocks_lsp.dart b/pkg/analysis_server/test/mocks_lsp.dart
index 6c83f82..3888981 100644
--- a/pkg/analysis_server/test/mocks_lsp.dart
+++ b/pkg/analysis_server/test/mocks_lsp.dart
@@ -75,9 +75,10 @@
   }
 
   @override
-  void listen(void Function(lsp.Message message) onMessage,
+  StreamSubscription<void> listen(void Function(lsp.Message message) onMessage,
       {Function? onError, void Function()? onDone}) {
-    _clientToServer.stream.listen(onMessage, onError: onError, onDone: onDone);
+    return _clientToServer.stream
+        .listen(onMessage, onError: onError, onDone: onDone);
   }
 
   @override
diff --git a/pkg/analysis_server/test/services/completion/dart/location/field_formal_parameter_test.dart b/pkg/analysis_server/test/services/completion/dart/location/field_formal_parameter_test.dart
index 41f4004..68b4c68 100644
--- a/pkg/analysis_server/test/services/completion/dart/location/field_formal_parameter_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/location/field_formal_parameter_test.dart
@@ -30,66 +30,63 @@
 }
 
 mixin SuperFormalParameterTestCases on AbstractCompletionDriverTest {
-  /// https://github.com/dart-lang/sdk/issues/39028
-  Future<void> test_mixin_constructor() async {
-    var response = await getTestCodeSuggestions('''
-mixin M {
-  var field = 0;
-  M(this.^);
-}
-''');
-
-    check(response).suggestions.isEmpty;
+  Future<void> test_class_replacement_left() async {
+    _checkContainers(
+      declarations: 'var field = 0;',
+      constructorParameters: 'this.f^',
+      validator: (response) {
+        check(response)
+          ..hasReplacement(left: 1)
+          ..suggestions.matchesInAnyOrder([
+            (suggestion) => suggestion
+              ..completion.isEqualTo('field')
+              ..isField
+              ..returnType.isEqualTo('int'),
+          ]);
+      },
+    );
   }
 
-  Future<void> test_replacement_left() async {
-    var response = await getTestCodeSuggestions('''
-class A {
-  var field = 0;
-  A(this.f^);
-}
-''');
-
-    check(response)
-      ..hasReplacement(left: 1)
-      ..suggestions.matchesInAnyOrder([
-        (suggestion) => suggestion
-          ..completion.isEqualTo('field')
-          ..isField
-          ..returnType.isEqualTo('int'),
-      ]);
+  Future<void> test_class_replacement_right() async {
+    _checkContainers(
+      declarations: 'var field = 0;',
+      constructorParameters: 'this.^f',
+      validator: (response) {
+        check(response)
+          ..hasReplacement(right: 1)
+          ..suggestions.matchesInAnyOrder([
+            (suggestion) => suggestion
+              ..completion.isEqualTo('field')
+              ..isField
+              ..returnType.isEqualTo('int'),
+          ]);
+      },
+    );
   }
 
-  Future<void> test_replacement_right() async {
+  Future<void> test_class_suggestions_instanceFields_local() async {
     var response = await getTestCodeSuggestions('''
 class A {
-  var field = 0;
-  A(this.^f);
-}
-''');
-
-    check(response)
-      ..hasReplacement(right: 1)
-      ..suggestions.matchesInAnyOrder([
-        (suggestion) => suggestion
-          ..completion.isEqualTo('field')
-          ..isField
-          ..returnType.isEqualTo('int'),
-      ]);
-  }
-
-  Future<void> test_suggestions_onlyLocal() async {
-    var response = await getTestCodeSuggestions('''
-class A {
+  static final superStatic = 0;
   var inherited = 0;
+
+  void superMethod() {}
+  int get superGetter => 0;
+  void superSetter(int _) {}
 }
 
 class B extends A {
+  static final thisStatic = 0;
+
   var first = 0;
   var second = 1.2;
+
   B(this.^);
-  B.constructor() {}
-  void method() {}
+  B.otherConstructor() {}
+
+  void thisMethod() {}
+  int get thisGetter => 0;
+  void thisSetter(int _) {}
 }
 ''');
 
@@ -107,12 +104,56 @@
       ]);
   }
 
-  Future<void> test_suggestions_onlyNotSpecified_optionalNamed() async {
+  Future<void> test_class_suggestions_onlyNotSpecified_optionalNamed() async {
+    _checkContainers(
+      declarations: 'final int x; final int y;',
+      constructorParameters: '{this.x, this.^}',
+      validator: (response) {
+        check(response)
+          ..hasEmptyReplacement()
+          ..suggestions.matchesInAnyOrder([
+            (suggestion) => suggestion
+              ..completion.isEqualTo('y')
+              ..isField
+              ..returnType.isEqualTo('int'),
+          ]);
+      },
+    );
+  }
+
+  Future<void>
+      test_class_suggestions_onlyNotSpecified_requiredPositional() async {
+    _checkContainers(
+      declarations: 'final int x; final int y;',
+      constructorParameters: 'this.x, this.^',
+      validator: (response) {
+        check(response)
+          ..hasEmptyReplacement()
+          ..suggestions.matchesInAnyOrder([
+            (suggestion) => suggestion
+              ..completion.isEqualTo('y')
+              ..isField
+              ..returnType.isEqualTo('int'),
+          ]);
+      },
+    );
+  }
+
+  Future<void> test_enum_suggestions_instanceFields() async {
     var response = await getTestCodeSuggestions('''
-class Point {
-  final int x;
-  final int y;
-  Point({this.x, this.^});
+enum E {
+  v();
+
+  static final zero = 0;
+  final int first;
+  final double second;
+
+  E(this.^);
+  E.otherConstructor();
+
+  void myMethod() {}
+  int get myGetter => 0;
+  void mySetter(int _) {}
 }
 ''');
 
@@ -120,28 +161,53 @@
       ..hasEmptyReplacement()
       ..suggestions.matchesInAnyOrder([
         (suggestion) => suggestion
-          ..completion.isEqualTo('y')
+          ..completion.isEqualTo('first')
           ..isField
           ..returnType.isEqualTo('int'),
+        (suggestion) => suggestion
+          ..completion.isEqualTo('second')
+          ..isField
+          ..returnType.isEqualTo('double'),
       ]);
   }
 
-  Future<void> test_suggestions_onlyNotSpecified_requiredPositional() async {
+  /// https://github.com/dart-lang/sdk/issues/39028
+  Future<void> test_mixin_constructor() async {
     var response = await getTestCodeSuggestions('''
-class Point {
-  final int x;
-  final int y;
-  Point(this.x, this.^);
+mixin M {
+  var field = 0;
+  M(this.^);
 }
 ''');
 
-    check(response)
-      ..hasEmptyReplacement()
-      ..suggestions.matchesInAnyOrder([
-        (suggestion) => suggestion
-          ..completion.isEqualTo('y')
-          ..isField
-          ..returnType.isEqualTo('int'),
-      ]);
+    check(response).suggestions.isEmpty;
+  }
+
+  Future<void> _checkContainers({
+    required String declarations,
+    required String constructorParameters,
+    required void Function(CompletionResponseForTesting response) validator,
+  }) async {
+    // class
+    {
+      var response = await getTestCodeSuggestions('''
+class A {
+  $declarations
+  A($constructorParameters);
+}
+''');
+      validator(response);
+    }
+    // enum
+    {
+      var response = await getTestCodeSuggestions('''
+enum E {
+  v;
+  $declarations
+  E($constructorParameters);
+}
+''');
+      validator(response);
+    }
   }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
index c2f2e4a..4b81627 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
@@ -11,6 +11,7 @@
 
 void main() {
   defineReflectiveSuite(() {
+    defineReflectiveTests(AddConst_NonConstGenerativeEnumConstructorTest);
     defineReflectiveTests(AddConst_PreferConstConstructorsInImmutablesBulkTest);
     defineReflectiveTests(AddConst_PreferConstConstructorsInImmutablesTest);
     defineReflectiveTests(AddConst_PreferConstConstructorsBulkTest);
@@ -22,6 +23,42 @@
 }
 
 @reflectiveTest
+class AddConst_NonConstGenerativeEnumConstructorTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.ADD_CONST;
+
+  Future<void> test_named() async {
+    await resolveTestCode('''
+enum E {
+  v.named();
+  E.named();
+}
+''');
+    await assertHasFix('''
+enum E {
+  v.named();
+  const E.named();
+}
+''');
+  }
+
+  Future<void> test_unnamed() async {
+    await resolveTestCode('''
+enum E {
+  v;
+  E();
+}
+''');
+    await assertHasFix('''
+enum E {
+  v;
+  const E();
+}
+''');
+  }
+}
+
+@reflectiveTest
 class AddConst_PreferConstConstructorsBulkTest extends BulkFixProcessorTest {
   @override
   String get lintCode => LintNames.prefer_const_constructors;
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 627f80a..ce089032 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -1617,7 +1617,7 @@
       return super.evaluationResult;
     }
 
-    var superConstructorParameter = this.superConstructorParameter;
+    var superConstructorParameter = this.superConstructorParameter?.declaration;
     if (superConstructorParameter is ParameterElementImpl) {
       return superConstructorParameter.evaluationResult;
     }
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index a151c37..ffe0eb4 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -1962,8 +1962,22 @@
     }
 
     if (hasVisibleForOverriding) {
-      _errorReporter.reportErrorForNode(
-          HintCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER, node, [name]);
+      var parent = node.parent;
+      var validOverride = false;
+      if (parent is MethodInvocation && parent.target is SuperExpression ||
+          parent is PropertyAccess && parent.target is SuperExpression) {
+        var methodDeclaration =
+            grandparent?.thisOrAncestorOfType<MethodDeclaration>();
+        if (methodDeclaration?.name.token.value() == identifier.token.value()) {
+          validOverride = true;
+        }
+      }
+      if (!validOverride) {
+        _errorReporter.reportErrorForNode(
+            HintCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER,
+            node,
+            [name]);
+      }
     }
   }
 
diff --git a/pkg/analyzer/test/src/diagnostics/const_constructor_param_type_mismatch_test.dart b/pkg/analyzer/test/src/diagnostics/const_constructor_param_type_mismatch_test.dart
index 67cdfa0..29e89a5 100644
--- a/pkg/analyzer/test/src/diagnostics/const_constructor_param_type_mismatch_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/const_constructor_param_type_mismatch_test.dart
@@ -336,10 +336,24 @@
 }
 
 class B extends A {
-  static const f = B();
-
   const B({super.a});
 }
+
+const b = const B();
+''');
+  }
+
+  test_superFormalParameter_inherited_generic() async {
+    await assertNoErrorsInCode(r'''
+class A<T> {
+  const A({int a = 0});
+}
+
+class B extends A<int> {
+  const B({super.a});
+}
+
+const b = const B();
 ''');
   }
 
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_overriding_member_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_overriding_member_test.dart
index a5d17bd..d4e5892 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_overriding_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_overriding_member_test.dart
@@ -88,9 +88,125 @@
 ''');
   }
 
+  test_getter() async {
+    newFile2('$testPackageLibPath/a.dart', '''
+import 'package:meta/meta.dart';
+
+class A {
+  @visibleForOverriding
+  int get g => 0;
+}
+''');
+
+    await assertErrorsInCode('''
+import 'a.dart';
+
+class B {
+  int m(A a) {
+    return a.g;
+  }
+}
+''', [
+      error(HintCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER, 56, 1),
+    ]);
+  }
+
+  test_overriding_getter() async {
+    newFile2('$testPackageLibPath/a.dart', '''
+import 'package:meta/meta.dart';
+
+class A {
+  @visibleForOverriding
+  int get g => 0;
+}
+''');
+
+    await assertErrorsInCode('''
+import 'a.dart';
+
+class B extends A {
+  @override
+  int get g => super.g + 1;
+
+  int get x => super.g + 1;
+}
+''', [
+      error(HintCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER, 100, 1),
+    ]);
+  }
+
+  test_overriding_methodInvocation() async {
+    newFile2('$testPackageLibPath/a.dart', '''
+import 'package:meta/meta.dart';
+
+class A {
+  @visibleForOverriding
+  void m() {}
+}
+''');
+
+    await assertErrorsInCode('''
+import 'a.dart';
+
+class B extends A {
+  @override
+  void m() => super.m();
+
+  void x() => super.m();
+}
+''', [
+      error(HintCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER, 96, 1),
+    ]);
+  }
+
+  test_overriding_operator() async {
+    newFile2('$testPackageLibPath/a.dart', '''
+import 'package:meta/meta.dart';
+
+class A {
+  @visibleForOverriding
+  operator >(A other) => true;
+}
+''');
+
+    await assertNoErrorsInCode('''
+import 'a.dart';
+
+class B extends A {
+  @override
+  operator >(A other) => super > other;
+}
+''');
+  }
+
+  test_overriding_setter() async {
+    newFile2('$testPackageLibPath/a.dart', '''
+import 'package:meta/meta.dart';
+
+class A {
+  @visibleForOverriding
+  set s(int i) {}
+}
+''');
+
+    await assertErrorsInCode('''
+import 'a.dart';
+
+class B extends A {
+  @override
+  set s(int i) => super.s = i;
+
+  set x(int i) => super.s = i;
+}
+''', [
+      error(HintCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER, 106, 1),
+    ]);
+  }
+
   test_sameLibrary() async {
     await assertNoErrorsInCode('''
 import 'package:meta/meta.dart';
+
 class Parent {
   @visibleForOverriding
   void foo() {}
@@ -103,4 +219,27 @@
 }
 ''');
   }
+
+  test_setter() async {
+    newFile2('$testPackageLibPath/a.dart', '''
+import 'package:meta/meta.dart';
+
+class A {
+  @visibleForOverriding
+  set s(int i) {}
+}
+''');
+
+    await assertErrorsInCode('''
+import 'a.dart';
+
+class B {
+  void m(A a) {
+    a.s = 1;
+  }
+}
+''', [
+      error(HintCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER, 50, 1),
+    ]);
+  }
 }
diff --git a/pkg/dds/lib/devtools_server.dart b/pkg/dds/lib/devtools_server.dart
index 5841606..bd1e001 100644
--- a/pkg/dds/lib/devtools_server.dart
+++ b/pkg/dds/lib/devtools_server.dart
@@ -7,6 +7,7 @@
 
 import 'package:args/args.dart';
 import 'package:browser_launcher/browser_launcher.dart';
+import 'package:devtools_shared/devtools_shared.dart';
 import 'package:http_multi_server/http_multi_server.dart';
 import 'package:path/path.dart' as path;
 import 'package:shelf/shelf.dart' as shelf;
@@ -291,7 +292,7 @@
     if (launchBrowser) {
       if (serviceProtocolUri != null) {
         serviceProtocolUri =
-            _normalizeVmServiceUri(serviceProtocolUri).toString();
+            normalizeVmServiceUri(serviceProtocolUri).toString();
       }
 
       final queryParameters = {
@@ -674,23 +675,4 @@
     };
     return uri.hasPort && tunneledPorts.contains(uri.port);
   }
-
-  // TODO(https://github.com/flutter/devtools/issues/3571): move to devtools_shared.
-  // Note: please keep this copy of normalizeVmServiceUri() in sync with the one
-  // in devtools_app.
-  Uri? _normalizeVmServiceUri(String value) {
-    value = value.trim();
-
-    // Cleanup encoded urls likely copied from the uri of an existing running
-    // DevTools app.
-    if (value.contains('%3A%2F%2F')) {
-      value = Uri.decodeFull(value);
-    }
-    final uri = Uri.parse(value.trim()).removeFragment();
-    if (!uri.isAbsolute) {
-      return null;
-    }
-    if (uri.path.endsWith('/')) return uri;
-    return uri.replace(path: uri.path);
-  }
 }
diff --git a/pkg/dds/lib/src/devtools/memory_profile.dart b/pkg/dds/lib/src/devtools/memory_profile.dart
index 03fe5c1..604346e 100644
--- a/pkg/dds/lib/src/devtools/memory_profile.dart
+++ b/pkg/dds/lib/src/devtools/memory_profile.dart
@@ -12,8 +12,6 @@
 import 'package:devtools_shared/devtools_shared.dart';
 import 'package:vm_service/vm_service.dart';
 
-import 'service_registrations.dart' as service_registrations;
-
 class MemoryProfile {
   MemoryProfile(this.service, String profileFilename, this._verboseMode) {
     onConnectionClosed.listen(_handleConnectionStop);
@@ -77,7 +75,7 @@
 
   Future<Response?> getAdbMemoryInfo() async {
     return await callService(
-      service_registrations.flutterMemory.service,
+      flutterMemory.service,
       isolateId: _selectedIsolate.id,
     );
   }
@@ -221,7 +219,7 @@
   /// @throws Exception if no 'FlutterView'.
   Future<String?> getFlutterViewId(IsolateRef selectedIsolate) async {
     final flutterViewListResponse = await service!.callServiceExtension(
-      service_registrations.flutterListViews,
+      flutterListViews,
       isolateId: selectedIsolate.id,
     );
     final List<dynamic> views =
@@ -253,7 +251,7 @@
     final viewId = await getFlutterViewId(selectedIsolate);
 
     return await service!.callServiceExtension(
-      service_registrations.flutterEngineRasterCache,
+      flutterEngineRasterCache,
       args: {'viewId': viewId},
       isolateId: selectedIsolate.id,
     );
diff --git a/pkg/dds/lib/src/devtools/service_registrations.dart b/pkg/dds/lib/src/devtools/service_registrations.dart
deleted file mode 100644
index 10b35ea..0000000
--- a/pkg/dds/lib/src/devtools/service_registrations.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-
-// TODO(https://github.com/flutter/devtools/issues/3571): move to devtools_shared.
-class RegisteredServiceDescription {
-  const RegisteredServiceDescription._({
-    required this.service,
-    required this.title,
-  });
-
-  final String service;
-  final String title;
-}
-
-/// Flutter memory service registered by Flutter Tools.
-///
-/// We call this service to get version information about the Flutter Android memory info
-/// using Android's ADB.
-const flutterMemory = RegisteredServiceDescription._(
-  service: 'flutterMemoryInfo',
-  title: 'Flutter Memory Info',
-);
-
-const flutterListViews = '_flutter.listViews';
-
-/// Flutter engine returns estimate how much memory is used by layer/picture raster
-/// cache entries in bytes.
-const flutterEngineRasterCache = '_flutter.estimateRasterCacheMemory';
diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml
index 68a6e019..5ad059d 100644
--- a/pkg/dds/pubspec.yaml
+++ b/pkg/dds/pubspec.yaml
@@ -16,7 +16,7 @@
   browser_launcher: ^1.0.0
   collection: ^1.15.0
   dds_service_extensions: ^1.3.0
-  devtools_shared: ^2.11.4
+  devtools_shared: ^2.12.1
   http_multi_server: ^3.0.0
   json_rpc_2: ^3.0.0
   meta: ^1.1.8
diff --git a/pkg/dev_compiler/lib/src/compiler/js_names.dart b/pkg/dev_compiler/lib/src/compiler/js_names.dart
index 9e95de7..f884331 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_names.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_names.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:collection';
 
 import '../js_ast/js_ast.dart';
@@ -34,7 +32,7 @@
   @override
   dynamic get sourceInformation => null;
   @override
-  set sourceInformation(Object obj) {}
+  set sourceInformation(Object? obj) {}
 
   TemporaryId(String name) : super(name);
 }
@@ -49,9 +47,8 @@
   final Identifier qualifier;
   final Expression name;
 
-  MaybeQualifiedId(this.qualifier, this.name) {
-    _expr = PropertyAccess(qualifier, name);
-  }
+  MaybeQualifiedId(this.qualifier, this.name)
+      : _expr = PropertyAccess(qualifier, name);
 
   /// Helper to create an [Identifier] from something that starts as a property.
   static Identifier identifier(LiteralString propertyName) =>
@@ -97,32 +94,32 @@
 /// `function` or `instanceof`, and their `name` field controls whether they
 /// refer to the same variable.
 class TemporaryNamer extends LocalNamer {
-  _FunctionScope _scope;
+  _FunctionScope? _scope;
 
   /// Listener to be notified when a name is selected (rename or not) for an
   /// `Identifier`.
   ///
   /// Can be `null` when there is no listener attached.
-  final NameListener _nameListener;
+  final NameListener? _nameListener;
 
   TemporaryNamer(Node node, [this._nameListener])
       : _scope = _RenameVisitor.build(node).rootScope;
 
   @override
   String getName(Identifier node) {
-    var name = _scope.renames[identifierKey(node)] ?? node.name;
+    var name = _scope!.renames[identifierKey(node)] ?? node.name;
     _nameListener?.nameSelected(node, name);
     return name;
   }
 
   @override
   void enterScope(Node node) {
-    _scope = _scope.childScopes[node];
+    _scope = _scope!.childScopes[node];
   }
 
   @override
   void leaveScope() {
-    _scope = _scope.parent;
+    _scope = _scope!.parent;
   }
 }
 
@@ -131,7 +128,7 @@
 /// We don't currently track ES6 block scopes.
 class _FunctionScope {
   /// The parent scope.
-  final _FunctionScope parent;
+  final _FunctionScope? parent;
 
   /// All names declared in this scope.
   final declared = HashSet<Object>();
@@ -157,7 +154,7 @@
 
   final _FunctionScope globalScope = _FunctionScope(null);
   final _FunctionScope rootScope = _FunctionScope(null);
-  _FunctionScope scope;
+  _FunctionScope? scope;
 
   _RenameVisitor.build(Node root) {
     scope = rootScope;
@@ -169,11 +166,11 @@
   @override
   void declare(Identifier node) {
     var id = identifierKey(node);
-    var notAlreadyDeclared = scope.declared.add(id);
+    var notAlreadyDeclared = scope!.declared.add(id);
     // Normal identifiers can be declared multiple times, because we don't
     // implement block scope yet. However temps should only be declared once.
     assert(notAlreadyDeclared || node is! TemporaryId);
-    _markUsed(node, id, scope);
+    _markUsed(node, id, scope!);
   }
 
   @override
@@ -196,12 +193,14 @@
   void _markUsed(Identifier node, Object id, _FunctionScope declScope) {
     // If it needs rename, we can't add it to the used name set yet, instead we
     // will record all scopes it is visible in.
-    Set<_FunctionScope> usedIn;
+    Set<_FunctionScope>? usedIn;
     var rename = declScope != globalScope && needsRename(node);
     if (rename) {
       usedIn = pendingRenames.putIfAbsent(id, () => HashSet());
     }
-    for (var s = scope, end = declScope.parent; s != end; s = s.parent) {
+    for (var s = scope, end = declScope.parent;
+        s != end && s != null;
+        s = s.parent) {
       if (usedIn != null) {
         usedIn.add(s);
       } else {
@@ -213,16 +212,16 @@
   @override
   void visitFunctionExpression(FunctionExpression node) {
     // Visit nested functions after all identifiers are declared.
-    scope.childScopes[node] = _FunctionScope(scope);
+    scope!.childScopes[node] = _FunctionScope(scope);
   }
 
   @override
   void visitClassExpression(ClassExpression node) {
-    scope.childScopes[node] = _FunctionScope(scope);
+    scope!.childScopes[node] = _FunctionScope(scope);
   }
 
   void _finishScopes() {
-    scope.childScopes.forEach((node, s) {
+    scope!.childScopes.forEach((node, s) {
       scope = s;
       if (node is FunctionExpression) {
         super.visitFunctionExpression(node);
@@ -230,7 +229,7 @@
         super.visitClassExpression(node as ClassExpression);
       }
       _finishScopes();
-      scope = scope.parent;
+      scope = scope!.parent;
     });
   }
 
@@ -435,16 +434,15 @@
   if (name.isEmpty) return r'$';
 
   // Escape any invalid characters
-  StringBuffer buffer;
+  StringBuffer? buffer;
   for (var i = 0; i < name.length; i++) {
     var ch = name[i];
     var needsEscape = ch == r'$' || invalidCharInIdentifier.hasMatch(ch);
-    if (needsEscape && buffer == null) {
-      buffer = StringBuffer(name.substring(0, i));
+    if (needsEscape) {
+      buffer ??= StringBuffer(name.substring(0, i));
     }
-    if (buffer != null) {
-      buffer.write(needsEscape ? '\$${ch.codeUnits.join("")}' : ch);
-    }
+
+    buffer?.write(needsEscape ? '\$${ch.codeUnits.join("")}' : ch);
   }
 
   var result = buffer != null ? '$buffer' : name;
diff --git a/pkg/dev_compiler/lib/src/compiler/js_utils.dart b/pkg/dev_compiler/lib/src/compiler/js_utils.dart
index e072a12..aaecf7f 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_utils.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_utils.dart
@@ -2,14 +2,12 @@
 // 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 '../js_ast/js_ast.dart';
 
 /// Simplify `(args) => (() => { ... })()` to `(args) => { ... }`.
 // TODO(jmesserly): find a better home for this function
 Fun simplifyPassThroughArrowFunCallBody(Fun fn) {
-  if (fn.body is Block && fn.body.statements.length == 1) {
+  if (fn.body.statements.length == 1) {
     var stat = fn.body.statements.single;
     if (stat is Return && stat.value is Call) {
       var call = stat.value as Call;
diff --git a/pkg/dev_compiler/lib/src/js_ast/builder.dart b/pkg/dev_compiler/lib/src/js_ast/builder.dart
index 5f0c23e..98c70eb 100644
--- a/pkg/dev_compiler/lib/src/js_ast/builder.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/builder.dart
@@ -2,17 +2,14 @@
 // 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.
 
-// ignore_for_file: library_prefixes
 // ignore_for_file: non_constant_identifier_names
 // ignore_for_file: omit_local_variable_types
-// ignore_for_file: prefer_single_quotes
-// ignore_for_file: unnecessary_brace_in_string_interps
 
 /// Utilities for building JS ASTs at runtime. Contains a builder class and a
 /// parser that parses part of the language.
 library js_ast.builder;
 
-import 'characters.dart' as charCodes;
+import 'characters.dart' as char_codes;
 import 'nodes.dart';
 import 'template.dart';
 
@@ -236,7 +233,7 @@
     // TODO(sra): Parse with extra validation to forbid `#` interpolation in
     // functions, as this leads to unanticipated capture of temporaries that are
     // reused after capture.
-    if (source.startsWith("throw ")) {
+    if (source.startsWith('throw ')) {
       return _findStatementTemplate(source);
     } else {
       return _findExpressionTemplate(source);
@@ -297,21 +294,21 @@
     int quoteRune = quote.codeUnitAt(0);
 
     for (int rune in value.runes) {
-      if (rune == charCodes.$BACKSLASH) {
+      if (rune == char_codes.$BACKSLASH) {
         ++otherEscapes;
-      } else if (rune == charCodes.$LF ||
-          rune == charCodes.$CR ||
-          rune == charCodes.$LS ||
-          rune == charCodes.$PS) {
+      } else if (rune == char_codes.$LF ||
+          rune == char_codes.$CR ||
+          rune == char_codes.$LS ||
+          rune == char_codes.$PS) {
         // Line terminators.
         ++otherEscapes;
-      } else if (rune == charCodes.$BS ||
-          rune == charCodes.$TAB ||
-          rune == charCodes.$VTAB ||
-          rune == charCodes.$FF) {
+      } else if (rune == char_codes.$BS ||
+          rune == char_codes.$TAB ||
+          rune == char_codes.$VTAB ||
+          rune == char_codes.$FF) {
         ++otherEscapes;
       } else if (rune == quoteRune ||
-          rune == charCodes.$$ && quoteRune == charCodes.$BACKPING) {
+          rune == char_codes.$$ && quoteRune == char_codes.$BACKPING) {
         ++otherEscapes;
       } else if (_isUnpairedSurrogate(rune)) {
         ++unpairedSurrogates;
@@ -330,8 +327,8 @@
         sb.write(escape);
         continue;
       }
-      if (rune == charCodes.$LS ||
-          rune == charCodes.$PS ||
+      if (rune == char_codes.$LS ||
+          rune == char_codes.$PS ||
           _isUnpairedSurrogate(rune)) {
         if (rune < 0x100) {
           sb.write(r'\x');
@@ -356,28 +353,28 @@
 
   static String? _irregularEscape(int code, String quote) {
     switch (code) {
-      case charCodes.$SQ:
+      case char_codes.$SQ:
         return quote == "'" ? r"\'" : "'";
-      case charCodes.$DQ:
+      case char_codes.$DQ:
         return quote == '"' ? r'\"' : '"';
-      case charCodes.$BACKPING:
+      case char_codes.$BACKPING:
         return quote == '`' ? r'\`' : '`';
-      case charCodes.$$:
+      case char_codes.$$:
         // Escape $ inside of template strings.
         return quote == '`' ? r'\$' : r'$';
-      case charCodes.$BACKSLASH:
+      case char_codes.$BACKSLASH:
         return r'\\';
-      case charCodes.$BS:
+      case char_codes.$BS:
         return r'\b';
-      case charCodes.$TAB:
+      case char_codes.$TAB:
         return r'\t';
-      case charCodes.$LF:
+      case char_codes.$LF:
         return r'\n';
-      case charCodes.$VTAB:
+      case char_codes.$VTAB:
         return r'\v';
-      case charCodes.$FF:
+      case char_codes.$FF:
         return r'\f';
-      case charCodes.$CR:
+      case char_codes.$CR:
         return r'\r';
     }
     return null;
@@ -450,7 +447,7 @@
     // Replace non-tabs with spaces, giving a print indent that matches the text
     // for tabbing.
     String spaces = prefix.replaceAll(RegExp(r'[^\t]'), ' ');
-    return 'Error in MiniJsParser:\n${src}\n$spaces^\n$spaces$message\n';
+    return 'Error in MiniJsParser:\n$src\n$spaces^\n$spaces$message\n';
   }
 }
 
@@ -527,51 +524,51 @@
   static String categoryToString(int cat) {
     switch (cat) {
       case NONE:
-        return "NONE";
+        return 'NONE';
       case ALPHA:
-        return "ALPHA";
+        return 'ALPHA';
       case NUMERIC:
-        return "NUMERIC";
+        return 'NUMERIC';
       case SYMBOL:
-        return "SYMBOL";
+        return 'SYMBOL';
       case ASSIGNMENT:
-        return "ASSIGNMENT";
+        return 'ASSIGNMENT';
       case DOT:
-        return "DOT";
+        return 'DOT';
       case LPAREN:
-        return "LPAREN";
+        return 'LPAREN';
       case RPAREN:
-        return "RPAREN";
+        return 'RPAREN';
       case LBRACE:
-        return "LBRACE";
+        return 'LBRACE';
       case RBRACE:
-        return "RBRACE";
+        return 'RBRACE';
       case LSQUARE:
-        return "LSQUARE";
+        return 'LSQUARE';
       case RSQUARE:
-        return "RSQUARE";
+        return 'RSQUARE';
       case STRING:
-        return "STRING";
+        return 'STRING';
       case COMMA:
-        return "COMMA";
+        return 'COMMA';
       case QUERY:
-        return "QUERY";
+        return 'QUERY';
       case COLON:
-        return "COLON";
+        return 'COLON';
       case SEMICOLON:
-        return "SEMICOLON";
+        return 'SEMICOLON';
       case ARROW:
-        return "ARROW";
+        return 'ARROW';
       case ELLIPSIS:
-        return "ELLIPSIS";
+        return 'ELLIPSIS';
       case HASH:
-        return "HASH";
+        return 'HASH';
       case WHITESPACE:
-        return "WHITESPACE";
+        return 'WHITESPACE';
       case OTHER:
-        return "OTHER";
+        return 'OTHER';
     }
-    return "Unknown: $cat";
+    return 'Unknown: $cat';
   }
 
   static const CATEGORIES = <int>[
@@ -674,16 +671,16 @@
     int currentCode;
     do {
       position++;
-      if (position >= src.length) error("Unterminated literal");
+      if (position >= src.length) error('Unterminated literal');
       currentCode = src.codeUnitAt(position);
-      if (currentCode == charCodes.$LF) error("Unterminated literal");
-      if (currentCode == charCodes.$BACKSLASH) {
-        if (++position >= src.length) error("Unterminated literal");
+      if (currentCode == char_codes.$LF) error('Unterminated literal');
+      if (currentCode == char_codes.$BACKSLASH) {
+        if (++position >= src.length) error('Unterminated literal');
         int escaped = src.codeUnitAt(position);
-        if (escaped == charCodes.$x ||
-            escaped == charCodes.$X ||
-            escaped == charCodes.$u ||
-            escaped == charCodes.$U ||
+        if (escaped == char_codes.$x ||
+            escaped == char_codes.$X ||
+            escaped == char_codes.$u ||
+            escaped == char_codes.$U ||
             category(escaped) == NUMERIC) {
           error('Numeric and hex escapes are not allowed in literals');
         }
@@ -699,13 +696,13 @@
       if (position >= src.length) break;
       int code = src.codeUnitAt(position);
       //  Skip '//' and '/*' style comments.
-      if (code == charCodes.$SLASH && position + 1 < src.length) {
-        if (src.codeUnitAt(position + 1) == charCodes.$SLASH) {
+      if (code == char_codes.$SLASH && position + 1 < src.length) {
+        if (src.codeUnitAt(position + 1) == char_codes.$SLASH) {
           int nextPosition = src.indexOf('\n', position);
           if (nextPosition == -1) nextPosition = src.length;
           position = nextPosition;
           continue;
-        } else if (src.codeUnitAt(position + 1) == charCodes.$STAR) {
+        } else if (src.codeUnitAt(position + 1) == char_codes.$STAR) {
           int nextPosition = src.indexOf('*/', position + 2);
           if (nextPosition == -1) error('Unterminated comment');
           position = nextPosition + 2;
@@ -713,7 +710,7 @@
         }
       }
       if (category(code) != WHITESPACE) break;
-      if (code == charCodes.$LF) skippedNewline = true;
+      if (code == char_codes.$LF) skippedNewline = true;
       ++position;
     }
 
@@ -725,13 +722,13 @@
     }
     int code = src.codeUnitAt(position);
     lastPosition = position;
-    if (code == charCodes.$SQ || code == charCodes.$DQ) {
+    if (code == char_codes.$SQ || code == char_codes.$DQ) {
       // String literal.
       lastCategory = STRING;
       lastToken = getDelimited(position);
-    } else if (code == charCodes.$0 &&
+    } else if (code == char_codes.$0 &&
         position + 2 < src.length &&
-        src.codeUnitAt(position + 1) == charCodes.$x) {
+        src.codeUnitAt(position + 1) == char_codes.$x) {
       // Hex literal.
       for (position += 2; position < src.length; position++) {
         int cat = category(src.codeUnitAt(position));
@@ -740,13 +737,13 @@
       lastCategory = NUMERIC;
       lastToken = src.substring(lastPosition, position);
       if (int.tryParse(lastToken) == null) {
-        error("Unparseable number");
+        error('Unparseable number');
       }
-    } else if (code == charCodes.$SLASH) {
+    } else if (code == char_codes.$SLASH) {
       // Tokens that start with / are special due to regexp literals.
       lastCategory = SYMBOL;
       position++;
-      if (position < src.length && src.codeUnitAt(position) == charCodes.$EQ) {
+      if (position < src.length && src.codeUnitAt(position) == char_codes.$EQ) {
         position++;
       }
       lastToken = src.substring(lastPosition, position);
@@ -761,7 +758,7 @@
         // Special code to disallow ! and / in non-first position in token, so
         // that !! parses as two tokens and != parses as one, while =/ parses
         // as a an equals token followed by a regexp literal start.
-        newCat = (code == charCodes.$BANG || code == charCodes.$SLASH)
+        newCat = (code == char_codes.$BANG || code == char_codes.$SLASH)
             ? NONE
             : category(code);
       } while (!singleCharCategory(cat) &&
@@ -772,13 +769,13 @@
       lastToken = src.substring(lastPosition, position);
       if (cat == NUMERIC) {
         if (double.tryParse(lastToken) == null) {
-          error("Unparseable number");
+          error('Unparseable number');
         }
       } else if (cat == DOT && lastToken.length > 1) {
         if (lastToken == ELLIPSIS_TOKEN) {
           lastCategory = ELLIPSIS;
         } else {
-          error("Unknown operator");
+          error('Unknown operator');
         }
       } else if (cat == SYMBOL) {
         if (lastToken == ARROW_TOKEN) {
@@ -787,7 +784,7 @@
           int? binaryPrecedence = BINARY_PRECEDENCE[lastToken];
           if (binaryPrecedence == null &&
               !UNARY_OPERATORS.contains(lastToken)) {
-            error("Unknown operator");
+            error('Unknown operator');
           }
           if (isAssignment(lastToken)) lastCategory = ASSIGNMENT;
         }
@@ -800,7 +797,7 @@
   }
 
   void expectCategory(int cat) {
-    if (cat != lastCategory) error("Expected ${categoryToString(cat)}");
+    if (cat != lastCategory) error('Expected ${categoryToString(cat)}');
     getToken();
   }
 
@@ -861,19 +858,19 @@
   Expression parsePrimary() {
     String last = lastToken;
     if (acceptCategory(ALPHA)) {
-      if (last == "true") {
+      if (last == 'true') {
         return LiteralBool(true);
-      } else if (last == "false") {
+      } else if (last == 'false') {
         return LiteralBool(false);
-      } else if (last == "null") {
+      } else if (last == 'null') {
         return LiteralNull();
-      } else if (last == "function") {
+      } else if (last == 'function') {
         return parseFunctionExpression();
-      } else if (last == "this") {
+      } else if (last == 'this') {
         return This();
-      } else if (last == "super") {
+      } else if (last == 'super') {
         return Super();
-      } else if (last == "class") {
+      } else if (last == 'class') {
         return parseClass();
       } else {
         return Identifier(last);
@@ -888,7 +885,6 @@
       return parseObjectInitializer();
     } else if (acceptCategory(LSQUARE)) {
       var values = <Expression>[];
-
       while (true) {
         if (acceptCategory(COMMA)) {
           values.add(ArrayHole());
@@ -900,17 +896,17 @@
         expectCategory(COMMA);
       }
       return ArrayInitializer(values);
-    } else if (last.startsWith("/")) {
+    } else if (last.startsWith('/')) {
       String regexp = getDelimited(lastPosition);
       getToken();
       String flags = lastToken;
-      if (!acceptCategory(ALPHA)) flags = "";
+      if (!acceptCategory(ALPHA)) flags = '';
       Expression expression = RegExpLiteral(regexp + flags);
       return expression;
     } else if (acceptCategory(HASH)) {
       return parseInterpolatedExpression();
     } else {
-      error("Expected primary expression");
+      error('Expected primary expression');
     }
   }
 
@@ -989,7 +985,7 @@
     } else if (node is InterpolatedExpression) {
       params.add(InterpolatedParameter(node.nameOrPosition));
     } else {
-      error("Expected arrow function parameter list");
+      error('Expected arrow function parameter list');
     }
   }
 
@@ -1039,7 +1035,7 @@
         asyncModifier = const AsyncModifier.async();
       }
     } else if (acceptString('sync')) {
-      if (!acceptString('*')) error("Only sync* is valid - sync is implied");
+      if (!acceptString('*')) error('Only sync* is valid - sync is implied');
       asyncModifier = const AsyncModifier.syncStar();
     } else {
       asyncModifier = const AsyncModifier.sync();
@@ -1098,7 +1094,7 @@
   }
 
   Expression parseCall() {
-    bool constructor = acceptString("new");
+    bool constructor = acceptString('new');
     Expression receiver = parseMember();
     while (true) {
       if (acceptCategory(LPAREN)) {
@@ -1126,7 +1122,7 @@
         receiver = getDotRhs(receiver);
       } else {
         // JS allows new without (), but we don't.
-        if (constructor) error("Parentheses are required for new");
+        if (constructor) error('Parentheses are required for new');
         break;
       }
     }
@@ -1145,7 +1141,7 @@
     // names, and the IndexedDB API uses that, so we need to allow it here.
     if (acceptCategory(SYMBOL)) {
       if (!OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS.contains(identifier)) {
-        error("Expected alphanumeric identifier");
+        error('Expected alphanumeric identifier');
       }
     } else {
       expectCategory(ALPHA);
@@ -1160,7 +1156,7 @@
     //     LeftHandSideExpression [no LineTerminator here] ++
     if (lastCategory == SYMBOL &&
         !skippedNewline &&
-        (acceptString("++") || acceptString("--"))) {
+        (acceptString('++') || acceptString('--'))) {
       return Postfix(operator, expression);
     }
     // If we don't accept '++' or '--' due to skippedNewline a newline, no other
@@ -1173,8 +1169,8 @@
     String operator = lastToken;
     if (lastCategory == SYMBOL &&
         UNARY_OPERATORS.contains(operator) &&
-        (acceptString("++") || acceptString("--") || acceptString('await'))) {
-      if (operator == "await") return Await(parsePostfix());
+        (acceptString('++') || acceptString('--') || acceptString('await'))) {
+      if (operator == 'await') return Await(parsePostfix());
       return Prefix(operator, parsePostfix());
     }
     return parsePostfix();
@@ -1184,10 +1180,10 @@
     String operator = lastToken;
     if (lastCategory == SYMBOL &&
         UNARY_OPERATORS.contains(operator) &&
-        operator != "++" &&
-        operator != "--") {
+        operator != '++' &&
+        operator != '--') {
       expectCategory(SYMBOL);
-      if (operator == "await") return Await(parsePostfix());
+      if (operator == 'await') return Await(parsePostfix());
       return Prefix(operator, parseUnaryLow());
     }
     return parseUnaryHigh();
@@ -1238,7 +1234,7 @@
     String assignmentOperator = lastToken;
     if (acceptCategory(ASSIGNMENT)) {
       Expression rhs = parseAssignment();
-      if (assignmentOperator == "=") {
+      if (assignmentOperator == '=') {
         return Assignment(lhs, rhs);
       } else {
         // Handle +=, -=, etc.
@@ -1273,7 +1269,7 @@
         declarator = parseVariableBinding();
       }
 
-      var initializer = acceptString("=") ? parseAssignment() : null;
+      var initializer = acceptString('=') ? parseAssignment() : null;
       initialization.add(VariableInitialization(declarator, initializer));
     } while (acceptCategory(COMMA));
 
@@ -1321,10 +1317,10 @@
       } else if (declarator is BindingPattern) {
         structure = declarator;
       } else {
-        error("Unexpected LHS: $declarator");
+        error('Unexpected LHS: $declarator');
       }
 
-      if (acceptString("=")) {
+      if (acceptString('=')) {
         defaultValue = parseExpression();
       }
       variables.add(DestructuredVariable(
@@ -1344,7 +1340,7 @@
 
       if (acceptCategory(COLON)) {
         structure = parseBindingPattern();
-      } else if (acceptString("=")) {
+      } else if (acceptString('=')) {
         defaultValue = parseExpression();
       }
       variables.add(DestructuredVariable(
@@ -1375,7 +1371,7 @@
   Expression expression() {
     Expression expression = parseVarDeclarationOrExpression();
     if (lastCategory != NONE || position != src.length) {
-      error("Unparsed junk: ${categoryToString(lastCategory)}");
+      error('Unparsed junk: ${categoryToString(lastCategory)}');
     }
     return expression;
   }
@@ -1383,7 +1379,7 @@
   Statement statement() {
     Statement statement = parseStatement();
     if (lastCategory != NONE || position != src.length) {
-      error("Unparsed junk: ${categoryToString(lastCategory)}");
+      error('Unparsed junk: ${categoryToString(lastCategory)}');
     }
     // TODO(sra): interpolated capture here?
     return statement;
@@ -1445,9 +1441,9 @@
 
       if (acceptString('switch')) return parseSwitch();
 
-      if (lastToken == 'case') error("Case outside switch.");
+      if (lastToken == 'case') error('Case outside switch.');
 
-      if (lastToken == 'default') error("Default outside switch.");
+      if (lastToken == 'default') error('Default outside switch.');
 
       if (lastToken == 'yield') return parseYield();
 
@@ -1645,7 +1641,7 @@
 
   Statement parseDo() {
     Statement body = parseStatement();
-    if (lastToken != "while") error("Missing while after do body.");
+    if (lastToken != 'while') error('Missing while after do body.');
     getToken();
     expectCategory(LPAREN);
     Expression condition = parseExpression();
diff --git a/pkg/dev_compiler/lib/src/js_ast/nodes.dart b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
index 9d29e05..c64ff60 100644
--- a/pkg/dev_compiler/lib/src/js_ast/nodes.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
@@ -2,10 +2,7 @@
 // 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.
 
-// ignore_for_file: always_declare_return_types
 // ignore_for_file: omit_local_variable_types
-// ignore_for_file: prefer_single_quotes
-// ignore_for_file: unnecessary_this
 
 library js_ast.nodes;
 
@@ -507,7 +504,8 @@
   final Statement otherwise;
 
   If(this.condition, this.then, this.otherwise);
-  If.noElse(this.condition, this.then) : this.otherwise = EmptyStatement();
+
+  If.noElse(this.condition, this.then) : otherwise = EmptyStatement();
 
   @override
   bool get alwaysReturns =>
@@ -700,12 +698,12 @@
 class _ReturnFinder extends BaseVisitorVoid {
   bool found = false;
   @override
-  visitReturn(Return node) {
+  void visitReturn(Return node) {
     found = true;
   }
 
   @override
-  visitNode(Node node) {
+  void visitNode(Node node) {
     if (!found) super.visitNode(node);
   }
 }
@@ -1293,43 +1291,43 @@
   int get precedenceLevel {
     // TODO(floitsch): switch to constant map.
     switch (op) {
-      case "*":
-      case "/":
-      case "%":
+      case '*':
+      case '/':
+      case '%':
         return MULTIPLICATIVE;
-      case "+":
-      case "-":
+      case '+':
+      case '-':
         return ADDITIVE;
-      case "<<":
-      case ">>":
-      case ">>>":
+      case '<<':
+      case '>>':
+      case '>>>':
         return SHIFT;
-      case "<":
-      case ">":
-      case "<=":
-      case ">=":
-      case "instanceof":
-      case "in":
+      case '<':
+      case '>':
+      case '<=':
+      case '>=':
+      case 'instanceof':
+      case 'in':
         return RELATIONAL;
-      case "==":
-      case "===":
-      case "!=":
-      case "!==":
+      case '==':
+      case '===':
+      case '!=':
+      case '!==':
         return EQUALITY;
-      case "&":
+      case '&':
         return BIT_AND;
-      case "^":
+      case '^':
         return BIT_XOR;
-      case "|":
+      case '|':
         return BIT_OR;
-      case "&&":
+      case '&&':
         return LOGICAL_AND;
-      case "||":
+      case '||':
         return LOGICAL_OR;
       case ',':
         return EXPRESSION;
       default:
-        throw "Internal Error: Unhandled binary operator: $op";
+        throw 'Internal Error: Unhandled binary operator: $op';
     }
   }
 }
@@ -1398,7 +1396,7 @@
 
   Identifier(this.name, {this.allowRename = true}) {
     if (!_identifierRE.hasMatch(name)) {
-      throw ArgumentError.value(name, "name", "not a valid identifier");
+      throw ArgumentError.value(name, 'name', 'not a valid identifier');
     }
   }
   static final RegExp _identifierRE = RegExp(r'^[A-Za-z_$][A-Za-z_$0-9]*$');
@@ -1571,21 +1569,21 @@
   const AsyncModifier.sync()
       : isAsync = false,
         isYielding = false,
-        description = "sync";
+        description = 'sync';
   const AsyncModifier.async()
       : isAsync = true,
         isYielding = false,
-        description = "async";
+        description = 'async';
   const AsyncModifier.asyncStar()
       : isAsync = true,
         isYielding = true,
-        description = "async*";
+        description = 'async*';
   const AsyncModifier.syncStar()
       : isAsync = false,
         isYielding = true,
-        description = "sync*";
+        description = 'sync*';
   @override
-  toString() => description;
+  String toString() => description;
 }
 
 class PropertyAccess extends Expression {
@@ -1872,7 +1870,7 @@
   @override
   T accept<T>(NodeVisitor<T> visitor) => visitor.visitClassDeclaration(this);
   @override
-  visitChildren(NodeVisitor visitor) => classExpr.accept(visitor);
+  void visitChildren(NodeVisitor visitor) => classExpr.accept(visitor);
   @override
   ClassDeclaration _clone() => ClassDeclaration(classExpr);
 }
@@ -1940,7 +1938,7 @@
 
 /// Tag class for all interpolated positions.
 abstract class InterpolatedNode implements Node {
-  get nameOrPosition;
+  dynamic get nameOrPosition;
 
   bool get isNamed => nameOrPosition is String;
   bool get isPositional => nameOrPosition is int;
@@ -1986,12 +1984,12 @@
 
   @override
   String get name {
-    throw "InterpolatedParameter.name must not be invoked";
+    throw 'InterpolatedParameter.name must not be invoked';
   }
 
   @override
   String get parameterName {
-    throw "InterpolatedParameter.parameterName must not be invoked";
+    throw 'InterpolatedParameter.parameterName must not be invoked';
   }
 
   @override
@@ -2292,7 +2290,7 @@
   @override
   T accept<T>(NodeVisitor<T> visitor) => visitor.visitExportDeclaration(this);
   @override
-  visitChildren(NodeVisitor visitor) => exported.accept(visitor);
+  void visitChildren(NodeVisitor visitor) => exported.accept(visitor);
   @override
   ExportDeclaration _clone() =>
       ExportDeclaration(exported, isDefault: isDefault);
diff --git a/pkg/dev_compiler/lib/src/js_ast/printer.dart b/pkg/dev_compiler/lib/src/js_ast/printer.dart
index 7a97ad3..88434f0 100644
--- a/pkg/dev_compiler/lib/src/js_ast/printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/printer.dart
@@ -2,18 +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.
 
-// ignore_for_file: always_declare_return_types
-// ignore_for_file: library_prefixes
 // ignore_for_file: omit_local_variable_types
-// ignore_for_file: prefer_initializing_formals
-// ignore_for_file: prefer_interpolation_to_compose_strings
-// ignore_for_file: prefer_is_not_empty
-// ignore_for_file: prefer_single_quotes
-// ignore_for_file: use_function_type_syntax_for_parameters
 
 library js_ast.printer;
 
-import 'characters.dart' as charCodes;
+import 'characters.dart' as char_codes;
 import 'nodes.dart';
 import 'precedence.dart';
 
@@ -86,7 +79,7 @@
   // The current indentation level.
   int _indentLevel = 0;
   // A cache of all indentation strings used so far.
-  final List<String> _indentList = [""];
+  final List<String> _indentList = [''];
 
   /// Whether the next call to [indent] should just be a no-op.
   bool _skipNextIndent = false;
@@ -94,11 +87,8 @@
   static final identifierCharacterRegExp = RegExp(r'^[a-zA-Z_0-9$]');
   static final expressionContinuationRegExp = RegExp(r'^[-+([]');
 
-  Printer(JavaScriptPrintingOptions options, JavaScriptPrintingContext context,
-      {LocalNamer? localNamer})
-      : options = options,
-        context = context,
-        shouldCompressOutput = options.shouldCompressOutput,
+  Printer(this.options, this.context, {LocalNamer? localNamer})
+      : shouldCompressOutput = options.shouldCompressOutput,
         danglingElseVisitor = DanglingElseVisitor(context),
         localNamer = determineRenamer(localNamer, options) {
     context.printer = this;
@@ -116,7 +106,7 @@
   String get indentation {
     // Lazily add new indentation strings as required.
     while (_indentList.length <= _indentLevel) {
-      _indentList.add(_indentList.last + "  ");
+      _indentList.add('${_indentList.last}  ');
     }
     return _indentList[_indentLevel];
   }
@@ -131,7 +121,7 @@
 
   /// Always emit a newline, even under `enableMinification`.
   void forceLine() {
-    out("\n");
+    out('\n');
   }
 
   /// Emits a newline for readability.
@@ -140,7 +130,7 @@
   }
 
   void spaceOut() {
-    if (!shouldCompressOutput) out(" ");
+    if (!shouldCompressOutput) out(' ');
   }
 
   String lastAddedString = '\u0000';
@@ -151,11 +141,11 @@
   }
 
   void out(String str) {
-    if (str != "") {
+    if (str != '') {
       if (pendingSemicolon) {
         if (!shouldCompressOutput) {
-          context.emit(";");
-        } else if (str != "}") {
+          context.emit(';');
+        } else if (str != '}') {
           // We want to output newline instead of semicolon because it makes
           // the raw stack traces much easier to read and it also makes line-
           // based tools like diff work much better.  JavaScript will
@@ -169,15 +159,15 @@
           // than newlines because the former doesn't need escaping.
           if (options.preferSemicolonToNewlineInMinifiedOutput ||
               expressionContinuationRegExp.hasMatch(str)) {
-            context.emit(";");
+            context.emit(';');
           } else {
-            context.emit("\n");
+            context.emit('\n');
           }
         }
       }
       if (pendingSpace &&
           (!shouldCompressOutput || identifierCharacterRegExp.hasMatch(str))) {
-        context.emit(" ");
+        context.emit(' ');
       }
       pendingSpace = false;
       pendingSemicolon = false;
@@ -195,7 +185,7 @@
     if (shouldCompressOutput) {
       pendingSemicolon = true;
     } else {
-      out(";");
+      out(';');
       forceLine();
     }
   }
@@ -224,18 +214,18 @@
     }
   }
 
-  visit(Node node) {
+  void visit(Node node) {
     context.enterNode(node);
     node.accept(this);
     context.exitNode(node);
   }
 
-  visitCommaSeparated(List<Expression> nodes, int hasRequiredType,
+  void visitCommaSeparated(List<Expression> nodes, int hasRequiredType,
       {required bool newInForInit, required bool newAtStatementBegin}) {
     for (int i = 0; i < nodes.length; i++) {
       if (i != 0) {
         atStatementBegin = false;
-        out(",");
+        out(',');
         spaceOut();
       }
       visitNestedExpression(nodes[i], hasRequiredType,
@@ -243,12 +233,12 @@
     }
   }
 
-  visitAll(List<Node> nodes) {
+  void visitAll(List<Node> nodes) {
     nodes.forEach(visit);
   }
 
   @override
-  visitProgram(Program program) {
+  void visitProgram(Program program) {
     if (program.scriptTag != null) {
       out('#!${program.scriptTag}\n');
     }
@@ -265,7 +255,7 @@
     if (shouldCompressOutput && needsSeparation) {
       // If [shouldCompressOutput] is false, then the 'lineOut' will insert
       // the separation.
-      out(" ");
+      out(' ');
     } else {
       lineOut();
     }
@@ -290,38 +280,38 @@
       {required bool shouldIndent, required bool needsNewline}) {
     if (shouldIndent) indent();
     context.enterNode(node);
-    out("{");
+    out('{');
     lineOut();
     indentMore();
     node.statements.forEach(blockOutWithoutBraces);
     indentLess();
     indent();
-    out("}");
+    out('}');
     context.exitNode(node);
     if (needsNewline) lineOut();
   }
 
   @override
-  visitBlock(Block block) {
+  void visitBlock(Block block) {
     blockOut(block, shouldIndent: true, needsNewline: true);
   }
 
   @override
-  visitDebuggerStatement(node) {
+  void visitDebuggerStatement(node) {
     outIndentLn('debugger;');
   }
 
   @override
-  visitExpressionStatement(ExpressionStatement expressionStatement) {
+  void visitExpressionStatement(ExpressionStatement node) {
     indent();
-    visitNestedExpression(expressionStatement.expression, EXPRESSION,
+    visitNestedExpression(node.expression, EXPRESSION,
         newInForInit: false, newAtStatementBegin: true);
     outSemicolonLn();
   }
 
   @override
-  visitEmptyStatement(EmptyStatement nop) {
-    outIndentLn(";");
+  void visitEmptyStatement(EmptyStatement node) {
+    outIndentLn(';');
   }
 
   void ifOut(If node, bool shouldIndent) {
@@ -339,12 +329,12 @@
       }
     }
     if (shouldIndent) indent();
-    out("if");
+    out('if');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(node.condition, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     bool thenWasBlock;
     if (options.allowSingleLineIfStatements && !hasElse && then is! Block) {
       thenWasBlock = false;
@@ -361,7 +351,7 @@
       } else {
         indent();
       }
-      out("else");
+      out('else');
       if (elsePart is If) {
         pendingSpace = true;
         context.enterNode(elsePart);
@@ -374,132 +364,133 @@
   }
 
   @override
-  visitIf(If node) {
+  void visitIf(If node) {
     ifOut(node, true);
   }
 
   @override
-  visitFor(For loop) {
-    outIndent("for");
+  void visitFor(For loop) {
+    outIndent('for');
     spaceOut();
-    out("(");
+    out('(');
     if (loop.init != null) {
       visitNestedExpression(loop.init!, EXPRESSION,
           newInForInit: true, newAtStatementBegin: false);
     }
-    out(";");
+    out(';');
     if (loop.condition != null) {
       spaceOut();
       visitNestedExpression(loop.condition!, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
     }
-    out(";");
+    out(';');
     if (loop.update != null) {
       spaceOut();
       visitNestedExpression(loop.update!, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
     }
-    out(")");
+    out(')');
     blockBody(loop.body, needsSeparation: false, needsNewline: true);
   }
 
   @override
-  visitForIn(ForIn loop) {
-    outIndent("for");
+  void visitForIn(ForIn loop) {
+    outIndent('for');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(loop.leftHandSide, EXPRESSION,
         newInForInit: true, newAtStatementBegin: false);
-    out(" in");
+    out(' in');
     pendingSpace = true;
     visitNestedExpression(loop.object, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     blockBody(loop.body, needsSeparation: false, needsNewline: true);
   }
 
   @override
-  visitForOf(ForOf loop) {
-    outIndent("for");
+  void visitForOf(ForOf loop) {
+    outIndent('for');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(loop.leftHandSide, EXPRESSION,
         newInForInit: true, newAtStatementBegin: false);
-    out(" of");
+    out(' of');
     pendingSpace = true;
     visitNestedExpression(loop.iterable, ASSIGNMENT,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     blockBody(loop.body, needsSeparation: false, needsNewline: true);
   }
 
   @override
-  visitWhile(While loop) {
-    outIndent("while");
+  void visitWhile(While loop) {
+    outIndent('while');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(loop.condition, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     blockBody(loop.body, needsSeparation: false, needsNewline: true);
   }
 
   @override
-  visitDo(Do loop) {
-    outIndent("do");
+  void visitDo(Do loop) {
+    outIndent('do');
     if (blockBody(loop.body, needsSeparation: true, needsNewline: false)) {
       spaceOut();
     } else {
       indent();
     }
-    out("while");
+    out('while');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(loop.condition, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     outSemicolonLn();
   }
 
   @override
-  visitContinue(Continue node) {
+  void visitContinue(Continue node) {
     if (node.targetLabel == null) {
-      outIndent("continue");
+      outIndent('continue');
     } else {
-      outIndent("continue ${node.targetLabel}");
+      outIndent('continue ${node.targetLabel}');
     }
     outSemicolonLn();
   }
 
   @override
-  visitBreak(Break node) {
+  void visitBreak(Break node) {
     if (node.targetLabel == null) {
-      outIndent("break");
+      outIndent('break');
     } else {
-      outIndent("break ${node.targetLabel}");
+      outIndent('break ${node.targetLabel}');
     }
     outSemicolonLn();
   }
 
   @override
-  visitReturn(Return node) {
-    if (node.value == null) {
-      outIndent("return");
+  void visitReturn(Return node) {
+    final value = node.value;
+    if (value == null) {
+      outIndent('return');
     } else {
-      outIndent("return");
+      outIndent('return');
       pendingSpace = true;
-      visitNestedExpression(node.value!, EXPRESSION,
+      visitNestedExpression(value, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
     }
     outSemicolonLn();
   }
 
   @override
-  visitDartYield(DartYield node) {
+  void visitDartYield(DartYield node) {
     if (node.hasStar) {
-      outIndent("yield*");
+      outIndent('yield*');
     } else {
-      outIndent("yield");
+      outIndent('yield');
     }
     pendingSpace = true;
     visitNestedExpression(node.expression, EXPRESSION,
@@ -508,8 +499,8 @@
   }
 
   @override
-  visitThrow(Throw node) {
-    outIndent("throw");
+  void visitThrow(Throw node) {
+    outIndent('throw');
     pendingSpace = true;
     visitNestedExpression(node.expression, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
@@ -517,15 +508,15 @@
   }
 
   @override
-  visitTry(Try node) {
-    outIndent("try");
+  void visitTry(Try node) {
+    outIndent('try');
     blockBody(node.body, needsSeparation: true, needsNewline: false);
     if (node.catchPart != null) {
       visit(node.catchPart!);
     }
     if (node.finallyPart != null) {
       spaceOut();
-      out("finally");
+      out('finally');
       blockBody(node.finallyPart!, needsSeparation: true, needsNewline: true);
     } else {
       lineOut();
@@ -533,41 +524,41 @@
   }
 
   @override
-  visitCatch(Catch node) {
+  void visitCatch(Catch node) {
     spaceOut();
-    out("catch");
+    out('catch');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(node.declaration, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     blockBody(node.body, needsSeparation: false, needsNewline: false);
   }
 
   @override
-  visitSwitch(Switch node) {
-    outIndent("switch");
+  void visitSwitch(Switch node) {
+    outIndent('switch');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(node.key, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     spaceOut();
-    outLn("{");
+    outLn('{');
     indentMore();
     visitAll(node.cases);
     indentLess();
-    outIndentLn("}");
+    outIndentLn('}');
   }
 
   @override
-  visitCase(Case node) {
-    outIndent("case");
+  void visitCase(Case node) {
+    outIndent('case');
     pendingSpace = true;
     visitNestedExpression(node.expression, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    outLn(":");
-    if (!node.body.statements.isEmpty) {
+    outLn(':');
+    if (node.body.statements.isNotEmpty) {
       indentMore();
       blockOutWithoutBraces(node.body);
       indentLess();
@@ -575,9 +566,9 @@
   }
 
   @override
-  visitDefault(Default node) {
-    outIndentLn("default:");
-    if (!node.body.statements.isEmpty) {
+  void visitDefault(Default node) {
+    outIndentLn('default:');
+    if (node.body.statements.isNotEmpty) {
       indentMore();
       blockOutWithoutBraces(node.body);
       indentLess();
@@ -585,27 +576,25 @@
   }
 
   @override
-  visitLabeledStatement(LabeledStatement node) {
-    outIndent("${node.label}:");
+  void visitLabeledStatement(LabeledStatement node) {
+    outIndent('${node.label}:');
     blockBody(node.body, needsSeparation: false, needsNewline: true);
   }
 
   void functionOut(Fun fun, Identifier? name) {
-    out("function");
-    if (fun.isGenerator) out("*");
+    out('function');
+    if (fun.isGenerator) out('*');
     if (name != null) {
-      out(" ");
+      out(' ');
       // Name must be a [Decl]. Therefore only test for primary expressions.
       visitNestedExpression(name, PRIMARY,
           newInForInit: false, newAtStatementBegin: false);
     }
     localNamer.enterScope(fun);
-    out("(");
-
+    out('(');
     visitCommaSeparated(fun.params, PRIMARY,
         newInForInit: false, newAtStatementBegin: false);
-
-    out(")");
+    out(')');
     switch (fun.asyncModifier) {
       case AsyncModifier.sync():
         break;
@@ -624,7 +613,7 @@
   }
 
   @override
-  visitFunctionDeclaration(FunctionDeclaration declaration) {
+  void visitFunctionDeclaration(FunctionDeclaration declaration) {
     indent();
     var f = declaration.function;
     context.enterNode(f);
@@ -633,15 +622,15 @@
     lineOut();
   }
 
-  visitNestedExpression(Expression node, int requiredPrecedence,
+  void visitNestedExpression(Expression node, int requiredPrecedence,
       {required bool newInForInit, required bool newAtStatementBegin}) {
-    int nodePrecedence = node.precedenceLevel;
+    int precedenceLevel = node.precedenceLevel;
     bool needsParentheses =
         // a - (b + c).
         (requiredPrecedence != EXPRESSION &&
-                nodePrecedence < requiredPrecedence) ||
+                precedenceLevel < requiredPrecedence) ||
             // for (a = (x in o); ... ; ... ) { ... }
-            (newInForInit && node is Binary && node.op == "in") ||
+            (newInForInit && node is Binary && node.op == 'in') ||
             // (function() { ... })().
             // ({a: 2, b: 3}.toString()).
             (newAtStatementBegin &&
@@ -652,9 +641,9 @@
       inForInit = false;
       atStatementBegin = false;
       inNewTarget = false;
-      out("(");
+      out('(');
       visit(node);
-      out(")");
+      out(')');
     } else {
       inForInit = newInForInit;
       atStatementBegin = newAtStatementBegin;
@@ -663,46 +652,46 @@
   }
 
   @override
-  visitVariableDeclarationList(VariableDeclarationList list) {
+  void visitVariableDeclarationList(VariableDeclarationList list) {
     // Note: keyword can be null for non-static field declarations.
     if (list.keyword != null) {
       out(list.keyword!);
-      out(" ");
+      out(' ');
     }
     visitCommaSeparated(list.declarations, ASSIGNMENT,
         newInForInit: inForInit, newAtStatementBegin: false);
   }
 
   @override
-  visitArrayBindingPattern(ArrayBindingPattern node) {
-    out("[");
+  void visitArrayBindingPattern(ArrayBindingPattern node) {
+    out('[');
     visitCommaSeparated(node.variables, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out("]");
+    out(']');
   }
 
   @override
-  visitObjectBindingPattern(ObjectBindingPattern node) {
-    out("{");
+  void visitObjectBindingPattern(ObjectBindingPattern node) {
+    out('{');
     visitCommaSeparated(node.variables, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out("}");
+    out('}');
   }
 
   @override
-  visitDestructuredVariable(DestructuredVariable node) {
+  void visitDestructuredVariable(DestructuredVariable node) {
     var name = node.name;
     var property = node.property;
     visit(name);
     if (property != null) {
-      out("[");
+      out('[');
       visit(property);
-      out("]");
+      out(']');
     }
     var structure = node.structure;
     if (structure != null) {
       if (property != null) {
-        out(":");
+        out(':');
         spaceOut();
       }
       visit(structure);
@@ -710,7 +699,7 @@
     var defaultValue = node.defaultValue;
     if (defaultValue != null) {
       spaceOut();
-      out("=");
+      out('=');
       spaceOut();
       visitNestedExpression(defaultValue, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
@@ -718,30 +707,30 @@
   }
 
   @override
-  visitSimpleBindingPattern(SimpleBindingPattern node) {
+  void visitSimpleBindingPattern(SimpleBindingPattern node) {
     visit(node.name);
   }
 
   @override
-  visitAssignment(Assignment assignment) {
+  void visitAssignment(Assignment assignment) {
     visitNestedExpression(assignment.leftHandSide, LEFT_HAND_SIDE,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
     spaceOut();
     String? op = assignment.op;
     if (op != null) out(op);
-    out("=");
+    out('=');
     spaceOut();
     visitNestedExpression(assignment.value, ASSIGNMENT,
         newInForInit: inForInit, newAtStatementBegin: false);
   }
 
   @override
-  visitVariableInitialization(VariableInitialization initialization) {
+  void visitVariableInitialization(VariableInitialization initialization) {
     visitNestedExpression(initialization.declaration, LEFT_HAND_SIDE,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
     if (initialization.value != null) {
       spaceOut();
-      out("=");
+      out('=');
       spaceOut();
       visitNestedExpression(initialization.value!, ASSIGNMENT,
           newInForInit: inForInit, newAtStatementBegin: false);
@@ -749,47 +738,47 @@
   }
 
   @override
-  visitConditional(Conditional cond) {
+  void visitConditional(Conditional cond) {
     visitNestedExpression(cond.condition, LOGICAL_OR,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
     spaceOut();
-    out("?");
+    out('?');
     spaceOut();
     // The then part is allowed to have an 'in'.
     visitNestedExpression(cond.then, ASSIGNMENT,
         newInForInit: false, newAtStatementBegin: false);
     spaceOut();
-    out(":");
+    out(':');
     spaceOut();
     visitNestedExpression(cond.otherwise, ASSIGNMENT,
         newInForInit: inForInit, newAtStatementBegin: false);
   }
 
   @override
-  visitNew(New node) {
-    out("new ");
+  void visitNew(New node) {
+    out('new ');
     inNewTarget = true;
     visitNestedExpression(node.target, ACCESS,
         newInForInit: inForInit, newAtStatementBegin: false);
     inNewTarget = false;
-    out("(");
+    out('(');
     visitCommaSeparated(node.arguments, SPREAD,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
   }
 
   @override
-  visitCall(Call call) {
+  void visitCall(Call call) {
     visitNestedExpression(call.target, LEFT_HAND_SIDE,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
-    out("(");
+    out('(');
     visitCommaSeparated(call.arguments, SPREAD,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
   }
 
   @override
-  visitBinary(Binary binary) {
+  void visitBinary(Binary binary) {
     Expression left = binary.left;
     Expression right = binary.right;
     String op = binary.op;
@@ -803,55 +792,55 @@
         rightPrecedenceRequirement = EXPRESSION;
         leftSpace = false;
         break;
-      case "||":
+      case '||':
         leftPrecedenceRequirement = LOGICAL_OR;
         // x || (y || z) <=> (x || y) || z.
         rightPrecedenceRequirement = LOGICAL_OR;
         break;
-      case "&&":
+      case '&&':
         leftPrecedenceRequirement = LOGICAL_AND;
         // x && (y && z) <=> (x && y) && z.
         rightPrecedenceRequirement = LOGICAL_AND;
         break;
-      case "|":
+      case '|':
         leftPrecedenceRequirement = BIT_OR;
         // x | (y | z) <=> (x | y) | z.
         rightPrecedenceRequirement = BIT_OR;
         break;
-      case "^":
+      case '^':
         leftPrecedenceRequirement = BIT_XOR;
         // x ^ (y ^ z) <=> (x ^ y) ^ z.
         rightPrecedenceRequirement = BIT_XOR;
         break;
-      case "&":
+      case '&':
         leftPrecedenceRequirement = BIT_AND;
         // x & (y & z) <=> (x & y) & z.
         rightPrecedenceRequirement = BIT_AND;
         break;
-      case "==":
-      case "!=":
-      case "===":
-      case "!==":
+      case '==':
+      case '!=':
+      case '===':
+      case '!==':
         leftPrecedenceRequirement = EQUALITY;
         rightPrecedenceRequirement = RELATIONAL;
         break;
-      case "<":
-      case ">":
-      case "<=":
-      case ">=":
-      case "instanceof":
-      case "in":
+      case '<':
+      case '>':
+      case '<=':
+      case '>=':
+      case 'instanceof':
+      case 'in':
         leftPrecedenceRequirement = RELATIONAL;
         rightPrecedenceRequirement = SHIFT;
         break;
-      case ">>":
-      case "<<":
-      case ">>>":
+      case '>>':
+      case '<<':
+      case '>>>':
         leftPrecedenceRequirement = SHIFT;
         rightPrecedenceRequirement = ADDITIVE;
         break;
-      case "+":
-      case "-":
+      case '+':
+      case '-':
         leftPrecedenceRequirement = ADDITIVE;
         // We cannot remove parenthesis for "+" because
         //   x + (y + z) <!=> (x + y) + z:
@@ -860,9 +849,9 @@
         //   ("a" + 1) + 2 => "a12";
         rightPrecedenceRequirement = MULTIPLICATIVE;
         break;
-      case "*":
-      case "/":
-      case "%":
+      case '*':
+      case '/':
+      case '%':
         leftPrecedenceRequirement = MULTIPLICATIVE;
         // We cannot remove parenthesis for "*" because of precision issues.
         rightPrecedenceRequirement = UNARY;
@@ -870,18 +859,18 @@
       default:
         leftPrecedenceRequirement = EXPRESSION;
         rightPrecedenceRequirement = EXPRESSION;
-        context.error("Forgot operator: $op");
+        context.error('Forgot operator: $op');
     }
 
     visitNestedExpression(left, leftPrecedenceRequirement,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
 
-    if (op == "in" || op == "instanceof") {
+    if (op == 'in' || op == 'instanceof') {
       // There are cases where the space is not required but without further
       // analysis we cannot know.
-      out(" ");
+      out(' ');
       out(op);
-      out(" ");
+      out(' ');
     } else {
       if (leftSpace) spaceOut();
       out(op);
@@ -892,25 +881,25 @@
   }
 
   @override
-  visitPrefix(Prefix unary) {
+  void visitPrefix(Prefix unary) {
     String op = unary.op;
     switch (op) {
-      case "delete":
-      case "void":
-      case "typeof":
+      case 'delete':
+      case 'void':
+      case 'typeof':
         // There are cases where the space is not required but without further
         // analysis we cannot know.
         out(op);
-        out(" ");
+        out(' ');
         break;
-      case "+":
-      case "++":
-        if (lastCharCode == charCodes.$PLUS) out(" ");
+      case '+':
+      case '++':
+        if (lastCharCode == char_codes.$PLUS) out(' ');
         out(op);
         break;
-      case "-":
-      case "--":
-        if (lastCharCode == charCodes.$MINUS) out(" ");
+      case '-':
+      case '--':
+        if (lastCharCode == char_codes.$MINUS) out(' ');
         out(op);
         break;
       default:
@@ -921,47 +910,47 @@
   }
 
   @override
-  visitSpread(Spread unary) => visitPrefix(unary);
+  void visitSpread(Spread unary) => visitPrefix(unary);
 
   @override
-  visitYield(Yield yield) {
-    out(yield.star ? "yield*" : "yield");
+  void visitYield(Yield yield) {
+    out(yield.star ? 'yield*' : 'yield');
     if (yield.value == null) return;
-    out(" ");
+    out(' ');
     visitNestedExpression(yield.value!, yield.precedenceLevel,
         newInForInit: inForInit, newAtStatementBegin: false);
   }
 
   @override
-  visitPostfix(Postfix postfix) {
+  void visitPostfix(Postfix postfix) {
     visitNestedExpression(postfix.argument, LEFT_HAND_SIDE,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
     out(postfix.op);
   }
 
   @override
-  visitThis(This node) {
-    out("this");
+  void visitThis(This node) {
+    out('this');
   }
 
   @override
-  visitSuper(Super node) {
-    out("super");
+  void visitSuper(Super node) {
+    out('super');
   }
 
   @override
-  visitIdentifier(Identifier node) {
+  void visitIdentifier(Identifier node) {
     out(localNamer.getName(node));
   }
 
   @override
-  visitRestParameter(RestParameter node) {
+  void visitRestParameter(RestParameter node) {
     out('...');
     visitIdentifier(node.parameter);
   }
 
   bool isDigit(int charCode) {
-    return charCodes.$0 <= charCode && charCode <= charCodes.$9;
+    return char_codes.$0 <= charCode && charCode <= char_codes.$9;
   }
 
   bool isValidJavaScriptId(String field) {
@@ -970,15 +959,14 @@
     for (int i = 1; i < field.length - 1; i++) {
       // TODO(floitsch): allow more characters.
       int charCode = field.codeUnitAt(i);
-      if (!(charCodes.$a <= charCode && charCode <= charCodes.$z ||
-          charCodes.$A <= charCode && charCode <= charCodes.$Z ||
-          charCode == charCodes.$$ ||
-          charCode == charCodes.$_ ||
+      if (!(char_codes.$a <= charCode && charCode <= char_codes.$z ||
+          char_codes.$A <= charCode && charCode <= char_codes.$Z ||
+          charCode == char_codes.$$ ||
+          charCode == char_codes.$_ ||
           i != 1 && isDigit(charCode))) {
         return false;
       }
     }
-
     // TODO(floitsch): normally we should also check that the field is not a
     // reserved word.  We don't generate fields with reserved word names except
     // for 'super'.
@@ -986,7 +974,7 @@
   }
 
   @override
-  visitAccess(PropertyAccess access) {
+  void visitAccess(PropertyAccess access) {
     /// Normally we can omit parens on the receiver if it is a Call, even though
     /// Call expressions have lower precedence.
     ///
@@ -1010,7 +998,7 @@
   }
 
   @override
-  visitNamedFunction(NamedFunction namedFunction) {
+  void visitNamedFunction(NamedFunction namedFunction) {
     var f = namedFunction.function;
     context.enterNode(f);
     functionOut(f, namedFunction.name);
@@ -1018,35 +1006,35 @@
   }
 
   @override
-  visitFun(Fun fun) {
+  void visitFun(Fun fun) {
     functionOut(fun, null);
   }
 
   @override
-  visitArrowFun(ArrowFun fun) {
+  void visitArrowFun(ArrowFun fun) {
     localNamer.enterScope(fun);
     if (fun.params.length == 1 && fun.params[0] is Identifier) {
       visitNestedExpression(fun.params.single, SPREAD,
           newInForInit: false, newAtStatementBegin: false);
     } else {
-      out("(");
+      out('(');
       visitCommaSeparated(fun.params, SPREAD,
           newInForInit: false, newAtStatementBegin: false);
-      out(")");
+      out(')');
     }
     spaceOut();
-    out("=>");
+    out('=>');
     var body = fun.body;
     if (body is Expression) {
       spaceOut();
       // Object initializers require parentheses to disambiguate
       // AssignmentExpression from FunctionBody. See:
       // https://tc39.github.io/ecma262/#sec-arrow-function-definitions
-      var needsParen = fun.body is ObjectInitializer;
-      if (needsParen) out("(");
+      var needsParen = body is ObjectInitializer;
+      if (needsParen) out('(');
       visitNestedExpression(body, ASSIGNMENT,
           newInForInit: false, newAtStatementBegin: false);
-      if (needsParen) out(")");
+      if (needsParen) out(')');
     } else {
       blockBody(body as Block, needsSeparation: false, needsNewline: false);
     }
@@ -1054,32 +1042,32 @@
   }
 
   @override
-  visitLiteralBool(LiteralBool node) {
-    out(node.value ? "true" : "false");
+  void visitLiteralBool(LiteralBool node) {
+    out(node.value ? 'true' : 'false');
   }
 
   @override
-  visitLiteralString(LiteralString node) {
+  void visitLiteralString(LiteralString node) {
     out(node.value);
   }
 
   @override
-  visitLiteralNumber(LiteralNumber node) {
+  void visitLiteralNumber(LiteralNumber node) {
     int charCode = node.value.codeUnitAt(0);
-    if (charCode == charCodes.$MINUS && lastCharCode == charCodes.$MINUS) {
-      out(" ");
+    if (charCode == char_codes.$MINUS && lastCharCode == char_codes.$MINUS) {
+      out(' ');
     }
     out(node.value);
   }
 
   @override
-  visitLiteralNull(LiteralNull node) {
-    out("null");
+  void visitLiteralNull(LiteralNull node) {
+    out('null');
   }
 
   @override
-  visitArrayInitializer(ArrayInitializer node) {
-    out("[");
+  void visitArrayInitializer(ArrayInitializer node) {
+    out('[');
     indentMore();
     var multiline = node.multiline;
     List<Expression> elements = node.elements;
@@ -1090,7 +1078,7 @@
         // in last position. Otherwise `[,]` (having length 1) would become
         // equal to `[]` (the empty array)
         // and [1,,] (array with 1 and a hole) would become [1,] = [1].
-        out(",");
+        out(',');
         continue;
       }
       if (i != 0 && !multiline) spaceOut();
@@ -1102,31 +1090,31 @@
           newInForInit: false, newAtStatementBegin: false);
       // We can skip the trailing "," for the last element (since it's not
       // an array hole).
-      if (i != elements.length - 1) out(",");
+      if (i != elements.length - 1) out(',');
     }
     indentLess();
     if (multiline) {
       lineOut();
       indent();
     }
-    out("]");
+    out(']');
   }
 
   @override
-  visitArrayHole(ArrayHole node) {
-    throw "Unreachable";
+  void visitArrayHole(ArrayHole node) {
+    throw 'Unreachable';
   }
 
   @override
-  visitObjectInitializer(ObjectInitializer node) {
+  void visitObjectInitializer(ObjectInitializer node) {
     List<Property> properties = node.properties;
-    out("{");
+    out('{');
     indentMore();
 
     var multiline = node.multiline;
     for (int i = 0; i < properties.length; i++) {
       if (i != 0) {
-        out(",");
+        out(',');
         if (!multiline) spaceOut();
       }
       if (multiline) {
@@ -1140,25 +1128,25 @@
       lineOut();
       indent();
     }
-    out("}");
+    out('}');
   }
 
   @override
-  visitProperty(Property node) {
+  void visitProperty(Property node) {
     propertyNameOut(node.name);
-    out(":");
+    out(':');
     spaceOut();
     visitNestedExpression(node.value, ASSIGNMENT,
         newInForInit: false, newAtStatementBegin: false);
   }
 
   @override
-  visitRegExpLiteral(RegExpLiteral node) {
+  void visitRegExpLiteral(RegExpLiteral node) {
     out(node.pattern);
   }
 
   @override
-  visitTemplateString(TemplateString node) {
+  void visitTemplateString(TemplateString node) {
     out('`');
     int len = node.interpolations.length;
     for (var i = 0; i < len; i++) {
@@ -1172,20 +1160,20 @@
   }
 
   @override
-  visitTaggedTemplate(TaggedTemplate node) {
+  void visitTaggedTemplate(TaggedTemplate node) {
     visit(node.tag);
     visit(node.template);
   }
 
   @override
-  visitClassDeclaration(ClassDeclaration node) {
+  void visitClassDeclaration(ClassDeclaration node) {
     indent();
     visit(node.classExpr);
     lineOut();
   }
 
   @override
-  visitClassExpression(ClassExpression node) {
+  void visitClassExpression(ClassExpression node) {
     localNamer.enterScope(node);
     out('class ');
     visit(node.name);
@@ -1213,7 +1201,7 @@
   }
 
   @override
-  visitMethod(Method node) {
+  void visitMethod(Method node) {
     if (node.isStatic) {
       out('static ');
     }
@@ -1228,14 +1216,14 @@
 
     var fun = node.function;
     localNamer.enterScope(fun);
-    out("(");
+    out('(');
     visitCommaSeparated(fun.params, SPREAD,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     // TODO(jmesserly): async modifiers
     if (fun.body.statements.isEmpty) {
       spaceOut();
-      out("{}");
+      out('{}');
     } else {
       spaceOut();
       blockOut(fun.body, shouldIndent: false, needsNewline: false);
@@ -1256,22 +1244,22 @@
           if (inAccess) out('.');
           out(node.valueWithoutQuotes);
         } else {
-          if (inMethod || inAccess) out("[");
+          if (inMethod || inAccess) out('[');
           out(node.value);
-          if (inMethod || inAccess) out("]");
+          if (inMethod || inAccess) out(']');
         }
       } else {
         // ComputedPropertyName
-        out("[");
+        out('[');
         visitNestedExpression(node, EXPRESSION,
             newInForInit: false, newAtStatementBegin: false);
-        out("]");
+        out(']');
       }
     }
   }
 
   @override
-  visitImportDeclaration(ImportDeclaration node) {
+  void visitImportDeclaration(ImportDeclaration node) {
     indent();
     out('import ');
     if (node.defaultBinding != null) {
@@ -1289,7 +1277,7 @@
   }
 
   @override
-  visitExportDeclaration(ExportDeclaration node) {
+  void visitExportDeclaration(ExportDeclaration node) {
     indent();
     out('export ');
     if (node.isDefault) out('default ');
@@ -1299,14 +1287,14 @@
   }
 
   @override
-  visitExportClause(ExportClause node) {
+  void visitExportClause(ExportClause node) {
     nameSpecifierListOut(node.exports, true);
     if (node.from != null) {
       fromClauseOut(node.from!);
     }
   }
 
-  nameSpecifierListOut(List<NameSpecifier> names, bool export) {
+  void nameSpecifierListOut(List<NameSpecifier> names, bool export) {
     if (names.length == 1 && names[0].name!.name == '*') {
       nameSpecifierOut(names[0], export);
       return;
@@ -1325,7 +1313,7 @@
     out('}');
   }
 
-  fromClauseOut(LiteralString from) {
+  void fromClauseOut(LiteralString from) {
     out(' from');
     spaceOut();
     out("'${from.valueWithoutQuotes}.js'");
@@ -1333,11 +1321,11 @@
 
   /// This is unused, see [nameSpecifierOut].
   @override
-  visitNameSpecifier(NameSpecifier node) {
+  void visitNameSpecifier(NameSpecifier node) {
     throw UnsupportedError('visitNameSpecifier');
   }
 
-  nameSpecifierOut(NameSpecifier node, bool export) {
+  void nameSpecifierOut(NameSpecifier node, bool export) {
     if (node.isStar) {
       out('*');
     } else {
@@ -1364,45 +1352,45 @@
   }
 
   @override
-  visitLiteralExpression(LiteralExpression node) {
+  void visitLiteralExpression(LiteralExpression node) {
     out(node.template);
   }
 
   @override
-  visitLiteralStatement(LiteralStatement node) {
+  void visitLiteralStatement(LiteralStatement node) {
     outLn(node.code);
   }
 
-  visitInterpolatedNode(InterpolatedNode node) {
+  void visitInterpolatedNode(InterpolatedNode node) {
     out('#${node.nameOrPosition}');
   }
 
   @override
-  visitInterpolatedExpression(InterpolatedExpression node) =>
+  void visitInterpolatedExpression(InterpolatedExpression node) =>
       visitInterpolatedNode(node);
 
   @override
-  visitInterpolatedLiteral(InterpolatedLiteral node) =>
+  void visitInterpolatedLiteral(InterpolatedLiteral node) =>
       visitInterpolatedNode(node);
 
   @override
-  visitInterpolatedParameter(InterpolatedParameter node) =>
+  void visitInterpolatedParameter(InterpolatedParameter node) =>
       visitInterpolatedNode(node);
 
   @override
-  visitInterpolatedSelector(InterpolatedSelector node) =>
+  void visitInterpolatedSelector(InterpolatedSelector node) =>
       visitInterpolatedNode(node);
 
   @override
-  visitInterpolatedMethod(InterpolatedMethod node) =>
+  void visitInterpolatedMethod(InterpolatedMethod node) =>
       visitInterpolatedNode(node);
 
   @override
-  visitInterpolatedIdentifier(InterpolatedIdentifier node) =>
+  void visitInterpolatedIdentifier(InterpolatedIdentifier node) =>
       visitInterpolatedNode(node);
 
   @override
-  visitInterpolatedStatement(InterpolatedStatement node) {
+  void visitInterpolatedStatement(InterpolatedStatement node) {
     outLn('#${node.nameOrPosition}');
   }
 
@@ -1435,7 +1423,7 @@
 
   @override
   void visitAwait(Await node) {
-    out("await ");
+    out('await ');
     visit(node.expression);
   }
 }
@@ -1452,8 +1440,8 @@
         vars = {},
         params = {};
 
-  void forEachVar(void fn(String v)) => vars.forEach(fn);
-  void forEachParam(void fn(String p)) => params.forEach(fn);
+  void forEachVar(void Function(String) fn) => vars.forEach(fn);
+  void forEachParam(void Function(String) fn) => params.forEach(fn);
 
   void collectVarsInFunction(FunctionExpression fun) {
     if (!nested) {
@@ -1535,7 +1523,7 @@
 
   @override
   bool visitNode(Node node) {
-    context.error("Forgot node: $node");
+    context.error('Forgot node: $node');
     return true;
   }
 
@@ -1661,8 +1649,8 @@
 
   static int nthLetter(int n) {
     return (n < LOWER_CASE_LETTERS)
-        ? charCodes.$a + n
-        : charCodes.$A + n - LOWER_CASE_LETTERS;
+        ? char_codes.$a + n
+        : char_codes.$A + n - LOWER_CASE_LETTERS;
   }
 
   // Parameters go from a to z and variables go from z to a.  This makes each
@@ -1734,7 +1722,7 @@
         nameSpaceSize ~/= LETTERS;
         codes.add(nthLetter((n ~/ nameSpaceSize) % LETTERS));
       }
-      codes.add(charCodes.$0 + digit);
+      codes.add(char_codes.$0 + digit);
       newName = String.fromCharCodes(codes);
     }
     assert(RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName));
@@ -1746,15 +1734,15 @@
 /// Like [BaseVisitor], but calls [declare] for [Identifier] declarations, and
 /// [visitIdentifier] otherwise.
 abstract class VariableDeclarationVisitor extends BaseVisitorVoid {
-  declare(Identifier node);
+  void declare(Identifier node);
 
   @override
-  visitFunctionExpression(FunctionExpression node) {
+  void visitFunctionExpression(FunctionExpression node) {
     node.params.forEach(_scanVariableBinding);
     node.body.accept(this);
   }
 
-  _scanVariableBinding(VariableBinding d) {
+  void _scanVariableBinding(VariableBinding d) {
     if (d is Identifier) {
       declare(d);
     } else {
@@ -1763,50 +1751,50 @@
   }
 
   @override
-  visitRestParameter(RestParameter node) {
+  void visitRestParameter(RestParameter node) {
     _scanVariableBinding(node.parameter);
     super.visitRestParameter(node);
   }
 
   @override
-  visitDestructuredVariable(DestructuredVariable node) {
+  void visitDestructuredVariable(DestructuredVariable node) {
     var name = node.name;
     _scanVariableBinding(name);
     super.visitDestructuredVariable(node);
   }
 
   @override
-  visitSimpleBindingPattern(SimpleBindingPattern node) {
+  void visitSimpleBindingPattern(SimpleBindingPattern node) {
     _scanVariableBinding(node.name);
     super.visitSimpleBindingPattern(node);
   }
 
   @override
-  visitVariableInitialization(VariableInitialization node) {
+  void visitVariableInitialization(VariableInitialization node) {
     _scanVariableBinding(node.declaration);
     node.value?.accept(this);
   }
 
   @override
-  visitCatch(Catch node) {
+  void visitCatch(Catch node) {
     declare(node.declaration);
     node.body.accept(this);
   }
 
   @override
-  visitFunctionDeclaration(FunctionDeclaration node) {
+  void visitFunctionDeclaration(FunctionDeclaration node) {
     declare(node.name);
     node.function.accept(this);
   }
 
   @override
-  visitNamedFunction(NamedFunction node) {
+  void visitNamedFunction(NamedFunction node) {
     declare(node.name);
     node.function.accept(this);
   }
 
   @override
-  visitClassExpression(ClassExpression node) {
+  void visitClassExpression(ClassExpression node) {
     declare(node.name);
     node.heritage?.accept(this);
     for (Method element in node.methods) {
diff --git a/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart b/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart
index dcc1675..ac4f62f 100644
--- a/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/source_map_printer.dart
@@ -2,11 +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: omit_local_variable_types
-
 import 'package:source_maps/source_maps.dart' hide Printer;
 import 'package:source_span/source_span.dart' show SourceLocation;
 import 'js_ast.dart';
@@ -28,14 +23,14 @@
   final SourceLocation end;
   NodeEnd(this.end);
   @override
-  toString() => '#<NodeEnd $end>';
+  String toString() => '#<NodeEnd $end>';
 }
 
 class NodeSpan {
   final SourceLocation start, end;
   NodeSpan(this.start, this.end);
   @override
-  toString() => '#<NodeSpan $start to $end>';
+  String toString() => '#<NodeSpan $start to $end>';
 }
 
 class HoverComment {
@@ -43,7 +38,7 @@
   final Expression expression;
   HoverComment(this.expression, this.start, this.end);
   @override
-  toString() => '#<HoverComment `$expression` @ $start to $end>';
+  String toString() => '#<HoverComment `$expression` @ $start to $end>';
 }
 
 class SourceMapPrintingContext extends SimpleJavaScriptPrintingContext {
@@ -59,14 +54,14 @@
   /// The last marked line in the buffer.
   int _previousDartOffset = -1;
 
-  SourceLocation _pendingDartOffset;
-  SourceLocation _pendingJSLocation;
+  SourceLocation? _pendingDartOffset;
+  SourceLocation? _pendingJSLocation;
 
   @override
   void emit(String code) {
     var chars = code.runes.toList();
     var length = chars.length;
-    for (int i = 0; i < length; i++) {
+    for (var i = 0; i < length; i++) {
       var c = chars[i];
       if (c == _LF || (c == _CR && (i + 1 == length || chars[i + 1] != _LF))) {
         // Return not followed by line-feed is treated as a new line.
@@ -84,7 +79,7 @@
     var srcInfo = node.sourceInformation;
     if (srcInfo == null || srcInfo == continueSourceMap) return;
 
-    SourceLocation dartStart;
+    SourceLocation? dartStart;
     if (srcInfo is SourceLocation) {
       dartStart = srcInfo;
     } else if (srcInfo is NodeSpan) {
@@ -116,7 +111,7 @@
     var srcInfo = node.sourceInformation;
     if (srcInfo == null || srcInfo == continueSourceMap) return;
 
-    SourceLocation dartEnd;
+    SourceLocation? dartEnd;
     if (srcInfo is NodeSpan) {
       dartEnd = srcInfo.end;
     } else if (srcInfo is NodeEnd) {
@@ -130,7 +125,7 @@
       if (node is Fun || node is Method || node is NamedFunction) {
         // Mark the exit point of a function. V8 steps to the end of a function
         // at its exit, so this provides a mapping for that location.
-        int column = _column - 1;
+        var column = _column - 1;
         if (column >= 0) {
           // Adjust the colum, because any ending brace or semicolon is already in
           // the output.
@@ -169,13 +164,13 @@
   void _flushPendingMarks() {
     var pending = _pendingDartOffset;
     if (pending != null) {
-      _markInternal(pending, _pendingJSLocation);
+      _markInternal(pending, _pendingJSLocation!);
       _pendingDartOffset = null;
       _pendingJSLocation = null;
     }
   }
 
-  void _mark(SourceLocation dartLocation, [SourceLocation jsLocation]) {
+  void _mark(SourceLocation dartLocation, [SourceLocation? jsLocation]) {
     _flushPendingMarks();
     jsLocation ??= _getJSLocation();
     _markInternal(dartLocation, jsLocation);
diff --git a/pkg/dev_compiler/lib/src/js_ast/template.dart b/pkg/dev_compiler/lib/src/js_ast/template.dart
index 22d76d7..ff90080 100644
--- a/pkg/dev_compiler/lib/src/js_ast/template.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/template.dart
@@ -2,10 +2,7 @@
 // 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.
 
-// ignore_for_file: always_declare_return_types
 // ignore_for_file: omit_local_variable_types
-// ignore_for_file: prefer_generic_function_type_aliases
-// ignore_for_file: prefer_single_quotes
 
 library js_ast.template;
 
@@ -51,10 +48,11 @@
   final bool forceCopy;
   final Node ast;
   final Instantiator instantiator;
-  int positionalArgumentCount = -1;
+  final int positionalArgumentCount;
 
-  // Null, unless there are named holes.
-  List<String> holeNames;
+  // Names of named holes, empty if there are no named holes.
+  final List<String> holeNames;
+
   bool get isPositional => holeNames.isEmpty;
 
   Template._(this.source, this.ast,
@@ -95,7 +93,7 @@
     assert(_checkNoPlaceholders(ast));
     return Template._(null, ast,
         instantiator: (arguments) => ast,
-        isExpression: true,
+        isExpression: false,
         forceCopy: false,
         positionalArgumentCount: 0);
   }
@@ -114,27 +112,28 @@
     if (arguments is List) {
       if (arguments.length != positionalArgumentCount) {
         throw 'Wrong number of template arguments, given ${arguments.length}, '
-            'expected $positionalArgumentCount:\n$source';
+            'expected $positionalArgumentCount'
+            ', source: "$source"';
       }
       return instantiator(arguments) as Node;
     }
     if (arguments is Map) {
       if (holeNames.length < arguments.length) {
-        // This search is in O(n), but we only do it in case of a new
-        // StateError, and the number of holes should be quite limited.
+        // 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";
+            .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";
+            holeNames.where((name) => !arguments.containsKey(name)).join(', ');
+        throw 'Template arguments is missing mappings for: $notFound';
       }
       return instantiator(arguments) as Node;
     }
-    throw ArgumentError.value(arguments, 'must be a List or Map');
+    throw ArgumentError.value(arguments, 'arguments', 'Must be a List or Map');
   }
 }
 
@@ -142,11 +141,11 @@
 /// trees.
 ///
 /// [arguments] is a List for positional templates, or Map for named templates.
-typedef T Instantiator<T>(arguments);
+typedef Instantiator<T> = T Function(dynamic);
 
-/// InstantiatorGeneratorVisitor compiles a template.  This class compiles a tree
-/// containing [InterpolatedNode]s into a function that will create a copy of the
-/// tree with the interpolated nodes substituted with provided values.
+/// InstantiatorGeneratorVisitor compiles a template.  This class compiles a
+/// tree containing [InterpolatedNode]s into a function that will create a copy
+/// of the tree with the interpolated nodes substituted with provided values.
 class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
   final bool forceCopy;
 
@@ -341,7 +340,7 @@
   @override
   Instantiator<Program> visitProgram(Program node) {
     var instantiators = node.body.map(visitSplayableStatement).toList();
-    return (a) => Program(splayStatements(instantiators, a));
+    return (arguments) => Program(splayStatements(instantiators, arguments));
   }
 
   List<Statement> splayStatements(List<Instantiator> instantiators, arguments) {
@@ -350,9 +349,7 @@
       var node = instantiator(arguments);
       if (node is EmptyStatement) continue;
       if (node is Iterable) {
-        for (var n in node) {
-          statements.add(n as Statement);
-        }
+        statements.addAll(node as Iterable<Statement>);
       } else if (node is Block && !node.isScope) {
         statements.addAll(node.statements);
       } else {
@@ -365,26 +362,26 @@
   @override
   Instantiator<Block> visitBlock(Block node) {
     var instantiators = node.statements.map(visitSplayableStatement).toList();
-    return (a) => Block(splayStatements(instantiators, a));
+    return (arguments) => Block(splayStatements(instantiators, arguments));
   }
 
   @override
   Instantiator<Statement> visitExpressionStatement(ExpressionStatement node) {
     var makeExpression = visit(node.expression) as Instantiator<Expression>;
-    return (a) => makeExpression(a).toStatement();
+    return (arguments) => makeExpression(arguments).toStatement();
   }
 
   @override
   Instantiator<DebuggerStatement> visitDebuggerStatement(node) =>
-      (a) => DebuggerStatement();
+      (arguments) => DebuggerStatement();
 
   @override
   Instantiator<EmptyStatement> visitEmptyStatement(EmptyStatement node) =>
-      (a) => EmptyStatement();
+      (arguments) => EmptyStatement();
 
   @override
   Instantiator<Statement> visitIf(If node) {
-    var condition = node.condition;
+    final condition = node.condition;
     if (condition is InterpolatedExpression) {
       return visitIfConditionalCompilation(node, condition);
     } else {
@@ -403,8 +400,9 @@
       if (value is bool) {
         return value ? makeThen(arguments) : makeOtherwise(arguments);
       }
-      var cond = value is String ? Identifier(value) : value as Expression;
-      return If(cond, makeThen(arguments), makeOtherwise(arguments));
+      var newCondition =
+          value is String ? Identifier(value) : value as Expression;
+      return If(newCondition, makeThen(arguments), makeOtherwise(arguments));
     };
   }
 
@@ -412,7 +410,8 @@
     var makeCondition = visit(node.condition) as Instantiator<Expression>;
     var makeThen = visit(node.then) as Instantiator<Statement>;
     var makeOtherwise = visit(node.otherwise) as Instantiator<Statement>;
-    return (a) => If(makeCondition(a), makeThen(a), makeOtherwise(a));
+    return (arguments) => If(makeCondition(arguments), makeThen(arguments),
+        makeOtherwise(arguments));
   }
 
   @override
@@ -422,8 +421,8 @@
         visitNullable(node.condition) as Instantiator<Expression>;
     var makeUpdate = visitNullable(node.update) as Instantiator<Expression>;
     var makeBody = visit(node.body) as Instantiator<Statement>;
-    return (a) => For(makeInit(a), makeCondition(a),
-        makeUpdate(a).toVoidExpression(), makeBody(a));
+    return (arguments) => For(makeInit(arguments), makeCondition(arguments),
+        makeUpdate(arguments).toVoidExpression(), makeBody(arguments));
   }
 
   @override
@@ -431,7 +430,8 @@
     var makeLeftHandSide = visit(node.leftHandSide) as Instantiator<Expression>;
     var makeObject = visit(node.object) as Instantiator<Expression>;
     var makeBody = visit(node.body) as Instantiator<Statement>;
-    return (a) => ForIn(makeLeftHandSide(a), makeObject(a), makeBody(a));
+    return (arguments) => ForIn(makeLeftHandSide(arguments),
+        makeObject(arguments), makeBody(arguments));
   }
 
   @override
@@ -439,47 +439,49 @@
     var makeLeftHandSide = visit(node.leftHandSide) as Instantiator<Expression>;
     var makeObject = visit(node.iterable) as Instantiator<Expression>;
     var makeBody = visit(node.body) as Instantiator<Statement>;
-    return (a) => ForOf(makeLeftHandSide(a), makeObject(a), makeBody(a));
+    return (arguments) => ForOf(makeLeftHandSide(arguments),
+        makeObject(arguments), makeBody(arguments));
   }
 
   @override
   Instantiator<While> visitWhile(While node) {
     var makeCondition = visit(node.condition) as Instantiator<Expression>;
     var makeBody = visit(node.body) as Instantiator<Statement>;
-    return (a) => While(makeCondition(a), makeBody(a));
+    return (arguments) => While(makeCondition(arguments), makeBody(arguments));
   }
 
   @override
   Instantiator<Do> visitDo(Do node) {
     var makeBody = visit(node.body) as Instantiator<Statement>;
     var makeCondition = visit(node.condition) as Instantiator<Expression>;
-    return (a) => Do(makeBody(a), makeCondition(a));
+    return (arguments) => Do(makeBody(arguments), makeCondition(arguments));
   }
 
   @override
   Instantiator<Continue> visitContinue(Continue node) =>
-      (a) => Continue(node.targetLabel);
+      (arguments) => Continue(node.targetLabel);
 
   @override
-  Instantiator<Break> visitBreak(Break node) => (a) => Break(node.targetLabel);
+  Instantiator<Break> visitBreak(Break node) =>
+      (arguments) => Break(node.targetLabel);
 
   @override
   Instantiator<Statement> visitReturn(Return node) {
     if (node.value == null) return (args) => Return();
     var makeExpression = visit(node.value!) as Instantiator<Expression>;
-    return (a) => makeExpression(a).toReturn();
+    return (arguments) => makeExpression(arguments).toReturn();
   }
 
   @override
   Instantiator<DartYield> visitDartYield(DartYield node) {
     var makeExpression = visit(node.expression) as Instantiator<Expression>;
-    return (a) => DartYield(makeExpression(a), node.hasStar);
+    return (arguments) => DartYield(makeExpression(arguments), node.hasStar);
   }
 
   @override
   Instantiator<Throw> visitThrow(Throw node) {
     var makeExpression = visit(node.expression) as Instantiator<Expression>;
-    return (a) => Throw(makeExpression(a));
+    return (arguments) => Throw(makeExpression(arguments));
   }
 
   @override
@@ -487,14 +489,16 @@
     var makeBody = visit(node.body) as Instantiator<Block>;
     var makeCatch = visitNullable(node.catchPart) as Instantiator<Catch?>;
     var makeFinally = visitNullable(node.finallyPart) as Instantiator<Block?>;
-    return (a) => Try(makeBody(a), makeCatch(a), makeFinally(a));
+    return (arguments) =>
+        Try(makeBody(arguments), makeCatch(arguments), makeFinally(arguments));
   }
 
   @override
   Instantiator<Catch> visitCatch(Catch node) {
     var makeDeclaration = visit(node.declaration) as Instantiator<Identifier>;
     var makeBody = visit(node.body) as Instantiator<Block>;
-    return (a) => Catch(makeDeclaration(a), makeBody(a));
+    return (arguments) =>
+        Catch(makeDeclaration(arguments), makeBody(arguments));
   }
 
   @override
@@ -502,11 +506,12 @@
     var makeKey = visit(node.key) as Instantiator<Expression>;
     var makeCases =
         node.cases.map((c) => visit(c) as Instantiator<SwitchClause>);
-    return (a) => Switch(makeKey(a), makeCases.map((m) => m(a)).toList());
+    return (arguments) => Switch(makeKey(arguments),
+        makeCases.map((makeCase) => makeCase(arguments)).toList());
   }
 
   @override
-  Instantiator visitCase(Case node) {
+  Instantiator<Case> visitCase(Case node) {
     var makeExpression = visit(node.expression) as Instantiator<Expression>;
     var makeBody = visit(node.body) as Instantiator<Block>;
     return (arguments) {
@@ -515,7 +520,7 @@
   }
 
   @override
-  Instantiator visitDefault(Default node) {
+  Instantiator<Default> visitDefault(Default node) {
     var makeBody = visit(node.body) as Instantiator<Block>;
     return (arguments) {
       return Default(makeBody(arguments));
@@ -527,13 +532,14 @@
       FunctionDeclaration node) {
     var makeName = visit(node.name) as Instantiator<Identifier>;
     var makeFunction = visit(node.function) as Instantiator<Fun>;
-    return (a) => FunctionDeclaration(makeName(a), makeFunction(a));
+    return (arguments) =>
+        FunctionDeclaration(makeName(arguments), makeFunction(arguments));
   }
 
   @override
   Instantiator<LabeledStatement> visitLabeledStatement(LabeledStatement node) {
     var makeBody = visit(node.body) as Instantiator<Statement>;
-    return (a) => LabeledStatement(node.label, makeBody(a));
+    return (arguments) => LabeledStatement(node.label, makeBody(arguments));
   }
 
   @override
@@ -547,8 +553,8 @@
       VariableDeclarationList node) {
     var declarationMakers =
         node.declarations.map(visitVariableInitialization).toList();
-    return (a) => VariableDeclarationList(
-        node.keyword, declarationMakers.map((m) => m(a)).toList());
+    return (arguments) => VariableDeclarationList(
+        node.keyword, declarationMakers.map((m) => m(arguments)).toList());
   }
 
   @override
@@ -568,7 +574,8 @@
     var makeDeclaration =
         visit(node.declaration) as Instantiator<VariableBinding>;
     var makeValue = visitNullable(node.value) as Instantiator<Expression?>;
-    return (a) => VariableInitialization(makeDeclaration(a), makeValue(a));
+    return (arguments) => VariableInitialization(
+        makeDeclaration(arguments), makeValue(arguments));
   }
 
   @override
@@ -576,7 +583,8 @@
     var makeCondition = visit(cond.condition) as Instantiator<Expression>;
     var makeThen = visit(cond.then) as Instantiator<Expression>;
     var makeOtherwise = visit(cond.otherwise) as Instantiator<Expression>;
-    return (a) => Conditional(makeCondition(a), makeThen(a), makeOtherwise(a));
+    return (arguments) => Conditional(makeCondition(arguments),
+        makeThen(arguments), makeOtherwise(arguments));
   }
 
   @override
@@ -591,9 +599,9 @@
 
     // TODO(sra): Avoid copying call arguments if no interpolation or forced
     // copying.
-    return (a) {
-      var target = makeTarget(a);
-      var callArgs = splayNodes<Expression>(argumentMakers, a);
+    return (arguments) {
+      var target = makeTarget(arguments);
+      var callArgs = splayNodes<Expression>(argumentMakers, arguments);
       return isNew ? New(target, callArgs) : Call(target, callArgs);
     };
   }
@@ -603,69 +611,73 @@
     var makeLeft = visit(node.left) as Instantiator<Expression>;
     var makeRight = visit(node.right) as Instantiator<Expression>;
     String op = node.op;
-    return (a) => Binary(op, makeLeft(a), makeRight(a));
+    return (arguments) => Binary(op, makeLeft(arguments), makeRight(arguments));
   }
 
   @override
   Instantiator<Prefix> visitPrefix(Prefix node) {
     var makeOperand = visit(node.argument) as Instantiator<Expression>;
     String op = node.op;
-    return (a) => Prefix(op, makeOperand(a));
+    return (arguments) => Prefix(op, makeOperand(arguments));
   }
 
   @override
   Instantiator<Postfix> visitPostfix(Postfix node) {
     var makeOperand = visit(node.argument) as Instantiator<Expression>;
     String op = node.op;
-    return (a) => Postfix(op, makeOperand(a));
+    return (arguments) => Postfix(op, makeOperand(arguments));
   }
 
   @override
-  Instantiator<This> visitThis(This node) => (a) => This();
+  Instantiator<This> visitThis(This node) => (arguments) => This();
   @override
-  Instantiator<Super> visitSuper(Super node) => (a) => Super();
+  Instantiator<Super> visitSuper(Super node) => (arguments) => Super();
 
   @override
   Instantiator<Identifier> visitIdentifier(Identifier node) =>
-      (a) => Identifier(node.name);
+      (arguments) => Identifier(node.name);
 
   @override
   Instantiator<Spread> visitSpread(Spread node) {
     var maker = visit(node.argument);
-    return (a) => Spread(maker(a) as Expression);
+    return (arguments) => Spread(maker(arguments) as Expression);
   }
 
   @override
   Instantiator<Yield> visitYield(Yield node) {
     var maker = visitNullable(node.value);
-    return (a) => Yield(maker(a) as Expression, star: node.star);
+    return (arguments) =>
+        Yield(maker(arguments) as Expression, star: node.star);
   }
 
   @override
   Instantiator<RestParameter> visitRestParameter(RestParameter node) {
     var maker = visit(node.parameter);
-    return (a) => RestParameter(maker(a) as Identifier);
+    return (arguments) => RestParameter(maker(arguments) as Identifier);
   }
 
   @override
   Instantiator<PropertyAccess> visitAccess(PropertyAccess node) {
     var makeReceiver = visit(node.receiver) as Instantiator<Expression>;
     var makeSelector = visit(node.selector) as Instantiator<Expression>;
-    return (a) => PropertyAccess(makeReceiver(a), makeSelector(a));
+    return (arguments) =>
+        PropertyAccess(makeReceiver(arguments), makeSelector(arguments));
   }
 
   @override
   Instantiator<NamedFunction> visitNamedFunction(NamedFunction node) {
     var makeDeclaration = visit(node.name) as Instantiator<Identifier>;
     var makeFunction = visit(node.function) as Instantiator<Fun>;
-    return (a) => NamedFunction(makeDeclaration(a), makeFunction(a));
+    return (arguments) =>
+        NamedFunction(makeDeclaration(arguments), makeFunction(arguments));
   }
 
   @override
   Instantiator<Fun> visitFun(Fun node) {
     var paramMakers = node.params.map(visitSplayable).toList();
     var makeBody = visit(node.body) as Instantiator<Block>;
-    return (a) => Fun(splayNodes(paramMakers, a), makeBody(a),
+    return (arguments) => Fun(
+        splayNodes(paramMakers, arguments), makeBody(arguments),
         isGenerator: node.isGenerator, asyncModifier: node.asyncModifier);
   }
 
@@ -673,33 +685,34 @@
   Instantiator<ArrowFun> visitArrowFun(ArrowFun node) {
     var paramMakers = node.params.map(visitSplayable).toList();
     Instantiator makeBody = visit(node.body);
-    return (a) => ArrowFun(splayNodes(paramMakers, a), makeBody(a) as Node);
+    return (arguments) => ArrowFun(
+        splayNodes(paramMakers, arguments), makeBody(arguments) as Node);
   }
 
   @override
   Instantiator<LiteralBool> visitLiteralBool(LiteralBool node) =>
-      (a) => LiteralBool(node.value);
+      (arguments) => LiteralBool(node.value);
 
   @override
   Instantiator<LiteralString> visitLiteralString(LiteralString node) =>
-      (a) => LiteralString(node.value);
+      (arguments) => LiteralString(node.value);
 
   @override
   Instantiator<LiteralNumber> visitLiteralNumber(LiteralNumber node) =>
-      (a) => LiteralNumber(node.value);
+      (arguments) => LiteralNumber(node.value);
 
   @override
   Instantiator<LiteralNull> visitLiteralNull(LiteralNull node) =>
-      (a) => LiteralNull();
+      (arguments) => LiteralNull();
 
   @override
   Instantiator<ArrayInitializer> visitArrayInitializer(ArrayInitializer node) {
     var makers = node.elements.map(visitSplayableExpression).toList();
-    return (a) => ArrayInitializer(splayNodes(makers, a));
+    return (arguments) => ArrayInitializer(splayNodes(makers, arguments));
   }
 
   @override
-  Instantiator visitArrayHole(ArrayHole node) {
+  Instantiator<ArrayHole> visitArrayHole(ArrayHole node) {
     return (arguments) => ArrayHole();
   }
 
@@ -707,37 +720,40 @@
   Instantiator<ObjectInitializer> visitObjectInitializer(
       ObjectInitializer node) {
     var propertyMakers = node.properties.map(visitSplayable).toList();
-    return (a) => ObjectInitializer(splayNodes(propertyMakers, a));
+    return (arguments) =>
+        ObjectInitializer(splayNodes(propertyMakers, arguments));
   }
 
   @override
   Instantiator<Property> visitProperty(Property node) {
     var makeName = visit(node.name) as Instantiator<Expression>;
     var makeValue = visit(node.value) as Instantiator<Expression>;
-    return (a) => Property(makeName(a), makeValue(a));
+    return (arguments) => Property(makeName(arguments), makeValue(arguments));
   }
 
   @override
   Instantiator<RegExpLiteral> visitRegExpLiteral(RegExpLiteral node) =>
-      (a) => RegExpLiteral(node.pattern);
+      (arguments) => RegExpLiteral(node.pattern);
 
   @override
   Instantiator<TemplateString> visitTemplateString(TemplateString node) {
     var makeElements = node.interpolations.map(visit).toList();
-    return (a) => TemplateString(node.strings, splayNodes(makeElements, a));
+    return (arguments) =>
+        TemplateString(node.strings, splayNodes(makeElements, arguments));
   }
 
   @override
   Instantiator<TaggedTemplate> visitTaggedTemplate(TaggedTemplate node) {
     var makeTag = visit(node.tag) as Instantiator<Expression>;
     var makeTemplate = visitTemplateString(node.template);
-    return (a) => TaggedTemplate(makeTag(a), makeTemplate(a));
+    return (arguments) =>
+        TaggedTemplate(makeTag(arguments), makeTemplate(arguments));
   }
 
   @override
-  Instantiator visitClassDeclaration(ClassDeclaration node) {
+  Instantiator<ClassDeclaration> visitClassDeclaration(ClassDeclaration node) {
     var makeClass = visitClassExpression(node.classExpr);
-    return (a) => ClassDeclaration(makeClass(a));
+    return (arguments) => ClassDeclaration(makeClass(arguments));
   }
 
   @override
@@ -747,15 +763,15 @@
     var makeHeritage =
         visitNullable(node.heritage) as Instantiator<Expression?>;
 
-    return (a) => ClassExpression(
-        makeName(a), makeHeritage(a), splayNodes(makeMethods, a));
+    return (arguments) => ClassExpression(makeName(arguments),
+        makeHeritage(arguments), splayNodes(makeMethods, arguments));
   }
 
   @override
   Instantiator<Method> visitMethod(Method node) {
     var makeName = visit(node.name) as Instantiator<Expression>;
     var makeFunction = visit(node.function) as Instantiator<Fun>;
-    return (a) => Method(makeName(a), makeFunction(a),
+    return (arguments) => Method(makeName(arguments), makeFunction(arguments),
         isGetter: node.isGetter,
         isSetter: node.isSetter,
         isStatic: node.isStatic);
@@ -763,19 +779,19 @@
 
   @override
   Instantiator<Comment> visitComment(Comment node) =>
-      (a) => Comment(node.comment);
+      (arguments) => Comment(node.comment);
 
   @override
   Instantiator<CommentExpression> visitCommentExpression(
       CommentExpression node) {
     var makeExpr = visit(node.expression) as Instantiator<Expression>;
-    return (a) => CommentExpression(node.comment, makeExpr(a));
+    return (arguments) => CommentExpression(node.comment, makeExpr(arguments));
   }
 
   @override
   Instantiator<Await> visitAwait(Await node) {
     var makeExpr = visit(node.expression) as Instantiator<Expression>;
-    return (a) => Await(makeExpr(a));
+    return (arguments) => Await(makeExpr(arguments));
   }
 
   @override
@@ -804,29 +820,31 @@
         visitNullable(node.structure) as Instantiator<BindingPattern?>;
     var makeDefaultValue =
         visitNullable(node.defaultValue) as Instantiator<Expression?>;
-    return (a) => DestructuredVariable(
-        name: makeName(a),
-        property: makeProperty(a),
-        structure: makeStructure(a),
-        defaultValue: makeDefaultValue(a));
+    return (arguments) => DestructuredVariable(
+        name: makeName(arguments),
+        property: makeProperty(arguments),
+        structure: makeStructure(arguments),
+        defaultValue: makeDefaultValue(arguments));
   }
 
   @override
   Instantiator<ArrayBindingPattern> visitArrayBindingPattern(
       ArrayBindingPattern node) {
     List<Instantiator> makeVars = node.variables.map(visit).toList();
-    return (a) => ArrayBindingPattern(splayNodes(makeVars, a));
+    return (arguments) => ArrayBindingPattern(splayNodes(makeVars, arguments));
   }
 
   @override
-  Instantiator visitObjectBindingPattern(ObjectBindingPattern node) {
+  Instantiator<ObjectBindingPattern> visitObjectBindingPattern(
+      ObjectBindingPattern node) {
     List<Instantiator> makeVars = node.variables.map(visit).toList();
-    return (a) => ObjectBindingPattern(splayNodes(makeVars, a));
+    return (arguments) => ObjectBindingPattern(splayNodes(makeVars, arguments));
   }
 
   @override
-  Instantiator visitSimpleBindingPattern(SimpleBindingPattern node) =>
-      (a) => SimpleBindingPattern(Identifier(node.name.name));
+  Instantiator<SimpleBindingPattern> visitSimpleBindingPattern(
+          SimpleBindingPattern node) =>
+      (arguments) => SimpleBindingPattern(Identifier(node.name.name));
 }
 
 /// InterpolatedNodeAnalysis determines which AST trees contain
@@ -853,7 +871,7 @@
   }
 
   @override
-  visitInterpolatedNode(InterpolatedNode node) {
+  void visitInterpolatedNode(InterpolatedNode node) {
     containsInterpolatedNode.add(node);
     if (node.isNamed) holeNames.add(node.nameOrPosition as String);
     ++count;
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 0f4ece3..7a7f204 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -748,7 +748,7 @@
     }
 
     body = [classDef];
-    _emitStaticFields(c, body);
+    _emitStaticFieldsAndAccessors(c, body);
     if (finishGenericTypeTest != null) body.add(finishGenericTypeTest);
     for (var peer in jsPeerNames) {
       _registerExtensionType(c, peer, body);
@@ -1323,12 +1323,16 @@
 
   /// Emits static fields for a class, and initialize them eagerly if possible,
   /// otherwise define them as lazy properties.
-  void _emitStaticFields(Class c, List<js_ast.Statement> body) {
+  void _emitStaticFieldsAndAccessors(Class c, List<js_ast.Statement> body) {
     var fields = c.fields
         .where((f) => f.isStatic && !isRedirectingFactoryField(f))
         .toList();
+    var fieldNames = Set.from(fields.map((f) => f.name));
+    var staticSetters = c.procedures.where(
+        (p) => p.isStatic && p.isAccessor && fieldNames.contains(p.name));
+    var members = [...fields, ...staticSetters];
     if (fields.isNotEmpty) {
-      body.add(_emitLazyFields(_emitTopLevelName(c), fields,
+      body.add(_emitLazyMembers(_emitTopLevelName(c), members,
           (n) => _emitStaticMemberName(n.name.text)));
     }
   }
@@ -1847,10 +1851,13 @@
     }
 
     Set<Member> redirectingFactories;
+    var staticFieldNames = <Name>{};
     for (var m in c.fields) {
       if (m.isStatic) {
         if (isRedirectingFactoryField(m)) {
           redirectingFactories = getRedirectingFactories(m).toSet();
+        } else {
+          staticFieldNames.add(m.name);
         }
       } else if (_extensionTypes.isNativeClass(c)) {
         jsMethods.addAll(_emitNativeFieldAccessors(m));
@@ -1872,6 +1879,11 @@
 
     var savedUri = _currentUri;
     for (var m in c.procedures) {
+      // Static accessors on static/lazy fields are emitted earlier in
+      // `_emitStaticFieldsAndAccessors`.
+      if (m.isStatic && m.isAccessor && staticFieldNames.contains(m.name)) {
+        continue;
+      }
       _staticTypeContext.enterMember(m);
       // For the Dart SDK, we use the member URI because it may be different
       // from the class (because of patch files). User code does not need this.
@@ -2310,36 +2322,51 @@
     }
 
     if (fields.isEmpty) return;
-    moduleItems.add(_emitLazyFields(
+    moduleItems.add(_emitLazyMembers(
         emitLibraryName(_currentLibrary), fields, _emitTopLevelMemberName));
   }
 
-  js_ast.Statement _emitLazyFields(
-      js_ast.Expression objExpr,
-      Iterable<Field> fields,
-      js_ast.LiteralString Function(Field f) emitFieldName) {
+  js_ast.Statement _emitLazyMembers(
+    js_ast.Expression objExpr,
+    Iterable<Member> members,
+    js_ast.LiteralString Function(Member) emitMemberName,
+  ) {
     var accessors = <js_ast.Method>[];
     var savedUri = _currentUri;
 
-    for (var field in fields) {
-      _currentUri = field.fileUri;
-      _staticTypeContext.enterMember(field);
-      var access = emitFieldName(field);
-      memberNames[field] = access.valueWithoutQuotes;
-      accessors.add(js_ast.Method(access, _emitStaticFieldInitializer(field),
-          isGetter: true)
-        ..sourceInformation = _hoverComment(
-            js_ast.PropertyAccess(objExpr, access),
-            field.fileOffset,
-            field.name.text.length));
+    for (var member in members) {
+      _currentUri = member.fileUri;
+      _staticTypeContext.enterMember(member);
+      var access = emitMemberName(member);
+      memberNames[member] = access.valueWithoutQuotes;
 
-      // TODO(jmesserly): currently uses a dummy setter to indicate writable.
-      if (!field.isFinal && !field.isConst) {
+      if (member is Field) {
+        accessors.add(js_ast.Method(access, _emitStaticFieldInitializer(member),
+            isGetter: true)
+          ..sourceInformation = _hoverComment(
+              js_ast.PropertyAccess(objExpr, access),
+              member.fileOffset,
+              member.name.text.length));
+        if (!member.isFinal && !member.isConst) {
+          // TODO(jmesserly): currently uses a dummy setter to indicate
+          // writable.
+          accessors.add(js_ast.Method(
+              access, js.call('function(_) {}') as js_ast.Fun,
+              isSetter: true));
+        }
+      } else if (member is Procedure) {
         accessors.add(js_ast.Method(
-            access, js.call('function(_) {}') as js_ast.Fun,
-            isSetter: true));
+            access, _emitFunction(member.function, member.name.text),
+            isGetter: member.isGetter, isSetter: member.isSetter)
+          ..sourceInformation = _hoverComment(
+              js_ast.PropertyAccess(objExpr, access),
+              member.fileOffset,
+              member.name.text.length));
+      } else {
+        throw UnsupportedError(
+            'Unsupported lazy member type ${member.runtimeType}: $member');
       }
-      _staticTypeContext.leaveMember(field);
+      _staticTypeContext.leaveMember(member);
     }
     _currentUri = savedUri;
 
@@ -4777,9 +4804,9 @@
   @override
   js_ast.Expression visitStaticSet(StaticSet node) {
     var target = node.target;
+    var result = _emitStaticTarget(target);
     var value = isJsMember(target) ? _assertInterop(node.value) : node.value;
-    return _visitExpression(value)
-        .toAssignExpression(_emitStaticTarget(target));
+    return _visitExpression(value).toAssignExpression(result);
   }
 
   @override
diff --git a/pkg/dev_compiler/pubspec.yaml b/pkg/dev_compiler/pubspec.yaml
index acd4d9d..f84be03 100644
--- a/pkg/dev_compiler/pubspec.yaml
+++ b/pkg/dev_compiler/pubspec.yaml
@@ -30,7 +30,7 @@
     path: ../expect
   http_multi_server: any
   js: any
-  lints: ^1.0.0
+  lints: any
   modular_test:
     path: ../modular_test
   package_config: any
diff --git a/pkg/js_ast/analysis_options.yaml b/pkg/js_ast/analysis_options.yaml
index a1888bc..47e49e8 100644
--- a/pkg/js_ast/analysis_options.yaml
+++ b/pkg/js_ast/analysis_options.yaml
@@ -2,15 +2,24 @@
 # 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.
 
+include: package:lints/recommended.yaml
+
 analyzer:
   errors:
     todo: ignore
+    avoid_function_literals_in_foreach_calls: ignore
+    avoid_renaming_method_parameters: ignore
     # Allow deprecated calls from within the same package
     deprecated_member_use_from_same_package: ignore
+    constant_identifier_names: ignore
+    non_constant_identifier_names: ignore
+    prefer_void_to_null: ignore
 
 linter:
   rules:
-    - annotate_overrides
-    - prefer_final_fields
-    - prefer_if_null_operators
-    - prefer_null_aware_operators
+    # Not enforced by the lints package at any version.
+    - always_declare_return_types
+    - depend_on_referenced_packages
+    - directives_ordering
+    - prefer_single_quotes
+    - prefer_relative_imports
diff --git a/pkg/js_ast/lib/js_ast.dart b/pkg/js_ast/lib/js_ast.dart
index 8f75c74..024d331 100644
--- a/pkg/js_ast/lib/js_ast.dart
+++ b/pkg/js_ast/lib/js_ast.dart
@@ -6,8 +6,8 @@
 
 library js_ast;
 
-export 'src/nodes.dart';
 export 'src/builder.dart';
+export 'src/equivalence_visitor.dart';
+export 'src/nodes.dart';
 export 'src/printer.dart';
 export 'src/template.dart';
-export 'src/equivalence_visitor.dart';
diff --git a/pkg/js_ast/lib/src/builder.dart b/pkg/js_ast/lib/src/builder.dart
index cd92fab..60b5171 100644
--- a/pkg/js_ast/lib/src/builder.dart
+++ b/pkg/js_ast/lib/src/builder.dart
@@ -8,7 +8,7 @@
 /// parser that parses part of the language.
 library js_ast.builder;
 
-import 'characters.dart' as charCodes;
+import 'characters.dart' as char_codes;
 import 'nodes.dart';
 import 'template.dart';
 
@@ -135,7 +135,7 @@
 /// blocks to be appended.
 ///
 ///     var b1 = js.statement('{ 1; 2; }');
-///     var sEmpty = new Emptystatement();
+///     var sEmpty = new EmptyStatement();
 ///     js.statement('{ #; #; #; #; }', [sEmpty, b1, b1, sEmpty])
 ///     -->
 ///     { 1; 2; 1; 2; }
@@ -223,7 +223,7 @@
     // TODO(sra): Parse with extra validation to forbid `#` interpolation in
     // functions, as this leads to unanticipated capture of temporaries that are
     // reused after capture.
-    if (source.startsWith("throw ")) {
+    if (source.startsWith('throw ')) {
       return _findStatementTemplate(source);
     } else {
       return _findExpressionTemplate(source);
@@ -358,7 +358,7 @@
 }
 
 class MiniJsParserError {
-  MiniJsParserError(this.parser, this.message) {}
+  MiniJsParserError(this.parser, this.message);
 
   final MiniJsParser parser;
   final String message;
@@ -381,7 +381,7 @@
     // Replace non-tabs with spaces, giving a print indent that matches the text
     // for tabbing.
     String spaces = prefix.replaceAll(RegExp(r'[^\t]'), ' ');
-    return 'Error in MiniJsParser:\n${src}\n$spaces^\n$spaces$message\n';
+    return 'Error in MiniJsParser:\n$src\n$spaces^\n$spaces$message\n';
   }
 }
 
@@ -454,49 +454,49 @@
   static String categoryToString(int cat) {
     switch (cat) {
       case NONE:
-        return "NONE";
+        return 'NONE';
       case ALPHA:
-        return "ALPHA";
+        return 'ALPHA';
       case NUMERIC:
-        return "NUMERIC";
+        return 'NUMERIC';
       case SYMBOL:
-        return "SYMBOL";
+        return 'SYMBOL';
       case ASSIGNMENT:
-        return "ASSIGNMENT";
+        return 'ASSIGNMENT';
       case DOT:
-        return "DOT";
+        return 'DOT';
       case LPAREN:
-        return "LPAREN";
+        return 'LPAREN';
       case RPAREN:
-        return "RPAREN";
+        return 'RPAREN';
       case LBRACE:
-        return "LBRACE";
+        return 'LBRACE';
       case RBRACE:
-        return "RBRACE";
+        return 'RBRACE';
       case LSQUARE:
-        return "LSQUARE";
+        return 'LSQUARE';
       case RSQUARE:
-        return "RSQUARE";
+        return 'RSQUARE';
       case STRING:
-        return "STRING";
+        return 'STRING';
       case COMMA:
-        return "COMMA";
+        return 'COMMA';
       case QUERY:
-        return "QUERY";
+        return 'QUERY';
       case COLON:
-        return "COLON";
+        return 'COLON';
       case SEMICOLON:
-        return "SEMICOLON";
+        return 'SEMICOLON';
       case ARROW:
-        return "ARROW";
+        return 'ARROW';
       case HASH:
-        return "HASH";
+        return 'HASH';
       case WHITESPACE:
-        return "WHITESPACE";
+        return 'WHITESPACE';
       case OTHER:
-        return "OTHER";
+        return 'OTHER';
     }
-    return "Unknown: $cat";
+    return 'Unknown: $cat';
   }
 
   static const CATEGORIES = <int>[
@@ -595,16 +595,16 @@
     int currentCode;
     do {
       position++;
-      if (position >= src.length) error("Unterminated literal");
+      if (position >= src.length) error('Unterminated literal');
       currentCode = src.codeUnitAt(position);
-      if (currentCode == charCodes.$LF) error("Unterminated literal");
-      if (currentCode == charCodes.$BACKSLASH) {
-        if (++position >= src.length) error("Unterminated literal");
+      if (currentCode == char_codes.$LF) error('Unterminated literal');
+      if (currentCode == char_codes.$BACKSLASH) {
+        if (++position >= src.length) error('Unterminated literal');
         int escaped = src.codeUnitAt(position);
-        if (escaped == charCodes.$x ||
-            escaped == charCodes.$X ||
-            escaped == charCodes.$u ||
-            escaped == charCodes.$U ||
+        if (escaped == char_codes.$x ||
+            escaped == char_codes.$X ||
+            escaped == char_codes.$u ||
+            escaped == char_codes.$U ||
             category(escaped) == NUMERIC) {
           error('Numeric and hex escapes are not supported in RegExp literals');
         }
@@ -619,30 +619,30 @@
     position = startPosition + 1;
     final value = StringBuffer();
     while (true) {
-      if (position >= src.length) error("Unterminated literal");
+      if (position >= src.length) error('Unterminated literal');
       int code = src.codeUnitAt(position++);
       if (code == quote) break;
-      if (code == charCodes.$LF) error("Unterminated literal");
-      if (code == charCodes.$BACKSLASH) {
-        if (position >= src.length) error("Unterminated literal");
+      if (code == char_codes.$LF) error('Unterminated literal');
+      if (code == char_codes.$BACKSLASH) {
+        if (position >= src.length) error('Unterminated literal');
         code = src.codeUnitAt(position++);
-        if (code == charCodes.$f) {
+        if (code == char_codes.$f) {
           value.writeCharCode(12);
-        } else if (code == charCodes.$n) {
+        } else if (code == char_codes.$n) {
           value.writeCharCode(10);
-        } else if (code == charCodes.$r) {
+        } else if (code == char_codes.$r) {
           value.writeCharCode(13);
-        } else if (code == charCodes.$t) {
+        } else if (code == char_codes.$t) {
           value.writeCharCode(8);
-        } else if (code == charCodes.$BACKSLASH ||
-            code == charCodes.$SQ ||
-            code == charCodes.$DQ) {
+        } else if (code == char_codes.$BACKSLASH ||
+            code == char_codes.$SQ ||
+            code == char_codes.$DQ) {
           value.writeCharCode(code);
-        } else if (code == charCodes.$x || code == charCodes.$X) {
+        } else if (code == char_codes.$x || code == char_codes.$X) {
           error('Hex escapes not supported in string literals');
-        } else if (code == charCodes.$u || code == charCodes.$U) {
+        } else if (code == char_codes.$u || code == char_codes.$U) {
           error('Unicode escapes not supported in string literals');
-        } else if (charCodes.$0 <= code && code <= charCodes.$9) {
+        } else if (char_codes.$0 <= code && code <= char_codes.$9) {
           error('Numeric escapes not supported in string literals');
         } else {
           error('Unknown escape U+${code.toRadixString(16).padLeft(4, '0')}');
@@ -660,13 +660,13 @@
       if (position >= src.length) break;
       int code = src.codeUnitAt(position);
       //  Skip '//' and '/*' style comments.
-      if (code == charCodes.$SLASH && position + 1 < src.length) {
-        if (src.codeUnitAt(position + 1) == charCodes.$SLASH) {
+      if (code == char_codes.$SLASH && position + 1 < src.length) {
+        if (src.codeUnitAt(position + 1) == char_codes.$SLASH) {
           int nextPosition = src.indexOf('\n', position);
           if (nextPosition == -1) nextPosition = src.length;
           position = nextPosition;
           continue;
-        } else if (src.codeUnitAt(position + 1) == charCodes.$STAR) {
+        } else if (src.codeUnitAt(position + 1) == char_codes.$STAR) {
           int nextPosition = src.indexOf('*/', position + 2);
           if (nextPosition == -1) error('Unterminated comment');
           position = nextPosition + 2;
@@ -674,7 +674,7 @@
         }
       }
       if (category(code) != WHITESPACE) break;
-      if (code == charCodes.$LF) skippedNewline = true;
+      if (code == char_codes.$LF) skippedNewline = true;
       ++position;
     }
 
@@ -686,13 +686,13 @@
     }
     int code = src.codeUnitAt(position);
     lastPosition = position;
-    if (code == charCodes.$SQ || code == charCodes.$DQ) {
+    if (code == char_codes.$SQ || code == char_codes.$DQ) {
       // String literal.
       lastCategory = STRING;
       lastToken = getString(position, code);
-    } else if (code == charCodes.$0 &&
+    } else if (code == char_codes.$0 &&
         position + 2 < src.length &&
-        src.codeUnitAt(position + 1) == charCodes.$x) {
+        src.codeUnitAt(position + 1) == char_codes.$x) {
       // Hex literal.
       for (position += 2; position < src.length; position++) {
         int cat = category(src.codeUnitAt(position));
@@ -701,13 +701,13 @@
       lastCategory = NUMERIC;
       lastToken = src.substring(lastPosition, position);
       if (int.tryParse(lastToken) == null) {
-        error("Unparseable number");
+        error('Unparseable number');
       }
-    } else if (code == charCodes.$SLASH) {
+    } else if (code == char_codes.$SLASH) {
       // Tokens that start with / are special due to regexp literals.
       lastCategory = SYMBOL;
       position++;
-      if (position < src.length && src.codeUnitAt(position) == charCodes.$EQ) {
+      if (position < src.length && src.codeUnitAt(position) == char_codes.$EQ) {
         position++;
       }
       lastToken = src.substring(lastPosition, position);
@@ -722,9 +722,9 @@
         // Special code to disallow !, ~ and / in non-first position in token,
         // so that !! and ~~ parse as two tokens and != parses as one, while =/
         // parses as a an equals token followed by a regexp literal start.
-        newCat = (code == charCodes.$BANG ||
-                code == charCodes.$SLASH ||
-                code == charCodes.$TILDE)
+        newCat = (code == char_codes.$BANG ||
+                code == char_codes.$SLASH ||
+                code == char_codes.$TILDE)
             ? NONE
             : category(code);
       } while (!singleCharCategory(cat) &&
@@ -735,7 +735,7 @@
       lastToken = src.substring(lastPosition, position);
       if (cat == NUMERIC) {
         if (double.tryParse(lastToken) == null) {
-          error("Unparseable number");
+          error('Unparseable number');
         }
       } else if (cat == SYMBOL) {
         if (lastToken == '=>') {
@@ -744,7 +744,7 @@
           int? binaryPrecedence = BINARY_PRECEDENCE[lastToken];
           if (binaryPrecedence == null &&
               !UNARY_OPERATORS.contains(lastToken)) {
-            error("Unknown operator");
+            error('Unknown operator');
           }
           if (isAssignment(lastToken)) lastCategory = ASSIGNMENT;
         }
@@ -757,7 +757,7 @@
   }
 
   void expectCategory(int cat) {
-    if (cat != lastCategory) error("Expected ${categoryToString(cat)}");
+    if (cat != lastCategory) error('Expected ${categoryToString(cat)}');
     getToken();
   }
 
@@ -793,12 +793,12 @@
     return false;
   }
 
-  Never error(message) {
+  Never error(String message) {
     throw MiniJsParserError(this, message);
   }
 
   /// Returns either the name for the hole, or its integer position.
-  parseHash() {
+  Object parseHash() {
     String holeName = lastToken;
     if (acceptCategory(ALPHA)) {
       // Named hole. Example: 'function #funName() { ... }'
@@ -818,15 +818,15 @@
   Expression parsePrimary() {
     String last = lastToken;
     if (acceptCategory(ALPHA)) {
-      if (last == "true") {
+      if (last == 'true') {
         return LiteralBool(true);
-      } else if (last == "false") {
+      } else if (last == 'false') {
         return LiteralBool(false);
-      } else if (last == "null") {
+      } else if (last == 'null') {
         return LiteralNull();
-      } else if (last == "function") {
+      } else if (last == 'function') {
         return parseFunctionExpression();
-      } else if (last == "this") {
+      } else if (last == 'this') {
         return This();
       } else {
         return VariableUse(last);
@@ -852,11 +852,11 @@
         expectCategory(COMMA);
       }
       return ArrayInitializer(values);
-    } else if (last.startsWith("/")) {
+    } else if (last.startsWith('/')) {
       String regexp = getRegExp(lastPosition);
       getToken();
       String flags = lastToken;
-      if (!acceptCategory(ALPHA)) flags = "";
+      if (!acceptCategory(ALPHA)) flags = '';
       Expression expression = RegExpLiteral(regexp + flags);
       return expression;
     } else if (acceptCategory(HASH)) {
@@ -866,7 +866,7 @@
       interpolatedValues.add(expression);
       return expression;
     } else {
-      error("Expected primary expression");
+      error('Expected primary expression');
     }
   }
 
@@ -907,7 +907,7 @@
         asyncModifier = AsyncModifier.async;
       }
     } else if (acceptString('sync')) {
-      if (!acceptString('*')) error("Only sync* is valid - sync is implied");
+      if (!acceptString('*')) error('Only sync* is valid - sync is implied');
       asyncModifier = AsyncModifier.syncStar;
     } else {
       asyncModifier = AsyncModifier.sync;
@@ -974,7 +974,7 @@
   }
 
   Expression parseCall() {
-    bool constructor = acceptString("new");
+    bool constructor = acceptString('new');
     Expression receiver = parseMember();
     while (true) {
       if (acceptCategory(LPAREN)) {
@@ -998,7 +998,7 @@
         receiver = getDotRhs(receiver);
       } else {
         // JS allows new without (), but we don't.
-        if (constructor) error("Parentheses are required for new");
+        if (constructor) error('Parentheses are required for new');
         break;
       }
     }
@@ -1017,7 +1017,7 @@
     // names, and the IndexedDB API uses that, so we need to allow it here.
     if (acceptCategory(SYMBOL)) {
       if (!OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS.contains(identifier)) {
-        error("Expected alphanumeric identifier");
+        error('Expected alphanumeric identifier');
       }
     } else {
       expectCategory(ALPHA);
@@ -1032,7 +1032,7 @@
     //     LeftHandSideExpression [no LineTerminator here] ++
     if (lastCategory == SYMBOL &&
         !skippedNewline &&
-        (acceptString("++") || acceptString("--"))) {
+        (acceptString('++') || acceptString('--'))) {
       return Postfix(operator, expression);
     }
     // If we don't accept '++' or '--' due to skippedNewline a newline, no other
@@ -1045,8 +1045,8 @@
     String operator = lastToken;
     if (lastCategory == SYMBOL &&
         UNARY_OPERATORS.contains(operator) &&
-        (acceptString("++") || acceptString("--") || acceptString('await'))) {
-      if (operator == "await") return Await(parsePostfix());
+        (acceptString('++') || acceptString('--') || acceptString('await'))) {
+      if (operator == 'await') return Await(parsePostfix());
       return Prefix(operator, parsePostfix());
     }
     return parsePostfix();
@@ -1056,10 +1056,10 @@
     String operator = lastToken;
     if (lastCategory == SYMBOL &&
         UNARY_OPERATORS.contains(operator) &&
-        operator != "++" &&
-        operator != "--") {
+        operator != '++' &&
+        operator != '--') {
       expectCategory(SYMBOL);
-      if (operator == "await") return Await(parsePostfix());
+      if (operator == 'await') return Await(parsePostfix());
       return Prefix(operator, parseUnaryLow());
     }
     return parseUnaryHigh();
@@ -1108,7 +1108,7 @@
     String assignmentOperator = lastToken;
     if (acceptCategory(ASSIGNMENT)) {
       Expression rhs = parseAssignment();
-      if (assignmentOperator == "=") {
+      if (assignmentOperator == '=') {
         return Assignment(lhs, rhs);
       } else {
         // Handle +=, -=, etc.
@@ -1147,7 +1147,7 @@
         } else if (e is InterpolatedExpression) {
           params.add(InterpolatedParameter(e.nameOrPosition));
         } else {
-          error("Expected arrow function parameter list");
+          error('Expected arrow function parameter list');
         }
       }
       return parseArrowFunctionBody(params);
@@ -1176,8 +1176,8 @@
     var initialization = <VariableInitialization>[];
 
     void declare(Declaration declaration) {
-      Expression? initializer = null;
-      if (acceptString("=")) {
+      Expression? initializer;
+      if (acceptString('=')) {
         initializer = parseAssignment();
       }
       initialization.add(VariableInitialization(declaration, initializer));
@@ -1192,7 +1192,7 @@
   }
 
   Expression parseVarDeclarationOrExpression() {
-    if (acceptString("var")) {
+    if (acceptString('var')) {
       return parseVariableDeclarationList();
     } else {
       return parseExpression();
@@ -1202,7 +1202,7 @@
   Expression expression() {
     Expression expression = parseVarDeclarationOrExpression();
     if (lastCategory != NONE || position != src.length) {
-      error("Unparsed junk: ${categoryToString(lastCategory)}");
+      error('Unparsed junk: ${categoryToString(lastCategory)}');
     }
     return expression;
   }
@@ -1210,7 +1210,7 @@
   Statement statement() {
     Statement statement = parseStatement();
     if (lastCategory != NONE || position != src.length) {
-      error("Unparsed junk: ${categoryToString(lastCategory)}");
+      error('Unparsed junk: ${categoryToString(lastCategory)}');
     }
     // TODO(sra): interpolated capture here?
     return statement;
@@ -1264,9 +1264,9 @@
 
       if (acceptString('switch')) return parseSwitch();
 
-      if (lastToken == 'case') error("Case outside switch.");
+      if (lastToken == 'case') error('Case outside switch.');
 
-      if (lastToken == 'default') error("Default outside switch.");
+      if (lastToken == 'default') error('Default outside switch.');
 
       if (lastToken == 'yield') return parseYield();
 
@@ -1353,12 +1353,12 @@
     //     for (var variable in Expression) Statement
     //
     Statement finishFor(Expression? init) {
-      Expression? condition = null;
+      Expression? condition;
       if (!acceptCategory(SEMICOLON)) {
         condition = parseExpression();
         expectCategory(SEMICOLON);
       }
-      Expression? update = null;
+      Expression? update;
       if (!acceptCategory(RPAREN)) {
         update = parseExpression();
         expectCategory(RPAREN);
@@ -1417,9 +1417,9 @@
   Statement parseTry() {
     expectCategory(LBRACE);
     Block body = parseBlock();
-    Catch? catchPart = null;
+    Catch? catchPart;
     if (acceptString('catch')) catchPart = parseCatch();
-    Block? finallyPart = null;
+    Block? finallyPart;
     if (acceptString('finally')) {
       expectCategory(LBRACE);
       finallyPart = parseBlock();
@@ -1430,7 +1430,7 @@
   }
 
   SwitchClause parseSwitchClause() {
-    Expression? expression = null;
+    Expression? expression;
     if (acceptString('case')) {
       expression = parseExpression();
       expectCategory(COLON);
@@ -1461,7 +1461,7 @@
 
   Statement parseDo() {
     Statement body = parseStatement();
-    if (lastToken != "while") error("Missing while after do body.");
+    if (lastToken != 'while') error('Missing while after do body.');
     getToken();
     expectCategory(LPAREN);
     Expression condition = parseExpression();
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index 6d5d5ac..b36a52a 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -556,7 +556,7 @@
   void visitComment(Comment node, A arg) {}
 }
 
-/// This tag interface has no behaviour but must be implemented by any class
+/// This tag interface has no behavior but must be implemented by any class
 /// that is to be stored on a [Node] as source information.
 abstract class JavaScriptNodeSourceInformation {
   const JavaScriptNodeSourceInformation();
@@ -627,12 +627,16 @@
 
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
-    for (Statement statement in body) statement.accept(visitor);
+    for (Statement statement in body) {
+      statement.accept(visitor);
+    }
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
-    for (Statement statement in body) statement.accept1(visitor, arg);
+    for (Statement statement in body) {
+      statement.accept1(visitor, arg);
+    }
   }
 
   @override
@@ -672,7 +676,7 @@
 
   Block(this.statements);
 
-  Block.empty() : this.statements = [];
+  Block.empty() : statements = [];
 
   @override
   T accept<T>(NodeVisitor<T> visitor) => visitor.visitBlock(this);
@@ -683,12 +687,16 @@
 
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
-    for (Statement statement in statements) statement.accept(visitor);
+    for (Statement statement in statements) {
+      statement.accept(visitor);
+    }
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
-    for (Statement statement in statements) statement.accept1(visitor, arg);
+    for (Statement statement in statements) {
+      statement.accept1(visitor, arg);
+    }
   }
 
   @override
@@ -748,7 +756,7 @@
 
   If(this.condition, this.then, this.otherwise);
 
-  If.noElse(this.condition, this.then) : this.otherwise = EmptyStatement();
+  If.noElse(this.condition, this.then) : otherwise = EmptyStatement();
 
   bool get hasElse => otherwise is! EmptyStatement;
 
@@ -955,7 +963,7 @@
   /// The expression for `return expression;`, or `null` for `return;`.
   final Expression? value;
 
-  Return([this.value = null]);
+  Return([this.value]);
 
   @override
   T accept<T>(NodeVisitor<T> visitor) => visitor.visitReturn(this);
@@ -1083,13 +1091,17 @@
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
     key.accept(visitor);
-    for (SwitchClause clause in cases) clause.accept(visitor);
+    for (SwitchClause clause in cases) {
+      clause.accept(visitor);
+    }
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
     key.accept1(visitor, arg);
-    for (SwitchClause clause in cases) clause.accept1(visitor, arg);
+    for (SwitchClause clause in cases) {
+      clause.accept1(visitor, arg);
+    }
   }
 
   @override
@@ -1545,7 +1557,7 @@
 
   Call(this.target, this.arguments,
       {JavaScriptNodeSourceInformation? sourceInformation}) {
-    this._sourceInformation = sourceInformation;
+    _sourceInformation = sourceInformation;
   }
 
   @override
@@ -1628,43 +1640,43 @@
   int get precedenceLevel {
     // TODO(floitsch): switch to constant map.
     switch (op) {
-      case "*":
-      case "/":
-      case "%":
+      case '*':
+      case '/':
+      case '%':
         return MULTIPLICATIVE;
-      case "+":
-      case "-":
+      case '+':
+      case '-':
         return ADDITIVE;
-      case "<<":
-      case ">>":
-      case ">>>":
+      case '<<':
+      case '>>':
+      case '>>>':
         return SHIFT;
-      case "<":
-      case ">":
-      case "<=":
-      case ">=":
-      case "instanceof":
-      case "in":
+      case '<':
+      case '>':
+      case '<=':
+      case '>=':
+      case 'instanceof':
+      case 'in':
         return RELATIONAL;
-      case "==":
-      case "===":
-      case "!=":
-      case "!==":
+      case '==':
+      case '===':
+      case '!=':
+      case '!==':
         return EQUALITY;
-      case "&":
+      case '&':
         return BIT_AND;
-      case "^":
+      case '^':
         return BIT_XOR;
-      case "|":
+      case '|':
         return BIT_OR;
-      case "&&":
+      case '&&':
         return LOGICAL_AND;
-      case "||":
+      case '||':
         return LOGICAL_OR;
       case ',':
         return EXPRESSION;
       default:
-        throw "Internal Error: Unhandled binary operator: $op";
+        throw 'Internal Error: Unhandled binary operator: $op';
     }
   }
 }
@@ -1799,7 +1811,7 @@
 }
 
 class This extends Parameter {
-  This() : super("this");
+  This() : super('this');
 
   @override
   T accept<T>(NodeVisitor<T> visitor) => visitor.visitThis(this);
@@ -1869,13 +1881,17 @@
 
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
-    for (Parameter param in params) param.accept(visitor);
+    for (Parameter param in params) {
+      param.accept(visitor);
+    }
     body.accept(visitor);
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
-    for (Parameter param in params) param.accept1(visitor, arg);
+    for (Parameter param in params) {
+      param.accept1(visitor, arg);
+    }
     body.accept1(visitor, arg);
   }
 
@@ -1911,13 +1927,17 @@
 
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
-    for (Parameter param in params) param.accept(visitor);
+    for (Parameter param in params) {
+      param.accept(visitor);
+    }
     body.accept(visitor);
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
-    for (Parameter param in params) param.accept1(visitor, arg);
+    for (Parameter param in params) {
+      param.accept1(visitor, arg);
+    }
     body.accept1(visitor, arg);
   }
 
@@ -1940,13 +1960,13 @@
       {required this.isAsync, required this.isYielding});
 
   static const AsyncModifier sync =
-      AsyncModifier(0, "sync", isAsync: false, isYielding: false);
+      AsyncModifier(0, 'sync', isAsync: false, isYielding: false);
   static const AsyncModifier async =
-      AsyncModifier(1, "async", isAsync: true, isYielding: false);
+      AsyncModifier(1, 'async', isAsync: true, isYielding: false);
   static const AsyncModifier asyncStar =
-      AsyncModifier(2, "async*", isAsync: true, isYielding: true);
+      AsyncModifier(2, 'async*', isAsync: true, isYielding: true);
   static const AsyncModifier syncStar =
-      AsyncModifier(3, "sync*", isAsync: false, isYielding: true);
+      AsyncModifier(3, 'sync*', isAsync: false, isYielding: true);
 
   static const List<AsyncModifier> values = [sync, async, asyncStar, syncStar];
 
@@ -2159,16 +2179,20 @@
 
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
-    for (Literal part in parts) part.accept(visitor);
+    for (Literal part in parts) {
+      part.accept(visitor);
+    }
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
-    for (Literal part in parts) part.accept1(visitor, arg);
+    for (Literal part in parts) {
+      part.accept1(visitor, arg);
+    }
   }
 
   @override
-  StringConcatenation _clone() => StringConcatenation(this.parts);
+  StringConcatenation _clone() => StringConcatenation(parts);
 }
 
 class LiteralNumber extends Literal {
@@ -2204,12 +2228,16 @@
 
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
-    for (Expression element in elements) element.accept(visitor);
+    for (Expression element in elements) {
+      element.accept(visitor);
+    }
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
-    for (Expression element in elements) element.accept1(visitor, arg);
+    for (Expression element in elements) {
+      element.accept1(visitor, arg);
+    }
   }
 
   @override
@@ -2248,9 +2276,9 @@
 
   /// Constructs a new object-initializer containing the given [properties].
   ///
-  /// [isOneLiner] describes the behaviour when pretty-printing (non-minified).
+  /// [isOneLiner] describes the behavior when pretty-printing (non-minified).
   /// If true print all properties on the same line.
-  /// If false print each property on a seperate line.
+  /// If false print each property on a separate line.
   ObjectInitializer(this.properties, {this.isOneLiner = true});
 
   @override
@@ -2262,12 +2290,16 @@
 
   @override
   void visitChildren<T>(NodeVisitor<T> visitor) {
-    for (Property init in properties) init.accept(visitor);
+    for (Property init in properties) {
+      init.accept(visitor);
+    }
   }
 
   @override
   void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
-    for (Property init in properties) init.accept1(visitor, arg);
+    for (Property init in properties) {
+      init.accept1(visitor, arg);
+    }
   }
 
   @override
@@ -2343,7 +2375,7 @@
 
 /// Tag class for all interpolated positions.
 abstract class InterpolatedNode implements Node {
-  get nameOrPosition;
+  dynamic get nameOrPosition;
 
   bool get isNamed => nameOrPosition is String;
 
@@ -2352,7 +2384,7 @@
 
 class InterpolatedExpression extends Expression with InterpolatedNode {
   @override
-  final nameOrPosition;
+  final dynamic nameOrPosition;
 
   InterpolatedExpression(this.nameOrPosition);
 
@@ -2379,7 +2411,7 @@
 
 class InterpolatedLiteral extends Literal with InterpolatedNode {
   @override
-  final nameOrPosition;
+  final dynamic nameOrPosition;
 
   InterpolatedLiteral(this.nameOrPosition);
 
@@ -2404,13 +2436,13 @@
     with InterpolatedNode
     implements Parameter {
   @override
-  final nameOrPosition;
+  final dynamic nameOrPosition;
 
   InterpolatedParameter(this.nameOrPosition);
 
   @override
   String get name {
-    throw "InterpolatedParameter.name must not be invoked";
+    throw 'InterpolatedParameter.name must not be invoked';
   }
 
   @override
@@ -2439,7 +2471,7 @@
 
 class InterpolatedSelector extends Expression with InterpolatedNode {
   @override
-  final nameOrPosition;
+  final dynamic nameOrPosition;
 
   InterpolatedSelector(this.nameOrPosition);
 
@@ -2466,7 +2498,7 @@
 
 class InterpolatedStatement extends Statement with InterpolatedNode {
   @override
-  final nameOrPosition;
+  final dynamic nameOrPosition;
 
   InterpolatedStatement(this.nameOrPosition);
 
@@ -2492,7 +2524,7 @@
     with InterpolatedNode
     implements Declaration {
   @override
-  final nameOrPosition;
+  final dynamic nameOrPosition;
 
   InterpolatedDeclaration(this.nameOrPosition);
 
@@ -2516,7 +2548,7 @@
   }
 
   @override
-  String get name => throw "No name for the interpolated node";
+  String get name => throw 'No name for the interpolated node';
 
   @override
   int get precedenceLevel => PRIMARY;
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index 67d0f9b..4e1e59c 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -6,7 +6,7 @@
 
 library js_ast.printer;
 
-import 'characters.dart' as charCodes;
+import 'characters.dart' as char_codes;
 import 'nodes.dart';
 import 'precedence.dart';
 import 'strings.dart';
@@ -83,7 +83,7 @@
   return context.getText();
 }
 
-class Printer implements NodeVisitor {
+class Printer implements NodeVisitor<void> {
   final JavaScriptPrintingOptions options;
   final JavaScriptPrintingContext context;
   final bool shouldCompressOutput;
@@ -100,15 +100,13 @@
   // The current indentation level.
   int _indentLevel = 0;
   // A cache of all indentation strings used so far.
-  final List<String> _indentList = [""];
+  final List<String> _indentList = [''];
 
   static final identifierCharacterRegExp = RegExp(r'^[a-zA-Z_0-9$]');
   static final expressionContinuationRegExp = RegExp(r'^[-+([]');
 
-  Printer(JavaScriptPrintingOptions options, JavaScriptPrintingContext context)
-      : options = options,
-        context = context,
-        isDebugContext = context.isDebugContext,
+  Printer(this.options, this.context)
+      : isDebugContext = context.isDebugContext,
         shouldCompressOutput = options.shouldCompressOutput,
         danglingElseVisitor = DanglingElseVisitor(context),
         localNamer = determineRenamer(
@@ -125,7 +123,7 @@
   String get indentation {
     // Lazily add new indentation strings as required.
     while (_indentList.length <= _indentLevel) {
-      _indentList.add(_indentList.last + "  ");
+      _indentList.add('${_indentList.last}  ');
     }
     return _indentList[_indentLevel];
   }
@@ -140,7 +138,7 @@
 
   /// Always emit a newline, even under `enableMinification`.
   void forceLine() {
-    out("\n", isWhitespace: true);
+    out('\n', isWhitespace: true);
   }
 
   /// Emits a newline for readability.
@@ -149,7 +147,7 @@
   }
 
   void spaceOut() {
-    if (!shouldCompressOutput) out(" ", isWhitespace: true);
+    if (!shouldCompressOutput) out(' ', isWhitespace: true);
   }
 
   String lastAddedString = '\u0000';
@@ -160,11 +158,11 @@
   }
 
   void out(String str, {bool isWhitespace = false}) {
-    if (str != "") {
+    if (str != '') {
       if (pendingSemicolon) {
         if (!shouldCompressOutput) {
-          _emit(";");
-        } else if (str != "}") {
+          _emit(';');
+        } else if (str != '}') {
           // We want to output newline instead of semicolon because it makes
           // the raw stack traces much easier to read and it also makes line-
           // based tools like diff work much better.  JavaScript will
@@ -178,15 +176,15 @@
           // than newlines because the former doesn't need escaping.
           if (options.preferSemicolonToNewlineInMinifiedOutput ||
               expressionContinuationRegExp.hasMatch(str)) {
-            _emit(";");
+            _emit(';');
           } else {
-            _emit("\n");
+            _emit('\n');
           }
         }
       }
       if (pendingSpace &&
           (!shouldCompressOutput || identifierCharacterRegExp.hasMatch(str))) {
-        _emit(" ");
+        _emit(' ');
       }
       pendingSpace = false;
       pendingSemicolon = false;
@@ -207,7 +205,7 @@
     if (shouldCompressOutput) {
       pendingSemicolon = true;
     } else {
-      out(";");
+      out(';');
       forceLine();
     }
   }
@@ -269,7 +267,7 @@
     for (int i = 0; i < nodes.length; i++) {
       if (i != 0) {
         atStatementBegin = false;
-        out(",");
+        out(',');
         spaceOut();
       }
       visitNestedExpression(nodes[i], hasRequiredType,
@@ -314,7 +312,7 @@
     if (shouldCompressOutput && needsSeparation) {
       // If [shouldCompressOutput] is false, then the 'lineOut' will insert
       // the separation.
-      out(" ", isWhitespace: true);
+      out(' ', isWhitespace: true);
     } else {
       lineOut();
     }
@@ -344,13 +342,13 @@
       {required bool shouldIndent, required bool needsNewline}) {
     if (shouldIndent) indent();
     startNode(node);
-    out("{");
+    out('{');
     lineOut();
     indentMore();
     node.statements.forEach(blockOutWithoutBraces);
     indentLess();
     indent();
-    out("}");
+    out('}');
     int closingPosition = _charCount - 1;
     endNode(node);
     if (needsNewline) lineOut();
@@ -372,7 +370,7 @@
 
   @override
   void visitEmptyStatement(EmptyStatement node) {
-    outIndentLn(";");
+    outIndentLn(';');
   }
 
   void ifOut(If node, bool shouldIndent) {
@@ -390,12 +388,12 @@
       }
     }
     if (shouldIndent) indent();
-    out("if");
+    out('if');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(node.condition, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     bool thenWasBlock =
         blockBody(then, needsSeparation: false, needsNewline: !hasElse);
     if (hasElse) {
@@ -404,7 +402,7 @@
       } else {
         indent();
       }
-      out("else");
+      out('else');
       if (elsePart is If) {
         pendingSpace = true;
         startNode(elsePart);
@@ -424,82 +422,82 @@
 
   @override
   void visitFor(For loop) {
-    outIndent("for");
+    outIndent('for');
     spaceOut();
-    out("(");
+    out('(');
     if (loop.init != null) {
       visitNestedExpression(loop.init!, EXPRESSION,
           newInForInit: true, newAtStatementBegin: false);
     }
-    out(";");
+    out(';');
     if (loop.condition != null) {
       spaceOut();
       visitNestedExpression(loop.condition!, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
     }
-    out(";");
+    out(';');
     if (loop.update != null) {
       spaceOut();
       visitNestedExpression(loop.update!, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
     }
-    out(")");
+    out(')');
     blockBody(unwrapBlockIfSingleStatement(loop.body),
         needsSeparation: false, needsNewline: true);
   }
 
   @override
   void visitForIn(ForIn loop) {
-    outIndent("for");
+    outIndent('for');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(loop.leftHandSide, EXPRESSION,
         newInForInit: true, newAtStatementBegin: false);
-    out(" in");
+    out(' in');
     pendingSpace = true;
     visitNestedExpression(loop.object, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     blockBody(unwrapBlockIfSingleStatement(loop.body),
         needsSeparation: false, needsNewline: true);
   }
 
   @override
   void visitWhile(While loop) {
-    outIndent("while");
+    outIndent('while');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(loop.condition, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     blockBody(unwrapBlockIfSingleStatement(loop.body),
         needsSeparation: false, needsNewline: true);
   }
 
   @override
   void visitDo(Do loop) {
-    outIndent("do");
+    outIndent('do');
     if (blockBody(unwrapBlockIfSingleStatement(loop.body),
         needsSeparation: true, needsNewline: false)) {
       spaceOut();
     } else {
       indent();
     }
-    out("while");
+    out('while');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(loop.condition, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     outSemicolonLn();
   }
 
   @override
   void visitContinue(Continue node) {
     if (node.targetLabel == null) {
-      outIndent("continue");
+      outIndent('continue');
     } else {
-      outIndent("continue ${node.targetLabel}");
+      outIndent('continue ${node.targetLabel}');
     }
     outSemicolonLn();
   }
@@ -507,9 +505,9 @@
   @override
   void visitBreak(Break node) {
     if (node.targetLabel == null) {
-      outIndent("break");
+      outIndent('break');
     } else {
-      outIndent("break ${node.targetLabel}");
+      outIndent('break ${node.targetLabel}');
     }
     outSemicolonLn();
   }
@@ -518,9 +516,9 @@
   void visitReturn(Return node) {
     final value = node.value;
     if (value == null) {
-      outIndent("return");
+      outIndent('return');
     } else {
-      outIndent("return");
+      outIndent('return');
       pendingSpace = true;
       visitNestedExpression(value, EXPRESSION,
           newInForInit: false, newAtStatementBegin: false);
@@ -533,9 +531,9 @@
   @override
   void visitDartYield(DartYield node) {
     if (node.hasStar) {
-      outIndent("yield*");
+      outIndent('yield*');
     } else {
-      outIndent("yield");
+      outIndent('yield');
     }
     pendingSpace = true;
     visitNestedExpression(node.expression, EXPRESSION,
@@ -545,7 +543,7 @@
 
   @override
   void visitThrow(Throw node) {
-    outIndent("throw");
+    outIndent('throw');
     pendingSpace = true;
     visitNestedExpression(node.expression, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
@@ -554,14 +552,14 @@
 
   @override
   void visitTry(Try node) {
-    outIndent("try");
+    outIndent('try');
     blockBody(node.body, needsSeparation: true, needsNewline: false);
     if (node.catchPart != null) {
       visit(node.catchPart!);
     }
     if (node.finallyPart != null) {
       spaceOut();
-      out("finally");
+      out('finally');
       blockBody(node.finallyPart!, needsSeparation: true, needsNewline: true);
     } else {
       lineOut();
@@ -571,39 +569,39 @@
   @override
   void visitCatch(Catch node) {
     spaceOut();
-    out("catch");
+    out('catch');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(node.declaration, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     blockBody(node.body, needsSeparation: false, needsNewline: false);
   }
 
   @override
   void visitSwitch(Switch node) {
-    outIndent("switch");
+    outIndent('switch');
     spaceOut();
-    out("(");
+    out('(');
     visitNestedExpression(node.key, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     spaceOut();
-    outLn("{");
+    outLn('{');
     indentMore();
     visitAll(node.cases);
     indentLess();
-    outIndentLn("}");
+    outIndentLn('}');
   }
 
   @override
   void visitCase(Case node) {
-    outIndent("case");
+    outIndent('case');
     pendingSpace = true;
     visitNestedExpression(node.expression, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    outLn(":");
-    if (!node.body.statements.isEmpty) {
+    outLn(':');
+    if (node.body.statements.isNotEmpty) {
       indentMore();
       blockOutWithoutBraces(node.body);
       indentLess();
@@ -612,8 +610,8 @@
 
   @override
   void visitDefault(Default node) {
-    outIndentLn("default:");
-    if (!node.body.statements.isEmpty) {
+    outIndentLn('default:');
+    if (node.body.statements.isNotEmpty) {
       indentMore();
       blockOutWithoutBraces(node.body);
       indentLess();
@@ -632,23 +630,23 @@
       visit(EmptyStatement());
       return;
     }
-    outIndent("${node.label}:");
+    outIndent('${node.label}:');
     blockBody(body, needsSeparation: false, needsNewline: true);
   }
 
   int functionOut(Fun fun, Expression? name, VarCollector vars) {
-    out("function");
+    out('function');
     if (name != null) {
-      out(" ");
+      out(' ');
       // Name must be a [Decl]. Therefore only test for primary expressions.
       visitNestedExpression(name, PRIMARY,
           newInForInit: false, newAtStatementBegin: false);
     }
     localNamer.enterScope(vars);
-    out("(");
+    out('(');
     visitCommaSeparated(fun.params, PRIMARY,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     switch (fun.asyncModifier) {
       case AsyncModifier.sync:
         break;
@@ -673,7 +671,7 @@
   }
 
   @override
-  visitFunctionDeclaration(FunctionDeclaration declaration) {
+  void visitFunctionDeclaration(FunctionDeclaration declaration) {
     VarCollector vars = VarCollector();
     vars.visitFunctionDeclaration(declaration);
     indent();
@@ -684,7 +682,7 @@
     lineOut();
   }
 
-  visitNestedExpression(Expression node, int requiredPrecedence,
+  void visitNestedExpression(Expression node, int requiredPrecedence,
       {required bool newInForInit, required bool newAtStatementBegin}) {
     int precedenceLevel =
         (isDebugContext && !node.isFinalized) ? CALL : node.precedenceLevel;
@@ -693,7 +691,7 @@
         (requiredPrecedence != EXPRESSION &&
                 precedenceLevel < requiredPrecedence) ||
             // for (a = (x in o); ... ; ... ) { ... }
-            (newInForInit && node is Binary && node.op == "in") ||
+            (newInForInit && node is Binary && node.op == 'in') ||
             // (function() { ... })().
             // ({a: 2, b: 3}.toString()).
             (newAtStatementBegin &&
@@ -703,9 +701,9 @@
     if (needsParentheses) {
       inForInit = false;
       atStatementBegin = false;
-      out("(");
+      out('(');
       visit(node);
-      out(")");
+      out(')');
     } else {
       inForInit = newInForInit;
       atStatementBegin = newAtStatementBegin;
@@ -714,8 +712,8 @@
   }
 
   @override
-  visitVariableDeclarationList(VariableDeclarationList list) {
-    out("var ");
+  void visitVariableDeclarationList(VariableDeclarationList list) {
+    out('var ');
     final nodes = list.declarations;
     if (inForInit) {
       visitCommaSeparated(nodes, ASSIGNMENT,
@@ -733,7 +731,7 @@
         bool thisIsBig = !_isSmallInitialization(node);
         if (i > 0) {
           atStatementBegin = false;
-          out(",");
+          out(',');
           if (lastWasBig || thisIsBig) {
             lineOut();
             indent();
@@ -768,10 +766,10 @@
 
   void _outputIncDec(String op, Expression variable, [Expression? alias]) {
     if (op == '+') {
-      if (lastCharCode == charCodes.$PLUS) out(" ", isWhitespace: true);
+      if (lastCharCode == char_codes.$PLUS) out(' ', isWhitespace: true);
       out('++');
     } else {
-      if (lastCharCode == charCodes.$MINUS) out(" ", isWhitespace: true);
+      if (lastCharCode == char_codes.$MINUS) out(' ', isWhitespace: true);
       out('--');
     }
     if (alias != null) startNode(alias);
@@ -781,7 +779,7 @@
   }
 
   @override
-  visitAssignment(Assignment assignment) {
+  void visitAssignment(Assignment assignment) {
     /// To print assignments like `a = a + 1` and `a = a + b` compactly as
     /// `++a` and `a += b` in the face of [DeferredExpression]s we detect the
     /// pattern of the undeferred assignment.
@@ -791,7 +789,7 @@
     if ((op == '+' || op == '-') &&
         leftHandSide is VariableUse &&
         rightHandSide is LiteralNumber &&
-        rightHandSide.value == "1") {
+        rightHandSide.value == '1') {
       // Output 'a += 1' as '++a' and 'a -= 1' as '--a'.
       _outputIncDec(op!, assignment.leftHandSide);
       return;
@@ -814,7 +812,7 @@
           // Output 'a = a + 1' as '++a' and 'a = a - 1' as '--a'.
           if ((op == '+' || op == '-') &&
               rRight is LiteralNumber &&
-              rRight.value == "1") {
+              rRight.value == '1') {
             _outputIncDec(op, assignment.leftHandSide, rightHandSide.left);
             return;
           }
@@ -825,7 +823,7 @@
           endNode(rightHandSide.left);
           spaceOut();
           out(op);
-          out("=");
+          out('=');
           spaceOut();
           visitNestedExpression(rRight, ASSIGNMENT,
               newInForInit: inForInit, newAtStatementBegin: false);
@@ -838,19 +836,19 @@
 
     spaceOut();
     if (op != null) out(op);
-    out("=");
+    out('=');
     spaceOut();
     visitNestedExpression(assignment.value, ASSIGNMENT,
         newInForInit: inForInit, newAtStatementBegin: false);
   }
 
   @override
-  visitVariableInitialization(VariableInitialization initialization) {
+  void visitVariableInitialization(VariableInitialization initialization) {
     visitNestedExpression(initialization.declaration, CALL,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
     if (initialization.value != null) {
       spaceOut();
-      out("=");
+      out('=');
       spaceOut();
       visitNestedExpression(initialization.value!, ASSIGNMENT,
           newInForInit: inForInit, newAtStatementBegin: false);
@@ -858,41 +856,41 @@
   }
 
   @override
-  visitConditional(Conditional cond) {
+  void visitConditional(Conditional cond) {
     visitNestedExpression(cond.condition, LOGICAL_OR,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
     spaceOut();
-    out("?");
+    out('?');
     spaceOut();
     // The then part is allowed to have an 'in'.
     visitNestedExpression(cond.then, ASSIGNMENT,
         newInForInit: false, newAtStatementBegin: false);
     spaceOut();
-    out(":");
+    out(':');
     spaceOut();
     visitNestedExpression(cond.otherwise, ASSIGNMENT,
         newInForInit: inForInit, newAtStatementBegin: false);
   }
 
   @override
-  visitNew(New node) {
-    out("new ");
+  void visitNew(New node) {
+    out('new ');
     visitNestedExpression(node.target, LEFT_HAND_SIDE,
         newInForInit: inForInit, newAtStatementBegin: false);
-    out("(");
+    out('(');
     visitCommaSeparated(node.arguments, ASSIGNMENT,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
   }
 
   @override
-  visitCall(Call call) {
+  void visitCall(Call call) {
     visitNestedExpression(call.target, CALL,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
-    out("(");
+    out('(');
     visitCommaSeparated(call.arguments, ASSIGNMENT,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
   }
 
   @override
@@ -910,55 +908,55 @@
         rightPrecedenceRequirement = EXPRESSION;
         leftSpace = false;
         break;
-      case "||":
+      case '||':
         leftPrecedenceRequirement = LOGICAL_OR;
         // x || (y || z) <=> (x || y) || z.
         rightPrecedenceRequirement = LOGICAL_OR;
         break;
-      case "&&":
+      case '&&':
         leftPrecedenceRequirement = LOGICAL_AND;
         // x && (y && z) <=> (x && y) && z.
         rightPrecedenceRequirement = LOGICAL_AND;
         break;
-      case "|":
+      case '|':
         leftPrecedenceRequirement = BIT_OR;
         // x | (y | z) <=> (x | y) | z.
         rightPrecedenceRequirement = BIT_OR;
         break;
-      case "^":
+      case '^':
         leftPrecedenceRequirement = BIT_XOR;
         // x ^ (y ^ z) <=> (x ^ y) ^ z.
         rightPrecedenceRequirement = BIT_XOR;
         break;
-      case "&":
+      case '&':
         leftPrecedenceRequirement = BIT_AND;
         // x & (y & z) <=> (x & y) & z.
         rightPrecedenceRequirement = BIT_AND;
         break;
-      case "==":
-      case "!=":
-      case "===":
-      case "!==":
+      case '==':
+      case '!=':
+      case '===':
+      case '!==':
         leftPrecedenceRequirement = EQUALITY;
         rightPrecedenceRequirement = RELATIONAL;
         break;
-      case "<":
-      case ">":
-      case "<=":
-      case ">=":
-      case "instanceof":
-      case "in":
+      case '<':
+      case '>':
+      case '<=':
+      case '>=':
+      case 'instanceof':
+      case 'in':
         leftPrecedenceRequirement = RELATIONAL;
         rightPrecedenceRequirement = SHIFT;
         break;
-      case ">>":
-      case "<<":
-      case ">>>":
+      case '>>':
+      case '<<':
+      case '>>>':
         leftPrecedenceRequirement = SHIFT;
         rightPrecedenceRequirement = ADDITIVE;
         break;
-      case "+":
-      case "-":
+      case '+':
+      case '-':
         leftPrecedenceRequirement = ADDITIVE;
         // We cannot remove parenthesis for "+" because
         //   x + (y + z) <!=> (x + y) + z:
@@ -967,9 +965,9 @@
         //   ("a" + 1) + 2 => "a12";
         rightPrecedenceRequirement = MULTIPLICATIVE;
         break;
-      case "*":
-      case "/":
-      case "%":
+      case '*':
+      case '/':
+      case '%':
         leftPrecedenceRequirement = MULTIPLICATIVE;
         // We cannot remove parenthesis for "*" because of precision issues.
         rightPrecedenceRequirement = UNARY;
@@ -977,18 +975,18 @@
       default:
         leftPrecedenceRequirement = EXPRESSION;
         rightPrecedenceRequirement = EXPRESSION;
-        context.error("Forgot operator: $op");
+        context.error('Forgot operator: $op');
     }
 
     visitNestedExpression(left, leftPrecedenceRequirement,
         newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
 
-    if (op == "in" || op == "instanceof") {
+    if (op == 'in' || op == 'instanceof') {
       // There are cases where the space is not required but without further
       // analysis we cannot know.
-      out(" ", isWhitespace: true);
+      out(' ', isWhitespace: true);
       out(op);
-      out(" ", isWhitespace: true);
+      out(' ', isWhitespace: true);
     } else {
       if (leftSpace) spaceOut();
       out(op);
@@ -1002,22 +1000,22 @@
   void visitPrefix(Prefix unary) {
     String op = unary.op;
     switch (op) {
-      case "delete":
-      case "void":
-      case "typeof":
+      case 'delete':
+      case 'void':
+      case 'typeof':
         // There are cases where the space is not required but without further
         // analysis we cannot know.
         out(op);
-        out(" ", isWhitespace: true);
+        out(' ', isWhitespace: true);
         break;
-      case "+":
-      case "++":
-        if (lastCharCode == charCodes.$PLUS) out(" ", isWhitespace: true);
+      case '+':
+      case '++':
+        if (lastCharCode == char_codes.$PLUS) out(' ', isWhitespace: true);
         out(op);
         break;
-      case "-":
-      case "--":
-        if (lastCharCode == charCodes.$MINUS) out(" ", isWhitespace: true);
+      case '-':
+      case '--':
+        if (lastCharCode == char_codes.$MINUS) out(' ', isWhitespace: true);
         out(op);
         break;
       default:
@@ -1041,7 +1039,7 @@
 
   @override
   void visitThis(This node) {
-    out("this");
+    out('this');
   }
 
   @override
@@ -1055,19 +1053,19 @@
   }
 
   bool isDigit(int charCode) {
-    return charCodes.$0 <= charCode && charCode <= charCodes.$9;
+    return char_codes.$0 <= charCode && charCode <= char_codes.$9;
   }
 
   bool isValidJavaScriptId(String field) {
-    if (field.length == 0) return false;
+    if (field.isEmpty) return false;
     // Ignore the leading and trailing string-delimiter.
     for (int i = 0; i < field.length; i++) {
       // TODO(floitsch): allow more characters.
       int charCode = field.codeUnitAt(i);
-      if (!(charCodes.$a <= charCode && charCode <= charCodes.$z ||
-          charCodes.$A <= charCode && charCode <= charCodes.$Z ||
-          charCode == charCodes.$$ ||
-          charCode == charCodes.$_ ||
+      if (!(char_codes.$a <= charCode && charCode <= char_codes.$z ||
+          char_codes.$A <= charCode && charCode <= char_codes.$Z ||
+          charCode == char_codes.$$ ||
+          charCode == char_codes.$_ ||
           i > 0 && isDigit(charCode))) {
         return false;
       }
@@ -1116,7 +1114,7 @@
       {bool assumeValid = false}) {
     if (assumeValid || isValidJavaScriptId(selectorValue)) {
       if (_undefer(receiver) is LiteralNumber &&
-          lastCharCode != charCodes.$CLOSE_PAREN) {
+          lastCharCode != char_codes.$CLOSE_PAREN) {
         out(' ', isWhitespace: true);
       }
       out('.');
@@ -1167,13 +1165,13 @@
       visitNestedExpression(params.single, ASSIGNMENT,
           newInForInit: false, newAtStatementBegin: false);
     } else {
-      out("(");
+      out('(');
       visitCommaSeparated(fun.params, PRIMARY,
           newInForInit: false, newAtStatementBegin: false);
-      out(")");
+      out(')');
     }
     spaceOut();
-    out("=>");
+    out('=>');
     spaceOut();
     int closingPosition;
     Node body = fun.body;
@@ -1194,10 +1192,10 @@
       // AssignmentExpression from FunctionBody. See:
       // https://tc39.github.io/ecma262/#sec-arrow-function-definitions
       bool needsParens = body is ObjectInitializer;
-      if (needsParens) out("(");
+      if (needsParens) out('(');
       visitNestedExpression(body as Expression, ASSIGNMENT,
           newInForInit: false, newAtStatementBegin: false);
-      if (needsParens) out(")");
+      if (needsParens) out(')');
       closingPosition = _charCount;
     }
     localNamer.leaveScope();
@@ -1205,7 +1203,7 @@
   }
 
   @override
-  visitDeferredExpression(DeferredExpression node) {
+  void visitDeferredExpression(DeferredExpression node) {
     if (isDebugContext && !node.isFinalized) {
       out(node.nonfinalizedDebugText());
       return;
@@ -1216,33 +1214,33 @@
   }
 
   @override
-  visitDeferredStatement(DeferredStatement node) {
+  void visitDeferredStatement(DeferredStatement node) {
     startNode(node);
     visit(node.statement);
     endNode(node);
   }
 
-  outputNumberWithRequiredWhitespace(String number) {
+  void outputNumberWithRequiredWhitespace(String number) {
     int charCode = number.codeUnitAt(0);
-    if (charCode == charCodes.$MINUS && lastCharCode == charCodes.$MINUS) {
-      out(" ", isWhitespace: true);
+    if (charCode == char_codes.$MINUS && lastCharCode == char_codes.$MINUS) {
+      out(' ', isWhitespace: true);
     }
     out(number);
   }
 
   @override
-  visitDeferredNumber(DeferredNumber node) {
-    outputNumberWithRequiredWhitespace("${node.value}");
+  void visitDeferredNumber(DeferredNumber node) {
+    outputNumberWithRequiredWhitespace('${node.value}');
   }
 
   @override
-  visitDeferredString(DeferredString node) {
+  void visitDeferredString(DeferredString node) {
     out(node.value);
   }
 
   @override
-  visitLiteralBool(LiteralBool node) {
-    out(node.value ? "true" : "false");
+  void visitLiteralBool(LiteralBool node) {
+    out(node.value ? 'true' : 'false');
   }
 
   @override
@@ -1255,7 +1253,7 @@
   }
 
   @override
-  visitStringConcatenation(StringConcatenation node) {
+  void visitStringConcatenation(StringConcatenation node) {
     _handleString(_StringContentsCollector(isDebugContext).collect(node));
   }
 
@@ -1273,7 +1271,7 @@
   }
 
   @override
-  visitName(Name node) {
+  void visitName(Name node) {
     if (isDebugContext && !node.isFinalized) {
       out(node.nonfinalizedDebugText());
       return;
@@ -1282,26 +1280,26 @@
   }
 
   @override
-  visitParentheses(Parentheses node) {
-    out("(");
+  void visitParentheses(Parentheses node) {
+    out('(');
     visitNestedExpression(node.enclosed, EXPRESSION,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
   }
 
   @override
-  visitLiteralNumber(LiteralNumber node) {
+  void visitLiteralNumber(LiteralNumber node) {
     outputNumberWithRequiredWhitespace(node.value);
   }
 
   @override
   void visitLiteralNull(LiteralNull node) {
-    out("null");
+    out('null');
   }
 
   @override
   void visitArrayInitializer(ArrayInitializer node) {
-    out("[");
+    out('[');
     List<Expression> elements = node.elements;
     for (int i = 0; i < elements.length; i++) {
       Expression element = elements[i];
@@ -1311,7 +1309,7 @@
         // equal to `[]` (the empty array)
         // and [1,,] (array with 1 and a hole) would become [1,] = [1].
         startNode(element);
-        out(",");
+        out(',');
         endNode(element);
         continue;
       }
@@ -1320,14 +1318,14 @@
           newInForInit: false, newAtStatementBegin: false);
       // We can skip the trailing "," for the last element (since it's not
       // an array hole).
-      if (i != elements.length - 1) out(",");
+      if (i != elements.length - 1) out(',');
     }
-    out("]");
+    out(']');
   }
 
   @override
   void visitArrayHole(ArrayHole node) {
-    context.error("Unreachable");
+    context.error('Unreachable');
   }
 
   @override
@@ -1342,13 +1340,13 @@
 
     bool isOneLiner = node.isOneLiner || shouldCompressOutput;
     List<Property> properties = node.properties;
-    out("{");
+    out('{');
     indentMore();
     for (int i = 0; i < properties.length; i++) {
       Expression value = properties[i].value;
       if (isOneLiner && exitOneLinerMode(value)) isOneLiner = false;
       if (i != 0) {
-        out(",");
+        out(',');
         if (isOneLiner) spaceOut();
       }
       if (!isOneLiner) {
@@ -1358,24 +1356,24 @@
       visit(properties[i]);
     }
     indentLess();
-    if (!isOneLiner && !properties.isEmpty) {
+    if (!isOneLiner && properties.isNotEmpty) {
       lineOut();
       indent();
     }
-    out("}");
+    out('}');
   }
 
   @override
   void visitProperty(Property node) {
     propertyNameOut(node);
-    out(":");
+    out(':');
     spaceOut();
     visitNestedExpression(node.value, ASSIGNMENT,
         newInForInit: false, newAtStatementBegin: false);
   }
 
   @override
-  visitMethodDefinition(MethodDefinition node) {
+  void visitMethodDefinition(MethodDefinition node) {
     propertyNameOut(node);
     VarCollector vars = VarCollector();
     vars.visitMethodDefinition(node);
@@ -1388,10 +1386,10 @@
     // TODO: support static, get/set, async, and generators.
     Fun fun = node.function;
     localNamer.enterScope(vars);
-    out("(");
+    out('(');
     visitCommaSeparated(fun.params, PRIMARY,
         newInForInit: false, newAtStatementBegin: false);
-    out(")");
+    out(')');
     spaceOut();
     int closingPosition =
         blockOut(fun.body, shouldIndent: false, needsNewline: false);
@@ -1485,7 +1483,7 @@
 
   @override
   void visitAwait(Await node) {
-    out("await ");
+    out('await ');
     visit(node.expression);
   }
 }
@@ -1548,7 +1546,7 @@
   final List<T> list;
 
   OrderedSet()
-      : set = Set<T>(),
+      : set = <T>{},
         list = <T>[];
 
   void add(T x) {
@@ -1558,7 +1556,7 @@
     }
   }
 
-  void forEach(void fun(T x)) {
+  void forEach(void Function(T x) fun) {
     list.forEach(fun);
   }
 }
@@ -1571,16 +1569,16 @@
   final OrderedSet<String> vars;
   final OrderedSet<String> params;
 
-  static final String disableVariableMinificationPattern = "::norenaming::";
-  static final String enableVariableMinificationPattern = "::dorenaming::";
+  static final String disableVariableMinificationPattern = '::norenaming::';
+  static final String enableVariableMinificationPattern = '::dorenaming::';
 
   VarCollector()
       : nested = false,
         vars = OrderedSet<String>(),
         params = OrderedSet<String>();
 
-  void forEachVar(void fn(String v)) => vars.forEach(fn);
-  void forEachParam(void fn(String p)) => params.forEach(fn);
+  void forEachVar(void Function(String) fn) => vars.forEach(fn);
+  void forEachParam(void Function(String) fn) => params.forEach(fn);
 
   void collectVarsInFunction(FunctionExpression fun) {
     if (!nested) {
@@ -1651,7 +1649,7 @@
 
   @override
   bool visitNode(Node node) {
-    context.error("Forgot node: $node");
+    context.error('Forgot node: $node');
     return true;
   }
 
@@ -1785,8 +1783,8 @@
 
   static int nthLetter(int n) {
     return (n < LOWER_CASE_LETTERS)
-        ? charCodes.$a + n
-        : charCodes.$A + n - LOWER_CASE_LETTERS;
+        ? char_codes.$a + n
+        : char_codes.$A + n - LOWER_CASE_LETTERS;
   }
 
   // Parameters go from a to z and variables go from z to a.  This makes each
@@ -1799,7 +1797,7 @@
   @override
   String declareVariable(String oldName) {
     if (avoidRenaming(oldName)) return oldName;
-    var newName;
+    String newName;
     if (variableNumber + parameterNumber < LOWER_CASE_LETTERS) {
       // Variables start from z and go backwards, for better gzipability.
       newName = getNameNumber(oldName, LOWER_CASE_LETTERS - 1 - variableNumber);
@@ -1814,7 +1812,7 @@
   @override
   String declareParameter(String oldName) {
     if (avoidRenaming(oldName)) return oldName;
-    var newName;
+    String newName;
     if (variableNumber + parameterNumber < LOWER_CASE_LETTERS) {
       newName = getNameNumber(oldName, parameterNumber);
     } else {
@@ -1860,7 +1858,7 @@
         nameSpaceSize ~/= LETTERS;
         codes.add(nthLetter((n ~/ nameSpaceSize) % LETTERS));
       }
-      codes.add(charCodes.$0 + digit);
+      codes.add(char_codes.$0 + digit);
       newName = String.fromCharCodes(codes);
     }
     assert(RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName));
diff --git a/pkg/js_ast/lib/src/strings.dart b/pkg/js_ast/lib/src/strings.dart
index 871eea7..ddbe407 100644
--- a/pkg/js_ast/lib/src/strings.dart
+++ b/pkg/js_ast/lib/src/strings.dart
@@ -7,7 +7,7 @@
 // Utilities for converting between JavaScript source-code Strings and the
 // String value they represent.
 
-import 'characters.dart' as charCodes;
+import 'characters.dart' as char_codes;
 
 class StringToSourceKind {
   /// [true] if preferable to use double quotes, [false] if preferable to use
@@ -33,24 +33,25 @@
     int unpairedSurrogates = 0;
 
     for (int rune in value.runes) {
-      if (rune == charCodes.$BACKSLASH) {
+      if (rune == char_codes.$BACKSLASH) {
         ++otherEscapes;
-      } else if (rune == charCodes.$SQ) {
+      } else if (rune == char_codes.$SQ) {
         ++singleQuotes;
-      } else if (rune == charCodes.$DQ) {
+      } else if (rune == char_codes.$DQ) {
         ++doubleQuotes;
-      } else if (rune == charCodes.$LF ||
-          rune == charCodes.$CR ||
-          rune == charCodes.$LS ||
-          rune == charCodes.$PS) {
+      } else if (rune == char_codes.$LF ||
+          rune == char_codes.$CR ||
+          rune == char_codes.$LS ||
+          rune == char_codes.$PS) {
         // Line terminators.
         ++otherEscapes;
-      } else if (rune == charCodes.$BS ||
-          rune == charCodes.$TAB ||
-          rune == charCodes.$VTAB ||
-          rune == charCodes.$FF) {
+      } else if (rune == char_codes.$BS ||
+          rune == char_codes.$TAB ||
+          rune == char_codes.$VTAB ||
+          rune == char_codes.$FF) {
         ++otherEscapes;
-      } else if (ascii && (rune < charCodes.$SPACE || rune >= charCodes.$DEL)) {
+      } else if (ascii &&
+          (rune < char_codes.$SPACE || rune >= char_codes.$DEL)) {
         ++otherEscapes;
       } else if (_isUnpairedSurrogate(rune)) {
         // Need to escape unpaired surrogates in a UTF8-encoded output otherwise
@@ -82,10 +83,10 @@
         sb.write(escape);
         continue;
       }
-      if (rune == charCodes.$LS ||
-          rune == charCodes.$PS ||
+      if (rune == char_codes.$LS ||
+          rune == char_codes.$PS ||
           _isUnpairedSurrogate(rune) ||
-          !utf8 && (rune < charCodes.$SPACE || rune >= charCodes.$DEL)) {
+          !utf8 && (rune < char_codes.$SPACE || rune >= char_codes.$DEL)) {
         if (rune < 0x100) {
           sb.write(r'\x');
           sb.write(rune.toRadixString(16).padLeft(2, '0'));
@@ -113,23 +114,23 @@
 
   static String? _irregularEscape(int code, bool useDoubleQuotes) {
     switch (code) {
-      case charCodes.$SQ:
+      case char_codes.$SQ:
         return useDoubleQuotes ? r"'" : r"\'";
-      case charCodes.$DQ:
+      case char_codes.$DQ:
         return useDoubleQuotes ? r'\"' : r'"';
-      case charCodes.$BACKSLASH:
+      case char_codes.$BACKSLASH:
         return r'\\';
-      case charCodes.$BS:
+      case char_codes.$BS:
         return r'\b';
-      case charCodes.$TAB:
+      case char_codes.$TAB:
         return r'\t';
-      case charCodes.$LF:
+      case char_codes.$LF:
         return r'\n';
-      case charCodes.$VTAB:
+      case char_codes.$VTAB:
         return r'\v';
-      case charCodes.$FF:
+      case char_codes.$FF:
         return r'\f';
-      case charCodes.$CR:
+      case char_codes.$CR:
         return r'\r';
     }
     return null;
diff --git a/pkg/js_ast/lib/src/template.dart b/pkg/js_ast/lib/src/template.dart
index 662ff13..9e049fd 100644
--- a/pkg/js_ast/lib/src/template.dart
+++ b/pkg/js_ast/lib/src/template.dart
@@ -47,9 +47,7 @@
   final bool isExpression;
   final bool forceCopy;
   final Node ast;
-
   final Instantiator instantiator;
-
   final int positionalArgumentCount;
 
   // Names of named holes, empty if there are no named holes.
@@ -122,17 +120,17 @@
     }
     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.
+        // 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";
+            .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";
+            holeNames.where((name) => !arguments.containsKey(name)).join(', ');
+        throw 'Template arguments is missing mappings for: $notFound';
       }
       return instantiator(arguments);
     }
@@ -159,8 +157,7 @@
 
   Instantiator compile(Node node) {
     analysis.visit(node);
-    Instantiator result = visit(node);
-    return result;
+    return visit(node);
   }
 
   static Never error(String message) {
@@ -323,9 +320,7 @@
   Instantiator visitProgram(Program node) {
     List<Instantiator> instantiators =
         node.body.map(visitSplayableStatement).toList();
-    return (arguments) {
-      return Program(splayStatements(instantiators, arguments));
-    };
+    return (arguments) => Program(splayStatements(instantiators, arguments));
   }
 
   List<Statement> splayStatements(List<Instantiator> instantiators, arguments) {
@@ -350,17 +345,13 @@
   Instantiator visitBlock(Block node) {
     List<Instantiator> instantiators =
         node.statements.map(visitSplayableStatement).toList();
-    return (arguments) {
-      return Block(splayStatements(instantiators, arguments));
-    };
+    return (arguments) => Block(splayStatements(instantiators, arguments));
   }
 
   @override
   Instantiator visitExpressionStatement(ExpressionStatement node) {
     Instantiator buildExpression = visit(node.expression);
-    return (arguments) {
-      return buildExpression(arguments).toStatement();
-    };
+    return (arguments) => buildExpression(arguments).toStatement();
   }
 
   @override
@@ -405,10 +396,8 @@
     Instantiator makeCondition = visit(node.condition);
     Instantiator makeThen = visit(node.then);
     Instantiator makeOtherwise = visit(node.otherwise);
-    return (arguments) {
-      return If(makeCondition(arguments), makeThen(arguments),
-          makeOtherwise(arguments));
-    };
+    return (arguments) => If(makeCondition(arguments), makeThen(arguments),
+        makeOtherwise(arguments));
   }
 
   @override
@@ -417,10 +406,8 @@
     Instantiator makeCondition = visitNullable(node.condition);
     Instantiator makeUpdate = visitNullable(node.update);
     Instantiator makeBody = visit(node.body);
-    return (arguments) {
-      return For(makeInit(arguments), makeCondition(arguments),
-          makeUpdate(arguments), makeBody(arguments));
-    };
+    return (arguments) => For(makeInit(arguments), makeCondition(arguments),
+        makeUpdate(arguments), makeBody(arguments));
   }
 
   @override
@@ -428,13 +415,11 @@
     Instantiator makeLeftHandSide = visit(node.leftHandSide);
     Instantiator makeObject = visit(node.object);
     Instantiator makeBody = visit(node.body);
-    return (arguments) {
-      return ForIn(makeLeftHandSide(arguments), makeObject(arguments),
-          makeBody(arguments));
-    };
+    return (arguments) => ForIn(makeLeftHandSide(arguments),
+        makeObject(arguments), makeBody(arguments));
   }
 
-  TODO(String name) {
+  Never TODO(String name) {
     throw UnimplementedError('$this.$name');
   }
 
@@ -442,18 +427,14 @@
   Instantiator visitWhile(While node) {
     Instantiator makeCondition = visit(node.condition);
     Instantiator makeBody = visit(node.body);
-    return (arguments) {
-      return While(makeCondition(arguments), makeBody(arguments));
-    };
+    return (arguments) => While(makeCondition(arguments), makeBody(arguments));
   }
 
   @override
   Instantiator visitDo(Do node) {
     Instantiator makeBody = visit(node.body);
     Instantiator makeCondition = visit(node.condition);
-    return (arguments) {
-      return Do(makeBody(arguments), makeCondition(arguments));
-    };
+    return (arguments) => Do(makeBody(arguments), makeCondition(arguments));
   }
 
   @override
@@ -578,10 +559,8 @@
   Instantiator visitVariableInitialization(VariableInitialization node) {
     Instantiator makeDeclaration = visit(node.declaration);
     Instantiator makeValue = visitNullable(node.value);
-    return (arguments) {
-      return VariableInitialization(
-          makeDeclaration(arguments), makeValue(arguments));
-    };
+    return (arguments) => VariableInitialization(
+        makeDeclaration(arguments), makeValue(arguments));
   }
 
   @override
@@ -601,7 +580,7 @@
   Instantiator visitCall(Call node) =>
       handleCallOrNew(node, (target, arguments) => Call(target, arguments));
 
-  Instantiator handleCallOrNew(Call node, finish(target, arguments)) {
+  Instantiator handleCallOrNew(Call node, Function(dynamic, dynamic) finish) {
     Instantiator makeTarget = visit(node.target);
     Iterable<Instantiator> argumentMakers =
         node.arguments.map(visitSplayableExpression).toList();
@@ -855,7 +834,7 @@
   }
 
   @override
-  visitInterpolatedNode(InterpolatedNode node) {
+  void visitInterpolatedNode(InterpolatedNode node) {
     containsInterpolatedNode.add(node);
     if (node.isNamed) holeNames.add(node.nameOrPosition);
     ++count;
diff --git a/pkg/js_ast/pubspec.yaml b/pkg/js_ast/pubspec.yaml
index c510415..27f1857 100644
--- a/pkg/js_ast/pubspec.yaml
+++ b/pkg/js_ast/pubspec.yaml
@@ -8,4 +8,5 @@
 dev_dependencies:
   expect:
     path: ../expect
+  lints: ^2.0.0
   test: ^1.3.4
diff --git a/pkg/js_ast/test/deferred_expression_test.dart b/pkg/js_ast/test/deferred_expression_test.dart
index 6415b7ed..da1e158 100644
--- a/pkg/js_ast/test/deferred_expression_test.dart
+++ b/pkg/js_ast/test/deferred_expression_test.dart
@@ -7,7 +7,7 @@
 import 'package:expect/expect.dart';
 import 'package:js_ast/js_ast.dart';
 
-main() {
+void main() {
   Map<Expression, DeferredExpression> map = {};
   VariableUse variableUse = VariableUse('variable');
   DeferredExpression deferred =
@@ -75,18 +75,18 @@
     DeferredExpression deferred = map[argument];
     Expect.isTrue(
         directContext.enterPositions.containsKey(argument),
-        "Argument ${DebugPrint(argument)} not found in direct enter positions: "
-        "${directContext.enterPositions.keys}");
+        'Argument ${DebugPrint(argument)} not found in direct enter positions: '
+        '${directContext.enterPositions.keys}');
     Expect.isTrue(
         deferredContext.enterPositions.containsKey(argument),
-        "Argument ${DebugPrint(argument)} not found in "
-        "deferred enter positions: "
-        "${deferredContext.enterPositions.keys}");
+        'Argument ${DebugPrint(argument)} not found in '
+        'deferred enter positions: '
+        '${deferredContext.enterPositions.keys}');
     Expect.isTrue(
         deferredContext.enterPositions.containsKey(deferred),
-        "Argument ${DebugPrint(deferred)} not found in "
-        "deferred enter positions: "
-        "${deferredContext.enterPositions.keys}");
+        'Argument ${DebugPrint(deferred)} not found in '
+        'deferred enter positions: '
+        '${deferredContext.enterPositions.keys}');
     Expect.equals(directContext.enterPositions[argument],
         deferredContext.enterPositions[argument]);
     Expect.equals(directContext.enterPositions[argument],
@@ -94,18 +94,18 @@
 
     Expect.isTrue(
         directContext.exitPositions.containsKey(argument),
-        "Argument ${DebugPrint(argument)} not found in direct enter positions: "
-        "${directContext.exitPositions.keys}");
+        'Argument ${DebugPrint(argument)} not found in direct enter positions: '
+        '${directContext.exitPositions.keys}');
     Expect.isTrue(
         deferredContext.exitPositions.containsKey(argument),
-        "Argument ${DebugPrint(argument)} not found in "
-        "deferred enter positions: "
-        "${deferredContext.exitPositions.keys}");
+        'Argument ${DebugPrint(argument)} not found in '
+        'deferred enter positions: '
+        '${deferredContext.exitPositions.keys}');
     Expect.isTrue(
         deferredContext.exitPositions.containsKey(deferred),
-        "Argument ${DebugPrint(deferred)} not found in "
-        "deferred enter positions: "
-        "${deferredContext.exitPositions.keys}");
+        'Argument ${DebugPrint(deferred)} not found in '
+        'deferred enter positions: '
+        '${deferredContext.exitPositions.keys}');
     Expect.equals(directContext.exitPositions[argument],
         deferredContext.exitPositions[argument]);
     Expect.equals(directContext.exitPositions[argument],
diff --git a/pkg/js_ast/test/deferred_statement_test.dart b/pkg/js_ast/test/deferred_statement_test.dart
index 9bba39a..4db27a6 100644
--- a/pkg/js_ast/test/deferred_statement_test.dart
+++ b/pkg/js_ast/test/deferred_statement_test.dart
@@ -14,8 +14,8 @@
   _DeferredStatement(this.statement);
 }
 
-main() {
-  // Defering a statement should not change how it prints.
+void main() {
+  // Deferring a statement should not change how it prints.
   var undeferredStatement = js.statement('var x = 3');
   var deferredStatement = _DeferredStatement(undeferredStatement);
   Expect.equals(DebugPrint(undeferredStatement), DebugPrint(deferredStatement));
diff --git a/pkg/js_ast/test/printer_callback_test.dart b/pkg/js_ast/test/printer_callback_test.dart
index cfd56b9..433d3ad 100644
--- a/pkg/js_ast/test/printer_callback_test.dart
+++ b/pkg/js_ast/test/printer_callback_test.dart
@@ -32,25 +32,25 @@
 
 const List<TestCase> DATA = <TestCase>[
   TestCase({
-    TestMode.NONE: """
+    TestMode.NONE: '''
 function(a, b) {
   return null;
-}""",
-    TestMode.ENTER: """
+}''',
+    TestMode.ENTER: '''
 @0function(@1a, @2b) @3{
   @4return @5null;
-}""",
-    TestMode.DELIMITER: """
+}''',
+    TestMode.DELIMITER: '''
 function(a, b) {
   return null@4;
-@0}""",
-    TestMode.EXIT: """
+@0}''',
+    TestMode.EXIT: '''
 function(a@1, b@2) {
   return null@5;
-@4}@3@0"""
+@4}@3@0'''
   }),
   TestCase({
-    TestMode.NONE: """
+    TestMode.NONE: '''
 function() {
   if (true) {
     foo1();
@@ -63,8 +63,8 @@
     baz3();
     baz4();
   }
-}""",
-    TestMode.ENTER: """
+}''',
+    TestMode.ENTER: '''
 @0function() @1{
   @2if (@3true) @4{
     @5@6@7foo1();
@@ -77,8 +77,8 @@
     @23@24@25baz3();
     @26@27@28baz4();
   }
-}""",
-    TestMode.DELIMITER: """
+}''',
+    TestMode.DELIMITER: '''
 function() {
   if (true) {
     foo1();
@@ -91,8 +91,8 @@
     baz3();
     baz4();
   }
-@0}""",
-    TestMode.EXIT: """
+@0}''',
+    TestMode.EXIT: '''
 function() {
   if (true@3) {
     foo1@7()@6;
@@ -105,29 +105,29 @@
     baz3@25()@24;
 @23    baz4@28()@27;
 @26  }@22
-@20}@1@0""",
+@20}@1@0''',
   }),
   TestCase({
-    TestMode.NONE: """
+    TestMode.NONE: '''
 function() {
   function foo() {
   }
-}""",
-    TestMode.ENTER: """
+}''',
+    TestMode.ENTER: '''
 @0function() @1{
   @2@3function @4foo() @5{
   }
-}""",
-    TestMode.DELIMITER: """
+}''',
+    TestMode.DELIMITER: '''
 function() {
   function foo() {
   @3}
-@0}""",
-    TestMode.EXIT: """
+@0}''',
+    TestMode.EXIT: '''
 function() {
   function foo@4() {
   }@5@3
-@2}@1@0"""
+@2}@1@0'''
   }),
   TestCase({
     TestMode.INPUT: """
@@ -135,33 +135,33 @@
   a['b'];
   [1,, 2];
 }""",
-    TestMode.NONE: """
+    TestMode.NONE: '''
 function() {
   a.b;
   [1,, 2];
-}""",
-    TestMode.ENTER: """
+}''',
+    TestMode.ENTER: '''
 @0function() @1{
   @2@3@4a.@5b;
   @6@7[@81,@9, @102];
-}""",
-    TestMode.DELIMITER: """
+}''',
+    TestMode.DELIMITER: '''
 function() {
   a.b;
   [1,, 2];
-@0}""",
-    TestMode.EXIT: """
+@0}''',
+    TestMode.EXIT: '''
 function() {
   a@4.b@5@3;
 @2  [1@8,,@9 2@10]@7;
-@6}@1@0""",
+@6}@1@0''',
   }),
   TestCase({
-    TestMode.INPUT: "a.#nameTemplate = #nameTemplate",
-    TestMode.NONE: "a.nameValue = nameValue",
-    TestMode.ENTER: "@0@1@2a.@3nameValue = @3nameValue",
-    TestMode.DELIMITER: "a.nameValue = nameValue",
-    TestMode.EXIT: "a@2.nameValue@3@1 = nameValue@3@0",
+    TestMode.INPUT: 'a.#nameTemplate = #nameTemplate',
+    TestMode.NONE: 'a.nameValue = nameValue',
+    TestMode.ENTER: '@0@1@2a.@3nameValue = @3nameValue',
+    TestMode.DELIMITER: 'a.nameValue = nameValue',
+    TestMode.EXIT: 'a@2.nameValue@3@1 = nameValue@3@0',
   }, {
     'nameTemplate': 'nameValue'
   }),
@@ -179,10 +179,10 @@
 void check(TestCase testCase) {
   Map<TestMode, String> map = testCase.data;
   String code = map[TestMode.INPUT];
-  if (code == null) {
-    // Input is the same as output.
-    code = map[TestMode.NONE];
-  }
+
+  // Input is the same as output.
+  code ??= map[TestMode.NONE];
+
   JavaScriptPrintingOptions options = JavaScriptPrintingOptions();
   Map arguments = {};
   testCase.environment.forEach((String name, String value) {
@@ -196,7 +196,7 @@
     // TODO(johnniwinther): Remove `replaceAll(...)` when dart2js behaves as the
     // VM on newline in multiline strings.
     expect(context.getText(), equals(expectedOutput.replaceAll('\r\n', '\n')),
-        reason: "Unexpected output for $code in $mode");
+        reason: 'Unexpected output for $code in $mode');
   });
 }
 
diff --git a/pkg/js_ast/test/string_escape_test.dart b/pkg/js_ast/test/string_escape_test.dart
index 1b0ce74..c483ba9 100644
--- a/pkg/js_ast/test/string_escape_test.dart
+++ b/pkg/js_ast/test/string_escape_test.dart
@@ -14,7 +14,7 @@
 const int $RCURLY = $CLOSE_CURLY_BRACKET;
 
 void main() {
-  check(input, expected, {bool utf8 = false}) {
+  void check(input, expected, {bool utf8 = false}) {
     if (input is List) input = String.fromCharCodes(input);
     String actual = DebugPrint(js.string(input), utf8: utf8);
     if (expected is List) {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect
index 370e042..16be023 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect
@@ -14,13 +14,7 @@
     ;
 [@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasTearOffUses:false,methodOrSetterSelectorId:4] [@vm.unboxing-info.metadata=(b)->d]  operator []([@vm.inferred-type.metadata=!] core::int i) → core::double
     return [@vm.direct-call.metadata=dart.typed_data::_Float64List.[]] [@vm.inferred-type.metadata=dart.core::_Double (skip check)] [@vm.direct-call.metadata=#lib::_Vector._elements] [@vm.inferred-type.metadata=dart.typed_data::_Float64List] this.{self::_Vector::_elements}{core::List<core::double>}.{core::List::[]}([@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}([@vm.direct-call.metadata=#lib::_Vector._offset] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] this.{self::_Vector::_offset}{core::int}){(core::num) → core::int}){(core::int) → core::double};
-[@vm.procedure-attributes.metadata=getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5]  operator []=([@vm.inferred-type.metadata=dart.core::_OneByteString] core::int i, core::double value) → void {
-    block {
-      [@vm.direct-call.metadata=#lib::_Vector._elements] [@vm.inferred-type.metadata=dart.typed_data::_Float64List] this.{self::_Vector::_elements}{core::List<core::double>};
-      [@vm.direct-call.metadata=#lib::_Vector._offset] [@vm.inferred-type.metadata=dart.core::_Smi (value: 0)] this.{self::_Vector::_offset}{core::int};
-    } =>throw "Attempt to execute code removed by Dart AOT compiler (TFA)";
-  }
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:6] [@vm.unboxing-info.metadata=(b)->d]  operator *([@vm.inferred-type.metadata=#lib::_Vector?] self::_Vector a) → core::double {
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5] [@vm.unboxing-info.metadata=(b)->d]  operator *([@vm.inferred-type.metadata=#lib::_Vector?] self::_Vector a) → core::double {
     core::double result = 0.0;
     for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation.<] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i.{core::num::<}([@vm.direct-call.metadata=#lib::_Vector._length] [@vm.inferred-type.metadata=dart.core::_Smi (value: 10)] this.{self::_Vector::_length}{core::int}){(core::num) → core::bool}; i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1){(core::num) → core::int})
       result = [@vm.direct-call.metadata=dart.core::_Double.+??] [@vm.inferred-type.metadata=dart.core::_Double (skip check)] result.{core::double::+}([@vm.direct-call.metadata=dart.core::_Double.*] [@vm.inferred-type.metadata=dart.core::_Double (skip check)] [@vm.direct-call.metadata=#lib::_Vector.[]] [@vm.inferred-type.metadata=dart.core::_Double (skip check)] this.{self::_Vector::[]}(i){(core::int) → core::double}.{core::double::*}([@vm.direct-call.metadata=#lib::_Vector.[]??] [@vm.inferred-type.metadata=dart.core::_Double (skip check)] a.{self::_Vector::[]}(i){(core::int) → core::double}){(core::num) → core::double}){(core::num) → core::double};
diff --git a/sdk/bin/dart b/sdk/bin/dart
index 34cb80b..fb35d55 100755
--- a/sdk/bin/dart
+++ b/sdk/bin/dart
@@ -29,8 +29,8 @@
 then
   DIRS=$( ls "$OUT_DIR" )
   # list of possible configurations in decreasing desirability
-  CONFIGS=("ReleaseX64" "ReleaseIA32" "DebugX64" "DebugIA32"
-    "ReleaseARM" "ReleaseARM64" "DebugARM" "DebugARM64" )
+  CONFIGS=("ReleaseX64" "ReleaseARM64" "ReleaseIA32" "DebugX64" "DebugIA32"
+    "ReleaseARM" "DebugARM" "DebugARM64" )
   DART_CONFIGURATION="None"
   for CONFIG in ${CONFIGS[*]}
   do
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
index 9c9e4b9..6a2f7b6 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
@@ -858,7 +858,8 @@
     return value;
   };
   $desc.configurable = true;
-  if ($desc.set != null) {
+  let setter = $desc.set;
+  if (setter != null) {
     $desc.set = function(x) {
       if (!savedLocals) {
         $resetFields.push(() => {
@@ -871,6 +872,7 @@
       }
       init = null;
       value = x;
+      setter(x);
     };
   }
   return ${defineProperty(to, name, desc)};
@@ -914,7 +916,8 @@
     }
   };
   $desc.configurable = true;
-  if ($desc.set != null) {
+  let setter = $desc.set;
+  if (setter != null) {
     $desc.set = function(x) {
       if (!savedLocals) {
         $resetFields.push(() => {
@@ -926,6 +929,7 @@
       }
       init = null;
       value = x;
+      setter(x);
     };
   }
   return ${defineProperty(to, name, desc)};
diff --git a/sdk/lib/_internal/vm/bin/vmservice_io.dart b/sdk/lib/_internal/vm/bin/vmservice_io.dart
index 033a9cf..f70166e 100644
--- a/sdk/lib/_internal/vm/bin/vmservice_io.dart
+++ b/sdk/lib/_internal/vm/bin/vmservice_io.dart
@@ -108,7 +108,7 @@
       mode: ProcessStartMode.detachedWithStdio,
     );
     final completer = Completer<void>();
-    late StreamSubscription stderrSub;
+    late StreamSubscription<String> stderrSub;
     stderrSub = _process!.stderr.transform(utf8.decoder).listen((event) {
       final result = json.decode(event) as Map<String, dynamic>;
       final state = result['state'];
@@ -145,7 +145,7 @@
   Process? _process;
 }
 
-Future cleanupCallback() async {
+Future<void> cleanupCallback() async {
   // Cancel the sigquit subscription.
   if (_signalSubscription != null) {
     await _signalSubscription.cancel();
@@ -191,7 +191,7 @@
   return fsUri;
 }
 
-Future deleteDirCallback(Uri path) async =>
+Future<void> deleteDirCallback(Uri path) async =>
     await Directory.fromUri(path).delete(recursive: true);
 
 class PendingWrite {
@@ -200,7 +200,7 @@
   final Uri uri;
   final List<int> bytes;
 
-  Future write() async {
+  Future<void> write() async {
     final file = File.fromUri(uri);
     final parent_directory = file.parent;
     await parent_directory.create(recursive: true);
@@ -221,7 +221,7 @@
   static const kMaxOpenWrites = 16;
   static int openWrites = 0;
 
-  static Future scheduleWrite(Uri path, List<int> bytes) async {
+  static Future<void> scheduleWrite(Uri path, List<int> bytes) async {
     // Create a new pending write.
     final pw = PendingWrite(path, bytes);
     pendingWrites.add(pw);
@@ -229,7 +229,7 @@
     return pw.completer.future;
   }
 
-  static _maybeWriteFiles() {
+  static void _maybeWriteFiles() {
     while (openWrites < kMaxOpenWrites) {
       if (pendingWrites.length > 0) {
         final pw = pendingWrites.removeLast();
@@ -241,14 +241,14 @@
     }
   }
 
-  static _writeCompleted() {
+  static void _writeCompleted() {
     openWrites--;
     assert(openWrites >= 0);
     _maybeWriteFiles();
   }
 }
 
-Future writeFileCallback(Uri path, List<int> bytes) async =>
+Future<void> writeFileCallback(Uri path, List<int> bytes) async =>
     WriteLimiter.scheduleWrite(path, bytes);
 
 Future<void> writeStreamFileCallback(Uri path, Stream<List<int>> bytes) async {
@@ -336,7 +336,7 @@
 
 Timer? _registerSignalHandlerTimer;
 
-_registerSignalHandler() {
+void _registerSignalHandler() {
   if (VMService().isExiting) {
     // If the VM started shutting down we don't want to register this signal
     // handler, otherwise we'll cause the VM to hang after killing the service
diff --git a/sdk/lib/_internal/vm/bin/vmservice_server.dart b/sdk/lib/_internal/vm/bin/vmservice_server.dart
index 129e237..03ea982 100644
--- a/sdk/lib/_internal/vm/bin/vmservice_server.dart
+++ b/sdk/lib/_internal/vm/bin/vmservice_server.dart
@@ -28,40 +28,33 @@
     socket.done.then((_) => close());
   }
 
-  Future<void> disconnect() async {
-    if (socket != null) {
-      await socket.close();
-    }
-  }
+  Future<void> disconnect() => socket.close();
 
   void onWebSocketMessage(message) {
     if (message is String) {
-      Map map;
+      dynamic jsonObj;
       try {
-        map = json.decode(message);
+        jsonObj = json.decode(message);
       } catch (e) {
         socket.close(parseErrorCode, 'Message parse error: $e');
         return;
       }
-      if (map is! Map) {
+      if (jsonObj is! Map<String, dynamic>) {
         socket.close(notMapErrorCode, 'Message must be a JSON map.');
         return;
       }
-      try {
-        final rpc = Message.fromJsonRpc(this, map);
-        switch (rpc.type) {
-          case MessageType.Request:
-            onRequest(rpc);
-            break;
-          case MessageType.Notification:
-            onNotification(rpc);
-            break;
-          case MessageType.Response:
-            onResponse(rpc);
-            break;
-        }
-      } on dynamic catch (e) {
-        socket.close(idErrorCode, e.message);
+      final Map<String, dynamic> map = jsonObj;
+      final rpc = Message.fromJsonRpc(this, map);
+      switch (rpc.type) {
+        case MessageType.Request:
+          onRequest(rpc);
+          break;
+        case MessageType.Notification:
+          onNotification(rpc);
+          break;
+        case MessageType.Response:
+          onResponse(rpc);
+          break;
       }
     } else {
       socket.close(binaryMessageErrorCode, 'Message must be a string.');
@@ -80,7 +73,7 @@
           socket.add(result.payload);
           break;
         case ResponsePayloadKind.Utf8String:
-          socket.addUtf8Text(result.payload);
+          socket.addUtf8Text(result.payload as List<int>);
           break;
       }
     } on StateError catch (_) {
@@ -272,7 +265,7 @@
         : '/${requestPathSegments.sublist(1).join('/')}';
   }
 
-  Future _requestHandler(HttpRequest request) async {
+  Future<void> _requestHandler(HttpRequest request) async {
     if (!_originCheck(request)) {
       // This is a cross origin attempt to connect
       request.response.statusCode = HttpStatus.forbidden;
@@ -283,10 +276,10 @@
     if (request.method == 'PUT') {
       // PUT requests are forwarded to DevFS for processing.
 
-      List fsNameList;
-      List? fsPathList;
-      List? fsPathBase64List;
-      List? fsUriBase64List;
+      List<String> fsNameList;
+      List<String>? fsPathList;
+      List<String>? fsPathBase64List;
+      List<String>? fsUriBase64List;
       Object? fsName;
       Object? fsPath;
       Uri? fsUri;
@@ -327,11 +320,8 @@
         return;
       }
 
-      if (result != null) {
-        request.response.headers.contentType =
-            HttpRequestClient.jsonContentType;
-        request.response.write(result);
-      }
+      request.response.headers.contentType = HttpRequestClient.jsonContentType;
+      request.response.write(result);
       request.response.close();
       return;
     }
@@ -398,12 +388,12 @@
     client.onRequest(message); // exception free, no need to try catch
   }
 
-  Future<void> _dumpServiceInfoToFile(String serviceInfoFilenameLocal) async {
+  Future<File> _dumpServiceInfoToFile(String serviceInfoFilenameLocal) async {
     final serviceInfo = <String, dynamic>{
       'uri': serverAddress.toString(),
     };
     final file = File.fromUri(Uri.parse(serviceInfoFilenameLocal));
-    return file.writeAsString(json.encode(serviceInfo)) as Future<void>;
+    return file.writeAsString(json.encode(serviceInfo));
   }
 
   Future<Server> startup() async {
diff --git a/sdk/lib/vmservice/asset.dart b/sdk/lib/vmservice/asset.dart
index b42df32..985c905 100644
--- a/sdk/lib/vmservice/asset.dart
+++ b/sdk/lib/vmservice/asset.dart
@@ -42,10 +42,10 @@
     if (tarBytes == null) {
       return null;
     }
-    List assetList = _decodeAssets(tarBytes);
-    Map<String, Asset> assets = new HashMap<String, Asset>();
+    final assetList = _decodeAssets(tarBytes);
+    final assets = <String, Asset>{};
     for (int i = 0; i < assetList.length; i += 2) {
-      final a = Asset(assetList[i], assetList[i + 1]);
+      final a = Asset(assetList[i] as String, assetList[i + 1] as Uint8List);
       assets[a.name] = a;
     }
     return assets;
@@ -55,7 +55,7 @@
 }
 
 @pragma("vm:external-name", "VMService_DecodeAssets")
-external List _decodeAssets(Uint8List data);
+external List<Object> _decodeAssets(Uint8List data);
 
 Map<String, Asset>? _assets;
 Map<String, Asset> get assets {
diff --git a/sdk/lib/vmservice/devfs.dart b/sdk/lib/vmservice/devfs.dart
index 3463d6c..2815b06 100644
--- a/sdk/lib/vmservice/devfs.dart
+++ b/sdk/lib/vmservice/devfs.dart
@@ -84,7 +84,7 @@
     if (deleteDir == null) {
       return;
     }
-    final deletions = <Future>[
+    final deletions = <Future<void>>[
       for (final fs in _fsMap.values) deleteDir(fs.uri),
     ];
     Future.wait(deletions);
@@ -350,7 +350,7 @@
             details: "${message.method}: invalid 'files' parameter "
                 "at index ${i}: ${fileInfo}");
       }
-      final uri = fs.resolvePath(fileInfo[0]);
+      final uri = fs.resolvePath(fileInfo[0] as String);
       if (uri == null) {
         return encodeRpcError(message, kInvalidParams,
             details: "${message.method}: invalid 'files' parameter "
@@ -358,9 +358,10 @@
       }
       uris.add(uri);
     }
-    final pendingWrites = <Future>[];
+    final pendingWrites = <Future<void>>[];
     for (int i = 0; i < uris.length; i++) {
-      final decodedFileContents = base64.decode(files[i][1]);
+      final file = files[i].cast<String>();
+      final decodedFileContents = base64.decode(file[1]);
       pendingWrites.add(writeFile(uris[i], decodedFileContents));
     }
     await Future.wait(pendingWrites);
@@ -386,7 +387,7 @@
     final fileList = await listFiles(fs.uri);
     // Remove any url-encoding in the filenames.
     for (int i = 0; i < fileList.length; i++) {
-      fileList[i]['name'] = Uri.decodeFull(fileList[i]['name']);
+      fileList[i]['name'] = Uri.decodeFull(fileList[i]['name'] as String);
     }
     final result = <String, dynamic>{'type': 'FSFileList', 'files': fileList};
     return encodeResult(message, result);
diff --git a/sdk/lib/vmservice/message.dart b/sdk/lib/vmservice/message.dart
index e1164e5..a0b1fbf 100644
--- a/sdk/lib/vmservice/message.dart
+++ b/sdk/lib/vmservice/message.dart
@@ -18,15 +18,15 @@
   final MessageType type;
 
   // Client-side identifier for this message.
-  final serial;
+  final Object? serial;
 
   final String? method;
 
   final params = <String, dynamic>{};
-  final result = {};
-  final error = {};
+  final result = <String, dynamic>{};
+  final error = <String, dynamic>{};
 
-  factory Message.fromJsonRpc(Client? client, Map map) {
+  factory Message.fromJsonRpc(Client? client, Map<String, dynamic> map) {
     if (map.containsKey('id')) {
       final id = map['id'];
       if (id != null && id is! num && id is! String) {
@@ -48,47 +48,47 @@
   }
 
   // http://www.jsonrpc.org/specification#request_object
-  Message._fromJsonRpcRequest(Client? client, Map map)
+  Message._fromJsonRpcRequest(Client? client, Map<String, dynamic> map)
       : client = client,
         type = MessageType.Request,
         serial = map['id'],
-        method = map['method'] {
+        method = (map['method'] as String?) {
     if (map['params'] != null) {
-      params.addAll(map['params']);
+      params.addAll(map['params'] as Map<String, dynamic>);
     }
   }
 
   // http://www.jsonrpc.org/specification#notification
-  Message._fromJsonRpcNotification(Client? client, Map map)
+  Message._fromJsonRpcNotification(Client? client, Map<String, dynamic> map)
       : client = client,
         type = MessageType.Notification,
-        method = map['method'],
+        method = (map['method'] as String?),
         serial = null {
     if (map['params'] != null) {
-      params.addAll(map['params']);
+      params.addAll(map['params'] as Map<String, dynamic>);
     }
   }
 
   // http://www.jsonrpc.org/specification#response_object
-  Message._fromJsonRpcResult(Client? client, Map map)
+  Message._fromJsonRpcResult(Client? client, Map<String, dynamic> map)
       : client = client,
         type = MessageType.Response,
         serial = map['id'],
         method = null {
-    result.addAll(map['result']);
+    result.addAll(map['result'] as Map<String, dynamic>);
   }
 
   // http://www.jsonrpc.org/specification#response_object
-  Message._fromJsonRpcError(Client? client, Map map)
+  Message._fromJsonRpcError(Client? client, Map<String, dynamic> map)
       : client = client,
         type = MessageType.Response,
         serial = map['id'],
         method = null {
-    error.addAll(map['error']);
+    error.addAll(map['error'] as Map<String, dynamic>);
   }
 
   static String _methodNameFromUri(Uri uri) {
-    if (uri == null || uri.pathSegments.length == 0) {
+    if (uri.pathSegments.length == 0) {
       return '';
     }
     return uri.pathSegments[0];
@@ -147,7 +147,7 @@
   // elements in the list are strings, making consumption by C++ simpler.
   // This has a side effect that boolean literal values like true become 'true'
   // and thus indistinguishable from the string literal 'true'.
-  List<String> _makeAllString(List list) {
+  List<String> _makeAllString(List<Object> list) {
     var new_list = List<String>.filled(list.length, "");
     for (var i = 0; i < list.length; i++) {
       new_list[i] = list[i].toString();
@@ -167,8 +167,9 @@
       _setResponseFromPort(value);
     };
     final keys = _makeAllString(params.keys.toList(growable: false));
-    final values = _makeAllString(params.values.toList(growable: false));
-    final request = List<dynamic>.filled(6, null)
+    final values =
+        _makeAllString(params.values.cast<Object>().toList(growable: false));
+    final request = List<Object?>.filled(6, null)
       ..[0] = 0 // Make room for OOB message type.
       ..[1] = receivePort.sendPort
       ..[2] = serial
@@ -212,7 +213,7 @@
       _setResponseFromPort(value);
     };
     var keys = params.keys.toList(growable: false);
-    var values = params.values.toList(growable: false);
+    var values = params.values.cast<Object>().toList(growable: false);
     if (!_methodNeedsObjectParameters(method!)) {
       keys = _makeAllString(keys);
       values = _makeAllString(values);
@@ -235,7 +236,7 @@
     return _completer.future;
   }
 
-  void _setResponseFromPort(dynamic response) {
+  void _setResponseFromPort(Object? response) {
     if (response == null) {
       // We should only have a null response for Notifications.
       assert(type == MessageType.Notification);
@@ -252,10 +253,10 @@
 }
 
 @pragma("vm:external-name", "VMService_SendIsolateServiceMessage")
-external bool sendIsolateServiceMessage(SendPort sp, List m);
+external bool sendIsolateServiceMessage(SendPort sp, List<Object?> m);
 
 @pragma("vm:external-name", "VMService_SendRootServiceMessage")
-external void sendRootServiceMessage(List m);
+external void sendRootServiceMessage(List<Object?> m);
 
 @pragma("vm:external-name", "VMService_SendObjectRootServiceMessage")
-external void sendObjectRootServiceMessage(List m);
+external void sendObjectRootServiceMessage(List<Object?> m);
diff --git a/sdk/lib/vmservice/message_router.dart b/sdk/lib/vmservice/message_router.dart
index 2ca8d4f..fb5adac 100644
--- a/sdk/lib/vmservice/message_router.dart
+++ b/sdk/lib/vmservice/message_router.dart
@@ -74,9 +74,9 @@
   dynamic decodeJson() {
     switch (kind) {
       case ResponsePayloadKind.String:
-        return json.decode(payload);
+        return json.decode(payload as String);
       case ResponsePayloadKind.Utf8String:
-        return json.fuse(utf8).decode(payload);
+        return json.fuse(utf8).decode(payload as List<int>);
       case ResponsePayloadKind.Binary:
         throw 'Binary responses can not be decoded';
     }
diff --git a/sdk/lib/vmservice/named_lookup.dart b/sdk/lib/vmservice/named_lookup.dart
index 0c0a5a8..8431ccf 100644
--- a/sdk/lib/vmservice/named_lookup.dart
+++ b/sdk/lib/vmservice/named_lookup.dart
@@ -48,7 +48,7 @@
 
   /// Returns a new Id (possibly recycled)
   String newId() {
-    var id;
+    String id;
     if (_free.isEmpty) {
       id = prologue + (_next++).toString();
     } else {
diff --git a/sdk/lib/vmservice/running_isolate.dart b/sdk/lib/vmservice/running_isolate.dart
index 3902193..de8bf87 100644
--- a/sdk/lib/vmservice/running_isolate.dart
+++ b/sdk/lib/vmservice/running_isolate.dart
@@ -14,7 +14,7 @@
 
   void onIsolateExit() {
     pendingMessagesReceivePorts.forEach((port) {
-      (port as RawReceivePort).close();
+      port.close();
     });
   }
 
diff --git a/sdk/lib/vmservice/running_isolates.dart b/sdk/lib/vmservice/running_isolates.dart
index e699cb3..09f2f55 100644
--- a/sdk/lib/vmservice/running_isolates.dart
+++ b/sdk/lib/vmservice/running_isolates.dart
@@ -27,7 +27,7 @@
 
   @override
   Future<Response> routeRequest(VMService service, Message message) {
-    String isolateParam = message.params['isolateId']!;
+    String isolateParam = message.params['isolateId']! as String;
     int isolateId;
     if (!isolateParam.startsWith('isolates/')) {
       message.setErrorResponse(
@@ -76,16 +76,20 @@
 
   Future<Response> run() async {
     final buildScopeResponse = await _buildScope();
-    final responseJson = buildScopeResponse.decodeJson();
+    final responseJson =
+        buildScopeResponse.decodeJson() as Map<String, dynamic>;
 
     if (responseJson.containsKey('error')) {
-      return Response.from(encodeCompilationError(
-          _message, responseJson['error']['data']['details']));
+      final error = responseJson['error'] as Map<String, dynamic>;
+      final data = error['data'] as Map<String, dynamic>;
+      return Response.from(
+          encodeCompilationError(_message, data['details'] as String));
     }
 
     String kernelBase64;
     try {
-      kernelBase64 = await _compileExpression(responseJson['result']);
+      kernelBase64 = await _compileExpression(
+          responseJson['result'] as Map<String, dynamic>);
     } catch (e) {
       return Response.from(encodeCompilationError(_message, e.toString()));
     }
@@ -105,7 +109,8 @@
       'params': params,
     };
     if (_message.params['scope'] != null) {
-      buildScopeParams['params']['scope'] = _message.params['scope'];
+      (buildScopeParams['params'] as Map<String, dynamic>)['scope'] =
+          _message.params['scope'];
     }
     final buildScope =
         Message._fromJsonRpcRequest(_message.client!, buildScopeParams);
@@ -157,11 +162,12 @@
       externalClient.post(Response.json(compileExpression
           .forwardToJson({'id': id, 'method': 'compileExpression'})));
       return completer.future.then((s) => jsonDecode(s)).then((json) {
-        final Map<String, dynamic> jsonMap = json;
+        final jsonMap = json as Map<String, dynamic>;
         if (jsonMap.containsKey('error')) {
-          throw jsonMap['error'];
+          throw jsonMap['error'] as Object;
         }
-        return jsonMap['result']['kernelBytes'];
+        return (jsonMap['result'] as Map<String, dynamic>)['kernelBytes']
+            as String;
       });
     } else {
       // fallback to compile using kernel service
@@ -177,10 +183,14 @@
           .routeRequest(_service, compileExpression)
           .then((response) => response.decodeJson())
           .then((json) {
-        if (json['result'] != null) {
-          return json['result']['kernelBytes'];
+        final response = json as Map<String, dynamic>;
+        if (response['result'] != null) {
+          return (response['result'] as Map<String, dynamic>)['kernelBytes']
+              as String;
         }
-        throw json['error']['data']['details'];
+        final error = response['error'] as Map<String, dynamic>;
+        final data = error['data'] as Map<String, dynamic>;
+        throw data['details'] as Object;
       });
     }
   }
@@ -197,7 +207,8 @@
         'params': params,
       };
       if (_message.params['scope'] != null) {
-        runParams['params']['scope'] = _message.params['scope'];
+        (runParams['params'] as Map<String, dynamic>)['scope'] =
+            _message.params['scope'];
       }
       final runExpression =
           Message._fromJsonRpcRequest(_message.client!, runParams);
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index ae16c86..eac4597 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -102,7 +102,7 @@
     },
   };
   if (details != null) {
-    response['error']['data'] = <String, String>{
+    (response['error'] as Map<String, dynamic>)['data'] = <String, String>{
       'details': details,
     };
   }
@@ -122,7 +122,8 @@
 String encodeCompilationError(Message message, String diagnostic) =>
     encodeRpcError(message, kExpressionCompilationError, details: diagnostic);
 
-String encodeResult(Message message, Map result) => json.encode({
+String encodeResult(Message message, Map<String, dynamic> result) =>
+    json.encode({
       'jsonrpc': '2.0',
       'id': message.serial,
       'result': result,
@@ -134,10 +135,10 @@
 const shortDelay = Duration(milliseconds: 10);
 
 /// Called when the server should be started.
-typedef Future ServerStartCallback();
+typedef Future<void> ServerStartCallback();
 
 /// Called when the server should be stopped.
-typedef Future ServerStopCallback();
+typedef Future<void> ServerStopCallback();
 
 /// Called when DDS has connected.
 typedef Future<void> DdsConnectedCallback();
@@ -146,19 +147,19 @@
 typedef Future<void> DdsDisconnectedCallback();
 
 /// Called when the service is exiting.
-typedef Future CleanupCallback();
+typedef Future<void> CleanupCallback();
 
 /// Called to create a temporary directory
 typedef Future<Uri> CreateTempDirCallback(String base);
 
 /// Called to delete a directory
-typedef Future DeleteDirCallback(Uri path);
+typedef Future<void> DeleteDirCallback(Uri path);
 
 /// Called to write a file.
-typedef Future WriteFileCallback(Uri path, List<int> bytes);
+typedef Future<void> WriteFileCallback(Uri path, List<int> bytes);
 
 /// Called to write a stream into a file.
-typedef Future WriteStreamFileCallback(Uri path, Stream<List<int>> bytes);
+typedef Future<void> WriteStreamFileCallback(Uri path, Stream<List<int>> bytes);
 
 /// Called to read a file.
 typedef Future<List<int>> ReadFileCallback(Uri path);
@@ -269,7 +270,7 @@
           details: 'A DDS instance is already connected at ${_ddsUri!}.');
     }
 
-    final uri = message.params['uri'];
+    final uri = message.params['uri'] as String?;
     if (uri == null) {
       return encodeMissingParamError(message, 'uri');
     }
@@ -340,13 +341,15 @@
 
   void _profilerEventMessageHandler(Client client, Response event) {
     final eventJson = event.decodeJson() as Map<String, dynamic>;
-    final eventData = eventJson['params']!['event']!;
+    final params = eventJson['params']! as Map<String, dynamic>;
+    final eventData = params['event']! as Map<String, dynamic>;
     if (eventData['kind']! != 'CpuSamples') {
       client.post(event);
       return;
     }
-    final cpuSamplesEvent = eventData['cpuSamples']!;
-    final updatedSamples = cpuSamplesEvent['samples']!
+    final cpuSamplesEvent = eventData['cpuSamples']! as Map<String, dynamic>;
+    final samples = cpuSamplesEvent['samples']!.cast<Map<String, dynamic>>();
+    final updatedSamples = samples
         .where(
           (s) => client.profilerUserTagFilters.contains(s['userTag']),
         )
@@ -407,13 +410,14 @@
     }
   }
 
-  Future<void> _handleNativeRpcCall(message, SendPort replyPort) async {
+  Future<void> _handleNativeRpcCall(
+      List<int> message, SendPort replyPort) async {
     // Keep in sync with 'runtime/vm/service_isolate.cc:InvokeServiceRpc'.
     Response response;
 
     try {
       final rpc = Message.fromJsonRpc(
-          null, json.decode(utf8.decode(message as List<int>)));
+          null, json.decode(utf8.decode(message)) as Map<String, dynamic>);
       if (rpc.type != MessageType.Request) {
         response = Response.internalError(
             'The client sent a non-request json-rpc message.');
@@ -427,7 +431,7 @@
     late List<int> bytes;
     switch (response.kind) {
       case ResponsePayloadKind.String:
-        bytes = utf8.encode(response.payload);
+        bytes = utf8.encode(response.payload as String);
         bytes = bytes is Uint8List ? bytes : Uint8List.fromList(bytes);
         break;
       case ResponsePayloadKind.Binary:
@@ -448,7 +452,7 @@
     devfs.cleanup();
   }
 
-  Future _exit() async {
+  Future<void> _exit() async {
     isExiting = true;
 
     final serverStop = VMServiceEmbedderHooks.serverStop;
@@ -474,7 +478,8 @@
     if (message is List) {
       if (message.length == 2) {
         // This is an event.
-        _eventMessageHandler(message[0], Response.from(message[1]));
+        _eventMessageHandler(
+            message[0] as String, Response.from(message[1] as Object));
         return;
       }
       if (message.length == 1) {
@@ -485,20 +490,25 @@
       }
       final opcode = message[0];
       if (message.length == 3 && opcode == Constants.METHOD_CALL_FROM_NATIVE) {
-        _handleNativeRpcCall(message[1], message[2]);
+        _handleNativeRpcCall(message[1] as List<int>, message[2] as SendPort);
         return;
       }
       if (message.length == 4) {
         if ((opcode == Constants.WEB_SERVER_CONTROL_MESSAGE_ID) ||
             (opcode == Constants.SERVER_INFO_MESSAGE_ID)) {
           // This is a message interacting with the web server.
-          _serverMessageHandler(message[0], message[1], message[2], message[3]);
+          _serverMessageHandler(
+            message[0] as int,
+            message[1] as SendPort,
+            message[2] as bool,
+            message[3] as bool?,
+          );
           return;
         } else {
           // This is a message informing us of the birth or death of an
           // isolate.
-          _controlMessageHandler(
-              message[0], message[1], message[2], message[3]);
+          _controlMessageHandler(message[0] as int, message[1] as int,
+              message[2] as SendPort, message[3] as String);
           return;
         }
       }
@@ -543,7 +553,7 @@
 
   Future<String> _streamListen(Message message) async {
     final client = message.client!;
-    final streamId = message.params['streamId']!;
+    final streamId = message.params['streamId']! as String;
 
     if (client.streams.contains(streamId)) {
       return encodeRpcError(message, kStreamAlreadySubscribed);
@@ -576,7 +586,7 @@
 
   Future<String> _streamCancel(Message message) async {
     final client = message.client!;
-    final streamId = message.params['streamId']!;
+    final streamId = message.params['streamId']! as String;
 
     if (!client.streams.contains(streamId)) {
       return encodeRpcError(message, kStreamNotSubscribed);
@@ -676,11 +686,12 @@
   }
 
   Future<String> _getSupportedProtocols(Message message) async {
-    final version = json.decode(
+    final payload = json.decode(
       utf8.decode(
-        (await Message.forMethod('getVersion').sendToVM()).payload,
+        (await Message.forMethod('getVersion').sendToVM()).payload as List<int>,
       ),
-    )['result'];
+    ) as Map<String, dynamic>;
+    final version = payload['result'] as Map<String, dynamic>;
     final protocols = {
       'type': 'ProtocolList',
       'protocols': [
@@ -722,7 +733,8 @@
 
     // TODO(bkonyi): handle "subscribe all" case.
     final client = message.client!;
-    final tags = message.params['userTags']!.cast<String>().toSet();
+    final userTags = message.params['userTags']!.cast<String>();
+    final tags = userTags.toSet();
     final newTags = tags.difference(_profilerUserTagSubscriptions);
 
     // Clear the previously set user tag subscriptions for the client and
@@ -755,7 +767,7 @@
     return Response.from(response);
   }
 
-  Future _routeRequestImpl(Message message) async {
+  Future<Object?> _routeRequestImpl(Message message) async {
     try {
       if (message.completed) {
         return await message.response;
@@ -798,7 +810,7 @@
     final client = message.client!;
     if (client.serviceHandles.containsKey(message.serial)) {
       client.serviceHandles.remove(message.serial)!(message);
-      _serviceRequests.release(message.serial);
+      _serviceRequests.release(message.serial as String);
     }
   }
 }
@@ -841,7 +853,7 @@
 
 /// Get the bytes to the tar archive.
 @pragma("vm:external-name", "VMService_RequestAssets")
-external Uint8List _requestAssets();
+external Uint8List? _requestAssets();
 
 @pragma("vm:external-name", "VMService_AddUserTagsToStreamableSampleList")
 external void _addUserTagsToStreamableSampleList(List<String> userTags);
diff --git a/tests/dartdevc/hot_restart_static_test.dart b/tests/dartdevc/hot_restart_static_test.dart
index c26c298..5b62495 100644
--- a/tests/dartdevc/hot_restart_static_test.dart
+++ b/tests/dartdevc/hot_restart_static_test.dart
@@ -23,7 +23,20 @@
   static int withInitializer = 3;
 }
 
-main() {
+class StaticsSetter {
+  static int counter = 0;
+  static const field = 5;
+  static const field2 = null;
+  static set field(int value) => StaticsSetter.counter += 1;
+  static set field2(value) => 42;
+}
+
+void main() {
+  testStaticFields();
+  testStaticSetterOfConstField();
+}
+
+void testStaticFields() {
   var resetFieldCount = dart.resetFields.length;
 
   // Set static fields without explicit initializers. Avoid calling getters for
@@ -82,3 +95,49 @@
   expectedResets = resetFieldCount + 6;
   Expect.equals(expectedResets, dart.resetFields.length);
 }
+
+void testStaticSetterOfConstField() {
+  var resetFieldCount = dart.resetFields.length;
+
+  // Static setters of const fields should behave according to spec.
+  Expect.equals(StaticsSetter.counter, 0);
+  Expect.equals(StaticsSetter.field, 5);
+  StaticsSetter.field = 100;
+  StaticsSetter.field = 100;
+  StaticsSetter.field = 100;
+  Expect.equals(StaticsSetter.field, 5);
+  Expect.equals(StaticsSetter.counter, 3);
+
+  // 2 new field resets: [StaticsSetter.counter] and [StaticsSetter.field].
+  var expectedResets = resetFieldCount + 2;
+  Expect.equals(expectedResets, dart.resetFields.length);
+
+  dart.hotRestart();
+  resetFieldCount = dart.resetFields.length;
+
+  // Static setters of const fields should be properly reset.
+  Expect.equals(StaticsSetter.counter, 0);
+  Expect.equals(StaticsSetter.field, 5);
+  StaticsSetter.field = 100;
+  StaticsSetter.field = 100;
+  StaticsSetter.field = 100;
+  Expect.equals(StaticsSetter.field, 5);
+  Expect.equals(StaticsSetter.counter, 3);
+
+  // 2 new field resets: [StaticsSetter.counter] and [StaticsSetter.field].
+  expectedResets = resetFieldCount + 2;
+  Expect.equals(expectedResets, dart.resetFields.length);
+
+  dart.hotRestart();
+  dart.hotRestart();
+  resetFieldCount = dart.resetFields.length;
+
+  // Invoke the static setter but not the getter.
+  StaticsSetter.field2 = 100;
+  StaticsSetter.field2 = 100;
+  StaticsSetter.field2 = 100;
+
+  // 1 new field reset: [StaticsSetter.field2].
+  expectedResets = resetFieldCount + 1;
+  Expect.equals(expectedResets, dart.resetFields.length);
+}
diff --git a/tests/language/static/static_setter_on_const_field_test.dart b/tests/language/static/static_setter_on_const_field_test.dart
new file mode 100644
index 0000000..48b1700
--- /dev/null
+++ b/tests/language/static/static_setter_on_const_field_test.dart
@@ -0,0 +1,29 @@
+// 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:expect/expect.dart";
+
+// Tests that static setters on const fields are properly invoked on set.
+
+class A {
+  static const int field = 0;
+  static void set field(int value) {
+    Expect.equals(value, 100);
+    B.count += 1;
+  }
+}
+
+class B {
+  static int count = 0;
+}
+
+main() {
+  Expect.equals(B.count, 0);
+  A.field = 100;
+  Expect.equals(B.count, 1);
+  Expect.equals(A.field, 0);
+  A.field = 100;
+  Expect.equals(B.count, 2);
+  Expect.equals(A.field, 0);
+}
diff --git a/tests/language_2/static/static_setter_on_const_field_test.dart b/tests/language_2/static/static_setter_on_const_field_test.dart
new file mode 100644
index 0000000..354e724
--- /dev/null
+++ b/tests/language_2/static/static_setter_on_const_field_test.dart
@@ -0,0 +1,31 @@
+// 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.
+
+// @dart = 2.9
+
+import "package:expect/expect.dart";
+
+// Tests that static setters of const fields are properly invoked on set.
+
+class A {
+  static const int field = 0;
+  static void set field(int value) {
+    Expect.equals(value, 100);
+    B.count += 1;
+  }
+}
+
+class B {
+  static int count = 0;
+}
+
+main() {
+  Expect.equals(B.count, 0);
+  A.field = 100;
+  Expect.equals(B.count, 1);
+  Expect.equals(A.field, 0);
+  A.field = 100;
+  Expect.equals(B.count, 2);
+  Expect.equals(A.field, 0);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 0ec8410..98d02ab 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 266
+PRERELEASE 267
 PRERELEASE_PATCH 0
\ No newline at end of file