1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-08 12:06:26 +00:00

[cfe] Support interface member access on extension types

Change-Id: I53975b71683e119fe6abec72341cdcd814244f58
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/318982
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther 2023-08-09 12:19:39 +00:00 committed by Commit Queue
parent 30201181ce
commit 0769b22b4f
12 changed files with 622 additions and 32 deletions

View File

@ -1025,10 +1025,9 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
} else {
for (DartType implement
in extensionType.extensionTypeDeclaration.implements) {
// TODO(johnniwinther): Handle non-extension type supertypes.
if (implement is ExtensionType) {
ExtensionType supertype =
hierarchyBuilder.getExtensionTypeAsInstanceOf(
ExtensionType supertype = hierarchyBuilder
.getExtensionTypeAsInstanceOfExtensionTypeDeclaration(
extensionType, implement.extensionTypeDeclaration,
isNonNullableByDefault: isNonNullableByDefault)!;
ObjectAccessTarget? target = _findDirectExtensionTypeMember(
@ -1039,6 +1038,23 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
if (target != null) {
return target;
}
} else if (implement is InterfaceType) {
InterfaceType supertype =
hierarchyBuilder.getExtensionTypeAsInstanceOfClass(
extensionType, implement.classNode,
isNonNullableByDefault: isNonNullableByDefault)!;
Member? interfaceMember = _getInterfaceMember(
supertype.classNode, name, isSetter, fileOffset);
if (interfaceMember != null) {
return new ObjectAccessTarget.interfaceMember(
receiverType, interfaceMember,
isPotentiallyNullable: isReceiverTypePotentiallyNullable);
}
} else {
assert(
false,
"Unexpected supertype $implement extension type declaration of "
"$extensionType.");
}
}
return null;

View File

@ -0,0 +1,62 @@
// 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 b
// BSD-style license that can be found in the LICENSE file.
class A {
int field = 42;
int method() => field;
int get getter => field;
void set setter(int value) {
field = value;
}
}
class B extends A {}
extension type E(B it) implements B {}
extension type F(B it) implements E {}
main() {
B b = B();
E e = E(b);
F f = F(b);
expect(42, b.field);
expect(42, e.field);
expect(42, f.field);
b.field = 87;
expect(87, b.method());
expect(87, e.method());
expect(87, f.method());
b.setter = 123;
expect(123, b.getter);
expect(123, e.getter);
expect(123, f.getter);
e.setter = 87;
expect(87, b.field);
expect(87, e.field);
expect(87, f.field);
e.field = 42;
expect(42, b.getter);
expect(42, e.getter);
expect(42, f.getter);
f.field = 87;
expect(87, b.field);
expect(87, e.field);
expect(87, f.field);
f.setter = 123;
expect(123, b.method());
expect(123, e.method());
expect(123, f.method());
}
expect(expected, actual) {
if (expected != actual) throw 'Expected $expected, actual $actual';
}

View File

@ -0,0 +1,78 @@
library;
import self as self;
import "dart:core" as core;
class A extends core::Object {
field core::int field = 42;
synthetic constructor •() → self::A
: super core::Object::•()
;
method method() → core::int
return this.{self::A::field}{core::int};
get getter() → core::int
return this.{self::A::field}{core::int};
set setter(core::int value) → void {
this.{self::A::field} = value;
}
}
class B extends self::A {
synthetic constructor •() → self::B
: super self::A::•()
;
}
extension type E(self::B it) implements self::B {
constructor • = self::E|;
tearoff • = self::E|_#new#tearOff;
}
extension type F(self::B it) implements self::E {
constructor • = self::F|;
tearoff • = self::F|_#new#tearOff;
}
static inline-class-member method E|(dynamic it) → self::E {
lowered final self::E #this = it;
return #this;
}
static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
return self::E|(it);
static inline-class-member method F|(dynamic it) → self::F {
lowered final self::F #this = it;
return #this;
}
static inline-class-member method F|_#new#tearOff(dynamic it) → self::F
return self::F|(it);
static method main() → dynamic {
self::B b = new self::B::•();
self::E e = self::E|(b);
self::F f = self::F|(b);
self::expect(42, b.{self::A::field}{core::int});
self::expect(42, e.{self::A::field}{core::int});
self::expect(42, f.{self::A::field}{core::int});
b.{self::A::field} = 87;
self::expect(87, b.{self::A::method}(){() → core::int});
self::expect(87, e.{self::A::method}(){() → core::int});
self::expect(87, f.{self::A::method}(){() → core::int});
b.{self::A::setter} = 123;
self::expect(123, b.{self::A::getter}{core::int});
self::expect(123, e.{self::A::getter}{core::int});
self::expect(123, f.{self::A::getter}{core::int});
e.{self::A::setter} = 87;
self::expect(87, b.{self::A::field}{core::int});
self::expect(87, e.{self::A::field}{core::int});
self::expect(87, f.{self::A::field}{core::int});
e.{self::A::field} = 42;
self::expect(42, b.{self::A::getter}{core::int});
self::expect(42, e.{self::A::getter}{core::int});
self::expect(42, f.{self::A::getter}{core::int});
f.{self::A::field} = 87;
self::expect(87, b.{self::A::field}{core::int});
self::expect(87, e.{self::A::field}{core::int});
self::expect(87, f.{self::A::field}{core::int});
f.{self::A::setter} = 123;
self::expect(123, b.{self::A::method}(){() → core::int});
self::expect(123, e.{self::A::method}(){() → core::int});
self::expect(123, f.{self::A::method}(){() → core::int});
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}

View File

@ -0,0 +1,78 @@
library;
import self as self;
import "dart:core" as core;
class A extends core::Object {
field core::int field = 42;
synthetic constructor •() → self::A
: super core::Object::•()
;
method method() → core::int
return this.{self::A::field}{core::int};
get getter() → core::int
return this.{self::A::field}{core::int};
set setter(core::int value) → void {
this.{self::A::field} = value;
}
}
class B extends self::A {
synthetic constructor •() → self::B
: super self::A::•()
;
}
extension type E(self::B it) implements self::B {
constructor • = self::E|;
tearoff • = self::E|_#new#tearOff;
}
extension type F(self::B it) implements self::E {
constructor • = self::F|;
tearoff • = self::F|_#new#tearOff;
}
static inline-class-member method E|(dynamic it) → self::E {
lowered final self::E #this = it;
return #this;
}
static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
return self::E|(it);
static inline-class-member method F|(dynamic it) → self::F {
lowered final self::F #this = it;
return #this;
}
static inline-class-member method F|_#new#tearOff(dynamic it) → self::F
return self::F|(it);
static method main() → dynamic {
self::B b = new self::B::•();
self::E e = self::E|(b);
self::F f = self::F|(b);
self::expect(42, b.{self::A::field}{core::int});
self::expect(42, e.{self::A::field}{core::int});
self::expect(42, f.{self::A::field}{core::int});
b.{self::A::field} = 87;
self::expect(87, b.{self::A::method}(){() → core::int});
self::expect(87, e.{self::A::method}(){() → core::int});
self::expect(87, f.{self::A::method}(){() → core::int});
b.{self::A::setter} = 123;
self::expect(123, b.{self::A::getter}{core::int});
self::expect(123, e.{self::A::getter}{core::int});
self::expect(123, f.{self::A::getter}{core::int});
e.{self::A::setter} = 87;
self::expect(87, b.{self::A::field}{core::int});
self::expect(87, e.{self::A::field}{core::int});
self::expect(87, f.{self::A::field}{core::int});
e.{self::A::field} = 42;
self::expect(42, b.{self::A::getter}{core::int});
self::expect(42, e.{self::A::getter}{core::int});
self::expect(42, f.{self::A::getter}{core::int});
f.{self::A::field} = 87;
self::expect(87, b.{self::A::field}{core::int});
self::expect(87, e.{self::A::field}{core::int});
self::expect(87, f.{self::A::field}{core::int});
f.{self::A::setter} = 123;
self::expect(123, b.{self::A::method}(){() → core::int});
self::expect(123, e.{self::A::method}(){() → core::int});
self::expect(123, f.{self::A::method}(){() → core::int});
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}

View File

@ -0,0 +1,10 @@
class A {
int field = 42;
int method() => field;
int get getter => field;
void set setter(int value) {}
}
class B extends A {}
extension type E(B it) implements B {} extension type F(B it) implements E {}
main() {}
expect(expected, actual) {}

View File

@ -0,0 +1,78 @@
library;
import self as self;
import "dart:core" as core;
class A extends core::Object {
field core::int field = 42;
synthetic constructor •() → self::A
: super core::Object::•()
;
method method() → core::int
return this.{self::A::field}{core::int};
get getter() → core::int
return this.{self::A::field}{core::int};
set setter(core::int value) → void {
this.{self::A::field} = value;
}
}
class B extends self::A {
synthetic constructor •() → self::B
: super self::A::•()
;
}
extension type E(self::B it) implements self::B {
constructor • = self::E|;
tearoff • = self::E|_#new#tearOff;
}
extension type F(self::B it) implements self::E {
constructor • = self::F|;
tearoff • = self::F|_#new#tearOff;
}
static inline-class-member method E|(dynamic it) → self::E {
lowered final self::E #this = it;
return #this;
}
static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
return self::E|(it);
static inline-class-member method F|(dynamic it) → self::F {
lowered final self::F #this = it;
return #this;
}
static inline-class-member method F|_#new#tearOff(dynamic it) → self::F
return self::F|(it);
static method main() → dynamic {
self::B b = new self::B::•();
self::E e = self::E|(b);
self::F f = self::F|(b);
self::expect(42, b.{self::A::field}{core::int});
self::expect(42, e.{self::A::field}{core::int});
self::expect(42, f.{self::A::field}{core::int});
b.{self::A::field} = 87;
self::expect(87, b.{self::A::method}(){() → core::int});
self::expect(87, e.{self::A::method}(){() → core::int});
self::expect(87, f.{self::A::method}(){() → core::int});
b.{self::A::setter} = 123;
self::expect(123, b.{self::A::getter}{core::int});
self::expect(123, e.{self::A::getter}{core::int});
self::expect(123, f.{self::A::getter}{core::int});
e.{self::A::setter} = 87;
self::expect(87, b.{self::A::field}{core::int});
self::expect(87, e.{self::A::field}{core::int});
self::expect(87, f.{self::A::field}{core::int});
e.{self::A::field} = 42;
self::expect(42, b.{self::A::getter}{core::int});
self::expect(42, e.{self::A::getter}{core::int});
self::expect(42, f.{self::A::getter}{core::int});
f.{self::A::field} = 87;
self::expect(87, b.{self::A::field}{core::int});
self::expect(87, e.{self::A::field}{core::int});
self::expect(87, f.{self::A::field}{core::int});
f.{self::A::setter} = 123;
self::expect(123, b.{self::A::method}(){() → core::int});
self::expect(123, e.{self::A::method}(){() → core::int});
self::expect(123, f.{self::A::method}(){() → core::int});
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}

View File

@ -0,0 +1,78 @@
library;
import self as self;
import "dart:core" as core;
class A extends core::Object {
field core::int field = 42;
synthetic constructor •() → self::A
: super core::Object::•()
;
method method() → core::int
return this.{self::A::field}{core::int};
get getter() → core::int
return this.{self::A::field}{core::int};
set setter(core::int value) → void {
this.{self::A::field} = value;
}
}
class B extends self::A {
synthetic constructor •() → self::B
: super self::A::•()
;
}
extension type E(self::B it) implements self::B {
constructor • = self::E|;
tearoff • = self::E|_#new#tearOff;
}
extension type F(self::B it) implements self::E {
constructor • = self::F|;
tearoff • = self::F|_#new#tearOff;
}
static inline-class-member method E|(dynamic it) → self::E {
lowered final self::E #this = it;
return #this;
}
static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
return self::E|(it);
static inline-class-member method F|(dynamic it) → self::F {
lowered final self::F #this = it;
return #this;
}
static inline-class-member method F|_#new#tearOff(dynamic it) → self::F
return self::F|(it);
static method main() → dynamic {
self::B b = new self::B::•();
self::E e = self::E|(b);
self::F f = self::F|(b);
self::expect(42, b.{self::A::field}{core::int});
self::expect(42, e.{self::A::field}{core::int});
self::expect(42, f.{self::A::field}{core::int});
b.{self::A::field} = 87;
self::expect(87, b.{self::A::method}(){() → core::int});
self::expect(87, e.{self::A::method}(){() → core::int});
self::expect(87, f.{self::A::method}(){() → core::int});
b.{self::A::setter} = 123;
self::expect(123, b.{self::A::getter}{core::int});
self::expect(123, e.{self::A::getter}{core::int});
self::expect(123, f.{self::A::getter}{core::int});
e.{self::A::setter} = 87;
self::expect(87, b.{self::A::field}{core::int});
self::expect(87, e.{self::A::field}{core::int});
self::expect(87, f.{self::A::field}{core::int});
e.{self::A::field} = 42;
self::expect(42, b.{self::A::getter}{core::int});
self::expect(42, e.{self::A::getter}{core::int});
self::expect(42, f.{self::A::getter}{core::int});
f.{self::A::field} = 87;
self::expect(87, b.{self::A::field}{core::int});
self::expect(87, e.{self::A::field}{core::int});
self::expect(87, f.{self::A::field}{core::int});
f.{self::A::setter} = 123;
self::expect(123, b.{self::A::method}(){() → core::int});
self::expect(123, e.{self::A::method}(){() → core::int});
self::expect(123, f.{self::A::method}(){() → core::int});
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}

View File

@ -0,0 +1,39 @@
library;
import self as self;
import "dart:core" as core;
class A extends core::Object {
field core::int field;
synthetic constructor •() → self::A
;
method method() → core::int
;
get getter() → core::int
;
set setter(core::int value) → void
;
}
class B extends self::A {
synthetic constructor •() → self::B
;
}
extension type E(self::B it) implements self::B {
constructor • = self::E|;
tearoff • = self::E|_#new#tearOff;
}
extension type F(self::B it) implements self::E {
constructor • = self::F|;
tearoff • = self::F|_#new#tearOff;
}
static inline-class-member method E|(dynamic it) → self::E
;
static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
return self::E|(it);
static inline-class-member method F|(dynamic it) → self::F
;
static inline-class-member method F|_#new#tearOff(dynamic it) → self::F
return self::F|(it);
static method main() → dynamic
;
static method expect(dynamic expected, dynamic actual) → dynamic
;

View File

@ -0,0 +1,78 @@
library;
import self as self;
import "dart:core" as core;
class A extends core::Object {
field core::int field = 42;
synthetic constructor •() → self::A
: super core::Object::•()
;
method method() → core::int
return this.{self::A::field}{core::int};
get getter() → core::int
return this.{self::A::field}{core::int};
set setter(core::int value) → void {
this.{self::A::field} = value;
}
}
class B extends self::A {
synthetic constructor •() → self::B
: super self::A::•()
;
}
extension type E(self::B it) implements self::B {
constructor • = self::E|;
tearoff • = self::E|_#new#tearOff;
}
extension type F(self::B it) implements self::E {
constructor • = self::F|;
tearoff • = self::F|_#new#tearOff;
}
static inline-class-member method E|(dynamic it) → self::E {
lowered final self::E #this = it;
return #this;
}
static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
return self::E|(it);
static inline-class-member method F|(dynamic it) → self::F {
lowered final self::F #this = it;
return #this;
}
static inline-class-member method F|_#new#tearOff(dynamic it) → self::F
return self::F|(it);
static method main() → dynamic {
self::B b = new self::B::•();
self::E e = self::E|(b);
self::F f = self::F|(b);
self::expect(42, b.{self::A::field}{core::int});
self::expect(42, e.{self::A::field}{core::int});
self::expect(42, f.{self::A::field}{core::int});
b.{self::A::field} = 87;
self::expect(87, b.{self::A::method}(){() → core::int});
self::expect(87, e.{self::A::method}(){() → core::int});
self::expect(87, f.{self::A::method}(){() → core::int});
b.{self::A::setter} = 123;
self::expect(123, b.{self::A::getter}{core::int});
self::expect(123, e.{self::A::getter}{core::int});
self::expect(123, f.{self::A::getter}{core::int});
e.{self::A::setter} = 87;
self::expect(87, b.{self::A::field}{core::int});
self::expect(87, e.{self::A::field}{core::int});
self::expect(87, f.{self::A::field}{core::int});
e.{self::A::field} = 42;
self::expect(42, b.{self::A::getter}{core::int});
self::expect(42, e.{self::A::getter}{core::int});
self::expect(42, f.{self::A::getter}{core::int});
f.{self::A::field} = 87;
self::expect(87, b.{self::A::field}{core::int});
self::expect(87, e.{self::A::field}{core::int});
self::expect(87, f.{self::A::field}{core::int});
f.{self::A::setter} = 123;
self::expect(123, b.{self::A::method}(){() → core::int});
self::expect(123, e.{self::A::method}(){() → core::int});
self::expect(123, f.{self::A::method}(){() → core::int});
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}

View File

@ -124,6 +124,7 @@ general/type_variable_in_static_context: FormatterCrash
general/var_as_type_name: FormatterCrash
inline_class/inline_class_declaration: FormatterCrash
inline_class/issue52667: FormatterCrash
inline_class/extension_types/access_non_extension_type_members: FormatterCrash
inline_class/extension_types/annotations: FormatterCrash
inline_class/extension_types/const_constructor: FormatterCrash
inline_class/extension_types/constructor_access: FormatterCrash

View File

@ -42,17 +42,23 @@ abstract class ClassHierarchyBase {
List<DartType>? getTypeArgumentsAsInstanceOf(
InterfaceType type, Class superclass);
/// Returns the instantiation of [superclass] that is implemented by [type],
/// or `null` if [type] does not implement [superclass] at all.
ExtensionType? getExtensionTypeAsInstanceOf(
ExtensionType type, ExtensionTypeDeclaration superclass,
/// Returns the instantiation of [superDeclaration] that is implemented by
/// [type], or `null` if [type] does not implement [superDeclaration] at all.
ExtensionType? getExtensionTypeAsInstanceOfExtensionTypeDeclaration(
ExtensionType type, ExtensionTypeDeclaration superDeclaration,
{required bool isNonNullableByDefault});
/// Returns the type arguments of the instantiation of [superclass] that is
/// implemented by [type], or `null` if [type] does not implement [superclass]
/// at all.
/// Returns the instantiation of [superclass] that is implemented by [type],
/// or `null` if [type] does not implement [superclass] at all.
InterfaceType? getExtensionTypeAsInstanceOfClass(
ExtensionType type, Class superclass,
{required bool isNonNullableByDefault});
/// Returns the type arguments of the instantiation of [superDeclaration] that
/// is implemented by [type], or `null` if [type] does not implement
/// [superDeclaration] at all.
List<DartType>? getExtensionTypeArgumentsAsInstanceOf(
ExtensionType type, ExtensionTypeDeclaration superclass);
ExtensionType type, ExtensionTypeDeclaration superDeclaration);
/// True if [subtype] inherits from [superclass] though zero or more
/// `extends`, `with`, and `implements` relationships.
@ -78,26 +84,26 @@ abstract class ClassHierarchyBase {
{required bool isNonNullableByDefault});
}
mixin ClassHierarchyExtensionTypeMixin {
CoreTypes get coreTypes;
ExtensionType? getExtensionTypeDeclarationAsInstanceOf(
ExtensionTypeDeclaration subclass, ExtensionTypeDeclaration superclass,
{required bool isNonNullableByDefault}) {
mixin ClassHierarchyExtensionTypeMixin implements ClassHierarchyBase {
ExtensionType?
getExtensionTypeDeclarationAsInstanceOfExtensionTypeDeclaration(
ExtensionTypeDeclaration subDeclaration,
ExtensionTypeDeclaration superDeclaration,
{required bool isNonNullableByDefault}) {
// TODO(johnniwinther): Improve lookup performance.
if (identical(subclass, superclass)) {
if (identical(subDeclaration, superDeclaration)) {
return coreTypes.thisExtensionType(
subclass,
subDeclaration,
isNonNullableByDefault
? Nullability.nonNullable
: Nullability.legacy);
}
for (DartType implement in subclass.implements) {
// TODO(johnniwinther): Handle non-extension type supertypes.
for (DartType implement in subDeclaration.implements) {
if (implement is ExtensionType) {
ExtensionType? supertype = getExtensionTypeDeclarationAsInstanceOf(
implement.extensionTypeDeclaration, superclass,
isNonNullableByDefault: isNonNullableByDefault);
ExtensionType? supertype =
getExtensionTypeDeclarationAsInstanceOfExtensionTypeDeclaration(
implement.extensionTypeDeclaration, superDeclaration,
isNonNullableByDefault: isNonNullableByDefault);
if (supertype != null) {
if (implement.typeArguments.isNotEmpty) {
supertype = Substitution.fromExtensionType(implement)
@ -105,17 +111,63 @@ mixin ClassHierarchyExtensionTypeMixin {
}
return supertype;
}
} else if (implement is InterfaceType) {
// Extension type declarations cannot be implemented through classes.
} else {
assert(
false,
"Unexpected supertype $implement extension type declaration of "
"$subDeclaration.");
}
}
return null;
}
ExtensionType? getExtensionTypeAsInstanceOf(
InterfaceType? getExtensionTypeDeclarationAsInstanceOfClass(
ExtensionTypeDeclaration subDeclaration, Class superclass,
{required bool isNonNullableByDefault}) {
// TODO(johnniwinther): Improve lookup performance.
for (DartType implement in subDeclaration.implements) {
if (implement is ExtensionType) {
InterfaceType? supertype = getExtensionTypeDeclarationAsInstanceOfClass(
implement.extensionTypeDeclaration, superclass,
isNonNullableByDefault: isNonNullableByDefault);
if (supertype != null) {
if (implement.typeArguments.isNotEmpty) {
supertype = Substitution.fromExtensionType(implement)
.substituteType(supertype) as InterfaceType;
}
return supertype;
}
} else if (implement is InterfaceType) {
Supertype? supertype =
getClassAsInstanceOf(implement.classNode, superclass);
if (supertype != null) {
if (implement.typeArguments.isNotEmpty) {
supertype = Substitution.fromInterfaceType(implement)
.substituteSupertype(supertype);
}
return new InterfaceType(supertype.classNode, Nullability.nonNullable,
supertype.typeArguments);
}
} else {
assert(
false,
"Unexpected supertype $implement extension type declaration of "
"$subDeclaration.");
}
}
return null;
}
@override
ExtensionType? getExtensionTypeAsInstanceOfExtensionTypeDeclaration(
ExtensionType type, ExtensionTypeDeclaration superclass,
{required bool isNonNullableByDefault}) {
ExtensionType? supertype = getExtensionTypeDeclarationAsInstanceOf(
type.extensionTypeDeclaration, superclass,
isNonNullableByDefault: isNonNullableByDefault);
ExtensionType? supertype =
getExtensionTypeDeclarationAsInstanceOfExtensionTypeDeclaration(
type.extensionTypeDeclaration, superclass,
isNonNullableByDefault: isNonNullableByDefault);
if (supertype != null) {
if (type.typeArguments.isNotEmpty) {
supertype = Substitution.fromExtensionType(type)
@ -126,9 +178,28 @@ mixin ClassHierarchyExtensionTypeMixin {
return null;
}
@override
InterfaceType? getExtensionTypeAsInstanceOfClass(
ExtensionType type, Class superclass,
{required bool isNonNullableByDefault}) {
InterfaceType? supertype = getExtensionTypeDeclarationAsInstanceOfClass(
type.extensionTypeDeclaration, superclass,
isNonNullableByDefault: isNonNullableByDefault);
if (supertype != null) {
if (type.typeArguments.isNotEmpty) {
supertype = Substitution.fromExtensionType(type)
.substituteType(supertype) as InterfaceType;
}
return supertype;
}
return null;
}
@override
List<DartType>? getExtensionTypeArgumentsAsInstanceOf(
ExtensionType type, ExtensionTypeDeclaration superclass) {
return getExtensionTypeAsInstanceOf(type, superclass,
return getExtensionTypeAsInstanceOfExtensionTypeDeclaration(
type, superclass,
isNonNullableByDefault: true)
?.typeArguments;
}

View File

@ -1032,9 +1032,10 @@ mixin StandardBounds {
supertypes.add(type);
for (DartType implemented in type.extensionTypeDeclaration.implements) {
if (implemented is ExtensionType) {
ExtensionType supertype = hierarchy.getExtensionTypeAsInstanceOf(
type, implemented.extensionTypeDeclaration,
isNonNullableByDefault: isNonNullableByDefault)!;
ExtensionType supertype =
hierarchy.getExtensionTypeAsInstanceOfExtensionTypeDeclaration(
type, implemented.extensionTypeDeclaration,
isNonNullableByDefault: isNonNullableByDefault)!;
computeSuperTypes(supertype, supertypes);
}
}