1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-08 12:06:26 +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:
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
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_ITSELF:
status: noFix
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_NOT_SUPERTYPE_OF_ERASURE:
status: noFix
CompileTimeErrorCode.EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT:
status: noFix
CompileTimeErrorCode.EXTENSION_TYPE_REPRESENTATION_DEPENDS_ON_ITSELF:

View File

@ -1648,15 +1648,9 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
final type = namedType.typeOrThrow;
if (declaration is ExtensionTypeDeclaration) {
final typeSystem = _libraryElement.typeSystem;
if (!typeSystem.isValidExtensionTypeSuperinterface(type)) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_DISALLOWED_TYPE,
namedType,
[type],
);
}
final enclosingElement = _namedTypeResolver.enclosingClass;
if (enclosingElement is ExtensionTypeElementImpl) {
_verifyExtensionElementImplements(enclosingElement, namedType, type);
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) {
var caseClause = node.caseClause;
if (caseClause != null) {

View File

@ -1651,6 +1651,17 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
"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:
/// 0: the name of the extension type
/// 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_IMPLEMENTS_DISALLOWED_TYPE,
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_ITSELF,
CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_NOT_SUPERTYPE_OF_ERASURE,
CompileTimeErrorCode.EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT,
CompileTimeErrorCode.EXTENSION_TYPE_REPRESENTATION_DEPENDS_ON_ITSELF,
CompileTimeErrorCode.EXTERNAL_FIELD_CONSTRUCTOR_INITIALIZER,

View File

@ -5082,6 +5082,13 @@ CompileTimeErrorCode:
problemMessage: "The extension type can't implement itself."
correctionMessage: Try removing the superinterface that references this extension type.
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:
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.

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 {
await assertErrorsInCode('''
class A {
int foo() => 0;
void foo(int a) {}
}
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(
CompileTimeErrorCode.EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT,
82,
139,
1,
contextMessages: [
message('/home/test/lib/test.dart', 16, 3),
message('/home/test/lib/test.dart', 50, 3),
message('/home/test/lib/test.dart', 17, 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 {
await assertNoErrorsInCode('''
class A {
int foo() => 0;
void foo(int a) {}
}
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() {}
}
''');

View File

@ -250,6 +250,8 @@ import 'extension_type_implements_disallowed_type_test.dart'
as extension_type_implements_disallowed_type;
import 'extension_type_implements_itself_test.dart'
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'
as extension_type_inherited_member_conflict;
import 'extension_type_representation_depends_on_itself_test.dart'
@ -1058,6 +1060,7 @@ main() {
extension_type_declares_member_of_object.main();
extension_type_implements_disallowed_type.main();
extension_type_implements_itself.main();
extension_type_implements_not_supertype_of_erasure.main();
extension_type_inherited_member_conflict.main();
extension_type_representation_depends_on_itself.main();
external_field_constructor_initializer.main();