DeCo. Report initializingFormalForNonExistentField for primary constructors.
Change-Id: I42d2516902a0d7c2a3eb914d39afe01a10d4bf86 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/482640 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
@@ -6141,63 +6141,51 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
||||
}
|
||||
|
||||
void _checkForValidField(FieldFormalParameter parameter) {
|
||||
var parent2 = parameter.parent?.parent;
|
||||
if (parent2 is! ConstructorDeclaration &&
|
||||
parent2?.parent is! ConstructorDeclaration) {
|
||||
var constructor = parameter.parentFormalParameterList.parent;
|
||||
if (constructor is PrimaryConstructorDeclaration &&
|
||||
constructor.parent is ExtensionTypeDeclaration) {
|
||||
return;
|
||||
}
|
||||
if (constructor is! ConstructorDeclaration &&
|
||||
constructor is! PrimaryConstructorDeclaration) {
|
||||
return;
|
||||
}
|
||||
|
||||
var element = parameter.declaredFragment?.element;
|
||||
if (element is FieldFormalParameterElementImpl) {
|
||||
var fieldElement = element.field;
|
||||
if (fieldElement == null || fieldElement.isOriginGetterSetter) {
|
||||
diagnosticReporter.report(
|
||||
diag.initializingFormalForNonExistentField
|
||||
.withArguments(formalName: parameter.name.lexeme)
|
||||
.at(parameter),
|
||||
);
|
||||
} else {
|
||||
var parameterElement = parameter.declaredFragment?.element;
|
||||
if (parameterElement is FieldFormalParameterElementImpl) {
|
||||
var declaredType = parameterElement.type;
|
||||
var fieldType = fieldElement.type;
|
||||
if (fieldElement.isOriginGetterSetter) {
|
||||
diagnosticReporter.report(
|
||||
diag.initializingFormalForNonExistentField
|
||||
.withArguments(formalName: parameter.name.lexeme)
|
||||
.at(parameter),
|
||||
);
|
||||
} else if (fieldElement.isStatic) {
|
||||
diagnosticReporter.report(
|
||||
diag.initializerForStaticField
|
||||
.withArguments(formalName: parameter.name.lexeme)
|
||||
.at(parameter),
|
||||
);
|
||||
} else if (!typeSystem.isSubtypeOf(declaredType, fieldType)) {
|
||||
diagnosticReporter.report(
|
||||
diag.fieldInitializingFormalNotAssignable
|
||||
.withArguments(
|
||||
formalParameterType: declaredType,
|
||||
fieldType: fieldType,
|
||||
)
|
||||
.at(parameter),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (fieldElement.isOriginGetterSetter) {
|
||||
diagnosticReporter.report(
|
||||
diag.initializingFormalForNonExistentField
|
||||
.withArguments(formalName: parameter.name.lexeme)
|
||||
.at(parameter),
|
||||
);
|
||||
} else if (fieldElement.isStatic) {
|
||||
diagnosticReporter.report(
|
||||
diag.initializerForStaticField
|
||||
.withArguments(formalName: parameter.name.lexeme)
|
||||
.at(parameter),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (element is! FieldFormalParameterElementImpl) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fieldElement = element.field;
|
||||
if (fieldElement == null || fieldElement.isOriginGetterSetter) {
|
||||
diagnosticReporter.report(
|
||||
diag.initializingFormalForNonExistentField
|
||||
.withArguments(formalName: parameter.name.lexeme)
|
||||
.at(parameter),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fieldElement.isStatic) {
|
||||
diagnosticReporter.report(
|
||||
diag.initializerForStaticField
|
||||
.withArguments(formalName: parameter.name.lexeme)
|
||||
.at(parameter),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var elementType = element.type;
|
||||
var fieldType = fieldElement.type;
|
||||
if (!typeSystem.isSubtypeOf(elementType, fieldType)) {
|
||||
diagnosticReporter.report(
|
||||
diag.fieldInitializingFormalNotAssignable
|
||||
.withArguments(
|
||||
formalParameterType: elementType,
|
||||
fieldType: fieldType,
|
||||
)
|
||||
.at(parameter),
|
||||
);
|
||||
}
|
||||
// else {
|
||||
// TODO(jwren): Report error, constructor initializer variable is a top level element
|
||||
|
||||
@@ -6431,7 +6431,10 @@ class const A(this.x) {
|
||||
|
||||
const a = A(1);
|
||||
''',
|
||||
[error(diag.initializerForNonExistentField, 33, 5)],
|
||||
[
|
||||
error(diag.initializingFormalForNonExistentField, 14, 6),
|
||||
error(diag.initializerForNonExistentField, 33, 5),
|
||||
],
|
||||
);
|
||||
assertDartObjectText(_topLevelVar('a'), r'''
|
||||
A
|
||||
|
||||
@@ -15,7 +15,18 @@ main() {
|
||||
|
||||
@reflectiveTest
|
||||
class InitializerForStaticFieldTest extends PubPackageResolutionTest {
|
||||
test_fieldFormalParameter() async {
|
||||
test_class_primaryConstructor_fieldFormalParameter() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class A(this.x) {
|
||||
static int? x;
|
||||
}
|
||||
''',
|
||||
[error(diag.initializerForStaticField, 8, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_class_secondaryConstructor_fieldFormalParameter() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class A {
|
||||
@@ -27,7 +38,7 @@ class A {
|
||||
);
|
||||
}
|
||||
|
||||
test_initializer() async {
|
||||
test_class_secondaryConstructor_initializerList() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class A {
|
||||
@@ -40,4 +51,82 @@ class A {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_enum_primaryConstructor_fieldFormalParameter() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
enum E(this.x) {
|
||||
v(0);
|
||||
|
||||
static int? x;
|
||||
}
|
||||
''',
|
||||
[error(diag.initializerForStaticField, 7, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_enum_secondaryConstructor_fieldFormalParameter() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
enum E {
|
||||
v(0);
|
||||
static int x = 0;
|
||||
const E(this.x);
|
||||
}
|
||||
''',
|
||||
[error(diag.initializerForStaticField, 47, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_enum_secondaryConstructor_initializerList() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
enum E {
|
||||
v;
|
||||
static int x = 1;
|
||||
const E() : x = 0;
|
||||
}
|
||||
''',
|
||||
[
|
||||
error(diag.initializerForStaticField, 48, 5, messageContains: ["'x'"]),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_extensionType_primaryConstructor_fieldFormalParameter_notReportedHere() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
extension type E(this.x) {
|
||||
static int? x;
|
||||
}
|
||||
''',
|
||||
[error(diag.expectedRepresentationField, 17, 4)],
|
||||
);
|
||||
}
|
||||
|
||||
test_extensionType_secondaryConstructor_fieldFormalParameter() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
extension type E(int it) {
|
||||
static int x = 0;
|
||||
E.named(this.x) : this.it = 0;
|
||||
}
|
||||
''',
|
||||
[error(diag.initializerForStaticField, 57, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_extensionType_secondaryConstructor_initializerList() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
extension type E(int it) {
|
||||
static int x = 1;
|
||||
E.named() : x = 0, this.it = 0;
|
||||
}
|
||||
''',
|
||||
[
|
||||
error(diag.initializerForStaticField, 61, 5, messageContains: ["'x'"]),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+97
-22
@@ -16,7 +16,33 @@ main() {
|
||||
@reflectiveTest
|
||||
class InitializingFormalForNonExistentFieldTest
|
||||
extends PubPackageResolutionTest {
|
||||
test_class_nonExistent() async {
|
||||
test_class_primary_fieldExists() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class C(this.x) {
|
||||
final int x;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_class_primary_fieldMissing() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class C(this.x) {}
|
||||
''',
|
||||
[error(diag.initializingFormalForNonExistentField, 8, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_class_secondary_fieldExists() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class C {
|
||||
final int x;
|
||||
C(this.x);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_class_secondary_fieldMissing() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class A {
|
||||
@@ -27,7 +53,19 @@ class A {
|
||||
);
|
||||
}
|
||||
|
||||
test_class_notInEnclosingClass() async {
|
||||
test_class_secondary_fieldMissing_getter() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class A {
|
||||
int get x => 1;
|
||||
A(this.x) {}
|
||||
}
|
||||
''',
|
||||
[error(diag.initializingFormalForNonExistentField, 32, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_class_secondary_notInEnclosingClass() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class A {
|
||||
@@ -41,7 +79,7 @@ class B extends A {
|
||||
);
|
||||
}
|
||||
|
||||
test_class_optional() async {
|
||||
test_class_secondary_optionalPositional_fieldMissing() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class A {
|
||||
@@ -52,19 +90,28 @@ class A {
|
||||
);
|
||||
}
|
||||
|
||||
test_class_synthetic() async {
|
||||
test_enum_primary_fieldExists() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
enum E(this.x) {
|
||||
v(0);
|
||||
|
||||
final int x;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_enum_primary_fieldMissing() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class A {
|
||||
int get x => 1;
|
||||
A(this.x) {}
|
||||
enum E(this.x) {
|
||||
v(0);
|
||||
}
|
||||
''',
|
||||
[error(diag.initializingFormalForNonExistentField, 32, 6)],
|
||||
[error(diag.initializingFormalForNonExistentField, 7, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_enum_existing() async {
|
||||
test_enum_secondary_fieldExists() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
enum E {
|
||||
v(0);
|
||||
@@ -74,7 +121,32 @@ enum E {
|
||||
''');
|
||||
}
|
||||
|
||||
test_enum_optional() async {
|
||||
test_enum_secondary_fieldMissing() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
enum E {
|
||||
v(0);
|
||||
const E(this.x);
|
||||
}
|
||||
''',
|
||||
[error(diag.initializingFormalForNonExistentField, 27, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_enum_secondary_fieldMissing_getter() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
enum E {
|
||||
v(0);
|
||||
const E(this.x);
|
||||
int get x => 1;
|
||||
}
|
||||
''',
|
||||
[error(diag.initializingFormalForNonExistentField, 27, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_enum_secondary_optionalPositional_fieldMissing() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
enum E {
|
||||
@@ -89,28 +161,31 @@ enum E {
|
||||
);
|
||||
}
|
||||
|
||||
test_enum_required() async {
|
||||
test_extensionType_primary_fieldMissing_notReportedHere() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
enum E {
|
||||
v(0);
|
||||
const E(this.x);
|
||||
}
|
||||
extension type E(this.x) {}
|
||||
''',
|
||||
[error(diag.initializingFormalForNonExistentField, 27, 6)],
|
||||
[error(diag.expectedRepresentationField, 17, 4)],
|
||||
);
|
||||
}
|
||||
|
||||
test_enum_synthetic() async {
|
||||
test_extensionType_secondary_fieldExists() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
extension type E(int it) {
|
||||
E.named(this.it);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_extensionType_secondary_fieldMissing() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
enum E {
|
||||
v(0);
|
||||
const E(this.x);
|
||||
int get x => 1;
|
||||
extension type E(int it) {
|
||||
E.named(this.x) : this.it = 0;
|
||||
}
|
||||
''',
|
||||
[error(diag.initializingFormalForNonExistentField, 27, 6)],
|
||||
[error(diag.initializingFormalForNonExistentField, 37, 6)],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class Invalid {
|
||||
|
||||
test_requiredParam_declaring() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class A({required var String this.s});
|
||||
class A({required var String s});
|
||||
''');
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,8 @@ enum E(final String _v, [final String? v2]) {
|
||||
enum E(this._v, [this._v2]) {
|
||||
a('a'),
|
||||
b('b', 'c');
|
||||
final String _v;
|
||||
final String? _v2;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user