Skip to content

Commit 19195eb

Browse files
authored
Fixes #2384. Fix not well-bound extension types. Add function-type dynamic test (#2387)
Test bound errors with extension types . Add function-type dynamic test.
1 parent 460758b commit 19195eb

5 files changed

+172
-5
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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 At run time, for a given instance o typed as an extension type V,
6+
/// there is no reification of V associated with o.
7+
///
8+
/// @description Check that an extension type is 'erased' at run time
9+
/// @author [email protected]
10+
11+
// SharedOptions=--enable-experiment=inline-class
12+
13+
import "../../Utils/expect.dart";
14+
15+
extension type ET1(int id) {
16+
int add(int other) => id + other;
17+
}
18+
19+
extension type ET2<T>(T id) {
20+
bool equal(T other) => id == other;
21+
}
22+
23+
main() {
24+
dynamic d1 = ET1(1);
25+
Expect.throws(() {d1.id;});
26+
Expect.throws(() {d1.add(1);});
27+
dynamic d2 = ET2(1);
28+
Expect.throws(() {d2.id;});
29+
Expect.throws(() {d2.equal(1);});
30+
dynamic d3 = ET2<int>(1);
31+
Expect.throws(() {d3.id;});
32+
Expect.throws(() {d3.equal(1);});
33+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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, the following is known: args is included, and Dm is a method. The
18+
/// invocation proceeds to evaluate args to an actual argument list args1. Then
19+
/// it executes the body of Dm in an environment where this and the name of the
20+
/// representation are bound in the same way as in the getter invocation, the
21+
/// type variables of V are bound to the actual values of T1, .. Ts, and the
22+
/// formal parameters of m are bound to args1 in the same way that they would be
23+
/// bound for a normal function call. If the body completes returning an object
24+
/// o2 then the invocation evaluates to o2. If the body throws an object and a
25+
/// stack trace then the invocation completes throwing the same object and stack
26+
/// trace.
27+
///
28+
/// @description Check invocation of a representation type `call` member
29+
/// @author [email protected]
30+
31+
// SharedOptions=--enable-experiment=inline-class
32+
33+
import "../../Utils/expect.dart";
34+
35+
extension type V1<T extends Object Function(num)>(T id) {}
36+
37+
typedef num Foo(Object o);
38+
39+
Foo foo = (Object o) => o as num;
40+
41+
main() {
42+
Expect.equals(42, V1<Foo>(foo).id(42));
43+
Expect.equals(42, V1<Foo>(foo).id.call(42));
44+
dynamic d = V1<Foo>(foo);
45+
Expect.equals(42, d(42));
46+
Expect.equals(42, d.call(42));
47+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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, the following is known: args is included, and Dm is a method. The
18+
/// invocation proceeds to evaluate args to an actual argument list args1. Then
19+
/// it executes the body of Dm in an environment where this and the name of the
20+
/// representation are bound in the same way as in the getter invocation, the
21+
/// type variables of V are bound to the actual values of T1, .. Ts, and the
22+
/// formal parameters of m are bound to args1 in the same way that they would be
23+
/// bound for a normal function call. If the body completes returning an object
24+
/// o2 then the invocation evaluates to o2. If the body throws an object and a
25+
/// stack trace then the invocation completes throwing the same object and stack
26+
/// trace.
27+
///
28+
/// @description Check invocation of an extension type `call` member
29+
/// @author [email protected]
30+
31+
// SharedOptions=--enable-experiment=inline-class
32+
33+
import "../../Utils/expect.dart";
34+
35+
extension type ET1(int id) {
36+
int call(int other) => id + other;
37+
}
38+
39+
extension type ET2<T>(T id) {
40+
T call() => id;
41+
}
42+
43+
main() {
44+
Expect.equals(3, ET1(1).call(2));
45+
Expect.equals(5, ET1(2)(3));
46+
Expect.equals("42", ET2<String>("42").call());
47+
Expect.equals("42", ET2<String>("42")());
48+
}

LanguageFeatures/Extension-types/static_analysis_extension_types_A05_t02.dart

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@
1414
/// regular-bounded.
1515
///
1616
/// @description Checks that it is a compile-time error if the type
17-
/// `V<T1, .. Ts>` is not regular-bounded.
17+
/// `V<T1, .. Ts>` has type bound like V<T extends V<T>> (after extension type
18+
/// erasure it become `extension type V<T extends T>(T id) {}` which is an
19+
/// error)
1820
/// @author [email protected]
21+
/// @issue 54097
1922
2023
// SharedOptions=--enable-experiment=inline-class
2124

2225
extension type V<T extends V<T>>(T id) {}
23-
24-
main() {
25-
List<V> l = [];
26-
// ^
26+
// ^
2727
// [analyzer] unspecified
2828
// [cfe] unspecified
29+
30+
main() {
31+
print(V<Never>);
2932
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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 T1, .. Ts are types, and V resolves to an extension
6+
/// type declaration of the following form:
7+
///
8+
/// extension type V<X1 extends B1, .. Xs extends Bs>(T id) ... {
9+
/// ... // Members.
10+
/// }
11+
/// ...
12+
/// A compile-time error occurs if the type V<T1, .. Tk> provides a wrong number
13+
/// of type arguments to V (when k is different from s), and if it is not
14+
/// regular-bounded.
15+
///
16+
/// @description Checks that it is a compile-time error if an extension type
17+
/// `V<T1, .. Ts>` has any dependency cycles in type bounds
18+
/// @author [email protected]
19+
/// @issue 54097
20+
21+
// SharedOptions=--enable-experiment=inline-class
22+
23+
extension type V1<T extends T>(T id) {}
24+
// ^
25+
// [analyzer] unspecified
26+
// [cfe] unspecified
27+
28+
extension type V2<T1 extends T2, T2 extends T1>(T1 id) {}
29+
// ^
30+
// [analyzer] unspecified
31+
// [cfe] unspecified
32+
33+
main() {
34+
print(V1<Never>);
35+
print(V2<Never, Never>);
36+
}

0 commit comments

Comments
 (0)