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:
Konstantin Shcheglov 2023-08-09 22:18:27 +00:00 committed by Commit Queue
parent 6f645c8f1c
commit 4dffed5065
8 changed files with 125 additions and 18 deletions

View file

@ -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:

View file

@ -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) {

View file

@ -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

View file

@ -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,

View file

@ -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.

View file

@ -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 {}
''');
}
}

View file

@ -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() {}
} }
'''); ''');

View file

@ -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();