Skip to content

Commit 155e055

Browse files
authored
Fixes #2428. Add call member tests for extension types (#2438)
Add `call()` method tests for extension types
1 parent 18c300e commit 155e055

6 files changed

+458
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion Consider an invocation of the extension type member m on the
6+
/// receiver expression e according to the extension type declaration V with
7+
/// actual type arguments T1, ..., Ts. If the invocation includes an actual
8+
/// argument part (possibly including some actual type arguments) then call it
9+
/// args. If the invocation omits args, but includes a list of actual type
10+
/// arguments then call them typeArgs. Assume that V declares the type variables
11+
/// X1, ..., Xs
12+
/// ...
13+
/// Let Dm be the unique declaration named m that V has.
14+
///
15+
/// Evaluation of this invocation proceeds by evaluating e to an object o.
16+
/// ...
17+
/// Otherwise, if args is omitted and Dm is a method, the invocation evaluates
18+
/// to a closurization of Dm where this and the name of the representation are
19+
/// bound as with the getter invocation, and the type variables of V are bound
20+
/// to the actual values of T1, .. Ts. The operator == of the closurization
21+
/// returns true if and only if the operand is the same object.
22+
///
23+
/// @description Check implicit tear-off of a `call` member
24+
/// @author [email protected]
25+
26+
// SharedOptions=--enable-experiment=inline-class
27+
28+
import "../../Utils/expect.dart";
29+
30+
class C {
31+
String call() => "call from C";
32+
}
33+
34+
extension type ET1(Function it) {
35+
String call() => "call from ET1";
36+
}
37+
38+
extension type ET2(Function it) implements Object {
39+
String call() => "call from ET2";
40+
}
41+
42+
extension type ET3(Function it) {
43+
String call() => it.call();
44+
}
45+
46+
String foo() => "call from foo()";
47+
48+
Function get functionGetter1 => ET1(C());
49+
50+
Function get functionGetter2 => ET2(C());
51+
52+
Function get functionGetter3 => ET3(C());
53+
54+
Function get functionGetter4 => ET3(foo);
55+
56+
void main() {
57+
Expect.equals("call from ET1", functionGetter1());
58+
Expect.equals("call from ET2", functionGetter2());
59+
Expect.equals("call from C", functionGetter3());
60+
Expect.equals("call from foo()", functionGetter4());
61+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion Consider an invocation of the extension type member m on the
6+
/// receiver expression e according to the extension type declaration V with
7+
/// actual type arguments T1, ..., Ts. If the invocation includes an actual
8+
/// argument part (possibly including some actual type arguments) then call it
9+
/// args. If the invocation omits args, but includes a list of actual type
10+
/// arguments then call them typeArgs. Assume that V declares the type variables
11+
/// X1, ..., Xs
12+
/// ...
13+
/// Let Dm be the unique declaration named m that V has.
14+
///
15+
/// Evaluation of this invocation proceeds by evaluating e to an object o.
16+
/// ...
17+
/// Otherwise, if args is omitted and Dm is a method, the invocation evaluates
18+
/// to a closurization of Dm where this and the name of the representation are
19+
/// bound as with the getter invocation, and the type variables of V are bound
20+
/// to the actual values of T1, .. Ts. The operator == of the closurization
21+
/// returns true if and only if the operand is the same object.
22+
///
23+
/// @description Check invocation of an extension type `call` member
24+
/// @author [email protected]
25+
26+
// SharedOptions=--enable-experiment=inline-class
27+
28+
import "../../Utils/expect.dart";
29+
30+
class C {
31+
String call() => "call from C";
32+
}
33+
34+
extension type ET1(C _) implements C {}
35+
36+
extension type ET2(int _) {
37+
String call() => "call from ET2";
38+
}
39+
40+
main() {
41+
ET1 e1 = ET1(C());
42+
ET2 e2 = ET2(0);
43+
44+
Expect.equals("call from C", e1());
45+
Expect.equals("call from ET2", e2());
46+
Expect.equals("call from C", e1.call());
47+
Expect.equals("call from ET2", e2.call());
48+
Expect.equals("call from C", (e1.call)());
49+
Expect.equals("call from ET2", (e2.call)());
50+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion Consider an invocation of the extension type member m on the
6+
/// receiver expression e according to the extension type declaration V with
7+
/// actual type arguments T1, ..., Ts. If the invocation includes an actual
8+
/// argument part (possibly including some actual type arguments) then call it
9+
/// args. If the invocation omits args, but includes a list of actual type
10+
/// arguments then call them typeArgs. Assume that V declares the type variables
11+
/// X1, ..., Xs
12+
/// ...
13+
/// Let Dm be the unique declaration named m that V has.
14+
///
15+
/// Evaluation of this invocation proceeds by evaluating e to an object o.
16+
/// ...
17+
/// Otherwise, if args is omitted and Dm is a method, the invocation evaluates
18+
/// to a closurization of Dm where this and the name of the representation are
19+
/// bound as with the getter invocation, and the type variables of V are bound
20+
/// to the actual values of T1, .. Ts. The operator == of the closurization
21+
/// returns true if and only if the operand is the same object.
22+
///
23+
/// @description Check that if an extension type has `call()` member then it can
24+
/// be assigned to the type `Function`
25+
/// @author [email protected]
26+
27+
// SharedOptions=--enable-experiment=inline-class
28+
29+
import "../../Utils/expect.dart";
30+
31+
class C {
32+
String call() => "call from C";
33+
}
34+
35+
extension type ET1(C _) implements C {}
36+
37+
extension type ET2(int _) {
38+
String call() => "call from ET2";
39+
}
40+
41+
main() {
42+
ET1 e1 = ET1(C());
43+
ET2 e2 = ET2(0);
44+
45+
Function f1 = e1;
46+
Function f2 = e2;
47+
Function f3 = e1.call;
48+
Function f4 = e2.call;
49+
50+
Expect.equals("call from C", f1());
51+
Expect.equals("call from ET2", f2());
52+
Expect.equals("call from C", f3());
53+
Expect.equals("call from ET2", f4());
54+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion Assume that DV is an extension type declaration named Name, and
6+
/// V1 occurs as one of the <type>s in the <interfaces> of DV. In this case we
7+
/// say that V1 is a superinterface of DV.
8+
/// ...
9+
/// Assume that DV is an extension type declaration named Name, and the type V1,
10+
/// declared by DV1, is a superinterface of DV (V1 could be an extension type or
11+
/// a non-extension type). Let m be the name of a member of V1. If DV also
12+
/// declares a member named m then the latter may be considered similar to a
13+
/// declaration that "overrides" the former. However, it should be noted that
14+
/// extension type method invocation is resolved statically, and hence there is
15+
/// no override relationship among the two in the traditional object-oriented
16+
/// sense (that is, it will never occur that the statically known declaration is
17+
/// the member of V1, and the member invoked at run time is the one in DV). A
18+
/// receiver with static type V1 will invoke the declaration in DV1, and a
19+
/// receiver with a static type which is a reference to DV (like Name or
20+
/// Name<...>) will invoke the one in DV.
21+
///
22+
/// Hence, we use a different word to describe the relationship between a member
23+
/// named m of a superinterface, and a member named m which is declared by the
24+
/// subinterface: We say that the latter redeclares the former.
25+
///
26+
/// In particular, if two different declarations of m are inherited from two
27+
/// superinterfaces then the subinterface can resolve the conflict by
28+
/// redeclaring m.
29+
///
30+
/// There is no notion of having a 'correct override relation' here. With
31+
/// extension types, any member signature can redeclare any other member
32+
/// signature with the same name, including the case where a method is
33+
/// redeclared by a getter, or vice versa.
34+
///
35+
/// @description Checks that a `call` member can be redeclared as any other
36+
/// member, and also that an extension type member named `call` can coexist with
37+
/// a member named `call` in the interface of the representation type.
38+
/// @author [email protected]
39+
40+
// SharedOptions=--enable-experiment=inline-class
41+
42+
import '../../Utils/expect.dart';
43+
44+
class C1 {
45+
String call() => "call from C1";
46+
}
47+
48+
class C2 {
49+
String get call => "call from C2";
50+
}
51+
52+
class C3 {
53+
void set call(String _) {}
54+
}
55+
56+
extension type ET1(C1 c) {
57+
String call() => "call from ET1";
58+
}
59+
60+
extension type ET2(C2 c) {
61+
String call() => "call from ET2";
62+
}
63+
64+
extension type ET3(C3 c) {
65+
String call() => "call from ET3";
66+
}
67+
68+
extension type ET4(C1 c) implements C1 {
69+
String call() => "call from ET4";
70+
}
71+
72+
extension type ET5(C2 c) implements C2 {
73+
String call() => "call from ET5";
74+
}
75+
76+
extension type ET6(C3 c) implements C3 {
77+
String call() => "call from ET6";
78+
}
79+
80+
main() {
81+
Expect.equals("call from ET1", ET1(C1())());
82+
Expect.equals("call from ET1", ET1(C1()).call());
83+
Expect.equals("call from C1", ET1(C1()).c());
84+
Expect.equals("call from ET2", ET2(C2())());
85+
Expect.equals("call from ET2", ET2(C2()).call());
86+
Expect.equals("call from C2", ET2(C2()).c.call);
87+
Expect.equals("call from ET3", ET3(C3())());
88+
Expect.equals("call from ET3", ET3(C3()).call());
89+
ET3(C3()).c.call = "x";
90+
Expect.equals("call from ET4", ET4(C1())());
91+
Expect.equals("call from ET4", ET4(C1()).call());
92+
Expect.equals("call from C1", ET4(C1()).c());
93+
Expect.equals("call from ET5", ET5(C2())());
94+
Expect.equals("call from ET5", ET5(C2()).call());
95+
Expect.equals("call from C2", ET5(C2()).c.call);
96+
Expect.equals("call from ET6", ET6(C3())());
97+
Expect.equals("call from ET6", ET6(C3()).call());
98+
ET6(C3()).c.call = "x";
99+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion Assume that DV is an extension type declaration named Name, and
6+
/// V1 occurs as one of the <type>s in the <interfaces> of DV. In this case we
7+
/// say that V1 is a superinterface of DV.
8+
/// ...
9+
/// Assume that DV is an extension type declaration named Name, and the type V1,
10+
/// declared by DV1, is a superinterface of DV (V1 could be an extension type or
11+
/// a non-extension type). Let m be the name of a member of V1. If DV also
12+
/// declares a member named m then the latter may be considered similar to a
13+
/// declaration that "overrides" the former. However, it should be noted that
14+
/// extension type method invocation is resolved statically, and hence there is
15+
/// no override relationship among the two in the traditional object-oriented
16+
/// sense (that is, it will never occur that the statically known declaration is
17+
/// the member of V1, and the member invoked at run time is the one in DV). A
18+
/// receiver with static type V1 will invoke the declaration in DV1, and a
19+
/// receiver with a static type which is a reference to DV (like Name or
20+
/// Name<...>) will invoke the one in DV.
21+
///
22+
/// Hence, we use a different word to describe the relationship between a member
23+
/// named m of a superinterface, and a member named m which is declared by the
24+
/// subinterface: We say that the latter redeclares the former.
25+
///
26+
/// In particular, if two different declarations of m are inherited from two
27+
/// superinterfaces then the subinterface can resolve the conflict by
28+
/// redeclaring m.
29+
///
30+
/// There is no notion of having a 'correct override relation' here. With
31+
/// extension types, any member signature can redeclare any other member
32+
/// signature with the same name, including the case where a method is
33+
/// redeclared by a getter, or vice versa.
34+
///
35+
/// @description Checks that a `call` member can be redeclared as any other
36+
/// member, and it can coexist with a member named `call` in the interface of
37+
/// the representation type.
38+
/// @author [email protected]
39+
40+
// SharedOptions=--enable-experiment=inline-class
41+
42+
import '../../Utils/expect.dart';
43+
44+
class C1 {
45+
String call() => "call from C1";
46+
}
47+
48+
class C2 {
49+
String get call => "call from C2";
50+
}
51+
52+
class C3 {
53+
void set call(String _) {}
54+
}
55+
56+
extension type ET1(C1 c) {
57+
String get call => "call from ET1";
58+
}
59+
60+
extension type ET2(C2 c) {
61+
String get call => "call from ET2";
62+
}
63+
64+
extension type ET3(C3 c) {
65+
String get call => "call from ET3";
66+
}
67+
68+
extension type ET4(C1 c) implements C1 {
69+
String get call => "call from ET4";
70+
}
71+
72+
extension type ET5(C2 c) implements C2 {
73+
String get call => "call from ET5";
74+
}
75+
76+
extension type ET6(C3 c) implements C3 {
77+
String get call => "call from ET6";
78+
}
79+
80+
main() {
81+
Expect.equals("call from ET1", ET1(C1()).call);
82+
Expect.equals("call from ET2", ET2(C2()).call);
83+
Expect.equals("call from ET3", ET3(C3()).call);
84+
Expect.equals("call from ET4", ET4(C1()).call);
85+
Expect.equals("call from ET5", ET5(C2()).call);
86+
Expect.equals("call from ET6", ET6(C3()).call);
87+
}

0 commit comments

Comments
 (0)