[linter] Suppress prefer_initializing_formals when not a subtype.
Fixes the `prefer_initializing_formals` lint so that it no longer
fires on code like this:
class C {
int? _x;
C({dynamic x}) : _x = x;
}
The reason is that the type of an initializing formal parameter is
required to be a subtype of the type of the field; coercions and
dynamic downcasts are not allowed. So in the example above, there is
no semantics-preserving way to convert `x` to an initializing formal.
Note that this situation occasionally crops up due to the parameter
having an implicit type, e.g.:
class C {
int? _x;
C({x}) : _x = x;
}
Fixes https://github.com/dart-lang/sdk/issues/62765.
Change-Id: I6a6a69648d3b2bd2f631ef01093b199125a71fa7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/483864
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
@@ -142,6 +142,15 @@ class _ConstructorChecker {
|
||||
if (parameter is! FormalParameterElement) return;
|
||||
if (!_parameters.contains(parameter)) return;
|
||||
|
||||
// An initializing formal is required to have a type that's a subtype of the
|
||||
// field type (assignability is not sufficient). If this requirement isn't
|
||||
// met, don't lint, because the corresponding fix will lead to a
|
||||
// compile-time error.
|
||||
var library = parameter.library!;
|
||||
if (!library.typeSystem.isSubtypeOf(parameter.type, field.type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Must be the same name (modulo privacy for private named parameters).
|
||||
if (field.isPrivate) {
|
||||
// Never lint on private names if the feature isn't supported.
|
||||
|
||||
@@ -396,6 +396,42 @@ class C {
|
||||
''');
|
||||
}
|
||||
|
||||
test_dynamicParameterType_dynamicField() async {
|
||||
await assertDiagnostics(
|
||||
r'''
|
||||
class C {
|
||||
dynamic _x;
|
||||
|
||||
C({dynamic x}) : _x = x;
|
||||
}
|
||||
''',
|
||||
[lint(44, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_dynamicParameterType_nonTopTypeField() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C {
|
||||
String? _x;
|
||||
|
||||
C({dynamic x}) : _x = x;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_dynamicParameterType_objectQuestionField() async {
|
||||
await assertDiagnostics(
|
||||
r'''
|
||||
class C {
|
||||
Object? _x;
|
||||
|
||||
C({dynamic x}) : _x = x;
|
||||
}
|
||||
''',
|
||||
[lint(44, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_factoryConstructor() async {
|
||||
// https://github.com/dart-lang/linter/issues/2441
|
||||
await assertNoDiagnostics(r'''
|
||||
@@ -429,6 +465,42 @@ class C {
|
||||
''');
|
||||
}
|
||||
|
||||
test_implicitParameterType_dynamicField() async {
|
||||
await assertDiagnostics(
|
||||
r'''
|
||||
class C {
|
||||
dynamic _x;
|
||||
|
||||
C({x}) : _x = x;
|
||||
}
|
||||
''',
|
||||
[lint(36, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_implicitParameterType_nonTopTypeField() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C {
|
||||
String? _x;
|
||||
|
||||
C({x}) : _x = x;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_implicitParameterType_objectQuestionField() async {
|
||||
await assertDiagnostics(
|
||||
r'''
|
||||
class C {
|
||||
Object? _x;
|
||||
|
||||
C({x}) : _x = x;
|
||||
}
|
||||
''',
|
||||
[lint(36, 6)],
|
||||
);
|
||||
}
|
||||
|
||||
test_initializeFromOtherParameter() async {
|
||||
await assertNoDiagnostics(r'''
|
||||
class C {
|
||||
|
||||
Reference in New Issue
Block a user