Version 2.13.0-56.0.dev
Merge commit '32fe29617ef6e56bb00d48db0bb2a8f67e1eff16' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index bfcdff4..2545c3a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -3857,6 +3857,30 @@
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
+ Message Function(String name)> templateFfiFieldNull = const Template<
+ Message Function(String name)>(
+ messageTemplate:
+ r"""Field '#name' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct`.""",
+ withArguments: _withArgumentsFfiFieldNull);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)> codeFfiFieldNull =
+ const Code<Message Function(String name)>(
+ "FfiFieldNull",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFfiFieldNull(String name) {
+ if (name.isEmpty) throw 'No name provided';
+ name = demangleMixinApplicationName(name);
+ return new Message(codeFfiFieldNull,
+ message:
+ """Field '${name}' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct`.""",
+ arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
Message Function(String name)> templateFfiNotStatic = const Template<
Message Function(String name)>(
messageTemplate:
diff --git a/pkg/analysis_server/lib/src/cider/assists.dart b/pkg/analysis_server/lib/src/cider/assists.dart
new file mode 100644
index 0000000..ba46cce
--- /dev/null
+++ b/pkg/analysis_server/lib/src/cider/assists.dart
@@ -0,0 +1,49 @@
+// 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/plugin/edit/assist/assist_core.dart';
+import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/correction/assist_internal.dart';
+import 'package:analysis_server/src/services/correction/change_workspace.dart';
+import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/instrumentation/service.dart';
+import 'package:analyzer/src/dart/analysis/performance_logger.dart';
+import 'package:analyzer/src/dart/micro/resolve_file.dart';
+
+class CiderAssistsComputer {
+ final PerformanceLog _logger;
+ final FileResolver _fileResolver;
+
+ CiderAssistsComputer(this._logger, this._fileResolver);
+
+ /// Compute quick assists on the line and character position.
+ Future<List<Assist>> compute(
+ String path, int lineNumber, int colNumber, int length) async {
+ var result = <Assist>[];
+ var resolvedUnit = _fileResolver.resolve(path: path);
+ var lineInfo = resolvedUnit.lineInfo;
+ var offset = lineInfo.getOffsetOfLine(lineNumber) + colNumber;
+
+ await _logger.runAsync('Compute assists', () async {
+ try {
+ var workspace = DartChangeWorkspace([resolvedUnit.session]);
+ var context = DartAssistContextImpl(
+ InstrumentationService.NULL_SERVICE,
+ workspace,
+ resolvedUnit,
+ offset,
+ length,
+ );
+ final processor = AssistProcessor(context);
+ final assists = await processor.compute();
+ assists.sort(Assist.SORT_BY_RELEVANCE);
+ result.addAll(assists);
+ } on InconsistentAnalysisException {
+ // If an InconsistentAnalysisException occurs, it's likely the user modified
+ // the source and therefore is no longer interested in the results.
+ }
+ });
+ return result;
+ }
+}
diff --git a/pkg/analysis_server/test/src/cider/assists_test.dart b/pkg/analysis_server/test/src/cider/assists_test.dart
new file mode 100644
index 0000000..aa1fc47
--- /dev/null
+++ b/pkg/analysis_server/test/src/cider/assists_test.dart
@@ -0,0 +1,123 @@
+// 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/plugin/edit/assist/assist_core.dart';
+import 'package:analysis_server/src/cider/assists.dart';
+import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analyzer/source/line_info.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart' show SourceEdit;
+import 'package:analyzer_plugin/utilities/assist/assist.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'cider_service.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(CiderAssistsComputerTest);
+ });
+}
+
+@reflectiveTest
+class CiderAssistsComputerTest extends CiderServiceTest {
+ _CorrectionContext _correctionContext;
+ List<Assist> _assists;
+
+ void assertHasAssist(AssistKind kind, String expected) {
+ var assist = _getAssist(kind);
+
+ var fileEdits = assist.change.edits;
+ expect(fileEdits, hasLength(1));
+
+ var resultContent = SourceEdit.applySequence(
+ _correctionContext.content,
+ fileEdits.single.edits,
+ );
+ expect(resultContent, expected);
+ }
+
+ Future<void> test_addReturnType() async {
+ await _compute(r'''
+void m() {
+ ^f() {
+ return '';
+ }
+}
+''');
+
+ assertHasAssist(DartAssistKind.ADD_RETURN_TYPE, r'''
+void m() {
+ String f() {
+ return '';
+ }
+}
+''');
+ }
+
+ Future<void> test_assignToLocalVariable() async {
+ await _compute(r'''
+main() {
+ 12^345;
+}
+''');
+
+ assertHasAssist(DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE, r'''
+main() {
+ var i = 12345;
+}
+''');
+ }
+
+ Future<void> _compute(String content) async {
+ _updateFile(content);
+
+ var result = await CiderAssistsComputer(
+ logger,
+ fileResolver,
+ ).compute(
+ convertPath(testPath),
+ _correctionContext.line,
+ _correctionContext.character,
+ 0,
+ );
+ _assists = result;
+ }
+
+ Assist _getAssist(AssistKind kind) {
+ for (var assist in _assists) {
+ if (assist.kind == kind) {
+ return assist;
+ }
+ }
+ fail('No assist $kind');
+ }
+
+ void _updateFile(String content) {
+ var offset = content.indexOf('^');
+ expect(offset, isPositive, reason: 'Expected to find ^');
+ expect(content.indexOf('^', offset + 1), -1, reason: 'Expected only one ^');
+
+ var lineInfo = LineInfo.fromContent(content);
+ var location = lineInfo.getLocation(offset);
+
+ content = content.substring(0, offset) + content.substring(offset + 1);
+ newFile(testPath, content: content);
+
+ _correctionContext = _CorrectionContext(
+ content,
+ offset,
+ location.lineNumber - 1,
+ location.columnNumber - 1,
+ );
+ }
+}
+
+class _CorrectionContext {
+ final String content;
+ final int offset;
+ final int line;
+ final int character;
+
+ _CorrectionContext(this.content, this.offset, this.line, this.character);
+}
diff --git a/pkg/analysis_server/test/src/cider/test_all.dart b/pkg/analysis_server/test/src/cider/test_all.dart
index 9aea1f0..524383b 100644
--- a/pkg/analysis_server/test/src/cider/test_all.dart
+++ b/pkg/analysis_server/test/src/cider/test_all.dart
@@ -4,11 +4,13 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'assists_test.dart' as assists;
import 'completion_test.dart' as completion;
import 'fixes_test.dart' as fixes;
void main() {
defineReflectiveSuite(() {
+ assists.main();
completion.main();
fixes.main();
});
diff --git a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
index 69ebea3..5a01ac9 100644
--- a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
@@ -106,7 +106,7 @@
isExpired: IsExpired.extension_types,
documentation: 'Extension Types',
experimentalReleaseVersion: null,
- releaseVersion: Version.parse('2.13.0'),
+ releaseVersion: null,
);
static final generic_metadata = ExperimentalFeature(
@@ -204,7 +204,7 @@
static const bool extension_methods = true;
/// Default state of the experiment "extension-types"
- static const bool extension_types = true;
+ static const bool extension_types = false;
/// Default state of the experiment "generic-metadata"
static const bool generic_metadata = false;
diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
index 8d44190..41413ee 100644
--- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -772,11 +772,25 @@
return result;
} else {
var firstAccessor = first as PropertyAccessorElement;
- var result = PropertyAccessorElementImpl(firstAccessor.name, -1);
+ var variableName = firstAccessor.displayName;
+
+ var result = PropertyAccessorElementImpl(variableName, -1);
result.enclosingElement = targetClass;
result.isGetter = firstAccessor.isGetter;
+ result.isSetter = firstAccessor.isSetter;
result.returnType = resultType.returnType;
result.parameters = resultType.parameters;
+
+ var field = FieldElementImpl(variableName, -1);
+ if (firstAccessor.isGetter) {
+ field.getter = result;
+ field.type = result.returnType;
+ } else {
+ field.setter = result;
+ field.type = result.parameters[0].type;
+ }
+ result.variable = field;
+
return result;
}
}
diff --git a/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart b/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
index d584afe..7e56db3 100644
--- a/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
+++ b/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
@@ -1140,7 +1140,7 @@
);
}
- test_getMember_optIn_topMerge_getter() async {
+ test_getMember_optIn_topMerge_getter_existing() async {
await resolveTestCode('''
class A {
dynamic get foo => 0;
@@ -1160,6 +1160,26 @@
);
}
+ test_getMember_optIn_topMerge_getter_synthetic() async {
+ await resolveTestCode('''
+abstract class A {
+ Future<void> get foo;
+}
+
+abstract class B {
+ Future<dynamic> get foo;
+}
+
+abstract class X extends A implements B {}
+''');
+
+ _assertGetMember(
+ className: 'X',
+ name: 'foo',
+ expected: 'X.foo: Future<Object?> Function()',
+ );
+ }
+
test_getMember_optIn_topMerge_method() async {
await resolveTestCode('''
class A {
@@ -1180,7 +1200,7 @@
);
}
- test_getMember_optIn_topMerge_setter() async {
+ test_getMember_optIn_topMerge_setter_existing() async {
await resolveTestCode('''
class A {
set foo(dynamic _) {}
@@ -1200,6 +1220,26 @@
);
}
+ test_getMember_optIn_topMerge_setter_synthetic() async {
+ await resolveTestCode('''
+abstract class A {
+ set foo(Future<void> _);
+}
+
+abstract class B {
+ set foo(Future<dynamic> _);
+}
+
+abstract class X extends A implements B {}
+''');
+
+ _assertGetMember(
+ className: 'X',
+ name: 'foo=',
+ expected: 'X.foo=: void Function(Future<Object?>)',
+ );
+ }
+
test_getMember_optOut_inheritsOptIn() async {
newFile('$testPackageLibPath/a.dart', content: r'''
class A {
@@ -1299,6 +1339,16 @@
var actual = '${enclosingElement.name}.${element.name}: $typeStr';
expect(actual, expected);
+
+ if (element is PropertyAccessorElement) {
+ var variable = element.variable;
+ expect(variable.name, element.displayName);
+ if (element.isGetter) {
+ expect(variable.type, element.returnType);
+ } else {
+ expect(variable.type, element.parameters[0].type);
+ }
+ }
} else {
expect(element, isNull);
}
diff --git a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
index 87b8431..1581d51 100644
--- a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
@@ -135,6 +135,55 @@
);
}
+ test_indexExpression_instance_compound_double_num() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ num operator[](int index) => 0;
+ operator[]=(int index, num _) {}
+}
+
+void f(A a) {
+ a[0] += 2.0;
+}
+''');
+
+ assertAssignment(
+ findNode.assignment('[0] += 2.0'),
+ readElement: findElement.method('[]'),
+ readType: 'num',
+ writeElement: findElement.method('[]='),
+ writeType: 'num',
+ operatorElement: elementMatcher(
+ numElement.getMethod('+'),
+ isLegacy: isNullSafetySdkAndLegacyLibrary,
+ ),
+ type: 'double',
+ );
+ }
+
+ test_indexExpression_instance_ifNull() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ int? operator[](int? index) => 0;
+ operator[]=(int? index, num? _) {}
+}
+
+void f(A a) {
+ a[0] ??= 2;
+}
+''');
+
+ assertAssignment(
+ findNode.assignment('[0] ??= 2'),
+ readElement: findElement.method('[]'),
+ readType: 'int?',
+ writeElement: findElement.method('[]='),
+ writeType: 'num?',
+ operatorElement: null,
+ type: 'int',
+ );
+ }
+
test_indexExpression_instance_simple() async {
await assertNoErrorsInCode(r'''
class A {
@@ -697,6 +746,37 @@
assertType(assignment.rightHandSide, 'int');
}
+ test_prefixedIdentifier_instance_ifNull() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ int? get x => 0;
+ set x(num? _) {}
+}
+
+void f(A a) {
+ a.x ??= 2;
+}
+''');
+
+ var assignment = findNode.assignment('x ??= 2');
+ assertAssignment(
+ assignment,
+ readElement: findElement.getter('x'),
+ readType: 'int?',
+ writeElement: findElement.setter('x'),
+ writeType: 'num?',
+ operatorElement: null,
+ type: 'int',
+ );
+
+ var prefixed = assignment.leftHandSide as PrefixedIdentifier;
+ assertSimpleIdentifierAssignmentTarget(
+ prefixed.identifier,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
test_prefixedIdentifier_instance_simple() async {
await assertNoErrorsInCode(r'''
class A {
@@ -1104,6 +1184,37 @@
assertType(assignment.rightHandSide, 'int');
}
+ test_propertyAccess_instance_ifNull() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ int? get x => 0;
+ set x(num? _) {}
+}
+
+void f(A a) {
+ (a).x ??= 2;
+}
+''');
+
+ var assignment = findNode.assignment('x ??= 2');
+ assertAssignment(
+ assignment,
+ readElement: findElement.getter('x'),
+ readType: 'int?',
+ writeElement: findElement.setter('x'),
+ writeType: 'num?',
+ operatorElement: null,
+ type: 'int',
+ );
+
+ var propertyAccess = assignment.leftHandSide as PropertyAccess;
+ assertSimpleIdentifierAssignmentTarget(
+ propertyAccess.propertyName,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
test_propertyAccess_instance_simple() async {
await assertNoErrorsInCode(r'''
class A {
@@ -2085,6 +2196,36 @@
assertType(assignment.rightHandSide, 'int');
}
+ test_simpleIdentifier_thisGetter_thisSetter_ifNull() async {
+ await assertNoErrorsInCode('''
+class C {
+ int? get x => 0;
+ set x(num? _) {}
+
+ void f() {
+ x ??= 2;
+ }
+}
+''');
+
+ var assignment = findNode.assignment('x ??= 2');
+ assertAssignment(
+ assignment,
+ readElement: findElement.getter('x'),
+ readType: 'int?',
+ writeElement: findElement.setter('x'),
+ writeType: 'num?',
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifierAssignmentTarget(
+ assignment.leftHandSide,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
test_simpleIdentifier_topGetter_superSetter_simple() async {
await assertErrorsInCode('''
class A {
diff --git a/pkg/analyzer/test/src/dart/resolution/for_statement_test.dart b/pkg/analyzer/test/src/dart/resolution/for_statement_test.dart
index 0796c45..aab1ca9 100644
--- a/pkg/analyzer/test/src/dart/resolution/for_statement_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/for_statement_test.dart
@@ -17,6 +17,27 @@
/// TODO(scheglov) Move other for-in tests here.
@reflectiveTest
class ForEachStatementResolutionTest extends PubPackageResolutionTest {
+ test_forIn_variable() async {
+ var code = r'''
+T f<T>() => null;
+
+void test(Iterable<num> iter) {
+ for (var w in f()) {} // 1
+ for (var x in iter) {} // 2
+ for (num y in f()) {} // 3
+}
+''';
+ await resolveTestCode(code);
+
+ assertType(findElement.localVar('w').type, 'Object?');
+ assertType(findNode.methodInvocation('f()) {} // 1'), 'Iterable<Object?>');
+
+ assertType(findElement.localVar('x').type, 'num');
+
+ assertType(findElement.localVar('y').type, 'num');
+ assertType(findNode.methodInvocation('f()) {} // 3'), 'Iterable<num>');
+ }
+
test_iterable_missing() async {
await assertErrorsInCode(r'''
void f() {
diff --git a/pkg/analyzer/test/src/task/strong/dart2_inference_test.dart b/pkg/analyzer/test/src/task/strong/dart2_inference_test.dart
index d2ec94b..e7b1ac5 100644
--- a/pkg/analyzer/test/src/task/strong/dart2_inference_test.dart
+++ b/pkg/analyzer/test/src/task/strong/dart2_inference_test.dart
@@ -22,10 +22,7 @@
///
/// https://github.com/dart-lang/sdk/issues/31638
@reflectiveTest
-class Dart2InferenceTest extends PubPackageResolutionTest
- with WithoutNullSafetyMixin {
- // TODO(https://github.com/dart-lang/sdk/issues/44666): Use null safety in
- // test cases.
+class Dart2InferenceTest extends PubPackageResolutionTest {
test_bool_assert() async {
var code = r'''
T f<T>(int _) => null;
@@ -134,536 +131,6 @@
assertType(closure, 'List<int> Function()');
}
- test_compoundAssignment_index() async {
- await resolveTestCode(r'''
-int getInt() => 0;
-num getNum() => 0;
-double getDouble() => 0.0;
-
-abstract class Test<T, U> {
- T operator [](String s);
- void operator []=(String s, U v);
-}
-
-void test1(Test<int, int> t) {
- var /*@type=int*/ v1 = t['x'] = getInt();
- var /*@type=num*/ v2 = t['x'] = getNum();
- var /*@type=int*/ v4 = t['x'] ??= getInt();
- var /*@type=num*/ v5 = t['x'] ??= getNum();
- var /*@type=int*/ v7 = t['x'] += getInt();
- var /*@type=num*/ v8 = t['x'] += getNum();
- var /*@type=int*/ v10 = ++t['x'];
- var /*@type=int*/ v11 = t['x']++;
-}
-
-void test2(Test<int, num> t) {
- var /*@type=int*/ v1 = t['x'] = getInt();
- var /*@type=num*/ v2 = t['x'] = getNum();
- var /*@type=double*/ v3 = t['x'] = getDouble();
- var /*@type=int*/ v4 = t['x'] ??= getInt();
- var /*@type=num*/ v5 = t['x'] ??= getNum();
- var /*@type=num*/ v6 = t['x'] ??= getDouble();
- var /*@type=int*/ v7 = t['x'] += getInt();
- var /*@type=num*/ v8 = t['x'] += getNum();
- var /*@type=double*/ v9 = t['x'] += getDouble();
- var /*@type=int*/ v10 = ++t['x'];
- var /*@type=int*/ v11 = t['x']++;
-}
-
-void test3(Test<int, double> t) {
- var /*@type=num*/ v2 = t['x'] = getNum();
- var /*@type=double*/ v3 = t['x'] = getDouble();
- var /*@type=num*/ v5 = t['x'] ??= getNum();
- var /*@type=num*/ v6 = t['x'] ??= getDouble();
- var /*@type=int*/ v7 = t['x'] += getInt();
- var /*@type=num*/ v8 = t['x'] += getNum();
- var /*@type=double*/ v9 = t['x'] += getDouble();
- var /*@type=int*/ v10 = ++t['x'];
- var /*@type=int*/ v11 = t['x']++;
-}
-
-void test4(Test<num, int> t) {
- var /*@type=int*/ v1 = t['x'] = getInt();
- var /*@type=num*/ v2 = t['x'] = getNum();
- var /*@type=num*/ v4 = t['x'] ??= getInt();
- var /*@type=num*/ v5 = t['x'] ??= getNum();
- var /*@type=num*/ v7 = t['x'] += getInt();
- var /*@type=num*/ v8 = t['x'] += getNum();
- var /*@type=num*/ v10 = ++t['x'];
- var /*@type=num*/ v11 = t['x']++;
-}
-
-void test5(Test<num, num> t) {
- var /*@type=int*/ v1 = t['x'] = getInt();
- var /*@type=num*/ v2 = t['x'] = getNum();
- var /*@type=double*/ v3 = t['x'] = getDouble();
- var /*@type=num*/ v4 = t['x'] ??= getInt();
- var /*@type=num*/ v5 = t['x'] ??= getNum();
- var /*@type=num*/ v6 = t['x'] ??= getDouble();
- var /*@type=num*/ v7 = t['x'] += getInt();
- var /*@type=num*/ v8 = t['x'] += getNum();
- var /*@type=num*/ v9 = t['x'] += getDouble();
- var /*@type=num*/ v10 = ++t['x'];
- var /*@type=num*/ v11 = t['x']++;
-}
-
-void test6(Test<num, double> t) {
- var /*@type=num*/ v2 = t['x'] = getNum();
- var /*@type=double*/ v3 = t['x'] = getDouble();
- var /*@type=num*/ v5 = t['x'] ??= getNum();
- var /*@type=num*/ v6 = t['x'] ??= getDouble();
- var /*@type=num*/ v7 = t['x'] += getInt();
- var /*@type=num*/ v8 = t['x'] += getNum();
- var /*@type=num*/ v9 = t['x'] += getDouble();
- var /*@type=num*/ v10 = ++t['x'];
- var /*@type=num*/ v11 = t['x']++;
-}
-
-void test7(Test<double, int> t) {
- var /*@type=int*/ v1 = t['x'] = getInt();
- var /*@type=num*/ v2 = t['x'] = getNum();
- var /*@type=num*/ v4 = t['x'] ??= getInt();
- var /*@type=num*/ v5 = t['x'] ??= getNum();
- var /*@type=double*/ v7 = t['x'] += getInt();
- var /*@type=double*/ v8 = t['x'] += getNum();
- var /*@type=double*/ v10 = ++t['x'];
- var /*@type=double*/ v11 = t['x']++;
-}
-
-void test8(Test<double, num> t) {
- var /*@type=int*/ v1 = t['x'] = getInt();
- var /*@type=num*/ v2 = t['x'] = getNum();
- var /*@type=double*/ v3 = t['x'] = getDouble();
- var /*@type=num*/ v4 = t['x'] ??= getInt();
- var /*@type=num*/ v5 = t['x'] ??= getNum();
- var /*@type=double*/ v6 = t['x'] ??= getDouble();
- var /*@type=double*/ v7 = t['x'] += getInt();
- var /*@type=double*/ v8 = t['x'] += getNum();
- var /*@type=double*/ v9 = t['x'] += getDouble();
- var /*@type=double*/ v10 = ++t['x'];
- var /*@type=double*/ v11 = t['x']++;
-}
-
-void test9(Test<double, double> t) {
- var /*@type=num*/ v2 = t['x'] = getNum();
- var /*@type=double*/ v3 = t['x'] = getDouble();
- var /*@type=num*/ v5 = t['x'] ??= getNum();
- var /*@type=double*/ v6 = t['x'] ??= getDouble();
- var /*@type=double*/ v7 = t['x'] += getInt();
- var /*@type=double*/ v8 = t['x'] += getNum();
- var /*@type=double*/ v9 = t['x'] += getDouble();
- var /*@type=double*/ v10 = ++t['x'];
- var /*@type=double*/ v11 = t['x']++;
-}
-''');
- _assertTypeAnnotations();
- }
-
- test_compoundAssignment_prefixedIdentifier() async {
- await assertErrorsInCode(r'''
-int getInt() => 0;
-num getNum() => 0;
-double getDouble() => 0.0;
-
-class Test<T extends U, U> {
- T get x => null;
- void set x(U _) {}
-}
-
-void test1(Test<int, int> t) {
- var /*@type=int*/ v1 = t.x = getInt();
- var /*@type=num*/ v2 = t.x = getNum();
- var /*@type=int*/ v4 = t.x ??= getInt();
- var /*@type=num*/ v5 = t.x ??= getNum();
- var /*@type=int*/ v7 = t.x += getInt();
- var /*@type=num*/ v8 = t.x += getNum();
- var /*@type=int*/ v10 = ++t.x;
- var /*@type=int*/ v11 = t.x++;
-}
-
-void test2(Test<int, num> t) {
- var /*@type=int*/ v1 = t.x = getInt();
- var /*@type=num*/ v2 = t.x = getNum();
- var /*@type=double*/ v3 = t.x = getDouble();
- var /*@type=int*/ v4 = t.x ??= getInt();
- var /*@type=num*/ v5 = t.x ??= getNum();
- var /*@type=num*/ v6 = t.x ??= getDouble();
- var /*@type=int*/ v7 = t.x += getInt();
- var /*@type=num*/ v8 = t.x += getNum();
- var /*@type=double*/ v9 = t.x += getDouble();
- var /*@type=int*/ v10 = ++t.x;
- var /*@type=int*/ v11 = t.x++;
-}
-
-void test5(Test<num, num> t) {
- var /*@type=int*/ v1 = t.x = getInt();
- var /*@type=num*/ v2 = t.x = getNum();
- var /*@type=double*/ v3 = t.x = getDouble();
- var /*@type=num*/ v4 = t.x ??= getInt();
- var /*@type=num*/ v5 = t.x ??= getNum();
- var /*@type=num*/ v6 = t.x ??= getDouble();
- var /*@type=num*/ v7 = t.x += getInt();
- var /*@type=num*/ v8 = t.x += getNum();
- var /*@type=num*/ v9 = t.x += getDouble();
- var /*@type=num*/ v10 = ++t.x;
- var /*@type=num*/ v11 = t.x++;
-}
-
-void test8(Test<double, num> t) {
- var /*@type=int*/ v1 = t.x = getInt();
- var /*@type=num*/ v2 = t.x = getNum();
- var /*@type=double*/ v3 = t.x = getDouble();
- var /*@type=num*/ v4 = t.x ??= getInt();
- var /*@type=num*/ v5 = t.x ??= getNum();
- var /*@type=double*/ v6 = t.x ??= getDouble();
- var /*@type=double*/ v7 = t.x += getInt();
- var /*@type=double*/ v8 = t.x += getNum();
- var /*@type=double*/ v9 = t.x += getDouble();
- var /*@type=double*/ v10 = ++t.x;
- var /*@type=double*/ v11 = t.x++;
-}
-
-void test9(Test<double, double> t) {
- var /*@type=num*/ v2 = t.x = getNum();
- var /*@type=double*/ v3 = t.x = getDouble();
- var /*@type=num*/ v5 = t.x ??= getNum();
- var /*@type=double*/ v6 = t.x ??= getDouble();
- var /*@type=double*/ v7 = t.x += getInt();
- var /*@type=double*/ v8 = t.x += getNum();
- var /*@type=double*/ v9 = t.x += getDouble();
- var /*@type=double*/ v10 = ++t.x;
- var /*@type=double*/ v11 = t.x++;
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 189, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 230, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 271, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 314, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 357, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 399, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 441, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 474, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 541, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 582, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 626, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 670, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 713, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 756, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 802, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 844, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 889, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 934, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 967, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1034, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1075, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1119, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1163, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1206, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1249, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1295, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1337, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1379, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1424, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1457, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1527, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1568, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1612, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1656, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1699, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1745, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1794, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1839, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1884, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1932, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1968, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2041, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2085, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2129, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2175, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2224, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2269, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2314, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2362, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2398, 3),
- ]);
- _assertTypeAnnotations();
- }
-
- test_compoundAssignment_propertyAccess() async {
- var t1 = 'new Test<int, int>()';
- var t2 = 'new Test<int, num>()';
- var t5 = 'new Test<num, num>()';
- var t8 = 'new Test<double, num>()';
- var t9 = 'new Test<double, double>()';
- await assertErrorsInCode('''
-int getInt() => 0;
-num getNum() => 0;
-double getDouble() => 0.0;
-
-class Test<T extends U, U> {
- T get x => null;
- void set x(U _) {}
-}
-
-void test1() {
- var /*@type=int*/ v1 = $t1.x = getInt();
- var /*@type=num*/ v2 = $t1.x = getNum();
- var /*@type=int*/ v4 = $t1.x ??= getInt();
- var /*@type=num*/ v5 = $t1.x ??= getNum();
- var /*@type=int*/ v7 = $t1.x += getInt();
- var /*@type=num*/ v8 = $t1.x += getNum();
- var /*@type=int*/ v10 = ++$t1.x;
- var /*@type=int*/ v11 = $t1.x++;
-}
-
-void test2() {
- var /*@type=int*/ v1 = $t2.x = getInt();
- var /*@type=num*/ v2 = $t2.x = getNum();
- var /*@type=double*/ v3 = $t2.x = getDouble();
- var /*@type=int*/ v4 = $t2.x ??= getInt();
- var /*@type=num*/ v5 = $t2.x ??= getNum();
- var /*@type=num*/ v6 = $t2.x ??= getDouble();
- var /*@type=int*/ v7 = $t2.x += getInt();
- var /*@type=num*/ v8 = $t2.x += getNum();
- var /*@type=double*/ v9 = $t2.x += getDouble();
- var /*@type=int*/ v10 = ++$t2.x;
- var /*@type=int*/ v11 = $t2.x++;
-}
-
-void test5() {
- var /*@type=int*/ v1 = $t5.x = getInt();
- var /*@type=num*/ v2 = $t5.x = getNum();
- var /*@type=double*/ v3 = $t5.x = getDouble();
- var /*@type=num*/ v4 = $t5.x ??= getInt();
- var /*@type=num*/ v5 = $t5.x ??= getNum();
- var /*@type=num*/ v6 = $t5.x ??= getDouble();
- var /*@type=num*/ v7 = $t5.x += getInt();
- var /*@type=num*/ v8 = $t5.x += getNum();
- var /*@type=num*/ v9 = $t5.x += getDouble();
- var /*@type=num*/ v10 = ++$t5.x;
- var /*@type=num*/ v11 = $t5.x++;
-}
-
-void test8() {
- var /*@type=int*/ v1 = $t8.x = getInt();
- var /*@type=num*/ v2 = $t8.x = getNum();
- var /*@type=double*/ v3 = $t8.x = getDouble();
- var /*@type=num*/ v4 = $t8.x ??= getInt();
- var /*@type=num*/ v5 = $t8.x ??= getNum();
- var /*@type=double*/ v6 = $t8.x ??= getDouble();
- var /*@type=double*/ v7 = $t8.x += getInt();
- var /*@type=double*/ v8 = $t8.x += getNum();
- var /*@type=double*/ v9 = $t8.x += getDouble();
- var /*@type=double*/ v10 = ++$t8.x;
- var /*@type=double*/ v11 = $t8.x++;
-}
-
-void test9() {
- var /*@type=num*/ v2 = $t9.x = getNum();
- var /*@type=double*/ v3 = $t9.x = getDouble();
- var /*@type=num*/ v5 = $t9.x ??= getNum();
- var /*@type=double*/ v6 = $t9.x ??= getDouble();
- var /*@type=double*/ v7 = $t9.x += getInt();
- var /*@type=double*/ v8 = $t9.x += getNum();
- var /*@type=double*/ v9 = $t9.x += getDouble();
- var /*@type=double*/ v10 = ++$t9.x;
- var /*@type=double*/ v11 = $t9.x++;
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 173, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 233, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 293, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 355, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 417, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 478, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 539, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 591, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 661, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 721, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 784, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 847, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 909, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 971, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1036, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1097, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1161, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1225, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1277, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1347, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1407, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1470, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1533, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1595, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1657, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1722, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1783, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1844, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1908, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1960, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2030, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2093, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2159, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2225, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2290, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2358, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2429, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2496, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2563, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2633, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2691, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2764, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2833, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2902, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2973, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 3047, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 3117, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 3187, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 3260, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 3321, 3),
- ]);
- _assertTypeAnnotations();
- }
-
- test_compoundAssignment_simpleIdentifier() async {
- await assertErrorsInCode(r'''
-int getInt() => 0;
-num getNum() => 0;
-double getDouble() => 0.0;
-
-class Test<T extends U, U> {
- T get x => null;
- void set x(U _) {}
-}
-
-class Test1 extends Test<int, int> {
- void test1() {
- var /*@type=int*/ v1 = x = getInt();
- var /*@type=num*/ v2 = x = getNum();
- var /*@type=int*/ v4 = x ??= getInt();
- var /*@type=num*/ v5 = x ??= getNum();
- var /*@type=int*/ v7 = x += getInt();
- var /*@type=num*/ v8 = x += getNum();
- var /*@type=int*/ v10 = ++x;
- var /*@type=int*/ v11 = x++;
- }
-}
-
-class Test2 extends Test<int, num> {
- void test2() {
- var /*@type=int*/ v1 = x = getInt();
- var /*@type=num*/ v2 = x = getNum();
- var /*@type=double*/ v3 = x = getDouble();
- var /*@type=int*/ v4 = x ??= getInt();
- var /*@type=num*/ v5 = x ??= getNum();
- var /*@type=num*/ v6 = x ??= getDouble();
- var /*@type=int*/ v7 = x += getInt();
- var /*@type=num*/ v8 = x += getNum();
- var /*@type=double*/ v9 = x += getDouble();
- var /*@type=int*/ v10 = ++x;
- var /*@type=int*/ v11 = x++;
- }
-}
-
-class Test5 extends Test<num, num> {
- void test5() {
- var /*@type=int*/ v1 = x = getInt();
- var /*@type=num*/ v2 = x = getNum();
- var /*@type=double*/ v3 = x = getDouble();
- var /*@type=num*/ v4 = x ??= getInt();
- var /*@type=num*/ v5 = x ??= getNum();
- var /*@type=num*/ v6 = x ??= getDouble();
- var /*@type=num*/ v7 = x += getInt();
- var /*@type=num*/ v8 = x += getNum();
- var /*@type=num*/ v9 = x += getDouble();
- var /*@type=num*/ v10 = ++x;
- var /*@type=num*/ v11 = x++;
- }
-}
-
-class Test8 extends Test<double, num> {
- void test8() {
- var /*@type=int*/ v1 = x = getInt();
- var /*@type=num*/ v2 = x = getNum();
- var /*@type=double*/ v3 = x = getDouble();
- var /*@type=num*/ v4 = x ??= getInt();
- var /*@type=num*/ v5 = x ??= getNum();
- var /*@type=double*/ v6 = x ??= getDouble();
- var /*@type=double*/ v7 = x += getInt();
- var /*@type=double*/ v8 = x += getNum();
- var /*@type=double*/ v9 = x += getDouble();
- var /*@type=double*/ v10 = ++x;
- var /*@type=double*/ v11 = x++;
- }
-}
-
-class Test9 extends Test<double, double> {
- void test9() {
- var /*@type=num*/ v2 = x = getNum();
- var /*@type=double*/ v3 = x = getDouble();
- var /*@type=num*/ v5 = x ??= getNum();
- var /*@type=double*/ v6 = x ??= getDouble();
- var /*@type=double*/ v7 = x += getInt();
- var /*@type=double*/ v8 = x += getNum();
- var /*@type=double*/ v9 = x += getDouble();
- var /*@type=double*/ v10 = ++x;
- var /*@type=double*/ v11 = x++;
- }
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 214, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 255, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 296, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 339, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 382, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 424, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 466, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 499, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 593, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 634, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 678, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 722, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 765, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 808, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 854, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 896, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 941, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 986, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1019, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1113, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1154, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1198, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1242, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1285, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1328, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1374, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1416, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1458, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1503, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1536, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1633, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1674, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1718, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1762, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1805, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1851, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1900, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1945, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 1990, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2038, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2074, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2174, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2218, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2262, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2308, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2357, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2402, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2447, 2),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2495, 3),
- error(HintCode.UNUSED_LOCAL_VARIABLE, 2531, 3),
- ]);
- _assertTypeAnnotations();
- }
-
test_compoundAssignment_simpleIdentifier_topLevel() async {
await assertErrorsInCode(r'''
class A {}
@@ -719,46 +186,6 @@
assertInvocationType('f()) {} // top setter');
}
- test_forIn_variable() async {
- var code = r'''
-T f<T>() => null;
-
-void test(Iterable<num> iter) {
- for (var w in f()) {} // 1
- for (var x in iter) {} // 2
- for (num y in f()) {} // 3
-}
-''';
- await resolveTestCode(code);
- {
- var node = findNode.simple('w in');
- var element = node.staticElement as VariableElement;
- expect(node.staticType, isNull);
- expect(element.type, typeProvider.dynamicType);
-
- var invocation = findNode.methodInvocation('f()) {} // 1');
- assertType(invocation, 'Iterable<dynamic>');
- }
-
- {
- var node = findNode.simple('x in');
- var element = node.staticElement as VariableElement;
- expect(node.staticType, isNull);
- expect(element.type, typeProvider.numType);
- }
-
- {
- var node = findNode.simple('y in');
- var element = node.staticElement as VariableElement;
-
- expect(node.staticType, isNull);
- expect(element.type, typeProvider.numType);
-
- var invocation = findNode.methodInvocation('f()) {} // 3');
- assertType(invocation, 'Iterable<num>');
- }
- }
-
test_forIn_variable_implicitlyTyped() async {
var code = r'''
class A {}
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
index 699e59c..2c56811 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
@@ -79,7 +79,7 @@
ExperimentalFlag.constantUpdate2018: true,
ExperimentalFlag.controlFlowCollections: true,
ExperimentalFlag.extensionMethods: true,
- ExperimentalFlag.extensionTypes: true,
+ ExperimentalFlag.extensionTypes: false,
ExperimentalFlag.genericMetadata: false,
ExperimentalFlag.nonNullable: true,
ExperimentalFlag.nonfunctionTypeAliases: false,
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index 33b9faa..1b23da1 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -62,6 +62,7 @@
templateFfiFieldCyclic,
templateFfiFieldInitializer,
templateFfiFieldNoAnnotation,
+ templateFfiFieldNull,
templateFfiNotStatic,
templateFfiStructGeneric,
templateFfiTypeInvalid,
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 90141d2..725ff20 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -61,6 +61,8 @@
import '../type_inference/type_schema.dart' show UnknownType;
+import '../util/helpers.dart' show DelayedActionPerformer;
+
import 'builder.dart';
import 'constructor_builder.dart';
import 'constructor_reference_builder.dart';
@@ -122,7 +124,8 @@
List<ConstructorReferenceBuilder> get constructorReferences;
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes);
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers);
/// Registers a constructor redirection for this class and returns true if
/// this redirection gives rise to a cycle that has not been reported before.
@@ -349,10 +352,12 @@
}
@override
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes) {
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers) {
void build(String ignore, Builder declaration) {
MemberBuilder member = declaration;
- member.buildOutlineExpressions(library, coreTypes);
+ member.buildOutlineExpressions(
+ library, coreTypes, delayedActionPerformers);
}
MetadataBuilder.buildAnnotations(
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
index 432df8c..1b544eb 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
@@ -36,6 +36,7 @@
import '../source/source_class_builder.dart';
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
+import '../util/helpers.dart' show DelayedActionPerformer;
import 'builder.dart';
import 'class_builder.dart';
@@ -239,8 +240,9 @@
}
@override
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes) {
- super.buildOutlineExpressions(library, coreTypes);
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers) {
+ super.buildOutlineExpressions(library, coreTypes, delayedActionPerformers);
// For modular compilation purposes we need to include initializers
// for const constructors into the outline.
@@ -451,10 +453,13 @@
super(constructor, parent);
void buildOutlineExpressions(
- LibraryBuilder libraryBuilder, CoreTypes coreTypes) {
+ LibraryBuilder libraryBuilder,
+ CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers) {
if (_origin != null) {
// Ensure that default value expressions have been created for [_origin].
- _origin.buildOutlineExpressions(libraryBuilder, coreTypes);
+ _origin.buildOutlineExpressions(
+ libraryBuilder, coreTypes, delayedActionPerformers);
_clonedFunctionNode.cloneDefaultValues();
_clonedFunctionNode = null;
_origin = null;
diff --git a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
index 79c6bc6..5c150ad 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -10,6 +10,7 @@
import '../fasta_codes.dart' show templateInternalProblemNotFoundIn;
import '../scope.dart';
import '../problems.dart';
+import '../util/helpers.dart';
import 'builder.dart';
import 'library_builder.dart';
@@ -27,7 +28,8 @@
/// Return the [Extension] built by this builder.
Extension get extension;
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes);
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers);
/// Looks up extension member by [name] taking privacy into account.
///
@@ -145,10 +147,12 @@
String get debugName => "ExtensionBuilder";
@override
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes) {
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers) {
void build(String ignore, Builder declaration) {
MemberBuilder member = declaration;
- member.buildOutlineExpressions(library, coreTypes);
+ member.buildOutlineExpressions(
+ library, coreTypes, delayedActionPerformers);
}
// TODO(johnniwinther): Handle annotations on the extension declaration.
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 1fe24be..da7aea2 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -35,6 +35,8 @@
import '../type_inference/type_inference_engine.dart'
show IncludesTypeParametersNonCovariantly;
+import '../util/helpers.dart' show DelayedActionPerformer;
+
import 'class_builder.dart';
import 'extension_builder.dart';
import 'library_builder.dart';
@@ -376,7 +378,8 @@
}
@override
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes) {
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers) {
_fieldEncoding.completeSignature(coreTypes);
ClassBuilder classBuilder = isClassMember ? parent : null;
@@ -417,6 +420,9 @@
}
buildBody(coreTypes, initializer);
bodyBuilder.resolveRedirectingFactoryTargets();
+ if (bodyBuilder.hasDelayedActions) {
+ delayedActionPerformers.add(bodyBuilder);
+ }
}
constInitializerToken = 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 3b8fe9b..1b034996 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
@@ -37,6 +37,8 @@
import '../kernel/internal_ast.dart' show VariableDeclarationImpl;
+import '../util/helpers.dart' show DelayedActionPerformer;
+
import 'builder.dart';
import 'class_builder.dart';
import 'constructor_builder.dart';
@@ -177,7 +179,8 @@
/// Builds the default value from this [initializerToken] if this is a
/// formal parameter on a const constructor or instance method.
- void buildOutlineExpressions(LibraryBuilder library) {
+ void buildOutlineExpressions(LibraryBuilder library,
+ List<DelayedActionPerformer> delayedActionPerformers) {
if (initializerToken != null) {
// For modular compilation we need to include initializers for optional
// and named parameters of const constructors into the outline - to enable
@@ -213,6 +216,9 @@
}
initializerWasInferred = true;
bodyBuilder.resolveRedirectingFactoryTargets();
+ if (bodyBuilder.hasDelayedActions) {
+ delayedActionPerformers.add(bodyBuilder);
+ }
}
}
initializerToken = null;
diff --git a/pkg/front_end/lib/src/fasta/builder/function_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
index b938323..8477784 100644
--- a/pkg/front_end/lib/src/fasta/builder/function_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
@@ -37,6 +37,8 @@
import '../type_inference/type_inference_engine.dart'
show IncludesTypeParametersNonCovariantly;
+import '../util/helpers.dart' show DelayedActionPerformer;
+
import 'builder.dart';
import 'class_builder.dart';
import 'extension_builder.dart';
@@ -501,7 +503,8 @@
bool _hasBuiltOutlineExpressions = false;
@override
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes) {
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers) {
if (!_hasBuiltOutlineExpressions) {
MetadataBuilder.buildAnnotations(
member, metadata, library, isClassMember ? parent : null, this);
@@ -512,7 +515,7 @@
// buildOutlineExpressions to clear initializerToken to prevent
// consuming too much memory.
for (FormalParameterBuilder formal in formals) {
- formal.buildOutlineExpressions(library);
+ formal.buildOutlineExpressions(library, delayedActionPerformers);
}
}
_hasBuiltOutlineExpressions = true;
diff --git a/pkg/front_end/lib/src/fasta/builder/member_builder.dart b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
index 51ee376..070d275 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -16,6 +16,7 @@
import '../problems.dart' show unsupported;
import '../type_inference/type_inference_engine.dart'
show InferenceDataForTesting;
+import '../util/helpers.dart' show DelayedActionPerformer;
import 'builder.dart';
import 'class_builder.dart';
@@ -72,7 +73,8 @@
/// setter of a field.
bool get isConflictingSetter;
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes);
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers);
/// Returns the [ClassMember]s for the non-setter members created for this
/// member builder.
@@ -171,7 +173,8 @@
ProcedureKind get kind => unsupported("kind", charOffset, fileUri);
@override
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes) {}
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers) {}
/// Builds the core AST structures for this member as needed for the outline.
void buildMembers(
diff --git a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
index c7b250b..4c89f92 100644
--- a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
@@ -28,6 +28,8 @@
import '../type_inference/type_inferrer.dart';
import '../type_inference/type_schema.dart';
+import '../util/helpers.dart';
+
import 'builder.dart';
import 'constructor_reference_builder.dart';
import 'extension_builder.dart';
@@ -762,8 +764,9 @@
}
@override
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes) {
- super.buildOutlineExpressions(library, coreTypes);
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers) {
+ super.buildOutlineExpressions(library, coreTypes, delayedActionPerformers);
LibraryBuilder thisLibrary = this.library;
if (thisLibrary is SourceLibraryBuilder) {
RedirectingFactoryBody redirectingFactoryBody = procedure.function.body;
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 92a5cab..ec1a7ec 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -113,6 +113,10 @@
import '../type_inference/type_promotion.dart'
show TypePromoter, TypePromotionFact, TypePromotionScope;
+import '../type_inference/type_schema.dart' show UnknownType;
+
+import '../util/helpers.dart' show DelayedActionPerformer;
+
import 'collections.dart';
import 'constness.dart' show Constness;
@@ -151,7 +155,7 @@
const Object invalidCollectionElement = const Object();
class BodyBuilder extends ScopeListener<JumpTarget>
- implements ExpressionGeneratorHelper, EnsureLoaded {
+ implements ExpressionGeneratorHelper, EnsureLoaded, DelayedActionPerformer {
final Forest forest;
// TODO(ahe): Rename [library] to 'part'.
@@ -313,6 +317,13 @@
/// invocations are to be resolved in a separate step.
final List<Expression> redirectingFactoryInvocations = <Expression>[];
+ /// List of redirecting factory invocations delayed for resolution.
+ ///
+ /// A resolution of a redirecting factory invocation can be delayed because
+ /// the inference in the declaration of the redirecting factory isn't done
+ /// yet.
+ final List<Expression> delayedRedirectingFactoryInvocations = <Expression>[];
+
/// List of built type aliased generative constructor invocations that
/// require unaliasing.
final List<TypeAliasedConstructorInvocationJudgment>
@@ -1160,7 +1171,8 @@
void resolveRedirectingFactoryTargets() {
_unaliasTypeAliasedConstructorInvocations();
_unaliasTypeAliasedFactoryInvocations();
- _resolveRedirectingFactoryTargets();
+ _resolveRedirectingFactoryTargets(
+ redirectingFactoryInvocations, delayedRedirectingFactoryInvocations);
}
/// Return an [Expression] resolving the argument invocation.
@@ -1168,6 +1180,7 @@
/// The arguments specify the [StaticInvocation] whose `.target` is
/// [target], `.arguments` is [arguments], `.fileOffset` is [fileOffset],
/// and `.isConst` is [isConst].
+ /// Returns null if the invocation can't be resolved.
Expression _resolveRedirectingFactoryTarget(
Procedure target, Arguments arguments, int fileOffset, bool isConst) {
Procedure initialTarget = target;
@@ -1176,6 +1189,10 @@
RedirectionTarget redirectionTarget =
getRedirectionTarget(initialTarget, this);
Member resolvedTarget = redirectionTarget?.target;
+ if (redirectionTarget != null &&
+ redirectionTarget.typeArguments.any((type) => type is UnknownType)) {
+ return null;
+ }
if (resolvedTarget == null) {
String name = constructorNameForDiagnostics(initialTarget.name.text,
@@ -1233,7 +1250,9 @@
return replacementNode;
}
- void _resolveRedirectingFactoryTargets() {
+ void _resolveRedirectingFactoryTargets(
+ List<Expression> redirectingFactoryInvocations,
+ List<Expression> delayedRedirectingFactoryInvocations) {
for (StaticInvocation invocation in redirectingFactoryInvocations) {
// If the invocation was invalid, it or its parent has already been
// desugared into an exception throwing expression. There is nothing to
@@ -1254,8 +1273,16 @@
}
if (parent == null) continue;
}
- invocation.replaceWith(_resolveRedirectingFactoryTarget(invocation.target,
- invocation.arguments, invocation.fileOffset, invocation.isConst));
+ Expression replacement = _resolveRedirectingFactoryTarget(
+ invocation.target,
+ invocation.arguments,
+ invocation.fileOffset,
+ invocation.isConst);
+ if (replacement == null) {
+ delayedRedirectingFactoryInvocations?.add(invocation);
+ } else {
+ invocation.replaceWith(replacement);
+ }
}
redirectingFactoryInvocations.clear();
}
@@ -1306,6 +1333,33 @@
typeAliasedFactoryInvocations.clear();
}
+ /// Perform actions that were delayed
+ ///
+ /// An action can be delayed, for instance, because it depends on some
+ /// calculations in another library. For example, a resolution of a
+ /// redirecting factory invocation depends on the type inference in the
+ /// redirecting factory.
+ void performDelayedActions() {
+ if (delayedRedirectingFactoryInvocations.isNotEmpty) {
+ _resolveRedirectingFactoryTargets(
+ delayedRedirectingFactoryInvocations, null);
+ if (delayedRedirectingFactoryInvocations.isNotEmpty) {
+ for (StaticInvocation invocation
+ in delayedRedirectingFactoryInvocations) {
+ internalProblem(
+ fasta.templateInternalProblemUnhandled.withArguments(
+ invocation.target.name.text, 'performDelayedActions'),
+ invocation.fileOffset,
+ uri);
+ }
+ }
+ }
+ }
+
+ bool get hasDelayedActions {
+ return delayedRedirectingFactoryInvocations.isNotEmpty;
+ }
+
void finishVariableMetadata() {
List<VariableDeclaration> variablesWithMetadata =
this.variablesWithMetadata;
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index 004901a..62852fb 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -17,6 +17,7 @@
import 'builder/type_variable_builder.dart';
import 'kernel/body_builder.dart' show JumpTarget;
import 'kernel/class_hierarchy_builder.dart' show ClassMember;
+import 'util/helpers.dart' show DelayedActionPerformer;
import 'fasta_codes.dart'
show
@@ -799,7 +800,8 @@
ProcedureKind get kind => null;
@override
- void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes) {
+ void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
+ List<DelayedActionPerformer> delayedActionPerformers) {
throw new UnsupportedError(
'AmbiguousMemberBuilder.buildOutlineExpressions');
}
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 153430d6..ac98e95 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -110,6 +110,8 @@
import '../type_inference/type_inferrer.dart';
+import '../util/helpers.dart';
+
import 'diet_listener.dart' show DietListener;
import 'diet_parser.dart' show DietParser;
@@ -1134,6 +1136,8 @@
}
void buildOutlineExpressions(CoreTypes coreTypes) {
+ List<DelayedActionPerformer> delayedActionPerformers =
+ <DelayedActionPerformer>[];
for (LibraryBuilder library in builders.values) {
if (library.loader == this) {
library.buildOutlineExpressions();
@@ -1141,15 +1145,22 @@
while (iterator.moveNext()) {
Builder declaration = iterator.current;
if (declaration is ClassBuilder) {
- declaration.buildOutlineExpressions(library, coreTypes);
+ declaration.buildOutlineExpressions(
+ library, coreTypes, delayedActionPerformers);
} else if (declaration is ExtensionBuilder) {
- declaration.buildOutlineExpressions(library, coreTypes);
+ declaration.buildOutlineExpressions(
+ library, coreTypes, delayedActionPerformers);
} else if (declaration is MemberBuilder) {
- declaration.buildOutlineExpressions(library, coreTypes);
+ declaration.buildOutlineExpressions(
+ library, coreTypes, delayedActionPerformers);
}
}
}
}
+ for (DelayedActionPerformer delayedActionPerformer
+ in delayedActionPerformers) {
+ delayedActionPerformer.performDelayedActions();
+ }
ticker.logMs("Build outline expressions");
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index a61e28f..3acf8bb 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -2788,6 +2788,13 @@
fileOffset,
noLength);
} else {
+ // Handles cases like:
+ // int? i;
+ // i.methodOnNonNullInt();
+ // where `methodOnNonNullInt` is declared in an extension:
+ // extension on int {
+ // void methodOnNonNullInt() {}
+ // }
replacement = helper.wrapInProblem(
replacement,
templateNullableMethodCallError.withArguments(
@@ -2866,6 +2873,9 @@
fileOffset,
noLength);
} else {
+ // Handles cases like:
+ // void Function()? f;
+ // f.call();
replacement = helper.wrapInProblem(
replacement,
templateNullableMethodCallError.withArguments(
@@ -3029,6 +3039,9 @@
fileOffset,
noLength);
} else {
+ // Handles cases like:
+ // int? i;
+ // i.abs();
replacement = helper.wrapInProblem(
replacement,
templateNullableMethodCallError.withArguments(
diff --git a/pkg/front_end/lib/src/fasta/util/helpers.dart b/pkg/front_end/lib/src/fasta/util/helpers.dart
new file mode 100644
index 0000000..0e41efc
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/util/helpers.dart
@@ -0,0 +1,8 @@
+// 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.
+
+abstract class DelayedActionPerformer {
+ bool get hasDelayedActions;
+ void performDelayedActions();
+}
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index e07a53f..1124364 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -327,6 +327,7 @@
FfiFieldCyclic/analyzerCode: Fail
FfiFieldInitializer/analyzerCode: Fail
FfiFieldNoAnnotation/analyzerCode: Fail
+FfiFieldNull/analyzerCode: Fail
FfiNotStatic/analyzerCode: Fail
FfiStructAnnotation/analyzerCode: Fail
FfiStructGeneric/analyzerCode: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 5a98676..3c647b29 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4225,6 +4225,11 @@
template: "Expected type '#type' to be a valid and instantiated subtype of 'NativeType'."
external: test/ffi_test.dart
+FfiFieldNull:
+ # Used by dart:ffi
+ template: "Field '#name' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct`."
+ external: test/ffi_test.dart
+
FfiFieldAnnotation:
# Used by dart:ffi
template: "Field '#name' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields."
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 9601042..9a5012d 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -2164,6 +2164,8 @@
perform
performance
performed
+performer
+performers
performing
performs
perhaps
diff --git a/pkg/front_end/testcases/general/issue45003/bar_lib.dart b/pkg/front_end/testcases/general/issue45003/bar_lib.dart
new file mode 100644
index 0000000..15f7c60
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/bar_lib.dart
@@ -0,0 +1,9 @@
+// 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 './foo_lib.dart';
+
+class Bar<T> extends Foo {
+ const Bar();
+}
diff --git a/pkg/front_end/testcases/general/issue45003/foo_lib.dart b/pkg/front_end/testcases/general/issue45003/foo_lib.dart
new file mode 100644
index 0000000..3a7afdf
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/foo_lib.dart
@@ -0,0 +1,12 @@
+// 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 './bar_lib.dart';
+
+export './bar_lib.dart';
+
+abstract class Foo {
+ const Foo();
+ const factory Foo.bar() = Bar;
+}
diff --git a/pkg/front_end/testcases/general/issue45003/main.dart b/pkg/front_end/testcases/general/issue45003/main.dart
new file mode 100644
index 0000000..47bbc28
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/main.dart
@@ -0,0 +1,9 @@
+// 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 './foo_lib.dart';
+
+const Set<Foo> foo = <Foo>{Foo.bar()};
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45003/main.dart.outline.expect b/pkg/front_end/testcases/general/issue45003/main.dart.outline.expect
new file mode 100644
index 0000000..7e18438
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/main.dart.outline.expect
@@ -0,0 +1,57 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+import "bar_lib.dart" as bar;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+static const field core::Set<foo::Foo*>* foo = const <foo::Foo*>{const bar::Bar::•<dynamic>()};
+static method main() → dynamic
+ ;
+
+library;
+import self as foo;
+import "dart:core" as core;
+import "bar_lib.dart" as bar;
+additionalExports = (bar::Bar)
+
+import "org-dartlang-testcase:///bar_lib.dart";
+export "org-dartlang-testcase:///bar_lib.dart";
+
+abstract class Foo extends core::Object /*hasConstConstructor*/ {
+ static final field dynamic _redirecting# = <dynamic>[foo::Foo::bar];
+ const constructor •() → foo::Foo*
+ : super core::Object::•()
+ ;
+ static factory bar() → foo::Foo*
+ let dynamic #redirecting_factory = bar::Bar::• in let dynamic #typeArg0 = null in invalid-expression;
+ 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
+}
+
+library;
+import self as bar;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+class Bar<T extends core::Object* = dynamic> extends foo::Foo /*hasConstConstructor*/ {
+ const constructor •() → bar::Bar<bar::Bar::T*>*
+ : super foo::Foo::•()
+ ;
+}
+
+
+Extra constant evaluation status:
+Evaluated: SetLiteral @ org-dartlang-testcase:///main.dart:7:27 -> InstanceConstant(const _UnmodifiableSet<Foo*>{_UnmodifiableSet._map: const _ImmutableMap<Foo*, Null>{_ImmutableMap._kvPairs: const <dynamic>[const Bar<dynamic>{}, null]}})
+Extra constant evaluation: evaluated: 6, effectively constant: 1
diff --git a/pkg/front_end/testcases/general/issue45003/main.dart.strong.expect b/pkg/front_end/testcases/general/issue45003/main.dart.strong.expect
new file mode 100644
index 0000000..95d101a
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/main.dart.strong.expect
@@ -0,0 +1,69 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+static const field core::Set<foo::Foo*>* foo = #C5;
+static method main() → dynamic {}
+
+library;
+import self as foo;
+import "dart:core" as core;
+import "bar_lib.dart" as bar;
+additionalExports = (bar::Bar)
+
+import "org-dartlang-testcase:///bar_lib.dart";
+export "org-dartlang-testcase:///bar_lib.dart";
+
+abstract class Foo extends core::Object /*hasConstConstructor*/ {
+ static final field dynamic _redirecting# = <dynamic>[foo::Foo::bar];
+ const constructor •() → foo::Foo*
+ : super core::Object::•()
+ ;
+ static factory bar() → foo::Foo*
+ let dynamic #redirecting_factory = bar::Bar::• in let dynamic #typeArg0 = null in invalid-expression;
+ 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
+}
+
+library;
+import self as bar;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+class Bar<T extends core::Object* = dynamic> extends foo::Foo /*hasConstConstructor*/ {
+ const constructor •() → bar::Bar<bar::Bar::T*>*
+ : super foo::Foo::•()
+ ;
+}
+
+constants {
+ #C1 = bar::Bar<dynamic> {}
+ #C2 = null
+ #C3 = <dynamic>[#C1, #C2]
+ #C4 = core::_ImmutableMap<foo::Foo*, Null> {_kvPairs:#C3}
+ #C5 = col::_UnmodifiableSet<foo::Foo*> {_map:#C4}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///main.dart:
+- Bar. (from org-dartlang-testcase:///bar_lib.dart:8:9)
+
+org-dartlang-testcase:///foo_lib.dart:
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+
+org-dartlang-testcase:///bar_lib.dart:
+- Foo. (from org-dartlang-testcase:///foo_lib.dart:10:9)
diff --git a/pkg/front_end/testcases/general/issue45003/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue45003/main.dart.strong.transformed.expect
new file mode 100644
index 0000000..bfa7543
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/main.dart.strong.transformed.expect
@@ -0,0 +1,69 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+static const field core::Set<foo::Foo*>* foo = #C5;
+static method main() → dynamic {}
+
+library;
+import self as foo;
+import "dart:core" as core;
+import "bar_lib.dart" as bar;
+additionalExports = (bar::Bar)
+
+import "org-dartlang-testcase:///bar_lib.dart";
+export "org-dartlang-testcase:///bar_lib.dart";
+
+abstract class Foo extends core::Object /*hasConstConstructor*/ {
+ static final field dynamic _redirecting# = <dynamic>[foo::Foo::bar];
+ const constructor •() → foo::Foo*
+ : super core::Object::•()
+ ;
+ static factory bar() → foo::Foo*
+ let<BottomType> #redirecting_factory = bar::Bar::• in let<BottomType> #typeArg0 = null in invalid-expression;
+ 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
+}
+
+library;
+import self as bar;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+class Bar<T extends core::Object* = dynamic> extends foo::Foo /*hasConstConstructor*/ {
+ const constructor •() → bar::Bar<bar::Bar::T*>*
+ : super foo::Foo::•()
+ ;
+}
+
+constants {
+ #C1 = bar::Bar<dynamic> {}
+ #C2 = null
+ #C3 = <dynamic>[#C1, #C2]
+ #C4 = core::_ImmutableMap<foo::Foo*, Null> {_kvPairs:#C3}
+ #C5 = col::_UnmodifiableSet<foo::Foo*> {_map:#C4}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///main.dart:
+- Bar. (from org-dartlang-testcase:///bar_lib.dart:8:9)
+
+org-dartlang-testcase:///foo_lib.dart:
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+
+org-dartlang-testcase:///bar_lib.dart:
+- Foo. (from org-dartlang-testcase:///foo_lib.dart:10:9)
diff --git a/pkg/front_end/testcases/general/issue45003/main.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue45003/main.dart.textual_outline.expect
new file mode 100644
index 0000000..c7dc4d4
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/main.dart.textual_outline.expect
@@ -0,0 +1,4 @@
+import './foo_lib.dart';
+
+const Set<Foo> foo = <Foo>{Foo.bar()};
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45003/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue45003/main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..c7dc4d4
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/main.dart.textual_outline_modelled.expect
@@ -0,0 +1,4 @@
+import './foo_lib.dart';
+
+const Set<Foo> foo = <Foo>{Foo.bar()};
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45003/main.dart.weak.expect b/pkg/front_end/testcases/general/issue45003/main.dart.weak.expect
new file mode 100644
index 0000000..ba331a8
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/main.dart.weak.expect
@@ -0,0 +1,59 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+static const field core::Set<foo::Foo> foo = #C5;
+static method main() → dynamic {}
+
+library /*isNonNullableByDefault*/;
+import self as foo;
+import "dart:core" as core;
+import "bar_lib.dart" as bar;
+additionalExports = (bar::Bar)
+
+import "org-dartlang-testcase:///bar_lib.dart";
+export "org-dartlang-testcase:///bar_lib.dart";
+
+abstract class Foo extends core::Object /*hasConstConstructor*/ {
+ static final field dynamic _redirecting# = <dynamic>[foo::Foo::bar]/*isLegacy*/;
+ const constructor •() → foo::Foo
+ : super core::Object::•()
+ ;
+ static factory bar() → foo::Foo
+ let dynamic #redirecting_factory = bar::Bar::• in let dynamic #typeArg0 = null in invalid-expression;
+}
+
+library /*isNonNullableByDefault*/;
+import self as bar;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+class Bar<T extends core::Object? = dynamic> extends foo::Foo /*hasConstConstructor*/ {
+ const constructor •() → bar::Bar<bar::Bar::T%>
+ : super foo::Foo::•()
+ ;
+}
+
+constants {
+ #C1 = bar::Bar<dynamic> {}
+ #C2 = null
+ #C3 = <dynamic>[#C1, #C2]
+ #C4 = core::_ImmutableMap<foo::Foo*, Null> {_kvPairs:#C3}
+ #C5 = col::_UnmodifiableSet<foo::Foo*> {_map:#C4}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///main.dart:
+- Bar. (from org-dartlang-testcase:///bar_lib.dart:8:9)
+
+org-dartlang-testcase:///foo_lib.dart:
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+
+org-dartlang-testcase:///bar_lib.dart:
+- Foo. (from org-dartlang-testcase:///foo_lib.dart:10:9)
diff --git a/pkg/front_end/testcases/general/issue45003/main.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue45003/main.dart.weak.outline.expect
new file mode 100644
index 0000000..e71f7a0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/main.dart.weak.outline.expect
@@ -0,0 +1,47 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+import "bar_lib.dart" as bar;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+static const field core::Set<foo::Foo> foo = const <foo::Foo>{const bar::Bar::•<dynamic>()};
+static method main() → dynamic
+ ;
+
+library /*isNonNullableByDefault*/;
+import self as foo;
+import "dart:core" as core;
+import "bar_lib.dart" as bar;
+additionalExports = (bar::Bar)
+
+import "org-dartlang-testcase:///bar_lib.dart";
+export "org-dartlang-testcase:///bar_lib.dart";
+
+abstract class Foo extends core::Object /*hasConstConstructor*/ {
+ static final field dynamic _redirecting# = <dynamic>[foo::Foo::bar]/*isLegacy*/;
+ const constructor •() → foo::Foo
+ : super core::Object::•()
+ ;
+ static factory bar() → foo::Foo
+ let dynamic #redirecting_factory = bar::Bar::• in let dynamic #typeArg0 = null in invalid-expression;
+}
+
+library /*isNonNullableByDefault*/;
+import self as bar;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+class Bar<T extends core::Object? = dynamic> extends foo::Foo /*hasConstConstructor*/ {
+ const constructor •() → bar::Bar<bar::Bar::T%>
+ : super foo::Foo::•()
+ ;
+}
+
+
+Extra constant evaluation status:
+Evaluated: SetLiteral @ org-dartlang-testcase:///main.dart:7:27 -> InstanceConstant(const _UnmodifiableSet<Foo*>{_UnmodifiableSet._map: const _ImmutableMap<Foo*, Null>{_ImmutableMap._kvPairs: const <dynamic>[const Bar<dynamic>{}, null]}})
+Extra constant evaluation: evaluated: 6, effectively constant: 1
diff --git a/pkg/front_end/testcases/general/issue45003/main.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue45003/main.dart.weak.transformed.expect
new file mode 100644
index 0000000..c2de772
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003/main.dart.weak.transformed.expect
@@ -0,0 +1,59 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+static const field core::Set<foo::Foo> foo = #C5;
+static method main() → dynamic {}
+
+library /*isNonNullableByDefault*/;
+import self as foo;
+import "dart:core" as core;
+import "bar_lib.dart" as bar;
+additionalExports = (bar::Bar)
+
+import "org-dartlang-testcase:///bar_lib.dart";
+export "org-dartlang-testcase:///bar_lib.dart";
+
+abstract class Foo extends core::Object /*hasConstConstructor*/ {
+ static final field dynamic _redirecting# = <dynamic>[foo::Foo::bar]/*isLegacy*/;
+ const constructor •() → foo::Foo
+ : super core::Object::•()
+ ;
+ static factory bar() → foo::Foo
+ let<BottomType> #redirecting_factory = bar::Bar::• in let<BottomType> #typeArg0 = null in invalid-expression;
+}
+
+library /*isNonNullableByDefault*/;
+import self as bar;
+import "dart:core" as core;
+import "foo_lib.dart" as foo;
+
+import "org-dartlang-testcase:///foo_lib.dart";
+
+class Bar<T extends core::Object? = dynamic> extends foo::Foo /*hasConstConstructor*/ {
+ const constructor •() → bar::Bar<bar::Bar::T%>
+ : super foo::Foo::•()
+ ;
+}
+
+constants {
+ #C1 = bar::Bar<dynamic> {}
+ #C2 = null
+ #C3 = <dynamic>[#C1, #C2]
+ #C4 = core::_ImmutableMap<foo::Foo*, Null> {_kvPairs:#C3}
+ #C5 = col::_UnmodifiableSet<foo::Foo*> {_map:#C4}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///main.dart:
+- Bar. (from org-dartlang-testcase:///bar_lib.dart:8:9)
+
+org-dartlang-testcase:///foo_lib.dart:
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+
+org-dartlang-testcase:///bar_lib.dart:
+- Foo. (from org-dartlang-testcase:///foo_lib.dart:10:9)
diff --git a/pkg/front_end/testcases/general/issue45003_2.dart b/pkg/front_end/testcases/general/issue45003_2.dart
new file mode 100644
index 0000000..d93da65
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003_2.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class C {
+ const C({dynamic x = const A.foo()});
+}
+
+class B<X> extends A {
+ const B();
+}
+
+abstract class A {
+ const A();
+ const factory A.foo() = B;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45003_2.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue45003_2.dart.textual_outline.expect
new file mode 100644
index 0000000..6ceb0af
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003_2.dart.textual_outline.expect
@@ -0,0 +1,14 @@
+class C {
+ const C({dynamic x = const A.foo()});
+}
+
+class B<X> extends A {
+ const B();
+}
+
+abstract class A {
+ const A();
+ const factory A.foo() = B;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45003_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue45003_2.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..2a57c83
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003_2.dart.textual_outline_modelled.expect
@@ -0,0 +1,14 @@
+abstract class A {
+ const A();
+ const factory A.foo() = B;
+}
+
+class B<X> extends A {
+ const B();
+}
+
+class C {
+ const C({dynamic x = const A.foo()});
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45003_2.dart.weak.expect b/pkg/front_end/testcases/general/issue45003_2.dart.weak.expect
new file mode 100644
index 0000000..05d8566
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003_2.dart.weak.expect
@@ -0,0 +1,34 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object /*hasConstConstructor*/ {
+ const constructor •({dynamic x = #C1}) → self::C
+ : super core::Object::•()
+ ;
+}
+class B<X extends core::Object? = dynamic> extends self::A /*hasConstConstructor*/ {
+ const constructor •() → self::B<self::B::X%>
+ : super self::A::•()
+ ;
+}
+abstract class A extends core::Object /*hasConstConstructor*/ {
+ static final field dynamic _redirecting# = <dynamic>[self::A::foo]/*isLegacy*/;
+ const constructor •() → self::A
+ : super core::Object::•()
+ ;
+ static factory foo() → self::A
+ let dynamic #redirecting_factory = self::B::• in let dynamic #typeArg0 = null in invalid-expression;
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = self::B<dynamic> {}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///issue45003_2.dart:
+- B. (from org-dartlang-testcase:///issue45003_2.dart:10:9)
+- A. (from org-dartlang-testcase:///issue45003_2.dart:14:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/general/issue45003_2.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue45003_2.dart.weak.outline.expect
new file mode 100644
index 0000000..25cabc79
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003_2.dart.weak.outline.expect
@@ -0,0 +1,29 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object /*hasConstConstructor*/ {
+ const constructor •({dynamic x = const self::B::•<dynamic>()}) → self::C
+ : super core::Object::•()
+ ;
+}
+class B<X extends core::Object? = dynamic> extends self::A /*hasConstConstructor*/ {
+ const constructor •() → self::B<self::B::X%>
+ : super self::A::•()
+ ;
+}
+abstract class A extends core::Object /*hasConstConstructor*/ {
+ static final field dynamic _redirecting# = <dynamic>[self::A::foo]/*isLegacy*/;
+ const constructor •() → self::A
+ : super core::Object::•()
+ ;
+ static factory foo() → self::A
+ let dynamic #redirecting_factory = self::B::• in let dynamic #typeArg0 = null in invalid-expression;
+}
+static method main() → dynamic
+ ;
+
+
+Extra constant evaluation status:
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///issue45003_2.dart:6:30 -> InstanceConstant(const B<dynamic>{})
+Extra constant evaluation: evaluated: 6, effectively constant: 1
diff --git a/pkg/front_end/testcases/general/issue45003_2.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue45003_2.dart.weak.transformed.expect
new file mode 100644
index 0000000..6b11962
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45003_2.dart.weak.transformed.expect
@@ -0,0 +1,34 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object /*hasConstConstructor*/ {
+ const constructor •({dynamic x = #C1}) → self::C
+ : super core::Object::•()
+ ;
+}
+class B<X extends core::Object? = dynamic> extends self::A /*hasConstConstructor*/ {
+ const constructor •() → self::B<self::B::X%>
+ : super self::A::•()
+ ;
+}
+abstract class A extends core::Object /*hasConstConstructor*/ {
+ static final field dynamic _redirecting# = <dynamic>[self::A::foo]/*isLegacy*/;
+ const constructor •() → self::A
+ : super core::Object::•()
+ ;
+ static factory foo() → self::A
+ let<BottomType> #redirecting_factory = self::B::• in let<BottomType> #typeArg0 = null in invalid-expression;
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = self::B<dynamic> {}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///issue45003_2.dart:
+- B. (from org-dartlang-testcase:///issue45003_2.dart:10:9)
+- A. (from org-dartlang-testcase:///issue45003_2.dart:14:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index a2daadf..586d009 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -10,6 +10,7 @@
show
templateFfiEmptyStruct,
templateFfiFieldAnnotation,
+ templateFfiFieldNull,
templateFfiFieldCyclic,
templateFfiFieldNoAnnotation,
templateFfiTypeMismatch,
@@ -227,6 +228,14 @@
if (type is InvalidType) {
return false;
}
+ if (type is NullType) {
+ return false;
+ }
+ if (type is InterfaceType) {
+ if (type.classNode == structClass) {
+ return false;
+ }
+ }
return env.isSubtypeOf(type, InterfaceType(structClass, Nullability.legacy),
SubtypeCheckMode.ignoringNullabilities);
}
@@ -279,7 +288,15 @@
}
final nativeTypeAnnos = _getNativeTypeAnnotations(f).toList();
final type = _structFieldMemberType(f);
- if (_isPointerType(type) || _isStructSubtype(type)) {
+ if (type is NullType) {
+ diagnosticReporter.report(
+ templateFfiFieldNull.withArguments(f.name.text),
+ f.fileOffset,
+ f.name.text.length,
+ f.fileUri);
+ // This class is invalid, but continue reporting other errors on it.
+ success = false;
+ } else if (_isPointerType(type) || _isStructSubtype(type)) {
if (nativeTypeAnnos.length != 0) {
diagnosticReporter.report(
templateFfiFieldNoAnnotation.withArguments(f.name.text),
diff --git a/runtime/vm/experimental_features.cc b/runtime/vm/experimental_features.cc
index 12b02ef..e341195 100644
--- a/runtime/vm/experimental_features.cc
+++ b/runtime/vm/experimental_features.cc
@@ -18,7 +18,7 @@
bool GetExperimentalFeatureDefault(ExperimentalFeature feature) {
constexpr bool kFeatureValues[] = {
- true, true, true, true, true, true, true,
+ true, true, true, true, true, true,
};
ASSERT(static_cast<size_t>(feature) < ARRAY_SIZE(kFeatureValues));
return kFeatureValues[static_cast<int>(feature)];
@@ -26,10 +26,9 @@
const char* GetExperimentalFeatureName(ExperimentalFeature feature) {
constexpr const char* kFeatureNames[] = {
- "extension-types", "non-nullable",
- "extension-methods", "constant-update-2018",
- "control-flow-collections", "set-literals",
- "spread-collections",
+ "non-nullable", "extension-methods",
+ "constant-update-2018", "control-flow-collections",
+ "set-literals", "spread-collections",
};
ASSERT(static_cast<size_t>(feature) < ARRAY_SIZE(kFeatureNames));
return kFeatureNames[static_cast<int>(feature)];
diff --git a/runtime/vm/experimental_features.h b/runtime/vm/experimental_features.h
index 6418be6..8efd29e 100644
--- a/runtime/vm/experimental_features.h
+++ b/runtime/vm/experimental_features.h
@@ -14,7 +14,6 @@
namespace dart {
enum class ExperimentalFeature {
- extension_types,
non_nullable,
extension_methods,
constant_update_2018,
diff --git a/tests/ffi/regress_44985_test.dart b/tests/ffi/regress_44985_test.dart
new file mode 100644
index 0000000..6ef8da6
--- /dev/null
+++ b/tests/ffi/regress_44985_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:ffi";
+
+class S2 extends Struct {
+ external Pointer<Int8> notEmpty;
+
+ external Struct? s; //# 01: compile-time error
+}
+
+void main() {
+ S2? s2;
+}
diff --git a/tests/ffi/regress_44986_test.dart b/tests/ffi/regress_44986_test.dart
new file mode 100644
index 0000000..2736deb
--- /dev/null
+++ b/tests/ffi/regress_44986_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:ffi";
+
+class S2 extends Struct {
+ external Pointer<Int8> notEmpty;
+
+ external Null s; //# 01: compile-time error
+}
+
+void main() {
+ S2? s2;
+}
diff --git a/tests/ffi_2/regress_44985_test.dart b/tests/ffi_2/regress_44985_test.dart
new file mode 100644
index 0000000..b63931f
--- /dev/null
+++ b/tests/ffi_2/regress_44985_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:ffi";
+
+class S2 extends Struct {
+ Pointer<Int8> notEmpty;
+
+ Struct s; //# 01: compile-time error
+}
+
+void main() {
+ S2 s2;
+}
diff --git a/tests/ffi_2/regress_44986_test.dart b/tests/ffi_2/regress_44986_test.dart
new file mode 100644
index 0000000..7395880
--- /dev/null
+++ b/tests/ffi_2/regress_44986_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:ffi";
+
+class S2 extends Struct {
+ Pointer<Int8> notEmpty;
+
+ Null s; //# 01: compile-time error
+}
+
+void main() {
+ S2 s2;
+}
diff --git a/tests/language/generic/generic_function_type_argument_test.dart b/tests/language/generic/generic_function_type_argument_test.dart
new file mode 100644
index 0000000..c51c674
--- /dev/null
+++ b/tests/language/generic/generic_function_type_argument_test.dart
@@ -0,0 +1,90 @@
+// 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.
+
+// SharedOptions=--enable-experiment=generic-metadata
+
+import "package:expect/expect.dart";
+import "../static_type_helper.dart";
+
+// Check that generic function types can be used as type arguments.
+
+typedef F = T Function<T>(T);
+
+class C<T> {
+ final T value;
+ const C(this.value);
+}
+
+T f<T>(T value) => value;
+
+extension E<T> on T {
+ T get extensionValue => this;
+}
+
+// A generic function type can be a type parameter bound.
+
+// For a type alias:
+typedef FB<T extends F> = S Function<S extends T>(S);
+
+// For a class:
+class CB<T extends F> {
+ final T function;
+ const CB(this.function);
+}
+
+// For a function:
+T fb<T extends F>(T value) => value;
+
+extension EB<T extends F> on T {
+ T get boundExtensionValue => this;
+
+ // Any function type has a `call` of its own type?
+ T get boundCall => this.call;
+}
+
+// Can be used as arguments to metadata too.
+@C<F>(f)
+@CB<FB<F>>(fb)
+void main() {
+ // Sanity checks.
+ Expect.type<F>(f);
+ Expect.type<FB<F>>(fb);
+
+ // A generic function type can be the argument to a generic class.
+ var list = [f]; // Inferred from content.
+ Expect.type<List<F>>(list);
+ list = []; // Inferred from context.
+ list.add(f);
+ list = <F>[]; // Explicit.
+ list.add(f);
+
+ // Also if the type has a bound.
+ var list2 = [fb];
+ Expect.type<List<FB<F>>>(list2);
+
+ // The instance is a subtype of its supertypes.
+ Expect.type<List<Function>>(list);
+ Expect.type<List<Object? Function<T>(Never)>>(list);
+ Expect.notType<List<Object? Function(Never)>>(list);
+
+ // A generic function type can be the argument to a generic function.
+ var g1 = f(f); // inferred from argument.
+ g1 = f(f); // Inferred from context.
+ g1 = f<F>(f); // Explicit.
+ g1.expectStaticType<Exactly<F>>();
+
+ // Extensions can match generic function types.
+ list.add(f.extensionValue);
+ list.add(E(f).extensionValue);
+ list.add(E<F>(f).extensionValue);
+ list.add(f.boundExtensionValue);
+ list.add(EB(f).boundExtensionValue);
+ list.add(EB<F>(f).boundExtensionValue);
+ list.add(f.boundCall);
+ list.add(EB(f).boundCall);
+ list.add(EB<F>(f).boundCall);
+ list2.add(fb.extensionValue);
+ list2.add(E(fb).extensionValue);
+ list2.add(E<FB<F>>(fb).extensionValue);
+}
diff --git a/tests/standalone/io/https_connection_closed_during_handshake_test.dart b/tests/standalone/io/https_connection_closed_during_handshake_test.dart
index eed79c2..ca22cb0 100644
--- a/tests/standalone/io/https_connection_closed_during_handshake_test.dart
+++ b/tests/standalone/io/https_connection_closed_during_handshake_test.dart
@@ -11,6 +11,7 @@
import 'dart:convert';
import 'dart:io';
+import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
String getFilename(String path) => Platform.script.resolve(path).toFilePath();
@@ -45,6 +46,8 @@
exit(1);
}
+ asyncStart();
+
final serverProcess = await Process.start(
Platform.executable, [Platform.script.toFilePath(), 'server']);
final serverPortCompleter = Completer<int>();
@@ -65,17 +68,20 @@
int port = await serverPortCompleter.future;
- var thrownException;
- try {
- print('client connecting...');
- await SecureSocket.connect('localhost', port,
+ final errorCompleter = Completer();
+ await runZoned(() async {
+ var socket = await SecureSocket.connect('localhost', port,
context: clientSecurityContext);
- print('client connected.');
- } catch (e) {
- thrownException = e;
- } finally {
- await serverProcess.kill();
- }
- print('thrownException: $thrownException');
- Expect.isTrue(thrownException is HandshakeException);
+ socket.write(<int>[1, 2, 3]);
+ }, onError: (e) async {
+ // Even if server disconnects during later parts of handshake, since
+ // TLS v1.3 client might not notice it until attempt to communicate with
+ // the server.
+ print('thrownException: $e');
+ errorCompleter.complete(e);
+ });
+ Expect.isTrue((await errorCompleter.future) is SocketException);
+ await serverProcess.kill();
+
+ asyncEnd();
}
diff --git a/tests/standalone_2/io/https_connection_closed_during_handshake_test.dart b/tests/standalone_2/io/https_connection_closed_during_handshake_test.dart
index eed79c2..4ef2fef 100644
--- a/tests/standalone_2/io/https_connection_closed_during_handshake_test.dart
+++ b/tests/standalone_2/io/https_connection_closed_during_handshake_test.dart
@@ -11,6 +11,7 @@
import 'dart:convert';
import 'dart:io';
+import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
String getFilename(String path) => Platform.script.resolve(path).toFilePath();
@@ -44,6 +45,7 @@
print('server: exiting');
exit(1);
}
+ asyncStart();
final serverProcess = await Process.start(
Platform.executable, [Platform.script.toFilePath(), 'server']);
@@ -65,17 +67,20 @@
int port = await serverPortCompleter.future;
- var thrownException;
- try {
- print('client connecting...');
- await SecureSocket.connect('localhost', port,
+ final errorCompleter = Completer();
+ await runZoned(() async {
+ var socket = await SecureSocket.connect('localhost', port,
context: clientSecurityContext);
- print('client connected.');
- } catch (e) {
- thrownException = e;
- } finally {
- await serverProcess.kill();
- }
- print('thrownException: $thrownException');
- Expect.isTrue(thrownException is HandshakeException);
+ socket.write(<int>[1, 2, 3]);
+ }, onError: (e) async {
+ // Even if server disconnects during later parts of handshake, since
+ // TLS v1.3 client might not notice it until attempt to communicate with
+ // the server.
+ print('thrownException: $e');
+ errorCompleter.complete(e);
+ });
+ Expect.isTrue((await errorCompleter.future) is SocketException);
+ await serverProcess.kill();
+
+ asyncEnd();
}
diff --git a/tools/VERSION b/tools/VERSION
index df8e394..c32fee5 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 55
+PRERELEASE 56
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/experimental_features.yaml b/tools/experimental_features.yaml
index e97a0a3..8e83f80 100644
--- a/tools/experimental_features.yaml
+++ b/tools/experimental_features.yaml
@@ -119,15 +119,14 @@
generic-metadata:
help: "Allow annotations to accept type arguments; also allow generic function types as type arguments"
+ extension-types:
+ help: "Extension Types"
+
#
# Flags below this line are shipped, retired, or rejected, cannot be specified
# on the command line, and will eventually be removed.
#
- extension-types:
- help: "Extension Types"
- enabledIn: '2.13.0'
-
non-nullable:
help: "Non Nullable by default"
experimentalReleaseVersion: '2.10.0'