mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +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 {
|
} else {
|
||||||
for (DartType implement
|
for (DartType implement
|
||||||
in extensionType.extensionTypeDeclaration.implements) {
|
in extensionType.extensionTypeDeclaration.implements) {
|
||||||
// TODO(johnniwinther): Handle non-extension type supertypes.
|
|
||||||
if (implement is ExtensionType) {
|
if (implement is ExtensionType) {
|
||||||
ExtensionType supertype =
|
ExtensionType supertype = hierarchyBuilder
|
||||||
hierarchyBuilder.getExtensionTypeAsInstanceOf(
|
.getExtensionTypeAsInstanceOfExtensionTypeDeclaration(
|
||||||
extensionType, implement.extensionTypeDeclaration,
|
extensionType, implement.extensionTypeDeclaration,
|
||||||
isNonNullableByDefault: isNonNullableByDefault)!;
|
isNonNullableByDefault: isNonNullableByDefault)!;
|
||||||
ObjectAccessTarget? target = _findDirectExtensionTypeMember(
|
ObjectAccessTarget? target = _findDirectExtensionTypeMember(
|
||||||
|
@ -1039,6 +1038,23 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
return target;
|
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;
|
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
|
general/var_as_type_name: FormatterCrash
|
||||||
inline_class/inline_class_declaration: FormatterCrash
|
inline_class/inline_class_declaration: FormatterCrash
|
||||||
inline_class/issue52667: 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/annotations: FormatterCrash
|
||||||
inline_class/extension_types/const_constructor: FormatterCrash
|
inline_class/extension_types/const_constructor: FormatterCrash
|
||||||
inline_class/extension_types/constructor_access: FormatterCrash
|
inline_class/extension_types/constructor_access: FormatterCrash
|
||||||
|
|
|
@ -42,17 +42,23 @@ abstract class ClassHierarchyBase {
|
||||||
List<DartType>? getTypeArgumentsAsInstanceOf(
|
List<DartType>? getTypeArgumentsAsInstanceOf(
|
||||||
InterfaceType type, Class superclass);
|
InterfaceType type, Class superclass);
|
||||||
|
|
||||||
/// Returns the instantiation of [superclass] that is implemented by [type],
|
/// Returns the instantiation of [superDeclaration] that is implemented by
|
||||||
/// or `null` if [type] does not implement [superclass] at all.
|
/// [type], or `null` if [type] does not implement [superDeclaration] at all.
|
||||||
ExtensionType? getExtensionTypeAsInstanceOf(
|
ExtensionType? getExtensionTypeAsInstanceOfExtensionTypeDeclaration(
|
||||||
ExtensionType type, ExtensionTypeDeclaration superclass,
|
ExtensionType type, ExtensionTypeDeclaration superDeclaration,
|
||||||
{required bool isNonNullableByDefault});
|
{required bool isNonNullableByDefault});
|
||||||
|
|
||||||
/// Returns the type arguments of the instantiation of [superclass] that is
|
/// Returns the instantiation of [superclass] that is implemented by [type],
|
||||||
/// implemented by [type], or `null` if [type] does not implement [superclass]
|
/// or `null` if [type] does not implement [superclass] at all.
|
||||||
/// 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(
|
List<DartType>? getExtensionTypeArgumentsAsInstanceOf(
|
||||||
ExtensionType type, ExtensionTypeDeclaration superclass);
|
ExtensionType type, ExtensionTypeDeclaration superDeclaration);
|
||||||
|
|
||||||
/// True if [subtype] inherits from [superclass] though zero or more
|
/// True if [subtype] inherits from [superclass] though zero or more
|
||||||
/// `extends`, `with`, and `implements` relationships.
|
/// `extends`, `with`, and `implements` relationships.
|
||||||
|
@ -78,25 +84,25 @@ abstract class ClassHierarchyBase {
|
||||||
{required bool isNonNullableByDefault});
|
{required bool isNonNullableByDefault});
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin ClassHierarchyExtensionTypeMixin {
|
mixin ClassHierarchyExtensionTypeMixin implements ClassHierarchyBase {
|
||||||
CoreTypes get coreTypes;
|
ExtensionType?
|
||||||
|
getExtensionTypeDeclarationAsInstanceOfExtensionTypeDeclaration(
|
||||||
ExtensionType? getExtensionTypeDeclarationAsInstanceOf(
|
ExtensionTypeDeclaration subDeclaration,
|
||||||
ExtensionTypeDeclaration subclass, ExtensionTypeDeclaration superclass,
|
ExtensionTypeDeclaration superDeclaration,
|
||||||
{required bool isNonNullableByDefault}) {
|
{required bool isNonNullableByDefault}) {
|
||||||
// TODO(johnniwinther): Improve lookup performance.
|
// TODO(johnniwinther): Improve lookup performance.
|
||||||
if (identical(subclass, superclass)) {
|
if (identical(subDeclaration, superDeclaration)) {
|
||||||
return coreTypes.thisExtensionType(
|
return coreTypes.thisExtensionType(
|
||||||
subclass,
|
subDeclaration,
|
||||||
isNonNullableByDefault
|
isNonNullableByDefault
|
||||||
? Nullability.nonNullable
|
? Nullability.nonNullable
|
||||||
: Nullability.legacy);
|
: Nullability.legacy);
|
||||||
}
|
}
|
||||||
for (DartType implement in subclass.implements) {
|
for (DartType implement in subDeclaration.implements) {
|
||||||
// TODO(johnniwinther): Handle non-extension type supertypes.
|
|
||||||
if (implement is ExtensionType) {
|
if (implement is ExtensionType) {
|
||||||
ExtensionType? supertype = getExtensionTypeDeclarationAsInstanceOf(
|
ExtensionType? supertype =
|
||||||
implement.extensionTypeDeclaration, superclass,
|
getExtensionTypeDeclarationAsInstanceOfExtensionTypeDeclaration(
|
||||||
|
implement.extensionTypeDeclaration, superDeclaration,
|
||||||
isNonNullableByDefault: isNonNullableByDefault);
|
isNonNullableByDefault: isNonNullableByDefault);
|
||||||
if (supertype != null) {
|
if (supertype != null) {
|
||||||
if (implement.typeArguments.isNotEmpty) {
|
if (implement.typeArguments.isNotEmpty) {
|
||||||
|
@ -105,15 +111,61 @@ mixin ClassHierarchyExtensionTypeMixin {
|
||||||
}
|
}
|
||||||
return supertype;
|
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;
|
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,
|
ExtensionType type, ExtensionTypeDeclaration superclass,
|
||||||
{required bool isNonNullableByDefault}) {
|
{required bool isNonNullableByDefault}) {
|
||||||
ExtensionType? supertype = getExtensionTypeDeclarationAsInstanceOf(
|
ExtensionType? supertype =
|
||||||
|
getExtensionTypeDeclarationAsInstanceOfExtensionTypeDeclaration(
|
||||||
type.extensionTypeDeclaration, superclass,
|
type.extensionTypeDeclaration, superclass,
|
||||||
isNonNullableByDefault: isNonNullableByDefault);
|
isNonNullableByDefault: isNonNullableByDefault);
|
||||||
if (supertype != null) {
|
if (supertype != null) {
|
||||||
|
@ -126,9 +178,28 @@ mixin ClassHierarchyExtensionTypeMixin {
|
||||||
return null;
|
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(
|
List<DartType>? getExtensionTypeArgumentsAsInstanceOf(
|
||||||
ExtensionType type, ExtensionTypeDeclaration superclass) {
|
ExtensionType type, ExtensionTypeDeclaration superclass) {
|
||||||
return getExtensionTypeAsInstanceOf(type, superclass,
|
return getExtensionTypeAsInstanceOfExtensionTypeDeclaration(
|
||||||
|
type, superclass,
|
||||||
isNonNullableByDefault: true)
|
isNonNullableByDefault: true)
|
||||||
?.typeArguments;
|
?.typeArguments;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1032,7 +1032,8 @@ mixin StandardBounds {
|
||||||
supertypes.add(type);
|
supertypes.add(type);
|
||||||
for (DartType implemented in type.extensionTypeDeclaration.implements) {
|
for (DartType implemented in type.extensionTypeDeclaration.implements) {
|
||||||
if (implemented is ExtensionType) {
|
if (implemented is ExtensionType) {
|
||||||
ExtensionType supertype = hierarchy.getExtensionTypeAsInstanceOf(
|
ExtensionType supertype =
|
||||||
|
hierarchy.getExtensionTypeAsInstanceOfExtensionTypeDeclaration(
|
||||||
type, implemented.extensionTypeDeclaration,
|
type, implemented.extensionTypeDeclaration,
|
||||||
isNonNullableByDefault: isNonNullableByDefault)!;
|
isNonNullableByDefault: isNonNullableByDefault)!;
|
||||||
computeSuperTypes(supertype, supertypes);
|
computeSuperTypes(supertype, supertypes);
|
||||||
|
|
Loading…
Reference in a new issue