Version 2.15.0-261.0.dev
Merge commit 'ed0131bc7c149fe752743264463cb87c79d0c27b' into 'dev'
diff --git a/pkg/_js_interop_checks/pubspec.yaml b/pkg/_js_interop_checks/pubspec.yaml
index bae1992..53c668a 100644
--- a/pkg/_js_interop_checks/pubspec.yaml
+++ b/pkg/_js_interop_checks/pubspec.yaml
@@ -6,7 +6,10 @@
sdk: '>=2.12.0 <3.0.0'
dependencies:
- _fe_analyzer_shared:
- path: ../_fe_analyzer_shared
+ _fe_analyzer_shared: any
kernel:
path: ../kernel
+
+dependency_overrides:
+ _fe_analyzer_shared:
+ path: ../_fe_analyzer_shared
diff --git a/pkg/analysis_server/lib/src/cider/completion.dart b/pkg/analysis_server/lib/src/cider/completion.dart
index 5051a51..b9c27ec 100644
--- a/pkg/analysis_server/lib/src/cider/completion.dart
+++ b/pkg/analysis_server/lib/src/cider/completion.dart
@@ -70,7 +70,7 @@
var lineInfo = resolvedUnit.lineInfo;
var offset = lineInfo.getOffsetOfLine(line) + column;
- _dartCompletionRequest = DartCompletionRequest.from(
+ _dartCompletionRequest = DartCompletionRequest(
resolvedUnit: resolvedUnit,
offset: offset,
);
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index cfb6da5..4434ecc 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -33,6 +33,9 @@
/// 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;
@@ -66,11 +69,13 @@
/// [results]. Subclasses should override this method, append at least one
/// result to the [controller], and close the controller stream once complete.
Future<List<CompletionSuggestion>> computeSuggestions({
+ required CompletionBudget budget,
required OperationPerformanceImpl performance,
required DartCompletionRequest request,
Set<ElementKind>? includedElementKinds,
Set<String>? includedElementNames,
List<IncludedSuggestionRelevanceTag>? includedSuggestionRelevanceTags,
+ List<Uri>? librariesToImport,
}) async {
//
// Allow plugins to start computing fixes.
@@ -88,6 +93,7 @@
includedElementKinds: includedElementKinds,
includedElementNames: includedElementNames,
includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
+ librariesToImport: librariesToImport,
);
try {
@@ -106,7 +112,7 @@
//
if (requestToPlugins != null) {
await performance.runAsync('waitForPlugins', (_) async {
- await _addPluginSuggestions(requestToPlugins, suggestions);
+ await _addPluginSuggestions(budget, requestToPlugins, suggestions);
});
}
@@ -207,6 +213,8 @@
/// Implement the 'completion.getSuggestions2' request.
void getSuggestions2(Request request) async {
+ var budget = CompletionBudget(_budgetDuration);
+
var params = CompletionGetSuggestions2Params.fromRequest(request);
var file = params.file;
var offset = params.offset;
@@ -244,7 +252,7 @@
recordRequest(completionPerformance, file, resolvedUnit.content, offset);
await completionPerformance.runRequestOperation((performance) async {
- var completionRequest = DartCompletionRequest.from(
+ var completionRequest = DartCompletionRequest(
resolvedUnit: resolvedUnit,
offset: offset,
dartdocDirectiveInfo: server.getDartdocDirectiveInfoFor(
@@ -253,9 +261,12 @@
documentationCache: server.getDocumentationCacheFor(resolvedUnit),
);
+ var librariesToImport = <Uri>[];
var suggestions = await computeSuggestions(
+ budget: budget,
performance: performance,
request: completionRequest,
+ librariesToImport: librariesToImport,
);
performance.run('filter', (performance) {
@@ -276,7 +287,7 @@
completionRequest.replacementOffset,
completionRequest.replacementLength,
lengthRestricted,
- [], // TODO(scheglov)
+ librariesToImport.map((e) => '$e').toList(),
isIncomplete,
).toResponse(request.id),
);
@@ -326,6 +337,8 @@
/// Process a `completion.getSuggestions` request.
Future<void> processRequest(Request request) async {
+ var budget = CompletionBudget(_budgetDuration);
+
final performance = this.performance = CompletionPerformance();
await performance.runRequestOperation((perf) async {
@@ -392,7 +405,7 @@
return;
}
- var completionRequest = DartCompletionRequest.from(
+ var completionRequest = DartCompletionRequest(
resolvedUnit: resolvedUnit,
offset: offset,
dartdocDirectiveInfo: server.getDartdocDirectiveInfoFor(
@@ -423,6 +436,7 @@
// Compute suggestions in the background
try {
var suggestions = await computeSuggestions(
+ budget: budget,
performance: perf,
request: completionRequest,
includedElementKinds: includedElementKinds,
@@ -550,13 +564,15 @@
/// Add the completions produced by plugins to the server-generated list.
Future<void> _addPluginSuggestions(
+ CompletionBudget budget,
_RequestToPlugins requestToPlugins,
List<CompletionSuggestion> suggestions,
) async {
var responses = await waitForResponses(
requestToPlugins.futures,
requestParameters: requestToPlugins.parameters,
- timeout: 100,
+ // TODO(scheglov) pass Duration
+ timeout: budget.left.inMilliseconds,
);
for (var response in responses) {
var result = plugin.CompletionGetSuggestionsResult.fromResponse(response);
diff --git a/pkg/analysis_server/lib/src/domains/execution/completion.dart b/pkg/analysis_server/lib/src/domains/execution/completion.dart
index 1f20a26..c130a8a 100644
--- a/pkg/analysis_server/lib/src/domains/execution/completion.dart
+++ b/pkg/analysis_server/lib/src/domains/execution/completion.dart
@@ -69,7 +69,7 @@
return RuntimeCompletionResult([], []);
}
- var dartRequest = DartCompletionRequest.from(
+ var dartRequest = DartCompletionRequest(
resolvedUnit: targetResult,
offset: targetOffset,
);
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 0142b07..c853df6b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -208,7 +208,7 @@
server.performanceStats.completion.add(performance);
return await performance.runRequestOperation((perf) async {
- final completionRequest = DartCompletionRequest.from(
+ final completionRequest = DartCompletionRequest(
resolvedUnit: unit,
offset: offset,
dartdocDirectiveInfo: server.getDartdocDirectiveInfoFor(unit),
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 a26115a..77455f0 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
@@ -19,6 +19,7 @@
import 'package:analysis_server/src/services/completion/dart/local_library_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/local_reference_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/named_constructor_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/not_imported_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/override_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/redirecting_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/relevance_tables.g.dart';
@@ -44,6 +45,19 @@
import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
import 'package:analyzer_plugin/src/utilities/completion/optype.dart';
+/// Class that tracks how much time budget we have left.
+class CompletionBudget {
+ final Duration _budget;
+ final Stopwatch _timer = Stopwatch()..start();
+
+ CompletionBudget(this._budget);
+
+ Duration get left {
+ var result = _budget - _timer.elapsed;
+ return result.isNegative ? Duration.zero : result;
+ }
+}
+
/// [DartCompletionManager] determines if a completion request is Dart specific
/// and forwards those requests to all [DartCompletionContributor]s.
class DartCompletionManager {
@@ -67,16 +81,22 @@
/// suggestions, or `null` if no notification should occur.
final SuggestionListener? listener;
+ /// If specified, will be filled with URIs of libraries that are not yet
+ /// imported, but could be imported into the requested target. Corresponding
+ /// [CompletionSuggestion] will have the import index into this list.
+ final List<Uri>? librariesToImport;
+
/// Initialize a newly created completion manager. The parameters
/// [includedElementKinds], [includedElementNames], and
/// [includedSuggestionRelevanceTags] must either all be `null` or must all be
/// non-`null`.
- DartCompletionManager(
- {this.includedElementKinds,
- this.includedElementNames,
- this.includedSuggestionRelevanceTags,
- this.listener})
- : assert((includedElementKinds != null &&
+ DartCompletionManager({
+ this.includedElementKinds,
+ this.includedElementNames,
+ this.includedSuggestionRelevanceTags,
+ this.listener,
+ this.librariesToImport,
+ }) : assert((includedElementKinds != null &&
includedElementNames != null &&
includedSuggestionRelevanceTags != null) ||
(includedElementKinds == null &&
@@ -133,6 +153,13 @@
);
}
+ final librariesToImport = this.librariesToImport;
+ if (librariesToImport != null) {
+ contributors.add(
+ NotImportedContributor(request, builder, librariesToImport),
+ );
+ }
+
try {
for (var contributor in contributors) {
await performance.runAsync(
@@ -283,6 +310,47 @@
bool _aborted = false;
+ factory DartCompletionRequest({
+ required ResolvedUnitResult resolvedUnit,
+ required int offset,
+ DartdocDirectiveInfo? dartdocDirectiveInfo,
+ CompletionPreference completionPreference = CompletionPreference.insert,
+ DocumentationCache? documentationCache,
+ }) {
+ var target = CompletionTarget.forOffset(resolvedUnit.unit, offset);
+ var dotTarget = _dotTarget(target);
+
+ var featureComputer = FeatureComputer(
+ resolvedUnit.typeSystem,
+ resolvedUnit.typeProvider,
+ );
+
+ var contextType = featureComputer.computeContextType(
+ target.containingNode,
+ offset,
+ );
+
+ var opType = OpType.forCompletion(target, offset);
+ if (contextType != null && contextType.isVoid) {
+ opType.includeVoidReturnSuggestions = true;
+ }
+
+ return DartCompletionRequest._(
+ completionPreference: completionPreference,
+ contextType: contextType,
+ dartdocDirectiveInfo: dartdocDirectiveInfo ?? DartdocDirectiveInfo(),
+ documentationCache: documentationCache,
+ dotTarget: dotTarget,
+ featureComputer: featureComputer,
+ offset: offset,
+ opType: opType,
+ replacementRange: target.computeReplacementRange(offset),
+ result: resolvedUnit,
+ source: resolvedUnit.unit.declaredElement!.source,
+ target: target,
+ );
+ }
+
DartCompletionRequest._({
required this.completionPreference,
required this.contextType,
@@ -389,48 +457,6 @@
}
}
- /// Return a newly created completion request in [resolvedUnit] at [offset].
- static DartCompletionRequest from({
- required ResolvedUnitResult resolvedUnit,
- required int offset,
- DartdocDirectiveInfo? dartdocDirectiveInfo,
- CompletionPreference completionPreference = CompletionPreference.insert,
- DocumentationCache? documentationCache,
- }) {
- var target = CompletionTarget.forOffset(resolvedUnit.unit, offset);
- var dotTarget = _dotTarget(target);
-
- var featureComputer = FeatureComputer(
- resolvedUnit.typeSystem,
- resolvedUnit.typeProvider,
- );
-
- var contextType = featureComputer.computeContextType(
- target.containingNode,
- offset,
- );
-
- var opType = OpType.forCompletion(target, offset);
- if (contextType != null && contextType.isVoid) {
- opType.includeVoidReturnSuggestions = true;
- }
-
- return DartCompletionRequest._(
- completionPreference: completionPreference,
- contextType: contextType,
- dartdocDirectiveInfo: dartdocDirectiveInfo ?? DartdocDirectiveInfo(),
- documentationCache: documentationCache,
- dotTarget: dotTarget,
- featureComputer: featureComputer,
- offset: offset,
- opType: opType,
- replacementRange: target.computeReplacementRange(offset),
- result: resolvedUnit,
- source: resolvedUnit.unit.declaredElement!.source,
- target: target,
- );
- }
-
/// TODO(scheglov) Should this be a property of [CompletionTarget]?
static Expression? _dotTarget(CompletionTarget target) {
var node = target.containingNode;
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
new file mode 100644
index 0000000..e6415d0
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
@@ -0,0 +1,181 @@
+// 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 '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';
+import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart'
+ show SuggestionBuilder;
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/session.dart';
+import 'package:analyzer/src/dart/resolver/scope.dart';
+import 'package:analyzer/src/lint/pub.dart';
+import 'package:analyzer/src/workspace/pub.dart';
+import 'package:collection/collection.dart';
+
+/// A contributor of suggestions from not yet imported libraries.
+class NotImportedContributor extends DartCompletionContributor {
+ final List<Uri> librariesToImport;
+
+ NotImportedContributor(
+ DartCompletionRequest request,
+ SuggestionBuilder builder,
+ this.librariesToImport,
+ ) : super(request, builder);
+
+ @override
+ Future<void> computeSuggestions() async {
+ if (!request.includeIdentifiers) {
+ return;
+ }
+
+ var session = request.result.session as AnalysisSessionImpl;
+ var analysisDriver = session.getDriver(); // ignore: deprecated_member_use
+
+ var fsState = analysisDriver.fsState;
+ var filter = _buildFilter(fsState);
+
+ await analysisDriver.discoverAvailableFiles();
+
+ var knownFiles = fsState.knownFiles.toList();
+ for (var file in knownFiles) {
+ if (!filter.shouldInclude(file)) {
+ continue;
+ }
+
+ var elementResult = await session.getLibraryByUri(file.uriStr);
+ if (elementResult is! LibraryElementResult) {
+ continue;
+ }
+
+ var newSuggestions = builder.markSuggestions();
+
+ _buildSuggestions(
+ elementResult.element.exportNamespace,
+ );
+
+ newSuggestions.setLibraryUriToImportIndex(() {
+ librariesToImport.add(file.uri);
+ return librariesToImport.length - 1;
+ });
+ }
+ }
+
+ _Filter _buildFilter(FileSystemState fsState) {
+ var file = fsState.getFileForPath(request.result.path);
+ var workspacePackage = file.workspacePackage;
+ if (workspacePackage is PubWorkspacePackage) {
+ return _PubFilter(workspacePackage, file.path);
+ } else {
+ return _AnyFilter();
+ }
+ }
+
+ void _buildSuggestions(Namespace namespace) {
+ var visitor = LibraryElementSuggestionBuilder(request, builder);
+ for (var element in namespace.definedNames.values) {
+ element.accept(visitor);
+ }
+ }
+}
+
+class _AnyFilter implements _Filter {
+ @override
+ bool shouldInclude(FileState file) => true;
+}
+
+abstract class _Filter {
+ bool shouldInclude(FileState file);
+}
+
+class _PubFilter implements _Filter {
+ final PubWorkspacePackage targetPackage;
+ final String? targetPackageName;
+ final bool targetInLib;
+ final Set<String> dependencies;
+
+ factory _PubFilter(PubWorkspacePackage package, String path) {
+ var inLib = package.workspace.provider
+ .getFolder(package.root)
+ .getChildAssumingFolder('lib')
+ .contains(path);
+
+ var dependencies = <String>{};
+ var pubspec = package.pubspec;
+ if (pubspec != null) {
+ dependencies.addAll(pubspec.dependencies.names);
+ if (!inLib) {
+ dependencies.addAll(pubspec.devDependencies.names);
+ }
+ }
+
+ return _PubFilter._(
+ targetPackage: package,
+ targetPackageName: pubspec?.name?.value.text,
+ targetInLib: inLib,
+ dependencies: dependencies,
+ );
+ }
+
+ _PubFilter._({
+ required this.targetPackage,
+ required this.targetPackageName,
+ required this.targetInLib,
+ required this.dependencies,
+ });
+
+ @override
+ bool shouldInclude(FileState file) {
+ var uri = file.uri;
+ if (uri.isScheme('dart')) {
+ return true;
+ }
+
+ // Normally only package URIs are available.
+ // But outside of lib/ we allow any files of this package.
+ if (!uri.isScheme('package')) {
+ if (targetInLib) {
+ return false;
+ } else {
+ var filePackage = file.workspacePackage;
+ return filePackage is PubWorkspacePackage &&
+ filePackage.root == targetPackage.root;
+ }
+ }
+
+ // Sanity check.
+ var uriPathSegments = uri.pathSegments;
+ if (uriPathSegments.length < 2) {
+ return false;
+ }
+
+ // Any `package:` library from the same package.
+ var packageName = uriPathSegments[0];
+ if (packageName == targetPackageName) {
+ return true;
+ }
+
+ // If not the same package, must be public.
+ if (uriPathSegments[1] == 'src') {
+ return false;
+ }
+
+ return dependencies.contains(packageName);
+ }
+}
+
+extension on PSDependencyList? {
+ List<String> get names {
+ final self = this;
+ if (self == null) {
+ return const [];
+ } else {
+ return self
+ .map((dependency) => dependency.name?.text)
+ .whereNotNull()
+ .toList();
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index 8783ddd..06ce9e7 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -138,6 +138,54 @@
}
}
+class NewSuggestionsProcessor {
+ final SuggestionBuilder _builder;
+ final Set<protocol.CompletionSuggestion> _current = Set.identity();
+
+ NewSuggestionsProcessor._(this._builder) {
+ _current.addAll(_builder._suggestionMap.values);
+ }
+
+ /// Update suggestions added since this marker was created.
+ void setLibraryUriToImportIndex(int Function() produce) {
+ int? libraryUriToImportIndex;
+ var suggestionMap = _builder._suggestionMap;
+ for (var entry in suggestionMap.entries.toList()) {
+ var suggestion = entry.value;
+ if (!_current.contains(suggestion)) {
+ libraryUriToImportIndex ??= produce();
+ suggestionMap[entry.key] = protocol.CompletionSuggestion(
+ suggestion.kind,
+ suggestion.relevance,
+ suggestion.completion,
+ suggestion.selectionOffset,
+ suggestion.selectionLength,
+ suggestion.isDeprecated,
+ suggestion.isPotential,
+ displayText: suggestion.displayText,
+ replacementOffset: suggestion.replacementOffset,
+ replacementLength: suggestion.replacementLength,
+ docSummary: suggestion.docSummary,
+ docComplete: suggestion.docComplete,
+ declaringType: suggestion.declaringType,
+ defaultArgumentListString: suggestion.defaultArgumentListString,
+ defaultArgumentListTextRanges:
+ suggestion.defaultArgumentListTextRanges,
+ element: suggestion.element,
+ returnType: suggestion.returnType,
+ parameterNames: suggestion.parameterNames,
+ parameterTypes: suggestion.parameterTypes,
+ requiredParameterCount: suggestion.requiredParameterCount,
+ hasNamedParameters: suggestion.hasNamedParameters,
+ parameterName: suggestion.parameterName,
+ parameterType: suggestion.parameterType,
+ libraryUriToImportIndex: libraryUriToImportIndex,
+ );
+ }
+ }
+ }
+}
+
/// An object used to build a list of suggestions in response to a single
/// completion request.
class SuggestionBuilder {
@@ -216,6 +264,11 @@
bool get _isNonNullableByDefault =>
request.libraryElement.isNonNullableByDefault;
+ /// Return an object that knows which suggestions exist, and which are new.
+ NewSuggestionsProcessor markSuggestions() {
+ return NewSuggestionsProcessor._(this);
+ }
+
/// Add a suggestion for an [accessor] declared within a class or extension.
/// If the accessor is being invoked with a target of `super`, then the
/// [containingMemberName] should be the name of the member containing the
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index b0adedf..4536f8b 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -10,9 +10,11 @@
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
+import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
@@ -47,8 +49,12 @@
String get testPackageLibPath => '$testPackageRootPath/lib';
+ Folder get testPackageRoot => getFolder(testPackageRootPath);
+
String get testPackageRootPath => '$workspaceRootPath/test';
+ String get testPackageTestPath => '$testPackageRootPath/test';
+
String get workspaceRootPath => '/home';
Future<void> setRoots({
@@ -75,6 +81,8 @@
root: sdkRoot,
);
+ writeTestPackageConfig();
+
server = AnalysisServer(
serverChannel,
resourceProvider,
@@ -85,6 +93,441 @@
);
}
+ Future<void> test_notImported_pub_dependencies_inLib() async {
+ // TODO(scheglov) Switch to PubspecYamlFileConfig
+ newPubspecYamlFile(testPackageRootPath, r'''
+name: test
+dependencies:
+ aaa: any
+dev_dependencies:
+ bbb: any
+''');
+
+ var aaaRoot = getFolder('$workspaceRootPath/packages/aaa');
+ newFile('${aaaRoot.path}/lib/f.dart', content: '''
+class A01 {}
+''');
+ newFile('${aaaRoot.path}/lib/src/f.dart', content: '''
+class A02 {}
+''');
+
+ var bbbRoot = getFolder('$workspaceRootPath/packages/bbb');
+ newFile('${bbbRoot.path}/lib/f.dart', content: '''
+class A03 {}
+''');
+ newFile('${bbbRoot.path}/lib/src/f.dart', content: '''
+class A04 {}
+''');
+
+ writeTestPackageConfig(
+ config: PackageConfigFileBuilder()
+ ..add(name: 'aaa', rootPath: aaaRoot.path)
+ ..add(name: 'bbb', rootPath: bbbRoot.path),
+ );
+
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+void f() {
+ A0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(2)
+ ..assertLibrariesToImport(includes: [
+ 'package:aaa/f.dart',
+ ], excludes: [
+ 'dart:core',
+ 'package:bbb/f.dart',
+ 'package:test/test.dart',
+ ]);
+
+ var classes = responseValidator.suggestions.withElementClass();
+ classes.assertCompletions(['A01']);
+ classes.withCompletion('A01').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:aaa/f.dart');
+ }
+
+ Future<void> test_notImported_pub_dependencies_inTest() async {
+ // TODO(scheglov) Switch to PubspecYamlFileConfig
+ newPubspecYamlFile(testPackageRootPath, r'''
+name: test
+dependencies:
+ aaa: any
+dev_dependencies:
+ bbb: any
+''');
+
+ var aaaRoot = getFolder('$workspaceRootPath/packages/aaa');
+ newFile('${aaaRoot.path}/lib/f.dart', content: '''
+class A01 {}
+''');
+ newFile('${aaaRoot.path}/lib/src/f.dart', content: '''
+class A02 {}
+''');
+
+ var bbbRoot = getFolder('$workspaceRootPath/packages/bbb');
+ newFile('${bbbRoot.path}/lib/f.dart', content: '''
+class A03 {}
+''');
+ newFile('${bbbRoot.path}/lib/src/f.dart', content: '''
+class A04 {}
+''');
+
+ writeTestPackageConfig(
+ config: PackageConfigFileBuilder()
+ ..add(name: 'aaa', rootPath: aaaRoot.path)
+ ..add(name: 'bbb', rootPath: bbbRoot.path),
+ );
+
+ await _configureWithWorkspaceRoot();
+
+ var test_path = '$testPackageTestPath/test.dart';
+ var responseValidator = await _getCodeSuggestions(
+ path: test_path,
+ content: '''
+void f() {
+ A0^
+}
+''',
+ );
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(2)
+ ..assertLibrariesToImport(includes: [
+ 'package:aaa/f.dart',
+ 'package:bbb/f.dart',
+ ], excludes: [
+ 'dart:core',
+ 'package:test/test.dart',
+ ]);
+
+ var classes = responseValidator.suggestions.withElementClass();
+ classes.assertCompletions(['A01', 'A03']);
+ classes.withCompletion('A01').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:aaa/f.dart');
+ classes.withCompletion('A03').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:bbb/f.dart');
+ }
+
+ /// TODO(scheglov) Only lib/ libraries in lib/, no test/.
+ /// TODO(scheglov) Suggestions from available Pub packages.
+ Future<void> test_notImported_pub_this() async {
+ newFile('$testPackageLibPath/a.dart', content: '''
+class A01 {}
+''');
+
+ newFile('$testPackageLibPath/b.dart', content: '''
+class A02 {}
+''');
+
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+void f() {
+ A0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(2)
+ ..assertLibrariesToImport(includes: [
+ 'dart:async',
+ 'dart:math',
+ 'package:test/a.dart',
+ 'package:test/b.dart',
+ ], excludes: [
+ 'dart:core',
+ 'package:test/test.dart',
+ ]);
+
+ var classes = responseValidator.suggestions.withElementClass();
+ classes.assertCompletions(['A01', 'A02']);
+ classes.withCompletion('A01').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/a.dart');
+ classes.withCompletion('A02').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/b.dart');
+ }
+
+ Future<void> test_notImported_pub_this_hasImport() async {
+ newFile('$testPackageLibPath/a.dart', content: '''
+class A01 {}
+class A02 {}
+''');
+
+ newFile('$testPackageLibPath/b.dart', content: '''
+class A03 {}
+''');
+
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+import 'a.dart';
+
+void f() {
+ A0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(2)
+ ..assertLibrariesToImport(includes: [
+ 'dart:async',
+ 'dart:math',
+ 'package:test/b.dart',
+ ], excludes: [
+ 'dart:core',
+ 'package:test/a.dart',
+ 'package:test/test.dart',
+ ]);
+
+ var classes = responseValidator.suggestions.withElementClass();
+ classes.assertCompletions(['A01', 'A02', 'A03']);
+ classes.withCompletion('A01').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport(isNull);
+ classes.withCompletion('A02').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport(isNull);
+ classes.withCompletion('A03').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/b.dart');
+ }
+
+ Future<void> test_notImported_pub_this_hasImport_hasShow() async {
+ newFile('$testPackageLibPath/a.dart', content: '''
+class A01 {}
+class A02 {}
+''');
+
+ newFile('$testPackageLibPath/b.dart', content: '''
+class A03 {}
+''');
+
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+import 'a.dart' show A01;
+
+void f() {
+ A0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(2)
+ ..assertLibrariesToImport(includes: [
+ 'dart:async',
+ 'dart:math',
+ 'package:test/a.dart',
+ 'package:test/b.dart',
+ ], excludes: [
+ 'dart:core',
+ 'package:test/test.dart',
+ ]);
+
+ var classes = responseValidator.suggestions.withElementClass();
+ classes.assertCompletions(['A01', 'A02', 'A03']);
+ classes.withCompletion('A01').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport(isNull);
+ classes.withCompletion('A02').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/a.dart');
+ classes.withCompletion('A03').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/b.dart');
+ }
+
+ Future<void> test_notImported_pub_this_inLib_excludesTest() async {
+ // TODO(scheglov) Switch to PubspecYamlFileConfig
+ newPubspecYamlFile(testPackageRootPath, r'''
+name: test
+''');
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+class A01 {}
+''');
+
+ var b = newFile('$testPackageTestPath/b.dart', content: '''
+class A02 {}
+''');
+
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+void f() {
+ A0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(2)
+ ..assertLibrariesToImport(includes: [
+ 'package:test/a.dart',
+ ], excludes: [
+ 'dart:core',
+ 'package:test/test.dart',
+ toUriStr(b.path),
+ ]);
+
+ var classes = responseValidator.suggestions.withElementClass();
+ classes.assertCompletions(['A01']);
+ classes.withCompletion('A01').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/a.dart');
+ }
+
+ Future<void> test_notImported_pub_this_inLib_includesThisSrc() async {
+ // TODO(scheglov) Switch to PubspecYamlFileConfig
+ newPubspecYamlFile(testPackageRootPath, r'''
+name: test
+''');
+
+ newFile('$testPackageLibPath/f.dart', content: '''
+class A01 {}
+''');
+
+ newFile('$testPackageLibPath/src/f.dart', content: '''
+class A02 {}
+''');
+
+ await _configureWithWorkspaceRoot();
+
+ var responseValidator = await _getTestCodeSuggestions('''
+void f() {
+ A0^
+}
+''');
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(2)
+ ..assertLibrariesToImport(includes: [
+ 'package:test/f.dart',
+ 'package:test/src/f.dart',
+ ], excludes: [
+ 'dart:core',
+ 'package:test/test.dart',
+ ]);
+
+ var classes = responseValidator.suggestions.withElementClass();
+ classes.assertCompletions(['A01', 'A02']);
+ classes.withCompletion('A01').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/f.dart');
+ classes.withCompletion('A02').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/src/f.dart');
+ }
+
+ Future<void> test_notImported_pub_this_inTest_includesTest() async {
+ // TODO(scheglov) Switch to PubspecYamlFileConfig
+ newPubspecYamlFile(testPackageRootPath, r'''
+name: test
+''');
+
+ newFile('$testPackageLibPath/a.dart', content: '''
+class A01 {}
+''');
+
+ var b = newFile('$testPackageTestPath/b.dart', content: '''
+class A02 {}
+''');
+ var b_uriStr = toUriStr(b.path);
+
+ await _configureWithWorkspaceRoot();
+
+ var test_path = '$testPackageTestPath/test.dart';
+ var responseValidator = await _getCodeSuggestions(
+ path: test_path,
+ content: '''
+void f() {
+ A0^
+}
+''',
+ );
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(2)
+ ..assertLibrariesToImport(includes: [
+ 'package:test/a.dart',
+ b_uriStr,
+ ], excludes: [
+ 'dart:core',
+ toUriStr(test_path),
+ ]);
+
+ var classes = responseValidator.suggestions.withElementClass();
+ classes.assertCompletions(['A01', 'A02']);
+ classes.withCompletion('A01').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/a.dart');
+ classes.withCompletion('A02').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport(b_uriStr);
+ }
+
+ Future<void> test_notImported_pub_this_inTest_includesThisSrc() async {
+ // TODO(scheglov) Switch to PubspecYamlFileConfig
+ newPubspecYamlFile(testPackageRootPath, r'''
+name: test
+''');
+
+ newFile('$testPackageLibPath/f.dart', content: '''
+class A01 {}
+''');
+
+ newFile('$testPackageLibPath/src/f.dart', content: '''
+class A02 {}
+''');
+
+ await _configureWithWorkspaceRoot();
+
+ var test_path = '$testPackageTestPath/test.dart';
+ var responseValidator = await _getCodeSuggestions(
+ path: test_path,
+ content: '''
+void f() {
+ A0^
+}
+''',
+ );
+
+ responseValidator
+ ..assertComplete()
+ ..assertReplacementBack(2)
+ ..assertLibrariesToImport(includes: [
+ 'package:test/f.dart',
+ 'package:test/src/f.dart',
+ ], excludes: [
+ 'dart:core',
+ 'package:test/test.dart',
+ ]);
+
+ var classes = responseValidator.suggestions.withElementClass();
+ classes.assertCompletions(['A01', 'A02']);
+ classes.withCompletion('A01').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/f.dart');
+ classes.withCompletion('A02').assertSingle()
+ ..assertClass()
+ ..assertLibraryToImport('package:test/src/f.dart');
+ }
+
Future<void> test_numResults_class_methods() async {
await _configureWithWorkspaceRoot();
@@ -464,11 +907,59 @@
suggestionsValidator.assertCompletions(['foo02', 'foo01']);
}
+ void writePackageConfig(Folder root, PackageConfigFileBuilder config) {
+ newPackageConfigJsonFile(
+ root.path,
+ content: config.toContent(toUriStr: toUriStr),
+ );
+ }
+
+ void writeTestPackageConfig({
+ PackageConfigFileBuilder? config,
+ String? languageVersion,
+ }) {
+ if (config == null) {
+ config = PackageConfigFileBuilder();
+ } else {
+ config = config.copy();
+ }
+
+ config.add(
+ name: 'test',
+ rootPath: testPackageRootPath,
+ languageVersion: languageVersion,
+ );
+
+ writePackageConfig(testPackageRoot, config);
+ }
+
Future<void> _configureWithWorkspaceRoot() async {
await setRoots(included: [workspaceRootPath], excluded: []);
await server.onAnalysisComplete;
}
+ Future<CompletionGetSuggestions2ResponseValidator> _getCodeSuggestions({
+ required String path,
+ required String content,
+ int maxResults = 1 << 10,
+ }) async {
+ var completionOffset = content.indexOf('^');
+ expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
+
+ var nextOffset = content.indexOf('^', completionOffset + 1);
+ expect(nextOffset, equals(-1), reason: 'too many ^');
+
+ newFile(path,
+ content: content.substring(0, completionOffset) +
+ content.substring(completionOffset + 1));
+
+ return await _getSuggestions(
+ path: path,
+ completionOffset: completionOffset,
+ maxResults: maxResults,
+ );
+ }
+
Future<CompletionGetSuggestions2ResponseValidator> _getSuggestions({
required String path,
required int completionOffset,
@@ -489,19 +980,9 @@
String content, {
int maxResults = 1 << 10,
}) async {
- var completionOffset = content.indexOf('^');
- expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
-
- var nextOffset = content.indexOf('^', completionOffset + 1);
- expect(nextOffset, equals(-1), reason: 'too many ^');
-
- var testFile = newFile(testFilePath,
- content: content.substring(0, completionOffset) +
- content.substring(completionOffset + 1));
-
- return await _getSuggestions(
- path: testFile.path,
- completionOffset: completionOffset,
+ return _getCodeSuggestions(
+ path: testFilePath,
+ content: content,
maxResults: maxResults,
);
}
@@ -1413,7 +1894,10 @@
);
SuggestionsValidator get suggestions {
- return SuggestionsValidator(result.suggestions);
+ return SuggestionsValidator(
+ result.suggestions,
+ libraryUrisToImport: result.libraryUrisToImport,
+ );
}
void assertComplete() {
@@ -1428,6 +1912,18 @@
expect(result.isIncomplete, isTrue);
}
+ void assertLibrariesToImport({
+ required List<String> includes,
+ List<String>? excludes,
+ }) {
+ expect(result.libraryUrisToImport, containsAll(includes));
+ if (excludes != null) {
+ for (var exclude in excludes) {
+ expect(result.libraryUrisToImport, isNot(contains(exclude)));
+ }
+ }
+ }
+
void assertReplacement(int offset, int length) {
expect(result.replacementOffset, offset);
expect(result.replacementLength, length);
@@ -1440,8 +1936,12 @@
class SingleSuggestionValidator {
final CompletionSuggestion suggestion;
+ final List<String>? libraryUrisToImport;
- SingleSuggestionValidator(this.suggestion);
+ SingleSuggestionValidator(
+ this.suggestion, {
+ this.libraryUrisToImport,
+ });
void assertClass() {
expect(suggestion.kind, CompletionSuggestionKind.INVOCATION);
@@ -1458,6 +1958,15 @@
expect(suggestion.element?.kind, ElementKind.GETTER);
}
+ void assertLibraryToImport(Object matcher) {
+ final libraryUrisToImport = this.libraryUrisToImport;
+ final index = suggestion.libraryUriToImportIndex;
+ var libraryUri = libraryUrisToImport != null && index != null
+ ? libraryUrisToImport[index]
+ : null;
+ expect(libraryUri, matcher);
+ }
+
void assertMethod() {
expect(suggestion.kind, CompletionSuggestionKind.INVOCATION);
expect(suggestion.element?.kind, ElementKind.METHOD);
@@ -1471,8 +1980,12 @@
class SuggestionsValidator {
final List<CompletionSuggestion> suggestions;
+ final List<String>? libraryUrisToImport;
- SuggestionsValidator(this.suggestions);
+ SuggestionsValidator(
+ this.suggestions, {
+ this.libraryUrisToImport,
+ });
int get length => suggestions.length;
@@ -1495,7 +2008,10 @@
SingleSuggestionValidator assertSingle() {
assertLength(1);
- return SingleSuggestionValidator(suggestions.single);
+ return SingleSuggestionValidator(
+ suggestions.single,
+ libraryUrisToImport: libraryUrisToImport,
+ );
}
SuggestionsValidator withCompletion(String completion) {
@@ -1503,6 +2019,7 @@
suggestions.where((suggestion) {
return suggestion.completion == completion;
}).toList(),
+ libraryUrisToImport: libraryUrisToImport,
);
}
@@ -1519,6 +2036,7 @@
suggestions.where((suggestion) {
return suggestion.element?.kind == kind;
}).toList(),
+ libraryUrisToImport: libraryUrisToImport,
);
}
}
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
index b1d9045..4926490 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -533,7 +533,7 @@
return await CompletionPerformance().runRequestOperation(
(performance) async {
// Build the request
- var request = DartCompletionRequest.from(
+ var request = DartCompletionRequest(
resolvedUnit: result,
offset: completionOffset,
dartdocDirectiveInfo: dartdocInfo,
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart b/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
index 882d459..972198c 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
@@ -52,7 +52,7 @@
// Build the request
var resolvedUnit =
await session.getResolvedUnit(testFile) as ResolvedUnitResult;
- request = DartCompletionRequest.from(
+ request = DartCompletionRequest(
resolvedUnit: resolvedUnit,
offset: completionOffset,
);
diff --git a/pkg/analysis_server/test/src/services/completion/dart/suggestion_builder_test.dart b/pkg/analysis_server/test/src/services/completion/dart/suggestion_builder_test.dart
index 009797d..8c8bc43 100644
--- a/pkg/analysis_server/test/src/services/completion/dart/suggestion_builder_test.dart
+++ b/pkg/analysis_server/test/src/services/completion/dart/suggestion_builder_test.dart
@@ -27,7 +27,7 @@
}
Future<CompletionSuggestion> forTopLevelFunction(String functionName) async {
- var request = DartCompletionRequest.from(
+ var request = DartCompletionRequest(
resolvedUnit: testAnalysisResult,
offset: 0,
);
diff --git a/pkg/analysis_server/test/stress/completion/completion_runner.dart b/pkg/analysis_server/test/stress/completion/completion_runner.dart
index 25770fe..f54299e 100644
--- a/pkg/analysis_server/test/stress/completion/completion_runner.dart
+++ b/pkg/analysis_server/test/stress/completion/completion_runner.dart
@@ -98,7 +98,7 @@
}
timer.start();
- var dartRequest = DartCompletionRequest.from(
+ var dartRequest = DartCompletionRequest(
resolvedUnit: result,
offset: offset,
);
diff --git a/pkg/analysis_server/tool/code_completion/completion_metrics.dart b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
index fe1e019..7284e5d 100644
--- a/pkg/analysis_server/tool/code_completion/completion_metrics.dart
+++ b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
@@ -1366,7 +1366,7 @@
{required MetricsSuggestionListener listener,
required CompletionMetrics metrics}) async {
var stopwatch = Stopwatch()..start();
- var request = DartCompletionRequest.from(
+ var request = DartCompletionRequest(
resolvedUnit: resolvedUnitResult,
offset: expectedCompletion.offset,
documentationCache: documentationCache,
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index e146cf2..468934b 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -682,27 +682,37 @@
if (functionResult == null) {
return functionResult;
}
+
+ // Report an error if any of the _inferred_ type argument types refer to a
+ // type parameter. If, however, `node.typeArguments` is not `null`, then
+ // any type parameters contained therein are reported as non-constant in
+ // [ConstantVerifier].
+ if (node.typeArguments == null &&
+ (node.typeArgumentTypes?.any(hasTypeParameterReference) ?? false)) {
+ _error(node, null);
+ }
+
var typeArgumentList = node.typeArguments;
if (typeArgumentList == null) {
- return functionResult;
- } else {
- var typeArguments = <DartType>[];
- for (var typeArgument in typeArgumentList.arguments) {
- var object = typeArgument.accept(this);
- if (object == null) {
- return null;
- }
- var typeArgumentType = object.toTypeValue();
- if (typeArgumentType == null) {
- return null;
- }
- // TODO(srawlins): Test type alias types (`typedef i = int`) used as
- // type arguments. Possibly change implementation based on
- // canonicalization rules.
- typeArguments.add(typeArgumentType);
- }
- return _dartObjectComputer.typeInstantiate(functionResult, typeArguments);
+ return _instantiateFunctionType(node, functionResult);
}
+
+ var typeArguments = <DartType>[];
+ for (var typeArgument in typeArgumentList.arguments) {
+ var object = typeArgument.accept(this);
+ if (object == null) {
+ return null;
+ }
+ var typeArgumentType = object.toTypeValue();
+ if (typeArgumentType == null) {
+ return null;
+ }
+ // TODO(srawlins): Test type alias types (`typedef i = int`) used as
+ // type arguments. Possibly change implementation based on
+ // canonicalization rules.
+ typeArguments.add(typeArgumentType);
+ }
+ return _dartObjectComputer.typeInstantiate(functionResult, typeArguments);
}
@override
@@ -1000,7 +1010,7 @@
DartObjectImpl? visitSimpleIdentifier(SimpleIdentifier node) {
var value = _lexicalEnvironment?[node.name];
if (value != null) {
- return _instantiateFunctionType(node, value);
+ return _instantiateFunctionTypeForSimpleIdentifier(node, value);
}
return _getConstantValue(node, node);
@@ -1212,6 +1222,8 @@
var variableElement =
element is PropertyAccessorElement ? element.variable : element;
+ // TODO(srawlins): Remove this check when [FunctionReference]s are inserted
+ // for generic function instantiation for pre-constructor-references code.
if (node is SimpleIdentifier &&
(node.tearOffTypeArgumentTypes?.any(hasTypeParameterReference) ??
false)) {
@@ -1230,7 +1242,7 @@
if (value == null) {
return value;
}
- return _instantiateFunctionType(identifier, value);
+ return _instantiateFunctionTypeForSimpleIdentifier(identifier, value);
}
} else if (variableElement is ConstructorElement) {
return DartObjectImpl(
@@ -1246,7 +1258,7 @@
function.type,
FunctionState(function),
);
- return _instantiateFunctionType(identifier, rawType);
+ return _instantiateFunctionTypeForSimpleIdentifier(identifier, rawType);
}
} else if (variableElement is ClassElement) {
var type = variableElement.instantiate(
@@ -1305,12 +1317,41 @@
return null;
}
+ /// If the type of [value] is a generic [FunctionType], and [node] has type
+ /// argument types, returns [value] type-instantiated with those [node]'s
+ /// type argument types, otherwise returns [value].
+ DartObjectImpl? _instantiateFunctionType(
+ FunctionReference node, DartObjectImpl value) {
+ var functionElement = value.toFunctionValue();
+ if (functionElement is! ExecutableElement) {
+ return value;
+ }
+ var valueType = functionElement.type;
+ if (valueType.typeFormals.isNotEmpty) {
+ var typeArgumentTypes = node.typeArgumentTypes;
+ if (typeArgumentTypes != null && typeArgumentTypes.isNotEmpty) {
+ var instantiatedType =
+ functionElement.type.instantiate(typeArgumentTypes);
+ var substitution = _substitution;
+ if (substitution != null) {
+ instantiatedType =
+ substitution.substituteType(instantiatedType) as FunctionType;
+ }
+ return value.typeInstantiate(
+ typeSystem, instantiatedType, typeArgumentTypes);
+ }
+ }
+ return value;
+ }
+
/// If the type of [value] is a generic [FunctionType], and [node] is a
/// [SimpleIdentifier] with tear-off type argument types, returns [value]
/// type-instantiated with those [node]'s tear-off type argument types,
/// otherwise returns [value].
- DartObjectImpl? _instantiateFunctionType(
+ DartObjectImpl? _instantiateFunctionTypeForSimpleIdentifier(
SimpleIdentifier node, DartObjectImpl value) {
+ // TODO(srawlins): When all code uses [FunctionReference]s generated via
+ // generic function instantiation, remove this method and all call sites.
var functionElement = value.toFunctionValue();
if (functionElement is! ExecutableElement) {
return value;
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 1678bf8..549136f 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4188,12 +4188,17 @@
/// this variable is not a subject of type inference, or there was no error.
TopLevelInferenceError? typeInferenceError;
+ /// If this method is a synthetic element which is based on another method
+ /// with some modifications (such as making some parameters covariant),
+ /// this field contains the base method.
+ MethodElement? prototype;
+
/// Initialize a newly created method element to have the given [name] at the
/// given [offset].
MethodElementImpl(String name, int offset) : super(name, offset);
@override
- MethodElement get declaration => this;
+ MethodElement get declaration => prototype ?? this;
@override
String get displayName {
@@ -4988,6 +4993,11 @@
@override
late PropertyInducingElement variable;
+ /// If this method is a synthetic element which is based on another method
+ /// with some modifications (such as making some parameters covariant),
+ /// this field contains the base method.
+ PropertyAccessorElement? prototype;
+
/// Initialize a newly created property accessor element to have the given
/// [name] and [offset].
PropertyAccessorElementImpl(String name, int offset) : super(name, offset);
@@ -5020,7 +5030,7 @@
}
@override
- PropertyAccessorElement get declaration => this;
+ PropertyAccessorElement get declaration => prototype ?? this;
@override
String get identifier {
diff --git a/pkg/analyzer/lib/src/dart/element/extensions.dart b/pkg/analyzer/lib/src/dart/element/extensions.dart
index 2b9767d..6eaa94a 100644
--- a/pkg/analyzer/lib/src/dart/element/extensions.dart
+++ b/pkg/analyzer/lib/src/dart/element/extensions.dart
@@ -53,12 +53,16 @@
extension ParameterElementExtensions on ParameterElement {
/// Return [ParameterElement] with the specified properties replaced.
- ParameterElement copyWith({DartType? type, ParameterKind? kind}) {
+ ParameterElement copyWith({
+ DartType? type,
+ ParameterKind? kind,
+ bool? isCovariant,
+ }) {
return ParameterElementImpl.synthetic(
name,
type ?? this.type,
// ignore: deprecated_member_use_from_same_package
kind ?? parameterKind,
- )..isExplicitlyCovariant = isCovariant;
+ )..isExplicitlyCovariant = isCovariant ?? this.isCovariant;
}
}
diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
index b19d846..cf52a23 100644
--- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -5,6 +5,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/extensions.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
@@ -626,6 +627,11 @@
}
}
+ implemented = implemented.map<Name, ExecutableElement>((key, value) {
+ var result = _inheritCovariance(element, namedCandidates, key, value);
+ return MapEntry(key, result);
+ });
+
return Interface._(
interface,
declared,
@@ -697,6 +703,102 @@
);
}
+ /// If a candidate from [namedCandidates] has covariant parameters, return
+ /// a copy of the [executable] with the corresponding parameters marked
+ /// covariant. If there are no covariant parameters, or parameters to
+ /// update are already covariant, return the [executable] itself.
+ ExecutableElement _inheritCovariance(
+ ClassElement class_,
+ Map<Name, List<ExecutableElement>> namedCandidates,
+ Name name,
+ ExecutableElement executable,
+ ) {
+ if (executable.enclosingElement == class_) {
+ return executable;
+ }
+
+ var parameters = executable.parameters;
+ if (parameters.isEmpty) {
+ return executable;
+ }
+
+ var candidates = namedCandidates[name];
+ if (candidates == null) {
+ return executable;
+ }
+
+ // Find parameters that are covariant (by declaration) in any overridden.
+ Set<_ParameterDesc>? covariantParameters;
+ for (var candidate in candidates) {
+ var parameters = candidate.parameters;
+ for (var i = 0; i < parameters.length; i++) {
+ var parameter = parameters[i];
+ if (parameter.isCovariant) {
+ covariantParameters ??= {};
+ covariantParameters.add(
+ _ParameterDesc(i, parameter),
+ );
+ }
+ }
+ }
+
+ if (covariantParameters == null) {
+ return executable;
+ }
+
+ // Update covariance of the parameters of the chosen executable.
+ List<ParameterElement>? transformedParameters;
+ for (var index = 0; index < parameters.length; index++) {
+ var parameter = parameters[index];
+ var shouldBeCovariant = covariantParameters.contains(
+ _ParameterDesc(index, parameter),
+ );
+ if (parameter.isCovariant != shouldBeCovariant) {
+ transformedParameters ??= parameters.toList();
+ transformedParameters[index] = parameter.copyWith(
+ isCovariant: shouldBeCovariant,
+ );
+ }
+ }
+
+ if (transformedParameters == null) {
+ return executable;
+ }
+
+ if (executable is MethodElement) {
+ var result = MethodElementImpl(executable.name, -1);
+ result.enclosingElement = class_;
+ result.isSynthetic = true;
+ result.parameters = transformedParameters;
+ result.prototype = executable;
+ result.returnType = executable.returnType;
+ result.typeParameters = executable.typeParameters;
+ return result;
+ }
+
+ if (executable is PropertyAccessorElement) {
+ assert(executable.isSetter);
+ var result = PropertyAccessorElementImpl(executable.name, -1);
+ result.enclosingElement = class_;
+ result.isSynthetic = true;
+ result.parameters = transformedParameters;
+ result.prototype = executable;
+ result.returnType = executable.returnType;
+
+ var field = executable.variable;
+ var resultField = FieldElementImpl(field.name, -1);
+ resultField.enclosingElement = class_;
+ resultField.getter = field.getter;
+ resultField.setter = executable;
+ resultField.type = executable.parameters[0].type;
+ result.variable = resultField;
+
+ return result;
+ }
+
+ return executable;
+ }
+
/// Given one or more [validOverrides], merge them into a single resulting
/// signature. This signature always exists.
ExecutableElement _topMerge(
@@ -907,3 +1009,34 @@
@override
String toString() => libraryUri != null ? '$libraryUri::$name' : name;
}
+
+class _ParameterDesc {
+ final int? index;
+ final String? name;
+
+ factory _ParameterDesc(int index, ParameterElement element) {
+ return element.isNamed
+ ? _ParameterDesc.name(element.name)
+ : _ParameterDesc.index(index);
+ }
+
+ _ParameterDesc.index(int index)
+ : index = index,
+ name = null;
+
+ _ParameterDesc.name(String name)
+ : index = null,
+ name = name;
+
+ @override
+ int get hashCode {
+ return index?.hashCode ?? name?.hashCode ?? 0;
+ }
+
+ @override
+ bool operator ==(other) {
+ return other is _ParameterDesc &&
+ other.index == index &&
+ other.name == name;
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
index 6257b73..da8742a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
@@ -242,15 +242,21 @@
if (node.function is ConstructorReference) {
node.staticType = DynamicTypeImpl.instance;
} else {
- var typeArguments = _checkTypeArguments(
- // `node.typeArguments`, coming from the parser, is never null.
- node.typeArguments!, name, rawType.typeFormals,
- CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_FUNCTION,
- );
+ var typeArguments = node.typeArguments;
+ if (typeArguments == null) {
+ node.staticType = rawType;
+ } else {
+ var typeArgumentTypes = _checkTypeArguments(
+ typeArguments,
+ name,
+ rawType.typeFormals,
+ CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_FUNCTION,
+ );
- var invokeType = rawType.instantiate(typeArguments);
- node.typeArgumentTypes = typeArguments;
- node.staticType = invokeType;
+ var invokeType = rawType.instantiate(typeArgumentTypes);
+ node.typeArgumentTypes = typeArgumentTypes;
+ node.staticType = invokeType;
+ }
}
} else {
if (_resolver.isConstructorTearoffsEnabled) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart
index 14d554a..eb97c1f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart
@@ -83,8 +83,15 @@
type = result.functionTypeCallType!;
}
- type = _inferenceHelper.inferTearOff(node, identifier, type);
-
+ if (!_resolver.isConstructorTearoffsEnabled) {
+ // Only perform a generic function instantiation on a [PrefixedIdentifier]
+ // in pre-constructor-tearoffs code. In constructor-tearoffs-enabled code,
+ // generic function instantiation is performed at assignability check
+ // sites.
+ // TODO(srawlins): Switch all resolution to use the latter method, in a
+ // breaking change release.
+ type = _inferenceHelper.inferTearOff(node, identifier, type);
+ }
_recordStaticType(identifier, type);
_recordStaticType(node, type);
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart
index bb564f7..1f9befa 100644
--- a/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart
@@ -12,7 +12,6 @@
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
-import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -25,8 +24,6 @@
ErrorReporter get _errorReporter => _resolver.errorReporter;
- InvocationInferenceHelper get _inferenceHelper => _resolver.inferenceHelper;
-
TypeProviderImpl get _typeProvider => _resolver.typeProvider;
void resolve(SimpleIdentifierImpl node) {
@@ -259,7 +256,17 @@
} else {
staticType = DynamicTypeImpl.instance;
}
- staticType = _inferenceHelper.inferTearOff(node, node, staticType);
+
+ if (!_resolver.isConstructorTearoffsEnabled) {
+ // Only perform a generic function instantiation on a [PrefixedIdentifier]
+ // in pre-constructor-tearoffs code. In constructor-tearoffs-enabled code,
+ // generic function instantiation is performed at assignability check
+ // sites.
+ // TODO(srawlins): Switch all resolution to use the latter method, in a
+ // breaking change release.
+ staticType =
+ _resolver.inferenceHelper.inferTearOff(node, node, staticType);
+ }
_recordStaticType(node, staticType);
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
index 8542adc..ca56632 100644
--- a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
@@ -65,17 +65,14 @@
_resolver.flowAnalysis.flow?.lateInitializer_end();
}
+ initializer = _resolver.insertImplicitCallReference(initializer);
+
// Initializers of top-level variables and fields are already included
// into elements during linking.
if (element is ConstLocalVariableElementImpl) {
element.constantInitializer = initializer;
}
- var callReference = _resolver.insertImplicitCallReference(initializer);
- if (callReference != initializer) {
- initializer = callReference;
- }
-
_resolver.checkForInvalidAssignment(node.name, initializer,
whyNotPromoted: whyNotPromoted);
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 8b33178..5f87d47 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -7,7 +7,6 @@
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/syntactic_entity.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -19,6 +18,7 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/ast_factory.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
@@ -628,6 +628,62 @@
return null;
}
+ /// If generic function instantiation should be performed on `expression`,
+ /// inserts a [FunctionReference] node which wraps [expression].
+ ///
+ /// If an [FunctionReference] is inserted, returns it; otherwise, returns
+ /// [expression].
+ ExpressionImpl insertGenericFunctionInstantiation(Expression expression) {
+ expression as ExpressionImpl;
+ if (!isConstructorTearoffsEnabled) {
+ // Temporarily, only create [ImplicitCallReference] nodes under the
+ // 'constructor-tearoffs' feature.
+ // TODO(srawlins): When we are ready to make a breaking change release to
+ // the analyzer package, remove this exception.
+ return expression;
+ }
+
+ var staticType = expression.staticType;
+ var context = InferenceContext.getContext(expression);
+ if (context == null ||
+ staticType is! FunctionType ||
+ staticType.typeFormals.isEmpty) {
+ return expression;
+ }
+
+ context = typeSystem.flatten(context);
+ if (context is! FunctionType || context.typeFormals.isNotEmpty) {
+ return expression;
+ }
+
+ List<DartType> typeArgumentTypes =
+ typeSystem.inferFunctionTypeInstantiation(
+ context,
+ staticType,
+ errorReporter: errorReporter,
+ errorNode: expression,
+ // If the constructor-tearoffs feature is enabled, then so is
+ // generic-metadata.
+ genericMetadataIsEnabled: true,
+ )!;
+ if (typeArgumentTypes.isNotEmpty) {
+ staticType = staticType.instantiate(typeArgumentTypes);
+ }
+
+ var parent = expression.parent;
+ var genericFunctionInstantiation = astFactory.functionReference(
+ function: expression,
+ typeArguments: null,
+ );
+ NodeReplacer.replace(expression, genericFunctionInstantiation,
+ parent: parent);
+
+ genericFunctionInstantiation.typeArgumentTypes = typeArgumentTypes;
+ genericFunctionInstantiation.staticType = staticType;
+
+ return genericFunctionInstantiation;
+ }
+
/// If `expression` should be treated as `expression.call`, inserts an
/// [ImplicitCallReferece] node which wraps [expression].
///
@@ -667,6 +723,7 @@
typeArgumentTypes = typeSystem.inferFunctionTypeInstantiation(
context,
callMethodType,
+ errorReporter: errorReporter,
errorNode: expression,
// If the constructor-tearoffs feature is enabled, then so is
// generic-metadata.
@@ -683,7 +740,7 @@
staticElement: callMethod,
typeArguments: null,
typeArgumentTypes: typeArgumentTypes,
- ) as ImplicitCallReferenceImpl;
+ );
NodeReplacer.replace(expression, callReference, parent: parent);
callReference.staticType = callMethodType;
@@ -1060,6 +1117,7 @@
void visitAsExpression(AsExpression node) {
super.visitAsExpression(node);
flowAnalysis.asExpression(node);
+ insertGenericFunctionInstantiation(node);
}
@override
@@ -1095,6 +1153,7 @@
@override
void visitAssignmentExpression(AssignmentExpression node) {
_assignmentExpressionResolver.resolve(node as AssignmentExpressionImpl);
+ insertGenericFunctionInstantiation(node);
}
@override
@@ -1105,11 +1164,13 @@
InferenceContext.setType(node.expression, futureUnion);
}
super.visitAwaitExpression(node);
+ insertGenericFunctionInstantiation(node);
}
@override
void visitBinaryExpression(BinaryExpression node) {
_binaryExpressionResolver.resolve(node as BinaryExpressionImpl);
+ insertGenericFunctionInstantiation(node);
}
@override
@@ -1540,6 +1601,7 @@
_enclosingFunction = node.declaredElement;
_functionExpressionResolver.resolve(node);
+ insertGenericFunctionInstantiation(node);
_enclosingFunction = outerFunction;
}
@@ -1551,6 +1613,7 @@
_functionExpressionInvocationResolver.resolve(
node as FunctionExpressionInvocationImpl, whyNotPromotedList);
nullShortingTermination(node);
+ insertGenericFunctionInstantiation(node);
checkForArgumentTypesNotAssignableInList(
node.argumentList, whyNotPromotedList);
}
@@ -1681,6 +1744,7 @@
type = DynamicTypeImpl.instance;
}
inferenceHelper.recordStaticType(node, type);
+ insertGenericFunctionInstantiation(node);
nullShortingTermination(node);
}
@@ -1786,6 +1850,7 @@
} else {
nullShortingTermination(node);
}
+ insertGenericFunctionInstantiation(node);
checkForArgumentTypesNotAssignableInList(
node.argumentList, whyNotPromotedList);
}
@@ -1849,16 +1914,19 @@
@override
void visitPostfixExpression(PostfixExpression node) {
_postfixExpressionResolver.resolve(node as PostfixExpressionImpl);
+ insertGenericFunctionInstantiation(node);
}
@override
void visitPrefixedIdentifier(covariant PrefixedIdentifierImpl node) {
_prefixedIdentifierResolver.resolve(node);
+ insertGenericFunctionInstantiation(node);
}
@override
void visitPrefixExpression(PrefixExpression node) {
_prefixExpressionResolver.resolve(node as PrefixExpressionImpl);
+ insertGenericFunctionInstantiation(node);
}
@override
@@ -1888,10 +1956,19 @@
type = DynamicTypeImpl.instance;
}
- type = inferenceHelper.inferTearOff(node, propertyName, type);
+ if (!isConstructorTearoffsEnabled) {
+ // Only perform a generic function instantiation on a [PrefixedIdentifier]
+ // in pre-constructor-tearoffs code. In constructor-tearoffs-enabled code,
+ // generic function instantiation is performed at assignability check
+ // sites.
+ // TODO(srawlins): Switch all resolution to use the latter method, in a
+ // breaking change release.
+ type = inferenceHelper.inferTearOff(node, propertyName, type);
+ }
inferenceHelper.recordStaticType(propertyName, type);
inferenceHelper.recordStaticType(node, type);
+ insertGenericFunctionInstantiation(node);
nullShortingTermination(node);
}
@@ -1950,6 +2027,7 @@
@override
void visitSimpleIdentifier(covariant SimpleIdentifierImpl node) {
_simpleIdentifierResolver.resolve(node);
+ insertGenericFunctionInstantiation(node);
}
@override
diff --git a/pkg/analyzer/lib/src/summary2/reference.dart b/pkg/analyzer/lib/src/summary2/reference.dart
index 8c305bd..aea331f 100644
--- a/pkg/analyzer/lib/src/summary2/reference.dart
+++ b/pkg/analyzer/lib/src/summary2/reference.dart
@@ -56,19 +56,32 @@
/// Return the child with the given name, or `null` if does not exist.
Reference? operator [](String name) {
+ name = _rewriteDartUi(name);
return _children?[name];
}
/// Return the child with the given name, create if does not exist yet.
Reference getChild(String name) {
+ name = _rewriteDartUi(name);
var map = _children ??= <String, Reference>{};
return map[name] ??= Reference._(this, name);
}
Reference? removeChild(String name) {
+ name = _rewriteDartUi(name);
return _children?.remove(name);
}
@override
String toString() => parent == null ? 'root' : '$parent::$name';
+
+ /// TODO(scheglov) Remove it, once when the actual issue is fixed.
+ /// https://buganizer.corp.google.com/issues/203423390
+ static String _rewriteDartUi(String name) {
+ const srcPrefix = 'dart:ui/src/ui/';
+ if (name.startsWith(srcPrefix)) {
+ return 'dart:ui/${name.substring(srcPrefix.length)}';
+ }
+ return name;
+ }
}
diff --git a/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart b/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
index b8af67e..ba5aa89 100644
--- a/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
+++ b/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
@@ -838,6 +838,48 @@
);
}
+ test_getMember_method_covariantByDeclaration_inherited() async {
+ await resolveTestCode('''
+abstract class A {
+ void foo(covariant num a);
+}
+
+abstract class B extends A {
+ void foo(int a);
+}
+''');
+ var member = manager.getMember2(
+ findElement.classOrMixin('B'),
+ Name(null, 'foo'),
+ )!;
+ // TODO(scheglov) It would be nice to use `_assertGetMember`.
+ // But we need a way to check covariance.
+ // Maybe check the element display string, not the type.
+ expect(member.parameters[0].isCovariant, isTrue);
+ }
+
+ test_getMember_method_covariantByDeclaration_merged() async {
+ await resolveTestCode('''
+class A {
+ void foo(covariant num a) {}
+}
+
+class B {
+ void foo(int a) {}
+}
+
+class C extends B implements A {}
+''');
+ var member = manager.getMember2(
+ findElement.classOrMixin('C'),
+ Name(null, 'foo'),
+ concrete: true,
+ )!;
+ // TODO(scheglov) It would be nice to use `_assertGetMember`.
+ expect(member.declaration, same(findElement.method('foo', of: 'B')));
+ expect(member.parameters[0].isCovariant, isTrue);
+ }
+
test_getMember_preferLatest_mixin() async {
await resolveTestCode('''
class A {
@@ -909,6 +951,48 @@
);
}
+ test_getMember_setter_covariantByDeclaration_inherited() async {
+ await resolveTestCode('''
+abstract class A {
+ set foo(covariant num a);
+}
+
+abstract class B extends A {
+ set foo(int a);
+}
+''');
+ var member = manager.getMember2(
+ findElement.classOrMixin('B'),
+ Name(null, 'foo='),
+ )!;
+ // TODO(scheglov) It would be nice to use `_assertGetMember`.
+ // But we need a way to check covariance.
+ // Maybe check the element display string, not the type.
+ expect(member.parameters[0].isCovariant, isTrue);
+ }
+
+ test_getMember_setter_covariantByDeclaration_merged() async {
+ await resolveTestCode('''
+class A {
+ set foo(covariant num a) {}
+}
+
+class B {
+ set foo(int a) {}
+}
+
+class C extends B implements A {}
+''');
+ var member = manager.getMember2(
+ findElement.classOrMixin('C'),
+ Name(null, 'foo='),
+ concrete: true,
+ )!;
+ // TODO(scheglov) It would be nice to use `_assertGetMember`.
+ expect(member.declaration, same(findElement.setter('foo', of: 'B')));
+ expect(member.parameters[0].isCovariant, isTrue);
+ }
+
test_getMember_super_abstract() async {
await resolveTestCode('''
abstract class A {
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
index 814951e..fe578e8 100644
--- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
@@ -416,7 +416,7 @@
mixin WithoutConstructorTearoffsMixin on PubPackageResolutionTest {
@override
- String? get testPackageLanguageVersion => '2.13';
+ String? get testPackageLanguageVersion => '2.14';
}
mixin WithoutNullSafetyMixin on PubPackageResolutionTest {
diff --git a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
index 2ccdb48..fc226d1 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
@@ -10,6 +10,8 @@
main() {
defineReflectiveSuite(() {
+ defineReflectiveTests(
+ FunctionReferenceResolution_genericFunctionInstantiationTest);
defineReflectiveTests(FunctionReferenceResolutionTest);
defineReflectiveTests(
FunctionReferenceResolutionWithoutConstructorTearoffsTest);
@@ -17,6 +19,262 @@
}
@reflectiveTest
+class FunctionReferenceResolution_genericFunctionInstantiationTest
+ extends PubPackageResolutionTest {
+ test_asExpression() async {
+ await assertNoErrorsInCode('''
+void Function(int) foo(void Function<T>(T) f) {
+ return (f as dynamic) as void Function<T>(T);
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('as void Function<T>(T);'),
+ null,
+ 'void Function(int)');
+ }
+
+ test_assignmentExpression() async {
+ await assertNoErrorsInCode('''
+late void Function<T>(T) g;
+void Function(int) foo(void Function<T>(T) f) {
+ return g = f;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('g = f;'), null, 'void Function(int)');
+ }
+
+ test_assignmentExpression_compound() async {
+ await assertNoErrorsInCode('''
+extension on void Function<T>(T) {
+ void Function<T>(T) operator +(int i) {
+ return this;
+ }
+}
+
+void Function(int) foo(void Function<T>(T) f) {
+ return f += 1;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('f += 1'), null, 'void Function(int)');
+ }
+
+ test_awaitExpression() async {
+ await assertNoErrorsInCode('''
+Future<void Function(int)> foo(Future<void Function<T>(T)> f) async {
+ return await f;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('await f'), null, 'void Function(int)');
+ }
+
+ test_binaryExpression() async {
+ await assertNoErrorsInCode('''
+class C {
+ void Function<T>(T) operator +(int i) {
+ return <T>(T a) {};
+ }
+}
+
+void Function(int) foo(C c) {
+ return c + 1;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('c + 1'), null, 'void Function(int)');
+ }
+
+ test_cascadeExpression() async {
+ await assertNoErrorsInCode('''
+void Function(int) foo(void Function<T>(T) f) {
+ return f..toString();
+}
+''');
+
+ assertFunctionReference(findNode.functionReference('f..toString()'), null,
+ 'void Function(int)');
+ }
+
+ test_constructorReference() async {
+ await assertNoErrorsInCode('''
+class C<T> {
+ C(T a);
+}
+C<int> Function(int) foo() {
+ return C.new;
+}
+''');
+
+ // TODO(srawlins): Leave the constructor reference uninstantiated, then
+ // perform generic function instantiation as a wrapping node.
+ assertConstructorReference(
+ findNode.constructorReference('C.new'),
+ findElement.unnamedConstructor('C'),
+ findElement.class_('C'),
+ 'C<int> Function(int)');
+ }
+
+ test_functionExpression() async {
+ await assertNoErrorsInCode('''
+Null Function(int) foo() {
+ return <T>(T a) {};
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('<T>(T a) {};'), null, 'Null Function(int)');
+ }
+
+ test_functionExpressionInvocation() async {
+ await assertNoErrorsInCode('''
+void Function(int) foo(void Function<T>(T) Function() f) {
+ return (f)();
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('(f)()'), null, 'void Function(int)');
+ }
+
+ test_functionReference() async {
+ await assertNoErrorsInCode('''
+typedef Fn = void Function<U>(U);
+
+void Function(int) foo(Fn f) {
+ return f;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('f;'), null, 'void Function(int)');
+ }
+
+ test_implicitCallReference() async {
+ await assertNoErrorsInCode('''
+class C {
+ void call<T>(T a) {}
+}
+
+void Function(int) foo(C c) {
+ return c;
+}
+''');
+
+ assertImplicitCallReference(findNode.implicitCallReference('c;'),
+ findElement.method('call'), 'void Function(int)');
+ }
+
+ test_indexExpression() async {
+ await assertNoErrorsInCode('''
+void Function(int) foo(List<void Function<T>(T)> f) {
+ return f[0];
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('f[0];'), null, 'void Function(int)');
+ }
+
+ test_methodInvocation() async {
+ await assertNoErrorsInCode('''
+class C {
+ late void Function<T>(T) f;
+ void Function<T>(T) m() => f;
+}
+
+void Function(int) foo(C c) {
+ return c.m();
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('c.m();'), null, 'void Function(int)');
+ }
+
+ test_postfixExpression_compound() async {
+ await assertNoErrorsInCode('''
+extension on void Function<T>(T) {
+ void Function<T>(T) operator +(int i) {
+ return this;
+ }
+}
+
+void Function(int) foo(void Function<T>(T) f) {
+ return f++;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('f++'), null, 'void Function(int)');
+ }
+
+ test_prefixedIdentifier() async {
+ await assertNoErrorsInCode('''
+class C {
+ late void Function<T>(T) f;
+}
+
+void Function(int) foo(C c) {
+ return c.f;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('c.f;'), null, 'void Function(int)');
+ }
+
+ test_prefixExpression_compound() async {
+ await assertNoErrorsInCode('''
+extension on void Function<T>(T) {
+ void Function<T>(T) operator +(int i) {
+ return this;
+ }
+}
+
+void Function(int) foo(void Function<T>(T) f) {
+ return ++f;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('++f'), null, 'void Function(int)');
+ }
+
+ test_propertyAccess() async {
+ await assertNoErrorsInCode('''
+class C {
+ late void Function<T>(T) f;
+}
+
+void Function(int) foo(C c) {
+ return (c).f;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('(c).f;'), null, 'void Function(int)');
+ }
+
+ test_simpleIdentifier() async {
+ await assertNoErrorsInCode('''
+void Function(int) foo(void Function<T>(T) f) {
+ return f;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('f;'), null, 'void Function(int)');
+ }
+}
+
+@reflectiveTest
class FunctionReferenceResolutionTest extends PubPackageResolutionTest {
test_constructorFunction_named() async {
await assertNoErrorsInCode('''
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 6f09001..bed3b36 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -360,7 +360,9 @@
void assertFunctionReference(
FunctionReference node, Element? expectedElement, String expectedType) {
- assertElement(node, expectedElement);
+ if (expectedElement != null) {
+ assertElement(node, expectedElement);
+ }
assertType(node, expectedType);
}
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/tear_off_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/tear_off_test.dart
index 85fe012..84e3362 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/tear_off_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/tear_off_test.dart
@@ -32,7 +32,6 @@
'f; // 1',
findElement.topFunction('f'),
'T Function<T>(T)',
- [],
);
}
@@ -51,68 +50,94 @@
'f; // 1',
findElement.topFunction('f'),
'int Function(int)',
- [],
);
}
- test_notEmpty() async {
- await assertErrorsInCode('''
-T f<T>(T x) => x;
-
+ test_notEmpty_instanceMethod() async {
+ await assertNoErrorsInCode('''
class C {
T f<T>(T x) => x;
- static T g<T>(T x) => x;
+}
+
+int Function(int) test() {
+ return new C().f;
+}
+''');
+ _assertGenericFunctionInstantiation(
+ 'f;',
+ findElement.method('f', of: 'C'),
+ 'int Function(int)',
+ ['int'],
+ );
+ }
+
+ test_notEmpty_localFunction() async {
+ await assertNoErrorsInCode('''
+int Function(int) test() {
+ T f<T>(T x) => x;
+ return f;
+}
+''');
+ _assertGenericFunctionInstantiation(
+ 'f;',
+ findElement.localFunction('f'),
+ 'int Function(int)',
+ ['int'],
+ );
+ }
+
+ test_notEmpty_staticMethod() async {
+ await assertNoErrorsInCode('''
+class C {
+ static T f<T>(T x) => x;
+}
+
+int Function(int) test() {
+ return C.f;
+}
+''');
+ _assertGenericFunctionInstantiation(
+ 'f;',
+ findElement.method('f', of: 'C'),
+ 'int Function(int)',
+ ['int'],
+ );
+ }
+
+ test_notEmpty_superMethod() async {
+ await assertNoErrorsInCode('''
+class C {
+ T f<T>(T x) => x;
}
class D extends C {
- void test() {
- int Function(int) func;
- func = super.f; // 1
+ int Function(int) test() {
+ return super.f;
}
}
+''');
+ _assertGenericFunctionInstantiation(
+ 'f;',
+ findElement.method('f', of: 'C'),
+ 'int Function(int)',
+ ['int'],
+ );
+ }
-void test() {
- T h<T>(T x) => x;
- int Function(int) func;
- func = f; // 2
- func = new C().f; // 3
- func = C.g; // 4
- func = h; // 5
+ test_notEmpty_topLevelFunction() async {
+ await assertNoErrorsInCode('''
+T f<T>(T x) => x;
+
+int Function(int) test() {
+ return f;
}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 137, 4),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 229, 4),
- ]);
- _assertTearOff(
- 'f; // 1',
- findElement.method('f', of: 'C'),
- 'int Function(int)',
- ['int'],
- );
- _assertTearOff(
- 'f; // 2',
+''');
+ _assertGenericFunctionInstantiation(
+ 'f;',
findElement.topFunction('f'),
'int Function(int)',
['int'],
);
- _assertTearOff(
- 'f; // 3',
- findElement.method('f', of: 'C'),
- 'int Function(int)',
- ['int'],
- );
- _assertTearOff(
- 'g; // 4',
- findElement.method('g', of: 'C'),
- 'int Function(int)',
- ['int'],
- );
- _assertTearOff(
- 'h; // 5',
- findElement.localFunction('h'),
- 'int Function(int)',
- ['int'],
- );
}
test_null_notTearOff() async {
@@ -127,7 +152,6 @@
'f(0);',
findElement.topFunction('f'),
'T Function<T>(T)',
- null,
);
assertInvokeType(
findNode.methodInvocation('f(0)'),
@@ -135,19 +159,30 @@
);
}
- void _assertTearOff(
+ void _assertGenericFunctionInstantiation(
String search,
ExecutableElement element,
String type,
List<String>? typeArguments,
) {
- var id = findNode.simple(search);
+ var id = findNode.functionReference(search);
assertElement(id, element);
assertType(id, type);
if (typeArguments != null) {
- assertElementTypes(id.tearOffTypeArgumentTypes, typeArguments);
+ assertElementTypes(id.typeArgumentTypes, typeArguments);
} else {
- expect(id.tearOffTypeArgumentTypes, isNull);
+ expect(id.typeArgumentTypes, isNull);
}
}
+
+ void _assertTearOff(
+ String search,
+ ExecutableElement element,
+ String type,
+ ) {
+ var id = findNode.simple(search);
+ assertElement(id, element);
+ assertType(id, type);
+ expect(id.tearOffTypeArgumentTypes, isNull);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart
index 2de6c7e..a303efd 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart
@@ -20,24 +20,14 @@
class InvalidAssignment_ImplicitCallReferenceTest
extends PubPackageResolutionTest {
test_invalid_genericBoundedCall_nonGenericContext() async {
- await assertNoErrorsInCode('''
+ await assertErrorsInCode('''
class C {
T call<T extends num>(T t) => t;
}
String Function(String) f = C();
-''');
- }
-
- test_invalid_genericCall() async {
- await assertErrorsInCode('''
-class C {
- T call<T>(T t) => t;
-}
-
-void Function() f = C();
''', [
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 56, 3),
+ error(CompileTimeErrorCode.COULD_NOT_INFER, 76, 3),
]);
}
@@ -57,6 +47,18 @@
]);
}
+ test_invalid_genericCall_nonGenericContext() async {
+ await assertErrorsInCode('''
+class C {
+ T call<T>(T t) => t;
+}
+
+void Function() f = C();
+''', [
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 56, 3),
+ ]);
+ }
+
test_invalid_genericCall_nonGenericContext_withoutConstructorTearoffs() async {
await assertErrorsInCode('''
// @dart=2.12
@@ -349,6 +351,20 @@
]);
}
+ test_functionTearoff_genericInstantiation() async {
+ await assertNoErrorsInCode('''
+int Function() foo(int Function<T extends int>() f) {
+ return f;
+}
+''');
+
+ assertFunctionReference(
+ findNode.functionReference('f;'),
+ findElement.parameter('f'),
+ 'int Function()',
+ );
+ }
+
test_functionTearoff_inferredTypeArgs() async {
await assertNoErrorsInCode('''
void f<T>(T a) {}
@@ -524,6 +540,38 @@
]);
}
+ test_functionInstantiation_topLevelVariable_genericContext_assignable() async {
+ await assertNoErrorsInCode('''
+T f<T>(T a) => a;
+U Function<U>(U) foo = f;
+''');
+ }
+
+ test_functionInstantiation_topLevelVariable_genericContext_nonAssignable() async {
+ await assertErrorsInCode('''
+T f<T>(T a) => a;
+U Function<U>(U, int) foo = f;
+''', [
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 46, 1),
+ ]);
+ }
+
+ test_functionInstantiation_topLevelVariable_nonGenericContext_assignable() async {
+ await assertNoErrorsInCode('''
+T f<T>(T a) => a;
+int Function(int) foo = f;
+''');
+ }
+
+ test_functionInstantiation_topLevelVariable_nonGenericContext_nonAssignable() async {
+ await assertErrorsInCode('''
+T f<T>(T a) => a;
+int Function(int, int) foo = f;
+''', [
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 47, 1),
+ ]);
+ }
+
test_implicitlyImplementFunctionViaCall_1() async {
// issue 18341
//
@@ -983,6 +1031,20 @@
@reflectiveTest
class InvalidAssignmentWithoutNullSafetyTest extends PubPackageResolutionTest
with InvalidAssignmentTestCases, WithoutNullSafetyMixin {
+ test_functionTearoff_genericInstantiation() async {
+ await assertNoErrorsInCode('''
+int Function() foo(int Function<T extends int>() f) {
+ return f;
+}
+''');
+
+ assertSimpleIdentifier(
+ findNode.simple('f;'),
+ element: findElement.parameter('f'),
+ type: 'int Function()',
+ );
+ }
+
test_ifNullAssignment() async {
await assertErrorsInCode('''
void f(int i) {
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_implementation_override_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_implementation_override_test.dart
index d8c60f6..a4d4a40 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_implementation_override_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_implementation_override_test.dart
@@ -120,6 +120,26 @@
error(CompileTimeErrorCode.INVALID_OVERRIDE, 94, 1),
]);
}
+
+ test_method_covariant_inheritance_merge() async {
+ await assertNoErrorsInCode(r'''
+class A {}
+class B extends A {}
+
+class C {
+ /// Not covariant-by-declaration here.
+ void foo(B b) {}
+}
+
+abstract class I {
+ /// Is covariant-by-declaration here.
+ void foo(covariant A a);
+}
+
+/// Is covariant-by-declaration here.
+class D extends C implements I {}
+''');
+ }
}
@reflectiveTest
diff --git a/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart
index 76204ef..8d45f28 100644
--- a/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart
@@ -23,6 +23,42 @@
var v = const <String?>[null];
''');
}
+
+ test_nonConst_genericFunction_genericContext() async {
+ await assertNoErrorsInCode('''
+List<U Function<U>(U)> foo(T Function<T>(T a) f) {
+ return [f];
+}
+''');
+ }
+
+ test_nonConst_genericFunction_genericContext_nonAssignable() async {
+ await assertErrorsInCode('''
+List<U Function<U>(U, int)> foo(T Function<T>(T a) f) {
+ return [f];
+}
+''', [
+ error(CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE, 66, 1),
+ ]);
+ }
+
+ test_nonConst_genericFunction_nonGenericContext() async {
+ await assertNoErrorsInCode('''
+List<int Function(int)> foo(T Function<T>(T a) f) {
+ return [f];
+}
+''');
+ }
+
+ test_nonConst_genericFunction_nonGenericContext_nonAssignable() async {
+ await assertErrorsInCode('''
+List<int Function(int, int)> foo(T Function<T>(T a) f) {
+ return [f];
+}
+''', [
+ error(CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE, 67, 1),
+ ]);
+ }
}
mixin ListElementTypeNotAssignableTestCases on PubPackageResolutionTest {
diff --git a/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart b/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart
index 5f7f7cb..89bab3f 100644
--- a/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart
@@ -258,6 +258,42 @@
''');
}
+ test_function_sync_block_genericFunction__to_genericFunction() async {
+ await assertNoErrorsInCode('''
+U Function<U>(U) foo(T Function<T>(T a) f) {
+ return f;
+}
+''');
+ }
+
+ test_function_sync_block_genericFunction__to_genericFunction_notAssignable() async {
+ await assertErrorsInCode('''
+U Function<U>(U, int) foo(T Function<T>(T a) f) {
+ return f;
+}
+''', [
+ error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 59, 1),
+ ]);
+ }
+
+ test_function_sync_block_genericFunction__to_nonGenericFunction() async {
+ await assertNoErrorsInCode('''
+int Function(int) foo(T Function<T>(T a) f) {
+ return f;
+}
+''');
+ }
+
+ test_function_sync_block_genericFunction__to_nonGenericFunction_notAssignable() async {
+ await assertErrorsInCode('''
+int Function(int, int) foo(T Function<T>(T a) f) {
+ return f;
+}
+''', [
+ error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 60, 1),
+ ]);
+ }
+
test_function_sync_block_int__to_num() async {
await assertNoErrorsInCode(r'''
num f(int a) {
@@ -352,6 +388,34 @@
''');
}
+ test_function_sync_expression_genericFunction__to_genericFunction() async {
+ await assertNoErrorsInCode('''
+U Function<U>(U) foo(T Function<T>(T a) f) => f;
+''');
+ }
+
+ test_function_sync_expression_genericFunction__to_genericFunction_notAssignable() async {
+ await assertErrorsInCode('''
+U Function<U>(U, int) foo(T Function<T>(T a) f) => f;
+''', [
+ error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 51, 1),
+ ]);
+ }
+
+ test_function_sync_expression_genericFunction__to_nonGenericFunction() async {
+ await assertNoErrorsInCode('''
+int Function(int) foo(T Function<T>(T a) f) => f;
+''');
+ }
+
+ test_function_sync_expression_genericFunction__to_nonGenericFunction_notAssignable() async {
+ await assertErrorsInCode('''
+int Function(int, int) foo(T Function<T>(T a) f) => f;
+''', [
+ error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 52, 1),
+ ]);
+ }
+
test_function_sync_expression_int__to_void() async {
await assertNoErrorsInCode('''
void f() => 42;
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 60a785c..25f182d 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -6526,6 +6526,41 @@
''');
}
+ test_const_functionExpression_typeArgumentTypes() async {
+ var library = await checkLibrary('''
+void f<T>(T a) {}
+
+const void Function(int) v = f;
+''');
+ checkElementText(library, '''
+library
+ definingUnit
+ topLevelVariables
+ static const v @44
+ type: void Function(int)
+ constantInitializer
+ FunctionReference
+ function: SimpleIdentifier
+ staticElement: self::@function::f
+ staticType: void Function<T>(T)
+ token: f @48
+ staticType: void Function(int)
+ typeArgumentTypes
+ int
+ accessors
+ synthetic static get v @-1
+ returnType: void Function(int)
+ functions
+ f @5
+ typeParameters
+ covariant T @7
+ parameters
+ requiredPositional a @12
+ type: T
+ returnType: void
+''');
+ }
+
test_const_functionReference() async {
var library = await checkLibrary(r'''
void f<T>(T a) {}
@@ -10475,39 +10510,6 @@
''');
}
- test_const_simpleIdentifier_tearOffTypeArgumentTypes() async {
- var library = await checkLibrary(r'''
-void f<T>(T a) {}
-
-const void Function(int) v = f;
-''');
- checkElementText(library, r'''
-library
- definingUnit
- topLevelVariables
- static const v @44
- type: void Function(int)
- constantInitializer
- SimpleIdentifier
- staticElement: self::@function::f
- staticType: void Function(int)
- tearOffTypeArgumentTypes
- int
- token: f @48
- accessors
- synthetic static get v @-1
- returnType: void Function(int)
- functions
- f @5
- typeParameters
- covariant T @7
- parameters
- requiredPositional a @12
- type: T
- returnType: void
-''');
- }
-
test_const_topLevel_binary() async {
var library = await checkLibrary(r'''
const vEqual = 1 == 2;
@@ -14065,12 +14067,14 @@
aliasArguments
dynamic
constantInitializer
- SimpleIdentifier
- staticElement: self::@function::defaultF
+ FunctionReference
+ function: SimpleIdentifier
+ staticElement: self::@function::defaultF
+ staticType: void Function<T>(T)
+ token: defaultF @93
staticType: void Function(dynamic)
- tearOffTypeArgumentTypes
+ typeArgumentTypes
dynamic
- token: defaultF @93
accessors
synthetic get f @-1
returnType: void Function(dynamic)
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index ad1c27b..bbee8a4 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -9,6 +9,7 @@
# NOTE: `pub get / pub upgrade` are generally not needed when working on this
# package. The `.packages` file in the repository root will be used by default.
dependencies:
+ _fe_analyzer_shared: any
# Published packages - repo version ensured via dependency_overrides
collection: any
crypto: any
@@ -20,8 +21,6 @@
path: ../kernel
# Unpublished packages that can be used via path dependency
- _fe_analyzer_shared:
- path: ../_fe_analyzer_shared
_js_interop_checks:
path: ../_js_interop_checks
js_ast:
diff --git a/pkg/dartdev/pubspec.yaml b/pkg/dartdev/pubspec.yaml
index 9fbdb4b..0145fab 100644
--- a/pkg/dartdev/pubspec.yaml
+++ b/pkg/dartdev/pubspec.yaml
@@ -34,6 +34,8 @@
usage: any
dev_dependencies:
+ expect:
+ path: ../expect
lints: any
pub_semver: any
test: any
diff --git a/pkg/dartdev/test/regress_46364_test.dart b/pkg/dartdev/test/regress_46364_test.dart
new file mode 100644
index 0000000..09edc21
--- /dev/null
+++ b/pkg/dartdev/test/regress_46364_test.dart
@@ -0,0 +1,40 @@
+// 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:expect/expect.dart';
+import 'package:path/path.dart' as p;
+
+// Copied from package:io
+Future<void> copyPath(String from, String to) async {
+ await Directory(to).create(recursive: true);
+ await for (final file in Directory(from).list(recursive: true)) {
+ final copyTo = p.join(to, p.relative(file.path, from: from));
+ if (file is Directory) {
+ await Directory(copyTo).create(recursive: true);
+ } else if (file is File) {
+ await File(file.path).copy(copyTo);
+ } else if (file is Link) {
+ await Link(copyTo).create(await file.target(), recursive: true);
+ }
+ }
+}
+
+Future<void> main() async {
+ final exePath = Platform.resolvedExecutable;
+ final sdkDir = p.dirname(p.dirname(exePath));
+ // Try to run the VM located on a path with % encoded characters. The VM
+ // should not try and resolve the path as a URI for SDK artifacts (e.g.,
+ // dartdev.dart.snapshot).
+ final d = Directory.systemTemp.createTempSync('dart_symlink%3A');
+ try {
+ await copyPath(sdkDir, d.path);
+ final path = '${d.path}/bin/dart';
+ final result = await Process.run(path, ['help']);
+ Expect.equals(result.exitCode, 0);
+ } finally {
+ await d.delete(recursive: true);
+ }
+}
diff --git a/pkg/dev_compiler/analysis_options.yaml b/pkg/dev_compiler/analysis_options.yaml
index 4c72ad8..c1925c0 100644
--- a/pkg/dev_compiler/analysis_options.yaml
+++ b/pkg/dev_compiler/analysis_options.yaml
@@ -1,10 +1,15 @@
-include: package:pedantic/analysis_options.1.11.0.yaml
+include: package:lints/recommended.yaml
analyzer:
strong-mode:
implicit-casts: false
errors:
todo: ignore
+ avoid_function_literals_in_foreach_calls: ignore
+ avoid_renaming_method_parameters: ignore
+ constant_identifier_names: ignore
+ implementation_imports: ignore
+ prefer_void_to_null: ignore
exclude:
- doc/api/**
- gen/**
@@ -15,7 +20,10 @@
linter:
rules:
- # Not enforced by pedantic at any version.
+ # Not enforced by lints at any version.
+ - always_declare_return_types
- directives_ordering
- - prefer_null_aware_operators
- - prefer_typing_uninitialized_variables
+ - omit_local_variable_types
+ - prefer_single_quotes
+ - prefer_relative_imports
+ - unawaited_futures
diff --git a/pkg/dev_compiler/lib/src/compiler/js_metalet.dart b/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
index d9ff9c1..06d5941 100644
--- a/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
+++ b/pkg/dev_compiler/lib/src/compiler/js_metalet.dart
@@ -322,9 +322,7 @@
/// Compute fresh IDs to avoid
static int _uniqueId = 0;
- MetaLetVariable(String displayName)
- : displayName = displayName,
- super(displayName + '@${++_uniqueId}');
+ MetaLetVariable(this.displayName) : super(displayName + '@${++_uniqueId}');
}
class _VariableUseCounter extends BaseVisitor<void> {
diff --git a/pkg/dev_compiler/lib/src/compiler/module_builder.dart b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
index 922b17f..9761f01 100644
--- a/pkg/dev_compiler/lib/src/compiler/module_builder.dart
+++ b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
@@ -5,11 +5,11 @@
// @dart = 2.9
import 'package:args/args.dart' show ArgParser, ArgResults;
-import 'package:dev_compiler/src/compiler/shared_compiler.dart';
import 'package:path/path.dart' as p;
import '../js_ast/js_ast.dart';
import 'js_names.dart';
+import 'shared_compiler.dart';
/// The module format to emit.
enum ModuleFormat {
diff --git a/pkg/dev_compiler/lib/src/compiler/module_containers.dart b/pkg/dev_compiler/lib/src/compiler/module_containers.dart
index 0040d60..a669e71 100644
--- a/pkg/dev_compiler/lib/src/compiler/module_containers.dart
+++ b/pkg/dev_compiler/lib/src/compiler/module_containers.dart
@@ -9,7 +9,7 @@
import '../js_ast/js_ast.dart' show js;
/// Defines how to emit a value of a table
-typedef _emitValue<K> = js_ast.Expression Function(K, ModuleItemData);
+typedef _EmitValue<K> = js_ast.Expression Function(K, ModuleItemData);
/// Represents a top-level property hoisted to a top-level object.
class ModuleItemData {
@@ -125,7 +125,7 @@
/// necessary.
///
/// Uses [emitValue] to emit the values in the table.
- List<js_ast.Statement> emit({_emitValue<K> emitValue});
+ List<js_ast.Statement> emit({_EmitValue<K> emitValue});
}
/// Associates a [K] with a container-unique JS key and arbitrary JS value.
@@ -184,7 +184,7 @@
}
@override
- List<js_ast.Statement> emit({_emitValue<K> emitValue}) {
+ List<js_ast.Statement> emit({_EmitValue<K> emitValue}) {
var containersToProperties = <js_ast.Identifier, List<js_ast.Property>>{};
moduleItems.forEach((k, v) {
if (!incrementalMode && _noEmit.contains(k)) return;
@@ -240,7 +240,7 @@
}
@override
- List<js_ast.Statement> emit({_emitValue<K> emitValue}) {
+ List<js_ast.Statement> emit({_EmitValue<K> emitValue}) {
var properties = List<js_ast.Expression>.filled(length, null);
// If the entire array holds just one value, generate a short initializer.
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
index 3a60942..ee52937 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
@@ -28,7 +28,7 @@
/// Holds all top-level JS symbols (used for caching or indexing fields).
final _symbolContainer = ModuleItemContainer<js_ast.Identifier>.asObject('S',
- keyToString: (js_ast.Identifier i) => '${i.name}');
+ keyToString: (js_ast.Identifier i) => i.name);
ModuleItemContainer<js_ast.Identifier> get symbolContainer =>
_symbolContainer;
diff --git a/pkg/dev_compiler/lib/src/js_ast/builder.dart b/pkg/dev_compiler/lib/src/js_ast/builder.dart
index 0e0077a..1621087 100644
--- a/pkg/dev_compiler/lib/src/js_ast/builder.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/builder.dart
@@ -4,9 +4,10 @@
// @dart = 2.9
-// ignore_for_file: slash_for_doc_comments, unnecessary_new
// ignore_for_file: always_declare_return_types, prefer_single_quotes
+// ignore_for_file: non_constant_identifier_names
// ignore_for_file: prefer_collection_literals, omit_local_variable_types
+// ignore_for_file: slash_for_doc_comments, unnecessary_new
// ignore_for_file: unnecessary_brace_in_string_interps
// Utilities for building JS ASTs at runtime. Contains a builder class
diff --git a/pkg/dev_compiler/lib/src/js_ast/nodes.dart b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
index d721e6e..8618c7e 100644
--- a/pkg/dev_compiler/lib/src/js_ast/nodes.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/nodes.dart
@@ -4,10 +4,11 @@
// @dart = 2.9
-// ignore_for_file: slash_for_doc_comments, prefer_single_quotes
// ignore_for_file: always_declare_return_types, prefer_final_fields
// ignore_for_file: always_require_non_null_named_parameters
// ignore_for_file: omit_local_variable_types, unnecessary_this
+// ignore_for_file: prefer_initializing_formals
+// ignore_for_file: slash_for_doc_comments, prefer_single_quotes
part of js_ast;
diff --git a/pkg/dev_compiler/lib/src/js_ast/printer.dart b/pkg/dev_compiler/lib/src/js_ast/printer.dart
index c6d7581..ff54cdb 100644
--- a/pkg/dev_compiler/lib/src/js_ast/printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/printer.dart
@@ -4,10 +4,11 @@
// @dart = 2.9
-// ignore_for_file: slash_for_doc_comments, unnecessary_const
// ignore_for_file: always_declare_return_types, prefer_single_quotes
// ignore_for_file: prefer_collection_literals, omit_local_variable_types
// ignore_for_file: prefer_final_fields
+// ignore_for_file: prefer_initializing_formals
+// ignore_for_file: slash_for_doc_comments, unnecessary_const
// ignore_for_file: use_function_type_syntax_for_parameters
part of js_ast;
diff --git a/pkg/dev_compiler/lib/src/js_ast/template.dart b/pkg/dev_compiler/lib/src/js_ast/template.dart
index d421d6a..bcba9f0 100644
--- a/pkg/dev_compiler/lib/src/js_ast/template.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/template.dart
@@ -4,9 +4,10 @@
// @dart = 2.9
-// ignore_for_file: slash_for_doc_comments, omit_local_variable_types
// ignore_for_file: always_declare_return_types, prefer_collection_literals
+// ignore_for_file: avoid_returning_null_for_void
// ignore_for_file: prefer_single_quotes, prefer_generic_function_type_aliases
+// ignore_for_file: slash_for_doc_comments, omit_local_variable_types
// ignore_for_file: unnecessary_this
part of js_ast;
diff --git a/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart b/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart
index 54fd3b5..a293c28 100644
--- a/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart
+++ b/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart
@@ -9,9 +9,9 @@
import 'dart:io';
import 'package:async/async.dart';
-import 'package:dev_compiler/src/kernel/retry_timeout_client.dart';
import 'package:front_end/src/api_prototype/file_system.dart';
-import 'package:pedantic/pedantic.dart';
+
+import 'retry_timeout_client.dart';
/// A wrapper around asset server that redirects file read requests
/// to http get requests to the asset server.
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index ed6fa697..ba81acf 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -2278,11 +2278,12 @@
// Helper functions to test if a constructor invocation is internal and
// should be eagerly evaluated.
- var isInternalConstructor = (ConstructorInvocation node) {
+ bool isInternalConstructor(ConstructorInvocation node) {
var type = node.getStaticType(_staticTypeContext) as InterfaceType;
var library = type.classNode.enclosingLibrary;
return isSdkInternalRuntime(library);
- };
+ }
+
for (var field in fields) {
_staticTypeContext.enterMember(field);
var init = field.initializer;
@@ -2824,9 +2825,9 @@
// type arguments are applied.
if (type.typeParameters.isNotEmpty) return true;
- return (_canEmitTypeAtTopLevel(type.returnType) &&
+ return _canEmitTypeAtTopLevel(type.returnType) &&
type.positionalParameters.every(_canEmitTypeAtTopLevel) &&
- type.namedParameters.every((n) => _canEmitTypeAtTopLevel(n.type)));
+ type.namedParameters.every((n) => _canEmitTypeAtTopLevel(n.type));
}
if (type is TypedefType) {
return type.typeArguments.every(_canEmitTypeAtTopLevel);
@@ -3667,6 +3668,7 @@
_cacheUri(location?.file?.toString()),
js.number(location?.line ?? -1),
js.number(location?.column ?? -1),
+ // ignore: unnecessary_string_interpolations
js.escapedString('${p.name}')
])
]);
@@ -5082,10 +5084,10 @@
if (parent.name.text == '&' && parent.arguments.positional.length == 1) {
var left = getInvocationReceiver(parent);
var right = parent.arguments.positional[0];
- final MAX = (1 << width) - 1;
+ final max = (1 << width) - 1;
if (left != null) {
- if (_asIntInRange(right, 0, MAX) != null) return true;
- if (_asIntInRange(left, 0, MAX) != null) return true;
+ if (_asIntInRange(right, 0, max) != null) return true;
+ if (_asIntInRange(left, 0, max) != null) return true;
}
}
return _parentMasksToWidth(parent, width);
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
index 0a1e1c2..4e2cd32 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
@@ -10,10 +10,6 @@
show Code, Message, PlainAndColorizedString;
import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'
show DiagnosticMessage, DiagnosticMessageHandler;
-import 'package:dev_compiler/dev_compiler.dart';
-import 'package:dev_compiler/src/compiler/js_names.dart' as js_ast;
-import 'package:dev_compiler/src/compiler/module_builder.dart';
-import 'package:dev_compiler/src/js_ast/js_ast.dart' as js_ast;
import 'package:front_end/src/api_unstable/ddc.dart';
import 'package:kernel/ast.dart'
show
@@ -36,6 +32,11 @@
VisitorNullMixin,
VisitorVoidMixin;
+import '../../dev_compiler.dart';
+import '../compiler/js_names.dart' as js_ast;
+import '../compiler/module_builder.dart';
+import '../js_ast/js_ast.dart' as js_ast;
+
DiagnosticMessage _createInternalError(Uri uri, int line, int col, String msg) {
return Message(Code<String>('Expression Compiler Internal error'),
problemMessage: msg)
@@ -453,7 +454,7 @@
var imports = <js_ast.ModuleItem>[];
var jsFun = _kernel2jsCompiler.emitFunctionIncremental(imports,
- scope.library, scope.cls, procedure.function, '$debugProcedureName');
+ scope.library, scope.cls, procedure.function, debugProcedureName);
_log('Generated JavaScript for expression');
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
index 6f11aa6..1068a8a 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
@@ -11,9 +11,6 @@
import 'package:args/args.dart';
import 'package:build_integration/file_system/multi_root.dart';
-import 'package:dev_compiler/dev_compiler.dart';
-import 'package:dev_compiler/src/kernel/target.dart'
- show sdkLibraryEnvironmentDefines;
import 'package:front_end/src/api_prototype/file_system.dart';
import 'package:front_end/src/api_unstable/ddc.dart';
import 'package:kernel/ast.dart' show Component, Library;
@@ -24,9 +21,11 @@
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:meta/meta.dart';
+import '../../dev_compiler.dart';
import '../compiler/js_names.dart';
import 'asset_file_system.dart';
import 'command.dart';
+import 'target.dart' show sdkLibraryEnvironmentDefines;
/// The service that handles expression compilation requests from
/// the debugger.
diff --git a/pkg/dev_compiler/lib/src/kernel/module_metadata.dart b/pkg/dev_compiler/lib/src/kernel/module_metadata.dart
index 416f0d8..0ed050a 100644
--- a/pkg/dev_compiler/lib/src/kernel/module_metadata.dart
+++ b/pkg/dev_compiler/lib/src/kernel/module_metadata.dart
@@ -144,10 +144,10 @@
if (!libraries.containsKey(library.importUri)) {
libraries[library.importUri] = library;
} else {
- throw ('Metadata creation error: '
+ throw 'Metadata creation error: '
'Cannot add library $library with uri ${library.importUri}: '
'another library "${libraries[library.importUri]}" is found '
- 'with the same uri');
+ 'with the same uri';
}
}
diff --git a/pkg/dev_compiler/lib/src/kernel/retry_timeout_client.dart b/pkg/dev_compiler/lib/src/kernel/retry_timeout_client.dart
index dfaa3d9..ce67906 100644
--- a/pkg/dev_compiler/lib/src/kernel/retry_timeout_client.dart
+++ b/pkg/dev_compiler/lib/src/kernel/retry_timeout_client.dart
@@ -8,8 +8,6 @@
import 'dart:io';
import 'dart:math';
-import 'package:pedantic/pedantic.dart';
-
/// An HTTP client wrapper that times out connections and requests and
/// automatically retries failing requests.
class RetryTimeoutClient {
diff --git a/pkg/dev_compiler/pubspec.yaml b/pkg/dev_compiler/pubspec.yaml
index e0271f3..f8e49e9 100644
--- a/pkg/dev_compiler/pubspec.yaml
+++ b/pkg/dev_compiler/pubspec.yaml
@@ -6,8 +6,7 @@
sdk: '>=2.12.0 <3.0.0'
dependencies:
- _fe_analyzer_shared:
- path: ../_fe_analyzer_shared
+ _fe_analyzer_shared: any
_js_interop_checks:
path: ../_js_interop_checks
args: any
@@ -21,10 +20,8 @@
path: ../front_end
kernel:
path: ../kernel
- meta:
- path: ../meta
+ meta: any
path: any
- pedantic: ^1.11.0
source_maps: any
source_span: any
@@ -32,18 +29,16 @@
browser_launcher: ^1.0.0
expect:
path: ../expect
- http_multi_server:
- path: ../../third_party/pkg/http_multi_server
- js:
- path: ../js
+ http_multi_server: any
+ js: any
+ lints: ^1.0.0
modular_test:
path: ../modular_test
package_config: any
sourcemap_testing:
path: ../sourcemap_testing
stack_trace: any
- shelf:
- path: ../../third_party/pkg/shelf
+ shelf: any
test: any
testing:
path: ../testing
@@ -51,3 +46,14 @@
path: ../vm
webkit_inspection_protocol: ^1.0.0
+dependency_overrides:
+ _fe_analyzer_shared:
+ path: ../_fe_analyzer_shared
+ js:
+ path: ../js
+ meta:
+ path: ../meta
+ shelf:
+ path: ../../third_party/pkg/shelf
+ http_multi_server:
+ path: ../../third_party/pkg/http_multi_server
diff --git a/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart b/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart
index ca481dc..77b6904 100644
--- a/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart
@@ -208,17 +208,17 @@
() async {
var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
- var elapsedReadAsString = () async {
+ Future<int> elapsedReadAsString() async {
var stopwatch = Stopwatch()..start();
await expectLater(entity.readAsString(), isNotNull);
return stopwatch.elapsedMilliseconds;
- };
+ }
- var elapsedReadAsBytesAndDecode = () async {
+ Future<int> elapsedReadAsBytesAndDecode() async {
var stopwatch = Stopwatch()..start();
await expectLater(utf8.decode(await entity.readAsBytes()), isNotNull);
return stopwatch.elapsedMilliseconds;
- };
+ }
await expectLater(await elapsedReadAsString(),
lessThan(await elapsedReadAsBytesAndDecode()));
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
index c121403..7eaac57 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
@@ -520,7 +520,7 @@
await driver.check(
breakpointId: 'bp',
expression: 'typo',
- expectedError: "Undefined name \'typo\'");
+ expectedError: "Undefined name 'typo'");
});
test('local', () async {
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
index 8e8f1bf..bc5786d 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
@@ -120,7 +120,7 @@
var component = await compiler.computeDelta();
component.computeCanonicalNames();
// Initialize DDC.
- var moduleName = '${p.basenameWithoutExtension(output.toFilePath())}';
+ var moduleName = p.basenameWithoutExtension(output.toFilePath());
var classHierarchy = compiler.getClassHierarchy();
var compilerOptions = SharedCompilerOptions(
@@ -157,7 +157,7 @@
var codeBytes = utf8.encode(code.code);
var sourceMapBytes = utf8.encode(json.encode(code.sourceMap));
- File('${output.toFilePath()}').writeAsBytesSync(codeBytes);
+ File(output.toFilePath()).writeAsBytesSync(codeBytes);
File('${output.toFilePath()}.map').writeAsBytesSync(sourceMapBytes);
// Save the expression evaluator for future evaluations.
@@ -438,7 +438,7 @@
final scriptController = StreamController<wip.ScriptParsedEvent>();
var scriptSub = debugger.onScriptParsed.listen((event) {
- if ('${event.script.url}' == '$output') {
+ if (event.script.url == '$output') {
scriptController.add(event);
}
});
@@ -569,7 +569,7 @@
var response = await connection.runtime
.getProperties(scope.object, ownProperties: true);
for (var prop in response) {
- var propKey = '${prop.name}';
+ var propKey = prop.name;
var propValue = '${prop.value.value}';
if (prop.value.type == 'string') {
propValue = "'$propValue'";
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
index 4a98206..66db5dd 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
@@ -218,7 +218,7 @@
String _normalize(String text) {
return text
.replaceAll(RegExp('\'.*foo.dart\''), '\'foo.dart\'')
- .replaceAll(RegExp('\".*foo.dart\"'), '\'foo.dart\'');
+ .replaceAll(RegExp('".*foo.dart"'), '\'foo.dart\'');
}
Matcher _matches(String text) {
@@ -281,7 +281,7 @@
expression: 'Directory.systemTemp',
expectedResult: '''
(function() {
- const dart_sdk = ${options.loadModule}(\'dart_sdk\');
+ const dart_sdk = ${options.loadModule}('dart_sdk');
const io = dart_sdk.io;
return io.Directory.systemTemp;
}(
@@ -296,7 +296,7 @@
expression: 'p.Directory.systemTemp',
expectedResult: '''
(function() {
- const dart_sdk = ${options.loadModule}(\'dart_sdk\');
+ const dart_sdk = ${options.loadModule}('dart_sdk');
const io = dart_sdk.io;
return io.Directory.systemTemp;
}(
@@ -313,7 +313,7 @@
expression: 'p.utf8.decoder',
expectedResult: '''
(function() {
- const dart_sdk = ${options.loadModule}(\'dart_sdk\');
+ const dart_sdk = ${options.loadModule}('dart_sdk');
const convert = dart_sdk.convert;
return convert.utf8.decoder;
}(
@@ -543,7 +543,7 @@
expression: 'Directory.systemTemp',
expectedResult: '''
(function() {
- const dart_sdk = ${options.loadModule}(\'dart_sdk\');
+ const dart_sdk = ${options.loadModule}('dart_sdk');
const io = dart_sdk.io;
return io.Directory.systemTemp;
}(
@@ -558,7 +558,7 @@
expression: 'p.Directory.systemTemp',
expectedResult: '''
(function() {
- const dart_sdk = ${options.loadModule}(\'dart_sdk\');
+ const dart_sdk = ${options.loadModule}('dart_sdk');
const io = dart_sdk.io;
return io.Directory.systemTemp;
}(
@@ -575,7 +575,7 @@
expression: 'p.utf8.decoder',
expectedResult: '''
(function() {
- const dart_sdk = ${options.loadModule}(\'dart_sdk\');
+ const dart_sdk = ${options.loadModule}('dart_sdk');
const convert = dart_sdk.convert;
return convert.utf8.decoder;
}(
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_shared.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_shared.dart
index cd8a9ef..a1631cf 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_shared.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_shared.dart
@@ -19,7 +19,6 @@
import 'package:front_end/src/compute_platform_binaries_location.dart';
import 'package:http_multi_server/http_multi_server.dart';
import 'package:path/path.dart' as p;
-import 'package:pedantic/pedantic.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart';
import 'package:test/test.dart';
@@ -1008,7 +1007,7 @@
if (config.soundNullSafety) '--sound-null-safety',
if (!config.soundNullSafety) '--no-sound-null-safety',
'--modules',
- '${config.moduleFormat}',
+ config.moduleFormat,
];
var exitCode = await runProcess(dart, args, config.rootPath);
@@ -1037,7 +1036,7 @@
if (config.soundNullSafety) '--sound-null-safety',
if (!config.soundNullSafety) '--no-sound-null-safety',
'--modules',
- '${config.moduleFormat}',
+ config.moduleFormat,
];
exitCode = await runProcess(dart, args, config.rootPath);
@@ -1069,7 +1068,7 @@
if (config.soundNullSafety) '--sound-null-safety',
if (!config.soundNullSafety) '--no-sound-null-safety',
'--modules',
- '${config.moduleFormat}',
+ config.moduleFormat,
];
exitCode = await runProcess(dart, args, config.rootPath);
@@ -1104,7 +1103,7 @@
if (config.soundNullSafety) '--sound-null-safety',
if (!config.soundNullSafety) '--no-sound-null-safety',
'--modules',
- '${config.moduleFormat}',
+ config.moduleFormat,
];
return await runProcess(dart, args, config.rootPath);
diff --git a/pkg/dev_compiler/test/modular_suite.dart b/pkg/dev_compiler/test/modular_suite.dart
index fde41a3..77ee34f 100644
--- a/pkg/dev_compiler/test/modular_suite.dart
+++ b/pkg/dev_compiler/test/modular_suite.dart
@@ -128,11 +128,11 @@
'${toUri(sdkModule, dillId)}',
'--exclude-non-sources',
],
- ...(transitiveDependencies
+ ...transitiveDependencies
.where((m) => !m.isSdk)
- .expand((m) => ['--input-summary', '${toUri(m, dillId)}'])),
- ...(sources.expand((String uri) => ['--source', uri])),
- ...(flags.expand((String flag) => ['--enable-experiment', flag])),
+ .expand((m) => ['--input-summary', '${toUri(m, dillId)}']),
+ ...sources.expand((String uri) => ['--source', uri]),
+ ...flags.expand((String flag) => ['--enable-experiment', flag]),
];
var result =
@@ -211,9 +211,9 @@
...sources,
...extraArgs,
for (String flag in flags) '--enable-experiment=$flag',
- ...(transitiveDependencies
+ ...transitiveDependencies
.where((m) => !m.isSdk)
- .expand((m) => ['-s', '${toUri(m, dillId)}=${m.name}'])),
+ .expand((m) => ['-s', '${toUri(m, dillId)}=${m.name}']),
'-o',
'$output',
];
diff --git a/pkg/dev_compiler/test/modular_suite_nnbd.dart b/pkg/dev_compiler/test/modular_suite_nnbd.dart
index e00e185..2cba274 100644
--- a/pkg/dev_compiler/test/modular_suite_nnbd.dart
+++ b/pkg/dev_compiler/test/modular_suite_nnbd.dart
@@ -126,15 +126,15 @@
'${toUri(sdkModule, dillId)}',
'--exclude-non-sources',
],
- ...(transitiveDependencies
+ ...transitiveDependencies
.where((m) => !m.isSdk)
- .expand((m) => ['--input-summary', '${toUri(m, dillId)}'])),
- ...(sources.expand((String uri) => ['--source', uri])),
+ .expand((m) => ['--input-summary', '${toUri(m, dillId)}']),
+ ...sources.expand((String uri) => ['--source', uri]),
// TODO(40266) After unfork of dart:_runtime only need experiment when
// compiling SDK. For now always use the Null Safety experiment.
'--enable-experiment',
'non-nullable',
- ...(flags.expand((String flag) => ['--enable-experiment', flag])),
+ ...flags.expand((String flag) => ['--enable-experiment', flag]),
];
var result =
@@ -215,9 +215,9 @@
'--enable-experiment',
'non-nullable',
for (String flag in flags) '--enable-experiment=$flag',
- ...(transitiveDependencies
+ ...transitiveDependencies
.where((m) => !m.isSdk)
- .expand((m) => ['-s', '${toUri(m, dillId)}=${m.name}'])),
+ .expand((m) => ['-s', '${toUri(m, dillId)}=${m.name}']),
'-o',
'$output',
];
diff --git a/pkg/dev_compiler/test/nullable_inference_test.dart b/pkg/dev_compiler/test/nullable_inference_test.dart
index da8d7c6..901ca21 100644
--- a/pkg/dev_compiler/test/nullable_inference_test.dart
+++ b/pkg/dev_compiler/test/nullable_inference_test.dart
@@ -530,7 +530,7 @@
/// Given the Dart [code], expects all the expressions inferred to be not-null.
Future expectAllNotNull(String code) async {
code = '// @dart = 2.9\n$code';
- var result = (await kernelCompile(code));
+ var result = await kernelCompile(code);
result.component.accept(ExpectAllNotNull(result.librariesFromDill));
}
diff --git a/pkg/dev_compiler/test/sourcemap/testfiles/multiple_debugger_calls.dart b/pkg/dev_compiler/test/sourcemap/testfiles/multiple_debugger_calls.dart
index f976b63..7ce45b4 100644
--- a/pkg/dev_compiler/test/sourcemap/testfiles/multiple_debugger_calls.dart
+++ b/pkg/dev_compiler/test/sourcemap/testfiles/multiple_debugger_calls.dart
@@ -30,4 +30,4 @@
foo(/*s:8*/ debugger());
}
-void foo(bool _) => null;
+void foo(bool _) {}
diff --git a/pkg/dev_compiler/test/worker/worker_test.dart b/pkg/dev_compiler/test/worker/worker_test.dart
index b03c32f..84111ba 100644
--- a/pkg/dev_compiler/test/worker/worker_test.dart
+++ b/pkg/dev_compiler/test/worker/worker_test.dart
@@ -378,7 +378,7 @@
}
Future<WorkResponse> _readResponse(MessageGrouper messageGrouper) async {
- var buffer = (await messageGrouper.next) as List<int>;
+ var buffer = await messageGrouper.next as List<int>;
try {
return WorkResponse.fromBuffer(buffer);
} catch (_) {
diff --git a/pkg/expect/pubspec.yaml b/pkg/expect/pubspec.yaml
index f84f8c9..70c2817 100644
--- a/pkg/expect/pubspec.yaml
+++ b/pkg/expect/pubspec.yaml
@@ -12,5 +12,8 @@
sdk: '>=2.12.0 <3.0.0'
dependencies:
- meta:
- path: ../meta
+ meta: any
+
+dependency_overrides:
+ meta:
+ path: ../meta
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
index c71dda4..1031699 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
@@ -37,6 +37,7 @@
import '../source/source_class_builder.dart';
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
import '../type_inference/type_schema.dart';
+import '../type_inference/type_inferrer.dart';
import '../util/helpers.dart' show DelayedActionPerformer;
import 'builder.dart';
@@ -68,8 +69,8 @@
void injectInvalidInitializer(Message message, int charOffset, int length,
ExpressionGeneratorHelper helper);
- void addInitializer(
- Initializer initializer, ExpressionGeneratorHelper helper);
+ void addInitializer(Initializer initializer, ExpressionGeneratorHelper helper,
+ {required InitializerInferenceResult? inferenceResult});
void prepareInitializers();
@@ -328,8 +329,8 @@
}
@override
- void addInitializer(
- Initializer initializer, ExpressionGeneratorHelper helper) {
+ void addInitializer(Initializer initializer, ExpressionGeneratorHelper helper,
+ {required InitializerInferenceResult? inferenceResult}) {
List<Initializer> initializers = _constructor.initializers;
if (initializer is SuperInitializer) {
if (superInitializer != null) {
@@ -342,6 +343,7 @@
"super".length,
helper);
} else {
+ inferenceResult?.applyResult(initializers, _constructor);
initializers.add(initializer..parent = _constructor);
superInitializer = initializer;
}
@@ -373,9 +375,11 @@
error.parent = _constructor;
initializers[i] = error;
}
+ inferenceResult?.applyResult(initializers, _constructor);
initializers.add(initializer..parent = _constructor);
redirectingInitializer = initializer;
} else {
+ inferenceResult?.applyResult(initializers, _constructor);
initializers.add(initializer..parent = _constructor);
redirectingInitializer = initializer;
}
@@ -391,6 +395,7 @@
injectInvalidInitializer(messageSuperInitializerNotLast,
initializer.fileOffset, noLength, helper);
} else {
+ inferenceResult?.applyResult(initializers, _constructor);
initializers.add(initializer..parent = _constructor);
}
}
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 b13e27c..6f08b8b 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -112,7 +112,7 @@
import '../source/value_kinds.dart';
import '../type_inference/type_inferrer.dart'
- show TypeInferrer, InferredFunctionBody;
+ show TypeInferrer, InferredFunctionBody, InitializerInferenceResult;
import '../type_inference/type_schema.dart' show UnknownType;
import '../util/helpers.dart' show DelayedActionPerformer;
@@ -960,7 +960,7 @@
formal: formal);
}
for (Initializer initializer in initializers) {
- member.addInitializer(initializer, this);
+ member.addInitializer(initializer, this, inferenceResult: null);
}
}
}
@@ -1648,12 +1648,16 @@
}
}
if (_initializers != null) {
+ Map<Initializer, InitializerInferenceResult> inferenceResults =
+ <Initializer, InitializerInferenceResult>{};
for (Initializer initializer in _initializers!) {
- typeInferrer.inferInitializer(this, initializer);
+ inferenceResults[initializer] =
+ typeInferrer.inferInitializer(this, initializer);
}
if (!builder.isExternal) {
for (Initializer initializer in _initializers!) {
- builder.addInitializer(initializer, this);
+ builder.addInitializer(initializer, this,
+ inferenceResult: inferenceResults[initializer]!);
}
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 57f6519..87a0d06 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -42,7 +42,7 @@
implements
ExpressionVisitor1<ExpressionInferenceResult, DartType>,
StatementVisitor<StatementInferenceResult>,
- InitializerVisitor<void> {
+ InitializerVisitor<InitializerInferenceResult> {
final TypeInferrerImpl inferrer;
Class? mapEntryClass;
@@ -326,23 +326,23 @@
return _unhandledStatement(node);
}
- void _unhandledInitializer(Initializer node) {
+ Never _unhandledInitializer(Initializer node) {
unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
node.location!.file);
}
@override
- void defaultInitializer(Initializer node) {
+ InitializerInferenceResult defaultInitializer(Initializer node) {
_unhandledInitializer(node);
}
@override
- void visitInvalidInitializer(InvalidInitializer node) {
+ InitializerInferenceResult visitInvalidInitializer(InvalidInitializer node) {
_unhandledInitializer(node);
}
@override
- void visitLocalInitializer(LocalInitializer node) {
+ InitializerInferenceResult visitLocalInitializer(LocalInitializer node) {
_unhandledInitializer(node);
}
@@ -488,11 +488,12 @@
}
@override
- void visitAssertInitializer(AssertInitializer node) {
+ InitializerInferenceResult visitAssertInitializer(AssertInitializer node) {
StatementInferenceResult result = inferrer.inferStatement(node.statement);
if (result.hasChanged) {
node.statement = (result.statement as AssertStatement)..parent = node;
}
+ return const SuccessfulInitializerInferenceResult();
}
@override
@@ -1059,13 +1060,14 @@
}
@override
- void visitFieldInitializer(FieldInitializer node) {
+ InitializerInferenceResult visitFieldInitializer(FieldInitializer node) {
ExpressionInferenceResult initializerResult =
inferrer.inferExpression(node.value, node.field.type, true);
Expression initializer = inferrer.ensureAssignableResult(
node.field.type, initializerResult,
fileOffset: node.fileOffset);
node.value = initializer..parent = node;
+ return const SuccessfulInitializerInferenceResult();
}
ForInResult handleForInDeclaringVariable(
@@ -1410,7 +1412,7 @@
return new ExpressionInferenceResult(inferredType, node);
}
- void visitInvalidSuperInitializerJudgment(
+ InitializerInferenceResult visitInvalidSuperInitializerJudgment(
InvalidSuperInitializerJudgment node) {
Substitution substitution = Substitution.fromSupertype(
inferrer.classHierarchy.getClassAsInstanceOf(
@@ -1420,9 +1422,12 @@
.computeThisFunctionType(inferrer.library.nonNullable)
.withoutTypeParameters) as FunctionType,
inferrer.thisType!);
- inferrer.inferInvocation(const UnknownType(), node.fileOffset, functionType,
- node.argumentsJudgment,
- skipTypeArgumentInference: true);
+ InvocationInferenceResult invocationInferenceResult =
+ inferrer.inferInvocation(const UnknownType(), node.fileOffset,
+ functionType, node.argumentsJudgment,
+ skipTypeArgumentInference: true);
+ return new InitializerInferenceResult.fromInvocationInferenceResult(
+ invocationInferenceResult);
}
ExpressionInferenceResult visitIfNullExpression(
@@ -1566,19 +1571,23 @@
return new ExpressionInferenceResult(inferredType, replacement);
}
- void visitShadowInvalidInitializer(ShadowInvalidInitializer node) {
+ InitializerInferenceResult visitShadowInvalidInitializer(
+ ShadowInvalidInitializer node) {
ExpressionInferenceResult initializerResult = inferrer.inferExpression(
node.variable.initializer!, const UnknownType(), !inferrer.isTopLevel,
isVoidAllowed: false);
node.variable.initializer = initializerResult.expression
..parent = node.variable;
+ return const SuccessfulInitializerInferenceResult();
}
- void visitShadowInvalidFieldInitializer(ShadowInvalidFieldInitializer node) {
+ InitializerInferenceResult visitShadowInvalidFieldInitializer(
+ ShadowInvalidFieldInitializer node) {
ExpressionInferenceResult initializerResult = inferrer.inferExpression(
node.value, node.field.type, !inferrer.isTopLevel,
isVoidAllowed: false);
node.value = initializerResult.expression..parent = node;
+ return const SuccessfulInitializerInferenceResult();
}
@override
@@ -5850,7 +5859,8 @@
}
@override
- void visitRedirectingInitializer(RedirectingInitializer node) {
+ InitializerInferenceResult visitRedirectingInitializer(
+ RedirectingInitializer node) {
inferrer.inferConstructorParameterTypes(node.target);
List<TypeParameter> classTypeParameters =
node.target.enclosingClass.typeParameters;
@@ -5866,11 +5876,17 @@
.computeThisFunctionType(inferrer.library.nonNullable),
inferrer.coreTypes.thisInterfaceType(
node.target.enclosingClass, inferrer.library.nonNullable));
- inferrer.inferInvocation(const UnknownType(), node.fileOffset, functionType,
+ InvocationInferenceResult inferenceResult = inferrer.inferInvocation(
+ const UnknownType(),
+ node.fileOffset,
+ functionType,
node.arguments as ArgumentsImpl,
- skipTypeArgumentInference: true, staticTarget: node.target);
+ skipTypeArgumentInference: true,
+ staticTarget: node.target);
ArgumentsImpl.removeNonInferrableArgumentTypes(
node.arguments as ArgumentsImpl);
+ return new InitializerInferenceResult.fromInvocationInferenceResult(
+ inferenceResult);
}
@override
@@ -6080,7 +6096,7 @@
}
@override
- void visitSuperInitializer(SuperInitializer node) {
+ InitializerInferenceResult visitSuperInitializer(SuperInitializer node) {
inferrer.inferConstructorParameterTypes(node.target);
Substitution substitution = Substitution.fromSupertype(
inferrer.classHierarchy.getClassAsInstanceOf(
@@ -6090,9 +6106,15 @@
.computeThisFunctionType(inferrer.library.nonNullable)
.withoutTypeParameters) as FunctionType,
inferrer.thisType!);
- inferrer.inferInvocation(const UnknownType(), node.fileOffset, functionType,
+ InvocationInferenceResult inferenceResult = inferrer.inferInvocation(
+ const UnknownType(),
+ node.fileOffset,
+ functionType,
node.arguments as ArgumentsImpl,
- skipTypeArgumentInference: true, staticTarget: node.target);
+ skipTypeArgumentInference: true,
+ staticTarget: node.target);
+ return new InitializerInferenceResult.fromInvocationInferenceResult(
+ inferenceResult);
}
@override
diff --git a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index 7560883..7239b43 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -891,7 +891,7 @@
: super(variable);
@override
- void acceptInference(InferenceVisitor visitor) {
+ InitializerInferenceResult acceptInference(InferenceVisitor visitor) {
return visitor.visitInvalidSuperInitializerJudgment(this);
}
@@ -982,7 +982,7 @@
abstract class InitializerJudgment implements Initializer {
/// Performs type inference for whatever concrete type of
/// [InitializerJudgment] this is.
- void acceptInference(InferenceVisitor visitor);
+ InitializerInferenceResult acceptInference(InferenceVisitor visitor);
}
Expression? checkWebIntLiteralsErrorIfUnexact(
@@ -1089,7 +1089,7 @@
ShadowInvalidInitializer(VariableDeclaration variable) : super(variable);
@override
- void acceptInference(InferenceVisitor visitor) {
+ InitializerInferenceResult acceptInference(InferenceVisitor visitor) {
return visitor.visitShadowInvalidInitializer(this);
}
@@ -1114,7 +1114,7 @@
}
@override
- void acceptInference(InferenceVisitor visitor) {
+ InitializerInferenceResult acceptInference(InferenceVisitor visitor) {
return visitor.visitShadowInvalidFieldInitializer(this);
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 7e9d30a..93e1544 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -145,7 +145,8 @@
DartType returnType, AsyncMarker asyncMarker, Statement body);
/// Performs type inference on the given constructor initializer.
- void inferInitializer(InferenceHelper helper, Initializer initializer);
+ InitializerInferenceResult inferInitializer(
+ InferenceHelper helper, Initializer initializer);
/// Performs type inference on the given metadata annotations.
void inferMetadata(
@@ -410,19 +411,22 @@
}
@override
- void inferInitializer(InferenceHelper helper, Initializer initializer) {
+ InitializerInferenceResult inferInitializer(
+ InferenceHelper helper, Initializer initializer) {
this.helper = helper;
// Use polymorphic dispatch on [KernelInitializer] to perform whatever
// kind of type inference is correct for this kind of initializer.
// TODO(paulberry): experiment to see if dynamic dispatch would be better,
// so that the type hierarchy will be simpler (which may speed up "is"
// checks).
+ InitializerInferenceResult inferenceResult;
if (initializer is InitializerJudgment) {
- initializer.acceptInference(new InferenceVisitor(this));
+ inferenceResult = initializer.acceptInference(new InferenceVisitor(this));
} else {
- initializer.accept(new InferenceVisitor(this));
+ inferenceResult = initializer.accept(new InferenceVisitor(this));
}
this.helper = null;
+ return inferenceResult;
}
bool isDoubleContext(DartType typeContext) {
@@ -4905,11 +4909,9 @@
if (expression is FactoryConstructorInvocation) {
return _insertHoistedExpressions(expression, hoistedArguments);
} else if (expression is TypeAliasedConstructorInvocation) {
- // Should be unaliased at this point, the code is for completeness.
return _insertHoistedExpressions(expression, hoistedArguments);
} else if (expression is TypeAliasedFactoryInvocation) {
- // Should be unaliased at this point, the code is for completeness.
- return expression;
+ return _insertHoistedExpressions(expression, hoistedArguments);
} else if (expression is ConstructorInvocation) {
return _insertHoistedExpressions(expression, hoistedArguments);
} else if (expression is DynamicInvocation) {
@@ -4982,6 +4984,78 @@
}
}
+abstract class InitializerInferenceResult {
+ /// Modifies list of initializers in-place to apply the inference result.
+ void applyResult(List<Initializer> initializers, TreeNode? parent);
+
+ factory InitializerInferenceResult.fromInvocationInferenceResult(
+ InvocationInferenceResult invocationInferenceResult) {
+ if (invocationInferenceResult is SuccessfulInferenceResult) {
+ return new SuccessfulInitializerInvocationInferenceResult
+ .fromSuccessfulInferenceResult(invocationInferenceResult);
+ } else {
+ return new WrapInProblemInitializerInferenceResult
+ .fromWrapInProblemInferenceResult(
+ invocationInferenceResult as WrapInProblemInferenceResult);
+ }
+ }
+}
+
+class SuccessfulInitializerInferenceResult
+ implements InitializerInferenceResult {
+ const SuccessfulInitializerInferenceResult();
+
+ @override
+ void applyResult(List<Initializer> initializers, TreeNode? parent) {}
+}
+
+class SuccessfulInitializerInvocationInferenceResult
+ implements InitializerInferenceResult {
+ final DartType inferredType;
+
+ final FunctionType functionType;
+
+ final List<VariableDeclaration>? hoistedArguments;
+
+ final DartType? inferredReceiverType;
+
+ SuccessfulInitializerInvocationInferenceResult(
+ {required this.inferredType,
+ required this.functionType,
+ required this.hoistedArguments,
+ required this.inferredReceiverType});
+
+ SuccessfulInitializerInvocationInferenceResult.fromSuccessfulInferenceResult(
+ SuccessfulInferenceResult successfulInferenceResult)
+ : this(
+ inferredType: successfulInferenceResult.inferredType,
+ functionType: successfulInferenceResult.functionType,
+ hoistedArguments: successfulInferenceResult.hoistedArguments,
+ inferredReceiverType:
+ successfulInferenceResult.inferredReceiverType);
+
+ @override
+ void applyResult(List<Initializer> initializers, TreeNode? parent) {
+ List<VariableDeclaration>? hoistedArguments = this.hoistedArguments;
+ if (hoistedArguments != null && hoistedArguments.isNotEmpty) {
+ for (VariableDeclaration hoistedArgument in hoistedArguments) {
+ initializers.add(new LocalInitializer(hoistedArgument)
+ ..parent = parent
+ ..fileOffset = hoistedArgument.fileOffset);
+ }
+ }
+ }
+}
+
+class WrapInProblemInitializerInferenceResult
+ implements InitializerInferenceResult {
+ WrapInProblemInitializerInferenceResult.fromWrapInProblemInferenceResult(
+ WrapInProblemInferenceResult wrapInProblemInferenceResult);
+
+ @override
+ void applyResult(List<Initializer> initializers, TreeNode? parent) {}
+}
+
/// The result of inference of a property get expression.
class PropertyGetInferenceResult {
/// The main inference result.
diff --git a/pkg/front_end/pubspec.yaml b/pkg/front_end/pubspec.yaml
index 9e67ea3..4fff6ab 100644
--- a/pkg/front_end/pubspec.yaml
+++ b/pkg/front_end/pubspec.yaml
@@ -9,37 +9,43 @@
sdk: '>=2.13.0 <3.0.0'
dependencies:
- _fe_analyzer_shared:
- path: ../_fe_analyzer_shared
+ _fe_analyzer_shared: any
kernel:
path: ../kernel
- package_config:
- path: ../../third_party/pkg_tested/package_config
+ package_config: any
dev_dependencies:
- analyzer:
- path: ../analyzer
- args: '>=0.13.0 <2.0.0'
+ analyzer: any
+ args: ^2.0.0
async_helper:
path: ../async_helper
build_integration:
path: ../build_integration
compiler:
path: ../compiler
- dart_style: '^1.0.7'
+ dart_style: ^2.0.0
dev_compiler:
path: ../dev_compiler
expect:
path: ../expect
- json_rpc_2: ^2.0.9
- path: '^1.3.9'
+ json_rpc_2: ^3.0.0
+ path: ^1.3.9
test: ^1.3.4
testing:
path: ../testing
- test_reflective_loader: ^0.1.0
+ test_reflective_loader: ^0.2.0
vm:
path: ../vm
+ vm_service: any
+ web_socket_channel: ^2.0.0
+ yaml: any
+
+dependency_overrides:
+ analyzer:
+ path: ../analyzer
+ _fe_analyzer_shared:
+ path: ../_fe_analyzer_shared
+ package_config:
+ path: ../../third_party/pkg_tested/package_config
vm_service:
path: ../vm_service
- web_socket_channel: ^1.0.4
- yaml: any
diff --git a/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart b/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart
index 2c51514..8d34e3c 100644
--- a/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart
+++ b/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart
@@ -1,3 +1,7 @@
+// 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.
+
class A {
A(int x, int y, {required int z});
diff --git a/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart.strong.transformed.expect b/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart.strong.transformed.expect
index 4cfee0f..c92ba29 100644
--- a/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart.strong.transformed.expect
@@ -78,44 +78,44 @@
}
Extra constant evaluation status:
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:77:15 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:77:21 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:78:18 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:17:18 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:27:7 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:27:13 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:28:10 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:32:13 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:32:19 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:33:16 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:35:13 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:35:19 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:36:16 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:40:9 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:40:15 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:41:12 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:43:9 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:43:15 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:44:12 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:48:5 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:48:11 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:49:8 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:53:5 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:53:11 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:54:8 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:57:14 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:57:17 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:57:23 -> IntConstant(3)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:58:14 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:58:23 -> IntConstant(3)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:58:20 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:59:20 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:59:23 -> IntConstant(3)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:59:17 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:63:9 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:63:15 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:64:12 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:68:9 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:68:15 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:69:12 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:81:15 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:81:21 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:82:18 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:21:18 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:31:7 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:31:13 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:32:10 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:36:13 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:36:19 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:37:16 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:39:13 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:39:19 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:40:16 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:44:9 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:44:15 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:45:12 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:47:9 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:47:15 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:48:12 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:52:5 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:52:11 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:53:8 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:57:5 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:57:11 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:58:8 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:61:14 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:61:17 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:61:23 -> IntConstant(3)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:62:14 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:62:23 -> IntConstant(3)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:62:20 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:63:20 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:63:23 -> IntConstant(3)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:63:17 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:67:9 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:67:15 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:68:12 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:72:9 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:72:15 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:73:12 -> IntConstant(1)
Extra constant evaluation: evaluated: 155, effectively constant: 40
diff --git a/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart.weak.transformed.expect b/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart.weak.transformed.expect
index 4cfee0f..c92ba29 100644
--- a/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/named_arguments_anywhere/all_kinds.dart.weak.transformed.expect
@@ -78,44 +78,44 @@
}
Extra constant evaluation status:
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:77:15 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:77:21 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:78:18 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:17:18 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:27:7 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:27:13 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:28:10 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:32:13 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:32:19 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:33:16 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:35:13 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:35:19 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:36:16 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:40:9 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:40:15 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:41:12 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:43:9 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:43:15 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:44:12 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:48:5 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:48:11 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:49:8 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:53:5 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:53:11 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:54:8 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:57:14 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:57:17 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:57:23 -> IntConstant(3)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:58:14 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:58:23 -> IntConstant(3)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:58:20 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:59:20 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:59:23 -> IntConstant(3)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:59:17 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:63:9 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:63:15 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:64:12 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:68:9 -> IntConstant(1)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:68:15 -> IntConstant(2)
-Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:69:12 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:81:15 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:81:21 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:82:18 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:21:18 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:31:7 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:31:13 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:32:10 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:36:13 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:36:19 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:37:16 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:39:13 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:39:19 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:40:16 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:44:9 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:44:15 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:45:12 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:47:9 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:47:15 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:48:12 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:52:5 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:52:11 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:53:8 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:57:5 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:57:11 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:58:8 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:61:14 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:61:17 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:61:23 -> IntConstant(3)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:62:14 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:62:23 -> IntConstant(3)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:62:20 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:63:20 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:63:23 -> IntConstant(3)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:63:17 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:67:9 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:67:15 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:68:12 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:72:9 -> IntConstant(1)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:72:15 -> IntConstant(2)
+Evaluated: VariableGet @ org-dartlang-testcase:///all_kinds.dart:73:12 -> IntConstant(1)
Extra constant evaluation: evaluated: 155, effectively constant: 40
diff --git a/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart
new file mode 100644
index 0000000..ebb9e92
--- /dev/null
+++ b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart
@@ -0,0 +1,23 @@
+// 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.
+
+class A {
+ A(int x, bool y, {required String z});
+
+ A.foo() : this(42, z: "foo", false);
+
+ factory A.bar(int x, bool y, {required String z}) = A;
+}
+
+class B extends A {
+ B() : super(42, z: "foo", false);
+}
+
+test() {
+ new A.bar(42, false, z: "bar");
+ new A.bar(42, z: "bar", false);
+ new A.bar(z: "bar", 42, false);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.strong.expect b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.strong.expect
new file mode 100644
index 0000000..5b2dee8
--- /dev/null
+++ b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.strong.expect
@@ -0,0 +1,31 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
+ constructor •(core::int x, core::bool y, {required core::String z = #C2}) → self::A
+ : super core::Object::•()
+ ;
+ constructor foo() → self::A
+ : final core::int #t1 = 42, final core::String #t2 = "foo", this self::A::•(#t1, false, z: #t2)
+ ;
+ static factory bar(core::int x, core::bool y, {required core::String z = #C2}) → self::A
+ return new self::A::•(x, y, z: z);
+}
+class B extends self::A {
+ constructor •() → self::B
+ : final core::int #t3 = 42, final core::String #t4 = "foo", super self::A::•(#t3, false, z: #t4)
+ ;
+}
+static method test() → dynamic {
+ new self::A::•(42, false, z: "bar");
+ let final core::int #t5 = 42 in let final core::String #t6 = "bar" in new self::A::•(#t5, false, z: #t6);
+ let final core::String #t7 = "bar" in new self::A::•(42, false, z: #t7);
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = constructor-tearoff self::A::bar
+ #C2 = null
+}
diff --git a/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.strong.transformed.expect b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.strong.transformed.expect
new file mode 100644
index 0000000..06dd91e
--- /dev/null
+++ b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.strong.transformed.expect
@@ -0,0 +1,37 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
+ constructor •(core::int x, core::bool y, {required core::String z = #C2}) → self::A
+ : super core::Object::•()
+ ;
+ constructor foo() → self::A
+ : final core::int #t1 = 42, final core::String #t2 = "foo", this self::A::•(#t1, false, z: #t2)
+ ;
+ static factory bar(core::int x, core::bool y, {required core::String z = #C2}) → self::A
+ return new self::A::•(x, y, z: z);
+}
+class B extends self::A {
+ constructor •() → self::B
+ : final core::int #t3 = 42, final core::String #t4 = "foo", super self::A::•(#t3, false, z: #t4)
+ ;
+}
+static method test() → dynamic {
+ new self::A::•(42, false, z: "bar");
+ let final core::int #t5 = 42 in let final core::String #t6 = "bar" in new self::A::•(#t5, false, z: #t6);
+ let final core::String #t7 = "bar" in new self::A::•(42, false, z: #t7);
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = constructor-tearoff self::A::bar
+ #C2 = null
+}
+
+Extra constant evaluation status:
+Evaluated: VariableGet @ org-dartlang-testcase:///redirecting_constructor_initializers.dart:19:13 -> IntConstant(42)
+Evaluated: VariableGet @ org-dartlang-testcase:///redirecting_constructor_initializers.dart:19:20 -> StringConstant("bar")
+Evaluated: VariableGet @ org-dartlang-testcase:///redirecting_constructor_initializers.dart:20:16 -> StringConstant("bar")
+Extra constant evaluation: evaluated: 18, effectively constant: 3
diff --git a/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.textual_outline.expect b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.textual_outline.expect
new file mode 100644
index 0000000..4ca0a85
--- /dev/null
+++ b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.textual_outline.expect
@@ -0,0 +1,10 @@
+class A {
+ A(int x, bool y, {required String z});
+ A.foo() : this(42, z: "foo", false);
+ factory A.bar(int x, bool y, {required String z}) = A;
+}
+class B extends A {
+ B() : super(42, z: "foo", false);
+}
+test() {}
+main() {}
diff --git a/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.weak.expect b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.weak.expect
new file mode 100644
index 0000000..5b2dee8
--- /dev/null
+++ b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.weak.expect
@@ -0,0 +1,31 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
+ constructor •(core::int x, core::bool y, {required core::String z = #C2}) → self::A
+ : super core::Object::•()
+ ;
+ constructor foo() → self::A
+ : final core::int #t1 = 42, final core::String #t2 = "foo", this self::A::•(#t1, false, z: #t2)
+ ;
+ static factory bar(core::int x, core::bool y, {required core::String z = #C2}) → self::A
+ return new self::A::•(x, y, z: z);
+}
+class B extends self::A {
+ constructor •() → self::B
+ : final core::int #t3 = 42, final core::String #t4 = "foo", super self::A::•(#t3, false, z: #t4)
+ ;
+}
+static method test() → dynamic {
+ new self::A::•(42, false, z: "bar");
+ let final core::int #t5 = 42 in let final core::String #t6 = "bar" in new self::A::•(#t5, false, z: #t6);
+ let final core::String #t7 = "bar" in new self::A::•(42, false, z: #t7);
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = constructor-tearoff self::A::bar
+ #C2 = null
+}
diff --git a/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.weak.outline.expect b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.weak.outline.expect
new file mode 100644
index 0000000..ccf5a7c
--- /dev/null
+++ b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.weak.outline.expect
@@ -0,0 +1,26 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::A::bar]/*isLegacy*/;
+ constructor •(core::int x, core::bool y, {required core::String z}) → self::A
+ ;
+ constructor foo() → self::A
+ ;
+ static factory bar(core::int x, core::bool y, {required core::String z}) → self::A
+ return new self::A::•(x, y, z: z);
+}
+class B extends self::A {
+ constructor •() → self::B
+ ;
+}
+static method test() → dynamic
+ ;
+static method main() → dynamic
+ ;
+
+
+Extra constant evaluation status:
+Evaluated: ConstructorTearOff @ org-dartlang-testcase:///redirecting_constructor_initializers.dart:5:7 -> ConstructorTearOffConstant(A.bar)
+Extra constant evaluation: evaluated: 6, effectively constant: 1
diff --git a/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.weak.transformed.expect b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.weak.transformed.expect
new file mode 100644
index 0000000..06dd91e
--- /dev/null
+++ b/pkg/front_end/testcases/named_arguments_anywhere/redirecting_constructor_initializers.dart.weak.transformed.expect
@@ -0,0 +1,37 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
+ constructor •(core::int x, core::bool y, {required core::String z = #C2}) → self::A
+ : super core::Object::•()
+ ;
+ constructor foo() → self::A
+ : final core::int #t1 = 42, final core::String #t2 = "foo", this self::A::•(#t1, false, z: #t2)
+ ;
+ static factory bar(core::int x, core::bool y, {required core::String z = #C2}) → self::A
+ return new self::A::•(x, y, z: z);
+}
+class B extends self::A {
+ constructor •() → self::B
+ : final core::int #t3 = 42, final core::String #t4 = "foo", super self::A::•(#t3, false, z: #t4)
+ ;
+}
+static method test() → dynamic {
+ new self::A::•(42, false, z: "bar");
+ let final core::int #t5 = 42 in let final core::String #t6 = "bar" in new self::A::•(#t5, false, z: #t6);
+ let final core::String #t7 = "bar" in new self::A::•(42, false, z: #t7);
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = constructor-tearoff self::A::bar
+ #C2 = null
+}
+
+Extra constant evaluation status:
+Evaluated: VariableGet @ org-dartlang-testcase:///redirecting_constructor_initializers.dart:19:13 -> IntConstant(42)
+Evaluated: VariableGet @ org-dartlang-testcase:///redirecting_constructor_initializers.dart:19:20 -> StringConstant("bar")
+Evaluated: VariableGet @ org-dartlang-testcase:///redirecting_constructor_initializers.dart:20:16 -> StringConstant("bar")
+Extra constant evaluation: evaluated: 18, effectively constant: 3
diff --git a/pkg/front_end/testcases/nnbd_mixed/mock_http_headers.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd_mixed/mock_http_headers.dart.weak.outline.expect
index 4789762..ed2219b 100644
--- a/pkg/front_end/testcases/nnbd_mixed/mock_http_headers.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/mock_http_headers.dart.weak.outline.expect
@@ -170,8 +170,8 @@
Evaluated: SymbolLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> SymbolConstant(#noFolding)
Evaluated: ListLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> ListConstant(const <Type*>[])
Evaluated: MapLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> MapConstant(const <Symbol*, dynamic>{})
-Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:707:8 -> SymbolConstant(#clear)
-Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:707:8 -> ListConstant(const <Type*>[])
-Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:707:8 -> ListConstant(const <dynamic>[])
-Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:707:8 -> MapConstant(const <Symbol*, dynamic>{})
+Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:676:8 -> SymbolConstant(#clear)
+Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:676:8 -> ListConstant(const <Type*>[])
+Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:676:8 -> ListConstant(const <dynamic>[])
+Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:676:8 -> MapConstant(const <Symbol*, dynamic>{})
Extra constant evaluation: evaluated: 268, effectively constant: 91
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 9306978..0c51eb2 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -74,10 +74,10 @@
general/error_recovery/yield_not_in_generator: RuntimeError
general/expressions: RuntimeError
general/getter_vs_setter_type: TypeCheckError
+general/implement_semi_stub: TypeCheckError
+general/implicit_super_call: TypeCheckError
general/incomplete_field_formal_parameter: RuntimeError
general/infer_field_from_multiple: TypeCheckError
-general/implicit_super_call: TypeCheckError
-general/implement_semi_stub: TypeCheckError
general/invalid_operator: TypeCheckError
general/invalid_operator_override: TypeCheckError
general/invocations: RuntimeError
@@ -135,6 +135,7 @@
inference_new/infer_assign_to_index_this_upwards: TypeCheckError
inference_new/infer_assign_to_index_upwards: TypeCheckError
late_lowering/covariant_late_field: TypeCheckError
+named_arguments_anywhere/redirecting_constructor_initializers: Crash # Issue 47524.
nnbd/covariant_late_field: TypeCheckError
nnbd/getter_vs_setter_type: TypeCheckError
nnbd/issue42603: TypeCheckError
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index decb8b5..260c55f 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -134,6 +134,7 @@
late_lowering/override_getter_setter: FormatterCrash
late_lowering/skip_late_final_uninitialized_instance_fields/main: FormatterCrash
late_lowering/uninitialized_non_nullable_late_fields: FormatterCrash
+named_arguments_anywhere/redirecting_constructor_initializers: FormatterCrash
nnbd/abstract_field_errors: FormatterCrash
nnbd/covariant_late_field: FormatterCrash
nnbd/duplicates_instance: FormatterCrash
diff --git a/pkg/status_file/pubspec.yaml b/pkg/status_file/pubspec.yaml
index 1536b63..5f9e8e2 100644
--- a/pkg/status_file/pubspec.yaml
+++ b/pkg/status_file/pubspec.yaml
@@ -5,7 +5,8 @@
sdk: "^2.12.0"
dependencies:
path: "^1.4.0"
- args: "^1.4.4"
+ args: ^2.0.0
+
dev_dependencies:
expect:
path: ../expect
diff --git a/pkg/vm/lib/transformations/ffi/native.dart b/pkg/vm/lib/transformations/ffi/native.dart
index 2919bf1..51a4d71 100644
--- a/pkg/vm/lib/transformations/ffi/native.dart
+++ b/pkg/vm/lib/transformations/ffi/native.dart
@@ -118,7 +118,7 @@
ffiReturnType,
handleClass.getThisType(coreTypes, Nullability.nonNullable),
SubtypeCheckMode.ignoringNullabilities)) {
- return objectClass.getThisType(coreTypes, Nullability.nonNullable);
+ return objectClass.getThisType(coreTypes, dartReturnType.nullability);
}
return dartReturnType;
}
@@ -293,7 +293,8 @@
ffiFunctionType.returnType,
handleClass.getThisType(coreTypes, Nullability.nonNullable),
SubtypeCheckMode.ignoringNullabilities)) {
- resultInitializer = AsExpression(invocation, dartFunctionType.returnType);
+ resultInitializer = StaticInvocation(unsafeCastMethod,
+ Arguments([invocation], types: [dartFunctionType.returnType]));
}
// final T #t1 = foo(Pointer.fromAddress(_getNativeField(#t0)));
diff --git a/pkg/vm/pubspec.yaml b/pkg/vm/pubspec.yaml
index 20b2cd7..3ae9534 100644
--- a/pkg/vm/pubspec.yaml
+++ b/pkg/vm/pubspec.yaml
@@ -7,7 +7,7 @@
sdk: '>=2.12.0 <3.0.0'
dependencies:
- args: ^1.4.4
+ args: ^2.0.0
build_integration:
path: ../build_integration
crypto: any
@@ -25,7 +25,3 @@
path: any
test: any
web_socket_channel: any
-
-dependency_overrides:
- front_end:
- path: ../front_end
diff --git a/pkg/vm/test/transformations/ffinative_test.dart b/pkg/vm/test/transformations/ffi_test.dart
similarity index 96%
rename from pkg/vm/test/transformations/ffinative_test.dart
rename to pkg/vm/test/transformations/ffi_test.dart
index a6326a1..cda6097 100644
--- a/pkg/vm/test/transformations/ffinative_test.dart
+++ b/pkg/vm/test/transformations/ffi_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// 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.
diff --git a/pkg/vm/testcases/transformations/ffi/ffinative.dart b/pkg/vm/testcases/transformations/ffi/ffinative.dart
index 347ba00..d2d8c18 100644
--- a/pkg/vm/testcases/transformations/ffi/ffinative.dart
+++ b/pkg/vm/testcases/transformations/ffi/ffinative.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// 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.
diff --git a/pkg/vm/testcases/transformations/ffi/ffinative.dart.expect b/pkg/vm/testcases/transformations/ffi/ffinative.dart.expect
index 557aa76..b33994e 100644
--- a/pkg/vm/testcases/transformations/ffi/ffinative.dart.expect
+++ b/pkg/vm/testcases/transformations/ffi/ffinative.dart.expect
@@ -22,7 +22,7 @@
static final field (self::NativeClassy, ffi::Pointer<ffi::Void>) → void _goodHasReceiverHandleAndPtr$FfiNative$Ptr = ffi::_asFunctionInternal<(self::NativeClassy, ffi::Pointer<ffi::Void>) → void, (ffi::Handle*, ffi::Pointer<ffi::Void*>*) →* ffi::Void*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Handle*, ffi::Pointer<ffi::Void*>*) →* ffi::Void*>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
static final field (self::NativeClassy, self::NativeClassy) → void _goodHasReceiverHandleAndHandle$FfiNative$Ptr = ffi::_asFunctionInternal<(self::NativeClassy, self::NativeClassy) → void, (ffi::Handle*, ffi::Handle*) →* ffi::Void*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Handle*, ffi::Handle*) →* ffi::Void*>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
static final field (ffi::Pointer<ffi::Void>, self::NativeClassy) → void _goodHasReceiverPtrAndHandle$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, self::NativeClassy) → void, (ffi::Pointer<ffi::Void*>*, ffi::Handle*) →* ffi::Void*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void*>*, ffi::Handle*) →* ffi::Void*>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
- static final field (ffi::Pointer<ffi::Void>, core::bool) → core::Object _meh$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, core::bool) → core::Object, (ffi::Pointer<ffi::Void*>*, ffi::Bool*) →* ffi::Handle*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void*>*, ffi::Bool*) →* ffi::Handle*>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
+ static final field (ffi::Pointer<ffi::Void>, core::bool) → core::Object? _meh$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, core::bool) → core::Object?, (ffi::Pointer<ffi::Void*>*, ffi::Bool*) →* ffi::Handle*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void*>*, ffi::Bool*) →* ffi::Handle*>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
static final field (ffi::Pointer<ffi::Void>) → core::bool _blah$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>) → core::bool, (ffi::Pointer<ffi::Void*>*) →* ffi::Bool*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void*>*) →* ffi::Bool*>*>(ffi::_ffi_resolver(#C1, #C4, #C3){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
synthetic constructor •() → self::NativeClassy
: super nat::NativeFieldWrapperClass1::•()
@@ -56,7 +56,7 @@
return block {
final nat::NativeFieldWrapperClass1 #t10 = this;
final core::bool #t11 = blah;
- final core::String? #t12 = self::NativeClassy::_meh$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t10)), #t11){(ffi::Pointer<ffi::Void>, core::bool) → core::Object} as core::String?;
+ final core::String? #t12 = _in::unsafeCast<core::String?>(self::NativeClassy::_meh$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t10)), #t11){(ffi::Pointer<ffi::Void>, core::bool) → core::Object?});
_in::reachabilityFence(#t10);
} =>#t12;
method blah() → core::bool
diff --git a/runtime/bin/dfe.cc b/runtime/bin/dfe.cc
index b6c27fa..701967b 100644
--- a/runtime/bin/dfe.cc
+++ b/runtime/bin/dfe.cc
@@ -231,9 +231,11 @@
void DFE::ReadScript(const char* script_uri,
uint8_t** kernel_buffer,
- intptr_t* kernel_buffer_size) const {
+ intptr_t* kernel_buffer_size,
+ bool decode_uri) const {
int64_t start = Dart_TimelineGetMicros();
- if (!TryReadKernelFile(script_uri, kernel_buffer, kernel_buffer_size)) {
+ if (!TryReadKernelFile(script_uri, kernel_buffer, kernel_buffer_size,
+ decode_uri)) {
return;
}
if (!Dart_IsKernel(*kernel_buffer, *kernel_buffer_size)) {
@@ -274,9 +276,12 @@
///
/// If successful, newly allocated buffer with file contents is returned in
/// [buffer], file contents byte count - in [size].
-static bool TryReadFile(const char* script_uri, uint8_t** buffer,
- intptr_t* size) {
- void* script_file = DartUtils::OpenFileUri(script_uri, false);
+static bool TryReadFile(const char* script_uri,
+ uint8_t** buffer,
+ intptr_t* size,
+ bool decode_uri = true) {
+ void* script_file = decode_uri ? DartUtils::OpenFileUri(script_uri, false)
+ : DartUtils::OpenFile(script_uri, false);
if (script_file == nullptr) {
return false;
}
@@ -417,12 +422,13 @@
bool DFE::TryReadKernelFile(const char* script_uri,
uint8_t** kernel_ir,
- intptr_t* kernel_ir_size) {
+ intptr_t* kernel_ir_size,
+ bool decode_uri) {
*kernel_ir = nullptr;
*kernel_ir_size = -1;
uint8_t* buffer;
- if (!TryReadFile(script_uri, &buffer, kernel_ir_size)) {
+ if (!TryReadFile(script_uri, &buffer, kernel_ir_size, decode_uri)) {
return false;
}
diff --git a/runtime/bin/dfe.h b/runtime/bin/dfe.h
index 649cc32..038bca7 100644
--- a/runtime/bin/dfe.h
+++ b/runtime/bin/dfe.h
@@ -92,7 +92,8 @@
// valid kernel file, false otherwise.
void ReadScript(const char* script_uri,
uint8_t** kernel_buffer,
- intptr_t* kernel_buffer_size) const;
+ intptr_t* kernel_buffer_size,
+ bool decode_uri = true) const;
bool KernelServiceDillAvailable() const;
@@ -103,7 +104,8 @@
// was returned.
static bool TryReadKernelFile(const char* script_uri,
uint8_t** kernel_buffer,
- intptr_t* kernel_buffer_size);
+ intptr_t* kernel_buffer_size,
+ bool decode_uri = true);
// We distinguish between "intent to use Dart frontend" vs "can actually
// use Dart frontend". The method UseDartFrontend tells us about the
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 64f1715..4193965 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -431,8 +431,9 @@
AppSnapshot* app_snapshot = NULL;
// Kernel isolate uses an app snapshot or uses the dill file.
if ((kernel_snapshot_uri != NULL) &&
- (app_snapshot = Snapshot::TryReadAppSnapshot(kernel_snapshot_uri)) !=
- NULL) {
+ (app_snapshot = Snapshot::TryReadAppSnapshot(
+ kernel_snapshot_uri, /*force_load_elf_from_memory=*/false,
+ /*decode_uri=*/false)) != nullptr) {
const uint8_t* isolate_snapshot_data = NULL;
const uint8_t* isolate_snapshot_instructions = NULL;
const uint8_t* ignore_vm_snapshot_data;
@@ -603,8 +604,9 @@
AppSnapshot* app_snapshot = nullptr;
bool isolate_run_app_snapshot = true;
if (dartdev_path.get() != nullptr &&
- (app_snapshot = Snapshot::TryReadAppSnapshot(dartdev_path.get())) !=
- nullptr) {
+ (app_snapshot = Snapshot::TryReadAppSnapshot(
+ dartdev_path.get(), /*force_load_elf_from_memory=*/false,
+ /*decode_uri=*/false)) != nullptr) {
const uint8_t* isolate_snapshot_data = NULL;
const uint8_t* isolate_snapshot_instructions = NULL;
const uint8_t* ignore_vm_snapshot_data;
@@ -613,8 +615,8 @@
&ignore_vm_snapshot_data, &ignore_vm_snapshot_instructions,
&isolate_snapshot_data, &isolate_snapshot_instructions);
isolate_group_data =
- new IsolateGroupData(dartdev_path.get(), packages_config, app_snapshot,
- isolate_run_app_snapshot);
+ new IsolateGroupData(DART_DEV_ISOLATE_NAME, packages_config,
+ app_snapshot, isolate_run_app_snapshot);
isolate_data = new IsolateData(isolate_group_data);
isolate = Dart_CreateIsolateGroup(
DART_DEV_ISOLATE_NAME, DART_DEV_ISOLATE_NAME, isolate_snapshot_data,
@@ -642,7 +644,7 @@
uint8_t* application_kernel_buffer = NULL;
intptr_t application_kernel_buffer_size = 0;
dfe.ReadScript(dartdev_path.get(), &application_kernel_buffer,
- &application_kernel_buffer_size);
+ &application_kernel_buffer_size, /*decode_uri=*/false);
isolate_group_data->SetKernelBufferNewlyOwned(
application_kernel_buffer, application_kernel_buffer_size);
diff --git a/runtime/bin/snapshot_utils.cc b/runtime/bin/snapshot_utils.cc
index cf9589a..754043a 100644
--- a/runtime/bin/snapshot_utils.cc
+++ b/runtime/bin/snapshot_utils.cc
@@ -330,13 +330,19 @@
#endif // defined(DART_PRECOMPILED_RUNTIME)
AppSnapshot* Snapshot::TryReadAppSnapshot(const char* script_uri,
- bool force_load_elf_from_memory) {
- auto decoded_path = File::UriToPath(script_uri);
- if (decoded_path == nullptr) {
- return nullptr;
+ bool force_load_elf_from_memory,
+ bool decode_uri) {
+ Utils::CStringUniquePtr decoded_path(nullptr, std::free);
+ const char* script_name = nullptr;
+ if (decode_uri) {
+ decoded_path = File::UriToPath(script_uri);
+ if (decoded_path == nullptr) {
+ return nullptr;
+ }
+ script_name = decoded_path.get();
+ } else {
+ script_name = script_uri;
}
-
- const char* script_name = decoded_path.get();
if (File::GetType(nullptr, script_name, true) != File::kIsFile) {
// If 'script_name' refers to a pipe, don't read to check for an app
// snapshot since we cannot rewind if it isn't (and couldn't mmap it in
diff --git a/runtime/bin/snapshot_utils.h b/runtime/bin/snapshot_utils.h
index 57d8929..ed96fb1 100644
--- a/runtime/bin/snapshot_utils.h
+++ b/runtime/bin/snapshot_utils.h
@@ -41,7 +41,8 @@
static AppSnapshot* TryReadAppendedAppSnapshotElf(const char* container_path);
static AppSnapshot* TryReadAppSnapshot(
const char* script_uri,
- bool force_load_elf_from_memory = false);
+ bool force_load_elf_from_memory = false,
+ bool decode_uri = true);
static void WriteAppSnapshot(const char* filename,
uint8_t* vm_data_buffer,
intptr_t vm_data_size,
diff --git a/runtime/observatory/tests/service/coverage_closure_call_test.dart b/runtime/observatory/tests/service/coverage_closure_call_test.dart
new file mode 100644
index 0000000..d7566a2
--- /dev/null
+++ b/runtime/observatory/tests/service/coverage_closure_call_test.dart
@@ -0,0 +1,115 @@
+// 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 'package:observatory/service_io.dart';
+import 'package:test/test.dart';
+import 'test_helper.dart';
+import 'service_test_common.dart';
+import 'dart:developer';
+
+String leafFunction(void Function() f) {
+ f();
+ return "some constant";
+}
+
+void testFunction() {
+ debugger();
+ leafFunction(() {});
+ debugger();
+}
+
+bool allRangesCompiled(coverage) {
+ for (int i = 0; i < coverage['ranges'].length; i++) {
+ if (!coverage['ranges'][i]['compiled']) {
+ return false;
+ }
+ }
+ return true;
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ (Isolate isolate) async {
+ var stack = await isolate.getStack();
+
+ // Make sure we are in the right place.
+ expect(stack.type, equals('Stack'));
+ expect(stack['frames'].length, greaterThanOrEqualTo(1));
+ expect(stack['frames'][0].function.name, equals('testFunction'));
+
+ var root = isolate.rootLibrary;
+ await root.load();
+ var func = root.functions.singleWhere((f) => f.name == 'leafFunction');
+ await func.load();
+
+ var expectedRange = {
+ 'scriptIndex': 0,
+ 'startPos': 384,
+ 'endPos': 458,
+ 'compiled': true,
+ 'coverage': {
+ 'hits': [],
+ 'misses': [384, 428]
+ }
+ };
+
+ var params = {
+ 'reports': ['Coverage'],
+ 'scriptId': func.location!.script.id,
+ 'tokenPos': func.location!.tokenPos,
+ 'endTokenPos': func.location!.endTokenPos,
+ 'forceCompile': true
+ };
+ var report = await isolate.invokeRpcNoUpgrade('getSourceReport', params);
+ expect(report['type'], equals('SourceReport'));
+ expect(report['ranges'].length, 1);
+ expect(report['ranges'][0], equals(expectedRange));
+ expect(report['scripts'].length, 1);
+ expect(report['scripts'][0]['uri'],
+ endsWith('coverage_closure_call_test.dart'));
+ },
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ (Isolate isolate) async {
+ var stack = await isolate.getStack();
+
+ // Make sure we are in the right place.
+ expect(stack.type, equals('Stack'));
+ expect(stack['frames'].length, greaterThanOrEqualTo(1));
+ expect(stack['frames'][0].function.name, equals('testFunction'));
+
+ var root = isolate.rootLibrary;
+ await root.load();
+ var func = root.functions.singleWhere((f) => f.name == 'leafFunction');
+ await func.load();
+
+ var expectedRange = {
+ 'scriptIndex': 0,
+ 'startPos': 384,
+ 'endPos': 458,
+ 'compiled': true,
+ 'coverage': {
+ 'hits': [384, 428],
+ 'misses': []
+ }
+ };
+
+ var params = {
+ 'reports': ['Coverage'],
+ 'scriptId': func.location!.script.id,
+ 'tokenPos': func.location!.tokenPos,
+ 'endTokenPos': func.location!.endTokenPos,
+ 'forceCompile': true
+ };
+ var report = await isolate.invokeRpcNoUpgrade('getSourceReport', params);
+ expect(report['type'], equals('SourceReport'));
+ expect(report['ranges'].length, 1);
+ expect(report['ranges'][0], equals(expectedRange));
+ expect(report['scripts'].length, 1);
+ expect(report['scripts'][0]['uri'],
+ endsWith('coverage_closure_call_test.dart'));
+ },
+];
+
+main(args) => runIsolateTests(args, tests, testeeConcurrent: testFunction);
diff --git a/runtime/vm/compiler/backend/block_scheduler.cc b/runtime/vm/compiler/backend/block_scheduler.cc
index 33dae39..7fb1408 100644
--- a/runtime/vm/compiler/backend/block_scheduler.cc
+++ b/runtime/vm/compiler/backend/block_scheduler.cc
@@ -63,7 +63,11 @@
return;
}
Array& edge_counters = Array::Handle();
- edge_counters ^= ic_data_array.At(0);
+ edge_counters ^=
+ ic_data_array.At(Function::ICDataArrayIndices::kEdgeCounters);
+ if (edge_counters.IsNull()) {
+ return;
+ }
auto graph_entry = flow_graph->graph_entry();
BlockEntryInstr* entry = graph_entry->normal_entry();
diff --git a/runtime/vm/compiler/backend/constant_propagator.cc b/runtime/vm/compiler/backend/constant_propagator.cc
index 60fdf3a..50418b8 100644
--- a/runtime/vm/compiler/backend/constant_propagator.cc
+++ b/runtime/vm/compiler/backend/constant_propagator.cc
@@ -758,6 +758,10 @@
// Nothing to do.
}
+void ConstantPropagator::VisitRecordCoverage(RecordCoverageInstr* instr) {
+ // Nothing to do.
+}
+
void ConstantPropagator::VisitOneByteStringFromCharCode(
OneByteStringFromCharCodeInstr* instr) {
const Object& o = instr->char_code()->definition()->constant_value();
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index fa930ed..5aeec58 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -506,6 +506,9 @@
void CreateCommonConstants();
+ const Array& coverage_array() const { return *coverage_array_; }
+ void set_coverage_array(const Array& array) { coverage_array_ = &array; }
+
private:
friend class FlowGraphCompiler; // TODO(ajcbik): restructure
friend class FlowGraphChecker;
@@ -629,6 +632,8 @@
intptr_t inlining_id_;
bool should_print_;
+
+ const Array* coverage_array_ = &Array::empty_array();
};
class LivenessAnalysis : public ValueObject {
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 7f82524..8e7e24d 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -3002,6 +3002,11 @@
return NULL;
}
+Instruction* RecordCoverageInstr::Canonicalize(FlowGraph* flow_graph) {
+ ASSERT(!coverage_array_.IsNull());
+ return coverage_array_.At(coverage_index_) != Smi::New(0) ? nullptr : this;
+}
+
Definition* BoxInstr::Canonicalize(FlowGraph* flow_graph) {
if (input_use_list() == nullptr) {
// Environments can accommodate any representation. No need to box.
@@ -6783,6 +6788,28 @@
return locs;
}
+LocationSummary* RecordCoverageInstr::MakeLocationSummary(Zone* zone,
+ bool opt) const {
+ const intptr_t kNumInputs = 0;
+ const intptr_t kNumTemps = 2;
+ LocationSummary* locs = new (zone)
+ LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_temp(0, Location::RequiresRegister());
+ locs->set_temp(1, Location::RequiresRegister());
+ return locs;
+}
+
+void RecordCoverageInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ const auto array_temp = locs()->temp(0).reg();
+ const auto value_temp = locs()->temp(1).reg();
+
+ __ LoadObject(array_temp, coverage_array_);
+ __ LoadImmediate(value_temp, Smi::RawValue(1));
+ __ StoreFieldToOffset(value_temp, array_temp,
+ Array::element_offset(coverage_index_),
+ compiler::kObjectBytes);
+}
+
#undef Z
Representation FfiCallInstr::representation() const {
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index a6f9d2d..a211039 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -426,6 +426,7 @@
M(RelationalOp, kNoGC) \
M(NativeCall, _) \
M(DebugStepCheck, _) \
+ M(RecordCoverage, kNoGC) \
M(LoadIndexed, kNoGC) \
M(LoadCodeUnits, kNoGC) \
M(StoreIndexed, kNoGC) \
@@ -6017,6 +6018,31 @@
DISALLOW_COPY_AND_ASSIGN(StoreIndexedInstr);
};
+class RecordCoverageInstr : public TemplateInstruction<0, NoThrow> {
+ public:
+ RecordCoverageInstr(const Array& coverage_array,
+ intptr_t coverage_index,
+ const InstructionSource& source)
+ : TemplateInstruction(source),
+ coverage_array_(coverage_array),
+ coverage_index_(coverage_index),
+ token_pos_(source.token_pos) {}
+
+ DECLARE_INSTRUCTION(RecordCoverage)
+
+ virtual TokenPosition token_pos() const { return token_pos_; }
+ virtual bool ComputeCanDeoptimize() const { return false; }
+ virtual bool HasUnknownSideEffects() const { return false; }
+ virtual Instruction* Canonicalize(FlowGraph* flow_graph);
+
+ private:
+ const Array& coverage_array_;
+ const intptr_t coverage_index_;
+ const TokenPosition token_pos_;
+
+ DISALLOW_COPY_AND_ASSIGN(RecordCoverageInstr);
+};
+
// Note overrideable, built-in: value ? false : true.
class BooleanNegateInstr : public TemplateDefinition<1, NoThrow> {
public:
@@ -6164,6 +6190,7 @@
private:
friend class BranchInstr;
friend class IfThenElseInstr;
+ friend class RecordCoverageInstr;
virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
};
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index b16a368..7b9bac9 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -1138,10 +1138,25 @@
return call_hook;
}
+static bool SupportsCoverage() {
+#if defined(PRODUCT)
+ return false;
+#else
+ return !CompilerState::Current().is_aot();
+#endif
+}
+
Fragment BaseFlowGraphBuilder::ClosureCall(TokenPosition position,
intptr_t type_args_len,
intptr_t argument_count,
const Array& argument_names) {
+ Fragment result;
+
+ if (SupportsCoverage()) {
+ const intptr_t coverage_index = GetCoverageIndexFor(position);
+ result <<= new (Z) RecordCoverageInstr(coverage_array(), coverage_index,
+ InstructionSource(position));
+ }
const intptr_t total_count =
(type_args_len > 0 ? 1 : 0) + argument_count +
/*closure (bare instructions) or function (otherwise)*/ 1;
@@ -1150,7 +1165,8 @@
new (Z) ClosureCallInstr(arguments, type_args_len, argument_names,
InstructionSource(position), GetNextDeoptId());
Push(call);
- return Fragment(call);
+ result <<= call;
+ return result;
}
void BaseFlowGraphBuilder::reset_context_depth_for_deopt_id(intptr_t deopt_id) {
@@ -1233,5 +1249,53 @@
return Fragment(instr);
}
+intptr_t BaseFlowGraphBuilder::GetCoverageIndexFor(TokenPosition token_pos) {
+ if (coverage_array_.IsNull()) {
+ // We have not yet created coverage_array, this is the first time
+ // we are building the graph for this function. Collect coverage
+ // positions.
+ for (intptr_t i = 0; i < coverage_array_positions_.length(); i++) {
+ if (coverage_array_positions_.At(i) == token_pos) {
+ return 2 * i + 1;
+ }
+ }
+ const auto index = 2 * coverage_array_positions_.length() + 1;
+ coverage_array_positions_.Add(token_pos);
+ return index;
+ }
+
+ for (intptr_t i = 0; i < coverage_array_.Length(); i += 2) {
+ if (TokenPosition::Deserialize(Smi::Value(
+ static_cast<SmiPtr>(coverage_array_.At(i)))) == token_pos) {
+ return i + 1;
+ }
+ }
+ // Reaching here indicates that the graph is constructed in an unstable way.
+ UNREACHABLE();
+ return 1;
+}
+
+void BaseFlowGraphBuilder::FinalizeCoverageArray() {
+ if (!coverage_array_.IsNull()) {
+ return;
+ }
+
+ if (coverage_array_positions_.is_empty()) {
+ coverage_array_ = Array::empty_array().ptr();
+ return;
+ }
+
+ coverage_array_ =
+ Array::New(coverage_array_positions_.length() * 2, Heap::kOld);
+
+ Smi& value = Smi::Handle();
+ for (intptr_t i = 0; i < coverage_array_positions_.length(); i++) {
+ value = Smi::New(coverage_array_positions_[i].Serialize());
+ coverage_array_.SetAt(2 * i, value);
+ value = Smi::New(0); // no coverage recorded.
+ coverage_array_.SetAt(2 * i + 1, value);
+ }
+}
+
} // namespace kernel
} // namespace dart
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.h b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
index 0a5339f..ee7e7ce 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
@@ -159,7 +159,15 @@
saved_args_desc_array_(
has_saved_args_desc_array()
? Array::ZoneHandle(zone_, function_.saved_args_desc())
- : Object::null_array()) {}
+ : Object::null_array()),
+ coverage_array_(
+ Array::ZoneHandle(parsed_function->function().GetCoverageArray())) {
+ }
+
+ const Array& coverage_array() const { return coverage_array_; }
+
+ intptr_t GetCoverageIndexFor(TokenPosition token_pos);
+ void FinalizeCoverageArray();
Fragment LoadField(const Field& field, bool calls_initializer);
Fragment LoadNativeField(const Slot& native_field,
@@ -496,6 +504,9 @@
const bool inlining_unchecked_entry_;
const Array& saved_args_desc_array_;
+ GrowableArray<TokenPosition> coverage_array_positions_;
+ Array& coverage_array_;
+
friend class StreamingFlowGraphBuilder;
private:
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc
index 6bb19fa..85ba707 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph_test.cc
@@ -333,6 +333,7 @@
kMatchAndMoveCheckNull,
kMatchAndMoveLoadField,
kMoveDebugStepChecks,
+ kMatchAndMoveRecordCoverage,
kMatchAndMoveClosureCall,
kMoveDebugStepChecks,
kMatchReturn,
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 503e051..efd2f8e 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -772,7 +772,12 @@
StreamingFlowGraphBuilder streaming_flow_graph_builder(
this, kernel_data, kernel_data_program_offset);
- return streaming_flow_graph_builder.BuildGraph();
+ auto result = streaming_flow_graph_builder.BuildGraph();
+
+ FinalizeCoverageArray();
+ result->set_coverage_array(coverage_array());
+
+ return result;
}
Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index b750d2d..b85bfec 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -461,11 +461,10 @@
}
}
} else { // not optimized.
- if (function.ic_data_array() == Array::null()) {
- function.SaveICDataMap(
- graph_compiler->deopt_id_to_ic_data(),
- Array::Handle(zone, graph_compiler->edge_counters_array()));
- }
+ function.SaveICDataMap(
+ graph_compiler->deopt_id_to_ic_data(),
+ Array::Handle(zone, graph_compiler->edge_counters_array()),
+ flow_graph->coverage_array());
function.set_unoptimized_code(code);
function.AttachCode(code);
function.SetWasCompiled(true);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index cf8f107..e272c5c 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -9937,25 +9937,37 @@
void Function::SaveICDataMap(
const ZoneGrowableArray<const ICData*>& deopt_id_to_ic_data,
- const Array& edge_counters_array) const {
+ const Array& edge_counters_array,
+ const Array& coverage_array) const {
#if !defined(DART_PRECOMPILED_RUNTIME)
+ // Already installed nothing to do.
+ if (ic_data_array() != Array::null()) {
+ ASSERT(coverage_array.ptr() == GetCoverageArray());
+ return;
+ }
+
// Compute number of ICData objects to save.
- // Store edge counter array in the first slot.
- intptr_t count = 1;
+ intptr_t count = 0;
for (intptr_t i = 0; i < deopt_id_to_ic_data.length(); i++) {
if (deopt_id_to_ic_data[i] != NULL) {
count++;
}
}
- const Array& array = Array::Handle(Array::New(count, Heap::kOld));
- count = 1;
- for (intptr_t i = 0; i < deopt_id_to_ic_data.length(); i++) {
+
+ // Compress sparse deopt_id_to_ic_data mapping into a linear sequence of
+ // ICData objects.
+ const Array& array = Array::Handle(
+ Array::New(ICDataArrayIndices::kFirstICData + count, Heap::kOld));
+ for (intptr_t i = 0, pos = ICDataArrayIndices::kFirstICData;
+ i < deopt_id_to_ic_data.length(); i++) {
if (deopt_id_to_ic_data[i] != NULL) {
ASSERT(i == deopt_id_to_ic_data[i]->deopt_id());
- array.SetAt(count++, *deopt_id_to_ic_data[i]);
+ array.SetAt(pos++, *deopt_id_to_ic_data[i]);
}
}
- array.SetAt(0, edge_counters_array);
+ array.SetAt(ICDataArrayIndices::kEdgeCounters, edge_counters_array);
+ // Preserve coverage_array which is stored early after graph construction.
+ array.SetAt(ICDataArrayIndices::kCoverageData, coverage_array);
set_ic_data_array(array);
#else // DART_PRECOMPILED_RUNTIME
UNREACHABLE();
@@ -9979,7 +9991,7 @@
}
const intptr_t saved_length = saved_ic_data.Length();
ASSERT(saved_length > 0);
- if (saved_length > 1) {
+ if (saved_length > ICDataArrayIndices::kFirstICData) {
const intptr_t restored_length =
ICData::Cast(Object::Handle(zone, saved_ic_data.At(saved_length - 1)))
.deopt_id() +
@@ -9988,7 +10000,7 @@
for (intptr_t i = 0; i < restored_length; i++) {
(*deopt_id_to_ic_data)[i] = NULL;
}
- for (intptr_t i = 1; i < saved_length; i++) {
+ for (intptr_t i = ICDataArrayIndices::kFirstICData; i < saved_length; i++) {
ICData& ic_data = ICData::ZoneHandle(zone);
ic_data ^= saved_ic_data.At(i);
if (clone_ic_data) {
@@ -10005,6 +10017,14 @@
#endif // DART_PRECOMPILED_RUNTIME
}
+ArrayPtr Function::GetCoverageArray() const {
+ const Array& arr = Array::Handle(ic_data_array());
+ if (arr.IsNull()) {
+ return Array::null();
+ }
+ return Array::RawCast(arr.At(ICDataArrayIndices::kCoverageData));
+}
+
void Function::set_ic_data_array(const Array& value) const {
untag()->set_ic_data_array<std::memory_order_release>(value.ptr());
}
@@ -10020,7 +10040,7 @@
ICDataPtr Function::FindICData(intptr_t deopt_id) const {
const Array& array = Array::Handle(ic_data_array());
ICData& ic_data = ICData::Handle();
- for (intptr_t i = 1; i < array.Length(); i++) {
+ for (intptr_t i = ICDataArrayIndices::kFirstICData; i < array.Length(); i++) {
ic_data ^= array.At(i);
if (ic_data.deopt_id() == deopt_id) {
return ic_data.ptr();
@@ -10033,7 +10053,7 @@
ICData::DeoptReasonId reason) {
const Array& array = Array::Handle(ic_data_array());
ICData& ic_data = ICData::Handle();
- for (intptr_t i = 1; i < array.Length(); i++) {
+ for (intptr_t i = ICDataArrayIndices::kFirstICData; i < array.Length(); i++) {
ic_data ^= array.At(i);
if (ic_data.deopt_id() == deopt_id) {
ic_data.AddDeoptReason(reason);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index ad0d7cd..df0932e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3675,16 +3675,31 @@
// Works with map [deopt-id] -> ICData.
void SaveICDataMap(
const ZoneGrowableArray<const ICData*>& deopt_id_to_ic_data,
- const Array& edge_counters_array) const;
+ const Array& edge_counters_array,
+ const Array& coverage_array) const;
// Uses 'ic_data_array' to populate the table 'deopt_id_to_ic_data'. Clone
// ic_data (array and descriptor) if 'clone_ic_data' is true.
void RestoreICDataMap(ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data,
bool clone_ic_data) const;
+ // ic_data_array attached to the function stores edge counters in the
+ // first element, coverage data array in the second element and the rest
+ // are ICData objects.
+ struct ICDataArrayIndices {
+ static constexpr intptr_t kEdgeCounters = 0;
+ static constexpr intptr_t kCoverageData = 1;
+ static constexpr intptr_t kFirstICData = 2;
+ };
+
ArrayPtr ic_data_array() const;
void ClearICDataArray() const;
ICDataPtr FindICData(intptr_t deopt_id) const;
+ // Coverage data array is a list of pairs:
+ // element 2 * i + 0 is token position
+ // element 2 * i + 1 is coverage hit (zero meaning code was not hit)
+ ArrayPtr GetCoverageArray() const;
+
// Sets deopt reason in all ICData-s with given deopt_id.
void SetDeoptReasonForAll(intptr_t deopt_id, ICData::DeoptReasonId reason);
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index cc089f2..5ed79a5 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -29,7 +29,8 @@
return;
}
ASSERT(ic_data_array_.Length() > 0);
- edge_counters_ ^= ic_data_array_.At(0);
+ edge_counters_ ^=
+ ic_data_array_.At(Function::ICDataArrayIndices::kEdgeCounters);
if (edge_counters_.IsNull()) {
return;
}
@@ -98,7 +99,7 @@
ICData* ic_data) {
// ic_data_array is sorted because of how it is constructed in
// Function::SaveICDataMap.
- intptr_t lo = 1;
+ intptr_t lo = Function::ICDataArrayIndices::kFirstICData;
intptr_t hi = ic_data_array.Length() - 1;
while (lo <= hi) {
intptr_t mid = (hi - lo + 1) / 2 + lo;
diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc
index f72a72e..ede8d64 100644
--- a/runtime/vm/source_report.cc
+++ b/runtime/vm/source_report.cc
@@ -263,6 +263,21 @@
coverage[0] = kCoverageMiss;
}
+ auto update_coverage = [&](TokenPosition token_pos, bool was_executed) {
+ if (!token_pos.IsWithin(begin_pos, end_pos)) {
+ return;
+ }
+
+ const intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
+ if (was_executed) {
+ coverage[token_offset] = kCoverageHit;
+ } else {
+ if (coverage[token_offset] == kCoverageNone) {
+ coverage[token_offset] = kCoverageMiss;
+ }
+ }
+ };
+
PcDescriptors::Iterator iter(
descriptors,
UntaggedPcDescriptors::kIcCall | UntaggedPcDescriptors::kUnoptStaticCall);
@@ -272,19 +287,19 @@
const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
if (ic_data != NULL) {
const TokenPosition& token_pos = iter.TokenPos();
- if (!token_pos.IsWithin(begin_pos, end_pos)) {
- // Does not correspond to a valid source position.
- continue;
- }
- intptr_t count = ic_data->AggregateCount();
- intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
- if (count > 0) {
- coverage[token_offset] = kCoverageHit;
- } else {
- if (coverage[token_offset] == kCoverageNone) {
- coverage[token_offset] = kCoverageMiss;
- }
- }
+ update_coverage(token_pos, ic_data->AggregateCount() > 0);
+ }
+ }
+
+ // Merge the coverage from coverage_array attached to the function.
+ const Array& coverage_array = Array::Handle(function.GetCoverageArray());
+ if (!coverage_array.IsNull()) {
+ for (intptr_t i = 0; i < coverage_array.Length(); i += 2) {
+ const TokenPosition token_pos = TokenPosition::Deserialize(
+ Smi::Value(Smi::RawCast(coverage_array.At(i))));
+ const bool was_executed =
+ Smi::Value(Smi::RawCast(coverage_array.At(i + 1))) != 0;
+ update_coverage(token_pos, was_executed);
}
}
diff --git a/runtime/vm/source_report_test.cc b/runtime/vm/source_report_test.cc
index 5934703..00c4c2e 100644
--- a/runtime/vm/source_report_test.cc
+++ b/runtime/vm/source_report_test.cc
@@ -339,7 +339,7 @@
// One range compiled with one hit (helper0).
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":73,\"compiled\":true,"
- "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
+ "\"coverage\":{\"hits\":[0,56],\"misses\":[]}},"
// One range not compiled (helper1).
"{\"scriptIndex\":0,\"startPos\":75,\"endPos\":86,\"compiled\":false},"
@@ -402,7 +402,7 @@
// One range compiled with one hit (helper0).
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":73,\"compiled\":true,"
- "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
+ "\"coverage\":{\"hits\":[0,56],\"misses\":[]}},"
// Nested range compiled (nestedHelper0).
"{\"scriptIndex\":0,\"startPos\":14,\"endPos\":31,\"compiled\":true,"
diff --git a/sdk/lib/_http/http.dart b/sdk/lib/_http/http.dart
index 4193db2..84cfbdf 100644
--- a/sdk/lib/_http/http.dart
+++ b/sdk/lib/_http/http.dart
@@ -4,6 +4,8 @@
library dart._http;
+import 'dart:_internal'
+ show Since, valueOfNonNullableParamWithDefault, HttpStatus;
import 'dart:async';
import 'dart:collection'
show
@@ -15,11 +17,9 @@
UnmodifiableMapView;
import 'dart:convert';
import 'dart:developer' hide log;
-import 'dart:_internal'
- show Since, valueOfNonNullableParamWithDefault, HttpStatus;
+import 'dart:io';
import 'dart:isolate' show Isolate;
import 'dart:math';
-import 'dart:io';
import 'dart:typed_data';
part 'crypto.dart';
@@ -35,35 +35,39 @@
/// A server that delivers content, such as web pages, using the HTTP protocol.
///
-/// The HttpServer is a [Stream] that provides [HttpRequest] objects. Each
-/// HttpRequest has an associated [HttpResponse] object.
-/// The server responds to a request by writing to that HttpResponse object.
-/// The following example shows how to bind an HttpServer to an IPv6
+/// Note: [HttpServer] provides low-level HTTP functionality.
+/// We recommend users evaluate the high-level APIs discussed at
+/// [Write HTTP servers](https://dart.dev/tutorials/server/httpserver) on
+/// [dart.dev](https://dart.dev/).
+///
+/// `HttpServer` is a [Stream] that provides [HttpRequest] objects. Each
+/// `HttpRequest` has an associated [HttpResponse] object.
+/// The server responds to a request by writing to that [HttpResponse] object.
+/// The following example shows how to bind an `HttpServer` to an IPv6
/// [InternetAddress] on port 80 (the standard port for HTTP servers)
/// and how to listen for requests.
/// Port 80 is the default HTTP port. However, on most systems accessing
/// this requires super-user privileges. For local testing consider
/// using a non-reserved port (1024 and above).
///
-/// import 'dart:io';
+/// ```dart
+/// import 'dart:io';
///
-/// main() {
-/// HttpServer
-/// .bind(InternetAddress.anyIPv6, 80)
-/// .then((server) {
-/// server.listen((HttpRequest request) {
-/// request.response.write('Hello, world!');
-/// request.response.close();
-/// });
-/// });
-/// }
+/// Future<void> main() async {
+/// var server = await HttpServer.bind(InternetAddress.anyIPv6, 80);
+/// await server.forEach((HttpRequest request) {
+/// request.response.write('Hello, world!');
+/// request.response.close();
+/// });
+/// }
+/// ```
///
/// Incomplete requests, in which all or part of the header is missing, are
-/// ignored, and no exceptions or HttpRequest objects are generated for them.
-/// Likewise, when writing to an HttpResponse, any [Socket] exceptions are
+/// ignored, and no exceptions or [HttpRequest] objects are generated for them.
+/// Likewise, when writing to an [HttpResponse], any [Socket] exceptions are
/// ignored and any future writes are ignored.
///
-/// The HttpRequest exposes the request headers and provides the request body,
+/// The [HttpRequest] exposes the request headers and provides the request body,
/// if it exists, as a Stream of data. If the body is unread, it is drained
/// when the server writes to the HttpResponse or closes it.
///
@@ -75,62 +79,27 @@
/// chain and the private key are set in the [SecurityContext]
/// object that is passed to [bindSecure].
///
-/// import 'dart:io';
-/// import "dart:isolate";
+/// ```dart
+/// import 'dart:io';
///
-/// main() {
-/// SecurityContext context = new SecurityContext();
-/// var chain =
-/// Platform.script.resolve('certificates/server_chain.pem')
-/// .toFilePath();
-/// var key =
-/// Platform.script.resolve('certificates/server_key.pem')
-/// .toFilePath();
-/// context.useCertificateChain(chain);
-/// context.usePrivateKey(key, password: 'dartdart');
+/// Future<void> main() async {
+/// var chain =
+/// Platform.script.resolve('certificates/server_chain.pem').toFilePath();
+/// var key = Platform.script.resolve('certificates/server_key.pem').toFilePath();
+/// var context = SecurityContext()
+/// ..useCertificateChain(chain)
+/// ..usePrivateKey(key, password: 'dartdart');
+/// var server =
+/// await HttpServer.bindSecure(InternetAddress.anyIPv6, 443, context);
+/// await server.forEach((HttpRequest request) {
+/// request.response.write('Hello, world!');
+/// request.response.close();
+/// });
+/// }
+/// ```
///
-/// HttpServer
-/// .bindSecure(InternetAddress.anyIPv6,
-/// 443,
-/// context)
-/// .then((server) {
-/// server.listen((HttpRequest request) {
-/// request.response.write('Hello, world!');
-/// request.response.close();
-/// });
-/// });
-/// }
-///
-/// The certificates and keys are PEM files, which can be created and
-/// managed with the tools in OpenSSL.
-///
-/// ## Connect to a server socket
-///
-/// You can use the [listenOn] constructor to attach an HTTP server to
-/// a [ServerSocket].
-///
-/// import 'dart:io';
-///
-/// main() {
-/// ServerSocket.bind(InternetAddress.anyIPv6, 80)
-/// .then((serverSocket) {
-/// HttpServer httpserver = new HttpServer.listenOn(serverSocket);
-/// serverSocket.listen((Socket socket) {
-/// socket.write('Hello, client.');
-/// });
-/// });
-/// }
-///
-/// ## Other resources
-///
-/// * HttpServer is a Stream. Refer to the [Stream] class for information
-/// about the streaming qualities of an HttpServer.
-/// Pausing the subscription of the stream, pauses at the OS level.
-///
-/// * The [shelf](https://pub.dev/packages/shelf)
-/// package on pub.dev contains a set of high-level classes that,
-/// together with this class, makes it easy to provide content through HTTP
-/// servers.
+/// The certificates and keys are PEM files, which can be created and
+/// managed with the tools in OpenSSL.
abstract class HttpServer implements Stream<HttpRequest> {
/// Gets and sets the default value of the `Server` header for all responses
/// generated by this [HttpServer].
@@ -206,7 +175,7 @@
/// value of 0 (the default) a reasonable value will be chosen by
/// the system.
///
- /// The optional argument [shared] specifies whether additional HttpServer
+ /// The optional argument [shared] specifies whether additional `HttpServer`
/// objects can bind to the same combination of `address`, `port` and `v6Only`.
/// If `shared` is `true` and more `HttpServer`s from this isolate or other
/// isolates are bound to the port, then the incoming connections will be
@@ -247,7 +216,7 @@
/// certificates, getting them from a [SecurityContext], where they have been
/// set using [SecurityContext.setClientAuthorities].
///
- /// The optional argument [shared] specifies whether additional HttpServer
+ /// The optional argument [shared] specifies whether additional `HttpServer`
/// objects can bind to the same combination of `address`, `port` and `v6Only`.
/// If `shared` is `true` and more `HttpServer`s from this isolate or other
/// isolates are bound to the port, then the incoming connections will be
@@ -727,7 +696,7 @@
/// use code like this:
///
/// HttpClientRequest request = ...;
-/// var v = new HeaderValue("text/plain", {"q": "0.3"});
+/// var v = HeaderValue("text/plain", {"q": "0.3"});
/// request.headers.add(HttpHeaders.acceptHeader, v);
/// request.headers.add(HttpHeaders.acceptHeader, "text/html");
///
@@ -775,6 +744,7 @@
String toString();
}
+/// The [session][HttpRequest.session] of an [HttpRequest].
abstract class HttpSession implements Map {
/// The id of the current session.
String get id;
@@ -949,11 +919,6 @@
/// A server-side object
/// that contains the content of and information about an HTTP request.
///
-/// __Note__: Check out the
-/// [http_server](https://pub.dev/packages/http_server)
-/// package, which makes working with the low-level
-/// dart:io HTTP server subsystem easier.
-///
/// `HttpRequest` objects are generated by an [HttpServer],
/// which listens for HTTP requests on a specific host and port.
/// For each request received, the HttpServer, which is a [Stream],
@@ -1100,7 +1065,7 @@
///
/// HttpResponse response = ...
/// response.headers.contentType
-/// = new ContentType("application", "json", charset: "utf-8");
+/// = ContentType("application", "json", charset: "utf-8");
/// response.write(...); // Strings written will be UTF-8 encoded.
///
/// If no charset is provided the default of ISO-8859-1 (Latin 1) will
@@ -1202,8 +1167,15 @@
HttpConnectionInfo? get connectionInfo;
}
-/// A client that receives content, such as web pages, from
-/// a server using the HTTP protocol.
+/// An HTTP client for communicating with an HTTP server.
+///
+/// Sends HTTP requests to an HTTP server and receives responses.
+/// Maintains state, including session cookies and other cookies,
+/// between multiple requests to the same server.
+///
+/// Note: [HttpClient] provides low-level HTTP functionality.
+/// We recommend users start with more developer-friendly and composable APIs
+/// found in [`package:http`](https://pub.dev/packages/http).
///
/// HttpClient contains a number of methods to send an [HttpClientRequest]
/// to an Http server and receive an [HttpClientResponse] back.
@@ -1223,30 +1195,31 @@
/// the second future, which is returned by close,
/// completes with an [HttpClientResponse] object.
/// This object provides access to the headers and body of the response.
-/// The body is available as a stream implemented by HttpClientResponse.
+/// The body is available as a stream implemented by `HttpClientResponse`.
/// If a body is present, it must be read. Otherwise, it leads to resource
/// leaks. Consider using [HttpClientResponse.drain] if the body is unused.
///
-/// HttpClient client = new HttpClient();
-/// client.getUrl(Uri.parse("http://www.example.com/"))
-/// .then((HttpClientRequest request) {
-/// // Optionally set up headers...
-/// // Optionally write to the request object...
-/// // Then call close.
-/// ...
-/// return request.close();
-/// })
-/// .then((HttpClientResponse response) {
-/// // Process the response.
-/// ...
-/// });
+/// ```dart
+/// var client = HttpClient();
+/// try {
+/// HttpClientRequest request = await client.get('localhost', 80, '/file.txt');
+/// // Optionally set up headers...
+/// // Optionally write to the request object...
+/// HttpClientResponse response = await request.close();
+/// // Process the response
+/// final stringData = await response.transform(utf8.decoder).join();
+/// print(stringData);
+/// } finally {
+/// client.close();
+/// }
+/// ```
///
/// The future for [HttpClientRequest] is created by methods such as
/// [getUrl] and [open].
///
/// ## HTTPS connections
///
-/// An HttpClient can make HTTPS requests, connecting to a server using
+/// An `HttpClient` can make HTTPS requests, connecting to a server using
/// the TLS (SSL) secure networking protocol. Calling [getUrl] with an
/// https: scheme will work automatically, if the server's certificate is
/// signed by a root CA (certificate authority) on the default list of
@@ -1259,7 +1232,7 @@
///
/// ## Headers
///
-/// All HttpClient requests set the following header by default:
+/// All `HttpClient` requests set the following header by default:
///
/// Accept-Encoding: gzip
///
@@ -1270,23 +1243,22 @@
///
/// request.headers.removeAll(HttpHeaders.acceptEncodingHeader)
///
-/// ## Closing the HttpClient
+/// ## Closing the `HttpClient`
///
-/// The HttpClient supports persistent connections and caches network
+/// `HttpClient` supports persistent connections and caches network
/// connections to reuse them for multiple requests whenever
/// possible. This means that network connections can be kept open for
-/// some time after a request has completed. Use HttpClient.close
-/// to force the HttpClient object to shut down and to close the idle
+/// some time after a request has completed. Use [HttpClient.close]
+/// to force the `HttpClient` object to shut down and to close the idle
/// network connections.
///
/// ## Turning proxies on and off
///
-/// By default the HttpClient uses the proxy configuration available
+/// By default the `HttpClient` uses the proxy configuration available
/// from the environment, see [findProxyFromEnvironment]. To turn off
-/// the use of proxies set the [findProxy] property to
-/// `null`.
+/// the use of proxies set the [findProxy] property to `null`.
///
-/// HttpClient client = new HttpClient();
+/// HttpClient client = HttpClient();
/// client.findProxy = null;
abstract class HttpClient {
static const int defaultHttpPort = 80;
@@ -1601,13 +1573,13 @@
/// To activate this way of resolving proxies assign this function to
/// the [findProxy] property on the [HttpClient].
///
- /// HttpClient client = new HttpClient();
+ /// HttpClient client = HttpClient();
/// client.findProxy = HttpClient.findProxyFromEnvironment;
///
/// If you don't want to use the system environment you can use a
/// different one by wrapping the function.
///
- /// HttpClient client = new HttpClient();
+ /// HttpClient client = HttpClient();
/// client.findProxy = (url) {
/// return HttpClient.findProxyFromEnvironment(
/// url, environment: {"http_proxy": ..., "no_proxy": ...});
@@ -1665,9 +1637,9 @@
/// returned `false`
///
/// If the callback returns true, the secure connection is accepted and the
- /// [:Future<HttpClientRequest>:] that was returned from the call making the
+ /// `Future<HttpClientRequest>` that was returned from the call making the
/// request completes with a valid HttpRequest object. If the callback returns
- /// false, the [:Future<HttpClientRequest>:] completes with an exception.
+ /// false, the `Future<HttpClientRequest>` completes with an exception.
///
/// If a bad certificate is received on a connection attempt, the library calls
/// the function that was the value of badCertificateCallback at the time
@@ -1691,8 +1663,8 @@
///
/// To set up a request, set the headers using the headers property
/// provided in this class and write the data to the body of the request.
-/// HttpClientRequest is an [IOSink]. Use the methods from IOSink,
-/// such as writeCharCode(), to write the body of the HTTP
+/// `HttpClientRequest` is an [IOSink]. Use the methods from IOSink,
+/// such as `writeCharCode()`, to write the body of the HTTP
/// request. When one of the IOSink methods is used for the first
/// time, the request header is sent. Calling any methods that
/// change the header after it is sent throws an exception.
@@ -1701,17 +1673,20 @@
/// encoding used is determined from the "charset" parameter of
/// the "Content-Type" header.
///
-/// HttpClientRequest request = ...
-/// request.headers.contentType
-/// = new ContentType("application", "json", charset: "utf-8");
-/// request.write(...); // Strings written will be UTF-8 encoded.
+/// ```dart
+/// HttpClientRequest request = await client.get('localhost', 80, '/file.txt');
+/// request.headers.contentType =
+/// ContentType('application', 'json', charset: 'utf-8');
+/// request.write('text content👍🎯'); // Strings written will be UTF-8 encoded.
+/// ```
///
-/// If no charset is provided the default of ISO-8859-1 (Latin 1) is
-/// be used.
+/// If no charset is provided the default of ISO-8859-1 (Latin 1) is used.
///
-/// HttpClientRequest request = ...
-/// request.headers.add(HttpHeaders.contentTypeHeader, "text/plain");
-/// request.write(...); // Strings written will be ISO-8859-1 encoded.
+/// ```dart
+/// HttpClientRequest request = await client.get('localhost', 80, '/file.txt');
+/// request.headers.add(HttpHeaders.contentTypeHeader, "text/plain");
+/// request.write('blåbærgrød'); // Strings written will be ISO-8859-1 encoded
+/// ```
///
/// An exception is thrown if you use an unsupported encoding and the
/// `write()` method being used takes a string parameter.
@@ -1825,17 +1800,21 @@
/// HTTP response for a client connection.
///
-/// The body of a [HttpClientResponse] object is a
-/// [Stream] of data from the server. Listen to the body to handle
-/// the data and be notified when the entire body is received.
+/// The body of a [HttpClientResponse] object is a [Stream] of data from the
+/// server. Use [Stream] methods like [`transform`][Stream.transform] and
+/// [`join`][Stream.join] to access the data.
///
-/// new HttpClient().get('localhost', 80, '/file.txt')
-/// .then((HttpClientRequest request) => request.close())
-/// .then((HttpClientResponse response) {
-/// response.transform(utf8.decoder).listen((contents) {
-/// // handle data
-/// });
-/// });
+/// ```dart
+/// var client = HttpClient();
+/// try {
+/// HttpClientRequest request = await client.get('localhost', 80, '/file.txt');
+/// HttpClientResponse response = await request.close();
+/// final stringData = await response.transform(utf8.decoder).join();
+/// print(stringData);
+/// } finally {
+/// client.close();
+/// }
+/// ```
abstract class HttpClientResponse implements Stream<List<int>> {
/// Returns the status code.
///
@@ -2008,16 +1987,6 @@
Uri get location;
}
-/// When detaching a socket from either the [:HttpServer:] or the
-/// [:HttpClient:] due to a HTTP connection upgrade there might be
-/// unparsed data already read from the socket. This unparsed data
-/// together with the detached socket is returned in an instance of
-/// this class.
-abstract class DetachedSocket {
- Socket get socket;
- List<int> get unparsedData;
-}
-
class HttpException implements IOException {
final String message;
final Uri? uri;
diff --git a/sdk/lib/_http/overrides.dart b/sdk/lib/_http/overrides.dart
index 5c49590..db464f8 100644
--- a/sdk/lib/_http/overrides.dart
+++ b/sdk/lib/_http/overrides.dart
@@ -26,7 +26,7 @@
/// // Operations will use MyHttpClient instead of the real HttpClient
/// // implementation whenever HttpClient is used.
/// ...
-/// }, createHttpClient: (SecurityContext c) => new MyHttpClient(c));
+/// }, createHttpClient: (SecurityContext c) => MyHttpClient(c));
/// }
/// ```
abstract class HttpOverrides {
diff --git a/sdk/lib/cli/cli.dart b/sdk/lib/cli/cli.dart
index 223dd68..f43efeb 100644
--- a/sdk/lib/cli/cli.dart
+++ b/sdk/lib/cli/cli.dart
@@ -2,8 +2,14 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/// Utilities for building CLI apps.
+///
+/// ## Deprecation notice
+///
+/// The functionality of this library is incomplete and may be removed in a
+/// later version. See [waitFor] for details.
+///
/// {@category VM}
-/// {@nodoc}
@Deprecated(
"The functionality of this library is incomplete and may be removed in a later version")
library dart.cli;
diff --git a/sdk/lib/cli/wait_for.dart b/sdk/lib/cli/wait_for.dart
index 29e5386..2aa8ff8 100644
--- a/sdk/lib/cli/wait_for.dart
+++ b/sdk/lib/cli/wait_for.dart
@@ -69,7 +69,32 @@
* Suspends the stack, runs microtasks, and handles incoming events until
* [future] completes.
*
- * WARNING: EXPERIMENTAL. USE AT YOUR OWN RISK.
+ * ## Deprecation notice
+ *
+ * The `waitFor` feature is deprecated.
+ * The feature was intended to solve a particular problem for existing code,
+ * a problem introduced by a breaking change to the platform libraries.
+ * The `waitFor` function is not suitable for general use.
+ * The feature has shortcomings that can affect other code
+ * running in the same isolate, including:
+ * * A function call that looks synchronous may cause other asynchronous
+ * events to run before it returns.
+ * This is something synchronous code can usually assume not to happen,
+ * and some code may have been written to take advantage of that
+ * assumed behavior. Such code can fail in unexpected ways.
+ * * Multiple nested calls to `waitFor` may block each other
+ * since the most recent call always needs to complete
+ * before any other call can complete.
+ * Judicious use of `waitFor` is necessary to avoid unexpected deadlocks
+ * which wouldn't happen if using `await` instead.
+ * If more than one library in the same program is using `waitFor`,
+ * then it's hard to avoid or control whether such blocking will happen.
+ *
+ * The feature is not actively maintained.
+ * It will remain as-is to support the original problem it was added to solve,
+ * at least until that problem can be solved in some other way.
+ *
+ * ## Call semantics
*
* This call does the following:
* - While [future] is not completed:
@@ -111,30 +136,6 @@
* Please be aware that nesting calls to [waitFor] can lead to deadlock if
* subsequent calls block waiting for a condition that is only satisfied when
* an earlier call returns.
- *
- * **NOTICE**
- * The `waitFor` feature is deprecated.
- * The feature was intended to solve a particular problem for existing code,
- * a problem introduced by a breaking change to the platform libraries.
- * The `waitFor` function is not suitable for general use.
- * The feature has shortcomings that can affect other code
- * running in the same isolate, including:
- * * A function call that looks synchronous may cause other asynchronous
- * events to run before it returns.
- * This is something synchronous code can usually assume not to happen,
- * and some code may have been written to take advantage of that
- * assumed behavior. Such code can fail in unexpected ways.
- * * Multiple nested calls to `waitFor` may block each other
- * since the most recent call always needs to complete
- * before any other call can complete.
- * Judicious use of `waitFor` is necessary to avoid unexpected deadlocks
- * which wouldn't happen if using `await` instead.
- * If more than one library in the same program is using `waitFor`,
- * then it's hard to avoid or control whether such blocking will happen.
- *
- * The feature is not actively maintained.
- * It will remain as-is to support the original problem it was added to solve,
- * at least until that problem can be solved in some other way.
*/
@Deprecated(
"This functionality is incomplete and may be removed in a later version")
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index f504810..dbecc26 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -62,16 +62,17 @@
/// ```
/// ## HttpServer and HttpClient
///
-/// The classes [HttpServer] and [HttpClient]
-/// provide HTTP server and HTTP client functionality.
+/// The classes [HttpClient] and [HttpServer] provide low-level HTTP
+/// functionality.
///
-/// The [HttpServer] class provides the basic functionality for
-/// implementing an HTTP server.
-/// For some higher-level building-blocks, we recommend that you try
-/// the [shelf](https://pub.dev/packages/shelf)
-/// pub package, which contains
-/// a set of high-level classes that, together with the [HttpServer] class
-/// in this library, make it easier to implement HTTP servers.
+/// Instead of using these classes directly, consider using more
+/// developer-friendly and composable APIs found in packages.
+///
+/// For HTTP clients, look at [`package:http`](https://pub.dev/packages/http).
+///
+/// For HTTP servers, look at
+/// [Write HTTP servers](https://dart.dev/tutorials/server/httpserver) on
+/// [dart.dev](https://dart.dev/).
///
/// ## Process
///
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index f8283f9..d439fd4 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -582,7 +582,10 @@
/// If the port is a native port -- one provided by [ReceivePort.sendPort] or
/// [RawReceivePort.sendPort] -- the system may be able to send this final
/// message more efficiently than normal port communication between live
- /// isolates.
+ /// isolates. In these cases this final message object graph will be
+ /// reassigned to the receiving isolate without copying. Further, the
+ /// receiving isolate will in most cases be able to receive the message
+ /// in constant time.
external static Never exit([SendPort? finalMessagePort, Object? message]);
}
diff --git a/tools/VERSION b/tools/VERSION
index ea1d582..f8a05d9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 260
+PRERELEASE 261
PRERELEASE_PATCH 0
\ No newline at end of file