mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Extension types. Report when implemented not extension type superinterface is not a supertype of the representation type erasure.
Change-Id: Ib1f2bfcfe51edb6bcbc54d7165f148810e3df4ab Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/319600 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
6f645c8f1c
commit
4dffed5065
|
@ -654,6 +654,8 @@ CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_DISALLOWED_TYPE:
|
||||||
status: noFix
|
status: noFix
|
||||||
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_ITSELF:
|
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_ITSELF:
|
||||||
status: noFix
|
status: noFix
|
||||||
|
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_NOT_SUPERTYPE_OF_ERASURE:
|
||||||
|
status: noFix
|
||||||
CompileTimeErrorCode.EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT:
|
CompileTimeErrorCode.EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT:
|
||||||
status: noFix
|
status: noFix
|
||||||
CompileTimeErrorCode.EXTENSION_TYPE_REPRESENTATION_DEPENDS_ON_ITSELF:
|
CompileTimeErrorCode.EXTENSION_TYPE_REPRESENTATION_DEPENDS_ON_ITSELF:
|
||||||
|
|
|
@ -1648,15 +1648,9 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
|
||||||
|
|
||||||
final type = namedType.typeOrThrow;
|
final type = namedType.typeOrThrow;
|
||||||
|
|
||||||
if (declaration is ExtensionTypeDeclaration) {
|
final enclosingElement = _namedTypeResolver.enclosingClass;
|
||||||
final typeSystem = _libraryElement.typeSystem;
|
if (enclosingElement is ExtensionTypeElementImpl) {
|
||||||
if (!typeSystem.isValidExtensionTypeSuperinterface(type)) {
|
_verifyExtensionElementImplements(enclosingElement, namedType, type);
|
||||||
_errorReporter.reportErrorForNode(
|
|
||||||
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_DISALLOWED_TYPE,
|
|
||||||
namedType,
|
|
||||||
[type],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1770,6 +1764,35 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _verifyExtensionElementImplements(
|
||||||
|
ExtensionTypeElementImpl declaredElement,
|
||||||
|
NamedTypeImpl node,
|
||||||
|
DartType type,
|
||||||
|
) {
|
||||||
|
final typeSystem = _libraryElement.typeSystem;
|
||||||
|
|
||||||
|
if (!typeSystem.isValidExtensionTypeSuperinterface(type)) {
|
||||||
|
_errorReporter.reportErrorForNode(
|
||||||
|
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_DISALLOWED_TYPE,
|
||||||
|
node,
|
||||||
|
[type],
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.element is! ExtensionTypeElement) {
|
||||||
|
final erasure = declaredElement.typeErasure;
|
||||||
|
if (!typeSystem.isSubtypeOf(erasure, type)) {
|
||||||
|
_errorReporter.reportErrorForNode(
|
||||||
|
CompileTimeErrorCode
|
||||||
|
.EXTENSION_TYPE_IMPLEMENTS_NOT_SUPERTYPE_OF_ERASURE,
|
||||||
|
node,
|
||||||
|
[type, erasure],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _visitIf(IfElementOrStatementImpl node) {
|
void _visitIf(IfElementOrStatementImpl node) {
|
||||||
var caseClause = node.caseClause;
|
var caseClause = node.caseClause;
|
||||||
if (caseClause != null) {
|
if (caseClause != null) {
|
||||||
|
|
|
@ -1651,6 +1651,17 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
|
||||||
"Try removing the superinterface that references this extension type.",
|
"Try removing the superinterface that references this extension type.",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Parameters:
|
||||||
|
/// 0: the implemented not extension type
|
||||||
|
/// 1: the ultimate representation type
|
||||||
|
static const CompileTimeErrorCode
|
||||||
|
EXTENSION_TYPE_IMPLEMENTS_NOT_SUPERTYPE_OF_ERASURE = CompileTimeErrorCode(
|
||||||
|
'EXTENSION_TYPE_IMPLEMENTS_NOT_SUPERTYPE_OF_ERASURE',
|
||||||
|
"'{0}' is not a supertype of '{1}', the ultimate representation type.",
|
||||||
|
correctionMessage:
|
||||||
|
"Try specifying a different type, or remove the type from the list.",
|
||||||
|
);
|
||||||
|
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// 0: the name of the extension type
|
/// 0: the name of the extension type
|
||||||
/// 1: the name of the conflicting member
|
/// 1: the name of the conflicting member
|
||||||
|
|
|
@ -197,6 +197,7 @@ const List<ErrorCode> errorCodeValues = [
|
||||||
CompileTimeErrorCode.EXTENSION_TYPE_DECLARES_MEMBER_OF_OBJECT,
|
CompileTimeErrorCode.EXTENSION_TYPE_DECLARES_MEMBER_OF_OBJECT,
|
||||||
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_DISALLOWED_TYPE,
|
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_DISALLOWED_TYPE,
|
||||||
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_ITSELF,
|
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_ITSELF,
|
||||||
|
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_NOT_SUPERTYPE_OF_ERASURE,
|
||||||
CompileTimeErrorCode.EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT,
|
CompileTimeErrorCode.EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT,
|
||||||
CompileTimeErrorCode.EXTENSION_TYPE_REPRESENTATION_DEPENDS_ON_ITSELF,
|
CompileTimeErrorCode.EXTENSION_TYPE_REPRESENTATION_DEPENDS_ON_ITSELF,
|
||||||
CompileTimeErrorCode.EXTERNAL_FIELD_CONSTRUCTOR_INITIALIZER,
|
CompileTimeErrorCode.EXTERNAL_FIELD_CONSTRUCTOR_INITIALIZER,
|
||||||
|
|
|
@ -5082,6 +5082,13 @@ CompileTimeErrorCode:
|
||||||
problemMessage: "The extension type can't implement itself."
|
problemMessage: "The extension type can't implement itself."
|
||||||
correctionMessage: Try removing the superinterface that references this extension type.
|
correctionMessage: Try removing the superinterface that references this extension type.
|
||||||
comment: No parameters.
|
comment: No parameters.
|
||||||
|
EXTENSION_TYPE_IMPLEMENTS_NOT_SUPERTYPE_OF_ERASURE:
|
||||||
|
problemMessage: "'{0}' is not a supertype of '{1}', the ultimate representation type."
|
||||||
|
correctionMessage: Try specifying a different type, or remove the type from the list.
|
||||||
|
comment: |-
|
||||||
|
Parameters:
|
||||||
|
0: the implemented not extension type
|
||||||
|
1: the ultimate representation type
|
||||||
EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT:
|
EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT:
|
||||||
problemMessage: "The extension type '{0}' has more than one distinct member named '{1}' from implemented types."
|
problemMessage: "The extension type '{0}' has more than one distinct member named '{1}' from implemented types."
|
||||||
correctionMessage: Try redeclaring the corresponding member in this extension type.
|
correctionMessage: Try redeclaring the corresponding member in this extension type.
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
||||||
|
// for details. All rights reserved. Use of this source code is governed by a
|
||||||
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:analyzer/src/error/codes.dart';
|
||||||
|
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||||
|
|
||||||
|
import '../dart/resolution/context_collection_resolution.dart';
|
||||||
|
|
||||||
|
main() {
|
||||||
|
defineReflectiveSuite(() {
|
||||||
|
defineReflectiveTests(ExtensionTypeImplementsDisallowedTypeTest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@reflectiveTest
|
||||||
|
class ExtensionTypeImplementsDisallowedTypeTest
|
||||||
|
extends PubPackageResolutionTest {
|
||||||
|
test_notSupertype() async {
|
||||||
|
await assertErrorsInCode('''
|
||||||
|
extension type A(int it) implements String {}
|
||||||
|
''', [
|
||||||
|
error(
|
||||||
|
CompileTimeErrorCode
|
||||||
|
.EXTENSION_TYPE_IMPLEMENTS_NOT_SUPERTYPE_OF_ERASURE,
|
||||||
|
36,
|
||||||
|
6),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_supertype2() async {
|
||||||
|
await assertNoErrorsInCode('''
|
||||||
|
extension type A(S3 it) implements S1 {}
|
||||||
|
class S1 {}
|
||||||
|
class S2 extends S1 {}
|
||||||
|
class S3 extends S2 {}
|
||||||
|
''');
|
||||||
|
}
|
||||||
|
|
||||||
|
test_supertype_erasure() async {
|
||||||
|
await assertNoErrorsInCode('''
|
||||||
|
extension type A(int it) {}
|
||||||
|
extension type B(A it) implements num {}
|
||||||
|
''');
|
||||||
|
}
|
||||||
|
|
||||||
|
test_supertype_interfaceType() async {
|
||||||
|
await assertNoErrorsInCode('''
|
||||||
|
extension type A(int it) implements num {}
|
||||||
|
''');
|
||||||
|
}
|
||||||
|
}
|
|
@ -129,22 +129,26 @@ class ExtensionTypeInheritedMemberConflictTest_notExtension
|
||||||
test_conflict() async {
|
test_conflict() async {
|
||||||
await assertErrorsInCode('''
|
await assertErrorsInCode('''
|
||||||
class A {
|
class A {
|
||||||
int foo() => 0;
|
void foo(int a) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class B {
|
class B {
|
||||||
String foo() => '0';
|
void foo(String a) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension type C(Object it) implements A, B {}
|
class C implements A, B {
|
||||||
|
void foo(Object a) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension type D(C it) implements A, B {}
|
||||||
''', [
|
''', [
|
||||||
error(
|
error(
|
||||||
CompileTimeErrorCode.EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT,
|
CompileTimeErrorCode.EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT,
|
||||||
82,
|
139,
|
||||||
1,
|
1,
|
||||||
contextMessages: [
|
contextMessages: [
|
||||||
message('/home/test/lib/test.dart', 16, 3),
|
message('/home/test/lib/test.dart', 17, 3),
|
||||||
message('/home/test/lib/test.dart', 50, 3),
|
message('/home/test/lib/test.dart', 51, 3)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
@ -153,14 +157,18 @@ extension type C(Object it) implements A, B {}
|
||||||
test_noConflict_redeclared() async {
|
test_noConflict_redeclared() async {
|
||||||
await assertNoErrorsInCode('''
|
await assertNoErrorsInCode('''
|
||||||
class A {
|
class A {
|
||||||
int foo() => 0;
|
void foo(int a) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class B {
|
class B {
|
||||||
String foo() => '0';
|
void foo(String a) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension type C(Object it) implements A, B {
|
class C implements A, B {
|
||||||
|
void foo(Object a) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension type D(C it) implements A, B {
|
||||||
void foo() {}
|
void foo() {}
|
||||||
}
|
}
|
||||||
''');
|
''');
|
||||||
|
|
|
@ -250,6 +250,8 @@ import 'extension_type_implements_disallowed_type_test.dart'
|
||||||
as extension_type_implements_disallowed_type;
|
as extension_type_implements_disallowed_type;
|
||||||
import 'extension_type_implements_itself_test.dart'
|
import 'extension_type_implements_itself_test.dart'
|
||||||
as extension_type_implements_itself;
|
as extension_type_implements_itself;
|
||||||
|
import 'extension_type_implements_not_supertype_of_erasure_test.dart'
|
||||||
|
as extension_type_implements_not_supertype_of_erasure;
|
||||||
import 'extension_type_inherited_member_conflict_test.dart'
|
import 'extension_type_inherited_member_conflict_test.dart'
|
||||||
as extension_type_inherited_member_conflict;
|
as extension_type_inherited_member_conflict;
|
||||||
import 'extension_type_representation_depends_on_itself_test.dart'
|
import 'extension_type_representation_depends_on_itself_test.dart'
|
||||||
|
@ -1058,6 +1060,7 @@ main() {
|
||||||
extension_type_declares_member_of_object.main();
|
extension_type_declares_member_of_object.main();
|
||||||
extension_type_implements_disallowed_type.main();
|
extension_type_implements_disallowed_type.main();
|
||||||
extension_type_implements_itself.main();
|
extension_type_implements_itself.main();
|
||||||
|
extension_type_implements_not_supertype_of_erasure.main();
|
||||||
extension_type_inherited_member_conflict.main();
|
extension_type_inherited_member_conflict.main();
|
||||||
extension_type_representation_depends_on_itself.main();
|
extension_type_representation_depends_on_itself.main();
|
||||||
external_field_constructor_initializer.main();
|
external_field_constructor_initializer.main();
|
||||||
|
|
Loading…
Reference in a new issue