Version 2.18.0-82.0.dev

Merge commit '9c572f08cab7df52c8dfd7f5105885668d9d16fc' into 'dev'
diff --git a/DEPS b/DEPS
index fe525a4..8501f0d 100644
--- a/DEPS
+++ b/DEPS
@@ -182,7 +182,7 @@
   # Pinned browser versions used by the testing infrastructure. These are not
   # meant to be downloaded by users for local testing.
   "download_chrome": False,
-  "chrome_tag": "91",
+  "chrome_tag": "101.0.4951.41",
   "download_firefox": False,
   "firefox_tag": "98.0.2",
 }
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 ac13d91..75a29be 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -241,7 +241,7 @@
   String _createImportedSymbolKey(String name, Uri declaringUri) =>
       '$name/$declaringUri';
 
-  Future<List<CompletionItem>> _getDartSnippetItems({
+  Future<Iterable<CompletionItem>> _getDartSnippetItems({
     required LspClientCapabilities clientCapabilities,
     required ResolvedUnitResult unit,
     required int offset,
@@ -254,16 +254,14 @@
     final snippetManager = DartSnippetManager();
     final snippets = await snippetManager.computeSnippets(request);
 
-    return snippets
-        .map((snippet) => snippetToCompletionItem(
-              server,
-              clientCapabilities,
-              unit.path,
-              lineInfo,
-              toPosition(lineInfo.getLocation(offset)),
-              snippet,
-            ))
-        .toList();
+    return snippets.map((snippet) => snippetToCompletionItem(
+          server,
+          clientCapabilities,
+          unit.path,
+          lineInfo,
+          toPosition(lineInfo.getLocation(offset)),
+          snippet,
+        ));
   }
 
   Future<ErrorOr<CompletionList>> _getPluginResults(
@@ -310,6 +308,7 @@
       completionPreference: CompletionPreference.replace,
     );
     final target = completionRequest.target;
+    final fuzzy = _FuzzyFilterHelper(completionRequest.targetPrefix);
 
     if (triggerCharacter != null) {
       if (!_triggerCharacterValid(offset, triggerCharacter, target)) {
@@ -367,45 +366,48 @@
           ? false
           : server.clientConfiguration.global.completeFunctionCalls;
 
+      /// Helper to convert [CompletionSuggestions] to [CompletionItem].
+      CompletionItem suggestionToCompletionItem(CompletionSuggestion item) {
+        var itemReplacementOffset =
+            item.replacementOffset ?? completionRequest.replacementOffset;
+        var itemReplacementLength =
+            item.replacementLength ?? completionRequest.replacementLength;
+        var itemInsertLength = insertLength;
+
+        // Recompute the insert length if it may be affected by the above.
+        if (item.replacementOffset != null || item.replacementLength != null) {
+          itemInsertLength = _computeInsertLength(
+              offset, itemReplacementOffset, itemInsertLength);
+        }
+
+        // Convert to LSP ranges using the LineInfo.
+        Range? replacementRange = toRange(
+            unit.lineInfo, itemReplacementOffset, itemReplacementLength);
+        Range? insertionRange =
+            toRange(unit.lineInfo, itemReplacementOffset, itemInsertLength);
+
+        return toCompletionItem(
+          capabilities,
+          unit.lineInfo,
+          item,
+          replacementRange: replacementRange,
+          insertionRange: insertionRange,
+          // TODO(dantup): Move commit characters to the main response
+          // and remove from each individual item (to reduce payload size)
+          // once the following change ships (and the Dart VS Code
+          // extension is updated to use it).
+          // https://github.com/microsoft/vscode-languageserver-node/issues/673
+          includeCommitCharacters:
+              server.clientConfiguration.global.previewCommitCharacters,
+          completeFunctionCalls: completeFunctionCalls,
+        );
+      }
+
       final rankedResults = performance.run('mapSuggestions', (performance) {
-        return serverSuggestions.map(
-          (item) {
-            var itemReplacementOffset =
-                item.replacementOffset ?? completionRequest.replacementOffset;
-            var itemReplacementLength =
-                item.replacementLength ?? completionRequest.replacementLength;
-            var itemInsertLength = insertLength;
-
-            // Recompute the insert length if it may be affected by the above.
-            if (item.replacementOffset != null ||
-                item.replacementLength != null) {
-              itemInsertLength = _computeInsertLength(
-                  offset, itemReplacementOffset, itemInsertLength);
-            }
-
-            // Convert to LSP ranges using the LineInfo.
-            Range? replacementRange = toRange(
-                unit.lineInfo, itemReplacementOffset, itemReplacementLength);
-            Range? insertionRange =
-                toRange(unit.lineInfo, itemReplacementOffset, itemInsertLength);
-
-            return toCompletionItem(
-              capabilities,
-              unit.lineInfo,
-              item,
-              replacementRange: replacementRange,
-              insertionRange: insertionRange,
-              // TODO(dantup): Move commit characters to the main response
-              // and remove from each individual item (to reduce payload size)
-              // once the following change ships (and the Dart VS Code
-              // extension is updated to use it).
-              // https://github.com/microsoft/vscode-languageserver-node/issues/673
-              includeCommitCharacters:
-                  server.clientConfiguration.global.previewCommitCharacters,
-              completeFunctionCalls: completeFunctionCalls,
-            );
-          },
-        ).toList();
+        return serverSuggestions
+            .where(fuzzy.completionSuggestionMatches)
+            .map(suggestionToCompletionItem)
+            .toList();
       });
 
       // Now compute items in suggestion sets.
@@ -429,70 +431,77 @@
 
         // Build a fast lookup for imported symbols so that we can filter out
         // duplicates.
-        final alreadyImportedSymbols = _buildLookupOfImportedSymbols(unit);
+        final alreadyImportedSymbols =
+            performance.run('_buildLookupOfImportedSymbols', (performance) {
+          return _buildLookupOfImportedSymbols(unit);
+        });
+
+        /// Helper to check existing imports to ensure we don't already import
+        /// this element (this exact element from its declaring
+        /// library, not just something with the same name). If we do
+        /// we'll want to skip it.
+        bool isNotImportedOrLibraryIsFirst(Declaration item, Library library) {
+          final declaringUri =
+              item.parent?.locationLibraryUri ?? item.locationLibraryUri!;
+
+          // For enums and named constructors, only the parent enum/class is in
+          // the list of imported symbols so we use the parents name.
+          final nameKey = item.kind == DeclarationKind.ENUM_CONSTANT ||
+                  item.kind == DeclarationKind.CONSTRUCTOR
+              ? item.parent!.name
+              : item.name;
+          final key = _createImportedSymbolKey(nameKey, declaringUri);
+          final importingUris = alreadyImportedSymbols[key];
+
+          // Keep it only if:
+          // - no existing imports include it
+          //     (in which case all libraries will be offered as
+          //     auto-imports)
+          // - this is the first imported URI that includes it
+          //     (we don't want to repeat it for each imported library that
+          //     includes it)
+          return importingUris == null ||
+              importingUris.first == '${library.uri}';
+        }
+
+        /// Helper to filter to only the kinds we should return.
+        bool shouldIncludeKind(Declaration item) =>
+            includedElementKinds!.contains(protocolElementKind(item.kind));
+
+        // Only specific types of child declarations should be included.
+        // This list matches what's in _protocolAvailableSuggestion in
+        // the DAS implementation.
+        bool shouldIncludeChild(Declaration child) =>
+            child.kind == DeclarationKind.CONSTRUCTOR ||
+            child.kind == DeclarationKind.ENUM_CONSTANT ||
+            (child.kind == DeclarationKind.GETTER && child.isStatic) ||
+            (child.kind == DeclarationKind.FIELD && child.isStatic);
 
         performance.run('addIncludedSuggestionSets', (performance) {
           // Checked in `if` above.
           includedSuggestionRelevanceTags!;
 
-          for (var includedSet in includedSuggestionSets) {
+          // Make a fast lookup for tag relevance.
+          final tagBoosts = <String, int>{};
+          for (final t in includedSuggestionRelevanceTags) {
+            tagBoosts[t.tag] = t.relevanceBoost;
+          }
+
+          for (final includedSet in includedSuggestionSets) {
             final library = declarationsTracker.getLibrary(includedSet.id);
             if (library == null) {
               break;
             }
 
-            // Make a fast lookup for tag relevance.
-            final tagBoosts = <String, int>{};
-            for (var t in includedSuggestionRelevanceTags) {
-              tagBoosts[t.tag] = t.relevanceBoost;
-            }
-
-            // Only specific types of child declarations should be included.
-            // This list matches what's in _protocolAvailableSuggestion in
-            // the DAS implementation.
-            bool shouldIncludeChild(Declaration child) =>
-                child.kind == DeclarationKind.CONSTRUCTOR ||
-                child.kind == DeclarationKind.ENUM_CONSTANT ||
-                (child.kind == DeclarationKind.GETTER && child.isStatic) ||
-                (child.kind == DeclarationKind.FIELD && child.isStatic);
-
             // Collect declarations and their children.
-            final allDeclarations = library.declarations
+            final setResults = library.declarations
                 .followedBy(library.declarations
                     .expand((decl) => decl.children.where(shouldIncludeChild)))
-                .toList();
-
-            final setResults = allDeclarations
-                // Filter to only the kinds we should return.
-                .where((item) => includedElementKinds!
-                    .contains(protocolElementKind(item.kind)))
-                .where((item) {
-              // Check existing imports to ensure we don't already import
-              // this element (this exact element from its declaring
-              // library, not just something with the same name). If we do
-              // we'll want to skip it.
-              final declaringUri =
-                  item.parent?.locationLibraryUri ?? item.locationLibraryUri!;
-
-              // For enums and named constructors, only the parent enum/class is in
-              // the list of imported symbols so we use the parents name.
-              final nameKey = item.kind == DeclarationKind.ENUM_CONSTANT ||
-                      item.kind == DeclarationKind.CONSTRUCTOR
-                  ? item.parent!.name
-                  : item.name;
-              final key = _createImportedSymbolKey(nameKey, declaringUri);
-              final importingUris = alreadyImportedSymbols[key];
-
-              // Keep it only if:
-              // - no existing imports include it
-              //     (in which case all libraries will be offered as
-              //     auto-imports)
-              // - this is the first imported URI that includes it
-              //     (we don't want to repeat it for each imported library that
-              //     includes it)
-              return importingUris == null ||
-                  importingUris.first == '${library.uri}';
-            }).map((item) => declarationToCompletionItem(
+                .where(fuzzy.declarationMatches)
+                .where(shouldIncludeKind)
+                .where((Declaration item) =>
+                    isNotImportedOrLibraryIsFirst(item, library))
+                .map((item) => declarationToCompletionItem(
                       capabilities,
                       unit.path,
                       offset,
@@ -531,46 +540,26 @@
           isEditableFile) {
         unrankedResults =
             await performance.runAsync('getSnippets', (performance) async {
-          // `await` required for `performance.runAsync` to count time.
-          return await _getDartSnippetItems(
+          final snippets = await _getDartSnippetItems(
             clientCapabilities: capabilities,
             unit: unit,
             offset: offset,
             lineInfo: unit.lineInfo,
           );
+          return snippets.where(fuzzy.completionItemMatches).toList();
         });
       } else {
         unrankedResults = [];
       }
 
-      // Perform fuzzy matching based on the identifier in front of the caret to
-      // reduce the size of the payload.
-      final fuzzyPattern = completionRequest.targetPrefix;
-      final fuzzyMatcher =
-          FuzzyMatcher(fuzzyPattern, matchStyle: MatchStyle.TEXT);
-
-      final matchingRankedResults =
-          performance.run('fuzzyFilterRanked', (performance) {
-        return rankedResults
-            .where((e) => fuzzyMatcher.score(e.filterText ?? e.label) > 0)
-            .toList();
-      });
-
-      final matchingUnrankedResults =
-          performance.run('fuzzyFilterRanked', (performance) {
-        return unrankedResults
-            .where((e) => fuzzyMatcher.score(e.filterText ?? e.label) > 0)
-            .toList();
-      });
-
       // transmittedCount will be set after combining with plugins + truncation.
       completionPerformance.computedSuggestionCount =
-          matchingRankedResults.length + matchingUnrankedResults.length;
+          rankedResults.length + unrankedResults.length;
 
       return success(_CompletionResults(
           isIncomplete: false,
-          rankedItems: matchingRankedResults,
-          unrankedItems: matchingUnrankedResults));
+          rankedItems: rankedResults,
+          unrankedItems: unrankedResults));
     } on AbortCompletion {
       return success(_CompletionResults(isIncomplete: false));
     } on InconsistentAnalysisException {
@@ -771,3 +760,23 @@
     required this.isIncomplete,
   });
 }
+
+/// Helper to simplify fuzzy filtering.
+///
+/// Used to perform fuzzy matching based on the identifier in front of the caret to
+/// reduce the size of the payload.
+class _FuzzyFilterHelper {
+  final FuzzyMatcher _matcher;
+
+  _FuzzyFilterHelper(String prefix)
+      : _matcher = FuzzyMatcher(prefix, matchStyle: MatchStyle.TEXT);
+
+  bool completionItemMatches(CompletionItem item) =>
+      _matcher.score(item.filterText ?? item.label) > 0;
+
+  bool completionSuggestionMatches(CompletionSuggestion item) =>
+      _matcher.score(item.displayText ?? item.completion) > 0;
+
+  bool declarationMatches(Declaration item) =>
+      _matcher.score(getDeclarationName(item)) > 0;
+}
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 3bbb8c3..176162a 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -298,31 +298,10 @@
   required bool completeFunctionCalls,
 }) {
   final supportsSnippets = capabilities.completionSnippets;
-  final parent = declaration.parent;
 
-  String completion;
-  switch (declaration.kind) {
-    case DeclarationKind.ENUM_CONSTANT:
-      completion = '${parent!.name}.${declaration.name}';
-      break;
-    case DeclarationKind.GETTER:
-    case DeclarationKind.FIELD:
-      completion = parent != null && parent.name.isNotEmpty
-          ? '${parent.name}.${declaration.name}'
-          : declaration.name;
-      break;
-    case DeclarationKind.CONSTRUCTOR:
-      completion = parent!.name;
-      if (declaration.name.isNotEmpty) {
-        completion += '.${declaration.name}';
-      }
-      break;
-    default:
-      completion = declaration.name;
-      break;
-  }
   // By default, label is the same as the completion text, but may be added to
   // later (parens/snippets).
+  final completion = getDeclarationName(declaration);
   var label = completion;
 
   // isCallable is used to suffix the label with parens so it's clear the item
@@ -642,6 +621,32 @@
   }
 }
 
+String getDeclarationName(Declaration declaration) {
+  final parent = declaration.parent;
+  String completion;
+  switch (declaration.kind) {
+    case DeclarationKind.ENUM_CONSTANT:
+      completion = '${parent!.name}.${declaration.name}';
+      break;
+    case DeclarationKind.GETTER:
+    case DeclarationKind.FIELD:
+      completion = parent != null && parent.name.isNotEmpty
+          ? '${parent.name}.${declaration.name}'
+          : declaration.name;
+      break;
+    case DeclarationKind.CONSTRUCTOR:
+      completion = parent!.name;
+      if (declaration.name.isNotEmpty) {
+        completion += '.${declaration.name}';
+      }
+      break;
+    default:
+      completion = declaration.name;
+      break;
+  }
+  return completion;
+}
+
 List<lsp.DiagnosticTag>? getDiagnosticTags(
     Set<lsp.DiagnosticTag>? supportedTags, plugin.AnalysisError error) {
   if (supportedTags == null) {
diff --git a/pkg/analysis_server/lib/src/lsp/snippets.dart b/pkg/analysis_server/lib/src/lsp/snippets.dart
index 0c9d5c6..3cec1f0 100644
--- a/pkg/analysis_server/lib/src/lsp/snippets.dart
+++ b/pkg/analysis_server/lib/src/lsp/snippets.dart
@@ -124,7 +124,11 @@
       placeholder.offset < 0 ||
       placeholder.offset + placeholder.length > text.length);
 
-  final builder = SnippetBuilder()..appendPlaceholders(text, placeholders);
+  /// If there are no edit groups, then placeholders are all simple and
+  /// guaranteed to be in the correct order.
+  final isPreSorted = editGroups.isEmpty;
+  final builder = SnippetBuilder()
+    ..appendPlaceholders(text, placeholders, isPreSorted: isPreSorted);
   return builder.value;
 }
 
@@ -140,6 +144,18 @@
   /// The constant `$0` used do indicate a final tab stop in the snippet syntax.
   static const finalTabStop = r'$0';
 
+  /// Regex used by [escapeSnippetChoiceText].
+  static final _escapeSnippetChoiceTextRegex =
+      RegExp(r'[$}\\\|,]'); // Replace any of $ } \ | ,
+
+  /// Regex used by [escapeSnippetPlainText].
+  static final _escapeSnippetPlainTextRegex =
+      RegExp(r'[$\\]'); // Replace any of $ \
+
+  /// Regex used by [escapeSnippetVariableText].
+  static final _escapeSnippetVariableTextRegex =
+      RegExp(r'[$}\\]'); // Replace any of $ } \
+
   final _buffer = StringBuffer();
 
   var _nextPlaceholder = 1;
@@ -152,9 +168,7 @@
   /// If there are 0 or 1 choices, a placeholder will be inserted instead.
   ///
   /// Returns the placeholder number used.
-  int appendChoice(Iterable<String> choices, {int? placeholderNumber}) {
-    final uniqueChoices = choices.where((item) => item.isNotEmpty).toSet();
-
+  int appendChoice(Set<String> uniqueChoices, {int? placeholderNumber}) {
     // If there's only 0/1 items, we can downgrade this to a placeholder.
     if (uniqueChoices.length <= 1) {
       return appendPlaceholder(
@@ -185,7 +199,11 @@
     placeholderNumber = _usePlaceholerNumber(placeholderNumber);
 
     final escapedText = escapeSnippetVariableText(text);
-    _buffer.write('\${$placeholderNumber:$escapedText}');
+    _buffer.write(r'${');
+    _buffer.write(placeholderNumber);
+    _buffer.write(':');
+    _buffer.write(escapedText);
+    _buffer.write('}');
 
     return placeholderNumber;
   }
@@ -196,7 +214,8 @@
   int appendTabStop({int? placeholderNumber}) {
     placeholderNumber = _usePlaceholerNumber(placeholderNumber);
 
-    _buffer.write('\$$placeholderNumber');
+    _buffer.write(r'$');
+    _buffer.write(placeholderNumber);
 
     return placeholderNumber;
   }
@@ -222,7 +241,7 @@
   /// by pipes and commas (`${1:|a,b,c|}`).
   static String escapeSnippetChoiceText(String input) => _escapeCharacters(
         input,
-        RegExp(r'[$}\\\|,]'), // Replace any of $ } \ | ,
+        _escapeSnippetChoiceTextRegex,
       );
 
   /// Escapes a string to be used in an LSP edit that uses Snippet mode where the
@@ -230,10 +249,8 @@
   ///
   /// Snippets can contain special markup like `${a:b}` so `$` needs escaping
   /// as does `\` so it's not interpreted as an escape.
-  static String escapeSnippetPlainText(String input) => _escapeCharacters(
-        input,
-        RegExp(r'[$\\]'), // Replace any of $ \
-      );
+  static String escapeSnippetPlainText(String input) =>
+      _escapeCharacters(input, _escapeSnippetPlainTextRegex);
 
   /// Escapes a string to be used inside a snippet token.
   ///
@@ -241,7 +258,7 @@
   /// token is not ended early if the included text contains braces.
   static String escapeSnippetVariableText(String input) => _escapeCharacters(
         input,
-        RegExp(r'[$}\\]'), // Replace any of $ } \
+        _escapeSnippetVariableTextRegex,
       );
 
   /// Escapes [pattern] in [input] with backslashes.
@@ -272,11 +289,20 @@
 
 /// Helpers for [SnippetBuilder] that do not relate to building the main snippet
 /// syntax (for example, converting from intermediate structures).
+///
+/// `isPreSorted` is a performance optimisation that allows skipping some
+/// sorting if it's guaranteed that placeholders are already in source-order.
 extension SnippetBuilderExtensions on SnippetBuilder {
-  void appendPlaceholders(String text, List<SnippetPlaceholder> placeholders) {
+  void appendPlaceholders(
+    String text,
+    List<SnippetPlaceholder> placeholders, {
+    required bool isPreSorted,
+  }) {
     // Ensure placeholders are in the order they're visible in the source so
     // tabbing through them doesn't appear to jump around.
-    placeholders.sortBy<num>((placeholder) => placeholder.offset);
+    if (!isPreSorted) {
+      placeholders.sortBy<num>((placeholder) => placeholder.offset);
+    }
 
     // We need to use the same placeholder number for all placeholders in the
     // same linked group, so the first time we see a linked item, store its
@@ -305,11 +331,23 @@
         placeholder.offset + placeholder.length,
       );
       // appendChoice handles mapping empty/single suggestions to a normal
-      // placeholder.
-      thisPaceholderNumber = appendChoice(
-        [placeholderText, ...?placeholder.suggestions],
-        placeholderNumber: thisPaceholderNumber,
-      );
+      // placeholder but it's faster if we can avoid putting a single item into
+      // a set and then detecting it.
+      if (placeholder.suggestions == null) {
+        thisPaceholderNumber = appendPlaceholder(
+          placeholderText,
+          placeholderNumber: thisPaceholderNumber,
+        );
+      } else {
+        final choices = <String>{
+          if (placeholderText.isNotEmpty) placeholderText,
+          ...?placeholder.suggestions,
+        };
+        thisPaceholderNumber = appendChoice(
+          choices,
+          placeholderNumber: thisPaceholderNumber,
+        );
+      }
 
       // Track where we're up to.
       offset = placeholder.offset + placeholder.length;
diff --git a/pkg/analysis_server/lib/src/status/diagnostics.dart b/pkg/analysis_server/lib/src/status/diagnostics.dart
index b4d5a3a..03c6ddd 100644
--- a/pkg/analysis_server/lib/src/status/diagnostics.dart
+++ b/pkg/analysis_server/lib/src/status/diagnostics.dart
@@ -261,6 +261,9 @@
   List<CompletionPerformance> get performanceItems;
 
   @override
+  bool get showInNav => false;
+
+  @override
   Future generateContent(Map<String, String> params) async {
     var id = int.parse(params['id'] ?? '');
     var completionInfo =
diff --git a/pkg/analysis_server/test/lsp/snippets_test.dart b/pkg/analysis_server/test/lsp/snippets_test.dart
index 48cefb0..6ca43a2 100644
--- a/pkg/analysis_server/test/lsp/snippets_test.dart
+++ b/pkg/analysis_server/test/lsp/snippets_test.dart
@@ -20,10 +20,10 @@
   Future<void> test_appendChoice() async {
     final builder = SnippetBuilder()
       ..appendChoice({r'a'})
-      ..appendChoice([r'a', r'b', r'a'])
-      ..appendChoice([], placeholderNumber: 6)
-      ..appendChoice([r'aaa', r'bbb'], placeholderNumber: 12)
-      ..appendChoice([r'aaa', r'bbb $ bbb | bbb } bbb']);
+      ..appendChoice({r'a', r'b'})
+      ..appendChoice({}, placeholderNumber: 6)
+      ..appendChoice({r'aaa', r'bbb'}, placeholderNumber: 12)
+      ..appendChoice({r'aaa', r'bbb $ bbb | bbb } bbb'});
 
     expect(
       builder.value,
@@ -88,13 +88,14 @@
 
     final placeholders = [
       lsp.SnippetPlaceholder(2, 2),
-      lsp.SnippetPlaceholder(12, 2, isFinal: true),
-      lsp.SnippetPlaceholder(22, 2, suggestions: ['aaa', 'bbb']),
       lsp.SnippetPlaceholder(32, 2, linkedGroupId: 123),
+      lsp.SnippetPlaceholder(12, 2, isFinal: true),
       lsp.SnippetPlaceholder(42, 2, linkedGroupId: 123),
+      lsp.SnippetPlaceholder(22, 2, suggestions: ['aaa', 'bbb']),
     ];
 
-    final builder = SnippetBuilder()..appendPlaceholders(code, placeholders);
+    final builder = SnippetBuilder()
+      ..appendPlaceholders(code, placeholders, isPreSorted: false);
 
     expect(builder.value, r'''
 01${1:23}45678
@@ -110,7 +111,7 @@
       ..appendText('text1')
       ..appendPlaceholder('placeholder')
       ..appendText('text2')
-      ..appendChoice(['aaa', 'bbb'])
+      ..appendChoice({'aaa', 'bbb'})
       ..appendText('text3')
       ..appendTabStop()
       ..appendText('text4');
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 4e67afa..0f7bb2d 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -985,7 +985,7 @@
 
 /// A concrete implementation of a [CompilationUnitElement].
 class CompilationUnitElementImpl extends UriReferencedElementImpl
-    implements CompilationUnitElement {
+    implements CompilationUnitElement, MacroTargetElementContainer {
   /// The source that corresponds to this compilation unit.
   @override
   final Source source;
@@ -3628,7 +3628,7 @@
 
 /// A concrete implementation of a [LibraryElement].
 class LibraryElementImpl extends _ExistingElementImpl
-    implements LibraryElement {
+    implements LibraryElement, MacroTargetElementContainer {
   /// The analysis context in which this library is defined.
   @override
   final AnalysisContext context;
@@ -4166,6 +4166,9 @@
   List<MacroApplicationError> macroApplicationErrors = [];
 }
 
+/// Marker interface for elements that may have [MacroTargetElement]s.
+class MacroTargetElementContainer {}
+
 /// A concrete implementation of a [MethodElement].
 class MethodElementImpl extends ExecutableElementImpl implements MethodElement {
   /// Is `true` if this method is `operator==`, and there is no explicit
diff --git a/pkg/analyzer/lib/src/summary2/macro_application.dart b/pkg/analyzer/lib/src/summary2/macro_application.dart
index a65e183..6d75973 100644
--- a/pkg/analyzer/lib/src/summary2/macro_application.dart
+++ b/pkg/analyzer/lib/src/summary2/macro_application.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/visitor.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/summary2/library_builder.dart';
 import 'package:analyzer/src/summary2/link.dart';
@@ -23,8 +24,7 @@
   final MultiMacroExecutor macroExecutor;
   final LibraryBuilder libraryBuilder;
 
-  final Map<MacroTargetElement, List<_MacroApplication>> _applications =
-      Map.identity();
+  final List<_MacroTarget> _targets = [];
 
   final Map<ClassDeclaration, macro.ClassDeclaration> _classDeclarations = {};
 
@@ -36,103 +36,72 @@
 
   Linker get _linker => libraryBuilder.linker;
 
-  /// Fill [_applications]s with macro applications.
+  /// Fill [_targets]s with macro applications.
   Future<void> buildApplications() async {
-    for (final unitElement in libraryBuilder.element.units) {
-      for (final classElement in unitElement.classes) {
-        classElement as ClassElementImpl;
-        final classNode = _linker.elementNodes[classElement];
-        // TODO(scheglov) support other declarations
-        if (classNode is ClassDeclaration) {
-          await _buildApplications(
-            classElement,
-            classNode.metadata,
-            () => getClassDeclaration(classNode),
-          );
-        }
+    final collector = _MacroTargetElementCollector();
+    libraryBuilder.element.accept(collector);
+
+    for (final targetElement in collector.targets) {
+      final targetNode = _linker.elementNodes[targetElement];
+      // TODO(scheglov) support other declarations
+      if (targetNode is ClassDeclaration) {
+        await _buildApplications(
+          targetElement,
+          targetNode.metadata,
+          () => getClassDeclaration(targetNode),
+        );
       }
     }
   }
 
   Future<String?> executeDeclarationsPhase() async {
     final results = <macro.MacroExecutionResult>[];
-    for (final unitElement in libraryBuilder.element.units) {
-      for (final classElement in unitElement.classes) {
-        classElement as ClassElementImpl;
-        final applications = _applications[classElement];
-        if (applications != null) {
-          for (final application in applications) {
-            if (application.shouldExecute(macro.Phase.declarations)) {
-              await _runWithCatchingExceptions(
-                () async {
-                  final result =
-                      await application.instance.executeDeclarationsPhase(
-                    typeResolver: _typeResolver,
-                    classIntrospector: _classIntrospector,
-                  );
-                  if (result.isNotEmpty) {
-                    results.add(result);
-                  }
-                },
-                annotationIndex: application.annotationIndex,
-                onError: (error) {
-                  classElement.macroApplicationErrors.add(error);
-                },
+    for (final target in _targets) {
+      for (final application in target.applications) {
+        if (application.shouldExecute(macro.Phase.declarations)) {
+          await _runWithCatchingExceptions(
+            () async {
+              final result =
+                  await application.instance.executeDeclarationsPhase(
+                typeResolver: _typeResolver,
+                classIntrospector: _classIntrospector,
               );
-            }
-          }
+              if (result.isNotEmpty) {
+                results.add(result);
+              }
+            },
+            annotationIndex: application.annotationIndex,
+            onError: (error) {
+              target.element.macroApplicationErrors.add(error);
+            },
+          );
         }
       }
     }
-
-    if (results.isNotEmpty) {
-      final code = macroExecutor.buildAugmentationLibrary(
-        results,
-        _resolveIdentifier,
-        _inferOmittedType,
-      );
-      return code.trim();
-    }
-    return null;
+    return _buildAugmentationLibrary(results);
   }
 
   Future<String?> executeTypesPhase() async {
     final results = <macro.MacroExecutionResult>[];
-    // TODO(scheglov) Share the elements iteration logic.
-    for (final unitElement in libraryBuilder.element.units) {
-      for (final classElement in unitElement.classes) {
-        classElement as ClassElementImpl;
-        final applications = _applications[classElement];
-        if (applications != null) {
-          for (final application in applications) {
-            if (application.shouldExecute(macro.Phase.types)) {
-              await _runWithCatchingExceptions(
-                () async {
-                  final result = await application.instance.executeTypesPhase();
-                  if (result.isNotEmpty) {
-                    results.add(result);
-                  }
-                },
-                annotationIndex: application.annotationIndex,
-                onError: (error) {
-                  classElement.macroApplicationErrors.add(error);
-                },
-              );
-            }
-          }
+    for (final target in _targets) {
+      for (final application in target.applications) {
+        if (application.shouldExecute(macro.Phase.types)) {
+          await _runWithCatchingExceptions(
+            () async {
+              final result = await application.instance.executeTypesPhase();
+              if (result.isNotEmpty) {
+                results.add(result);
+              }
+            },
+            annotationIndex: application.annotationIndex,
+            onError: (error) {
+              target.element.macroApplicationErrors.add(error);
+            },
+          );
         }
       }
     }
-
-    if (results.isNotEmpty) {
-      final code = macroExecutor.buildAugmentationLibrary(
-        results,
-        _resolveIdentifier,
-        _inferOmittedType,
-      );
-      return code.trim();
-    }
-    return null;
+    return _buildAugmentationLibrary(results);
   }
 
   /// TODO(scheglov) Do we need this caching?
@@ -141,8 +110,8 @@
     return _classDeclarations[node] ??= _buildClassDeclaration(node);
   }
 
-  /// If there are any macro applications in [annotations], record for the
-  /// [targetElement] in [_applications], for future execution.
+  /// If there are any macro applications in [annotations], add a new
+  /// element into [_targets].
   Future<void> _buildApplications(
     MacroTargetElement targetElement,
     List<Annotation> annotations,
@@ -186,15 +155,16 @@
 
       final annotation = annotations[i];
       final macroInstance = await _importedMacroDeclaration(
-        annotation.name,
+        annotation,
         whenClass: ({
           required macroClass,
+          required constructorName,
         }) async {
           final argumentsNode = annotation.arguments;
           if (argumentsNode != null) {
             return await instantiateSingle(
               macroClass: macroClass,
-              constructorName: '', // TODO(scheglov) implement
+              constructorName: constructorName ?? '',
               argumentsNode: argumentsNode,
             );
           }
@@ -205,7 +175,7 @@
         }) async {
           return await instantiateSingle(
             macroClass: macroClass,
-            constructorName: '', // TODO(scheglov) implement
+            constructorName: instanceCreation.constructorName.name?.name ?? '',
             argumentsNode: instanceCreation.argumentList,
           );
         },
@@ -220,16 +190,39 @@
         );
       }
     }
+
     if (applications.isNotEmpty) {
-      _applications[targetElement] = applications;
+      _targets.add(
+        _MacroTarget(
+          element: targetElement,
+          applications: applications,
+        ),
+      );
     }
   }
 
-  /// If [node] references a macro, invokes the right callback.
+  /// If there are any [results], builds the augmentation library with them.
+  String? _buildAugmentationLibrary(
+    List<macro.MacroExecutionResult> results,
+  ) {
+    if (results.isEmpty) {
+      return null;
+    }
+
+    final code = macroExecutor.buildAugmentationLibrary(
+      results,
+      _resolveIdentifier,
+      _inferOmittedType,
+    );
+    return code.trim();
+  }
+
+  /// If [annotation] references a macro, invokes the right callback.
   Future<R?> _importedMacroDeclaration<R>(
-    Identifier node, {
+    Annotation annotation, {
     required Future<R?> Function({
       required ClassElementImpl macroClass,
+      required String? constructorName,
     })
         whenClass,
     required Future<R?> Function({
@@ -240,14 +233,27 @@
   }) async {
     final String? prefix;
     final String name;
-    if (node is PrefixedIdentifier) {
-      prefix = node.prefix.name;
-      name = node.identifier.name;
-    } else if (node is SimpleIdentifier) {
+    final String? constructorName;
+    final nameNode = annotation.name;
+    if (nameNode is SimpleIdentifier) {
       prefix = null;
-      name = node.name;
+      name = nameNode.name;
+      constructorName = annotation.constructorName?.name;
+    } else if (nameNode is PrefixedIdentifier) {
+      final importPrefixCandidate = nameNode.prefix.name;
+      final hasImportPrefix = libraryBuilder.element.imports
+          .any((import) => import.prefix?.name == importPrefixCandidate);
+      if (hasImportPrefix) {
+        prefix = importPrefixCandidate;
+        name = nameNode.identifier.name;
+        constructorName = annotation.constructorName?.name;
+      } else {
+        prefix = null;
+        name = nameNode.prefix.name;
+        constructorName = nameNode.identifier.name;
+      }
     } else {
-      throw StateError('${node.runtimeType} $node');
+      throw StateError('${nameNode.runtimeType} $nameNode');
     }
 
     for (final import in libraryBuilder.element.imports) {
@@ -270,7 +276,10 @@
       final element = lookupResult.getter;
       if (element is ClassElementImpl) {
         if (element.isMacro) {
-          return await whenClass(macroClass: element);
+          return await whenClass(
+            macroClass: element,
+            constructorName: constructorName,
+          );
         }
       } else if (element is PropertyAccessorElementImpl &&
           element.isGetter &&
@@ -616,6 +625,30 @@
   bool shouldExecute(macro.Phase phase) => instance.shouldExecute(phase);
 }
 
+class _MacroTarget {
+  final MacroTargetElement element;
+  final List<_MacroApplication> applications;
+
+  _MacroTarget({
+    required this.element,
+    required this.applications,
+  });
+}
+
+class _MacroTargetElementCollector extends GeneralizingElementVisitor<void> {
+  final List<MacroTargetElement> targets = [];
+
+  @override
+  void visitElement(covariant ElementImpl element) {
+    if (element is MacroTargetElement) {
+      targets.add(element as MacroTargetElement);
+    }
+    if (element is MacroTargetElementContainer) {
+      element.visitChildren(this);
+    }
+  }
+}
+
 class _TypeResolver implements macro.TypeResolver {
   @override
   Future<macro.StaticType> resolve(macro.TypeAnnotationCode type) {
diff --git a/pkg/analyzer/test/src/summary/macro_test.dart b/pkg/analyzer/test/src/summary/macro_test.dart
index 6f9fc4e..097547d 100644
--- a/pkg/analyzer/test/src/summary/macro_test.dart
+++ b/pkg/analyzer/test/src/summary/macro_test.dart
@@ -63,7 +63,7 @@
     );
   }
 
-  test_application_getter_withoutPrefix_withoutArguments() async {
+  test_application_getter_withoutPrefix() async {
     newFile('$testPackageLibPath/a.dart', r'''
 import 'dart:async';
 import 'package:_fe_analyzer_shared/src/macros/api.dart';
@@ -121,7 +121,67 @@
         withExportScope: true);
   }
 
-  test_application_getter_withPrefix_withoutArguments() async {
+  test_application_getter_withoutPrefix_namedConstructor() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+import 'dart:async';
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+
+macro class MyMacro implements ClassTypesMacro {
+  const MyMacro.named();
+
+  FutureOr<void> buildTypesForClass(clazz, builder) {
+    builder.declareType(
+      'MyClass',
+      DeclarationCode.fromString('class MyClass {}'),
+    );
+  }
+}
+
+const myMacro = MyMacro.named();
+''');
+
+    var library = await buildLibrary(r'''
+import 'a.dart';
+
+@myMacro
+class A {}
+''', preBuildSequence: [
+      {'package:test/a.dart'}
+    ]);
+
+    checkElementText(
+        library,
+        r'''
+library
+  imports
+    package:test/a.dart
+  definingUnit
+    classes
+      class A @33
+        metadata
+          Annotation
+            atSign: @ @18
+            name: SimpleIdentifier
+              token: myMacro @19
+              staticElement: package:test/a.dart::@getter::myMacro
+              staticType: null
+            element: package:test/a.dart::@getter::myMacro
+        constructors
+          synthetic @-1
+  parts
+    package:test/_macro_types.dart
+      classes
+        class MyClass @6
+          constructors
+            synthetic @-1
+  exportScope
+    A: package:test/test.dart;A
+    MyClass: package:test/test.dart;package:test/_macro_types.dart;MyClass
+''',
+        withExportScope: true);
+  }
+
+  test_application_getter_withPrefix() async {
     newFile('$testPackageLibPath/a.dart', r'''
 import 'dart:async';
 import 'package:_fe_analyzer_shared/src/macros/api.dart';
@@ -187,6 +247,74 @@
         withExportScope: true);
   }
 
+  test_application_getter_withPrefix_namedConstructor() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+import 'dart:async';
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+
+macro class MyMacro implements ClassTypesMacro {
+  const MyMacro.named();
+
+  FutureOr<void> buildTypesForClass(clazz, builder) {
+    builder.declareType(
+      'MyClass',
+      DeclarationCode.fromString('class MyClass {}'),
+    );
+  }
+}
+
+const myMacro = MyMacro.named();
+''');
+
+    var library = await buildLibrary(r'''
+import 'a.dart' as prefix;
+
+@prefix.myMacro
+class A {}
+''', preBuildSequence: [
+      {'package:test/a.dart'}
+    ]);
+
+    checkElementText(
+        library,
+        r'''
+library
+  imports
+    package:test/a.dart as prefix @19
+  definingUnit
+    classes
+      class A @50
+        metadata
+          Annotation
+            atSign: @ @28
+            name: PrefixedIdentifier
+              prefix: SimpleIdentifier
+                token: prefix @29
+                staticElement: self::@prefix::prefix
+                staticType: null
+              period: . @35
+              identifier: SimpleIdentifier
+                token: myMacro @36
+                staticElement: package:test/a.dart::@getter::myMacro
+                staticType: null
+              staticElement: package:test/a.dart::@getter::myMacro
+              staticType: null
+            element: package:test/a.dart::@getter::myMacro
+        constructors
+          synthetic @-1
+  parts
+    package:test/_macro_types.dart
+      classes
+        class MyClass @6
+          constructors
+            synthetic @-1
+  exportScope
+    A: package:test/test.dart;A
+    MyClass: package:test/test.dart;package:test/_macro_types.dart;MyClass
+''',
+        withExportScope: true);
+  }
+
   test_application_newInstance_withoutPrefix() async {
     newFile('$testPackageLibPath/a.dart', r'''
 import 'dart:async';
@@ -246,6 +374,75 @@
         withExportScope: true);
   }
 
+  test_application_newInstance_withoutPrefix_namedConstructor() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+import 'dart:async';
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+
+macro class MyMacro implements ClassTypesMacro {
+  const MyMacro.named();
+
+  FutureOr<void> buildTypesForClass(clazz, builder) {
+    builder.declareType(
+      'MyClass',
+      DeclarationCode.fromString('class MyClass {}'),
+    );
+  }
+}
+''');
+
+    var library = await buildLibrary(r'''
+import 'a.dart';
+
+@MyMacro.named()
+class A {}
+''', preBuildSequence: [
+      {'package:test/a.dart'}
+    ]);
+
+    checkElementText(
+        library,
+        r'''
+library
+  imports
+    package:test/a.dart
+  definingUnit
+    classes
+      class A @41
+        metadata
+          Annotation
+            atSign: @ @18
+            name: PrefixedIdentifier
+              prefix: SimpleIdentifier
+                token: MyMacro @19
+                staticElement: package:test/a.dart::@class::MyMacro
+                staticType: null
+              period: . @26
+              identifier: SimpleIdentifier
+                token: named @27
+                staticElement: package:test/a.dart::@class::MyMacro::@constructor::named
+                staticType: null
+              staticElement: package:test/a.dart::@class::MyMacro::@constructor::named
+              staticType: null
+            arguments: ArgumentList
+              leftParenthesis: ( @32
+              rightParenthesis: ) @33
+            element: package:test/a.dart::@class::MyMacro::@constructor::named
+        constructors
+          synthetic @-1
+  parts
+    package:test/_macro_types.dart
+      classes
+        class MyClass @6
+          constructors
+            synthetic @-1
+  exportScope
+    A: package:test/test.dart;A
+    MyClass: package:test/test.dart;package:test/_macro_types.dart;MyClass
+''',
+        withExportScope: true);
+  }
+
   test_application_newInstance_withPrefix() async {
     newFile('$testPackageLibPath/a.dart', r'''
 import 'package:_fe_analyzer_shared/src/macros/api.dart';
@@ -312,6 +509,79 @@
         withExportScope: true);
   }
 
+  test_application_newInstance_withPrefix_namedConstructor() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+import 'package:_fe_analyzer_shared/src/macros/api.dart';
+
+macro class MyMacro implements ClassTypesMacro {
+  const MyMacro.named();
+
+  buildTypesForClass(clazz, builder) {
+    builder.declareType(
+      'MyClass',
+      DeclarationCode.fromString('class MyClass {}'),
+    );
+  }
+}
+''');
+
+    var library = await buildLibrary(r'''
+import 'a.dart' as prefix;
+
+@prefix.MyMacro.named()
+class A {}
+''', preBuildSequence: [
+      {'package:test/a.dart'}
+    ]);
+
+    checkElementText(
+        library,
+        r'''
+library
+  imports
+    package:test/a.dart as prefix @19
+  definingUnit
+    classes
+      class A @58
+        metadata
+          Annotation
+            atSign: @ @28
+            name: PrefixedIdentifier
+              prefix: SimpleIdentifier
+                token: prefix @29
+                staticElement: self::@prefix::prefix
+                staticType: null
+              period: . @35
+              identifier: SimpleIdentifier
+                token: MyMacro @36
+                staticElement: package:test/a.dart::@class::MyMacro
+                staticType: null
+              staticElement: package:test/a.dart::@class::MyMacro
+              staticType: null
+            period: . @43
+            constructorName: SimpleIdentifier
+              token: named @44
+              staticElement: package:test/a.dart::@class::MyMacro::@constructor::named
+              staticType: null
+            arguments: ArgumentList
+              leftParenthesis: ( @49
+              rightParenthesis: ) @50
+            element: package:test/a.dart::@class::MyMacro::@constructor::named
+        constructors
+          synthetic @-1
+  parts
+    package:test/_macro_types.dart
+      classes
+        class MyClass @6
+          constructors
+            synthetic @-1
+  exportScope
+    A: package:test/test.dart;A
+    MyClass: package:test/test.dart;package:test/_macro_types.dart;MyClass
+''',
+        withExportScope: true);
+  }
+
   test_arguments_error() async {
     await _assertTypesPhaseArgumentsText(
       fields: {
@@ -325,7 +595,47 @@
     );
   }
 
-  test_arguments_typesPhase_kind_optionalNamed() async {
+  test_arguments_getter_type_bool() async {
+    await _assertTypesPhaseArgumentsText(
+      fields: {
+        'foo': 'bool',
+        'bar': 'bool',
+      },
+      constructorParametersCode: '(this.foo, this.bar)',
+      argumentsCode: '(true, false)',
+      usingGetter: true,
+      expected: r'''
+foo: true
+bar: false
+''',
+    );
+  }
+
+  test_arguments_getter_type_int() async {
+    await _assertTypesPhaseArgumentsText(
+      fields: {'foo': 'int'},
+      constructorParametersCode: '(this.foo)',
+      argumentsCode: '(42)',
+      usingGetter: true,
+      expected: r'''
+foo: 42
+''',
+    );
+  }
+
+  test_arguments_getter_type_string() async {
+    await _assertTypesPhaseArgumentsText(
+      fields: {'foo': 'String'},
+      constructorParametersCode: '(this.foo)',
+      argumentsCode: "('aaa')",
+      usingGetter: true,
+      expected: r'''
+foo: aaa
+''',
+    );
+  }
+
+  test_arguments_newInstance_kind_optionalNamed() async {
     await _assertTypesPhaseArgumentsText(
       fields: {
         'foo': 'int',
@@ -340,7 +650,7 @@
     );
   }
 
-  test_arguments_typesPhase_kind_optionalPositional() async {
+  test_arguments_newInstance_kind_optionalPositional() async {
     await _assertTypesPhaseArgumentsText(
       fields: {
         'foo': 'int',
@@ -355,7 +665,7 @@
     );
   }
 
-  test_arguments_typesPhase_kind_requiredNamed() async {
+  test_arguments_newInstance_kind_requiredNamed() async {
     await _assertTypesPhaseArgumentsText(
       fields: {'foo': 'int'},
       constructorParametersCode: '({required this.foo})',
@@ -366,7 +676,7 @@
     );
   }
 
-  test_arguments_typesPhase_kind_requiredPositional() async {
+  test_arguments_newInstance_kind_requiredPositional() async {
     await _assertTypesPhaseArgumentsText(
       fields: {'foo': 'int'},
       constructorParametersCode: '(this.foo)',
@@ -377,7 +687,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_bool() async {
+  test_arguments_newInstance_type_bool() async {
     await _assertTypesPhaseArgumentsText(
       fields: {
         'foo': 'bool',
@@ -392,7 +702,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_double() async {
+  test_arguments_newInstance_type_double() async {
     await _assertTypesPhaseArgumentsText(
       fields: {'foo': 'double'},
       constructorParametersCode: '(this.foo)',
@@ -403,7 +713,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_double_negative() async {
+  test_arguments_newInstance_type_double_negative() async {
     await _assertTypesPhaseArgumentsText(
       fields: {'foo': 'double'},
       constructorParametersCode: '(this.foo)',
@@ -414,7 +724,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_int() async {
+  test_arguments_newInstance_type_int() async {
     await _assertTypesPhaseArgumentsText(
       fields: {'foo': 'int'},
       constructorParametersCode: '(this.foo)',
@@ -425,7 +735,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_int_negative() async {
+  test_arguments_newInstance_type_int_negative() async {
     await _assertTypesPhaseArgumentsText(
       fields: {'foo': 'int'},
       constructorParametersCode: '(this.foo)',
@@ -436,7 +746,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_list() async {
+  test_arguments_newInstance_type_list() async {
     await _assertTypesPhaseArgumentsText(
       fields: {
         'foo': 'List<Object?>',
@@ -449,7 +759,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_map() async {
+  test_arguments_newInstance_type_map() async {
     await _assertTypesPhaseArgumentsText(
       fields: {
         'foo': 'Map<Object?, Object?>',
@@ -462,7 +772,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_null() async {
+  test_arguments_newInstance_type_null() async {
     await _assertTypesPhaseArgumentsText(
       fields: {'foo': 'Object?'},
       constructorParametersCode: '(this.foo)',
@@ -473,7 +783,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_set() async {
+  test_arguments_newInstance_type_set() async {
     await _assertTypesPhaseArgumentsText(
       fields: {
         'foo': 'Set<Object?>',
@@ -486,7 +796,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_string() async {
+  test_arguments_newInstance_type_string() async {
     await _assertTypesPhaseArgumentsText(
       fields: {'foo': 'String'},
       constructorParametersCode: '(this.foo)',
@@ -497,7 +807,7 @@
     );
   }
 
-  test_arguments_typesPhase_type_string_adjacent() async {
+  test_arguments_newInstance_type_string_adjacent() async {
     await _assertTypesPhaseArgumentsText(
       fields: {'foo': 'String'},
       constructorParametersCode: '(this.foo)',
@@ -1106,6 +1416,7 @@
     required String argumentsCode,
     String? expected,
     String? expectedErrors,
+    bool usingGetter = false,
   }) async {
     final dumpCode = fields.keys.map((name) {
       return "$name: \$$name\\\\n";
@@ -1129,12 +1440,14 @@
     );
   }
 }
+
+${usingGetter ? 'const argumentsTextMacro = ArgumentsTextMacro$argumentsCode;' : ''}
 ''');
 
     final library = await buildLibrary('''
 import 'arguments_text.dart';
 
-@ArgumentsTextMacro$argumentsCode
+${usingGetter ? '@argumentsTextMacro' : '@ArgumentsTextMacro$argumentsCode'}
 class A {}
     ''', preBuildSequence: [
       {'package:test/arguments_text.dart'}
diff --git a/pkg/compiler/test/dump_info/data/closures.dart b/pkg/compiler/test/dump_info/data/closures.dart
new file mode 100644
index 0000000..7bc3f58
--- /dev/null
+++ b/pkg/compiler/test/dump_info/data/closures.dart
@@ -0,0 +1,1153 @@
+/*library: 
+ constant=[
+  {
+  "id": "constant/B.C_JS_CONST = function getTagFallback(o) {\n  var s = Object.prototype.toString.call(o);\n  return s.substring(8, s.length - 1);\n};\n",
+  "kind": "constant",
+  "name": null,
+  "size": 131,
+  "outputUnit": "outputUnit/main",
+  "code": "B.C_JS_CONST = function getTagFallback(o) {\n  var s = Object.prototype.toString.call(o);\n  return s.substring(8, s.length - 1);\n};\n"
+},
+  {
+  "id": "constant/B.Interceptor_methods = J.Interceptor.prototype;\n",
+  "kind": "constant",
+  "name": null,
+  "size": 49,
+  "outputUnit": "outputUnit/main",
+  "code": "B.Interceptor_methods = J.Interceptor.prototype;\n"
+},
+  {
+  "id": "constant/B.JSArray_methods = J.JSArray.prototype;\n",
+  "kind": "constant",
+  "name": null,
+  "size": 41,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JSArray_methods = J.JSArray.prototype;\n"
+},
+  {
+  "id": "constant/B.JSString_methods = J.JSString.prototype;\n",
+  "kind": "constant",
+  "name": null,
+  "size": 43,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JSString_methods = J.JSString.prototype;\n"
+},
+  {
+  "id": "constant/B.JavaScriptObject_methods = J.JavaScriptObject.prototype;\n",
+  "kind": "constant",
+  "name": null,
+  "size": 59,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JavaScriptObject_methods = J.JavaScriptObject.prototype;\n"
+}],
+ deferredFiles=[{}],
+ dependencies=[{}],
+ library=[{
+  "id": "library/memory:sdk/tests/web/native/main.dart::",
+  "kind": "library",
+  "name": "<unnamed>",
+  "size": 10341,
+  "children": [
+    "class/memory:sdk/tests/web/native/main.dart::Class1",
+    "function/memory:sdk/tests/web/native/main.dart::main",
+    "function/memory:sdk/tests/web/native/main.dart::topLevelMethod1",
+    "function/memory:sdk/tests/web/native/main.dart::topLevelMethod2",
+    "function/memory:sdk/tests/web/native/main.dart::topLevelMethod3",
+    "function/memory:sdk/tests/web/native/main.dart::topLevelMethod4",
+    "function/memory:sdk/tests/web/native/main.dart::twoLocals"
+  ],
+  "canonicalUri": "memory:sdk/tests/web/native/main.dart"
+}],
+ outputUnits=[{
+  "id": "outputUnit/main",
+  "kind": "outputUnit",
+  "name": "main",
+  "size": 107495,
+  "filename": "out",
+  "imports": []
+}]
+*/
+
+/*class: Class1:class=[{
+  "id": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "kind": "class",
+  "name": "Class1",
+  "size": 6151,
+  "outputUnit": "outputUnit/main",
+  "parent": "library/memory:sdk/tests/web/native/main.dart::",
+  "modifiers": {
+    "abstract": false
+  },
+  "children": [
+    "field/memory:sdk/tests/web/native/main.dart::Class1.field",
+    "field/memory:sdk/tests/web/native/main.dart::Class1.funcField",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.Class1",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact2",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.Class1.setFunc",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.method1",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.method2",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.method3",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.method4",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.method5",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.method6",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod1",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod2",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3",
+    "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4"
+  ]
+}]*/
+class Class1<T> {
+  /*member: Class1.field:
+   closure=[{
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.field.Class1_field_closure",
+  "kind": "closure",
+  "name": "Class1_field_closure",
+  "size": 242,
+  "outputUnit": "outputUnit/main",
+  "parent": "field/memory:sdk/tests/web/native/main.dart::Class1.field",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.field.Class1_field_closure.call"
+}],
+   function=[{
+  "id": "field/memory:sdk/tests/web/native/main.dart::Class1.field",
+  "kind": "field",
+  "name": "field",
+  "size": 318,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.field.Class1_field_closure"
+  ],
+  "inferredType": "[subclass=Closure]",
+  "code": "set$field(field) {\n      this.field = type$.Type_Function._as(field);\n    }",
+  "type": "Type Function()"
+}],
+   holding=[
+    {"id":"field/memory:sdk/tests/web/native/main.dart::Class1.field","mask":null},
+    {"id":"function/dart:_js_helper::throwCyclicInit","mask":null},
+    {"id":"function/dart:_late_helper::throwLateFieldADI","mask":null},
+    {"id":"function/dart:_rti::Rti._bind","mask":null},
+    {"id":"function/dart:_rti::Rti._eval","mask":null},
+    {"id":"function/dart:_rti::_arrayInstanceType","mask":null},
+    {"id":"function/dart:_rti::_asBool","mask":null},
+    {"id":"function/dart:_rti::_asBoolQ","mask":null},
+    {"id":"function/dart:_rti::_asBoolS","mask":null},
+    {"id":"function/dart:_rti::_asDouble","mask":null},
+    {"id":"function/dart:_rti::_asDoubleQ","mask":null},
+    {"id":"function/dart:_rti::_asDoubleS","mask":null},
+    {"id":"function/dart:_rti::_asInt","mask":null},
+    {"id":"function/dart:_rti::_asIntQ","mask":null},
+    {"id":"function/dart:_rti::_asIntS","mask":null},
+    {"id":"function/dart:_rti::_asNum","mask":null},
+    {"id":"function/dart:_rti::_asNumQ","mask":null},
+    {"id":"function/dart:_rti::_asNumS","mask":null},
+    {"id":"function/dart:_rti::_asObject","mask":null},
+    {"id":"function/dart:_rti::_asString","mask":null},
+    {"id":"function/dart:_rti::_asStringQ","mask":null},
+    {"id":"function/dart:_rti::_asStringS","mask":null},
+    {"id":"function/dart:_rti::_asTop","mask":null},
+    {"id":"function/dart:_rti::_generalAsCheckImplementation","mask":null},
+    {"id":"function/dart:_rti::_generalIsTestImplementation","mask":null},
+    {"id":"function/dart:_rti::_generalNullableAsCheckImplementation","mask":null},
+    {"id":"function/dart:_rti::_generalNullableIsTestImplementation","mask":null},
+    {"id":"function/dart:_rti::_installSpecializedAsCheck","mask":null},
+    {"id":"function/dart:_rti::_installSpecializedIsTest","mask":null},
+    {"id":"function/dart:_rti::_instanceType","mask":null},
+    {"id":"function/dart:_rti::_isBool","mask":null},
+    {"id":"function/dart:_rti::_isInt","mask":null},
+    {"id":"function/dart:_rti::_isNum","mask":null},
+    {"id":"function/dart:_rti::_isObject","mask":null},
+    {"id":"function/dart:_rti::_isString","mask":null},
+    {"id":"function/dart:_rti::_isTop","mask":null},
+    {"id":"function/dart:_rti::findType","mask":null},
+    {"id":"function/dart:_rti::instanceType","mask":null}]
+  */
+  var field = () => T;
+  /*member: Class1.funcField:
+   function=[{
+  "id": "field/memory:sdk/tests/web/native/main.dart::Class1.funcField",
+  "kind": "field",
+  "name": "funcField",
+  "size": 0,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [],
+  "inferredType": "[null|subclass=Closure]",
+  "code": "",
+  "type": "dynamic"
+}],
+   holding=[
+    {"id":"field/memory:sdk/tests/web/native/main.dart::Class1.funcField","mask":null},
+    {"id":"function/dart:_js_helper::throwCyclicInit","mask":null},
+    {"id":"function/dart:_late_helper::throwLateFieldADI","mask":null}]
+  */
+  var funcField;
+
+  /*member: Class1.:
+   closure=[{
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.Class1.Class1_closure",
+  "kind": "closure",
+  "name": "Class1_closure",
+  "size": 204,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.Class1",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.Class1.Class1_closure.call"
+}],
+   function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.Class1",
+  "kind": "function",
+  "name": "Class1",
+  "size": 355,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.Class1.Class1_closure"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[exact=Class1]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes field)",
+  "inlinedCount": 0,
+  "code": "Class1$($T) {\n      var t1 = new A.Class1(new A.Class1_field_closure($T), null, $T._eval$1(\"Class1<0>\"));\n      t1.Class1$0($T);\n      return t1;\n    }",
+  "type": "dynamic Function()"
+}],
+   holding=[
+    {"id":"function/dart:_rti::Rti._eval","mask":null},
+    {"id":"function/dart:_rti::_setArrayType","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.field.Class1_field_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.field.Class1_field_closure.call","mask":null}]
+  */
+  Class1() {
+    field = () => T;
+  }
+
+  /*member: Class1.setFunc:
+   function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.Class1.setFunc",
+  "kind": "function",
+  "name": "Class1.setFunc",
+  "size": 132,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[exact=Class1]",
+  "parameters": [
+    {
+      "name": "funcField",
+      "type": "[subclass=Closure]",
+      "declaredType": "dynamic"
+    }
+  ],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 0,
+  "code": "Class1$setFunc(funcField, $T) {\n      return new A.Class1(new A.Class1_field_closure($T), funcField, $T._eval$1(\"Class1<0>\"));\n    }",
+  "type": "dynamic Function(dynamic)"
+}],
+   holding=[
+    {"id":"function/dart:_rti::Rti._eval","mask":null},
+    {"id":"function/dart:_rti::_setArrayType","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.field.Class1_field_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.field.Class1_field_closure.call","mask":null}]
+  */
+  Class1.setFunc(this.funcField);
+  /*member: Class1.fact:function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact",
+  "kind": "function",
+  "name": "Class1.fact",
+  "size": 0,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": true,
+    "external": false
+  },
+  "returnType": "Class1<#Afree>",
+  "inferredReturnType": "[exact=Class1]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes field)",
+  "inlinedCount": 1,
+  "code": "",
+  "type": "Class1<#A> Function<#A extends Object?>()"
+}]*/
+  factory Class1.fact() => new Class1<T>();
+  /*member: Class1.fact2:
+   closure=[{
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact2.Class1_Class1$fact2_closure",
+  "kind": "closure",
+  "name": "Class1_Class1$fact2_closure",
+  "size": 314,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact2",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact2.Class1_Class1$fact2_closure.call"
+}],
+   function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact2",
+  "kind": "function",
+  "name": "Class1.fact2",
+  "size": 419,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact2.Class1_Class1$fact2_closure"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": true,
+    "external": false
+  },
+  "returnType": "Class1<#Afree>",
+  "inferredReturnType": "[exact=Class1]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 0,
+  "code": "Class1_Class1$fact2($T) {\n      return A.Class1$setFunc(new A.Class1_Class1$fact2_closure($T), $T);\n    }",
+  "type": "Class1<#A> Function<#A extends Object?>()"
+}],
+   holding=[
+    {"id":"function/dart:_rti::_setArrayType","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact2.Class1_Class1$fact2_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact2.Class1_Class1$fact2_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.Class1.setFunc","mask":null}]
+  */
+  factory Class1.fact2() => new Class1.setFunc(() => new Set<T>());
+
+  /*member: Class1.method1:function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.method1",
+  "kind": "function",
+  "name": "method1",
+  "size": 0,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[exact=_Type]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 1,
+  "code": "",
+  "type": "dynamic Function()"
+}]*/
+  method1() => T;
+  /*member: Class1.method2:
+   closure=[{
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.method2.Class1_method2_closure",
+  "kind": "closure",
+  "name": "Class1_method2_closure",
+  "size": 262,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.method2",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.method2.Class1_method2_closure.call"
+}],
+   function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.method2",
+  "kind": "function",
+  "name": "method2",
+  "size": 330,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.method2.Class1_method2_closure"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 0,
+  "code": "method2$0() {\n      return new A.Class1_method2_closure(this);\n    }",
+  "type": "dynamic Function()"
+}],
+   holding=[
+    {"id":"function/dart:_rti::_setArrayType","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method2.Class1_method2_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method2.Class1_method2_closure.call","mask":null}]
+  */
+  method2() {
+    return () => T;
+  }
+
+  /*member: Class1.method3:function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.method3",
+  "kind": "function",
+  "name": "method3",
+  "size": 0,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[exact=_Type]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 1,
+  "code": "",
+  "type": "dynamic Function<#A extends Object?>()"
+}]*/
+  method3<S>() => S;
+  /*member: Class1.method4:
+   closure=[{
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.method4.Class1_method4_closure",
+  "kind": "closure",
+  "name": "Class1_method4_closure",
+  "size": 236,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.method4",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.method4.Class1_method4_closure.call"
+}],
+   function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.method4",
+  "kind": "function",
+  "name": "method4",
+  "size": 306,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.method4.Class1_method4_closure"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 0,
+  "code": "method4$1$0($S) {\n      return new A.Class1_method4_closure($S);\n    }",
+  "type": "dynamic Function<#A extends Object?>()"
+}],
+   holding=[
+    {"id":"function/dart:_rti::_setArrayType","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method4.Class1_method4_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method4.Class1_method4_closure.call","mask":null}]
+  */
+  method4<S>() {
+    return () => S;
+  }
+
+  /*member: Class1.method5:
+   closure=[
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.method5.Class1_method5_local",
+  "kind": "closure",
+  "name": "Class1_method5_local",
+  "size": 287,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.method5",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.method5.Class1_method5_local.call"
+},
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.method5.Class1_method5_local_closure",
+  "kind": "closure",
+  "name": "Class1_method5_local_closure",
+  "size": 260,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.method5",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.method5.Class1_method5_local_closure.call"
+}],
+   function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.method5",
+  "kind": "function",
+  "name": "method5",
+  "size": 632,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.method5.Class1_method5_local",
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.method5.Class1_method5_local_closure"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 0,
+  "code": "method5$0() {\n      return new A.Class1_method5_local().call$1$0(type$.double);\n    }",
+  "type": "dynamic Function()"
+}],
+   holding=[
+    {"id":"function/dart:_rti::_setArrayType","mask":null},
+    {"id":"function/dart:_rti::findType","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method5.Class1_method5_local.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method5.Class1_method5_local.call","mask":null}]
+  */
+  method5() {
+    local<S>() {
+      return () => S;
+    }
+
+    return local<double>();
+  }
+
+  /*member: Class1.method6:
+   closure=[
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6__closure",
+  "kind": "closure",
+  "name": "Class1_method6__closure",
+  "size": 415,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.method6",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6__closure.call"
+},
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_closure",
+  "kind": "closure",
+  "name": "Class1_method6_closure",
+  "size": 363,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.method6",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_closure.call"
+},
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_local",
+  "kind": "closure",
+  "name": "Class1_method6_local",
+  "size": 316,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.method6",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_local.call"
+},
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_local_closure",
+  "kind": "closure",
+  "name": "Class1_method6_local_closure",
+  "size": 341,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.method6",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_local_closure.call"
+}],
+   function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.method6",
+  "kind": "function",
+  "name": "method6",
+  "size": 1573,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6__closure",
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_closure",
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_local",
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_local_closure"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads anything; writes anything)",
+  "inlinedCount": 0,
+  "code": "method6$1$0($S) {\n      return new A.Class1_method6_closure(this, $S).call$1(new A.Class1_method6_local($S).call$1$0(type$.double));\n    }",
+  "type": "dynamic Function<#A extends Object?>()"
+}],
+   holding=[
+    {"id":"function/dart:_rti::_setArrayType","mask":null},
+    {"id":"function/dart:_rti::findType","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_local.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method6.Class1_method6_local.call","mask":null}]
+  */
+  method6<S>() {
+    local<U>() {
+      return () => '$S$U';
+    }
+
+    var local2 = (o) {
+      return () => new Map<T, S>();
+    };
+    return local2(local<double>());
+  }
+
+  /*member: Class1.staticMethod1:function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod1",
+  "kind": "function",
+  "name": "staticMethod1",
+  "size": 0,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [],
+  "modifiers": {
+    "static": true,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[exact=_Type]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 1,
+  "code": "",
+  "type": "dynamic Function<#A extends Object?>()"
+}]*/
+  static staticMethod1<S>() => S;
+  /*member: Class1.staticMethod2:
+   closure=[{
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod2.Class1_staticMethod2_closure",
+  "kind": "closure",
+  "name": "Class1_staticMethod2_closure",
+  "size": 260,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod2",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod2.Class1_staticMethod2_closure.call"
+}],
+   function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod2",
+  "kind": "function",
+  "name": "staticMethod2",
+  "size": 345,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod2.Class1_staticMethod2_closure"
+  ],
+  "modifiers": {
+    "static": true,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 0,
+  "code": "Class1_staticMethod2($S) {\n      return new A.Class1_staticMethod2_closure($S);\n    }",
+  "type": "dynamic Function<#A extends Object?>()"
+}],
+   holding=[
+    {"id":"function/dart:_rti::_setArrayType","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod2.Class1_staticMethod2_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod2.Class1_staticMethod2_closure.call","mask":null}]
+  */
+  static staticMethod2<S>() {
+    return () => S;
+  }
+
+  /*member: Class1.staticMethod3:
+   closure=[
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3.Class1_staticMethod3_local",
+  "kind": "closure",
+  "name": "Class1_staticMethod3_local",
+  "size": 317,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3.Class1_staticMethod3_local.call"
+},
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3.Class1_staticMethod3_local_closure",
+  "kind": "closure",
+  "name": "Class1_staticMethod3_local_closure",
+  "size": 284,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3.Class1_staticMethod3_local_closure.call"
+}],
+   function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3",
+  "kind": "function",
+  "name": "staticMethod3",
+  "size": 703,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3.Class1_staticMethod3_local",
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3.Class1_staticMethod3_local_closure"
+  ],
+  "modifiers": {
+    "static": true,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 0,
+  "code": "Class1_staticMethod3() {\n      return new A.Class1_staticMethod3_local().call$1$0(type$.double);\n    }",
+  "type": "dynamic Function()"
+}],
+   holding=[
+    {"id":"function/dart:_rti::_setArrayType","mask":null},
+    {"id":"function/dart:_rti::findType","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3.Class1_staticMethod3_local.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3.Class1_staticMethod3_local.call","mask":null}]
+  */
+  static staticMethod3() {
+    local<S>() {
+      return () => S;
+    }
+
+    return local<double>();
+  }
+
+  /*member: Class1.staticMethod4:
+   closure=[
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4__closure",
+  "kind": "closure",
+  "name": "Class1_staticMethod4__closure",
+  "size": 322,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4__closure.call"
+},
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_closure",
+  "kind": "closure",
+  "name": "Class1_staticMethod4_closure",
+  "size": 328,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_closure.call"
+},
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_local",
+  "kind": "closure",
+  "name": "Class1_staticMethod4_local",
+  "size": 346,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_local.call"
+},
+    {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_local_closure",
+  "kind": "closure",
+  "name": "Class1_staticMethod4_local_closure",
+  "size": 365,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4",
+  "function": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_local_closure.call"
+}],
+   function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4",
+  "kind": "function",
+  "name": "staticMethod4",
+  "size": 1514,
+  "outputUnit": "outputUnit/main",
+  "parent": "class/memory:sdk/tests/web/native/main.dart::Class1",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4__closure",
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_closure",
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_local",
+    "closure/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_local_closure"
+  ],
+  "modifiers": {
+    "static": true,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads anything; writes anything)",
+  "inlinedCount": 0,
+  "code": "Class1_staticMethod4($S) {\n      return new A.Class1_staticMethod4_closure($S).call$1(new A.Class1_staticMethod4_local($S).call$1$0(type$.double));\n    }",
+  "type": "dynamic Function<#A extends Object?>()"
+}],
+   holding=[
+    {"id":"function/dart:_rti::_setArrayType","mask":null},
+    {"id":"function/dart:_rti::findType","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_closure.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_local.call","mask":null},
+    {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4.Class1_staticMethod4_local.call","mask":null}]
+  */
+  static staticMethod4<S>() {
+    local<U>() {
+      return () => '$S$U';
+    }
+
+    var local2 = (o) {
+      return () => new Set<S>();
+    };
+    return local2(local<double>());
+  }
+}
+
+/*member: topLevelMethod1:function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod1",
+  "kind": "function",
+  "name": "topLevelMethod1",
+  "size": 0,
+  "outputUnit": "outputUnit/main",
+  "parent": "library/memory:sdk/tests/web/native/main.dart::",
+  "children": [],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[exact=_Type]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 1,
+  "code": "",
+  "type": "dynamic Function<#A extends Object?>()"
+}]*/
+topLevelMethod1<S>() => S;
+
+/*member: topLevelMethod2:
+ closure=[{
+  "id": "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod2.topLevelMethod2_closure",
+  "kind": "closure",
+  "name": "topLevelMethod2_closure",
+  "size": 240,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod2",
+  "function": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod2.topLevelMethod2_closure.call"
+}],
+ function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod2",
+  "kind": "function",
+  "name": "topLevelMethod2",
+  "size": 315,
+  "outputUnit": "outputUnit/main",
+  "parent": "library/memory:sdk/tests/web/native/main.dart::",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod2.topLevelMethod2_closure"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 0,
+  "code": "topLevelMethod2($S) {\n      return new A.topLevelMethod2_closure($S);\n    }",
+  "type": "dynamic Function<#A extends Object?>()"
+}],
+ holding=[
+  {"id":"function/dart:_rti::_setArrayType","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod2.topLevelMethod2_closure.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod2.topLevelMethod2_closure.call","mask":null}]
+*/
+topLevelMethod2<S>() {
+  return () => S;
+}
+
+/*member: topLevelMethod3:
+ closure=[
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod3.topLevelMethod3_local",
+  "kind": "closure",
+  "name": "topLevelMethod3_local",
+  "size": 292,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod3",
+  "function": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod3.topLevelMethod3_local.call"
+},
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod3.topLevelMethod3_local_closure",
+  "kind": "closure",
+  "name": "topLevelMethod3_local_closure",
+  "size": 264,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod3",
+  "function": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod3.topLevelMethod3_local_closure.call"
+}],
+ function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod3",
+  "kind": "function",
+  "name": "topLevelMethod3",
+  "size": 648,
+  "outputUnit": "outputUnit/main",
+  "parent": "library/memory:sdk/tests/web/native/main.dart::",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod3.topLevelMethod3_local",
+    "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod3.topLevelMethod3_local_closure"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 0,
+  "code": "topLevelMethod3() {\n      return new A.topLevelMethod3_local().call$1$0(type$.double);\n    }",
+  "type": "dynamic Function()"
+}],
+ holding=[
+  {"id":"function/dart:_rti::_setArrayType","mask":null},
+  {"id":"function/dart:_rti::findType","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod3.topLevelMethod3_local.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod3.topLevelMethod3_local.call","mask":null}]
+*/
+topLevelMethod3() {
+  local<S>() {
+    return () => S;
+  }
+
+  return local<double>();
+}
+
+/*member: topLevelMethod4:
+ closure=[
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4__closure",
+  "kind": "closure",
+  "name": "topLevelMethod4__closure",
+  "size": 302,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod4",
+  "function": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4__closure.call"
+},
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_closure",
+  "kind": "closure",
+  "name": "topLevelMethod4_closure",
+  "size": 303,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod4",
+  "function": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_closure.call"
+},
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_local",
+  "kind": "closure",
+  "name": "topLevelMethod4_local",
+  "size": 321,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod4",
+  "function": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_local.call"
+},
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_local_closure",
+  "kind": "closure",
+  "name": "topLevelMethod4_local_closure",
+  "size": 345,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod4",
+  "function": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_local_closure.call"
+}],
+ function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::topLevelMethod4",
+  "kind": "function",
+  "name": "topLevelMethod4",
+  "size": 1409,
+  "outputUnit": "outputUnit/main",
+  "parent": "library/memory:sdk/tests/web/native/main.dart::",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4__closure",
+    "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_closure",
+    "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_local",
+    "closure/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_local_closure"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads anything; writes anything)",
+  "inlinedCount": 0,
+  "code": "topLevelMethod4($S) {\n      return new A.topLevelMethod4_closure($S).call$1(new A.topLevelMethod4_local($S).call$1$0(type$.double));\n    }",
+  "type": "dynamic Function<#A extends Object?>()"
+}],
+ holding=[
+  {"id":"function/dart:_rti::_setArrayType","mask":null},
+  {"id":"function/dart:_rti::findType","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_closure.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_closure.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_local.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod4.topLevelMethod4_local.call","mask":null}]
+*/
+topLevelMethod4<S>() {
+  local<U>() {
+    return () => '$S$U';
+  }
+
+  var local2 = (o) {
+    return () => new Set<S>();
+  };
+  return local2(local<double>());
+}
+
+/*member: twoLocals:
+ closure=[
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::twoLocals.twoLocals_local1",
+  "kind": "closure",
+  "name": "twoLocals_local1",
+  "size": 149,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::twoLocals",
+  "function": "function/memory:sdk/tests/web/native/main.dart::twoLocals.twoLocals_local1.call"
+},
+  {
+  "id": "closure/memory:sdk/tests/web/native/main.dart::twoLocals.twoLocals_local2",
+  "kind": "closure",
+  "name": "twoLocals_local2",
+  "size": 210,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::twoLocals",
+  "function": "function/memory:sdk/tests/web/native/main.dart::twoLocals.twoLocals_local2.call"
+}],
+ function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::twoLocals",
+  "kind": "function",
+  "name": "twoLocals",
+  "size": 441,
+  "outputUnit": "outputUnit/main",
+  "parent": "library/memory:sdk/tests/web/native/main.dart::",
+  "children": [
+    "closure/memory:sdk/tests/web/native/main.dart::twoLocals.twoLocals_local1",
+    "closure/memory:sdk/tests/web/native/main.dart::twoLocals.twoLocals_local2"
+  ],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[subclass=Closure]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads nothing; writes nothing)",
+  "inlinedCount": 0,
+  "code": "twoLocals() {\n      return new A.twoLocals_local2(new A.twoLocals_local1());\n    }",
+  "type": "dynamic Function()"
+}],
+ holding=[
+  {"id":"function/dart:_rti::_setArrayType","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::twoLocals.twoLocals_local1.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::twoLocals.twoLocals_local1.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::twoLocals.twoLocals_local2.call","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::twoLocals.twoLocals_local2.call","mask":null}]
+*/
+dynamic twoLocals() {
+  local1() {}
+  local2() => local1();
+  return local2;
+}
+
+/*member: main:
+ function=[{
+  "id": "function/memory:sdk/tests/web/native/main.dart::main",
+  "kind": "function",
+  "name": "main",
+  "size": 649,
+  "outputUnit": "outputUnit/main",
+  "parent": "library/memory:sdk/tests/web/native/main.dart::",
+  "children": [],
+  "modifiers": {
+    "static": false,
+    "const": false,
+    "factory": false,
+    "external": false
+  },
+  "returnType": "dynamic",
+  "inferredReturnType": "[null]",
+  "parameters": [],
+  "sideEffects": "SideEffects(reads anything; writes anything)",
+  "inlinedCount": 0,
+  "code": "main() {\n      var t2,\n        t1 = type$.int;\n      A.createRuntimeType(A.Class1$(t1).$ti._precomputed1);\n      A.Class1$(t1).method2$0();\n      A.Class1_Class1$fact2(t1).funcField.call$0();\n      A.Class1$(t1);\n      t2 = type$.double;\n      A.createRuntimeType(t2);\n      A.Class1$(t1).method4$1$0(t2);\n      A.Class1$(t1).method5$0();\n      A.Class1$(t1).method6$1$0(t2);\n      A.createRuntimeType(t2);\n      A.Class1_staticMethod2(t2);\n      A.Class1_staticMethod3();\n      A.Class1_staticMethod4(t2);\n      A.createRuntimeType(t2);\n      A.topLevelMethod2(t2);\n      A.topLevelMethod3();\n      A.topLevelMethod4(t2);\n      A.twoLocals();\n    }",
+  "type": "dynamic Function()"
+}],
+ holding=[
+  {"id":"field/dart:_rti::Rti._precomputed1","mask":null},
+  {"id":"field/memory:sdk/tests/web/native/main.dart::Class1.funcField","mask":null},
+  {"id":"function/dart:_rti::createRuntimeType","mask":null},
+  {"id":"function/dart:_rti::findType","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.Class1","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact","mask":"inlined"},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.Class1.fact2","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method1","mask":"inlined"},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method1","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method2","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method3","mask":"inlined"},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method3","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method4","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method5","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.method6","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod1","mask":"inlined"},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod1","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod2","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod3","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::Class1.staticMethod4","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod1","mask":"inlined"},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod1","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod2","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod3","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::topLevelMethod4","mask":null},
+  {"id":"function/memory:sdk/tests/web/native/main.dart::twoLocals","mask":null}]
+*/
+main() {
+  new Class1<int>().method1();
+  new Class1<int>.fact().method2();
+  new Class1<int>.fact2().funcField() is Set;
+  new Class1<int>().method3<double>();
+  new Class1<int>().method4<double>();
+  new Class1<int>().method5();
+  new Class1<int>().method6<double>();
+  Class1.staticMethod1<double>();
+  Class1.staticMethod2<double>();
+  Class1.staticMethod3();
+  Class1.staticMethod4<double>();
+  topLevelMethod1<double>();
+  topLevelMethod2<double>();
+  topLevelMethod3();
+  topLevelMethod4<double>();
+  twoLocals();
+}
diff --git a/pkg/compiler/test/dump_info/data/deferred/main.dart b/pkg/compiler/test/dump_info/data/deferred/main.dart
index 58ffa26..2bed74e 100644
--- a/pkg/compiler/test/dump_info/data/deferred/main.dart
+++ b/pkg/compiler/test/dump_info/data/deferred/main.dart
@@ -123,6 +123,15 @@
 import 'lib.dart' deferred as lib;
 
 /*member: main:
+ closure=[{
+  "id": "closure/memory:sdk/tests/web/native/main.dart::main.main_closure",
+  "kind": "closure",
+  "name": "main_closure",
+  "size": 201,
+  "outputUnit": "outputUnit/main",
+  "parent": "function/memory:sdk/tests/web/native/main.dart::main",
+  "function": "function/memory:sdk/tests/web/native/main.dart::main.main_closure.call"
+}],
  function=[{
   "id": "function/memory:sdk/tests/web/native/main.dart::main",
   "kind": "function",
diff --git a/pkg/compiler/test/dump_info/dump_info_test.dart b/pkg/compiler/test/dump_info/dump_info_test.dart
index 87e0585..97d9e43 100644
--- a/pkg/compiler/test/dump_info/dump_info_test.dart
+++ b/pkg/compiler/test/dump_info/dump_info_test.dart
@@ -19,6 +19,17 @@
 import '../equivalence/id_equivalence.dart';
 import '../equivalence/id_equivalence_helper.dart';
 
+final JsonEncoder encoder = const JsonEncoder();
+final JsonEncoder indentedEncoder = const JsonEncoder.withIndent('  ');
+
+String jsonEncode(object, {bool indent = true}) {
+  var jsonEncoder = indent ? indentedEncoder : encoder;
+  // Filter block comments since they interfere with ID test comments.
+  var json =
+      jsonEncoder.convert(object).replaceAll('/*', '').replaceAll('*/', '');
+  return json;
+}
+
 main(List<String> args) {
   asyncTest(() async {
     Directory dataDir = Directory.fromUri(Platform.script.resolve('data'));
@@ -33,6 +44,7 @@
   static const String library = 'library';
   static const String clazz = 'class';
   static const String classType = 'classType';
+  static const String closure = 'closure';
   static const String function = 'function';
   static const String typeDef = 'typedef';
   static const String field = 'field';
@@ -46,9 +58,6 @@
 class DumpInfoDataComputer extends DataComputer<Features> {
   const DumpInfoDataComputer();
 
-  final JsonEncoder encoder = const JsonEncoder();
-  final JsonEncoder indentedEncoder = const JsonEncoder.withIndent('  ');
-
   static const String wildcard = '%';
 
   @override
@@ -64,23 +73,23 @@
     if (libraryInfo == null) return;
 
     features.addElement(
-        Tags.library, indentedEncoder.convert(libraryInfo.accept(converter)));
+        Tags.library, jsonEncode(libraryInfo.accept(converter)));
 
     // Store program-wide information on the main library.
     var name = '${library.canonicalUri.pathSegments.last}';
     if (name.startsWith('main')) {
       for (final constantInfo in dumpInfoState.info.constants) {
-        features.addElement(Tags.constant,
-            indentedEncoder.convert(constantInfo.accept(converter)));
+        features.addElement(
+            Tags.constant, jsonEncode(constantInfo.accept(converter)));
       }
-      features.addElement(Tags.dependencies,
-          indentedEncoder.convert(dumpInfoState.info.dependencies));
+      features.addElement(
+          Tags.dependencies, jsonEncode(dumpInfoState.info.dependencies));
       for (final outputUnit in dumpInfoState.info.outputUnits) {
-        features.addElement(Tags.outputUnits,
-            indentedEncoder.convert(outputUnit.accept(converter)));
+        features.addElement(
+            Tags.outputUnits, jsonEncode(outputUnit.accept(converter)));
       }
-      features.addElement(Tags.deferredFiles,
-          indentedEncoder.convert(dumpInfoState.info.deferredFiles));
+      features.addElement(
+          Tags.deferredFiles, jsonEncode(dumpInfoState.info.deferredFiles));
     }
 
     final id = LibraryId(library.canonicalUri);
@@ -100,8 +109,7 @@
     final classInfo = dumpInfoState.entityToInfo[cls];
     if (classInfo == null) return;
 
-    features.addElement(
-        Tags.clazz, indentedEncoder.convert(classInfo.accept(converter)));
+    features.addElement(Tags.clazz, jsonEncode(classInfo.accept(converter)));
     final classTypeInfos =
         dumpInfoState.info.classTypes.where((i) => i.name == classInfo.name);
     assert(
@@ -109,8 +117,8 @@
         'Ambiguous class type info resolution. '
         'Expected 0 or 1 elements, found: $classTypeInfos');
     if (classTypeInfos.length == 1) {
-      features.addElement(Tags.classType,
-          indentedEncoder.convert(classTypeInfos.first.accept(converter)));
+      features.addElement(
+          Tags.classType, jsonEncode(classTypeInfos.first.accept(converter)));
     }
 
     JsClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
@@ -135,20 +143,28 @@
     if (functionInfo == null) return;
 
     if (functionInfo is info.FunctionInfo) {
-      features.addElement(Tags.function,
-          indentedEncoder.convert(functionInfo.accept(converter)));
+      features.addElement(
+          Tags.function, jsonEncode(functionInfo.accept(converter)));
       for (final use in functionInfo.uses) {
+        features.addElement(Tags.holding,
+            jsonEncode(converter.visitDependencyInfo(use), indent: false));
+      }
+      for (var closure in functionInfo.closures) {
         features.addElement(
-            Tags.holding, encoder.convert(converter.visitDependencyInfo(use)));
+            Tags.closure, jsonEncode(closure.accept(converter)));
       }
     }
 
     if (functionInfo is info.FieldInfo) {
-      features.addElement(Tags.function,
-          indentedEncoder.convert(functionInfo.accept(converter)));
+      features.addElement(
+          Tags.function, jsonEncode(functionInfo.accept(converter)));
       for (final use in functionInfo.uses) {
+        features.addElement(Tags.holding,
+            jsonEncode(converter.visitDependencyInfo(use), indent: false));
+      }
+      for (var closure in functionInfo.closures) {
         features.addElement(
-            Tags.holding, encoder.convert(converter.visitDependencyInfo(use)));
+            Tags.closure, jsonEncode(closure.accept(converter)));
       }
     }
 
@@ -201,7 +217,8 @@
           if (actualValue is List) {
             List actualList = actualValue.toList();
             for (Object expectedObject in expectedValue) {
-              String expectedText = encoder.convert(jsonDecode(expectedObject));
+              String expectedText =
+                  jsonEncode(jsonDecode(expectedObject), indent: false);
               bool matchFound = false;
               if (wildcard != null && expectedText.endsWith(wildcard)) {
                 // Wildcard matcher.
@@ -210,7 +227,7 @@
                 List matches = [];
                 for (Object actualObject in actualList) {
                   final formattedActualObject =
-                      encoder.convert(jsonDecode(actualObject));
+                      jsonEncode(jsonDecode(actualObject), indent: false);
                   if (formattedActualObject.startsWith(prefix)) {
                     matches.add(actualObject);
                     matchFound = true;
@@ -222,7 +239,7 @@
               } else {
                 for (Object actualObject in actualList) {
                   final formattedActualObject =
-                      encoder.convert(jsonDecode(actualObject));
+                      jsonEncode(jsonDecode(actualObject), indent: false);
                   if (expectedText == formattedActualObject) {
                     actualList.remove(actualObject);
                     matchFound = true;
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 5eca49b..e95a0af 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -4396,11 +4396,32 @@
   @override
   js_ast.Statement visitIfStatement(IfStatement node) {
     var condition = _visitTest(node.condition);
-    var then = _visitScope(node.then);
     if (node.otherwise != null) {
-      return js_ast.If(condition, then, _visitScope(node.otherwise));
+      if (condition is js_ast.LiteralBool) {
+        // Avoid emitting the branch with code that will never execute.
+        if (condition.value) {
+          return _visitScope(node.then).toStatement();
+        } else {
+          return _visitScope(node.otherwise).toStatement();
+        }
+      }
+      return js_ast.If(
+          condition, _visitScope(node.then), _visitScope(node.otherwise));
     }
-    return js_ast.If.noElse(condition, then);
+
+    if (condition is js_ast.LiteralBool) {
+      if (condition.value) {
+        // Avoid emitting conditional when it is always true.
+        // ex: `if (true) {abc...}` -> `{abc...}`
+        return _visitScope(node.then).toStatement();
+      } else {
+        // Avoid emitting conditional and then when it will never execute.
+        // ex: `if (false) {abc...}` -> `;`
+        return js_ast.EmptyStatement();
+      }
+    }
+
+    return js_ast.If.noElse(condition, _visitScope(node.then));
   }
 
   /// Visits a statement, and ensures the resulting AST handles block scope
@@ -5905,11 +5926,19 @@
           negated: true);
     }
 
+    var jsOperand = _visitTest(operand);
+    if (jsOperand is js_ast.LiteralBool) {
+      // Flipping the value here for `!true` or `!false` allows for simpler
+      // `if (true)` or `if (false)` detection and optimization.
+      return js_ast.LiteralBool(!jsOperand.value)
+              .withSourceInformation(jsOperand.sourceInformation)
+          as js_ast.LiteralBool;
+    }
+
     // Logical negation, `!e`, is a boolean conversion context since it is
     // defined as `e ? false : true`.
-    return js
-        .call('!#', _visitTest(operand))
-        .withSourceInformation(continueSourceMap) as js_ast.Expression;
+    return js.call('!#', jsOperand).withSourceInformation(continueSourceMap)
+        as js_ast.Expression;
   }
 
   @override
@@ -5930,6 +5959,16 @@
   @override
   js_ast.Expression visitConditionalExpression(ConditionalExpression node) {
     var condition = _visitTest(node.condition);
+    if (condition is js_ast.LiteralBool) {
+      if (condition.value) {
+        // Avoid emitting conditional when one branch is effectively dead code.
+        // ex: `true ? foo : bar` -> `foo`
+        return _visitExpression(node.then);
+      } else {
+        // ex: `false ? foo : bar` -> `bar`
+        return _visitExpression(node.otherwise);
+      }
+    }
     var then = _visitExpression(node.then);
     var otherwise = _visitExpression(node.otherwise);
     return js.call('# ? # : #', [condition, then, otherwise])
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index da1ffb1..086b86b 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -223,7 +223,11 @@
   TIMELINE_STREAM_LIST(TIMELINE_STREAM_DISABLE)
 #undef TIMELINE_STREAM_DISABLE
   RecorderLock::WaitForShutdown();
-  Timeline::Clear();
+  // Timeline::Clear() is guarded by the recorder lock and will return
+  // immediately if we've started the shutdown sequence, leaking the recorder.
+  // All outstanding work has already been completed, so we're safe to call this
+  // without explicitly grabbing a recorder lock.
+  Timeline::ClearUnsafe();
   delete recorder_;
   recorder_ = NULL;
   if (enabled_streams_ != NULL) {
@@ -238,7 +242,12 @@
   if (recorder == NULL || rl.IsShuttingDown()) {
     return;
   }
+  ReclaimCachedBlocksFromThreadsUnsafe();
+}
 
+void Timeline::ReclaimCachedBlocksFromThreadsUnsafe() {
+  TimelineEventRecorder* recorder = Timeline::recorder();
+  ASSERT(recorder != nullptr);
   // Iterate over threads.
   OSThreadIterator it;
   while (it.HasNext()) {
@@ -246,7 +255,7 @@
     MutexLocker ml(thread->timeline_block_lock());
     // Grab block and clear it.
     TimelineEventBlock* block = thread->timeline_block();
-    thread->set_timeline_block(NULL);
+    thread->set_timeline_block(nullptr);
     // TODO(johnmccutchan): Consider dropping the timeline_block_lock here
     // if we can do it everywhere. This would simplify the lock ordering
     // requirements.
@@ -295,10 +304,16 @@
 void Timeline::Clear() {
   RecorderLockScope rl;
   TimelineEventRecorder* recorder = Timeline::recorder();
-  if (recorder == NULL || rl.IsShuttingDown()) {
+  if (recorder == nullptr || rl.IsShuttingDown()) {
     return;
   }
-  ReclaimCachedBlocksFromThreads();
+  ClearUnsafe();
+}
+
+void Timeline::ClearUnsafe() {
+  TimelineEventRecorder* recorder = Timeline::recorder();
+  ASSERT(recorder != nullptr);
+  ReclaimCachedBlocksFromThreadsUnsafe();
   recorder->Clear();
 }
 
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 7456aab..759e09f 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -209,6 +209,9 @@
 #undef TIMELINE_STREAM_FLAGS
 
  private:
+  static void ClearUnsafe();
+  static void ReclaimCachedBlocksFromThreadsUnsafe();
+
   static TimelineEventRecorder* recorder_;
   static MallocGrowableArray<char*>* enabled_streams_;
   static bool recorder_discards_clock_values_;
diff --git a/tests/dartdevc/if_else_literal_compilation_test.dart b/tests/dartdevc/if_else_literal_compilation_test.dart
new file mode 100644
index 0000000..c50ae96
--- /dev/null
+++ b/tests/dartdevc/if_else_literal_compilation_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2019, 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 'dart:_foreign_helper' show JS;
+
+import 'package:expect/expect.dart';
+
+void main() async {
+  var count = 0;
+  if (JS<bool>('!', 'false')) {
+    // Should be eliminated from the output based on the condition above.
+    JS('', 'syntax error here!');
+  }
+  count++;
+  if (JS<bool>('!', 'true')) {
+    count++;
+  } else {
+    // Should be eliminated from the output based on the condition above.
+    JS('', 'syntax error here!');
+  }
+  if (JS<bool>('!', 'false')) {
+    // Should be eliminated from the output based on the condition above.
+    JS('', 'syntax error here!');
+  } else {
+    count++;
+  }
+  if (!JS<bool>('!', 'true')) {
+    // Should be eliminated from the output based on the condition above.
+    JS('', 'syntax error here!');
+  }
+  count++;
+  if (!JS<bool>('!', 'false')) {
+    count++;
+  } else {
+    // Should be eliminated from the output based on the condition above.
+    JS('', 'syntax error here!');
+  }
+  if (!JS<bool>('!', 'true')) {
+    // Should be eliminated from the output based on the condition above.
+    JS('', 'syntax error here!');
+  } else {
+    count++;
+  }
+
+  JS<bool>('!', 'true') ? count++ : JS('', 'syntax error here!');
+  JS<bool>('!', 'false') ? JS('', 'syntax error here!') : count++;
+  !JS<bool>('!', 'true') ? JS('', 'syntax error here!') : count++;
+  !JS<bool>('!', 'false') ? count++ : JS('', 'syntax error here!');
+
+  // All expected branches are evaluated, and none of the syntax errors where
+  // compiled at all.
+  Expect.equals(10, count);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 20af0ab..a8dd7e6 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 81
+PRERELEASE 82
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/buildtools/update.py b/tools/buildtools/update.py
index bafeab1..ebdec73 100755
--- a/tools/buildtools/update.py
+++ b/tools/buildtools/update.py
@@ -75,8 +75,10 @@
 
 def main(argv):
     arch_id = platform.machine()
-    # Don't try to download binaries if we're on an arm machine.
-    if arch_id.startswith('arm') or arch_id.startswith('aarch64'):
+    # Don't try to download binaries if we're on an arm machine unless it is a
+    # Mac arm machine because the x64 binaries work using rossetta translation.
+    if ((arch_id.startswith('arm') and sys.platform != 'darwin') or
+            arch_id.startswith('aarch64')):
         print('Not downloading buildtools binaries for ' + arch_id)
         return 0
     if sys.platform.startswith('win'):