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'):