[cfe] Implement subtype relation for ExtensionType

Change-Id: I725c6abd4ad2ec7fe217e271fbe60d57af443f7a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196933
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
This commit is contained in:
Dmitry Stefantsov 2021-04-27 13:03:38 +00:00 committed by commit-bot@chromium.org
parent 6a7aaf5bc3
commit cc621431f9
6 changed files with 55 additions and 52 deletions

View file

@ -38,6 +38,9 @@ class ExtendedClass;
class ExtendedGenericClass<X>;
extension Extension on ExtendedClass;
extension GenericExtension<Y> on ExtendedGenericClass<Y>;
extension TopExtension on dynamic;
extension GenericTopExtension<Z> on dynamic;
class ExtendedSubclass extends ExtendedClass;
""";
const String expectedSdk = """
@ -89,10 +92,16 @@ class ExtendedClass extends self::Object {
}
class ExtendedGenericClass<X extends self::Object? = dynamic> extends self::Object {
}
class ExtendedSubclass extends self::ExtendedClass {
}
extension Extension on self::ExtendedClass {
}
extension GenericExtension<Y extends self::Object? = dynamic> on self::ExtendedGenericClass<Y%> {
}
extension TopExtension on dynamic {
}
extension GenericTopExtension<Z extends self::Object? = dynamic> on dynamic {
}
""";
Component parseSdk(Uri uri, TypeParserEnvironment environment) {

View file

@ -1042,5 +1042,32 @@ abstract class SubtypeTest<T, E> {
isSubtype("List<int?>?", "List<int?>?");
isSubtype("T & int?", "T & int?", typeParameters: "T extends Object?");
isSubtype("T? & int?", "T? & int?", typeParameters: "T extends Object");
// Tests for extension types.
isSubtype("Never", "Extension");
isSubtype("Never", "GenericExtension<Never>");
isSubtype("Extension", "dynamic");
isSubtype("Extension", "void");
isSubtype("Extension", "Object?");
isSubtype("Extension", "FutureOr<dynamic>");
isSubtype("GenericExtension<dynamic>", "dynamic");
isSubtype("GenericExtension<dynamic>", "void");
isSubtype("GenericExtension<dynamic>", "Object?");
isSubtype("GenericExtension<dynamic>", "FutureOr<dynamic>");
isSubtype("dynamic", "TopExtension");
isSubtype("void", "TopExtension");
isSubtype("Object?", "TopExtension");
isSubtype("FutureOr<dynamic>", "TopExtension");
isSubtype("num", "TopExtension");
isSubtype("dynamic", "GenericTopExtension<String>");
isSubtype("void", "GenericTopExtension<String>");
isSubtype("Object?", "GenericTopExtension<String>");
isSubtype("FutureOr<dynamic>", "GenericTopExtension<String>");
isSubtype("num", "GenericTopExtension<String>");
isNotSubtype("Extension", "ExtendedClass");
isNotSubtype("GenericExtension<num>", "ExtendedGenericClass<num>");
isSubtype("ExtendedClass", "Extension");
isSubtype("ExtendedGenericClass<num>", "GenericExtension<num>");
isSubtype("ExtendedSubclass", "Extension");
}
}

View file

@ -1,12 +1,4 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
// - 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
// Bar bar = Foo();
// ^
//
import self as self;
import "dart:core" as core;
@ -18,8 +10,5 @@ class Foo extends core::Object {
extension Bar on self::Foo {
}
static method main() → void {
self::Bar bar = let final Never #t1 = invalid-expression "pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
- 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
Bar bar = Foo();
^" in new self::Foo::•() as{TypeError,ForNonNullableByDefault} self::Bar;
self::Bar bar = new self::Foo::•();
}

View file

@ -1,12 +1,4 @@
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
// - 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
// Bar bar = Foo();
// ^
//
import self as self;
import "dart:core" as core;
@ -18,8 +10,5 @@ class Foo extends core::Object {
extension Bar on self::Foo {
}
static method main() → void {
self::Bar bar = let final Never #t1 = invalid-expression "pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
- 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
Bar bar = Foo();
^" in new self::Foo::•() as{TypeError,ForNonNullableByDefault} self::Bar;
self::Bar bar = new self::Foo::•();
}

View file

@ -447,7 +447,6 @@ class IsInterfaceSubtypeOf extends TypeRelation<InterfaceType> {
@override
IsSubtypeOf isExtensionRelated(
ExtensionType s, InterfaceType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@ -628,7 +627,6 @@ class IsFunctionSubtypeOf extends TypeRelation<FunctionType> {
@override
IsSubtypeOf isExtensionRelated(ExtensionType s, FunctionType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@ -715,7 +713,6 @@ class IsTypeParameterSubtypeOf extends TypeRelation<TypeParameterType> {
@override
IsSubtypeOf isExtensionRelated(
ExtensionType s, TypeParameterType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@ -767,8 +764,7 @@ class IsTypedefSubtypeOf extends TypeRelation<TypedefType> {
@override
IsSubtypeOf isExtensionRelated(ExtensionType s, TypedefType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
return types.performNullabilityAwareSubtypeCheck(s, t.unalias);
}
}
@ -900,8 +896,9 @@ class IsFutureOrSubtypeOf extends TypeRelation<FutureOrType> {
@override
IsSubtypeOf isExtensionRelated(ExtensionType s, FutureOrType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
// Rule 11.
return types.performNullabilityAwareSubtypeCheck(
s, t.typeArgument.withDeclaredNullability(t.nullability));
}
}
@ -966,7 +963,6 @@ class IsIntersectionSubtypeOf extends TypeRelation<TypeParameterType> {
@override
IsSubtypeOf isExtensionRelated(
ExtensionType s, TypeParameterType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@ -1022,7 +1018,6 @@ class IsNullTypeSubtypeOf implements TypeRelation<NullType> {
@override
IsSubtypeOf isExtensionRelated(ExtensionType s, NullType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@ -1077,7 +1072,6 @@ class IsNeverTypeSubtypeOf implements TypeRelation<NeverType> {
@override
IsSubtypeOf isExtensionRelated(ExtensionType s, NeverType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@ -1087,62 +1081,54 @@ class IsExtensionTypeSubtypeOf implements TypeRelation<ExtensionType> {
@override
IsSubtypeOf isDynamicRelated(DynamicType s, ExtensionType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isVoidRelated(VoidType s, ExtensionType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isInterfaceRelated(
InterfaceType s, ExtensionType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isIntersectionRelated(
TypeParameterType intersection, ExtensionType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
return types.performNullabilityAwareSubtypeCheck(intersection, t.onType);
}
@override
IsSubtypeOf isFunctionRelated(FunctionType s, ExtensionType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isFutureOrRelated(FutureOrType s, ExtensionType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isTypeParameterRelated(
TypeParameterType s, ExtensionType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isTypedefRelated(TypedefType s, ExtensionType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isExtensionRelated(
ExtensionType s, ExtensionType t, Types types) {
// TODO(dmitryas): Use with the actual subtyping rules for extension types.
if (s.extension != t.extension) {
return const IsSubtypeOf.never();
}
// TODO(dmitryas): Check if subtyping or mutual subtyping should be used.
return types
.areTypeArgumentsOfSubtypeKernel(
s.typeArguments, t.typeArguments, t.extension.typeParameters)

View file

@ -327,6 +327,9 @@ class _KernelFromParsedType implements Visitor<Node, TypeParserEnvironment> {
} else if (declaration is Typedef) {
return new TypedefType(declaration,
interpretParsedNullability(node.parsedNullability), kernelArguments);
} else if (declaration is Extension) {
return new ExtensionType(declaration,
interpretParsedNullability(node.parsedNullability), kernelArguments);
} else {
throw "Unhandled ${declaration.runtimeType}";
}
@ -380,7 +383,7 @@ class _KernelFromParsedType implements Visitor<Node, TypeParserEnvironment> {
..addAll(parameters);
{
TypeParserEnvironment environment = parameterEnvironment.environment;
InterfaceType onType =
DartType onType =
node.onType?.accept<Node, TypeParserEnvironment>(this, environment);
ext.onType = onType;
}