Version 2.14.0-129.0.dev
Merge commit '6f2eeae1a4c632a569ccb1858c8b585b1c0b0cd3' into 'dev'
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
index 9d6fe11..8f88db8 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
@@ -254,6 +254,20 @@
// Otherwise call the map function
: f(result);
}
+
+ /// Converts a [List<ErrorOr<T>>] into an [ErrorOr<List<T>>]. If any of the
+ /// items represents an error, that error will be returned. Otherwise, the
+ /// list of results will be returned in a success response.
+ static ErrorOr<List<T>> all<T>(Iterable<ErrorOr<T>> items) {
+ final results = <T>[];
+ for (final item in items) {
+ if (item.isError) {
+ return failure(item);
+ }
+ results.add(item.result);
+ }
+ return success(results);
+ }
}
/// A base class containing the fields common to RequestMessage and
diff --git a/pkg/analysis_server/lib/src/computer/computer_selection_ranges.dart b/pkg/analysis_server/lib/src/computer/computer_selection_ranges.dart
new file mode 100644
index 0000000..4f4b6b3
--- /dev/null
+++ b/pkg/analysis_server/lib/src/computer/computer_selection_ranges.dart
@@ -0,0 +1,55 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+
+/// Computes selection ranges for a specific offset of a Dart [CompilationUnit].
+///
+/// Select ranges support IDE functionality for "expand range" to increase the
+/// selection based on the syntax node of the language.
+class DartSelectionRangeComputer {
+ final CompilationUnit _unit;
+ final int _offset;
+ final _selectionRanges = <SelectionRange>[];
+
+ DartSelectionRangeComputer(this._unit, this._offset);
+
+ /// Returns selection ranges for nodes containing [_offset], starting with the
+ /// closest working up to the outer-most node.
+ List<SelectionRange> compute() {
+ var node = NodeLocator(_offset).searchWithin(_unit);
+ if (node == null) {
+ return [];
+ }
+
+ while (node != null && node != _unit) {
+ _recordRange(node);
+ node = node.parent;
+ }
+
+ return _selectionRanges;
+ }
+
+ /// Record the range for [node] if it is not the same as the last-recorded
+ /// range.
+ void _recordRange(AstNode node) {
+ // Ignore this node if its range is the same as the last one.
+ if (_selectionRanges.isNotEmpty) {
+ final last = _selectionRanges.last;
+ if (node.offset == last.offset && node.length == last.length) {
+ return;
+ }
+ }
+
+ _selectionRanges.add(SelectionRange(node.offset, node.length));
+ }
+}
+
+class SelectionRange {
+ final int offset;
+ final int length;
+
+ SelectionRange(this.offset, this.length);
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
new file mode 100644
index 0000000..193002f
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
@@ -0,0 +1,84 @@
+// 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/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/computer/computer_selection_ranges.dart'
+ hide SelectionRange;
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+import 'package:analysis_server/src/lsp/mapping.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/source/line_info.dart';
+
+class SelectionRangeHandler
+ extends MessageHandler<SelectionRangeParams, List<SelectionRange>?> {
+ SelectionRangeHandler(LspAnalysisServer server) : super(server);
+ @override
+ Method get handlesMessage => Method.textDocument_selectionRange;
+
+ @override
+ LspJsonHandler<SelectionRangeParams> get jsonHandler =>
+ SelectionRangeParams.jsonHandler;
+
+ @override
+ Future<ErrorOr<List<SelectionRange>?>> handle(
+ SelectionRangeParams params, CancellationToken token) async {
+ if (!isDartDocument(params.textDocument)) {
+ return success(null);
+ }
+
+ final path = pathOfDoc(params.textDocument);
+ return path.mapResult((path) async {
+ final lineInfo = server.getLineInfo(path);
+ // If there is no lineInfo, the request cannot be translated from LSP
+ // line/col to server offset/length.
+ if (lineInfo == null) {
+ return success(null);
+ }
+
+ final unit = requireUnresolvedUnit(path);
+ final positions = params.positions;
+ final offsets = await unit.mapResult((unit) =>
+ ErrorOr.all(positions.map((pos) => toOffset(unit.lineInfo, pos))));
+ final allRanges = await offsets.mapResult((offsets) =>
+ success(_getSelectionRangesForOffsets(offsets, unit, lineInfo)));
+
+ return allRanges;
+ });
+ }
+
+ SelectionRange _getSelectionRangesForOffset(
+ CompilationUnit unit, LineInfo lineInfo, int offset) {
+ final computer = DartSelectionRangeComputer(unit, offset);
+ final ranges = computer.compute();
+ // Loop through the items starting at the end (the outermost range), using
+ // each item as the parent for the next item.
+ SelectionRange? last;
+ for (var i = ranges.length - 1; i >= 0; i--) {
+ final range = ranges[i];
+ last = SelectionRange(
+ range: toRange(lineInfo, range.offset, range.length),
+ parent: last,
+ );
+ }
+
+ // It's not clear how to respond if a subset of the results
+ // do not have results, so for now if the list is empty just return a single
+ // range that is exactly the same as the position.
+ // TODO(dantup): Update this based on the response to
+ // https://github.com/microsoft/language-server-protocol/issues/1270
+
+ return last ?? SelectionRange(range: toRange(lineInfo, offset, 0));
+ }
+
+ List<SelectionRange> _getSelectionRangesForOffsets(
+ List<int> offsets, ErrorOr<ParsedUnitResult> unit, LineInfo lineInfo) {
+ return offsets
+ .map((offset) =>
+ _getSelectionRangesForOffset(unit.result.unit, lineInfo, offset))
+ .toList();
+ }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
index c8b201d..c0e413d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
@@ -29,6 +29,7 @@
import 'package:analysis_server/src/lsp/handlers/handler_initialized.dart';
import 'package:analysis_server/src/lsp/handlers/handler_references.dart';
import 'package:analysis_server/src/lsp/handlers/handler_rename.dart';
+import 'package:analysis_server/src/lsp/handlers/handler_select_range.dart';
import 'package:analysis_server/src/lsp/handlers/handler_semantic_tokens.dart';
import 'package:analysis_server/src/lsp/handlers/handler_shutdown.dart';
import 'package:analysis_server/src/lsp/handlers/handler_signature_help.dart';
@@ -103,6 +104,7 @@
registerHandler(WorkspaceDidChangeConfigurationMessageHandler(server));
registerHandler(ReanalyzeHandler(server));
registerHandler(WillRenameFilesHandler(server));
+ registerHandler(SelectionRangeHandler(server));
registerHandler(SemanticTokensFullHandler(server));
registerHandler(SemanticTokensRangeHandler(server));
}
diff --git a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
index 65af61f..ca0b352 100644
--- a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
+++ b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
@@ -37,6 +37,7 @@
Method.textDocument_codeAction,
Method.textDocument_rename,
Method.textDocument_foldingRange,
+ Method.textDocument_selectionRange,
// workspace.fileOperations covers all file operation methods but we only
// support this one.
Method.workspace_willRenameFiles,
@@ -92,6 +93,9 @@
bool get rename =>
_capabilities.textDocument?.rename?.dynamicRegistration ?? false;
+ bool get selectionRange =>
+ _capabilities.textDocument?.selectionRange?.dynamicRegistration ?? false;
+
bool get semanticTokens =>
_capabilities.textDocument?.semanticTokens?.dynamicRegistration ?? false;
@@ -231,6 +235,10 @@
FoldingRangeRegistrationOptions>.t1(
true,
),
+ selectionRangeProvider: dynamicRegistrations.selectionRange
+ ? null
+ : Either3<bool, SelectionRangeOptions,
+ SelectionRangeRegistrationOptions>.t1(true),
semanticTokensProvider: dynamicRegistrations.semanticTokens
? null
: Either2<SemanticTokensOptions,
@@ -457,6 +465,13 @@
Method.workspace_didChangeConfiguration,
);
register(
+ dynamicRegistrations.selectionRange,
+ Method.textDocument_selectionRange,
+ SelectionRangeRegistrationOptions(
+ documentSelector: [dartFiles],
+ ),
+ );
+ register(
dynamicRegistrations.semanticTokens,
CustomMethods.semanticTokenDynamicRegistration,
SemanticTokensRegistrationOptions(
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index bf400ba..2fb7918 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -201,7 +201,7 @@
final crashReportSender =
CrashReportSender.prod(crashProductId, shouldSendCallback);
- if (telemetry.SHOW_ANALYTICS_UI) {
+ if (telemetry.showAnalyticsUI) {
if (results.wasParsed(ANALYTICS_FLAG)) {
analytics.enabled = results[ANALYTICS_FLAG];
print(telemetry.createAnalyticsStatusMessage(analytics.enabled));
@@ -537,7 +537,7 @@
print('Supported flags are:');
print(parser.usage);
- if (telemetry.SHOW_ANALYTICS_UI) {
+ if (telemetry.showAnalyticsUI) {
// Print analytics status and information.
if (fromHelp) {
print('');
@@ -648,11 +648,11 @@
//
parser.addFlag(ANALYTICS_FLAG,
help: 'enable or disable sending analytics information to Google',
- hide: !telemetry.SHOW_ANALYTICS_UI);
+ hide: !telemetry.showAnalyticsUI);
parser.addFlag(SUPPRESS_ANALYTICS_FLAG,
negatable: false,
help: 'suppress analytics for this session',
- hide: !telemetry.SHOW_ANALYTICS_UI);
+ hide: !telemetry.showAnalyticsUI);
//
// Hidden; these are for internal development.
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index cdc4cc8..e7eb40b 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -191,6 +191,7 @@
expect(initResult.capabilities.foldingRangeProvider, isNotNull);
expect(initResult.capabilities.workspace!.fileOperations!.willRename,
equals(ServerCapabilitiesComputer.fileOperationRegistrationOptions));
+ expect(initResult.capabilities.selectionRangeProvider, isNotNull);
expect(initResult.capabilities.semanticTokensProvider, isNotNull);
expect(didGetRegisterCapabilityRequest, isFalse);
@@ -247,6 +248,7 @@
expect(initResult.capabilities.renameProvider, isNull);
expect(initResult.capabilities.foldingRangeProvider, isNull);
expect(initResult.capabilities.workspace!.fileOperations, isNull);
+ expect(initResult.capabilities.selectionRangeProvider, isNull);
expect(initResult.capabilities.semanticTokensProvider, isNull);
// Ensure all expected dynamic registrations.
diff --git a/pkg/analysis_server/test/lsp/selection_range_test.dart b/pkg/analysis_server/test/lsp/selection_range_test.dart
new file mode 100644
index 0000000..2a4da46
--- /dev/null
+++ b/pkg/analysis_server/test/lsp/selection_range_test.dart
@@ -0,0 +1,117 @@
+// 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/lsp_protocol/protocol_generated.dart';
+import 'package:analyzer/source/line_info.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'server_abstract.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(SelectionRangeTest);
+ });
+}
+
+/// Additional tests are in
+///
+/// test/src/computer/selection_range_computer_test.dart
+@reflectiveTest
+class SelectionRangeTest extends AbstractLspAnalysisServerTest {
+ Future<void> test_multiple() async {
+ final content = '''
+class Foo {
+ void a() { /*1*/ }
+ void b() { /*2*/ }
+}
+''';
+
+ await initialize();
+ await openFile(mainFileUri, content);
+ final lineInfo = LineInfo.fromContent(content);
+
+ // Send a request for two positions.
+ final regions = await getSelectionRanges(mainFileUri, [
+ positionFromOffset(content.indexOf('/*1*/'), content),
+ positionFromOffset(content.indexOf('/*2*/'), content),
+ ]);
+ expect(regions!.length, equals(2));
+ final firstTexts =
+ _getSelectionRangeText(lineInfo, content, regions[0]).toList();
+ final secondTexts =
+ _getSelectionRangeText(lineInfo, content, regions[1]).toList();
+
+ expect(
+ firstTexts,
+ equals([
+ '{ /*1*/ }',
+ 'void a() { /*1*/ }',
+ content.trim(), // Whole content minus the trailing newline
+ ]));
+ expect(
+ secondTexts,
+ equals([
+ '{ /*2*/ }',
+ 'void b() { /*2*/ }',
+ content.trim(), // Whole content minus the trailing newline
+ ]));
+ }
+
+ Future<void> test_single() async {
+ final content = '''
+class Foo<T> {
+ void a(String b) {
+ print((1 ^+ 2) * 3);
+ }
+}
+''';
+ final contentWithoutMarker = withoutMarkers(content);
+
+ await initialize();
+ await openFile(mainFileUri, contentWithoutMarker);
+ final lineInfo = LineInfo.fromContent(contentWithoutMarker);
+
+ // The returned List corresponds to the input list of positions, and not
+ // the set of ranges - each range within that list has a (recusrive) parent
+ // to walk up all ranges for that position.
+ final regions =
+ await getSelectionRanges(mainFileUri, [positionFromMarker(content)]);
+ expect(regions!.length, equals(1)); // Only one position was sent.
+ final regionTexts =
+ _getSelectionRangeText(lineInfo, contentWithoutMarker, regions.first)
+ .toList();
+
+ expect(
+ regionTexts,
+ equals([
+ '1 + 2',
+ '(1 + 2)',
+ '(1 + 2) * 3',
+ '((1 + 2) * 3)',
+ 'print((1 + 2) * 3)',
+ 'print((1 + 2) * 3);',
+ '{\n print((1 + 2) * 3);\n }',
+ 'void a(String b) {\n print((1 + 2) * 3);\n }',
+ 'class Foo<T> {\n void a(String b) {\n print((1 + 2) * 3);\n }\n}',
+ ]));
+ }
+
+ Iterable<String> _getSelectionRangeText(
+ LineInfo lineInfo, String content, SelectionRange range) sync* {
+ yield _rangeOfText(lineInfo, content, range.range);
+ final parent = range.parent;
+ if (parent != null) {
+ yield* _getSelectionRangeText(lineInfo, content, parent);
+ }
+ }
+
+ String _rangeOfText(LineInfo lineInfo, String content, Range range) {
+ final startPos = range.start;
+ final endPos = range.end;
+ final start = lineInfo.getOffsetOfLine(startPos.line) + startPos.character;
+ final end = lineInfo.getOffsetOfLine(endPos.line) + endPos.character;
+ return content.substring(start, end);
+ }
+}
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 4bdc585..78b1ba8 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -254,6 +254,7 @@
'codeAction': {'dynamicRegistration': true},
'rename': {'dynamicRegistration': true},
'foldingRange': {'dynamicRegistration': true},
+ 'selectionRange': {'dynamicRegistration': true},
'semanticTokens': SemanticTokensClientCapabilities(
dynamicRegistration: true,
requests: SemanticTokensClientCapabilitiesRequests(),
@@ -1134,6 +1135,18 @@
return resolveCompletion(completion);
}
+ Future<List<SelectionRange>?> getSelectionRanges(
+ Uri uri, List<Position> positions) {
+ final request = makeRequest(
+ Method.textDocument_selectionRange,
+ SelectionRangeParams(
+ textDocument: TextDocumentIdentifier(uri: uri.toString()),
+ positions: positions),
+ );
+ return expectSuccessfulResponseTo(
+ request, _fromJsonList(SelectionRange.fromJson));
+ }
+
Future<SemanticTokens> getSemanticTokens(Uri uri) {
final request = makeRequest(
Method.textDocument_semanticTokens_full,
diff --git a/pkg/analysis_server/test/lsp/test_all.dart b/pkg/analysis_server/test/lsp/test_all.dart
index dd27eb3..fbdd56c 100644
--- a/pkg/analysis_server/test/lsp/test_all.dart
+++ b/pkg/analysis_server/test/lsp/test_all.dart
@@ -35,6 +35,7 @@
import 'reanalyze_test.dart' as reanalyze;
import 'references_test.dart' as references;
import 'rename_test.dart' as rename;
+import 'selection_range_test.dart' as selection_range;
import 'semantic_tokens_test.dart' as semantic_tokens;
import 'server_test.dart' as server;
import 'signature_help_test.dart' as signature_help;
@@ -76,6 +77,7 @@
reanalyze.main();
references.main();
rename.main();
+ selection_range.main();
semantic_tokens.main();
server.main();
signature_help.main();
diff --git a/pkg/analysis_server/test/src/computer/selection_range_computer_test.dart b/pkg/analysis_server/test/src/computer/selection_range_computer_test.dart
new file mode 100644
index 0000000..cbb6cf8
--- /dev/null
+++ b/pkg/analysis_server/test/src/computer/selection_range_computer_test.dart
@@ -0,0 +1,212 @@
+// 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/computer/computer_selection_ranges.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../abstract_context.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(SelectionRangeComputerTest);
+ });
+}
+
+@reflectiveTest
+class SelectionRangeComputerTest extends AbstractContextTest {
+ late String sourcePath;
+
+ @override
+ void setUp() {
+ super.setUp();
+ sourcePath = convertPath('/home/test/lib/test.dart');
+ }
+
+ Future<void> test_arguments() async {
+ final content = '''
+class Foo {
+ Foo({String arg1});
+}
+final foo = Foo(arg1: "test");
+''';
+ final offset = content.indexOf('test');
+
+ final regions = await _computeSelectionRanges(content, offset);
+ _expectRegions(
+ regions,
+ content,
+ [
+ '"test"',
+ 'arg1: "test"',
+ '(arg1: "test")',
+ 'Foo(arg1: "test")',
+ 'foo = Foo(arg1: "test")',
+ 'final foo = Foo(arg1: "test")',
+ 'final foo = Foo(arg1: "test");',
+ ],
+ );
+ }
+
+ Future<void> test_class_definition() async {
+ final content = 'class Foo<T> {}';
+ final offset = 0;
+
+ final regions = await _computeSelectionRanges(content, offset);
+ _expectRegions(regions, content, ['class Foo<T> {}']);
+ }
+
+ Future<void> test_class_fields() async {
+ final content = '''
+class Foo<T> {
+ String a = 'test';
+}
+''';
+ final offset = content.indexOf('String');
+
+ final regions = await _computeSelectionRanges(content, offset);
+ _expectRegions(
+ regions,
+ content,
+ [
+ 'String',
+ "String a = 'test'",
+ "String a = 'test';",
+ "class Foo<T> {\n String a = 'test';\n}",
+ ],
+ );
+ }
+
+ Future<void> test_constructorCall() async {
+ final content = '''
+class Foo {
+ Foo(String b);
+}
+final foo = Foo("test");
+''';
+ final offset = content.indexOf('test');
+
+ final regions = await _computeSelectionRanges(content, offset);
+ _expectRegions(
+ regions,
+ content,
+ [
+ '"test"',
+ '("test")',
+ 'Foo("test")',
+ 'foo = Foo("test")',
+ 'final foo = Foo("test")',
+ 'final foo = Foo("test");',
+ ],
+ );
+ }
+
+ Future<void> test_method() async {
+ final content = '''
+class Foo<T> {
+ void a(String b) {
+ print((1 + 2) * 3);
+ }
+}
+''';
+ final offset = content.indexOf('+');
+
+ final regions = await _computeSelectionRanges(content, offset);
+ _expectRegions(
+ regions,
+ content,
+ [
+ '1 + 2',
+ '(1 + 2)',
+ '(1 + 2) * 3',
+ '((1 + 2) * 3)',
+ 'print((1 + 2) * 3)',
+ 'print((1 + 2) * 3);',
+ '{\n print((1 + 2) * 3);\n }',
+ 'void a(String b) {\n print((1 + 2) * 3);\n }',
+ 'class Foo<T> {\n void a(String b) {\n print((1 + 2) * 3);\n }\n}',
+ ],
+ );
+ }
+
+ Future<void> test_methodLambda() async {
+ final content = '''
+class Foo<T> {
+ void a(String b) => print((1 + 2) * 3);
+}
+''';
+ final offset = content.indexOf('+');
+
+ final regions = await _computeSelectionRanges(content, offset);
+ _expectRegions(
+ regions,
+ content,
+ [
+ '1 + 2',
+ '(1 + 2)',
+ '(1 + 2) * 3',
+ '((1 + 2) * 3)',
+ 'print((1 + 2) * 3)',
+ '=> print((1 + 2) * 3);',
+ 'void a(String b) => print((1 + 2) * 3);',
+ 'class Foo<T> {\n void a(String b) => print((1 + 2) * 3);\n}',
+ ],
+ );
+ }
+
+ Future<void> test_topLevelFunction() async {
+ final content = '''
+void a(String b) {
+ print((1 + 2) * 3);
+}
+''';
+ final offset = content.indexOf('+');
+
+ final regions = await _computeSelectionRanges(content, offset);
+ _expectRegions(
+ regions,
+ content,
+ [
+ '1 + 2',
+ '(1 + 2)',
+ '(1 + 2) * 3',
+ '((1 + 2) * 3)',
+ 'print((1 + 2) * 3)',
+ 'print((1 + 2) * 3);',
+ '{\n print((1 + 2) * 3);\n}',
+ '(String b) {\n print((1 + 2) * 3);\n}',
+ 'void a(String b) {\n print((1 + 2) * 3);\n}',
+ ],
+ );
+ }
+
+ Future<void> test_whitespace() async {
+ final content = ' class Foo {}';
+ final offset = 0;
+
+ final regions = await _computeSelectionRanges(content, offset);
+ expect(regions, isEmpty);
+ }
+
+ Future<List<SelectionRange>?> _computeSelectionRanges(
+ String sourceContent, int offset) async {
+ newFile(sourcePath, content: sourceContent);
+ var result =
+ await session.getResolvedUnit2(sourcePath) as ResolvedUnitResult;
+ var computer = DartSelectionRangeComputer(result.unit!, offset);
+ return computer.compute();
+ }
+
+ /// Checks the text of [regions] against [expected].
+ void _expectRegions(
+ List<SelectionRange>? regions, String content, List<String> expected) {
+ final actual = regions!
+ .map((region) =>
+ content.substring(region.offset, region.offset + region.length))
+ .toList();
+
+ expect(actual, equals(expected));
+ }
+}
diff --git a/pkg/analysis_server/test/src/computer/test_all.dart b/pkg/analysis_server/test/src/computer/test_all.dart
index 1a04173..6f67c7a 100644
--- a/pkg/analysis_server/test/src/computer/test_all.dart
+++ b/pkg/analysis_server/test/src/computer/test_all.dart
@@ -10,6 +10,7 @@
import 'import_elements_computer_test.dart' as import_elements_computer;
import 'imported_elements_computer_test.dart' as imported_elements_computer;
import 'outline_computer_test.dart' as outline_computer;
+import 'selection_range_computer_test.dart' as selection_range;
void main() {
defineReflectiveSuite(() {
@@ -19,5 +20,6 @@
import_elements_computer.main();
imported_elements_computer.main();
outline_computer.main();
+ selection_range.main();
});
}
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index e70af29..1ef02d9 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -89,6 +89,7 @@
| textDocument/references | ✅ | ✅ | | ✅ | ✅ |
| textDocument/documentHighlight | ✅ | ✅ | | ✅ | ✅ |
| textDocument/documentSymbol | ✅ | ✅ | | ✅ | ✅ |
+| textDocument/selectionRanges | ✅ | ✅ | | ✅ | ✅ |
| textDocument/codeAction (sortMembers) | ✅ | ✅ | | ✅ | ✅ |
| textDocument/codeAction (organiseImports) | ✅ | ✅ | | ✅ | ✅ |
| textDocument/codeAction (refactors) | ✅ | ✅ | | ✅ | ✅ |
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index edfcd2e..596c1b6 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -601,6 +601,10 @@
/// Return `true` if this element has an annotation of the form `@sealed`.
bool get hasSealed;
+ /// Return `true` if this element has an annotation of the form `@useResult`
+ /// or `@UseResult('..')`.
+ bool get hasUseResult;
+
/// Return `true` if this element has an annotation of the form
/// `@visibleForTemplate`.
bool get hasVisibleForTemplate;
@@ -807,6 +811,10 @@
/// intended to be used as an annotation.
bool get isTarget;
+ /// Return `true` if this annotation marks the associated returned element as
+ /// requiring use.
+ bool get isUseResult;
+
/// Return `true` if this annotation marks the associated member as being
/// visible for template files.
bool get isVisibleForTemplate;
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index a0f2061..c77e160 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -607,6 +607,8 @@
HintCode.UNUSED_IMPORT,
HintCode.UNUSED_LABEL,
HintCode.UNUSED_LOCAL_VARIABLE,
+ HintCode.UNUSED_RESULT,
+ HintCode.UNUSED_RESULT_WITH_MESSAGE,
HintCode.UNUSED_SHOWN_NAME,
LanguageCode.IMPLICIT_DYNAMIC_FIELD,
LanguageCode.IMPLICIT_DYNAMIC_FUNCTION,
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 5f12fdb..daea242 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -80,7 +80,7 @@
/// TODO(scheglov) Clean up the list of implicitly analyzed files.
class AnalysisDriver implements AnalysisDriverGeneric {
/// The version of data format, should be incremented on every format change.
- static const int DATA_VERSION = 137;
+ static const int DATA_VERSION = 138;
/// The length of the list returned by [_computeDeclaredVariablesSignature].
static const int _declaredVariablesSignatureLength = 4;
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index f6fae99..2d9f7ff 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -2006,6 +2006,13 @@
/// specific set of target element kinds.
static const String _TARGET_CLASS_NAME = 'Target';
+ /// The name of the class used to mark a returned element as requiring use.
+ static const String _USE_RESULT_CLASS_NAME = "UseResult";
+
+ /// The name of the top-level variable used to mark a returned element as
+ /// requiring use.
+ static const String _USE_RESULT_VARIABLE_NAME = "useResult";
+
/// The name of the top-level variable used to mark a method as being
/// visible for templates.
static const String _VISIBLE_FOR_TEMPLATE_VARIABLE_NAME =
@@ -2119,6 +2126,12 @@
libraryName: _META_META_LIB_NAME, className: _TARGET_CLASS_NAME);
@override
+ bool get isUseResult =>
+ _isConstructor(
+ libraryName: _META_LIB_NAME, className: _USE_RESULT_CLASS_NAME) ||
+ _isPackageMetaGetter(_USE_RESULT_VARIABLE_NAME);
+
+ @override
bool get isVisibleForTemplate => _isTopGetter(
libraryName: _NG_META_LIB_NAME,
name: _VISIBLE_FOR_TEMPLATE_VARIABLE_NAME);
@@ -2498,6 +2511,18 @@
}
@override
+ bool get hasUseResult {
+ final metadata = this.metadata;
+ for (var i = 0; i < metadata.length; i++) {
+ var annotation = metadata[i];
+ if (annotation.isUseResult) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @override
bool get hasVisibleForTemplate {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
@@ -3668,22 +3693,14 @@
DartType? _returnType;
/// The elements representing the parameters of the function.
- List<ParameterElement> _parameters = _Sentinel.parameterElement;
+ List<ParameterElement> _parameters = const [];
/// Is `true` if the type has the question mark, so is nullable.
- bool _isNullable = false;
+ bool isNullable = false;
/// The type defined by this element.
FunctionType? _type;
- GenericFunctionTypeElementImpl.forLinkedNode(
- ElementImpl enclosingElement, AstNode linkedNode)
- : super.forLinkedNode(enclosingElement, null, linkedNode) {
- if (linkedNode is GenericFunctionTypeImpl) {
- linkedNode.declaredElement = this;
- }
- }
-
/// Initialize a newly created function element to have no name and the given
/// [nameOffset]. This is used for function expressions, that have no name.
GenericFunctionTypeElementImpl.forOffset(int nameOffset)
@@ -3692,41 +3709,11 @@
@override
String get identifier => '-';
- bool get isNullable {
- if (linkedNode != null) {
- var node = linkedNode;
- if (node is GenericFunctionType) {
- return _isNullable = node.question != null;
- } else {
- return _isNullable = false;
- }
- }
- return _isNullable;
- }
-
- set isNullable(bool isNullable) {
- _isNullable = isNullable;
- }
-
@override
ElementKind get kind => ElementKind.GENERIC_FUNCTION_TYPE;
@override
List<ParameterElement> get parameters {
- if (!identical(_parameters, _Sentinel.parameterElement)) {
- return _parameters;
- }
-
- if (linkedNode != null) {
- var context = enclosingUnit.linkedContext!;
- return _parameters = ParameterElementImpl.forLinkedNodeList(
- this,
- context,
- null,
- context.getFormalParameters(linkedNode!),
- );
- }
-
return _parameters;
}
@@ -3752,12 +3739,6 @@
@override
DartType get returnTypeInternal {
- if (_returnType == null) {
- if (linkedNode != null) {
- var context = enclosingUnit.linkedContext!;
- return _returnType = context.getReturnType(linkedNode!);
- }
- }
return _returnType!;
}
@@ -3786,12 +3767,8 @@
@override
List<TypeParameterElement> get typeParameters {
- if (linkedNode != null) {
- if (linkedNode is FunctionTypeAlias) {
- return const <TypeParameterElement>[];
- }
- }
- return super.typeParameters;
+ // TODO(scheglov) remove the method
+ return _typeParameterElements;
}
/// Set the type parameters defined by this function type element to the given
@@ -4919,6 +4896,9 @@
bool get hasSealed => false;
@override
+ bool get hasUseResult => false;
+
+ @override
bool get hasVisibleForTemplate => false;
@override
@@ -5960,7 +5940,6 @@
ElementLinkedData? linkedData;
- bool _isAliasedElementReady = false;
ElementImpl? _aliasedElement;
DartType? _aliasedType;
@@ -6002,12 +5981,11 @@
@override
ElementImpl? get aliasedElement {
- _ensureAliasedElement();
+ linkedData?.read(this);
return _aliasedElement;
}
set aliasedElement(ElementImpl? aliasedElement) {
- _isAliasedElementReady = true;
_aliasedElement = aliasedElement;
aliasedElement?.enclosingElement = this;
}
@@ -6017,8 +5995,6 @@
linkedData?.read(this);
if (_aliasedType != null) return _aliasedType!;
- _ensureAliasedElement();
-
final linkedNode = this.linkedNode;
if (linkedNode is GenericTypeAlias) {
var typeNode = linkedNode.type;
@@ -6162,44 +6138,6 @@
this.linkedData = linkedData;
}
- void _ensureAliasedElement() {
- if (_isAliasedElementReady) return;
- _isAliasedElementReady = true;
-
- linkedData?.read(this);
-
- final linkedNode = this.linkedNode;
- if (linkedNode != null) {
- if (linkedNode is GenericTypeAlias) {
- var type = linkedNode.type;
- if (type is GenericFunctionTypeImpl) {
- _aliasedElement =
- type.declaredElement as GenericFunctionTypeElementImpl?;
- // TODO(scheglov) Do we need this?
- // We probably should set it when linking and when applying.
- _aliasedElement ??= GenericFunctionTypeElementImpl.forLinkedNode(
- this,
- type,
- );
- } else if (isNonFunctionTypeAliasesEnabled) {
- // No element for `typedef A<T> = List<T>;`
- } else {
- _aliasedElement = GenericFunctionTypeElementImpl.forOffset(-1)
- ..enclosingElement = this
- ..typeParameters = const <TypeParameterElement>[]
- ..parameters = const <ParameterElement>[]
- ..returnType = DynamicTypeImpl.instance;
- }
- } else {
- // TODO(scheglov) Same as above.
- _aliasedElement = GenericFunctionTypeElementImpl.forLinkedNode(
- this,
- linkedNode,
- );
- }
- }
- }
-
FunctionTypeImpl _errorFunctionType(NullabilitySuffix nullabilitySuffix) {
return FunctionTypeImpl(
typeFormals: const [],
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index aa87517..0cb160f 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -519,6 +519,9 @@
bool get hasSealed => _declaration.hasSealed;
@override
+ bool get hasUseResult => _declaration.hasUseResult;
+
+ @override
bool get hasVisibleForTemplate => _declaration.hasVisibleForTemplate;
@override
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index da49e89..a4a3347 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -96,6 +96,37 @@
correction: "Replace the '.' with a '?.' in the invocation.");
/**
+ * Generate a hint for method, property or function annotated with
+ * `@useResult` whose invocation is unchecked.
+ *
+ * Parameters:
+ * 0: the name of the annotated method, property or function
+ */
+ static const HintCode UNUSED_RESULT = HintCode(
+ 'UNUSED_RESULT', "'{0}' should be used.",
+ correction:
+ "Try using the result by invoking a member, passing it to a function, or returning it from this function.",
+ hasPublishedDocs: false);
+
+ /**
+ * Generate a hint for method, property or function annotated with
+ * `@useResult` whose invocation is unchecked.
+ *
+ * Parameters:
+ * 0: the name of the annotated method, property or function
+ * 1: message details
+ */
+ static const HintCode UNUSED_RESULT_WITH_MESSAGE = HintCode(
+ 'UNUSED_RESULT',
+ "'{0}' should be used. {1}.",
+ // todo(pq): consider passing in correction details: https://github.com/dart-lang/sdk/issues/46066
+ correction:
+ "Try using the result by invoking a member, passing it to a function, or returning it from this function.",
+ hasPublishedDocs: false,
+ uniqueName: 'HintCode.UNUSED_RESULT_WITH_MESSAGE',
+ );
+
+ /**
* Dead code is code that is never reached, this can happen for instance if a
* statement follows a return statement.
*
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
index 4635774..63b77b3 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -71,7 +71,7 @@
required ErrorReporter errorReporter,
required TypeSystemImpl typeSystem,
required MigrationResolutionHooks? migrationResolutionHooks,
- }) : _resolver = resolver,
+ }) : _resolver = resolver,
_errorReporter = errorReporter,
_typeSystem = typeSystem,
_migrationResolutionHooks = migrationResolutionHooks,
@@ -110,6 +110,10 @@
} else {
var name = constructorIdentifier.name;
rawElement = typeElement.getNamedConstructor(name);
+ if (rawElement != null &&
+ !rawElement.isAccessibleIn(definingLibrary)) {
+ rawElement = null;
+ }
}
}
} else if (typeElement is TypeAliasElement) {
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 2cfb030..9304693 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -98,7 +98,7 @@
required DeclaredVariables declaredVariables,
required AnalysisOptions analysisOptions,
required WorkspacePackage? workspacePackage,
- }) : _nullType = typeProvider.nullType,
+ }) : _nullType = typeProvider.nullType,
_typeSystem = typeSystem,
_isNonNullableByDefault = typeSystem.isNonNullableByDefault,
_strictInference =
@@ -2007,6 +2007,8 @@
return 'parameters';
case TargetKind.setter:
return 'setters';
+ case TargetKind.topLevelVariable:
+ return 'top-level variables';
case TargetKind.type:
return 'types (classes, enums, mixins, or typedefs)';
case TargetKind.typedefType:
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 907c52c..a1ab43c 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -759,7 +759,7 @@
node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
_checkForMainFunction(node.name);
_checkForTypeAliasCannotReferenceItself(
- node, node.declaredElement as TypeAliasElementImpl);
+ node.name, node.declaredElement as TypeAliasElementImpl);
super.visitFunctionTypeAlias(node);
}
@@ -794,7 +794,7 @@
node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
_checkForMainFunction(node.name);
_checkForTypeAliasCannotReferenceItself(
- node, node.declaredElement as TypeAliasElementImpl);
+ node.name, node.declaredElement as TypeAliasElementImpl);
super.visitGenericTypeAlias(node);
}
@@ -3962,13 +3962,13 @@
///
/// See [CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF].
void _checkForTypeAliasCannotReferenceItself(
- AstNode node,
+ SimpleIdentifier nameNode,
TypeAliasElementImpl element,
) {
if (element.hasSelfReference) {
errorReporter.reportErrorForNode(
CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
- node,
+ nameNode,
);
}
}
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index e75ff62..422e337 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -1457,7 +1457,7 @@
if (tag == AliasedElementTag.nothing) {
return null;
} else if (tag == AliasedElementTag.genericFunctionElement) {
- var typeParameters = _readTypeParameters();
+ var typeParameters = _readTypeParameters(unitElement);
var formalParameters = _readFormalParameters(unitElement);
var returnType = readRequiredType();
@@ -1536,7 +1536,7 @@
var kindIndex = _reader.readByte();
var kind = _formalParameterKind(kindIndex);
var isInitializingFormal = _reader.readBool();
- var typeParameters = _readTypeParameters();
+ var typeParameters = _readTypeParameters(unitElement);
var type = readRequiredType();
var name = readStringReference();
if (kind.isRequiredPositional) {
@@ -1577,7 +1577,7 @@
/// TODO(scheglov) Optimize for write/read of types without type parameters.
FunctionType _readFunctionType() {
// TODO(scheglov) reuse for formal parameters
- var typeParameters = _readTypeParameters();
+ var typeParameters = _readTypeParameters(null);
var returnType = readRequiredType();
var formalParameters = _readFormalParameters(null);
@@ -1666,7 +1666,9 @@
return types;
}
- List<TypeParameterElementImpl> _readTypeParameters() {
+ List<TypeParameterElementImpl> _readTypeParameters(
+ CompilationUnitElementImpl? unitElement,
+ ) {
var typeParameterCount = _reader.readUInt30();
var typeParameters = List.generate(typeParameterCount, (_) {
var name = readStringReference();
@@ -1677,6 +1679,9 @@
for (var typeParameter in typeParameters) {
typeParameter.bound = readType();
+ if (unitElement != null) {
+ typeParameter.metadata = _readAnnotationList(unitElement: unitElement);
+ }
}
return typeParameters;
}
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 5428c87..9dc8c56 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -630,7 +630,7 @@
_writeTypeParameters(element.typeParameters, () {
_writeFormalParameters(element.parameters, withAnnotations: true);
writeType(element.returnType);
- });
+ }, withAnnotations: true);
} else {
throw UnimplementedError('${element.runtimeType}');
}
@@ -665,7 +665,7 @@
parameter.parameters,
withAnnotations: withAnnotations,
);
- });
+ }, withAnnotations: withAnnotations);
if (withAnnotations) {
_writeAnnotationList(parameter.metadata);
}
@@ -680,7 +680,7 @@
_writeTypeParameters(type.typeFormals, () {
writeType(type.returnType);
_writeFormalParameters(type.parameters, withAnnotations: false);
- });
+ }, withAnnotations: false);
_writeNullabilitySuffix(type.nullabilitySuffix);
}
@@ -736,8 +736,9 @@
void _writeTypeParameters(
List<TypeParameterElement> typeParameters,
- void Function() f,
- ) {
+ void Function() f, {
+ required bool withAnnotations,
+ }) {
localElements.pushScope();
localElements.declareAll(typeParameters);
try {
@@ -747,6 +748,9 @@
}
for (var typeParameter in typeParameters) {
writeType(typeParameter.bound);
+ if (withAnnotations) {
+ _writeAnnotationList(typeParameter.metadata);
+ }
}
f();
} finally {
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index d4aa9f2..3784428 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -36,17 +36,7 @@
Linker get _linker => _libraryBuilder.linker;
void buildDeclarationElements(CompilationUnit unit) {
- // TODO(scheglov) Use `unit.accept` when all nodes handled.
- for (var declaration in unit.declarations) {
- if (declaration is ClassDeclaration ||
- declaration is EnumDeclaration ||
- declaration is ExtensionDeclaration ||
- declaration is FunctionDeclaration ||
- declaration is MixinDeclaration ||
- declaration is TopLevelVariableDeclaration) {
- declaration.accept(this);
- }
- }
+ unit.declarations.accept(this);
_unitElement.accessors = _enclosingContext.propertyAccessors;
_unitElement.enums = _enclosingContext.enums;
_unitElement.functions = _enclosingContext.functions;
@@ -74,10 +64,22 @@
@override
void visitClassDeclaration(ClassDeclaration node) {
+ node.typeParameters?.accept(this);
+ node.extendsClause?.accept(this);
+ node.withClause?.accept(this);
+ node.implementsClause?.accept(this);
_buildClassOrMixin(node);
}
@override
+ void visitClassTypeAlias(ClassTypeAlias node) {
+ node.typeParameters?.accept(this);
+ node.superclass.accept(this);
+ node.withClause.accept(this);
+ node.implementsClause?.accept(this);
+ }
+
+ @override
void visitConstructorDeclaration(
covariant ConstructorDeclarationImpl node,
) {
@@ -139,12 +141,19 @@
}
@override
+ void visitExtendsClause(ExtendsClause node) {
+ node.superclass.accept(this);
+ }
+
+ @override
void visitExtensionDeclaration(ExtensionDeclaration node) {
var element = node.declaredElement as ExtensionElementImpl;
var holder = _buildClassMembers(element, node.members);
element.accessors = holder.propertyAccessors;
element.fields = holder.properties.whereType<FieldElement>().toList();
element.methods = holder.methods;
+
+ node.extendedType.accept(this);
}
@override
@@ -197,6 +206,7 @@
_enclosingContext.addSetter(name, setter);
}
}
+ _buildType(node.fields.type);
}
@override
@@ -247,6 +257,8 @@
element.typeParameters = holder.typeParameters;
}
});
+
+ _buildType(node.type);
}
@override
@@ -310,6 +322,27 @@
} else {
localScope.declare(name, reference);
}
+
+ _buildType(node.returnType);
+ }
+
+ @override
+ void visitFunctionTypeAlias(FunctionTypeAlias node) {
+ node.returnType?.accept(this);
+ node.typeParameters?.accept(this);
+ node.parameters.accept(this);
+
+ var element = node.declaredElement as TypeAliasElementImpl;
+
+ var aliasedElement = GenericFunctionTypeElementImpl.forOffset(
+ node.name.offset,
+ );
+ // TODO(scheglov) Use enclosing context?
+ aliasedElement.parameters = node.parameters.parameters
+ .map((parameterNode) => parameterNode.declaredElement!)
+ .toList();
+
+ element.aliasedElement = aliasedElement;
}
@override
@@ -353,6 +386,51 @@
element.typeParameters = holder.typeParameters;
}
});
+
+ _buildType(node.returnType);
+ }
+
+ @override
+ void visitGenericFunctionType(covariant GenericFunctionTypeImpl node) {
+ var element = GenericFunctionTypeElementImpl.forOffset(node.offset);
+ _unitElement.encloseElement(element);
+
+ node.declaredElement = element;
+ _linker.elementNodes[element] = node;
+
+ var fakeReference = Reference.root();
+ var holder = _EnclosingContext(fakeReference, element);
+ _withEnclosing(holder, () {
+ var formalParameters = node.parameters;
+ formalParameters.accept(this);
+ element.parameters = holder.parameters;
+
+ var typeParameters = node.typeParameters;
+ if (typeParameters != null) {
+ typeParameters.accept(this);
+ element.typeParameters = holder.typeParameters;
+ }
+ });
+
+ _buildType(node.returnType);
+ }
+
+ @override
+ void visitGenericTypeAlias(GenericTypeAlias node) {
+ node.typeParameters?.accept(this);
+ node.type.accept(this);
+
+ var typeNode = node.type;
+ if (typeNode is GenericFunctionTypeImpl) {
+ var element = node.declaredElement as TypeAliasElementImpl;
+ element.aliasedElement =
+ typeNode.declaredElement as GenericFunctionTypeElementImpl;
+ }
+ }
+
+ @override
+ void visitImplementsClause(ImplementsClause node) {
+ node.interfaces.accept(this);
}
@override
@@ -448,14 +526,24 @@
formalParameters: node.parameters,
typeParameters: node.typeParameters,
);
+
+ _buildType(node.returnType);
}
@override
void visitMixinDeclaration(MixinDeclaration node) {
+ node.typeParameters?.accept(this);
+ node.onClause?.accept(this);
+ node.implementsClause?.accept(this);
_buildClassOrMixin(node);
}
@override
+ void visitOnClause(OnClause node) {
+ node.superclassConstraints.accept(this);
+ }
+
+ @override
void visitPartDirective(PartDirective node) {}
@override
@@ -494,6 +582,8 @@
node.declaredElement = element;
nameNode?.staticElement = element;
+
+ _buildType(node.type);
}
@override
@@ -546,6 +636,18 @@
localScope.declare('$name=', setter.reference!);
}
}
+
+ _buildType(node.variables.type);
+ }
+
+ @override
+ void visitTypeArgumentList(TypeArgumentList node) {
+ node.arguments.accept(this);
+ }
+
+ @override
+ void visitTypeName(TypeName node) {
+ node.typeArguments?.accept(this);
}
@override
@@ -556,8 +658,11 @@
var element = TypeParameterElementImpl(name, nameNode.offset);
element.metadata = _buildAnnotations(node.metadata);
+ nameNode.staticElement = element;
_linker.elementNodes[element] = node;
_enclosingContext.addTypeParameter(name, element);
+
+ _buildType(node.bound);
}
@override
@@ -565,6 +670,11 @@
node.typeParameters.accept(this);
}
+ @override
+ void visitWithClause(WithClause node) {
+ node.mixinTypes.accept(this);
+ }
+
List<ElementAnnotation> _buildAnnotations(List<Annotation> nodeList) {
return _buildAnnotationsWithUnit(_unitElement, nodeList);
}
@@ -670,6 +780,11 @@
}
}
+ /// TODO(scheglov) Maybe inline?
+ void _buildType(TypeAnnotation? node) {
+ node?.accept(this);
+ }
+
Uri? _selectAbsoluteUri(NamespaceDirective directive) {
var relativeUriStr = _selectRelativeUri(
directive.configurations,
@@ -892,9 +1007,9 @@
return _bindReference('@variable', name, element);
}
- Reference addTypeParameter(String name, TypeParameterElementImpl element) {
+ void addTypeParameter(String name, TypeParameterElementImpl element) {
typeParameters.add(element);
- return _bindReference('@typeParameter', name, element);
+ this.element.encloseElement(element);
}
Reference _bindReference(
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index 3fc1536..3b9c95d 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -263,6 +263,7 @@
var unitRef = reference.getChild('@unit');
var unitReference = unitRef.getChild(unitContext.uriStr);
var resolver = ReferenceResolver(
+ linker,
nodesToBuildType,
linker.elementFactory,
element,
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index 64c3567..ed8df04 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/summary2/function_type_builder.dart';
+import 'package:analyzer/src/summary2/link.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/linking_node_scope.dart';
import 'package:analyzer/src/summary2/named_type_builder.dart';
@@ -29,6 +30,7 @@
/// the type is set, otherwise we keep it empty, so we will attempt to infer
/// it later).
class ReferenceResolver extends ThrowingAstVisitor<void> {
+ final Linker linker;
final TypeSystemImpl _typeSystem;
final NodesToBuildType nodesToBuildType;
final LinkedElementFactory elementFactory;
@@ -40,6 +42,7 @@
Scope scope;
ReferenceResolver(
+ this.linker,
this.nodesToBuildType,
this.elementFactory,
LibraryElementImpl libraryElement,
@@ -253,13 +256,7 @@
var nodeImpl = node as GenericFunctionTypeImpl;
var outerScope = scope;
- var element = GenericFunctionTypeElementImpl.forLinkedNode(
- unitReference.element as CompilationUnitElementImpl,
- node,
- );
- element.parameters; // create elements
-
- _createTypeParameterElements(element, node.typeParameters);
+ var element = node.declaredElement as GenericFunctionTypeElementImpl;
scope = TypeParameterScope(outerScope, element.typeParameters);
node.returnType?.accept(this);
@@ -423,7 +420,15 @@
@override
void visitTypeParameter(TypeParameter node) {
- node.bound?.accept(this);
+ var bound = node.bound;
+ if (bound != null) {
+ bound.accept(this);
+ var element = node.declaredElement as TypeParameterElementImpl;
+ element.bound = bound.type;
+ // TODO(scheglov) We should not need to do it here.
+ // Only in the element builder, eventually.z
+ linker.elementNodes[element] = node;
+ }
}
@override
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index f502211..b3446f2 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -48,18 +48,22 @@
builder.build();
}
- _MixinsInference().perform(nodes.declarations);
-
for (var declaration in nodes.declarations) {
_declaration(declaration);
}
// TODO(scheglov) generalize
_linker.elementNodes.forEach((element, node) {
+ if (element is GenericFunctionTypeElementImpl &&
+ node is GenericFunctionType) {
+ element.returnType = node.returnType?.type ?? _dynamicType;
+ }
if (element is TypeParameterElementImpl && node is TypeParameter) {
element.bound = node.bound?.type;
}
});
+
+ _MixinsInference().perform(nodes.declarations);
}
FunctionType _buildFunctionType(
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
index 9482e66..dc79ac0 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
@@ -36,11 +36,19 @@
const _Protected protected = const _Protected();
const Required required = const Required();
const _Sealed sealed = const _Sealed();
+const UseResult useResult = UseResult();
const _VisibleForTesting visibleForTesting = const _VisibleForTesting();
class _AlwaysThrows {
const _AlwaysThrows();
}
+@Target({
+ TargetKind.field,
+ TargetKind.function,
+ TargetKind.getter,
+ TargetKind.method,
+ TargetKind.topLevelVariable,
+})
class _DoNotStore {
const _DoNotStore();
}
@@ -76,6 +84,10 @@
class _Sealed {
const _Sealed();
}
+class UseResult {
+ final String reason;
+ const UseResult([this.reason = '']);
+}
class _VisibleForTesting {
const _VisibleForTesting();
}
@@ -99,6 +111,7 @@
mixinType,
parameter,
setter,
+ topLevelVariable,
type,
typedefType,
}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
index 5ca4280..1ca267c 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
@@ -13,6 +13,7 @@
});
}
+/// todo(pq): add tests for topLevelVariables: https://dart-review.googlesource.com/c/sdk/+/200301
@reflectiveTest
class InvalidAnnotationTargetTest extends PubPackageResolutionTest {
void test_classType_class() async {
diff --git a/pkg/analyzer/test/src/diagnostics/new_with_undefined_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/new_with_undefined_constructor_test.dart
index 5e3e722..602e5ff 100644
--- a/pkg/analyzer/test/src/diagnostics/new_with_undefined_constructor_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/new_with_undefined_constructor_test.dart
@@ -62,4 +62,52 @@
error(CompileTimeErrorCode.NEW_WITH_UNDEFINED_CONSTRUCTOR, 35, 4),
]);
}
+
+ test_private_named() async {
+ newFile('$testPackageLibPath/a.dart', content: r'''
+class A {
+ A._named() {}
+}
+''');
+ await assertErrorsInCode(r'''
+import 'a.dart';
+void f() {
+ new A._named();
+}
+''', [
+ error(CompileTimeErrorCode.NEW_WITH_UNDEFINED_CONSTRUCTOR, 36, 6),
+ ]);
+ }
+
+ test_private_named_genericClass_noTypeArguments() async {
+ newFile('$testPackageLibPath/a.dart', content: r'''
+class A<T> {
+ A._named() {}
+}
+''');
+ await assertErrorsInCode(r'''
+import 'a.dart';
+void f() {
+ new A._named();
+}
+''', [
+ error(CompileTimeErrorCode.NEW_WITH_UNDEFINED_CONSTRUCTOR, 36, 6),
+ ]);
+ }
+
+ test_private_named_genericClass_withTypeArguments() async {
+ newFile('$testPackageLibPath/a.dart', content: r'''
+class A<T> {
+ A._named() {}
+}
+''');
+ await assertErrorsInCode(r'''
+import 'a.dart';
+void f() {
+ new A<int>._named();
+}
+''', [
+ error(CompileTimeErrorCode.NEW_WITH_UNDEFINED_CONSTRUCTOR, 41, 6),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/not_instantiated_bound_test.dart b/pkg/analyzer/test/src/diagnostics/not_instantiated_bound_test.dart
index c7254f7..930f6f4 100644
--- a/pkg/analyzer/test/src/diagnostics/not_instantiated_bound_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_instantiated_bound_test.dart
@@ -116,7 +116,7 @@
class C<T extends F> {}
class D<T extends C> {}
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 19),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
error(CompileTimeErrorCode.NOT_INSTANTIATED_BOUND, 38, 1),
error(CompileTimeErrorCode.NOT_INSTANTIATED_BOUND, 62, 1),
]);
diff --git a/pkg/analyzer/test/src/diagnostics/type_alias_cannot_reference_itself_test.dart b/pkg/analyzer/test/src/diagnostics/type_alias_cannot_reference_itself_test.dart
index 68ba41b..f863edb 100644
--- a/pkg/analyzer/test/src/diagnostics/type_alias_cannot_reference_itself_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/type_alias_cannot_reference_itself_test.dart
@@ -19,7 +19,7 @@
await assertErrorsInCode('''
typedef A<T extends A<int>>();
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 30),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -27,7 +27,7 @@
await assertErrorsInCode('''
typedef A(A b());
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 17),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -40,8 +40,8 @@
foo(null);
}
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 37),
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 38, 37),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 46, 1),
]);
}
@@ -49,7 +49,7 @@
await assertErrorsInCode('''
typedef A<T extends A<int>> = void Function();
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 46),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -57,7 +57,7 @@
await assertErrorsInCode(r'''
typedef F<X extends F<X>> = F Function();
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 41),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -70,8 +70,8 @@
foo(null);
}
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 26),
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 27, 26),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 13, 1),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 40, 1),
]);
}
@@ -93,8 +93,8 @@
typedef T1 = T2;
typedef T2 = T1;
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 16),
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 17, 16),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 2),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 25, 2),
]);
}
@@ -102,7 +102,7 @@
await assertErrorsInCode('''
typedef T = void Function(T);
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 29),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -110,7 +110,7 @@
await assertErrorsInCode('''
typedef T = T;
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 14),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -118,7 +118,7 @@
await assertErrorsInCode('''
typedef T = T?;
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 15),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -126,7 +126,7 @@
await assertErrorsInCode('''
typedef T = List<T>;
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 20),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -134,7 +134,7 @@
await assertErrorsInCode('''
typedef T<X extends T<Never>> = List<X>;
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 40),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -142,7 +142,7 @@
await assertErrorsInCode('''
typedef A({A a});
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 17),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -150,7 +150,7 @@
await assertErrorsInCode('''
typedef A([A a]);
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 17),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -158,7 +158,7 @@
await assertErrorsInCode('''
typedef A(A a);
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 15),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -166,7 +166,7 @@
await assertErrorsInCode('''
typedef A(List<A> a);
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 21),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 8, 1),
]);
}
@@ -194,7 +194,7 @@
await assertErrorsInCode('''
typedef A A();
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 14),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 10, 1),
]);
}
@@ -203,8 +203,8 @@
typedef B A();
typedef A B();
''', [
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 14),
- error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 15, 14),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 10, 1),
+ error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 25, 1),
]);
}
}
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 38c1c87..51f3b5b 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -1084,6 +1084,21 @@
}
buffer.writeln(';');
+
+ if (withFullyResolvedAst) {
+ _withIndent(() {
+ _writeResolvedMetadata(e.metadata);
+ _writeResolvedTypeParameters(e.typeParameters);
+ var aliasedElement = e.aliasedElement;
+ if (aliasedElement is GenericFunctionTypeElement) {
+ _writelnWithIndent('aliasedElement');
+ _withIndent(() {
+ _writeResolvedTypeParameters(aliasedElement.typeParameters);
+ _writeResolvedParameterElements(aliasedElement.parameters);
+ });
+ }
+ });
+ }
}
void writeTypeInferenceError(Element e) {
@@ -1319,6 +1334,37 @@
);
}
+ void _writeResolvedParameterElements(
+ List<ParameterElement> parameters, {
+ String enclosingNames = '',
+ }) {
+ if (parameters.isNotEmpty) {
+ _writelnWithIndent('parameters');
+ _withIndent(() {
+ var index = 0;
+ for (var formalParameter in parameters) {
+ var metadata = formalParameter.metadata;
+ var name = formalParameter.name;
+ if (name.isEmpty) {
+ name = '$index';
+ }
+ _writelnWithIndent(name);
+ _withIndent(() {
+ _writeResolvedMetadata(metadata);
+ var subParameters = formalParameter.parameters;
+ _withIndent(() {
+ _writeResolvedParameterElements(
+ subParameters,
+ enclosingNames: enclosingNames + name + '::',
+ );
+ });
+ });
+ index++;
+ }
+ });
+ }
+ }
+
void _writeResolvedTypeParameters(List<TypeParameterElement> elements) {
if (elements.isNotEmpty) {
_writelnWithIndent('typeParameters');
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 2cf8b1b..ef090f9 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -7921,6 +7921,33 @@
''');
}
+ test_genericFunction_boundOf_typeParameter_ofMixin() async {
+ var library = await checkLibrary(r'''
+mixin B<X extends void Function()> {}
+''');
+ checkElementText(library, r'''
+mixin B<X extends void Function() = void Function()> on Object {
+}
+''');
+ }
+
+ test_genericFunction_typeArgument_ofSuperclass_ofClassAlias() async {
+ var library = await checkLibrary(r'''
+class A<T> {}
+mixin M {}
+class B = A<void Function()> with M;
+''');
+ checkElementText(library, r'''
+class A<T> {
+}
+class alias B extends A<void Function()> with M {
+ synthetic B() : super();
+}
+mixin M on Object {
+}
+''');
+ }
+
test_genericFunction_typeParameter_asTypedefArgument() async {
var library = await checkLibrary(r'''
typedef F1 = Function<V1>(F2<V1>);
@@ -11027,6 +11054,96 @@
withFullyResolvedAst: true);
}
+ test_metadata_inAliasedElement_formalParameter() async {
+ var library = await checkLibrary('''
+const a = 42;
+typedef F = void Function(@a int first)
+''');
+ checkElementText(
+ library,
+ r'''
+typedef F = void Function(int first);
+ aliasedElement
+ parameters
+ first
+ metadata
+ Annotation
+ element: self::@getter::a
+ name: SimpleIdentifier
+ staticElement: self::@getter::a
+ staticType: null
+ token: a
+const int a;
+ constantInitializer
+ IntegerLiteral
+ literal: 42
+ staticType: int
+''',
+ withFullyResolvedAst: true);
+ }
+
+ test_metadata_inAliasedElement_formalParameter2() async {
+ var library = await checkLibrary('''
+const a = 42;
+typedef F = void Function(int foo(@a int bar))
+''');
+ checkElementText(
+ library,
+ r'''
+typedef F = void Function(int Function(int) foo);
+ aliasedElement
+ parameters
+ foo
+ parameters
+ bar
+ metadata
+ Annotation
+ element: self::@getter::a
+ name: SimpleIdentifier
+ staticElement: self::@getter::a
+ staticType: null
+ token: a
+const int a;
+ constantInitializer
+ IntegerLiteral
+ literal: 42
+ staticType: int
+''',
+ withFullyResolvedAst: true);
+ }
+
+ test_metadata_inAliasedElement_typeParameter() async {
+ var library = await checkLibrary('''
+const a = 42;
+typedef F = void Function<@a T>(int first)
+''');
+ checkElementText(
+ library,
+ r'''
+typedef F = void Function(int first);
+ aliasedElement
+ typeParameters
+ T
+ bound: null
+ defaultType: null
+ metadata
+ Annotation
+ element: self::@getter::a
+ name: SimpleIdentifier
+ staticElement: self::@getter::a
+ staticType: null
+ token: a
+ parameters
+ first
+const int a;
+ constantInitializer
+ IntegerLiteral
+ literal: 42
+ staticType: int
+''',
+ withFullyResolvedAst: true);
+ }
+
test_metadata_invalid_classDeclaration() async {
var library = await checkLibrary('f(_) {} @f(42) class C {}');
checkElementText(library, r'''
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 4ad11c96..851918e 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -519,12 +519,15 @@
}
void configureForPath(String path) {
- var parentFolder = _resourceProvider.getFile(path).parent2;
+ var folder = _resourceProvider.getFolder(path);
+ if (!folder.exists) {
+ folder = _resourceProvider.getFile(path).parent2;
+ }
// In batch mode we are given separate file paths to analyze.
// All files of a folder have the same configuration.
// So, reuse the corresponding analysis context.
- _analysisContext = _folderContexts[parentFolder];
+ _analysisContext = _folderContexts[folder];
if (_analysisContext != null) {
return;
}
@@ -550,7 +553,7 @@
);
_setContextForPath(path);
- _folderContexts[parentFolder] = _analysisContext;
+ _folderContexts[folder] = _analysisContext;
}
void setCommandLineOptions(
diff --git a/pkg/analyzer_cli/test/data/multiple_inputs_two_directories/bin/a.dart b/pkg/analyzer_cli/test/data/multiple_inputs_two_directories/bin/a.dart
new file mode 100644
index 0000000..4235844
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/multiple_inputs_two_directories/bin/a.dart
@@ -0,0 +1 @@
+Unresolved a;
diff --git a/pkg/analyzer_cli/test/data/multiple_inputs_two_directories/lib/b.dart b/pkg/analyzer_cli/test/data/multiple_inputs_two_directories/lib/b.dart
new file mode 100644
index 0000000..c7ce226
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/multiple_inputs_two_directories/lib/b.dart
@@ -0,0 +1 @@
+Unresolved b;
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index c5e003e..419aceb 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -470,6 +470,22 @@
expect(outSink.toString(), contains('Avoid empty else statements'));
}
+ Future<void> test_multiple_inputs_two_directories() async {
+ await driveMany([
+ 'data/multiple_inputs_two_directories/bin',
+ 'data/multiple_inputs_two_directories/lib',
+ ]);
+ expect(outSink.toString(), contains('2 errors found.'));
+ }
+
+ Future<void> test_multiple_inputs_two_files() async {
+ await driveMany([
+ 'data/multiple_inputs_two_directories/bin/a.dart',
+ 'data/multiple_inputs_two_directories/lib/b.dart',
+ ]);
+ expect(outSink.toString(), contains('2 errors found.'));
+ }
+
Future<void> test_todo() async {
await drive('data/file_with_todo.dart');
expect(outSink.toString().contains('[info]'), isFalse);
diff --git a/pkg/dartdev/lib/src/commands/create.dart b/pkg/dartdev/lib/src/commands/create.dart
index c7a3ca9..da41f79 100644
--- a/pkg/dartdev/lib/src/commands/create.dart
+++ b/pkg/dartdev/lib/src/commands/create.dart
@@ -138,8 +138,10 @@
'Created project $projectName in ${p.relative(dir)}! In order to get '
'started, run the following commands:');
log.stdout('');
- log.stdout(log.ansi.emphasized(' cd ${p.relative(dir)}'));
- log.stdout(log.ansi.emphasized(' dart run'));
+ log.stdout(generator.getInstallInstructions(
+ dir,
+ projectName,
+ ));
log.stdout('');
return 0;
diff --git a/pkg/dartdev/lib/src/templates.dart b/pkg/dartdev/lib/src/templates.dart
index 53666a3..041ded0 100644
--- a/pkg/dartdev/lib/src/templates.dart
+++ b/pkg/dartdev/lib/src/templates.dart
@@ -5,6 +5,7 @@
import 'dart:convert' show utf8;
import 'package:meta/meta.dart';
+import 'package:path/path.dart' as p;
import 'templates/console_full.dart';
import 'templates/console_simple.dart';
@@ -99,7 +100,25 @@
/// Return some user facing instructions about how to finish installation of
/// the template.
- String getInstallInstructions() => '';
+ ///
+ /// [directory] is the directory of the generated project.
+ ///
+ /// [scriptPath] is the path of the default target script
+ /// (e.g., bin/foo.dart) **without** an extension. If null, the implicit run
+ /// command will be output by default (e.g., dart run).
+ String getInstallInstructions(
+ String directory,
+ String scriptPath,
+ ) {
+ final buffer = StringBuffer();
+ buffer.writeln(' cd ${p.relative(directory)}');
+ if (scriptPath != null) {
+ buffer.write(' dart run $scriptPath.dart');
+ } else {
+ buffer.write(' dart run');
+ }
+ return buffer.toString();
+ }
@override
String toString() => '[$id: $description]';
diff --git a/pkg/dartdev/lib/src/templates/console_full.dart b/pkg/dartdev/lib/src/templates/console_full.dart
index f17c05c..f2e8b7a 100644
--- a/pkg/dartdev/lib/src/templates/console_full.dart
+++ b/pkg/dartdev/lib/src/templates/console_full.dart
@@ -24,8 +24,11 @@
}
@override
- String getInstallInstructions() => '${super.getInstallInstructions()}\n'
- 'run your app using `dart ${entrypoint.path}`.';
+ String getInstallInstructions(
+ String directory,
+ String scriptName,
+ ) =>
+ super.getInstallInstructions(directory, null);
}
final String _pubspec = '''
diff --git a/pkg/dartdev/lib/src/templates/console_simple.dart b/pkg/dartdev/lib/src/templates/console_simple.dart
index 22f9d9a..a90c2ef6 100644
--- a/pkg/dartdev/lib/src/templates/console_simple.dart
+++ b/pkg/dartdev/lib/src/templates/console_simple.dart
@@ -22,8 +22,11 @@
}
@override
- String getInstallInstructions() => '${super.getInstallInstructions()}\n'
- 'run your app using `dart ${entrypoint.path}`.';
+ String getInstallInstructions(
+ String directory,
+ String scriptName,
+ ) =>
+ super.getInstallInstructions(directory, null);
}
final String _pubspec = '''
diff --git a/pkg/dartdev/lib/src/templates/package_simple.dart b/pkg/dartdev/lib/src/templates/package_simple.dart
index 586c799..9d9eb59 100644
--- a/pkg/dartdev/lib/src/templates/package_simple.dart
+++ b/pkg/dartdev/lib/src/templates/package_simple.dart
@@ -25,8 +25,14 @@
}
@override
- String getInstallInstructions() => '${super.getInstallInstructions()}\n'
- 'run your app using `dart ${entrypoint.path}`.';
+ String getInstallInstructions(
+ String directory,
+ String projectName,
+ ) =>
+ super.getInstallInstructions(
+ directory,
+ 'example/${projectName}_example',
+ );
}
final String _gitignore = '''
diff --git a/pkg/dartdev/lib/src/templates/server_shelf.dart b/pkg/dartdev/lib/src/templates/server_shelf.dart
index 15f5898..fcd674f 100644
--- a/pkg/dartdev/lib/src/templates/server_shelf.dart
+++ b/pkg/dartdev/lib/src/templates/server_shelf.dart
@@ -25,8 +25,14 @@
}
@override
- String getInstallInstructions() => '${super.getInstallInstructions()}\n'
- 'run your app using `dart run ${entrypoint.path}`.';
+ String getInstallInstructions(
+ String directory,
+ String scriptName,
+ ) =>
+ super.getInstallInstructions(
+ directory,
+ 'bin/server',
+ );
}
final String _pubspec = '''
diff --git a/pkg/dartdev/lib/src/templates/web_simple.dart b/pkg/dartdev/lib/src/templates/web_simple.dart
index 836ec57..73ae51a 100644
--- a/pkg/dartdev/lib/src/templates/web_simple.dart
+++ b/pkg/dartdev/lib/src/templates/web_simple.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:path/path.dart' as p;
+
import '../templates.dart';
import 'common.dart' as common;
@@ -22,6 +24,15 @@
);
addFile('web/styles.css', _styles);
}
+
+ @override
+ String getInstallInstructions(
+ String directory,
+ String scriptName,
+ ) =>
+ ' cd ${p.relative(directory)}\n'
+ ' dart pub global activate webdev\n'
+ ' webdev serve';
}
final String _pubspec = '''
diff --git a/pkg/dartdev/test/commands/create_test.dart b/pkg/dartdev/test/commands/create_test.dart
index 969120c..0982a0c 100644
--- a/pkg/dartdev/test/commands/create_test.dart
+++ b/pkg/dartdev/test/commands/create_test.dart
@@ -95,7 +95,7 @@
expect(result.exitCode, 73);
});
- test('create project in current directory', () {
+ test('project in current directory', () {
p = project();
final projectDir = Directory('foo')..createSync();
final result = p.runSync(
@@ -107,7 +107,7 @@
expect(result.exitCode, 0);
});
- test('create project with normalized package name', () {
+ test('project with normalized package name', () {
p = project();
final result = p.runSync(['create', 'requires-normalization']);
expect(result.stderr, isEmpty);
@@ -118,7 +118,7 @@
expect(result.exitCode, 0);
});
- test('create project with an invalid package name', () {
+ test('project with an invalid package name', () {
p = project();
final result = p.runSync(['create', 'bad-package^name']);
expect(
@@ -141,7 +141,7 @@
// Create tests for each template.
for (String templateId in CreateCommand.legalTemplateIds) {
- test('create $templateId', () {
+ test('$templateId', () {
p = project();
const projectName = 'template_project';
ProcessResult result = p.runSync([
@@ -162,4 +162,34 @@
reason: 'File not found: ${entryFile.path}');
});
}
+
+ for (final generator in templates.generators) {
+ test('${generator.id} getting started message', () {
+ const dir = 'foo';
+ const projectName = dir;
+ final lines = generator
+ .getInstallInstructions(dir, projectName)
+ .split('\n')
+ .map((e) => e.trim())
+ .toList();
+ if (generator.categories.contains('web')) {
+ expect(lines.length, 3);
+ expect(lines[0], 'cd $dir');
+ expect(lines[1], 'dart pub global activate webdev');
+ expect(lines[2], 'webdev serve');
+ } else if (generator.categories.contains('console')) {
+ expect(lines.length, 2);
+ expect(lines[0], 'cd $dir');
+ expect(lines[1], 'dart run');
+ } else if (generator.categories.contains('server')) {
+ expect(lines.length, 2);
+ expect(lines[0], 'cd $dir');
+ expect(lines[1], 'dart run bin/server.dart');
+ } else {
+ expect(lines.length, 2);
+ expect(lines[0], 'cd $dir');
+ expect(lines[1], 'dart run example/${projectName}_example.dart');
+ }
+ });
+ }
}
diff --git a/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart
index b0ba617..d405be6 100644
--- a/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart
@@ -7,6 +7,7 @@
import 'package:kernel/ast.dart';
import '../problems.dart';
+import '../source/source_library_builder.dart';
import 'library_builder.dart';
import 'nullability_builder.dart';
import 'type_builder.dart';
@@ -18,7 +19,12 @@
const FixedTypeBuilder(this.type, this.fileUri, this.charOffset);
- TypeBuilder clone(List<TypeBuilder> newTypes) => this;
+ TypeBuilder clone(
+ List<TypeBuilder> newTypes,
+ SourceLibraryBuilder contextLibrary,
+ TypeParameterScopeBuilder contextDeclaration) {
+ return this;
+ }
Object get name => null;
diff --git a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
index 1b034996..306222e 100644
--- a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
@@ -29,7 +29,7 @@
import '../scope.dart' show Scope;
-import '../source/source_library_builder.dart' show SourceLibraryBuilder;
+import '../source/source_library_builder.dart';
import '../source/source_loader.dart' show SourceLoader;
@@ -141,12 +141,21 @@
return variable;
}
- FormalParameterBuilder clone(List<TypeBuilder> newTypes) {
+ FormalParameterBuilder clone(
+ List<TypeBuilder> newTypes,
+ SourceLibraryBuilder contextLibrary,
+ TypeParameterScopeBuilder contextDeclaration) {
// TODO(dmitryas): It's not clear how [metadata] is used currently, and
// how it should be cloned. Consider cloning it instead of reusing it.
return new FormalParameterBuilder(
- metadata, modifiers, type?.clone(newTypes), name, parent, charOffset,
- fileUri: fileUri, isExtensionThis: isExtensionThis)
+ metadata,
+ modifiers,
+ type?.clone(newTypes, contextLibrary, contextDeclaration),
+ name,
+ parent,
+ charOffset,
+ fileUri: fileUri,
+ isExtensionThis: isExtensionThis)
..kind = kind;
}
diff --git a/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart
index 26f56fc..2204d0d 100644
--- a/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart
@@ -18,6 +18,8 @@
import '../fasta_codes.dart' show messageSupertypeIsFunction, noLength;
+import '../source/source_library_builder.dart';
+
import 'formal_parameter_builder.dart';
import 'library_builder.dart';
import 'nullability_builder.dart';
@@ -131,14 +133,14 @@
return buildSupertype(library, charOffset, fileUri);
}
- FunctionTypeBuilder clone(List<TypeBuilder> newTypes) {
+ FunctionTypeBuilder clone(
+ List<TypeBuilder> newTypes,
+ SourceLibraryBuilder contextLibrary,
+ TypeParameterScopeBuilder contextDeclaration) {
List<TypeVariableBuilder> clonedTypeVariables;
if (typeVariables != null) {
clonedTypeVariables =
- new List<TypeVariableBuilder>.filled(typeVariables.length, null);
- for (int i = 0; i < clonedTypeVariables.length; i++) {
- clonedTypeVariables[i] = typeVariables[i].clone(newTypes);
- }
+ contextLibrary.copyTypeVariables(typeVariables, contextDeclaration);
}
List<FormalParameterBuilder> clonedFormals;
if (formals != null) {
@@ -146,11 +148,12 @@
new List<FormalParameterBuilder>.filled(formals.length, null);
for (int i = 0; i < clonedFormals.length; i++) {
FormalParameterBuilder formal = formals[i];
- clonedFormals[i] = formal.clone(newTypes);
+ clonedFormals[i] =
+ formal.clone(newTypes, contextLibrary, contextDeclaration);
}
}
FunctionTypeBuilder newType = new FunctionTypeBuilder(
- returnType?.clone(newTypes),
+ returnType?.clone(newTypes, contextLibrary, contextDeclaration),
clonedTypeVariables,
clonedFormals,
nullabilityBuilder,
diff --git a/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart b/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart
index e1439c5..2ea95bb 100644
--- a/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart
@@ -9,6 +9,7 @@
import 'package:kernel/ast.dart' show InterfaceType, Supertype, TypedefType;
import '../problems.dart' show unsupported;
+import '../source/source_library_builder.dart';
import 'library_builder.dart';
import 'nullability_builder.dart';
@@ -75,7 +76,10 @@
return unsupported("withNullabilityBuilder", -1, null);
}
- MixinApplicationBuilder clone(List<TypeBuilder> newTypes) {
+ MixinApplicationBuilder clone(
+ List<TypeBuilder> newTypes,
+ SourceLibraryBuilder contextLibrary,
+ TypeParameterScopeBuilder contextDeclaration) {
int charOffset = -1; // TODO(dmitryas): Provide these.
Uri fileUri = null; // TODO(dmitryas): Provide these.
return unsupported("clone", charOffset, fileUri);
diff --git a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
index 31a334d..c7e325a 100644
--- a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
@@ -406,12 +406,16 @@
return this;
}
- NamedTypeBuilder clone(List<TypeBuilder> newTypes) {
+ NamedTypeBuilder clone(
+ List<TypeBuilder> newTypes,
+ SourceLibraryBuilder contextLibrary,
+ TypeParameterScopeBuilder contextDeclaration) {
List<TypeBuilder> clonedArguments;
if (arguments != null) {
clonedArguments = new List<TypeBuilder>.filled(arguments.length, null);
for (int i = 0; i < clonedArguments.length; i++) {
- clonedArguments[i] = arguments[i].clone(newTypes);
+ clonedArguments[i] =
+ arguments[i].clone(newTypes, contextLibrary, contextDeclaration);
}
}
NamedTypeBuilder newType = new NamedTypeBuilder(
diff --git a/pkg/front_end/lib/src/fasta/builder/type_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
index 2aed213..57fbc8e 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
@@ -9,6 +9,7 @@
import 'package:kernel/ast.dart' show DartType, Supertype, TypedefType;
import '../scope.dart';
+import '../source/source_library_builder.dart';
import 'library_builder.dart';
import 'nullability_builder.dart';
import 'type_declaration_builder.dart';
@@ -61,7 +62,10 @@
/// existing declaration or type variable builders. All newly built types
/// are added to [newTypes], so that they can be added to a proper scope and
/// resolved later.
- TypeBuilder clone(List<TypeBuilder> newTypes);
+ TypeBuilder clone(
+ List<TypeBuilder> newTypes,
+ SourceLibraryBuilder contextLibrary,
+ TypeParameterScopeBuilder contextDeclaration);
String get fullNameForErrors => "${printOn(new StringBuffer())}";
diff --git a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
index db9c9ed..c396c39 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
@@ -174,12 +174,16 @@
patch.actualOrigin = this;
}
- TypeVariableBuilder clone(List<TypeBuilder> newTypes) {
+ TypeVariableBuilder clone(
+ List<TypeBuilder> newTypes,
+ SourceLibraryBuilder contextLibrary,
+ TypeParameterScopeBuilder contextDeclaration) {
// TODO(dmitryas): Figure out if using [charOffset] here is a good idea.
// An alternative is to use the offset of the node the cloned type variable
// is declared on.
return new TypeVariableBuilder(name, parent, charOffset, fileUri,
- bound: bound.clone(newTypes), variableVariance: variance);
+ bound: bound?.clone(newTypes, contextLibrary, contextDeclaration),
+ variableVariance: variance);
}
void buildOutlineExpressions(
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
index a20b83a..2b2c10f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
@@ -1064,6 +1064,7 @@
}
TypeDeclarationBuilder declaration = type.declaration;
+ // TODO(dmitryas): Unalias beyond the first layer for the check.
if (declaration is TypeAliasBuilder) {
TypeBuilder rhsType = declaration.type;
if (rhsType is FunctionTypeBuilder &&
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 0a1c8bb..0064a64 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -96,7 +96,7 @@
NonSimplicityIssue,
calculateBounds,
computeTypeVariableBuilderVariance,
- findGenericFunctionTypes,
+ findUnaliasedGenericFunctionTypes,
getInboundReferenceIssuesInType,
getNonSimplicityIssuesForDeclaration,
getNonSimplicityIssuesForTypeVariables,
@@ -1473,13 +1473,13 @@
for (TypeVariableBuilder type in typeVariables) {
if (type.name == "Function") {
addProblem(messageFunctionAsTypeParameter, type.charOffset,
- type.name.length, type.fileUri);
+ type.name.length, type.fileUri);
}
}
}
- void _checkBadFunctionDeclUse(String className, TypeParameterScopeKind kind,
- int charOffset) {
+ void _checkBadFunctionDeclUse(
+ String className, TypeParameterScopeKind kind, int charOffset) {
String decType;
switch (kind) {
case TypeParameterScopeKind.classDeclaration:
@@ -2068,12 +2068,14 @@
List<TypeBuilder> newTypes = <TypeBuilder>[];
if (supertype is NamedTypeBuilder && supertype.arguments != null) {
for (int i = 0; i < supertype.arguments.length; ++i) {
- supertype.arguments[i] = supertype.arguments[i].clone(newTypes);
+ supertype.arguments[i] = supertype.arguments[i]
+ .clone(newTypes, this, currentTypeParameterScopeBuilder);
}
}
if (mixin is NamedTypeBuilder && mixin.arguments != null) {
for (int i = 0; i < mixin.arguments.length; ++i) {
- mixin.arguments[i] = mixin.arguments[i].clone(newTypes);
+ mixin.arguments[i] = mixin.arguments[i]
+ .clone(newTypes, this, currentTypeParameterScopeBuilder);
}
}
for (TypeBuilder newType in newTypes) {
@@ -2953,7 +2955,7 @@
for (TypeVariableBuilder variable in original) {
TypeVariableBuilder newVariable = new TypeVariableBuilder(
variable.name, this, variable.charOffset, variable.fileUri,
- bound: variable.bound?.clone(newTypes),
+ bound: variable.bound?.clone(newTypes, this, declaration),
isExtensionTypeParameter: isExtensionTypeParameter,
variableVariance:
variable.parameter.isLegacyCovariant ? null : variable.variance);
@@ -3070,6 +3072,91 @@
return count;
}
+ /// Reports an error on generic function types used as bounds
+ ///
+ /// The function recursively searches for all generic function types in
+ /// [typeVariable.bound] and checks the bounds of type variables of the found
+ /// types for being generic function types. Additionally, the function checks
+ /// [typeVariable.bound] for being a generic function type. Returns `true` if
+ /// any errors were reported.
+ bool _recursivelyReportGenericFunctionTypesAsBoundsForVariable(
+ TypeVariableBuilder typeVariable) {
+ if (enableGenericMetadataInLibrary) return false;
+
+ bool hasReportedErrors = false;
+ hasReportedErrors =
+ _reportGenericFunctionTypeAsBoundIfNeeded(typeVariable) ||
+ hasReportedErrors;
+ hasReportedErrors = _recursivelyReportGenericFunctionTypesAsBoundsForType(
+ typeVariable.bound) ||
+ hasReportedErrors;
+ return hasReportedErrors;
+ }
+
+ /// Reports an error on generic function types used as bounds
+ ///
+ /// The function recursively searches for all generic function types in
+ /// [typeBuilder] and checks the bounds of type variables of the found types
+ /// for being generic function types. Returns `true` if any errors were
+ /// reported.
+ bool _recursivelyReportGenericFunctionTypesAsBoundsForType(
+ TypeBuilder typeBuilder) {
+ if (enableGenericMetadataInLibrary) return false;
+
+ List<FunctionTypeBuilder> genericFunctionTypeBuilders =
+ <FunctionTypeBuilder>[];
+ findUnaliasedGenericFunctionTypes(typeBuilder,
+ result: genericFunctionTypeBuilders);
+ bool hasReportedErrors = false;
+ for (FunctionTypeBuilder genericFunctionTypeBuilder
+ in genericFunctionTypeBuilders) {
+ assert(
+ genericFunctionTypeBuilder.typeVariables != null,
+ "Function 'findUnaliasedGenericFunctionTypes' "
+ "returned a function type without type variables.");
+ for (TypeVariableBuilder typeVariable
+ in genericFunctionTypeBuilder.typeVariables) {
+ hasReportedErrors =
+ _reportGenericFunctionTypeAsBoundIfNeeded(typeVariable) ||
+ hasReportedErrors;
+ }
+ }
+ return hasReportedErrors;
+ }
+
+ /// Reports an error if [typeVariable.bound] is a generic function type
+ ///
+ /// Returns `true` if any errors were reported.
+ bool _reportGenericFunctionTypeAsBoundIfNeeded(
+ TypeVariableBuilder typeVariable) {
+ if (enableGenericMetadataInLibrary) return false;
+
+ TypeBuilder bound = typeVariable.bound;
+ bool isUnaliasedGenericFunctionType = bound is FunctionTypeBuilder &&
+ bound.typeVariables != null &&
+ bound.typeVariables.isNotEmpty;
+ bool isAliasedGenericFunctionType = false;
+ if (bound is NamedTypeBuilder) {
+ TypeDeclarationBuilder declaration = bound.declaration;
+ // TODO(dmitryas): Unalias beyond the first layer for the check.
+ if (declaration is TypeAliasBuilder) {
+ TypeBuilder rhsType = declaration.type;
+ if (rhsType is FunctionTypeBuilder &&
+ rhsType.typeVariables != null &&
+ rhsType.typeVariables.isNotEmpty) {
+ isAliasedGenericFunctionType = true;
+ }
+ }
+ }
+
+ if (isUnaliasedGenericFunctionType || isAliasedGenericFunctionType) {
+ addProblem(messageGenericFunctionTypeInBound, typeVariable.charOffset,
+ typeVariable.name.length, typeVariable.fileUri);
+ return true;
+ }
+ return false;
+ }
+
int computeDefaultTypes(TypeBuilder dynamicType, TypeBuilder nullType,
TypeBuilder bottomType, ClassBuilder objectClass) {
int count = 0;
@@ -3081,16 +3168,11 @@
bool haveErroneousBounds = false;
if (!inErrorRecovery) {
if (!enableGenericMetadataInLibrary) {
- for (int i = 0; i < variables.length; ++i) {
- TypeVariableBuilder variable = variables[i];
- List<TypeBuilder> genericFunctionTypes = <TypeBuilder>[];
- findGenericFunctionTypes(variable.bound,
- result: genericFunctionTypes);
- if (genericFunctionTypes.length > 0) {
- haveErroneousBounds = true;
- addProblem(messageGenericFunctionTypeInBound, variable.charOffset,
- variable.name.length, variable.fileUri);
- }
+ for (TypeVariableBuilder variable in variables) {
+ haveErroneousBounds =
+ _recursivelyReportGenericFunctionTypesAsBoundsForVariable(
+ variable) ||
+ haveErroneousBounds;
}
}
@@ -3160,9 +3242,11 @@
}
if (formals != null && formals.isNotEmpty) {
for (FormalParameterBuilder formal in formals) {
- List<Object> issues =
+ List<NonSimplicityIssue> issues =
getInboundReferenceIssuesInType(formal.type);
reportIssues(issues);
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(
+ formal.type);
}
}
});
@@ -3174,10 +3258,14 @@
if (member.formals != null && member.formals.isNotEmpty) {
for (FormalParameterBuilder formal in member.formals) {
issues.addAll(getInboundReferenceIssuesInType(formal.type));
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(
+ formal.type);
}
}
if (member.returnType != null) {
issues.addAll(getInboundReferenceIssuesInType(member.returnType));
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(
+ member.returnType);
}
reportIssues(issues);
count += computeDefaultTypesForVariables(member.typeVariables,
@@ -3189,27 +3277,33 @@
if (fieldType != null) {
List<Object> issues = getInboundReferenceIssuesInType(fieldType);
reportIssues(issues);
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(fieldType);
}
}
});
} else if (declaration is TypeAliasBuilder) {
- List<Object> issues = getNonSimplicityIssuesForDeclaration(declaration,
+ List<NonSimplicityIssue> issues = getNonSimplicityIssuesForDeclaration(
+ declaration,
performErrorRecovery: true);
issues.addAll(getInboundReferenceIssuesInType(declaration.type));
reportIssues(issues);
count += computeDefaultTypesForVariables(declaration.typeVariables,
inErrorRecovery: issues.isNotEmpty);
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(declaration.type);
} else if (declaration is FunctionBuilder) {
List<Object> issues =
getNonSimplicityIssuesForTypeVariables(declaration.typeVariables);
if (declaration.formals != null && declaration.formals.isNotEmpty) {
for (FormalParameterBuilder formal in declaration.formals) {
issues.addAll(getInboundReferenceIssuesInType(formal.type));
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(formal.type);
}
}
if (declaration.returnType != null) {
issues
.addAll(getInboundReferenceIssuesInType(declaration.returnType));
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(
+ declaration.returnType);
}
reportIssues(issues);
count += computeDefaultTypesForVariables(declaration.typeVariables,
@@ -3230,16 +3324,25 @@
if (member.formals != null && member.formals.isNotEmpty) {
for (FormalParameterBuilder formal in member.formals) {
issues.addAll(getInboundReferenceIssuesInType(formal.type));
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(
+ formal.type);
}
}
if (member.returnType != null) {
issues.addAll(getInboundReferenceIssuesInType(member.returnType));
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(
+ member.returnType);
}
reportIssues(issues);
count += computeDefaultTypesForVariables(member.typeVariables,
inErrorRecovery: issues.isNotEmpty);
+ } else if (member is FieldBuilder) {
+ if (member.type != null) {
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(
+ member.type);
+ }
} else {
- assert(member is FieldBuilder,
+ throw new StateError(
"Unexpected extension member $member (${member.runtimeType}).");
}
});
@@ -3248,6 +3351,8 @@
List<Object> issues =
getInboundReferenceIssuesInType(declaration.type);
reportIssues(issues);
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(
+ declaration.type);
}
} else {
assert(
@@ -3268,6 +3373,7 @@
declaration.formals.isNotEmpty) {
for (FormalParameterBuilder formal in declaration.formals) {
reportIssues(getInboundReferenceIssuesInType(formal.type));
+ _recursivelyReportGenericFunctionTypesAsBoundsForType(formal.type);
}
}
}
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 7b81151..5136f0f 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -165,6 +165,7 @@
conversion
conversions
coo
+corge
corners
costly
cov
@@ -358,6 +359,7 @@
goo
google
graphic
+grault
greeting
gtgt
gulp
diff --git a/pkg/front_end/testcases/general/issue45834.dart b/pkg/front_end/testcases/general/issue45834.dart
new file mode 100644
index 0000000..931523e
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45834.dart
@@ -0,0 +1,47 @@
+// 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.
+
+// @dart=2.6
+
+class A1<X extends Function<T>()> {
+ A1(Function<X extends Function<T>()>() f);
+ bar1(Function<X extends Function<T>()>() f) {}
+ Function<X extends Function<T>()>() bar2() => throw 42;
+ Function<X extends Function<T>()>() get baz1 => throw 42;
+ void set qux1(Function<X extends Function<T>()>() value) {}
+ Function<X extends Function<T>()>() quux1 = throw 42;
+ static Function<X extends Function<T>()>() quux2 = throw 42;
+}
+
+class A2<X extends void Function<Y extends Function<T>()>()> {}
+
+class A3<
+ X extends Function(void Function<Y extends Function(Function<T>())>())> {}
+
+foo1(Function<X extends Function<T>()>() f) {}
+foo2(Function<X extends Function(Function<T>())>() f) {}
+Function<X extends Function<T>()>() foo3() => throw 42;
+Function<X extends Function(Function<T>())>() foo4() => throw 42;
+Function<X extends Function<T>()>() get corge1 => throw 42;
+void set grault1(Function<X extends Function<T>()>() value) {}
+Function<X extends Function<T>()>() quuz1 = throw 42;
+
+typedef F1 = void Function<X extends void Function<T>()>();
+typedef F2 = void Function<X extends Function(void Function<T>())>();
+typedef F3<X extends Function<T>()> = Function();
+typedef F4<X extends Function<Y extends Function<T>()>()> = Function();
+typedef F5<X extends Function(Function<Y extends Function(Function<T>())>())>
+ = Function();
+
+class B1 {}
+
+extension E1<X extends Function<T>()> on B1 {
+ bar3(Function<X extends Function<T>()>() f) {}
+ Function<X extends Function<T>()>() bar4() => throw 42;
+ Function<X extends Function<T>()>() get baz2 => throw 42;
+ void set qux2(Function<X extends Function<T>()>() value) {}
+ static Function<X extends Function<T>()>() quux3 = throw 42;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45834.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue45834.dart.textual_outline.expect
new file mode 100644
index 0000000..53e0e60
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45834.dart.textual_outline.expect
@@ -0,0 +1,41 @@
+// @dart = 2.6
+class A1<X extends Function<T>()> {
+ A1(Function<X extends Function<T>()>() f);
+ bar1(Function<X extends Function<T>()>() f) {}
+ Function<X extends Function<T>()>() bar2() => throw 42;
+ Function<X extends Function<T>()>() get baz1 => throw 42;
+ void set qux1(Function<X extends Function<T>()>() value) {}
+ Function<X extends Function<T>()>() quux1 = throw 42;
+ static Function<X extends Function<T>()>() quux2 = throw 42;
+}
+
+class A2<X extends void Function<Y extends Function<T>()>()> {}
+
+class A3<
+ X extends Function(void Function<Y extends Function(Function<T>())>())> {}
+
+foo1(Function<X extends Function<T>()>() f) {}
+foo2(Function<X extends Function(Function<T>())>() f) {}
+Function<X extends Function<T>()>() foo3() => throw 42;
+Function<X extends Function(Function<T>())>() foo4() => throw 42;
+Function<X extends Function<T>()>() get corge1 => throw 42;
+void set grault1(Function<X extends Function<T>()>() value) {}
+Function<X extends Function<T>()>() quuz1 = throw 42;
+typedef F1 = void Function<X extends void Function<T>()>();
+typedef F2 = void Function<X extends Function(void Function<T>())>();
+typedef F3<X extends Function<T>()> = Function();
+typedef F4<X extends Function<Y extends Function<T>()>()> = Function();
+typedef F5<X extends Function(Function<Y extends Function(Function<T>())>())>
+ = Function();
+
+class B1 {}
+
+extension E1<X extends Function<T>()> on B1 {
+ bar3(Function<X extends Function<T>()>() f) {}
+ Function<X extends Function<T>()>() bar4() => throw 42;
+ Function<X extends Function<T>()>() get baz2 => throw 42;
+ void set qux2(Function<X extends Function<T>()>() value) {}
+ static Function<X extends Function<T>()>() quux3 = throw 42;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45834.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue45834.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..2562b2d
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45834.dart.textual_outline_modelled.expect
@@ -0,0 +1,41 @@
+// @dart = 2.6
+Function<X extends Function(Function<T>())>() foo4() => throw 42;
+Function<X extends Function<T>()>() foo3() => throw 42;
+Function<X extends Function<T>()>() get corge1 => throw 42;
+Function<X extends Function<T>()>() quuz1 = throw 42;
+
+class A1<X extends Function<T>()> {
+ A1(Function<X extends Function<T>()>() f);
+ Function<X extends Function<T>()>() bar2() => throw 42;
+ Function<X extends Function<T>()>() get baz1 => throw 42;
+ Function<X extends Function<T>()>() quux1 = throw 42;
+ bar1(Function<X extends Function<T>()>() f) {}
+ static Function<X extends Function<T>()>() quux2 = throw 42;
+ void set qux1(Function<X extends Function<T>()>() value) {}
+}
+
+class A2<X extends void Function<Y extends Function<T>()>()> {}
+
+class A3<
+ X extends Function(void Function<Y extends Function(Function<T>())>())> {}
+
+class B1 {}
+
+extension E1<X extends Function<T>()> on B1 {
+ Function<X extends Function<T>()>() bar4() => throw 42;
+ Function<X extends Function<T>()>() get baz2 => throw 42;
+ bar3(Function<X extends Function<T>()>() f) {}
+ static Function<X extends Function<T>()>() quux3 = throw 42;
+ void set qux2(Function<X extends Function<T>()>() value) {}
+}
+
+foo1(Function<X extends Function<T>()>() f) {}
+foo2(Function<X extends Function(Function<T>())>() f) {}
+main() {}
+typedef F1 = void Function<X extends void Function<T>()>();
+typedef F2 = void Function<X extends Function(void Function<T>())>();
+typedef F3<X extends Function<T>()> = Function();
+typedef F4<X extends Function<Y extends Function<T>()>()> = Function();
+typedef F5<X extends Function(Function<Y extends Function(Function<T>())>())>
+ = Function();
+void set grault1(Function<X extends Function<T>()>() value) {}
diff --git a/pkg/front_end/testcases/general/issue45834.dart.weak.expect b/pkg/front_end/testcases/general/issue45834.dart.weak.expect
new file mode 100644
index 0000000..62ca870
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45834.dart.weak.expect
@@ -0,0 +1,211 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue45834.dart:7:10: Error: Type variables can't have generic function types in their bounds.
+// class A1<X extends Function<T>()> {
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:8:15: Error: Type variables can't have generic function types in their bounds.
+// A1(Function<X extends Function<T>()>() f);
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:9:17: Error: Type variables can't have generic function types in their bounds.
+// bar1(Function<X extends Function<T>()>() f) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:10:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() bar2() => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:11:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() get baz1 => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:13:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() quux1 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:14:19: Error: Type variables can't have generic function types in their bounds.
+// static Function<X extends Function<T>()>() quux2 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:12:26: Error: Type variables can't have generic function types in their bounds.
+// void set qux1(Function<X extends Function<T>()>() value) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:17:10: Error: Type variables can't have generic function types in their bounds.
+// class A2<X extends void Function<Y extends Function<T>()>()> {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:17:34: Error: Type variables can't have generic function types in their bounds.
+// class A2<X extends void Function<Y extends Function<T>()>()> {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:22:15: Error: Type variables can't have generic function types in their bounds.
+// foo1(Function<X extends Function<T>()>() f) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:24:10: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() foo3() => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:26:10: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() get corge1 => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:28:10: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() quuz1 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:30:28: Error: Type variables can't have generic function types in their bounds.
+// typedef F1 = void Function<X extends void Function<T>()>();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:32:12: Error: Type variables can't have generic function types in their bounds.
+// typedef F3<X extends Function<T>()> = Function();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:33:12: Error: Type variables can't have generic function types in their bounds.
+// typedef F4<X extends Function<Y extends Function<T>()>()> = Function();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:33:31: Error: Type variables can't have generic function types in their bounds.
+// typedef F4<X extends Function<Y extends Function<T>()>()> = Function();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:39:14: Error: Type variables can't have generic function types in their bounds.
+// extension E1<X extends Function<T>()> on B1 {
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:40:17: Error: Type variables can't have generic function types in their bounds.
+// bar3(Function<X extends Function<T>()>() f) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:41:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() bar4() => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:42:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() get baz2 => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:44:19: Error: Type variables can't have generic function types in their bounds.
+// static Function<X extends Function<T>()>() quux3 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:43:26: Error: Type variables can't have generic function types in their bounds.
+// void set qux2(Function<X extends Function<T>()>() value) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:27:27: Error: Type variables can't have generic function types in their bounds.
+// void set grault1(Function<X extends Function<T>()>() value) {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef F1 = <X extends <T extends core::Object* = dynamic>() →* void = dynamic>() →* void;
+typedef F2 = <X extends (<T extends core::Object* = dynamic>() →* void) →* dynamic = dynamic>() →* void;
+typedef F3<unrelated X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic> = () →* dynamic;
+typedef F4<unrelated X extends <Y extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic = dynamic> = () →* dynamic;
+typedef F5<unrelated X extends (<Y extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* dynamic) →* dynamic> = () →* dynamic;
+class A1<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic> extends core::Object {
+ field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic quux1 = throw 42;
+ static field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic quux2 = throw 42;
+ constructor •(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → self::A1<self::A1::X*>*
+ : super core::Object::•()
+ ;
+ method bar1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic {}
+ method bar2() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+ get baz1() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+ set qux1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic value) → void {}
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class A2<X extends <Y extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* void = dynamic> extends core::Object {
+ synthetic constructor •() → self::A2<self::A2::X*>*
+ : super core::Object::•()
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class A3<X extends (<Y extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* void) →* dynamic> extends core::Object {
+ synthetic constructor •() → self::A3<self::A3::X*>*
+ : super core::Object::•()
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class B1 extends core::Object {
+ synthetic constructor •() → self::B1*
+ : super core::Object::•()
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+extension E1<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic> on self::B1* {
+ method bar3 = self::E1|bar3;
+ tearoff bar3 = self::E1|get#bar3;
+ method bar4 = self::E1|bar4;
+ tearoff bar4 = self::E1|get#bar4;
+ get baz2 = self::E1|get#baz2;
+ static field quux3 = self::E1|quux3;
+ set qux2 = self::E1|set#qux2;
+}
+static field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic quuz1 = throw 42;
+static field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic E1|quux3 = throw 42;
+static method foo1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic {}
+static method foo2(<X extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* dynamic f) → dynamic {}
+static method foo3() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+static method foo4() → <X extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+static get corge1() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+static set grault1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic value) → void {}
+static method E1|bar3<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this, <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic {}
+static method E1|get#bar3<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → (<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic) →* dynamic
+ return (<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic => self::E1|bar3<self::E1|get#bar3::X*>(#this, f);
+static method E1|bar4<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+static method E1|get#bar4<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → () →* <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return () → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic => self::E1|bar4<self::E1|get#bar4::X*>(#this);
+static method E1|get#baz2<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+static method E1|set#qux2<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this, <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic value) → void {}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/issue45834.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue45834.dart.weak.outline.expect
new file mode 100644
index 0000000..838c120
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45834.dart.weak.outline.expect
@@ -0,0 +1,215 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue45834.dart:7:10: Error: Type variables can't have generic function types in their bounds.
+// class A1<X extends Function<T>()> {
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:8:15: Error: Type variables can't have generic function types in their bounds.
+// A1(Function<X extends Function<T>()>() f);
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:9:17: Error: Type variables can't have generic function types in their bounds.
+// bar1(Function<X extends Function<T>()>() f) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:10:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() bar2() => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:11:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() get baz1 => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:13:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() quux1 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:14:19: Error: Type variables can't have generic function types in their bounds.
+// static Function<X extends Function<T>()>() quux2 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:12:26: Error: Type variables can't have generic function types in their bounds.
+// void set qux1(Function<X extends Function<T>()>() value) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:17:10: Error: Type variables can't have generic function types in their bounds.
+// class A2<X extends void Function<Y extends Function<T>()>()> {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:17:34: Error: Type variables can't have generic function types in their bounds.
+// class A2<X extends void Function<Y extends Function<T>()>()> {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:22:15: Error: Type variables can't have generic function types in their bounds.
+// foo1(Function<X extends Function<T>()>() f) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:24:10: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() foo3() => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:26:10: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() get corge1 => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:28:10: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() quuz1 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:30:28: Error: Type variables can't have generic function types in their bounds.
+// typedef F1 = void Function<X extends void Function<T>()>();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:32:12: Error: Type variables can't have generic function types in their bounds.
+// typedef F3<X extends Function<T>()> = Function();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:33:12: Error: Type variables can't have generic function types in their bounds.
+// typedef F4<X extends Function<Y extends Function<T>()>()> = Function();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:33:31: Error: Type variables can't have generic function types in their bounds.
+// typedef F4<X extends Function<Y extends Function<T>()>()> = Function();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:39:14: Error: Type variables can't have generic function types in their bounds.
+// extension E1<X extends Function<T>()> on B1 {
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:40:17: Error: Type variables can't have generic function types in their bounds.
+// bar3(Function<X extends Function<T>()>() f) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:41:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() bar4() => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:42:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() get baz2 => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:44:19: Error: Type variables can't have generic function types in their bounds.
+// static Function<X extends Function<T>()>() quux3 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:43:26: Error: Type variables can't have generic function types in their bounds.
+// void set qux2(Function<X extends Function<T>()>() value) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:27:27: Error: Type variables can't have generic function types in their bounds.
+// void set grault1(Function<X extends Function<T>()>() value) {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef F1 = <X extends <T extends core::Object* = dynamic>() →* void = dynamic>() →* void;
+typedef F2 = <X extends (<T extends core::Object* = dynamic>() →* void) →* dynamic = dynamic>() →* void;
+typedef F3<unrelated X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic> = () →* dynamic;
+typedef F4<unrelated X extends <Y extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic = dynamic> = () →* dynamic;
+typedef F5<unrelated X extends (<Y extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* dynamic) →* dynamic> = () →* dynamic;
+class A1<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic> extends core::Object {
+ field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic quux1;
+ static field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic quux2;
+ constructor •(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → self::A1<self::A1::X*>*
+ ;
+ method bar1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic
+ ;
+ method bar2() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ ;
+ get baz1() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ ;
+ set qux1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic value) → void
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class A2<X extends <Y extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* void = dynamic> extends core::Object {
+ synthetic constructor •() → self::A2<self::A2::X*>*
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class A3<X extends (<Y extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* void) →* dynamic> extends core::Object {
+ synthetic constructor •() → self::A3<self::A3::X*>*
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class B1 extends core::Object {
+ synthetic constructor •() → self::B1*
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+extension E1<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic> on self::B1* {
+ method bar3 = self::E1|bar3;
+ tearoff bar3 = self::E1|get#bar3;
+ method bar4 = self::E1|bar4;
+ tearoff bar4 = self::E1|get#bar4;
+ get baz2 = self::E1|get#baz2;
+ static field quux3 = self::E1|quux3;
+ set qux2 = self::E1|set#qux2;
+}
+static field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic quuz1;
+static field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic E1|quux3;
+static method foo1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic
+ ;
+static method foo2(<X extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* dynamic f) → dynamic
+ ;
+static method foo3() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ ;
+static method foo4() → <X extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* dynamic
+ ;
+static get corge1() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ ;
+static set grault1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic value) → void
+ ;
+static method E1|bar3<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this, <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic
+ ;
+static method E1|get#bar3<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → (<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic) →* dynamic
+ return (<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic => self::E1|bar3<self::E1|get#bar3::X*>(#this, f);
+static method E1|bar4<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ ;
+static method E1|get#bar4<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → () →* <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return () → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic => self::E1|bar4<self::E1|get#bar4::X*>(#this);
+static method E1|get#baz2<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ ;
+static method E1|set#qux2<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this, <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic value) → void
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/issue45834.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue45834.dart.weak.transformed.expect
new file mode 100644
index 0000000..62ca870
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45834.dart.weak.transformed.expect
@@ -0,0 +1,211 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue45834.dart:7:10: Error: Type variables can't have generic function types in their bounds.
+// class A1<X extends Function<T>()> {
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:8:15: Error: Type variables can't have generic function types in their bounds.
+// A1(Function<X extends Function<T>()>() f);
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:9:17: Error: Type variables can't have generic function types in their bounds.
+// bar1(Function<X extends Function<T>()>() f) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:10:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() bar2() => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:11:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() get baz1 => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:13:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() quux1 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:14:19: Error: Type variables can't have generic function types in their bounds.
+// static Function<X extends Function<T>()>() quux2 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:12:26: Error: Type variables can't have generic function types in their bounds.
+// void set qux1(Function<X extends Function<T>()>() value) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:17:10: Error: Type variables can't have generic function types in their bounds.
+// class A2<X extends void Function<Y extends Function<T>()>()> {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:17:34: Error: Type variables can't have generic function types in their bounds.
+// class A2<X extends void Function<Y extends Function<T>()>()> {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:22:15: Error: Type variables can't have generic function types in their bounds.
+// foo1(Function<X extends Function<T>()>() f) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:24:10: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() foo3() => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:26:10: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() get corge1 => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:28:10: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() quuz1 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:30:28: Error: Type variables can't have generic function types in their bounds.
+// typedef F1 = void Function<X extends void Function<T>()>();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:32:12: Error: Type variables can't have generic function types in their bounds.
+// typedef F3<X extends Function<T>()> = Function();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:33:12: Error: Type variables can't have generic function types in their bounds.
+// typedef F4<X extends Function<Y extends Function<T>()>()> = Function();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:33:31: Error: Type variables can't have generic function types in their bounds.
+// typedef F4<X extends Function<Y extends Function<T>()>()> = Function();
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:39:14: Error: Type variables can't have generic function types in their bounds.
+// extension E1<X extends Function<T>()> on B1 {
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:40:17: Error: Type variables can't have generic function types in their bounds.
+// bar3(Function<X extends Function<T>()>() f) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:41:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() bar4() => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:42:12: Error: Type variables can't have generic function types in their bounds.
+// Function<X extends Function<T>()>() get baz2 => throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:44:19: Error: Type variables can't have generic function types in their bounds.
+// static Function<X extends Function<T>()>() quux3 = throw 42;
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:43:26: Error: Type variables can't have generic function types in their bounds.
+// void set qux2(Function<X extends Function<T>()>() value) {}
+// ^
+//
+// pkg/front_end/testcases/general/issue45834.dart:27:27: Error: Type variables can't have generic function types in their bounds.
+// void set grault1(Function<X extends Function<T>()>() value) {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef F1 = <X extends <T extends core::Object* = dynamic>() →* void = dynamic>() →* void;
+typedef F2 = <X extends (<T extends core::Object* = dynamic>() →* void) →* dynamic = dynamic>() →* void;
+typedef F3<unrelated X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic> = () →* dynamic;
+typedef F4<unrelated X extends <Y extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic = dynamic> = () →* dynamic;
+typedef F5<unrelated X extends (<Y extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* dynamic) →* dynamic> = () →* dynamic;
+class A1<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic> extends core::Object {
+ field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic quux1 = throw 42;
+ static field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic quux2 = throw 42;
+ constructor •(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → self::A1<self::A1::X*>*
+ : super core::Object::•()
+ ;
+ method bar1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic {}
+ method bar2() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+ get baz1() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+ set qux1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic value) → void {}
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class A2<X extends <Y extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* void = dynamic> extends core::Object {
+ synthetic constructor •() → self::A2<self::A2::X*>*
+ : super core::Object::•()
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class A3<X extends (<Y extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* void) →* dynamic> extends core::Object {
+ synthetic constructor •() → self::A3<self::A3::X*>*
+ : super core::Object::•()
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class B1 extends core::Object {
+ synthetic constructor •() → self::B1*
+ : super core::Object::•()
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+extension E1<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic> on self::B1* {
+ method bar3 = self::E1|bar3;
+ tearoff bar3 = self::E1|get#bar3;
+ method bar4 = self::E1|bar4;
+ tearoff bar4 = self::E1|get#bar4;
+ get baz2 = self::E1|get#baz2;
+ static field quux3 = self::E1|quux3;
+ set qux2 = self::E1|set#qux2;
+}
+static field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic quuz1 = throw 42;
+static field <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic E1|quux3 = throw 42;
+static method foo1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic {}
+static method foo2(<X extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* dynamic f) → dynamic {}
+static method foo3() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+static method foo4() → <X extends (<T extends core::Object* = dynamic>() →* dynamic) →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+static get corge1() → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+static set grault1(<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic value) → void {}
+static method E1|bar3<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this, <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic {}
+static method E1|get#bar3<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → (<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic) →* dynamic
+ return (<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic f) → dynamic => self::E1|bar3<self::E1|get#bar3::X*>(#this, f);
+static method E1|bar4<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+static method E1|get#bar4<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → () →* <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return () → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic => self::E1|bar4<self::E1|get#bar4::X*>(#this);
+static method E1|get#baz2<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this) → <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic
+ return throw 42;
+static method E1|set#qux2<X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>(lowered final self::B1* #this, <X extends <T extends core::Object* = dynamic>() →* dynamic = dynamic>() →* dynamic value) → void {}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.expect b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.expect
index 3444c42..50a886c 100644
--- a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.expect
+++ b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.expect
@@ -7,6 +7,7 @@
// ^
//
import self as self;
+import "dart:core" as core;
typedef Handle = invalid-type;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.outline.expect b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.outline.expect
index dc3f69b..74c6c6a 100644
--- a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.outline.expect
@@ -7,6 +7,7 @@
// ^
//
import self as self;
+import "dart:core" as core;
typedef Handle = invalid-type;
static method main() → dynamic
diff --git a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.transformed.expect b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.transformed.expect
index 3444c42..50a886c 100644
--- a/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/rasta/malformed_function_type.dart.weak.transformed.expect
@@ -7,6 +7,7 @@
// ^
//
import self as self;
+import "dart:core" as core;
typedef Handle = invalid-type;
static method main() → dynamic {
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index e5422e8..1fb72f2 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -824,7 +824,7 @@
// TODO(johnniwinther): Make this non-nullable.
DartType? type;
- // The following two fields describe parameters of the underlying type when
+ // The following fields describe parameters of the underlying type when
// that is a function type. They are needed to keep such attributes as names
// and annotations. When the underlying type is not a function type, they are
// empty.
@@ -849,6 +849,9 @@
this.namedParameters = namedParameters ?? <VariableDeclaration>[],
super(reference) {
setParents(this.typeParameters, this);
+ setParents(this.typeParametersOfFunctionType, this);
+ setParents(this.positionalParameters, this);
+ setParents(this.namedParameters, this);
}
Library get enclosingLibrary => parent as Library;
@@ -864,6 +867,9 @@
visitList(annotations, v);
visitList(typeParameters, v);
type?.accept(v);
+ visitList(typeParametersOfFunctionType, v);
+ visitList(positionalParameters, v);
+ visitList(namedParameters, v);
}
@override
@@ -873,6 +879,9 @@
if (type != null) {
type = v.visitDartType(type!);
}
+ v.transformList(typeParametersOfFunctionType, this);
+ v.transformList(positionalParameters, this);
+ v.transformList(namedParameters, this);
}
@override
@@ -887,6 +896,9 @@
type = newType;
}
}
+ v.transformTypeParameterList(typeParametersOfFunctionType, this);
+ v.transformVariableDeclarationList(positionalParameters, this);
+ v.transformVariableDeclarationList(namedParameters, this);
}
@override
@@ -4021,6 +4033,7 @@
receiver.accept(v);
interfaceTarget.acceptReference(v);
name.accept(v);
+ resultType.accept(v);
}
@override
@@ -4030,6 +4043,10 @@
receiver = v.transform(receiver);
receiver.parent = this;
}
+ // ignore: unnecessary_null_comparison
+ if (resultType != null) {
+ resultType = v.visitDartType(resultType);
+ }
}
@override
@@ -4039,6 +4056,10 @@
receiver = v.transform(receiver);
receiver.parent = this;
}
+ // ignore: unnecessary_null_comparison
+ if (resultType != null) {
+ resultType = v.visitDartType(resultType, cannotRemoveSentinel);
+ }
}
@override
@@ -4168,6 +4189,7 @@
receiver.accept(v);
interfaceTarget.acceptReference(v);
name.accept(v);
+ resultType.accept(v);
}
@override
@@ -4177,6 +4199,10 @@
receiver = v.transform(receiver);
receiver.parent = this;
}
+ // ignore: unnecessary_null_comparison
+ if (resultType != null) {
+ resultType = v.visitDartType(resultType);
+ }
}
@override
@@ -4186,6 +4212,10 @@
receiver = v.transform(receiver);
receiver.parent = this;
}
+ // ignore: unnecessary_null_comparison
+ if (resultType != null) {
+ resultType = v.visitDartType(resultType, cannotRemoveSentinel);
+ }
}
@override
@@ -5284,6 +5314,7 @@
interfaceTarget.acceptReference(v);
name.accept(v);
arguments.accept(v);
+ functionType.accept(v);
}
@override
@@ -5298,6 +5329,10 @@
arguments = v.transform(arguments);
arguments.parent = this;
}
+ // ignore: unnecessary_null_comparison
+ if (functionType != null) {
+ functionType = v.visitDartType(functionType) as FunctionType;
+ }
}
@override
@@ -5312,6 +5347,11 @@
arguments = v.transform(arguments);
arguments.parent = this;
}
+ // ignore: unnecessary_null_comparison
+ if (functionType != null) {
+ functionType =
+ v.visitDartType(functionType, cannotRemoveSentinel) as FunctionType;
+ }
}
@override
@@ -5589,6 +5629,7 @@
receiver.accept(v);
name.accept(v);
arguments.accept(v);
+ functionType?.accept(v);
}
@override
@@ -5603,6 +5644,10 @@
arguments = v.transform(arguments);
arguments.parent = this;
}
+ FunctionType? type = functionType;
+ if (type != null) {
+ functionType = v.visitDartType(type) as FunctionType;
+ }
}
@override
@@ -5617,6 +5662,11 @@
arguments = v.transform(arguments);
arguments.parent = this;
}
+ FunctionType? type = functionType;
+ if (type != null) {
+ functionType =
+ v.visitDartType(type, cannotRemoveSentinel) as FunctionType;
+ }
}
@override
@@ -5682,6 +5732,7 @@
@override
void visitChildren(Visitor v) {
arguments.accept(v);
+ functionType.accept(v);
}
@override
@@ -5691,6 +5742,10 @@
arguments = v.transform(arguments);
arguments.parent = this;
}
+ // ignore: unnecessary_null_comparison
+ if (functionType != null) {
+ functionType = v.visitDartType(functionType) as FunctionType;
+ }
}
@override
@@ -5700,6 +5755,11 @@
arguments = v.transform(arguments);
arguments.parent = this;
}
+ // ignore: unnecessary_null_comparison
+ if (functionType != null) {
+ functionType =
+ v.visitDartType(functionType, cannotRemoveSentinel) as FunctionType;
+ }
}
@override
@@ -5832,6 +5892,7 @@
left.accept(v);
interfaceTarget.acceptReference(v);
right.accept(v);
+ functionType.accept(v);
}
@override
@@ -5846,6 +5907,10 @@
right = v.transform(right);
right.parent = this;
}
+ // ignore: unnecessary_null_comparison
+ if (functionType != null) {
+ functionType = v.visitDartType(functionType) as FunctionType;
+ }
}
@override
@@ -5860,6 +5925,11 @@
right = v.transform(right);
right.parent = this;
}
+ // ignore: unnecessary_null_comparison
+ if (functionType != null) {
+ functionType =
+ v.visitDartType(functionType, cannotRemoveSentinel) as FunctionType;
+ }
}
@override
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index ad79a99..aec9d76 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -262,7 +262,8 @@
assert(state == null);
typedefState[node] = TypedefState.BeingChecked;
Set<TypeParameter> savedTypeParameters = typeParametersInScope;
- typeParametersInScope = node.typeParameters.toSet();
+ typeParametersInScope = node.typeParameters.toSet()
+ ..addAll(node.typeParametersOfFunctionType);
TreeNode? savedParent = currentParent;
currentParent = node;
// Visit children without checking the parent pointer on the typedef itself
@@ -540,7 +541,8 @@
!(parent is ForStatement && parent.body != node) &&
!(parent is ForInStatement && parent.body != node) &&
parent is! Let &&
- parent is! LocalInitializer) {
+ parent is! LocalInitializer &&
+ parent is! Typedef) {
problem(
node,
"VariableDeclaration must be a direct child of a Block, "
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index 45b2e84..5841c60 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -253,6 +253,20 @@
/// `C` and `D` are declared in different packages.
const _Sealed sealed = _Sealed();
+/// Used to annotate a method, field, or getter within a class, mixin, or
+/// extension, or a or top-level getter, variable or function to indicate that
+/// the value obtained by invoking it should be use. A value is considered used
+/// if it is assigned to a variable, passed to a function, or used as the target
+/// of an invocation, or invoked (if the result is itself a function).
+///
+/// Tools, such as the analyzer, can provide feedback if
+///
+/// * the annotation is associated with anything other than a method, field or
+/// getter, top-level variable, getter or function or
+/// * the value obtained by a method, field, getter or top-level getter,
+/// variable or function annotated with `@useResult` is not used.
+const UseResult useResult = UseResult();
+
/// Used to annotate a field that is allowed to be overridden in Strong Mode.
///
/// Deprecated: Most of strong mode is now the default in 2.0, but the notion of
@@ -314,6 +328,23 @@
const Required([this.reason = '']);
}
+/// See [useResult] for more details.
+@Target({
+ TargetKind.field,
+ TargetKind.function,
+ TargetKind.getter,
+ TargetKind.method,
+ TargetKind.topLevelVariable,
+})
+class UseResult {
+ /// A human-readable explanation of the reason why the value returned by
+ /// accessing this member should be checked.
+ final String reason;
+
+ /// Initialize a newly created instance to have the given [reason].
+ const UseResult([this.reason = '']);
+}
+
class _AlwaysThrows {
const _AlwaysThrows();
}
diff --git a/pkg/meta/lib/meta_meta.dart b/pkg/meta/lib/meta_meta.dart
index 5090b05..65af6b6 100644
--- a/pkg/meta/lib/meta_meta.dart
+++ b/pkg/meta/lib/meta_meta.dart
@@ -73,6 +73,10 @@
/// at the top-level of a library.
setter,
+ /// Indicates that an annotation is valid on any top-level variable
+ /// declaration.
+ topLevelVariable,
+
/// Indicates that an annotation is valid on any declaration that introduces a
/// type. This includes classes, enums, mixins and typedefs, but does not
/// include extensions because extensions don't introduce a type.
diff --git a/pkg/telemetry/analysis_options.yaml b/pkg/telemetry/analysis_options.yaml
index 250980e..0fcad72 100644
--- a/pkg/telemetry/analysis_options.yaml
+++ b/pkg/telemetry/analysis_options.yaml
@@ -1,11 +1,8 @@
+include: package:lints/recommended.yaml
+
analyzer:
strong-mode:
implicit-casts: false
linter:
rules:
- - annotate_overrides
- - empty_constructor_bodies
- - empty_statements
- unawaited_futures
- - unnecessary_brace_in_string_interps
- - valid_regexps
diff --git a/pkg/telemetry/lib/crash_reporting.dart b/pkg/telemetry/lib/crash_reporting.dart
index 63d549b..5ec776f 100644
--- a/pkg/telemetry/lib/crash_reporting.dart
+++ b/pkg/telemetry/lib/crash_reporting.dart
@@ -45,7 +45,7 @@
final String crashProductId;
final EnablementCallback shouldSend;
final http.Client _httpClient;
- final Stopwatch _processStopwatch = new Stopwatch()..start();
+ final Stopwatch _processStopwatch = Stopwatch()..start();
final ThrottlingBucket _throttle = ThrottlingBucket(10, Duration(minutes: 1));
int _reportsSent = 0;
@@ -56,8 +56,8 @@
this.shouldSend, {
http.Client? httpClient,
String endpointPath = _crashEndpointPathStaging,
- }) : _httpClient = httpClient ?? new http.Client(),
- _baseUri = new Uri(
+ }) : _httpClient = httpClient ?? http.Client(),
+ _baseUri = Uri(
scheme: 'https', host: _crashServerHost, path: endpointPath);
/// Create a new [CrashReportSender] connected to the staging endpoint.
@@ -120,7 +120,7 @@
},
);
- final http.MultipartRequest req = new http.MultipartRequest('POST', uri);
+ final http.MultipartRequest req = http.MultipartRequest('POST', uri);
Map<String, String> fields = req.fields;
fields['product'] = crashProductId;
@@ -144,9 +144,9 @@
fields['weight'] = weight.toString();
}
- final Chain chain = new Chain.forTrace(stackTrace);
+ final Chain chain = Chain.forTrace(stackTrace);
req.files.add(
- new http.MultipartFile.fromString(
+ http.MultipartFile.fromString(
_stackTraceFileField,
chain.terse.toString(),
filename: _stackTraceFilename,
@@ -155,7 +155,7 @@
for (var attachment in attachments) {
req.files.add(
- new http.MultipartFile.fromString(
+ http.MultipartFile.fromString(
attachment._field,
attachment._value,
filename: attachment._field,
@@ -200,4 +200,4 @@
/// A typedef to allow crash reporting to query as to whether it should send a
/// crash report.
-typedef bool EnablementCallback();
+typedef EnablementCallback = bool Function();
diff --git a/pkg/telemetry/lib/src/utils.dart b/pkg/telemetry/lib/src/utils.dart
index 2c38478..55597ff 100644
--- a/pkg/telemetry/lib/src/utils.dart
+++ b/pkg/telemetry/lib/src/utils.dart
@@ -15,7 +15,7 @@
final Duration replenishDuration;
late int _drops = bucketSize;
- late int _lastReplenish = new DateTime.now().millisecondsSinceEpoch;
+ late int _lastReplenish = DateTime.now().millisecondsSinceEpoch;
ThrottlingBucket(this.bucketSize, this.replenishDuration);
@@ -31,7 +31,7 @@
}
void _checkReplenish() {
- int now = new DateTime.now().millisecondsSinceEpoch;
+ int now = DateTime.now().millisecondsSinceEpoch;
int replenishMillis = replenishDuration.inMilliseconds;
diff --git a/pkg/telemetry/lib/telemetry.dart b/pkg/telemetry/lib/telemetry.dart
index e76e622..d394eff 100644
--- a/pkg/telemetry/lib/telemetry.dart
+++ b/pkg/telemetry/lib/telemetry.dart
@@ -6,8 +6,11 @@
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
+// ignore: implementation_imports
import 'package:usage/src/usage_impl.dart';
+// ignore: implementation_imports
import 'package:usage/src/usage_impl_io.dart';
+// ignore: implementation_imports
import 'package:usage/src/usage_impl_io.dart' as usage_io show getDartVersion;
import 'package:usage/usage.dart';
import 'package:usage/usage_io.dart';
@@ -15,7 +18,7 @@
export 'package:usage/usage.dart' show Analytics;
// TODO(devoncarew): Don't show the UI until we're ready to ship.
-final bool SHOW_ANALYTICS_UI = false;
+final bool showAnalyticsUI = false;
final String _dartDirectoryName = '.dart';
final String _settingsFileName = 'analytics.json';
@@ -38,7 +41,7 @@
/// be disabled with --no-analytics).'`
String createAnalyticsStatusMessage(
bool enabled, {
- String command: 'analytics',
+ String command = 'analytics',
}) {
String currentState = enabled ? 'enabled' : 'disabled';
String toggleState = enabled ? 'disabled' : 'enabled';
@@ -63,7 +66,7 @@
if (dir == null) {
// Some systems don't support user home directories; for those, fail
// gracefully by returning a disabled analytics object.
- return new _DisabledAnalytics(trackingId, applicationName);
+ return _DisabledAnalytics(trackingId, applicationName);
}
if (!dir.existsSync()) {
@@ -72,12 +75,12 @@
} catch (e) {
// If we can't create the directory for the analytics settings, fail
// gracefully by returning a disabled analytics object.
- return new _DisabledAnalytics(trackingId, applicationName);
+ return _DisabledAnalytics(trackingId, applicationName);
}
}
- File settingsFile = new File(path.join(dir.path, _settingsFileName));
- return new _TelemetryAnalytics(
+ File settingsFile = File(path.join(dir.path, _settingsFileName));
+ return _TelemetryAnalytics(
trackingId,
applicationName,
getDartVersion(),
@@ -96,10 +99,10 @@
/// directory does not exist.
@visibleForTesting
Directory? getDartStorageDirectory() {
- Directory homeDirectory = new Directory(userHomeDir());
+ Directory homeDirectory = Directory(userHomeDir());
if (!homeDirectory.existsSync()) return null;
- return new Directory(path.join(homeDirectory.path, _dartDirectoryName));
+ return Directory(path.join(homeDirectory.path, _dartDirectoryName));
}
/// Return the version of the Dart SDK.
@@ -118,8 +121,8 @@
required this.forceEnabled,
}) : super(
trackingId,
- new IOPersistentProperties.fromFile(settingsFile),
- new IOPostHandler(),
+ IOPersistentProperties.fromFile(settingsFile),
+ IOPostHandler(),
applicationName: applicationName,
applicationVersion: applicationVersion,
) {
diff --git a/pkg/telemetry/test/crash_reporting_test.dart b/pkg/telemetry/test/crash_reporting_test.dart
index 79cf728..ef6bc6f 100644
--- a/pkg/telemetry/test/crash_reporting_test.dart
+++ b/pkg/telemetry/test/crash_reporting_test.dart
@@ -18,20 +18,21 @@
late Request request;
setUp(() {
- mockClient = new MockClient((Request r) async {
+ mockClient = MockClient((Request r) async {
request = r;
- return new Response('crash-report-001', 200);
+ return Response('crash-report-001', 200);
});
- analytics = new AnalyticsMock()..enabled = true;
+ analytics = AnalyticsMock()..enabled = true;
});
- EnablementCallback shouldSend = () {
+ EnablementCallback shouldSend;
+ shouldSend = () {
return true;
};
test('general', () async {
- CrashReportSender sender = new CrashReportSender.prod(
+ CrashReportSender sender = CrashReportSender.prod(
analytics.trackingId, shouldSend,
httpClient: mockClient);
@@ -43,7 +44,7 @@
});
test('reportsSent', () async {
- CrashReportSender sender = new CrashReportSender.prod(
+ CrashReportSender sender = CrashReportSender.prod(
analytics.trackingId, shouldSend,
httpClient: mockClient);
@@ -59,7 +60,7 @@
});
test('contains message', () async {
- CrashReportSender sender = new CrashReportSender.prod(
+ CrashReportSender sender = CrashReportSender.prod(
analytics.trackingId, shouldSend,
httpClient: mockClient);
@@ -73,7 +74,7 @@
});
test('has attachments', () async {
- CrashReportSender sender = new CrashReportSender.prod(
+ CrashReportSender sender = CrashReportSender.prod(
analytics.trackingId, shouldSend,
httpClient: mockClient);
@@ -94,7 +95,7 @@
});
test('has ptime', () async {
- CrashReportSender sender = new CrashReportSender.prod(
+ CrashReportSender sender = CrashReportSender.prod(
analytics.trackingId, shouldSend,
httpClient: mockClient);
diff --git a/pkg/telemetry/test/utils_test.dart b/pkg/telemetry/test/utils_test.dart
index 2a9fcec..7f72c8a 100644
--- a/pkg/telemetry/test/utils_test.dart
+++ b/pkg/telemetry/test/utils_test.dart
@@ -8,12 +8,12 @@
void main() {
group('ThrottlingBucket', () {
test('can send', () {
- ThrottlingBucket bucket = new ThrottlingBucket(10, Duration(minutes: 1));
+ ThrottlingBucket bucket = ThrottlingBucket(10, Duration(minutes: 1));
expect(bucket.removeDrop(), true);
});
test("doesn't send too many", () {
- ThrottlingBucket bucket = new ThrottlingBucket(10, Duration(minutes: 1));
+ ThrottlingBucket bucket = ThrottlingBucket(10, Duration(minutes: 1));
for (int i = 0; i < 10; i++) {
expect(bucket.removeDrop(), true);
}
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 658d67d..00d1c06 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -142,15 +142,6 @@
super.defaultNode(node);
}
- @override
- visitTypedef(Typedef node) {
- super.visitTypedef(node);
- // These sub-nodes can have annotations but are not visited by
- // Typedef.visitChildren.
- visitList(node.positionalParameters, this);
- visitList(node.namedParameters, this);
- }
-
void _cleanupAnnotations(Node node, List<Expression> annotations) {
if (node is VariableDeclaration ||
node is Member ||
diff --git a/runtime/tests/vm/dart/regress_45966_test.dart b/runtime/tests/vm/dart/regress_45966_test.dart
new file mode 100644
index 0000000..ee4c70b
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_45966_test.dart
@@ -0,0 +1,24 @@
+// 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.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/45966.
+// Verifies that compiler doesn't crash if Typedef is only used from
+// function type of a call.
+
+import 'package:expect/expect.dart';
+
+class Message {}
+
+typedef void FooHandler(Message message);
+
+class A {
+ A(this.handler);
+ final FooHandler handler;
+}
+
+A? a;
+
+main() {
+ a?.handler(Message());
+}
diff --git a/runtime/tests/vm/dart_2/regress_45966_test.dart b/runtime/tests/vm/dart_2/regress_45966_test.dart
new file mode 100644
index 0000000..402d07c
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_45966_test.dart
@@ -0,0 +1,24 @@
+// 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.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/45966.
+// Verifies that compiler doesn't crash if Typedef is only used from
+// function type of a call.
+
+import 'package:expect/expect.dart';
+
+class Message {}
+
+typedef void FooHandler(Message message);
+
+class A {
+ A(this.handler);
+ final FooHandler handler;
+}
+
+A a;
+
+main() {
+ a?.handler(Message());
+}
diff --git a/sdk/bin/dart2native b/sdk/bin/dart2native
index 29f29d7..057490f 100755
--- a/sdk/bin/dart2native
+++ b/sdk/bin/dart2native
@@ -22,4 +22,4 @@
SNAPSHOTS_DIR="${BIN_DIR}/snapshots"
DART="$BIN_DIR/dart"
-exec "$DART" "${SNAPSHOTS_DIR}/dart2native.dart.snapshot" $*
+exec "$DART" "${SNAPSHOTS_DIR}/dart2native.dart.snapshot" "$@"
diff --git a/tests/language/function/type_alias6_test.dart b/tests/language/function/type_alias6_test.dart
index f8e508d..1694d82 100644
--- a/tests/language/function/type_alias6_test.dart
+++ b/tests/language/function/type_alias6_test.dart
@@ -6,9 +6,8 @@
import "package:expect/expect.dart";
typedef F(List<F> x);
-// [error line 8, column 1, length 21]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F' has a reference to itself.
typedef D C();
diff --git a/tests/language/function/type_alias9_test.dart b/tests/language/function/type_alias9_test.dart
index 71c0d7b..12ad3d6 100644
--- a/tests/language/function/type_alias9_test.dart
+++ b/tests/language/function/type_alias9_test.dart
@@ -4,12 +4,11 @@
// Dart test for legally self referencing function type alias.
typedef void F(List<G> l);
-// [error line 6, column 1, length 26]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F' has a reference to itself.
typedef void G(List<F> l);
-// [error line 11, column 1, length 26]
+// ^
// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
main() {
diff --git a/tests/language/regress/regress33479_test.dart b/tests/language/regress/regress33479_test.dart
index 38b558c3..fe9ca03 100644
--- a/tests/language/regress/regress33479_test.dart
+++ b/tests/language/regress/regress33479_test.dart
@@ -3,7 +3,7 @@
// [analyzer] COMPILE_TIME_ERROR.NOT_INSTANTIATED_BOUND
typedef Fisk = void Function // don't merge lines
-// [error line 5, column 1, length 346]
+// ^^^^
// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^
// [cfe] Generic type 'Fisk' can't be used without type arguments in the bounds of its own type variables. It is referenced indirectly through 'Hest'.
diff --git a/tests/language/typedef/cyclic2_test.dart b/tests/language/typedef/cyclic2_test.dart
index cf8befc..f61cdc8 100644
--- a/tests/language/typedef/cyclic2_test.dart
+++ b/tests/language/typedef/cyclic2_test.dart
@@ -6,62 +6,53 @@
// A body dependency, cycle length 1.
typedef F1<X> = F1<X> Function();
-// [error line 8, column 1, length 33]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F1' has a reference to itself.
// A body dependency (in a bound), cycle length 1.
typedef F2<X> = Function<Y extends F2<X>>(Y);
-// [error line 15, column 1, length 45]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F2' has a reference to itself.
// A bound dependency, cycle length 1.
typedef F3<X extends F3<X>> = Function(X);
-// [error line 22, column 1, length 42]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F3' has a reference to itself.
// A body dependency, cycle length 2.
typedef F4a<X> = F4b<X> Function();
-// [error line 29, column 1, length 35]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^^^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F4a' has a reference to itself.
typedef F4b<X> = F4a<X> Function();
-// [error line 35, column 1, length 35]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^^^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F4b' has a reference to itself.
// A body dependency (in a bound), cycle length 2.
typedef F5a<X> = Function<Y extends F5b<X>>(Y);
-// [error line 42, column 1, length 47]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^^^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F5a' has a reference to itself.
typedef F5b<X> = Function<Y extends F5a<X>>(Y);
-// [error line 48, column 1, length 47]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^^^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F5b' has a reference to itself.
// A bound dependency, cycle length 2.
typedef F6a<X extends F6b<X>> = Function(X);
-// [error line 55, column 1, length 44]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^^^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F6a' has a reference to itself.
typedef F6b<X extends F6a<X>> = Function(X);
-// [error line 61, column 1, length 44]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^^^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F6b' has a reference to itself.
void main() {}
diff --git a/tests/language_2/function/type_alias6_test.dart b/tests/language_2/function/type_alias6_test.dart
index b9a8704..55ade34 100644
--- a/tests/language_2/function/type_alias6_test.dart
+++ b/tests/language_2/function/type_alias6_test.dart
@@ -8,9 +8,8 @@
import "package:expect/expect.dart";
typedef F(List<F> x);
-// [error line 10, column 1, length 21]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F' has a reference to itself.
typedef D C();
diff --git a/tests/language_2/function/type_alias9_test.dart b/tests/language_2/function/type_alias9_test.dart
index bfb0db5..ed8029a 100644
--- a/tests/language_2/function/type_alias9_test.dart
+++ b/tests/language_2/function/type_alias9_test.dart
@@ -6,12 +6,11 @@
// @dart = 2.9
typedef void F(List<G> l);
-// [error line 8, column 1, length 26]
-// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^
+// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// [cfe] The typedef 'F' has a reference to itself.
typedef void G(List<F> l);
-// [error line 13, column 1, length 26]
+// ^
// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
main() {
diff --git a/tests/language_2/regress/regress33479_test.dart b/tests/language_2/regress/regress33479_test.dart
index 3e038ac..492913e 100644
--- a/tests/language_2/regress/regress33479_test.dart
+++ b/tests/language_2/regress/regress33479_test.dart
@@ -7,7 +7,7 @@
// [analyzer] COMPILE_TIME_ERROR.NOT_INSTANTIATED_BOUND
typedef Fisk = void Function // don't merge lines
-// [error line 9, column 1, length 346]
+// ^^^^
// [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
// ^
// [cfe] Generic type 'Fisk' can't be used without type arguments in the bounds of its own type variables. It is referenced indirectly through 'Hest'.
diff --git a/tools/VERSION b/tools/VERSION
index 0f5b868..b247895 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 128
+PRERELEASE 129
PRERELEASE_PATCH 0
\ No newline at end of file