mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 13:35:05 +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:
parent
30201181ce
commit
0769b22b4f
|
@ -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;
|
||||
|
|
|
@ -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';
|
||||
}
|
|
@ -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}";
|
||||
}
|
|
@ -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}";
|
||||
}
|
|
@ -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) {}
|
|
@ -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}";
|
||||
}
|
|
@ -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}";
|
||||
}
|
|
@ -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
|
||||
;
|
|
@ -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}";
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue