Version 2.15.0-263.0.dev
Merge commit '44e35b1daa9785aab04f77fa9dff287e61915ce4' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
index 82f970c..042507d 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
@@ -810,8 +810,8 @@
}
@override
- void endImplicitCreationExpression(Token token) {
- listener?.endImplicitCreationExpression(token);
+ void endImplicitCreationExpression(Token token, Token openAngleBracket) {
+ listener?.endImplicitCreationExpression(token, openAngleBracket);
}
@override
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
index cd83709..63a247f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
@@ -743,7 +743,7 @@
void beginImplicitCreationExpression(Token token) {}
- void endImplicitCreationExpression(Token token) {
+ void endImplicitCreationExpression(Token token, Token openAngleBracket) {
logEvent("ImplicitCreationExpression");
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
index 0f466bf..cb1ef21 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -5404,7 +5404,8 @@
Token afterPeriod = afterTypeArguments.next!;
if (_isNewOrIdentifier(afterPeriod) &&
optional('(', afterPeriod.next!)) {
- return parseImplicitCreationExpression(token, typeArg);
+ return parseImplicitCreationExpression(
+ token, identifier.next!, typeArg);
}
}
}
@@ -6057,13 +6058,13 @@
}
Token parseImplicitCreationExpression(
- Token token, TypeParamOrArgInfo typeArg) {
- Token begin = token;
- listener.beginImplicitCreationExpression(token);
+ Token token, Token openAngleBracket, TypeParamOrArgInfo typeArg) {
+ Token begin = token.next!; // This is the class name.
+ listener.beginImplicitCreationExpression(begin);
token = parseConstructorReference(
token, ConstructorReferenceContext.Implicit, typeArg);
token = parseConstructorInvocationArguments(token);
- listener.endImplicitCreationExpression(begin);
+ listener.endImplicitCreationExpression(begin, openAngleBracket);
return token;
}
diff --git a/pkg/analysis_server/benchmark/benchmarks.dart b/pkg/analysis_server/benchmark/benchmarks.dart
index a92b60e..c6b391f 100644
--- a/pkg/analysis_server/benchmark/benchmarks.dart
+++ b/pkg/analysis_server/benchmark/benchmarks.dart
@@ -154,6 +154,13 @@
String toString() => '${toJson()}';
}
+/// This interface is implemented by benchmarks that need to know the location
+/// of the Flutter repository.
+abstract class FlutterBenchmark {
+ /// Must be called exactly one time.
+ set flutterRepositoryPath(String path);
+}
+
class ListCommand extends Command {
final List<Benchmark> benchmarks;
@@ -190,6 +197,8 @@
final List<Benchmark> benchmarks;
RunCommand(this.benchmarks) {
+ argParser.addOption('flutter-repository',
+ help: 'The absolute normalized path of the Flutter repository.');
argParser.addFlag('quick',
negatable: false,
help: 'Run a quick version of the benchmark. This is not useful for '
@@ -220,6 +229,7 @@
var benchmarkId = argResults!.rest.first;
var repeatCount = int.parse(argResults!['repeat'] as String);
+ var flutterRepository = argResults!['flutter-repository'] as String?;
var quick = argResults!['quick'];
var verbose = argResults!['verbose'];
@@ -229,6 +239,17 @@
exit(1);
});
+ if (benchmark is FlutterBenchmark) {
+ if (flutterRepository != null) {
+ (benchmark as FlutterBenchmark).flutterRepositoryPath =
+ flutterRepository;
+ } else {
+ print('The option --flutter-repository is required to '
+ "run '$benchmarkId'.");
+ exit(1);
+ }
+ }
+
var actualIterations = repeatCount;
if (benchmark.maxIterations > 0) {
actualIterations = math.min(benchmark.maxIterations, repeatCount);
diff --git a/pkg/analysis_server/benchmark/perf/flutter_analyze_benchmark.dart b/pkg/analysis_server/benchmark/perf/flutter_analyze_benchmark.dart
index 048666b..f2d157b3 100644
--- a/pkg/analysis_server/benchmark/perf/flutter_analyze_benchmark.dart
+++ b/pkg/analysis_server/benchmark/perf/flutter_analyze_benchmark.dart
@@ -40,8 +40,8 @@
/// benchmarks:
/// - analysis-flutter-analyze
-class FlutterAnalyzeBenchmark extends Benchmark {
- late Directory flutterDir;
+class FlutterAnalyzeBenchmark extends Benchmark implements FlutterBenchmark {
+ late final String flutterRepositoryPath;
FlutterAnalyzeBenchmark()
: super(
@@ -56,43 +56,6 @@
int get maxIterations => 3;
@override
- bool get needsSetup => true;
-
- @override
- Future oneTimeCleanup() {
- try {
- flutterDir.deleteSync(recursive: true);
- } on FileSystemException catch (e) {
- print(e);
- }
-
- return Future.value();
- }
-
- @override
- Future oneTimeSetup() async {
- flutterDir = Directory.systemTemp.createTempSync('flutter');
-
- // git clone https://github.com/flutter/flutter $flutterDir
- await _runProcess('git', [
- 'clone',
- 'https://github.com/flutter/flutter',
- path.canonicalize(flutterDir.path)
- ]);
-
- var flutterTool = path.join(flutterDir.path, 'bin', 'flutter');
-
- // flutter --version
- await _runProcess(flutterTool, ['--version'], cwd: flutterDir.path);
-
- // flutter precache
- await _runProcess(flutterTool, ['precache'], cwd: flutterDir.path);
-
- // flutter update-packages
- await _runProcess(flutterTool, ['update-packages'], cwd: flutterDir.path);
- }
-
- @override
Future<BenchMarkResult> run({
bool quick = false,
bool verbose = false,
@@ -114,7 +77,7 @@
'--dart-sdk',
dartSdkPath,
],
- cwd: flutterDir.path,
+ cwd: flutterRepositoryPath,
failOnError: false,
);
diff --git a/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart b/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart
index 8515385..e2bac08 100644
--- a/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart
+++ b/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
-import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
@@ -11,36 +10,7 @@
import '../benchmarks.dart';
import 'memory_tests.dart';
-Future<int> _runProcess(
- String command,
- List<String> args, {
- String? cwd,
- bool failOnError = true,
-}) async {
- print('\n$command ${args.join(' ')}');
-
- var process = await Process.start(command, args, workingDirectory: cwd);
-
- process.stdout
- .transform(utf8.decoder)
- .transform(LineSplitter())
- .listen((line) {
- print(' $line');
- });
- process.stderr
- .transform(utf8.decoder)
- .transform(LineSplitter())
- .listen((line) => print(' $line'));
-
- var exitCode = await process.exitCode;
- if (exitCode != 0 && failOnError) {
- throw '$command exited with $exitCode';
- }
-
- return exitCode;
-}
-
-class FlutterCompletionBenchmark extends Benchmark {
+class FlutterCompletionBenchmark extends Benchmark implements FlutterBenchmark {
static final das = FlutterCompletionBenchmark(
'das',
() => AnalysisServerBenchmarkTest(),
@@ -53,7 +23,7 @@
final AbstractBenchmarkTest Function() testConstructor;
- late String flutterPath;
+ late final String flutterRepositoryPath;
FlutterCompletionBenchmark(String protocolName, this.testConstructor)
: super(
@@ -66,44 +36,6 @@
int get maxIterations => 2;
@override
- bool get needsSetup => true;
-
- @override
- Future oneTimeCleanup() {
- try {
- Directory(flutterPath).deleteSync(recursive: true);
- } on FileSystemException catch (e) {
- print(e);
- }
-
- return Future.value();
- }
-
- @override
- Future oneTimeSetup() async {
- flutterPath = Directory.systemTemp.createTempSync('flutter').path;
-
- // git clone https://github.com/flutter/flutter $flutterPath
- await _runProcess('git', [
- 'clone',
- 'https://github.com/flutter/flutter',
- path.canonicalize(flutterPath)
- ]);
-
- var flutterTool = path.join(flutterPath, 'bin', 'flutter');
-
- // flutter --version
- await _runProcess(flutterTool, ['--version'], cwd: flutterPath);
-
- // flutter update-packages
- await _runProcess(
- flutterTool,
- ['pub', 'get'],
- cwd: path.join(flutterPath, 'packages', 'flutter'),
- );
- }
-
- @override
Future<BenchMarkResult> run({
bool quick = false,
bool verbose = false,
@@ -117,7 +49,8 @@
test.debugStdio();
}
- final flutterPkgPath = path.join(flutterPath, 'packages', 'flutter');
+ final flutterPkgPath =
+ path.join(flutterRepositoryPath, 'packages', 'flutter');
// Open a small directory, but with the package config that allows us
// to analyze any file in `package:flutter`, including tests.
@@ -300,7 +233,7 @@
// Perform warm-up.
// The cold start does not matter.
// The sustained performance is much more important.
- const kWarmUpCount = 50;
+ const kWarmUpCount = 20;
for (var i = 0; i < kWarmUpCount; i++) {
await perform();
}
diff --git a/pkg/analysis_server/lib/src/cider/completion.dart b/pkg/analysis_server/lib/src/cider/completion.dart
index b9c27ec..17f00da 100644
--- a/pkg/analysis_server/lib/src/cider/completion.dart
+++ b/pkg/analysis_server/lib/src/cider/completion.dart
@@ -85,6 +85,7 @@
<IncludedSuggestionRelevanceTag>[];
var manager = DartCompletionManager(
+ budget: CompletionBudget(CompletionBudget.defaultDuration),
includedElementKinds: includedElementKinds,
includedElementNames: includedElementNames,
includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 015acf4..85c3ac9 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -33,12 +33,12 @@
/// Instances of the class [CompletionDomainHandler] implement a
/// [RequestHandler] that handles requests in the completion domain.
class CompletionDomainHandler extends AbstractRequestHandler {
- /// The time budget for a completion request.
- static const Duration _budgetDuration = Duration(milliseconds: 100);
-
/// The maximum number of performance measurements to keep.
static const int performanceListMaxLength = 50;
+ /// The time budget for a completion request.
+ Duration budgetDuration = CompletionBudget.defaultDuration;
+
/// The completion services that the client is currently subscribed.
final Set<CompletionService> subscriptions = <CompletionService>{};
@@ -90,6 +90,7 @@
var suggestions = <CompletionSuggestion>[];
await performance.runAsync('computeSuggestions', (performance) async {
var manager = DartCompletionManager(
+ budget: budget,
includedElementKinds: includedElementKinds,
includedElementNames: includedElementNames,
includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
@@ -213,7 +214,7 @@
/// Implement the 'completion.getSuggestions2' request.
void getSuggestions2(Request request) async {
- var budget = CompletionBudget(_budgetDuration);
+ var budget = CompletionBudget(budgetDuration);
var params = CompletionGetSuggestions2Params.fromRequest(request);
var file = params.file;
@@ -337,7 +338,7 @@
/// Process a `completion.getSuggestions` request.
Future<void> processRequest(Request request) async {
- var budget = CompletionBudget(_budgetDuration);
+ var budget = CompletionBudget(budgetDuration);
final performance = this.performance = CompletionPerformance();
diff --git a/pkg/analysis_server/lib/src/domains/execution/completion.dart b/pkg/analysis_server/lib/src/domains/execution/completion.dart
index c130a8a..a2f6ea6 100644
--- a/pkg/analysis_server/lib/src/domains/execution/completion.dart
+++ b/pkg/analysis_server/lib/src/domains/execution/completion.dart
@@ -74,7 +74,9 @@
offset: targetOffset,
);
- var suggestions = await DartCompletionManager().computeSuggestions(
+ var suggestions = await DartCompletionManager(
+ budget: CompletionBudget(CompletionBudget.defaultDuration),
+ ).computeSuggestions(
dartRequest,
OperationPerformanceImpl('<root>'),
);
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 74ca47f..85f3765 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -233,6 +233,7 @@
try {
var contributor = DartCompletionManager(
+ budget: CompletionBudget(CompletionBudget.defaultDuration),
includedElementKinds: includedElementKinds,
includedElementNames: includedElementNames,
includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 1b62943..4a18e4b 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -47,11 +47,17 @@
/// Class that tracks how much time budget we have left.
class CompletionBudget {
+ static const Duration defaultDuration = Duration(milliseconds: 100);
+
final Duration _budget;
final Stopwatch _timer = Stopwatch()..start();
CompletionBudget(this._budget);
+ bool get isEmpty {
+ return _timer.elapsed > _budget;
+ }
+
Duration get left {
var result = _budget - _timer.elapsed;
return result.isNegative ? Duration.zero : result;
@@ -61,6 +67,9 @@
/// [DartCompletionManager] determines if a completion request is Dart specific
/// and forwards those requests to all [DartCompletionContributor]s.
class DartCompletionManager {
+ /// Time budget to computing suggestions.
+ final CompletionBudget budget;
+
/// If not `null`, then instead of using [ImportedReferenceContributor],
/// fill this set with kinds of elements that are applicable at the
/// completion location, so should be suggested from available suggestion
@@ -91,6 +100,7 @@
/// [includedSuggestionRelevanceTags] must either all be `null` or must all be
/// non-`null`.
DartCompletionManager({
+ required this.budget,
this.includedElementKinds,
this.includedElementNames,
this.includedSuggestionRelevanceTags,
@@ -156,7 +166,7 @@
final librariesToImport = this.librariesToImport;
if (librariesToImport != null) {
contributors.add(
- NotImportedContributor(request, builder, librariesToImport),
+ NotImportedContributor(request, builder, budget, librariesToImport),
);
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
index e6415d0..4fba896 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
+
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
import 'package:analysis_server/src/services/completion/dart/local_library_contributor.dart';
@@ -17,11 +19,13 @@
/// A contributor of suggestions from not yet imported libraries.
class NotImportedContributor extends DartCompletionContributor {
+ final CompletionBudget budget;
final List<Uri> librariesToImport;
NotImportedContributor(
DartCompletionRequest request,
SuggestionBuilder builder,
+ this.budget,
this.librariesToImport,
) : super(request, builder);
@@ -37,10 +41,18 @@
var fsState = analysisDriver.fsState;
var filter = _buildFilter(fsState);
- await analysisDriver.discoverAvailableFiles();
+ try {
+ await analysisDriver.discoverAvailableFiles().timeout(budget.left);
+ } on TimeoutException {
+ return;
+ }
var knownFiles = fsState.knownFiles.toList();
for (var file in knownFiles) {
+ if (budget.isEmpty) {
+ return;
+ }
+
if (!filter.shouldInclude(file)) {
continue;
}
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 4536f8b..ca7daef 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -91,6 +91,31 @@
CrashReportingAttachmentsBuilder.empty,
InstrumentationService.NULL_SERVICE,
);
+
+ completionDomain.budgetDuration = const Duration(seconds: 30);
+ }
+
+ Future<void> test_notImported_emptyBudget() async {
+ await _configureWithWorkspaceRoot();
+
+ // Empty budget, so no not yet imported libraries.
+ completionDomain.budgetDuration = const Duration(milliseconds: 0);
+
+ var responseValidator = await _getTestCodeSuggestions('''
+void f() {
+ Rand^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(4)
+ ..assertLibrariesToImport(includes: [], excludes: [
+ 'dart:core',
+ 'dart:math',
+ ]);
+
+ responseValidator.suggestions.withElementClass().assertEmpty();
}
Future<void> test_notImported_pub_dependencies_inLib() async {
@@ -185,7 +210,7 @@
await _configureWithWorkspaceRoot();
- var test_path = '$testPackageTestPath/test.dart';
+ var test_path = convertPath('$testPackageTestPath/test.dart');
var responseValidator = await _getCodeSuggestions(
path: test_path,
content: '''
@@ -450,7 +475,7 @@
await _configureWithWorkspaceRoot();
- var test_path = '$testPackageTestPath/test.dart';
+ var test_path = convertPath('$testPackageTestPath/test.dart');
var responseValidator = await _getCodeSuggestions(
path: test_path,
content: '''
@@ -497,7 +522,7 @@
await _configureWithWorkspaceRoot();
- var test_path = '$testPackageTestPath/test.dart';
+ var test_path = convertPath('$testPackageTestPath/test.dart');
var responseValidator = await _getCodeSuggestions(
path: test_path,
content: '''
@@ -981,7 +1006,7 @@
int maxResults = 1 << 10,
}) async {
return _getCodeSuggestions(
- path: testFilePath,
+ path: convertPath(testFilePath),
content: content,
maxResults: maxResults,
);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_argument_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_argument_test.dart
index 87759cd..736da8c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_argument_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_argument_test.dart
@@ -21,7 +21,7 @@
@override
String get lintCode => LintNames.avoid_redundant_argument_values;
- Future<void> test_independentInvocations() async {
+ Future<void> test_singleFile() async {
await resolveTestCode('''
void f({bool valWithDefault = true, bool val}) {}
void f2({bool valWithDefault = true, bool val}) {}
@@ -41,23 +41,6 @@
}
''');
}
-
- Future<void> test_multipleInSingleInvocation() async {
- await resolveTestCode('''
-void f() {
- g(a: 0, b: 1, c: 2);
-}
-
-void g({int a = 0, int b = 1, int c = 2}) {}
-''');
- await assertHasFix('''
-void f() {
- g();
-}
-
-void g({int a = 0, int b = 1, int c = 2}) {}
-''');
- }
}
@reflectiveTest
diff --git a/pkg/analysis_server/test/stress/completion/completion_runner.dart b/pkg/analysis_server/test/stress/completion/completion_runner.dart
index f54299e..136684a 100644
--- a/pkg/analysis_server/test/stress/completion/completion_runner.dart
+++ b/pkg/analysis_server/test/stress/completion/completion_runner.dart
@@ -57,7 +57,9 @@
var collection = AnalysisContextCollection(
includedPaths: <String>[analysisRoot],
resourceProvider: resourceProvider);
- var contributor = DartCompletionManager();
+ var contributor = DartCompletionManager(
+ budget: CompletionBudget(const Duration(seconds: 30)),
+ );
var statistics = CompletionPerformance();
var stamp = 1;
diff --git a/pkg/analysis_server/tool/code_completion/completion_metrics.dart b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
index 7284e5d..c7a90fc 100644
--- a/pkg/analysis_server/tool/code_completion/completion_metrics.dart
+++ b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
@@ -1205,9 +1205,11 @@
availableSuggestionsParams]) async {
List<protocol.CompletionSuggestion> suggestions;
+ var budget = CompletionBudget(Duration(seconds: 30));
if (declarationsTracker == null) {
// available suggestions == false
suggestions = await DartCompletionManager(
+ budget: budget,
listener: listener,
).computeSuggestions(dartRequest, performance);
} else {
@@ -1218,6 +1220,7 @@
<protocol.IncludedSuggestionRelevanceTag>[];
var includedSuggestionSetList = <protocol.IncludedSuggestionSet>[];
suggestions = await DartCompletionManager(
+ budget: budget,
includedElementKinds: includedElementKinds,
includedElementNames: includedElementNames,
includedSuggestionRelevanceTags: includedSuggestionRelevanceTagList,
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index e88c858..4a50a3c 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -1664,7 +1664,7 @@
}
@override
- void endImplicitCreationExpression(Token token) {
+ void endImplicitCreationExpression(Token token, Token openAngleBracket) {
debugEvent("ImplicitCreationExpression");
_handleInstanceCreation(null);
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 6f08b8b..c19ef88 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -4948,6 +4948,14 @@
if (enableConstructorTearOffsInLibrary && inImplicitCreationContext) {
Expression receiver = receiverFunction();
if (typeArguments != null) {
+ if (receiver is StaticTearOff &&
+ (receiver.target.isFactory ||
+ isTearOffLowering(receiver.target)) ||
+ receiver is ConstructorTearOff ||
+ receiver is RedirectingFactoryTearOff) {
+ return buildProblem(fasta.messageConstructorTearOffWithTypeArguments,
+ instantiationOffset, noLength);
+ }
receiver = forest.createInstantiation(
instantiationOffset,
receiver,
@@ -4974,10 +4982,10 @@
}
@override
- void endImplicitCreationExpression(Token token) {
+ void endImplicitCreationExpression(Token token, Token openAngleBracket) {
debugEvent("ImplicitCreationExpression");
_buildConstructorReferenceInvocation(
- token.next!, token.offset, Constness.implicit,
+ token, openAngleBracket.offset, Constness.implicit,
inMetadata: false, inImplicitCreationContext: true);
}
diff --git a/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart b/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart
index ffb7439..4fedb0b 100644
--- a/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart
+++ b/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart
@@ -1172,11 +1172,12 @@
}
@override
- void endImplicitCreationExpression(Token token) {
+ void endImplicitCreationExpression(Token token, Token openAngleBracket) {
DirectParserASTContentImplicitCreationExpressionEnd data =
new DirectParserASTContentImplicitCreationExpressionEnd(
DirectParserASTType.END,
- token: token);
+ token: token,
+ openAngleBracket: openAngleBracket);
seen(data);
}
@@ -4782,14 +4783,16 @@
class DirectParserASTContentImplicitCreationExpressionEnd
extends DirectParserASTContent {
final Token token;
+ final Token openAngleBracket;
DirectParserASTContentImplicitCreationExpressionEnd(DirectParserASTType type,
- {required this.token})
+ {required this.token, required this.openAngleBracket})
: super("ImplicitCreationExpression", type);
@override
Map<String, Object?> get deprecatedArguments => {
"token": token,
+ "openAngleBracket": openAngleBracket,
};
}
diff --git a/pkg/front_end/parser_testcases/general/function_reference_following_token.dart.expect b/pkg/front_end/parser_testcases/general/function_reference_following_token.dart.expect
index 2fca01a..8b8e356 100644
--- a/pkg/front_end/parser_testcases/general/function_reference_following_token.dart.expect
+++ b/pkg/front_end/parser_testcases/general/function_reference_following_token.dart.expect
@@ -293,7 +293,7 @@
handleNoType(var)
handleIdentifier(typeArgs_period_methodInvocation, topLevelVariableDeclaration)
beginFieldInitializer(=)
- beginImplicitCreationExpression(=)
+ beginImplicitCreationExpression(f)
handleIdentifier(f, constructorReference)
beginConstructorReference(f)
beginTypeArguments(<)
@@ -308,7 +308,7 @@
endConstructorReference(f, ., (, ConstructorReferenceContext.Implicit)
beginArguments(()
endArguments(0, (, ))
- endImplicitCreationExpression(=)
+ endImplicitCreationExpression(f, <)
endFieldInitializer(=, ;)
endTopLevelFields(null, null, null, null, var, 1, var, ;)
endTopLevelDeclaration(var)
diff --git a/pkg/front_end/parser_testcases/general/function_reference_following_token.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/function_reference_following_token.dart.intertwined.expect
index 32d6f7d..11e6ef5 100644
--- a/pkg/front_end/parser_testcases/general/function_reference_following_token.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/general/function_reference_following_token.dart.intertwined.expect
@@ -396,8 +396,8 @@
parseExpression(=)
parsePrecedenceExpression(=, 1, true)
parseUnaryExpression(=, true)
- parseImplicitCreationExpression(=, Instance of 'ComplexTypeParamOrArgInfo')
- listener: beginImplicitCreationExpression(=)
+ parseImplicitCreationExpression(=, <, Instance of 'ComplexTypeParamOrArgInfo')
+ listener: beginImplicitCreationExpression(f)
parseConstructorReference(=, ConstructorReferenceContext.Implicit, Instance of 'ComplexTypeParamOrArgInfo')
ensureIdentifier(=, constructorReference)
listener: handleIdentifier(f, constructorReference)
@@ -418,7 +418,7 @@
parseArgumentsRest(()
listener: beginArguments(()
listener: endArguments(0, (, ))
- listener: endImplicitCreationExpression(=)
+ listener: endImplicitCreationExpression(f, <)
listener: endFieldInitializer(=, ;)
listener: endTopLevelFields(null, null, null, null, var, 1, var, ;)
listener: endTopLevelDeclaration(var)
diff --git a/pkg/front_end/parser_testcases/general/new_as_identifier.dart.expect b/pkg/front_end/parser_testcases/general/new_as_identifier.dart.expect
index 89b9611..97bcac4 100644
--- a/pkg/front_end/parser_testcases/general/new_as_identifier.dart.expect
+++ b/pkg/front_end/parser_testcases/general/new_as_identifier.dart.expect
@@ -545,7 +545,7 @@
handleNoType(var)
handleIdentifier(constructor_invocation_implicit_generic, topLevelVariableDeclaration)
beginFieldInitializer(=)
- beginImplicitCreationExpression(=)
+ beginImplicitCreationExpression(C)
handleIdentifier(C, constructorReference)
beginConstructorReference(C)
beginTypeArguments(<)
@@ -558,7 +558,7 @@
endConstructorReference(C, ., (, ConstructorReferenceContext.Implicit)
beginArguments(()
endArguments(0, (, ))
- endImplicitCreationExpression(=)
+ endImplicitCreationExpression(C, <)
endFieldInitializer(=, ;)
endTopLevelFields(null, null, null, null, var, 1, var, ;)
endTopLevelDeclaration(var)
@@ -595,7 +595,7 @@
handleNoType(var)
handleIdentifier(constructor_invocation_implicit_prefixed_generic, topLevelVariableDeclaration)
beginFieldInitializer(=)
- beginImplicitCreationExpression(=)
+ beginImplicitCreationExpression(prefix)
handleIdentifier(prefix, constructorReference)
beginConstructorReference(prefix)
handleIdentifier(C, constructorReferenceContinuation)
@@ -610,7 +610,7 @@
endConstructorReference(prefix, ., (, ConstructorReferenceContext.Implicit)
beginArguments(()
endArguments(0, (, ))
- endImplicitCreationExpression(=)
+ endImplicitCreationExpression(prefix, <)
endFieldInitializer(=, ;)
endTopLevelFields(null, null, null, null, var, 1, var, ;)
endTopLevelDeclaration(var)
diff --git a/pkg/front_end/parser_testcases/general/new_as_identifier.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/new_as_identifier.dart.intertwined.expect
index f1c6c1c..7af61b0 100644
--- a/pkg/front_end/parser_testcases/general/new_as_identifier.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/general/new_as_identifier.dart.intertwined.expect
@@ -1028,8 +1028,8 @@
parseExpression(=)
parsePrecedenceExpression(=, 1, true)
parseUnaryExpression(=, true)
- parseImplicitCreationExpression(=, Instance of 'SimpleTypeArgument1')
- listener: beginImplicitCreationExpression(=)
+ parseImplicitCreationExpression(=, <, Instance of 'SimpleTypeArgument1')
+ listener: beginImplicitCreationExpression(C)
parseConstructorReference(=, ConstructorReferenceContext.Implicit, Instance of 'SimpleTypeArgument1')
ensureIdentifier(=, constructorReference)
listener: handleIdentifier(C, constructorReference)
@@ -1049,7 +1049,7 @@
parseArgumentsRest(()
listener: beginArguments(()
listener: endArguments(0, (, ))
- listener: endImplicitCreationExpression(=)
+ listener: endImplicitCreationExpression(C, <)
listener: endFieldInitializer(=, ;)
listener: endTopLevelFields(null, null, null, null, var, 1, var, ;)
listener: endTopLevelDeclaration(var)
@@ -1126,8 +1126,8 @@
parseExpression(=)
parsePrecedenceExpression(=, 1, true)
parseUnaryExpression(=, true)
- parseImplicitCreationExpression(=, Instance of 'SimpleTypeArgument1')
- listener: beginImplicitCreationExpression(=)
+ parseImplicitCreationExpression(=, <, Instance of 'SimpleTypeArgument1')
+ listener: beginImplicitCreationExpression(prefix)
parseConstructorReference(=, ConstructorReferenceContext.Implicit, Instance of 'SimpleTypeArgument1')
ensureIdentifier(=, constructorReference)
listener: handleIdentifier(prefix, constructorReference)
@@ -1151,7 +1151,7 @@
parseArgumentsRest(()
listener: beginArguments(()
listener: endArguments(0, (, ))
- listener: endImplicitCreationExpression(=)
+ listener: endImplicitCreationExpression(prefix, <)
listener: endFieldInitializer(=, ;)
listener: endTopLevelFields(null, null, null, null, var, 1, var, ;)
listener: endTopLevelDeclaration(var)
diff --git a/pkg/front_end/test/parser_test_listener.dart b/pkg/front_end/test/parser_test_listener.dart
index 7fcb1c2..f82cd95 100644
--- a/pkg/front_end/test/parser_test_listener.dart
+++ b/pkg/front_end/test/parser_test_listener.dart
@@ -1086,10 +1086,11 @@
}
@override
- void endImplicitCreationExpression(Token token) {
+ void endImplicitCreationExpression(Token token, Token openAngleBracket) {
indent--;
seen(token);
- doPrint('endImplicitCreationExpression(' '$token)');
+ seen(openAngleBracket);
+ doPrint('endImplicitCreationExpression(' '$token, ' '$openAngleBracket)');
}
@override
diff --git a/pkg/front_end/test/parser_test_parser.dart b/pkg/front_end/test/parser_test_parser.dart
index 3ea2b0c..a6ba2ca 100644
--- a/pkg/front_end/test/parser_test_parser.dart
+++ b/pkg/front_end/test/parser_test_parser.dart
@@ -1651,10 +1651,14 @@
@override
Token parseImplicitCreationExpression(
- Token token, TypeParamOrArgInfo typeArg) {
- doPrint('parseImplicitCreationExpression(' '$token, ' '$typeArg)');
+ Token token, Token openAngleBracket, TypeParamOrArgInfo typeArg) {
+ doPrint('parseImplicitCreationExpression('
+ '$token, '
+ '$openAngleBracket, '
+ '$typeArg)');
indent++;
- var result = super.parseImplicitCreationExpression(token, typeArg);
+ var result =
+ super.parseImplicitCreationExpression(token, openAngleBracket, typeArg);
indent--;
return result;
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart b/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart
index efe748f..4232eea 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart
@@ -21,7 +21,7 @@
}
test() {
- A.named<int>.toString();
+ A.named<int>.toString(); // error
}
void main() {
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.strong.expect
index 99500cc..a62bd0c 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.strong.expect
@@ -1,4 +1,12 @@
library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/issue46719.dart:24:10: Error: A constructor tear-off can't have type arguments after the constructor name.
+// Try removing the type arguments or placing them after the class name.
+// A.named<int>.toString(); // error
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -27,30 +35,33 @@
static method FunctionApplier|get#applyAndPrint(lowered final core::Function #this) → (core::List<core::Object?>) → void
return (core::List<core::Object?> positionalArguments) → void => self::FunctionApplier|applyAndPrint(#this, positionalArguments);
static method test() → dynamic {
- #C3.{core::Object::toString}(){() → core::String};
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/issue46719.dart:24:10: Error: A constructor tear-off can't have type arguments after the constructor name.
+Try removing the type arguments or placing them after the class name.
+ A.named<int>.toString(); // error
+ ^";
}
static method main() → void {
self::A<dynamic> a = new self::A::•<dynamic>();
self::FunctionApplier|applyAndPrint(a.{self::A::m}{<X extends core::Object? = dynamic>(X%) → core::List<X%>}<core::int>, <core::Object?>[2]);
self::FunctionApplier|applyAndPrint(a.{self::A::m}{<X extends core::Object? = dynamic>(X%) → core::List<X%>}<core::String>, <core::Object?>["three"]);
- self::FunctionApplier|applyAndPrint(#C5, <core::Object?>[2]);
- self::FunctionApplier|applyAndPrint(#C6, <core::Object?>["three"]);
- self::FunctionApplier|applyAndPrint(#C8, <core::Object?>[2]);
- self::FunctionApplier|applyAndPrint(#C9, <core::Object?>["three"]);
- self::FunctionApplier|applyAndPrint(#C5, <core::Object?>[2]);
- self::FunctionApplier|applyAndPrint(#C6, <core::Object?>["three"]);
- #C2.{core::Object::toString}(){() → core::String};
- #C3.{core::Object::toString}(){() → core::String};
+ self::FunctionApplier|applyAndPrint(#C3, <core::Object?>[2]);
+ self::FunctionApplier|applyAndPrint(#C4, <core::Object?>["three"]);
+ self::FunctionApplier|applyAndPrint(#C6, <core::Object?>[2]);
+ self::FunctionApplier|applyAndPrint(#C7, <core::Object?>["three"]);
+ self::FunctionApplier|applyAndPrint(#C3, <core::Object?>[2]);
+ self::FunctionApplier|applyAndPrint(#C4, <core::Object?>["three"]);
+ #C8.{core::Object::toString}(){() → core::String};
+ #C9.{core::Object::toString}(){() → core::String};
}
constants {
#C1 = <core::Symbol, dynamic>{)
- #C2 = constructor-tearoff self::A::named
+ #C2 = static-tearoff self::A::n
#C3 = instantiation #C2 <core::int>
- #C4 = static-tearoff self::A::n
- #C5 = instantiation #C4 <core::int>
- #C6 = instantiation #C4 <core::String>
- #C7 = static-tearoff self::m
- #C8 = instantiation #C7 <core::int>
- #C9 = instantiation #C7 <core::String>
+ #C4 = instantiation #C2 <core::String>
+ #C5 = static-tearoff self::m
+ #C6 = instantiation #C5 <core::int>
+ #C7 = instantiation #C5 <core::String>
+ #C8 = constructor-tearoff self::A::named
+ #C9 = instantiation #C8 <core::int>
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.strong.transformed.expect
index 4e41cb6..7124a3a 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.strong.transformed.expect
@@ -1,4 +1,12 @@
library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/issue46719.dart:24:10: Error: A constructor tear-off can't have type arguments after the constructor name.
+// Try removing the type arguments or placing them after the class name.
+// A.named<int>.toString(); // error
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -27,30 +35,33 @@
static method FunctionApplier|get#applyAndPrint(lowered final core::Function #this) → (core::List<core::Object?>) → void
return (core::List<core::Object?> positionalArguments) → void => self::FunctionApplier|applyAndPrint(#this, positionalArguments);
static method test() → dynamic {
- #C3.{core::Object::toString}(){() → core::String};
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/issue46719.dart:24:10: Error: A constructor tear-off can't have type arguments after the constructor name.
+Try removing the type arguments or placing them after the class name.
+ A.named<int>.toString(); // error
+ ^";
}
static method main() → void {
self::A<dynamic> a = new self::A::•<dynamic>();
self::FunctionApplier|applyAndPrint(a.{self::A::m}{<X extends core::Object? = dynamic>(X%) → core::List<X%>}<core::int>, core::_GrowableList::_literal1<core::Object?>(2));
self::FunctionApplier|applyAndPrint(a.{self::A::m}{<X extends core::Object? = dynamic>(X%) → core::List<X%>}<core::String>, core::_GrowableList::_literal1<core::Object?>("three"));
- self::FunctionApplier|applyAndPrint(#C5, core::_GrowableList::_literal1<core::Object?>(2));
- self::FunctionApplier|applyAndPrint(#C6, core::_GrowableList::_literal1<core::Object?>("three"));
- self::FunctionApplier|applyAndPrint(#C8, core::_GrowableList::_literal1<core::Object?>(2));
- self::FunctionApplier|applyAndPrint(#C9, core::_GrowableList::_literal1<core::Object?>("three"));
- self::FunctionApplier|applyAndPrint(#C5, core::_GrowableList::_literal1<core::Object?>(2));
- self::FunctionApplier|applyAndPrint(#C6, core::_GrowableList::_literal1<core::Object?>("three"));
- #C2.{core::Object::toString}(){() → core::String};
- #C3.{core::Object::toString}(){() → core::String};
+ self::FunctionApplier|applyAndPrint(#C3, core::_GrowableList::_literal1<core::Object?>(2));
+ self::FunctionApplier|applyAndPrint(#C4, core::_GrowableList::_literal1<core::Object?>("three"));
+ self::FunctionApplier|applyAndPrint(#C6, core::_GrowableList::_literal1<core::Object?>(2));
+ self::FunctionApplier|applyAndPrint(#C7, core::_GrowableList::_literal1<core::Object?>("three"));
+ self::FunctionApplier|applyAndPrint(#C3, core::_GrowableList::_literal1<core::Object?>(2));
+ self::FunctionApplier|applyAndPrint(#C4, core::_GrowableList::_literal1<core::Object?>("three"));
+ #C8.{core::Object::toString}(){() → core::String};
+ #C9.{core::Object::toString}(){() → core::String};
}
constants {
#C1 = <core::Symbol, dynamic>{)
- #C2 = constructor-tearoff self::A::named
+ #C2 = static-tearoff self::A::n
#C3 = instantiation #C2 <core::int>
- #C4 = static-tearoff self::A::n
- #C5 = instantiation #C4 <core::int>
- #C6 = instantiation #C4 <core::String>
- #C7 = static-tearoff self::m
- #C8 = instantiation #C7 <core::int>
- #C9 = instantiation #C7 <core::String>
+ #C4 = instantiation #C2 <core::String>
+ #C5 = static-tearoff self::m
+ #C6 = instantiation #C5 <core::int>
+ #C7 = instantiation #C5 <core::String>
+ #C8 = constructor-tearoff self::A::named
+ #C9 = instantiation #C8 <core::int>
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.weak.expect
index ce83852..6add537 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.weak.expect
@@ -1,4 +1,12 @@
library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/issue46719.dart:24:10: Error: A constructor tear-off can't have type arguments after the constructor name.
+// Try removing the type arguments or placing them after the class name.
+// A.named<int>.toString(); // error
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -27,30 +35,33 @@
static method FunctionApplier|get#applyAndPrint(lowered final core::Function #this) → (core::List<core::Object?>) → void
return (core::List<core::Object?> positionalArguments) → void => self::FunctionApplier|applyAndPrint(#this, positionalArguments);
static method test() → dynamic {
- #C3.{core::Object::toString}(){() → core::String};
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/issue46719.dart:24:10: Error: A constructor tear-off can't have type arguments after the constructor name.
+Try removing the type arguments or placing them after the class name.
+ A.named<int>.toString(); // error
+ ^";
}
static method main() → void {
self::A<dynamic> a = new self::A::•<dynamic>();
self::FunctionApplier|applyAndPrint(a.{self::A::m}{<X extends core::Object? = dynamic>(X%) → core::List<X%>}<core::int>, <core::Object?>[2]);
self::FunctionApplier|applyAndPrint(a.{self::A::m}{<X extends core::Object? = dynamic>(X%) → core::List<X%>}<core::String>, <core::Object?>["three"]);
- self::FunctionApplier|applyAndPrint(#C5, <core::Object?>[2]);
- self::FunctionApplier|applyAndPrint(#C6, <core::Object?>["three"]);
- self::FunctionApplier|applyAndPrint(#C8, <core::Object?>[2]);
- self::FunctionApplier|applyAndPrint(#C9, <core::Object?>["three"]);
- self::FunctionApplier|applyAndPrint(#C5, <core::Object?>[2]);
- self::FunctionApplier|applyAndPrint(#C6, <core::Object?>["three"]);
- #C2.{core::Object::toString}(){() → core::String};
- #C3.{core::Object::toString}(){() → core::String};
+ self::FunctionApplier|applyAndPrint(#C3, <core::Object?>[2]);
+ self::FunctionApplier|applyAndPrint(#C4, <core::Object?>["three"]);
+ self::FunctionApplier|applyAndPrint(#C6, <core::Object?>[2]);
+ self::FunctionApplier|applyAndPrint(#C7, <core::Object?>["three"]);
+ self::FunctionApplier|applyAndPrint(#C3, <core::Object?>[2]);
+ self::FunctionApplier|applyAndPrint(#C4, <core::Object?>["three"]);
+ #C8.{core::Object::toString}(){() → core::String};
+ #C9.{core::Object::toString}(){() → core::String};
}
constants {
#C1 = <core::Symbol*, dynamic>{)
- #C2 = constructor-tearoff self::A::named
+ #C2 = static-tearoff self::A::n
#C3 = instantiation #C2 <core::int*>
- #C4 = static-tearoff self::A::n
- #C5 = instantiation #C4 <core::int*>
- #C6 = instantiation #C4 <core::String*>
- #C7 = static-tearoff self::m
- #C8 = instantiation #C7 <core::int*>
- #C9 = instantiation #C7 <core::String*>
+ #C4 = instantiation #C2 <core::String*>
+ #C5 = static-tearoff self::m
+ #C6 = instantiation #C5 <core::int*>
+ #C7 = instantiation #C5 <core::String*>
+ #C8 = constructor-tearoff self::A::named
+ #C9 = instantiation #C8 <core::int*>
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.weak.transformed.expect
index cd0afe2..328de14 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/issue46719.dart.weak.transformed.expect
@@ -1,4 +1,12 @@
library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/issue46719.dart:24:10: Error: A constructor tear-off can't have type arguments after the constructor name.
+// Try removing the type arguments or placing them after the class name.
+// A.named<int>.toString(); // error
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -27,30 +35,33 @@
static method FunctionApplier|get#applyAndPrint(lowered final core::Function #this) → (core::List<core::Object?>) → void
return (core::List<core::Object?> positionalArguments) → void => self::FunctionApplier|applyAndPrint(#this, positionalArguments);
static method test() → dynamic {
- #C3.{core::Object::toString}(){() → core::String};
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/issue46719.dart:24:10: Error: A constructor tear-off can't have type arguments after the constructor name.
+Try removing the type arguments or placing them after the class name.
+ A.named<int>.toString(); // error
+ ^";
}
static method main() → void {
self::A<dynamic> a = new self::A::•<dynamic>();
self::FunctionApplier|applyAndPrint(a.{self::A::m}{<X extends core::Object? = dynamic>(X%) → core::List<X%>}<core::int>, core::_GrowableList::_literal1<core::Object?>(2));
self::FunctionApplier|applyAndPrint(a.{self::A::m}{<X extends core::Object? = dynamic>(X%) → core::List<X%>}<core::String>, core::_GrowableList::_literal1<core::Object?>("three"));
- self::FunctionApplier|applyAndPrint(#C5, core::_GrowableList::_literal1<core::Object?>(2));
- self::FunctionApplier|applyAndPrint(#C6, core::_GrowableList::_literal1<core::Object?>("three"));
- self::FunctionApplier|applyAndPrint(#C8, core::_GrowableList::_literal1<core::Object?>(2));
- self::FunctionApplier|applyAndPrint(#C9, core::_GrowableList::_literal1<core::Object?>("three"));
- self::FunctionApplier|applyAndPrint(#C5, core::_GrowableList::_literal1<core::Object?>(2));
- self::FunctionApplier|applyAndPrint(#C6, core::_GrowableList::_literal1<core::Object?>("three"));
- #C2.{core::Object::toString}(){() → core::String};
- #C3.{core::Object::toString}(){() → core::String};
+ self::FunctionApplier|applyAndPrint(#C3, core::_GrowableList::_literal1<core::Object?>(2));
+ self::FunctionApplier|applyAndPrint(#C4, core::_GrowableList::_literal1<core::Object?>("three"));
+ self::FunctionApplier|applyAndPrint(#C6, core::_GrowableList::_literal1<core::Object?>(2));
+ self::FunctionApplier|applyAndPrint(#C7, core::_GrowableList::_literal1<core::Object?>("three"));
+ self::FunctionApplier|applyAndPrint(#C3, core::_GrowableList::_literal1<core::Object?>(2));
+ self::FunctionApplier|applyAndPrint(#C4, core::_GrowableList::_literal1<core::Object?>("three"));
+ #C8.{core::Object::toString}(){() → core::String};
+ #C9.{core::Object::toString}(){() → core::String};
}
constants {
#C1 = <core::Symbol*, dynamic>{)
- #C2 = constructor-tearoff self::A::named
+ #C2 = static-tearoff self::A::n
#C3 = instantiation #C2 <core::int*>
- #C4 = static-tearoff self::A::n
- #C5 = instantiation #C4 <core::int*>
- #C6 = instantiation #C4 <core::String*>
- #C7 = static-tearoff self::m
- #C8 = instantiation #C7 <core::int*>
- #C9 = instantiation #C7 <core::String*>
+ #C4 = instantiation #C2 <core::String*>
+ #C5 = static-tearoff self::m
+ #C6 = instantiation #C5 <core::int*>
+ #C7 = instantiation #C5 <core::String*>
+ #C8 = constructor-tearoff self::A::named
+ #C9 = instantiation #C8 <core::int*>
}
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index 0af318b..f30e794 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -30,6 +30,10 @@
return obj;
}
+List<dynamic> assertListOfDynamic(List<dynamic> list) {
+ return list;
+}
+
List<int> assertListOfInt(List<int> list) {
for (int elem in list) {
assertInt(elem);
@@ -1146,6 +1150,12 @@
return obj;
}
+vms.UriList assertUriList(vms.UriList obj) {
+ assertNotNull(obj);
+ assertListOfDynamic(obj.uris!);
+ return obj;
+}
+
vms.Version assertVersion(vms.Version obj) {
assertNotNull(obj);
assertInt(obj.major!);
diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore
index cc8a3e7..817e983 100644
--- a/pkg/vm_service/java/.gitignore
+++ b/pkg/vm_service/java/.gitignore
@@ -43,6 +43,7 @@
src/org/dartlang/vm/service/consumer/TimelineConsumer.java
src/org/dartlang/vm/service/consumer/TimelineFlagsConsumer.java
src/org/dartlang/vm/service/consumer/TimestampConsumer.java
+src/org/dartlang/vm/service/consumer/UriListConsumer.java
src/org/dartlang/vm/service/consumer/VMConsumer.java
src/org/dartlang/vm/service/consumer/VersionConsumer.java
src/org/dartlang/vm/service/element/AllocationProfile.java
@@ -131,6 +132,7 @@
src/org/dartlang/vm/service/element/TypeArgumentsRef.java
src/org/dartlang/vm/service/element/TypeParameters.java
src/org/dartlang/vm/service/element/UnresolvedSourceLocation.java
+src/org/dartlang/vm/service/element/UriList.java
src/org/dartlang/vm/service/element/VM.java
src/org/dartlang/vm/service/element/VMRef.java
src/org/dartlang/vm/service/element/Version.java
diff --git a/pkg/vm_service/java/src/org/dartlang/vm/service/consumer/ResolvePackageUriConsumer.java b/pkg/vm_service/java/src/org/dartlang/vm/service/consumer/ResolvePackageUriConsumer.java
new file mode 100644
index 0000000..cb35d14
--- /dev/null
+++ b/pkg/vm_service/java/src/org/dartlang/vm/service/consumer/ResolvePackageUriConsumer.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, the Dart project authors.
+ *
+ * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.dartlang.vm.service.consumer;
+
+// This is a generated file.
+
+import org.dartlang.vm.service.element.ResolvedPackageUri;
+import org.dartlang.vm.service.element.Sentinel;
+
+@SuppressWarnings({"WeakerAccess", "unused"})
+public interface ResolvePackageUriConsumer extends Consumer {
+ void received(ResolvedPackageUri response);
+
+ void received(Sentinel response);
+}
diff --git a/pkg/vm_service/java/src/org/dartlang/vm/service/element/ResolvedPackageUri.java b/pkg/vm_service/java/src/org/dartlang/vm/service/element/ResolvedPackageUri.java
new file mode 100644
index 0000000..376b4f0
--- /dev/null
+++ b/pkg/vm_service/java/src/org/dartlang/vm/service/element/ResolvedPackageUri.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, the Dart project authors.
+ *
+ * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.dartlang.vm.service.element;
+
+// This is a generated file.
+
+import com.google.gson.JsonObject;
+
+@SuppressWarnings({"WeakerAccess", "unused"})
+public class ResolvedPackageUri extends Response {
+ public ResolvedPackageUri(JsonObject json) {
+ super(json);
+ }
+
+ /**
+ * The file URI for a given package.
+ */
+ public String getResolvedUri() {
+ return getAsString("resolvedUri");
+ }
+}
diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties
index 383674e..8ae6998 100644
--- a/pkg/vm_service/java/version.properties
+++ b/pkg/vm_service/java/version.properties
@@ -1 +1 @@
-version=3.51
+version=3.52
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index 277b463..51958bd 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -26,7 +26,7 @@
HeapSnapshotObjectNoData,
HeapSnapshotObjectNullData;
-const String vmServiceVersion = '3.51.0';
+const String vmServiceVersion = '3.52.0';
/// @optional
const String optional = 'optional';
@@ -186,6 +186,7 @@
'TypeArguments': TypeArguments.parse,
'TypeParameters': TypeParameters.parse,
'UnresolvedSourceLocation': UnresolvedSourceLocation.parse,
+ 'UriList': UriList.parse,
'Version': Version.parse,
'@VM': VMRef.parse,
'VM': VM.parse,
@@ -226,6 +227,8 @@
'getVMTimelineMicros': const ['Timestamp'],
'pause': const ['Success'],
'kill': const ['Success'],
+ 'lookupResolvedPackageUris': const ['UriList'],
+ 'lookupPackageUris': const ['UriList'],
'registerService': const ['Success'],
'reloadSources': const ['ReloadReport'],
'removeBreakpoint': const ['Success'],
@@ -920,6 +923,37 @@
/// returned.
Future<Success> kill(String isolateId);
+ /// The `lookupResolvedPackageUris` RPC is used to convert a list of URIs to
+ /// their resolved (or absolute) paths. For example, URIs passed to this RPC
+ /// are mapped in the following ways:
+ ///
+ /// - `dart:io` -> `org-dartlang-sdk:///sdk/lib/io/io.dart`
+ /// - `package:test/test.dart` ->
+ /// `file:///$PACKAGE_INSTALLATION_DIR/lib/test.dart`
+ /// - `file:///foo/bar/bazz.dart` -> `file:///foo/bar/bazz.dart`
+ ///
+ /// If a URI is not known, the corresponding entry in the [UriList] response
+ /// will be `null`.
+ ///
+ /// See [UriList].
+ Future<UriList> lookupResolvedPackageUris(
+ String isolateId, List<String> uris);
+
+ /// The `lookupPackageUris` RPC is used to convert a list of URIs to their
+ /// unresolved paths. For example, URIs passed to this RPC are mapped in the
+ /// following ways:
+ ///
+ /// - `org-dartlang-sdk:///sdk/lib/io/io.dart` -> `dart:io`
+ /// - `file:///$PACKAGE_INSTALLATION_DIR/lib/test.dart` ->
+ /// `package:test/test.dart`
+ /// - `file:///foo/bar/bazz.dart` -> `file:///foo/bar/bazz.dart`
+ ///
+ /// If a URI is not known, the corresponding entry in the [UriList] response
+ /// will be `null`.
+ ///
+ /// See [UriList].
+ Future<UriList> lookupPackageUris(String isolateId, List<String> uris);
+
/// Registers a service that can be invoked by other VM service clients, where
/// `service` is the name of the service to advertise and `alias` is an
/// alternative name for the registered service.
@@ -1468,6 +1502,18 @@
params!['isolateId'],
);
break;
+ case 'lookupResolvedPackageUris':
+ response = await _serviceImplementation.lookupResolvedPackageUris(
+ params!['isolateId'],
+ List<String>.from(params['uris'] ?? []),
+ );
+ break;
+ case 'lookupPackageUris':
+ response = await _serviceImplementation.lookupPackageUris(
+ params!['isolateId'],
+ List<String>.from(params['uris'] ?? []),
+ );
+ break;
case 'reloadSources':
response = await _serviceImplementation.reloadSources(
params!['isolateId'],
@@ -1979,6 +2025,16 @@
_call('kill', {'isolateId': isolateId});
@override
+ Future<UriList> lookupResolvedPackageUris(
+ String isolateId, List<String> uris) =>
+ _call(
+ 'lookupResolvedPackageUris', {'isolateId': isolateId, 'uris': uris});
+
+ @override
+ Future<UriList> lookupPackageUris(String isolateId, List<String> uris) =>
+ _call('lookupPackageUris', {'isolateId': isolateId, 'uris': uris});
+
+ @override
Future<Success> registerService(String service, String alias) =>
_call('registerService', {'service': service, 'alias': alias});
@@ -6112,9 +6168,8 @@
/// example, memory associated with Dart objects through APIs such as
/// Dart_NewFinalizableHandle, Dart_NewWeakPersistentHandle and
/// Dart_NewExternalTypedData. This usage is only as accurate as the values
- /// supplied to these APIs from the VM embedder or native extensions. This
- /// external memory applies GC pressure, but is separate from heapUsage and
- /// heapCapacity.
+ /// supplied to these APIs from the VM embedder. This external memory applies
+ /// GC pressure, but is separate from heapUsage and heapCapacity.
int? externalUsage;
/// The total capacity of the heap in bytes. This is the amount of memory used
@@ -7876,6 +7931,38 @@
String toString() => '[UnresolvedSourceLocation]';
}
+class UriList extends Response {
+ static UriList? parse(Map<String, dynamic>? json) =>
+ json == null ? null : UriList._fromJson(json);
+
+ /// A list of URIs.
+ List<dynamic>? uris;
+
+ UriList({
+ required this.uris,
+ });
+
+ UriList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
+ uris = List<dynamic>.from(
+ createServiceObject(json['uris'], const ['dynamic']) as List? ?? []);
+ }
+
+ @override
+ String get type => 'UriList';
+
+ @override
+ Map<String, dynamic> toJson() {
+ final json = <String, dynamic>{};
+ json['type'] = type;
+ json.addAll({
+ 'uris': uris?.map((f) => f.toJson()).toList(),
+ });
+ return json;
+ }
+
+ String toString() => '[UriList uris: ${uris}]';
+}
+
/// See [Versioning].
class Version extends Response {
static Version? parse(Map<String, dynamic>? json) =>
diff --git a/pkg/vm_service/test/uri_mappings_lookup_test.dart b/pkg/vm_service/test/uri_mappings_lookup_test.dart
new file mode 100644
index 0000000..0155833
--- /dev/null
+++ b/pkg/vm_service/test/uri_mappings_lookup_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/test_helper.dart';
+
+final tests = <IsolateTest>[
+ (VmService service, IsolateRef isolate) async {
+ final isolateId = isolate.id!;
+ final unresolvedUris = <String>[
+ 'dart:io', // dart:io -> org-dartlang-sdk:///sdk/lib/io/io.dart
+ Platform.script.toString(), // file:///abc.dart -> file:///abc.dart
+ 'package:test/test.dart', // package:test/test.dart -> file:///some_dir/test/lib/test.dart
+ 'package:does_not_exist/does_not_exist.dart', // invalid URI -> null
+ ];
+
+ var result = await service.lookupResolvedPackageUris(
+ isolateId,
+ unresolvedUris,
+ );
+ expect(result.uris, isNotNull);
+ var uris = result.uris!;
+ expect(uris.length, 4);
+ expect(uris[0], 'org-dartlang-sdk:///sdk/lib/io/io.dart');
+ expect(uris[1], Platform.script.toString());
+ expect(uris[2], startsWith('file:///'));
+ expect(uris[2], endsWith('third_party/pkg/test/pkgs/test/lib/test.dart'));
+ expect(uris[3], isNull);
+
+ result = await service.lookupPackageUris(
+ isolateId,
+ [
+ ...uris.sublist(0, 3),
+ 'does_not_exist.dart',
+ ],
+ );
+ expect(result.uris, isNotNull);
+ uris = result.uris!;
+ expect(uris.length, 4);
+ expect(uris[0], unresolvedUris[0]);
+ expect(uris[1], unresolvedUris[1]);
+ expect(uris[2], unresolvedUris[2]);
+ expect(uris[3], isNull);
+ },
+];
+
+void main(args) => runIsolateTests(
+ args,
+ tests,
+ 'uri_mappings_lookup_test.dart',
+ );
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 340b046..4ad1d93 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
final result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], 'Version');
expect(result['major'], 3);
- expect(result['minor'], 51);
+ expect(result['minor'], 52);
expect(result['_privateMajor'], 0);
expect(result['_privateMinor'], 0);
},
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index c7e818c..ee2c8dc 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -29,12 +29,14 @@
[ $system == android ]
string_escaping_test: Skip # Issue http://dartbug.com/42094
+uri_mappings_lookup_test: SkipByDesign # Relies on file paths in the SDK.
[ $system == windows ]
*: Slow
async_generator_breakpoint_test: Skip # Issue 29145
dev_fs_http_put_weird_char_test: Skip # Windows disallows carriage returns in paths
dev_fs_weird_char_test: Skip # Windows disallows question mark in paths
+uri_mappings_lookup_test: SkipByDesign # Relies on file paths in the SDK.
[ $compiler == none && $runtime == vm ]
evaluate_activation_test/instance: RuntimeError # http://dartbug.com/20047
diff --git a/runtime/observatory/tests/service/uri_mappings_lookup_test.dart b/runtime/observatory/tests/service/uri_mappings_lookup_test.dart
new file mode 100644
index 0000000..dd19f6a
--- /dev/null
+++ b/runtime/observatory/tests/service/uri_mappings_lookup_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:observatory/service_io.dart';
+// Already a dependency of package:test.
+import 'package:pool/pool.dart';
+import 'package:test/test.dart';
+
+import 'test_helper.dart';
+
+final tests = <IsolateTest>[
+ (Isolate isolate) async {
+ final scriptUri =
+ 'file://${Directory.current.path}/runtime/observatory/tests/service/uri_mappings_lookup_test.dart';
+ final unresolvedUris = <String>[
+ 'package:does_not_exist/does_not_exist.dart', // invalid URI -> null
+ 'dart:io', // dart:io -> org-dartlang-sdk:///sdk/lib/io/io.dart
+ 'package:pool/pool.dart', // package:pool/pool.dart -> file:///some_dir/pool/lib/pool.dart
+ scriptUri, // file:///abc.dart -> file:///abc.dart
+ ];
+
+ var result = await isolate.invokeRpcNoUpgrade('lookupResolvedPackageUris', {
+ 'uris': unresolvedUris,
+ });
+ expect(result['uris'], isNotNull);
+ var uris = result['uris'].cast<String?>();
+ expect(uris.length, 4);
+ expect(uris[0], isNull);
+ expect(uris[1], 'org-dartlang-sdk:///sdk/lib/io/io.dart');
+ expect(uris[2], startsWith('file:///'));
+ expect(uris[2], endsWith('third_party/pkg/pool/lib/pool.dart'));
+ expect(uris[3], scriptUri);
+
+ result = await isolate.invokeRpcNoUpgrade('lookupPackageUris', {
+ 'uris': [
+ 'does_not_exist.dart',
+ ...uris.sublist(1, 4),
+ ]
+ });
+ expect(result['uris'], isNotNull);
+ uris = result['uris'].cast<String?>();
+ expect(uris.length, 4);
+ expect(uris[0], isNull);
+ expect(uris[1], unresolvedUris[1]);
+ expect(uris[2], unresolvedUris[2]);
+ expect(uris[3], unresolvedUris[3]);
+ },
+];
+
+void main(args) => runIsolateTests(args, tests);
diff --git a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
index 9b7cdf5..12ffc1c 100644
--- a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
+++ b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
final result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
expect(result['major'], equals(3));
- expect(result['minor'], equals(51));
+ expect(result['minor'], equals(52));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
},
diff --git a/runtime/observatory_2/tests/service_2/service_2.status b/runtime/observatory_2/tests/service_2/service_2.status
index 8e5b462..c5a50bb 100644
--- a/runtime/observatory_2/tests/service_2/service_2.status
+++ b/runtime/observatory_2/tests/service_2/service_2.status
@@ -15,10 +15,8 @@
[ $arch == arm ]
process_service_test: Pass, Fail # Issue 24344
-# Test uses service API and relies on correct class names
[ $builder_tag == obfuscated ]
-dominator_tree_vm_test: SkipByDesign
-dominator_tree_vm_with_double_field_test: SkipByDesign
+*: SkipByDesign # Responses full of obfuscated names
# Tests with known analyzer issues
[ $compiler == dart2analyzer ]
@@ -34,12 +32,14 @@
[ $system == android ]
string_escaping_test: Skip # Issue http://dartbug.com/42094
+uri_mappings_lookup_test: SkipByDesign # Relies on file paths in the SDK.
[ $system == windows ]
*: Slow
async_generator_breakpoint_test: Skip # Issue 29145
dev_fs_http_put_weird_char_test: Skip # Windows disallows carriage returns in paths
dev_fs_weird_char_test: Skip # Windows disallows question mark in paths
+uri_mappings_lookup_test: SkipByDesign # Relies on file paths in the SDK.
[ $compiler == none && $runtime == vm ]
evaluate_activation_test/instance: RuntimeError # http://dartbug.com/20047
diff --git a/runtime/observatory_2/tests/service_2/uri_mappings_lookup_test.dart b/runtime/observatory_2/tests/service_2/uri_mappings_lookup_test.dart
new file mode 100644
index 0000000..832dcee
--- /dev/null
+++ b/runtime/observatory_2/tests/service_2/uri_mappings_lookup_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:observatory_2/service_io.dart';
+// Already a dependency of package:test.
+import 'package:pool/pool.dart';
+import 'package:test/test.dart';
+
+import 'test_helper.dart';
+
+final tests = <IsolateTest>[
+ (Isolate isolate) async {
+ final scriptUri =
+ 'file://${Directory.current.path}/runtime/observatory_2/tests/service_2/uri_mappings_lookup_test.dart';
+ final unresolvedUris = <String>[
+ 'package:does_not_exist/does_not_exist.dart', // invalid URI -> null
+ 'dart:io', // dart:io -> org-dartlang-sdk:///sdk/lib/io/io.dart
+ 'package:pool/pool.dart', // package:pool/pool.dart -> file:///some_dir/pool/lib/pool.dart
+ scriptUri, // file:///abc.dart -> file:///abc.dart
+ ];
+
+ var result = await isolate.invokeRpcNoUpgrade('lookupResolvedPackageUris', {
+ 'uris': unresolvedUris,
+ });
+ expect(result['uris'], isNotNull);
+ var uris = result['uris'].cast<String>();
+ expect(uris.length, 4);
+ expect(uris[0], isNull);
+ expect(uris[1], 'org-dartlang-sdk:///sdk/lib/io/io.dart');
+ expect(uris[2], startsWith('file:///'));
+ expect(uris[2], endsWith('third_party/pkg/pool/lib/pool.dart'));
+ expect(uris[3], scriptUri);
+
+ result = await isolate.invokeRpcNoUpgrade('lookupPackageUris', {
+ 'uris': [
+ 'does_not_exist.dart',
+ ...uris.sublist(1, 4),
+ ]
+ });
+ expect(result['uris'], isNotNull);
+ uris = result['uris'].cast<String>();
+ expect(uris.length, 4);
+ expect(uris[0], isNull);
+ expect(uris[1], unresolvedUris[1]);
+ expect(uris[2], unresolvedUris[2]);
+ expect(uris[3], unresolvedUris[3]);
+ },
+];
+
+void main(args) => runIsolateTests(args, tests);
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 7d69548..8e8c737 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -558,6 +558,9 @@
constexpr intptr_t RoundWordsToGB(intptr_t size_in_words) {
return (size_in_words + (GBInWords >> 1)) >> GBInWordsLog2;
}
+constexpr double WordsToMB(intptr_t size_in_words) {
+ return static_cast<double>(size_in_words) / MBInWords;
+}
constexpr intptr_t kIntptrOne = 1;
constexpr intptr_t kIntptrMin = (kIntptrOne << (kBitsPerWord - 1));
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index b85bfec..acdb7c6 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -1109,9 +1109,8 @@
BackgroundCompiler::BackgroundCompiler(IsolateGroup* isolate_group)
: isolate_group_(isolate_group),
- queue_monitor_(),
+ monitor_(),
function_queue_(new BackgroundCompilationQueue()),
- done_monitor_(),
running_(false),
done_(true),
disabled_depth_(0) {}
@@ -1122,71 +1121,56 @@
}
void BackgroundCompiler::Run() {
- while (true) {
- // Maybe something is already in the queue, check first before waiting
- // to be notified.
- bool result = Thread::EnterIsolateGroupAsHelper(
- isolate_group_, Thread::kCompilerTask, /*bypass_safepoint=*/false);
- ASSERT(result);
+ bool result = Thread::EnterIsolateGroupAsHelper(
+ isolate_group_, Thread::kCompilerTask, /*bypass_safepoint=*/false);
+ ASSERT(result);
+ {
+ Thread* thread = Thread::Current();
+ StackZone stack_zone(thread);
+ Zone* zone = stack_zone.GetZone();
+ HANDLESCOPE(thread);
+ Function& function = Function::Handle(zone);
+ QueueElement* element = nullptr;
{
- Thread* thread = Thread::Current();
- StackZone stack_zone(thread);
- Zone* zone = stack_zone.GetZone();
- Function& function = Function::Handle(zone);
- {
- SafepointMonitorLocker ml(&queue_monitor_);
- if (running_) {
- function = function_queue()->PeekFunction();
- }
+ SafepointMonitorLocker ml(&monitor_);
+ if (running_ && !function_queue()->IsEmpty()) {
+ element = function_queue()->Remove();
+ function ^= element->function();
}
- while (!function.IsNull()) {
- Compiler::CompileOptimizedFunction(thread, function,
- Compiler::kNoOSRDeoptId);
+ }
+ if (element != nullptr) {
+ delete element;
+ Compiler::CompileOptimizedFunction(thread, function,
+ Compiler::kNoOSRDeoptId);
- QueueElement* qelem = NULL;
- {
- SafepointMonitorLocker ml(&queue_monitor_);
- if (!running_ || function_queue()->IsEmpty()) {
- // We are shutting down, queue was cleared.
- function = Function::null();
- } else {
- qelem = function_queue()->Remove();
- const Function& old = Function::Handle(qelem->Function());
- // If an optimizable method is not optimized, put it back on
- // the background queue (unless it was passed to foreground).
- if ((!old.HasOptimizedCode() && old.IsOptimizable()) ||
- FLAG_stress_test_background_compilation) {
- if (Compiler::CanOptimizeFunction(thread, old)) {
- QueueElement* repeat_qelem = new QueueElement(old);
- function_queue()->Add(repeat_qelem);
- }
- }
- function = function_queue()->PeekFunction();
+ // If an optimizable method is not optimized, put it back on
+ // the background queue (unless it was passed to foreground).
+ if ((!function.HasOptimizedCode() && function.IsOptimizable()) ||
+ FLAG_stress_test_background_compilation) {
+ if (Compiler::CanOptimizeFunction(thread, function)) {
+ SafepointMonitorLocker ml(&monitor_);
+ if (running_) {
+ QueueElement* repeat_qelem = new QueueElement(function);
+ function_queue()->Add(repeat_qelem);
}
}
- if (qelem != NULL) {
- delete qelem;
- }
}
}
- Thread::ExitIsolateGroupAsHelper(/*bypass_safepoint=*/false);
- {
- // Wait to be notified when the work queue is not empty.
- MonitorLocker ml(&queue_monitor_);
- while (function_queue()->IsEmpty() && running_) {
- ml.Wait();
- }
- if (!running_) {
- break;
- }
- }
- } // while running
-
+ }
+ Thread::ExitIsolateGroupAsHelper(/*bypass_safepoint=*/false);
{
- // Notify that the thread is done.
- MonitorLocker ml_done(&done_monitor_);
- done_ = true;
- ml_done.NotifyAll();
+ MonitorLocker ml(&monitor_);
+ if (running_ && !function_queue()->IsEmpty() &&
+ Dart::thread_pool()->Run<BackgroundCompilerTask>(this)) {
+ // Successfully scheduled a new task.
+ } else {
+ // Background compiler done. This notification must happen after the
+ // thread leaves to group to avoid a shutdown race with the thread
+ // registry.
+ running_ = false;
+ done_ = true;
+ ml.NotifyAll();
+ }
}
}
@@ -1195,7 +1179,7 @@
ASSERT(thread->IsMutatorThread());
ASSERT(!thread->IsAtSafepoint(SafepointLevel::kGCAndDeopt));
- SafepointMonitorLocker ml_done(&done_monitor_);
+ SafepointMonitorLocker ml(&monitor_);
if (disabled_depth_ > 0) return false;
if (!running_ && done_) {
running_ = true;
@@ -1211,7 +1195,6 @@
}
}
- SafepointMonitorLocker ml(&queue_monitor_);
ASSERT(running_);
if (function_queue()->ContainsObj(function)) {
return true;
@@ -1231,21 +1214,16 @@
ASSERT(thread->isolate() == nullptr || thread->IsMutatorThread());
ASSERT(!thread->IsAtSafepoint(SafepointLevel::kGCAndDeopt));
- SafepointMonitorLocker ml_done(&done_monitor_);
- StopLocked(thread, &ml_done);
+ SafepointMonitorLocker ml(&monitor_);
+ StopLocked(thread, &ml);
}
void BackgroundCompiler::StopLocked(Thread* thread,
- SafepointMonitorLocker* done_locker) {
- {
- SafepointMonitorLocker ml(&queue_monitor_);
- running_ = false;
- function_queue_->Clear();
- ml.NotifyAll(); // Stop waiting for the queue.
- }
-
+ SafepointMonitorLocker* locker) {
+ running_ = false;
+ function_queue_->Clear();
while (!done_) {
- done_locker->Wait();
+ locker->Wait();
}
}
@@ -1254,7 +1232,7 @@
ASSERT(thread->IsMutatorThread());
ASSERT(!thread->IsAtSafepoint(SafepointLevel::kGCAndDeopt));
- SafepointMonitorLocker ml_done(&done_monitor_);
+ SafepointMonitorLocker ml(&monitor_);
disabled_depth_--;
if (disabled_depth_ < 0) {
FATAL("Mismatched number of calls to BackgroundCompiler::Enable/Disable.");
@@ -1266,10 +1244,10 @@
ASSERT(thread->IsMutatorThread());
ASSERT(!thread->IsAtSafepoint(SafepointLevel::kGCAndDeopt));
- SafepointMonitorLocker ml_done(&done_monitor_);
+ SafepointMonitorLocker ml(&monitor_);
disabled_depth_++;
if (done_) return;
- StopLocked(thread, &ml_done);
+ StopLocked(thread, &ml);
}
#else // DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/compiler/jit/compiler.h b/runtime/vm/compiler/jit/compiler.h
index 528a964..caa0903 100644
--- a/runtime/vm/compiler/jit/compiler.h
+++ b/runtime/vm/compiler/jit/compiler.h
@@ -158,13 +158,10 @@
IsolateGroup* isolate_group_;
- Monitor queue_monitor_; // Controls access to the queue.
+ Monitor monitor_; // Controls access to the queue and running state.
BackgroundCompilationQueue* function_queue_;
-
- Monitor done_monitor_; // Notify/wait that the thread is done.
bool running_; // While true, will try to read queue and compile.
bool done_; // True if the thread is done.
-
int16_t disabled_depth_;
DISALLOW_IMPLICIT_CONSTRUCTORS(BackgroundCompiler);
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 7d4c1a4..9c8269b 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -409,7 +409,7 @@
if (phase == PageSpace::kAwaitingFinalization) {
CollectOldSpaceGarbage(thread, GCType::kMarkSweep, GCReason::kFinalize);
} else if (phase == PageSpace::kDone) {
- StartConcurrentMarking(thread);
+ StartConcurrentMarking(thread, GCReason::kIdle);
}
}
}
@@ -617,13 +617,23 @@
CollectNewSpaceGarbage(thread, GCReason::kFull);
}
- StartConcurrentMarking(thread);
+ StartConcurrentMarking(thread, reason);
}
}
-void Heap::StartConcurrentMarking(Thread* thread) {
+void Heap::StartConcurrentMarking(Thread* thread, GCReason reason) {
+ GcSafepointOperationScope safepoint_operation(thread);
+ RecordBeforeGC(GCType::kStartConcurrentMark, reason);
+ VMTagScope tagScope(thread, reason == GCReason::kIdle
+ ? VMTag::kGCIdleTagId
+ : VMTag::kGCOldSpaceTagId);
TIMELINE_FUNCTION_GC_DURATION(thread, "StartConcurrentMarking");
old_space_.CollectGarbage(/*compact=*/false, /*finalize=*/false);
+ RecordAfterGC(GCType::kStartConcurrentMark);
+ PrintStats();
+#if defined(SUPPORT_TIMELINE)
+ PrintStatsToTimeline(&tbes, reason);
+#endif
}
void Heap::CheckFinishConcurrentMarking(Thread* thread) {
@@ -852,6 +862,8 @@
switch (type) {
case GCType::kScavenge:
return "Scavenge";
+ case GCType::kStartConcurrentMark:
+ return "StartCMark";
case GCType::kMarkSweep:
return "MarkSweep";
case GCType::kMarkCompact:
@@ -1018,8 +1030,6 @@
stats_.before_.old_ = old_space_.GetCurrentUsage();
for (int i = 0; i < GCStats::kTimeEntries; i++)
stats_.times_[i] = 0;
- for (int i = 0; i < GCStats::kDataEntries; i++)
- stats_.data_[i] = 0;
}
static double AvgCollectionPeriod(int64_t run_time, intptr_t collections) {
@@ -1119,34 +1129,33 @@
if ((FLAG_verbose_gc_hdr != 0) &&
(((stats_.num_ - 1) % FLAG_verbose_gc_hdr) == 0)) {
OS::PrintErr(
- "[ | | | | "
+ "[ | | | | "
"| new gen | new gen | new gen "
"| old gen | old gen | old gen "
- "| sweep | safe- | roots/| stbuf/| tospc/| weaks/| ]\n"
- "[ GC isolate | space (reason) | GC# | start | time "
- "| used (kB) | capacity kB | external"
- "| used (kB) | capacity (kB) | external kB "
- "| thread| point |marking| reset | sweep |swplrge| data ]\n"
- "[ | | | (s) | (ms) "
+ "| sweep | safe- | roots/| stbuf/| tospc/| weaks/ ]\n"
+ "[ GC isolate | space (reason) | GC# | start | time "
+ "| used (MB) | capacity MB | external"
+ "| used (MB) | capacity (MB) | external MB "
+ "| thread| point |marking| reset | sweep |swplrge ]\n"
+ "[ | | | (s) | (ms) "
"|before| after|before| after| b4 |aftr"
"| before| after | before| after |before| after"
- "| (ms) | (ms) | (ms) | (ms) | (ms) | (ms) | ]\n");
+ "| (ms) | (ms) | (ms) | (ms) | (ms) | (ms) ]\n");
}
// clang-format off
OS::PrintErr(
- "[ %-13.13s, %10s(%9s), " // GC(isolate-group), type(reason)
+ "[ %-13.13s, %11s(%12s), " // GC(isolate-group), type(reason)
"%4" Pd ", " // count
"%6.2f, " // start time
"%5.1f, " // total time
- "%5" Pd ", %5" Pd ", " // new gen: in use before/after
- "%5" Pd ", %5" Pd ", " // new gen: capacity before/after
- "%3" Pd ", %3" Pd ", " // new gen: external before/after
- "%6" Pd ", %6" Pd ", " // old gen: in use before/after
- "%6" Pd ", %6" Pd ", " // old gen: capacity before/after
- "%5" Pd ", %5" Pd ", " // old gen: external before/after
+ "%5.1f, %5.1f, " // new gen: in use before/after
+ "%5.1f, %5.1f, " // new gen: capacity before/after
+ "%3.1f, %3.1f, " // new gen: external before/after
+ "%6.1f, %6.1f, " // old gen: in use before/after
+ "%6.1f, %6.1f, " // old gen: capacity before/after
+ "%5.1f, %5.1f, " // old gen: external before/after
"%6.2f, %6.2f, %6.2f, %6.2f, %6.2f, %6.2f, " // times
- "%" Pd ", %" Pd ", %" Pd ", %" Pd ", " // data
"]\n", // End with a comma to make it easier to import in spreadsheets.
isolate_group()->source()->name,
GCTypeToString(stats_.type_),
@@ -1155,28 +1164,24 @@
MicrosecondsToSeconds(isolate_group_->UptimeMicros()),
MicrosecondsToMilliseconds(stats_.after_.micros_ -
stats_.before_.micros_),
- RoundWordsToKB(stats_.before_.new_.used_in_words),
- RoundWordsToKB(stats_.after_.new_.used_in_words),
- RoundWordsToKB(stats_.before_.new_.capacity_in_words),
- RoundWordsToKB(stats_.after_.new_.capacity_in_words),
- RoundWordsToKB(stats_.before_.new_.external_in_words),
- RoundWordsToKB(stats_.after_.new_.external_in_words),
- RoundWordsToKB(stats_.before_.old_.used_in_words),
- RoundWordsToKB(stats_.after_.old_.used_in_words),
- RoundWordsToKB(stats_.before_.old_.capacity_in_words),
- RoundWordsToKB(stats_.after_.old_.capacity_in_words),
- RoundWordsToKB(stats_.before_.old_.external_in_words),
- RoundWordsToKB(stats_.after_.old_.external_in_words),
+ WordsToMB(stats_.before_.new_.used_in_words),
+ WordsToMB(stats_.after_.new_.used_in_words),
+ WordsToMB(stats_.before_.new_.capacity_in_words),
+ WordsToMB(stats_.after_.new_.capacity_in_words),
+ WordsToMB(stats_.before_.new_.external_in_words),
+ WordsToMB(stats_.after_.new_.external_in_words),
+ WordsToMB(stats_.before_.old_.used_in_words),
+ WordsToMB(stats_.after_.old_.used_in_words),
+ WordsToMB(stats_.before_.old_.capacity_in_words),
+ WordsToMB(stats_.after_.old_.capacity_in_words),
+ WordsToMB(stats_.before_.old_.external_in_words),
+ WordsToMB(stats_.after_.old_.external_in_words),
MicrosecondsToMilliseconds(stats_.times_[0]),
MicrosecondsToMilliseconds(stats_.times_[1]),
MicrosecondsToMilliseconds(stats_.times_[2]),
MicrosecondsToMilliseconds(stats_.times_[3]),
MicrosecondsToMilliseconds(stats_.times_[4]),
- MicrosecondsToMilliseconds(stats_.times_[5]),
- stats_.data_[0],
- stats_.data_[1],
- stats_.data_[2],
- stats_.data_[3]);
+ MicrosecondsToMilliseconds(stats_.times_[5]));
// clang-format on
#endif // !defined(PRODUCT)
}
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index a3973c1..04e8a62 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -126,7 +126,7 @@
void CollectAllGarbage(GCReason reason = GCReason::kFull);
void CheckStartConcurrentMarking(Thread* thread, GCReason reason);
- void StartConcurrentMarking(Thread* thread);
+ void StartConcurrentMarking(Thread* thread, GCReason reason);
void CheckFinishConcurrentMarking(Thread* thread);
void WaitForMarkerTasks(Thread* thread);
void WaitForSweeperTasks(Thread* thread);
@@ -261,11 +261,6 @@
stats_.times_[id] = micros;
}
- void RecordData(int id, intptr_t value) {
- ASSERT((id >= 0) && (id < GCStats::kDataEntries));
- stats_.data_[id] = value;
- }
-
void UpdateGlobalMaxUsed();
static bool IsAllocatableInNewSpace(intptr_t size) {
@@ -327,12 +322,10 @@
};
enum { kTimeEntries = 6 };
- enum { kDataEntries = 4 };
Data before_;
Data after_;
int64_t times_[kTimeEntries];
- intptr_t data_[kDataEntries];
private:
DISALLOW_COPY_AND_ASSIGN(GCStats);
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index db1541a..f17e8e6 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -1526,7 +1526,6 @@
ASSERT(end >= start);
history_.AddGarbageCollectionTime(start, end);
const int gc_time_fraction = history_.GarbageCollectionTimeFraction();
- heap_->RecordData(PageSpace::kGCTimeFraction, gc_time_fraction);
// Assume garbage increases linearly with allocation:
// G = kA, and estimate k from the previous cycle.
@@ -1544,7 +1543,6 @@
1.0, garbage / static_cast<double>(allocated_since_previous_gc));
const int garbage_ratio = static_cast<int>(k * 100);
- heap_->RecordData(PageSpace::kGarbageRatio, garbage_ratio);
// Define GC to be 'worthwhile' iff at least fraction t of heap is garbage.
double t = 1.0 - desired_utilization_;
@@ -1595,10 +1593,8 @@
}
}
} else {
- heap_->RecordData(PageSpace::kGarbageRatio, 100);
grow_heap = 0;
}
- heap_->RecordData(PageSpace::kPageGrowth, grow_heap);
last_usage_ = after;
intptr_t max_capacity_in_words = heap_->old_space()->max_capacity_in_words_;
@@ -1688,7 +1684,7 @@
}
#endif
- if (FLAG_log_growth) {
+ if (FLAG_log_growth || FLAG_verbose_gc) {
THR_Print("%s: threshold=%" Pd "kB, idle_threshold=%" Pd "kB, reason=%s\n",
heap_->isolate_group()->source()->name,
hard_gc_threshold_in_words_ / KBInWords,
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 8a91944..9d039e1 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -536,11 +536,6 @@
kResetFreeLists = 3,
kSweepPages = 4,
kSweepLargePages = 5,
- // Data
- kGarbageRatio = 0,
- kGCTimeFraction = 1,
- kPageGrowth = 2,
- kAllowedGrowth = 3
};
uword TryAllocateInternal(intptr_t size,
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 7cc5b8c..592627b 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -1148,13 +1148,10 @@
// Grab the deduplication sets out of the isolate's consolidated store buffer.
StoreBuffer* store_buffer = heap_->isolate_group()->store_buffer();
StoreBufferBlock* pending = blocks_;
- intptr_t total_count = 0;
while (pending != nullptr) {
StoreBufferBlock* next = pending->next();
// Generated code appends to store buffers; tell MemorySanitizer.
MSAN_UNPOISON(pending, sizeof(*pending));
- intptr_t count = pending->Count();
- total_count += count;
while (!pending->IsEmpty()) {
ObjectPtr raw_object = pending->Pop();
ASSERT(!raw_object->IsForwardingCorpse());
@@ -1172,10 +1169,6 @@
}
// Done iterating through old objects remembered in the store buffers.
visitor->VisitingOldObject(nullptr);
-
- heap_->RecordData(kStoreBufferEntries, total_count);
- heap_->RecordData(kDataUnused1, 0);
- heap_->RecordData(kDataUnused2, 0);
}
template <bool parallel>
diff --git a/runtime/vm/heap/scavenger.h b/runtime/vm/heap/scavenger.h
index f538f3a..ca75d9a 100644
--- a/runtime/vm/heap/scavenger.h
+++ b/runtime/vm/heap/scavenger.h
@@ -366,11 +366,6 @@
kIterateStoreBuffers = 3,
kProcessToSpace = 4,
kIterateWeaks = 5,
- // Data
- kStoreBufferEntries = 0,
- kDataUnused1 = 1,
- kDataUnused2 = 2,
- kToKBAfterStoreBuffer = 3
};
uword TryAllocateFromTLAB(Thread* thread, intptr_t size) {
diff --git a/runtime/vm/heap/spaces.h b/runtime/vm/heap/spaces.h
index 6b60e6c..f6827aa 100644
--- a/runtime/vm/heap/spaces.h
+++ b/runtime/vm/heap/spaces.h
@@ -31,6 +31,7 @@
enum class GCType {
kScavenge,
+ kStartConcurrentMark,
kMarkSweep,
kMarkCompact,
};
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 18a7bb6..11d116a 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -830,6 +830,11 @@
success = false;
}
+ Array& null_array = Array::Handle(Z);
+ // Invalidate the URI mapping caches.
+ IG->object_store()->set_uri_to_resolved_uri_map(null_array);
+ IG->object_store()->set_resolved_uri_to_uri_map(null_array);
+
// Re-queue any shutdown requests so they can inform each isolate's own thread
// to shut down.
if (result.IsUnwindError()) {
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index ebb2d60..3b308c6 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -143,6 +143,9 @@
RW(Library, _vmservice_library) \
RW(GrowableObjectArray, libraries) \
RW(Array, libraries_map) \
+ RW(Array, uri_to_resolved_uri_map) \
+ RW(Array, resolved_uri_to_uri_map) \
+ RW(Smi, last_libraries_count) \
RW(Array, loading_units) \
RW(GrowableObjectArray, closure_functions) \
RW(GrowableObjectArray, pending_classes) \
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index a0a5b9c..a75737e 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -4948,6 +4948,159 @@
Service::PrintJSONForVM(js, false);
}
+static intptr_t ParseJSONArray(Thread* thread,
+ const char* str,
+ const GrowableObjectArray& elements) {
+ ASSERT(str != nullptr);
+ ASSERT(thread != nullptr);
+ Zone* zone = thread->zone();
+ intptr_t n = strlen(str);
+ if (n < 2) {
+ return -1;
+ }
+ intptr_t start = 1;
+ while (start < n) {
+ intptr_t end = start;
+ while ((str[end + 1] != ',') && (str[end + 1] != ']')) {
+ end++;
+ }
+ if (end == start) {
+ // Empty element
+ break;
+ }
+ String& element = String::Handle(
+ zone, String::FromUTF8(reinterpret_cast<const uint8_t*>(&str[start]),
+ end - start + 1));
+ elements.Add(element);
+ start = end + 3;
+ }
+ return 0;
+}
+
+class UriMappingTraits {
+ public:
+ static const char* Name() { return "UriMappingTraits"; }
+ static bool ReportStats() { return false; }
+
+ static bool IsMatch(const Object& a, const Object& b) {
+ const String& a_str = String::Cast(a);
+ const String& b_str = String::Cast(b);
+
+ ASSERT(a_str.HasHash() && b_str.HasHash());
+ return a_str.Equals(b_str);
+ }
+
+ static uword Hash(const Object& key) { return String::Cast(key).Hash(); }
+
+ static ObjectPtr NewKey(const String& str) { return str.ptr(); }
+};
+
+typedef UnorderedHashMap<UriMappingTraits> UriMapping;
+
+static void PopulateUriMappings(Thread* thread) {
+ Zone* zone = thread->zone();
+ auto object_store = thread->isolate_group()->object_store();
+ UriMapping uri_to_resolved_uri(HashTables::New<UriMapping>(16, Heap::kOld));
+ UriMapping resolved_uri_to_uri(HashTables::New<UriMapping>(16, Heap::kOld));
+
+ const auto& libs =
+ GrowableObjectArray::Handle(zone, object_store->libraries());
+ intptr_t num_libs = libs.Length();
+
+ Library& lib = Library::Handle(zone);
+ Script& script = Script::Handle(zone);
+ Array& scripts = Array::Handle(zone);
+ String& uri = String::Handle(zone);
+ String& resolved_uri = String::Handle(zone);
+
+ for (intptr_t i = 0; i < num_libs; ++i) {
+ lib ^= libs.At(i);
+ scripts ^= lib.LoadedScripts();
+ intptr_t num_scripts = scripts.Length();
+ for (intptr_t j = 0; j < num_scripts; ++j) {
+ script ^= scripts.At(j);
+ uri ^= script.url();
+ resolved_uri ^= script.resolved_url();
+ uri_to_resolved_uri.UpdateOrInsert(uri, resolved_uri);
+ resolved_uri_to_uri.UpdateOrInsert(resolved_uri, uri);
+ }
+ }
+
+ object_store->set_uri_to_resolved_uri_map(uri_to_resolved_uri.Release());
+ object_store->set_resolved_uri_to_uri_map(resolved_uri_to_uri.Release());
+ Smi& count = Smi::Handle(zone, Smi::New(num_libs));
+ object_store->set_last_libraries_count(count);
+}
+
+static void LookupScriptUrisImpl(Thread* thread,
+ JSONStream* js,
+ bool lookup_resolved) {
+ Zone* zone = thread->zone();
+ auto object_store = thread->isolate_group()->object_store();
+
+ const auto& libs =
+ GrowableObjectArray::Handle(zone, object_store->libraries());
+ Smi& last_libraries_count =
+ Smi::Handle(zone, object_store->last_libraries_count());
+ if ((object_store->uri_to_resolved_uri_map() == Array::null()) ||
+ (object_store->resolved_uri_to_uri_map() == Array::null()) ||
+ (last_libraries_count.Value() != libs.Length())) {
+ PopulateUriMappings(thread);
+ }
+ const char* uris_arg = js->LookupParam("uris");
+ if (uris_arg == nullptr) {
+ PrintMissingParamError(js, "uris");
+ return;
+ }
+
+ const GrowableObjectArray& uris =
+ GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
+ intptr_t uris_length = ParseJSONArray(thread, uris_arg, uris);
+ if (uris_length < 0) {
+ PrintInvalidParamError(js, "uris");
+ return;
+ }
+
+ UriMapping map(lookup_resolved ? object_store->uri_to_resolved_uri_map()
+ : object_store->resolved_uri_to_uri_map());
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "UriList");
+
+ {
+ JSONArray uris_array(&jsobj, "uris");
+ String& uri = String::Handle(zone);
+ String& res = String::Handle(zone);
+ for (intptr_t i = 0; i < uris.Length(); ++i) {
+ uri ^= uris.At(i);
+ res ^= map.GetOrNull(uri);
+ if (res.IsNull()) {
+ uris_array.AddValueNull();
+ } else {
+ uris_array.AddValue(res.ToCString());
+ }
+ }
+ }
+ map.Release();
+}
+
+static const MethodParameter* const lookup_resolved_package_uris_params[] = {
+ ISOLATE_PARAMETER,
+ nullptr,
+};
+
+static void LookupResolvedPackageUris(Thread* thread, JSONStream* js) {
+ LookupScriptUrisImpl(thread, js, true);
+}
+
+static const MethodParameter* const lookup_package_uris_params[] = {
+ ISOLATE_PARAMETER,
+ nullptr,
+};
+
+static void LookupPackageUris(Thread* thread, JSONStream* js) {
+ LookupScriptUrisImpl(thread, js, false);
+}
+
static const char* const exception_pause_mode_names[] = {
"All",
"None",
@@ -5359,6 +5512,10 @@
get_reachable_size_params },
{ "_getRetainedSize", GetRetainedSize,
get_retained_size_params },
+ { "lookupResolvedPackageUris", LookupResolvedPackageUris,
+ lookup_resolved_package_uris_params },
+ { "lookupPackageUris", LookupPackageUris,
+ lookup_package_uris_params },
{ "getRetainingPath", GetRetainingPath,
get_retaining_path_params },
{ "getScripts", GetScripts,
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 6d32257..c3fe1f2 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -15,7 +15,7 @@
namespace dart {
#define SERVICE_PROTOCOL_MAJOR_VERSION 3
-#define SERVICE_PROTOCOL_MINOR_VERSION 51
+#define SERVICE_PROTOCOL_MINOR_VERSION 52
class Array;
class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index ad7d3bc..ba4add1 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.51
+# Dart VM Service Protocol 3.52
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.51_ of the Dart VM Service Protocol. This
+This document describes of _version 3.52_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@@ -62,6 +62,8 @@
- [getVMTimelineFlags](#getvmtimelineflags)
- [getVMTimelineMicros](#getvmtimelinemicros)
- [invoke](#invoke)
+ - [lookupResolvedPackageUris](#lookupresolvedpackageuris)
+ - [lookupPackageUris](#lookuppackageuris)
- [pause](#pause)
- [kill](#kill)
- [registerService](#registerService)
@@ -142,7 +144,8 @@
- [Timestamp](#timestamp)
- [TypeArguments](#typearguments)
- [TypeParameters](#typeparameters)[
- - [UresolvedSourceLocation](#unresolvedsourcelocation)
+ - [UnresolvedSourceLocation](#unresolvedsourcelocation)
+ - [UriList](#urilist)
- [Version](#version)
- [VM](#vm)
- [WebSocketTarget](#websockettarget)
@@ -1207,6 +1210,44 @@
See [Success](#success).
+### lookupResolvedPackageUris
+
+```
+UriList lookupResolvedPackageUris(string isolateId, string[] uris)
+```
+
+The _lookupResolvedPackageUris_ RPC is used to convert a list of URIs to their
+resolved (or absolute) paths. For example, URIs passed to this RPC are mapped in
+the following ways:
+
+- `dart:io` -> `org-dartlang-sdk:///sdk/lib/io/io.dart`
+- `package:test/test.dart` -> `file:///$PACKAGE_INSTALLATION_DIR/lib/test.dart`
+- `file:///foo/bar/bazz.dart` -> `file:///foo/bar/bazz.dart`
+
+If a URI is not known, the corresponding entry in the [UriList] response will be
+`null`.
+
+See [UriList](#urilist).
+
+### lookupPackageUris
+
+```
+UriList lookupPackageUris(string isolateId, string[] uris)
+```
+
+The _lookupPackageUris_ RPC is used to convert a list of URIs to their
+unresolved paths. For example, URIs passed to this RPC are mapped in the
+following ways:
+
+- `org-dartlang-sdk:///sdk/lib/io/io.dart` -> `dart:io`
+- `file:///$PACKAGE_INSTALLATION_DIR/lib/test.dart` -> `package:test/test.dart`
+- `file:///foo/bar/bazz.dart` -> `file:///foo/bar/bazz.dart`
+
+If a URI is not known, the corresponding entry in the [UriList] response will be
+`null`.
+
+See [UriList](#urilist).
+
### registerService
```
@@ -4057,6 +4098,15 @@
The _column_ field will only be present when the breakpoint was
specified with a specific column number.
+### UriList
+
+```
+class UriList extends Response {
+ // A list of URIs.
+ (string|Null)[] uris;
+}
+```
+
### Version
```
@@ -4184,5 +4234,5 @@
3.49 | Added `CpuSamples` event kind, and `cpuSamples` property to `Event`.
3.50 | Added `returnType`, `parameters`, and `typeParameters` to `@Instance`, and `implicit` to `@Function`. Added `Parameter` type.
3.51 | Added optional `reportLines` parameter to `getSourceReport` RPC.
-
+3.52 | Added `lookupResolvedPackageUris` and `lookupPackageUris` RPCs and `UriList` type.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/tests/language/constructor/reference_test.dart b/tests/language/constructor/reference_test.dart
index 6828160..06755d1 100644
--- a/tests/language/constructor/reference_test.dart
+++ b/tests/language/constructor/reference_test.dart
@@ -97,8 +97,7 @@
Foo.bar<int>.baz();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR
-// ^
-// [cfe] The method 'baz' isn't defined for the class 'Foo<int> Function()'.
+// [cfe] A constructor tear-off can't have type arguments after the constructor name.
Foo.bar.baz<int>();
// ^^^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_METHOD
diff --git a/tools/VERSION b/tools/VERSION
index c49f227..54f7e08 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 262
+PRERELEASE 263
PRERELEASE_PATCH 0
\ No newline at end of file