Skip to content

Commit 8002eb4

Browse files
authored
#2313. [Extension types] Add nullability tests (#2324)
Add nullability tests
1 parent 75b0584 commit 8002eb4

7 files changed

+287
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 Let V be an extension type of the form Name<T1, .. Ts>, and let R
6+
/// be the corresponding instantiated representation type. If R is non-nullable
7+
/// then V is a proper subtype of Object, and V is non-nullable. Otherwise, V is
8+
/// a proper subtype of Object?, and V is potentially nullable.
9+
///
10+
/// @description Checks that an extension type is not-nullable even if its
11+
/// representation type is nullable
12+
/// @author [email protected]
13+
14+
// SharedOptions=--enable-experiment=inline-class
15+
16+
import "dart:async" show FutureOr;
17+
18+
extension type ET1(int? _) {}
19+
20+
extension type ET2(Null _) {}
21+
22+
extension type ET3(dynamic _) {}
23+
24+
extension type ET4(void _) {}
25+
26+
extension type ET5(FutureOr<Null> _) {}
27+
28+
main() {
29+
ET1 et11 = null;
30+
// ^^^^
31+
// [analyzer] unspecified
32+
// [cfe] unspecified
33+
ET1? et12 = null;
34+
35+
ET2 et21 = null;
36+
// ^^^^
37+
// [analyzer] unspecified
38+
// [cfe] unspecified
39+
ET2? et22 = null;
40+
41+
ET3 et31 = null;
42+
// ^^^^
43+
// [analyzer] unspecified
44+
// [cfe] unspecified
45+
ET3? et32 = null;
46+
47+
ET4 et41 = null;
48+
// ^^^^
49+
// [analyzer] unspecified
50+
// [cfe] unspecified
51+
ET4? et42 = null;
52+
53+
ET5 et51 = null;
54+
// ^^^^
55+
// [analyzer] unspecified
56+
// [cfe] unspecified
57+
ET5? et52 = null;
58+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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 Let V be an extension type of the form Name<T1, .. Ts>, and let R
6+
/// be the corresponding instantiated representation type. If R is non-nullable
7+
/// then V is a proper subtype of Object, and V is non-nullable. Otherwise, V is
8+
/// a proper subtype of Object?, and V is potentially nullable.
9+
///
10+
/// @description Checks that null can be assigned to an extension type at run
11+
/// time if its representation type is nullable
12+
/// @author [email protected]
13+
14+
// SharedOptions=--enable-experiment=inline-class
15+
16+
import "dart:async" show FutureOr;
17+
import "../../Utils/expect.dart";
18+
19+
extension type ET1(int? _) {}
20+
21+
extension type ET2(Null _) {}
22+
23+
extension type ET3(dynamic _) {}
24+
25+
extension type ET4(void _) {}
26+
27+
extension type ET5(FutureOr<Null> _) {}
28+
29+
main() {
30+
ET1 et1 = null as dynamic;
31+
Expect.isNull(et1);
32+
ET2 et2 = null as dynamic;
33+
Expect.isNull(et2);
34+
ET3 et3 = null as dynamic;
35+
Expect.isNull(et3);
36+
ET4 et4 = null as dynamic;
37+
Expect.isNull(et4);
38+
ET5 et5 = null as dynamic;
39+
Expect.isNull(et5);
40+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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 Let V be an extension type of the form Name<T1, .. Ts>, and let R
6+
/// be the corresponding instantiated representation type. If R is non-nullable
7+
/// then V is a proper subtype of Object, and V is non-nullable. Otherwise, V is
8+
/// a proper subtype of Object?, and V is potentially nullable.
9+
///
10+
/// @description Checks that null can be assigned to an extension type at run
11+
/// time if its representation type is nullable
12+
/// @author [email protected]
13+
14+
// SharedOptions=--enable-experiment=inline-class
15+
16+
import "dart:async" show FutureOr;
17+
import "../../Utils/expect.dart";
18+
19+
typedef VoidAlias = void;
20+
21+
extension type ET1<T extends int?>(T _) {}
22+
23+
extension type ET2<T extends Null>(T _) {}
24+
25+
extension type ET3<T extends dynamic>(T _) {}
26+
27+
extension type ET4<T extends FutureOr<Null>>(T _) {}
28+
29+
extension type ET5<T extends VoidAlias>(T _) {}
30+
31+
main() {
32+
ET1 et1 = null as dynamic;
33+
Expect.isNull(et1);
34+
ET2 et2 = null as dynamic;
35+
Expect.isNull(et2);
36+
ET3 et3 = null as dynamic;
37+
Expect.isNull(et3);
38+
ET4 et4 = null as dynamic;
39+
Expect.isNull(et4);
40+
ET5 et5 = null as dynamic;
41+
Expect.isNull(et5);
42+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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 Let V be an extension type of the form Name<T1, .. Ts>, and let R
6+
/// be the corresponding instantiated representation type. If R is non-nullable
7+
/// then V is a proper subtype of Object, and V is non-nullable. Otherwise, V is
8+
/// a proper subtype of Object?, and V is potentially nullable.
9+
///
10+
/// @description Checks that a warning is produced depending of the
11+
/// representation type when an extension type is checked by `??` operator
12+
/// @author [email protected]
13+
/// @issue 53822
14+
15+
// SharedOptions=--enable-experiment=inline-class
16+
17+
extension type ET1<T>(T _) {
18+
void test() {
19+
this ?? print("No warning here!");
20+
}
21+
}
22+
23+
extension type ET2<T extends Object>(T _) {
24+
void test() {
25+
this ?? print("Expect a warning here!");
26+
// ^^
27+
// [analyzer] unspecified
28+
// [cfe] unspecified
29+
}
30+
}
31+
32+
main() {
33+
ET1(42).test();
34+
ET1(null).test();
35+
ET1<int?>(42).test();
36+
ET2(42).test();
37+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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 Let DV be an extension type declaration named Name with type
6+
/// parameters X1 extends B1, .. Xs extends Bs. Assume that the representation
7+
/// declaration of DV is (R id)
8+
///
9+
/// We then say that the declared representation type of Name is R, and the
10+
/// instantiated representation type corresponding to Name<T1,.. Ts> is
11+
/// [T1/X1, .. Ts/Xs]R.
12+
/// ...
13+
/// Let V be an extension type of the form Name<T1, .. Ts>, and let R be the
14+
/// corresponding instantiated representation type. If R is non-nullable then V
15+
/// is a proper subtype of Object, and V is non-nullable. Otherwise, V is a
16+
/// proper subtype of Object?, and V is potentially nullable.
17+
///
18+
/// @description Checks that it is not an error to call a member of an extension
19+
/// type with a nullable representation type
20+
/// @author [email protected]
21+
/// @issue 53822
22+
23+
// SharedOptions=--enable-experiment=inline-class
24+
25+
extension type ET1(int? _) {
26+
foo() {}
27+
}
28+
29+
extension type ET2<T>(T _) {
30+
foo() {}
31+
}
32+
33+
main() {
34+
ET1(42).foo();
35+
ET2<int?>(42).foo();
36+
ET2<Null>(null).foo();
37+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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 A rule for <extensionTypeDeclaration> is added to the grammar,
6+
/// along with some rules for elements used in extension type declarations:
7+
///
8+
/// <extensionTypeDeclaration> ::=
9+
/// 'extension' 'type' 'const'? <typeIdentifier> <typeParameters>?
10+
/// <representationDeclaration> <interfaces>?
11+
/// '{'
12+
/// (<metadata> <extensionTypeMemberDeclaration>)*
13+
/// '}'
14+
///
15+
/// <representationDeclaration> ::=
16+
/// ('.' <identifierOrNew>)? '(' <metadata> <type> <identifier> ')'
17+
///
18+
/// <identifierOrNew> ::= <identifier> | 'new'
19+
///
20+
/// <extensionTypeMemberDeclaration> ::= <classMemberDefinition>
21+
///
22+
/// @description Checks that it is a compile-time error if an extension type
23+
/// declares a type parameter which extends type `void`
24+
/// @author [email protected]
25+
26+
// SharedOptions=--enable-experiment=inline-class
27+
28+
extension type ET1<T extends void>(T id) {}
29+
// ^^^^
30+
// [analyzer] unspecified
31+
// [cfe] unspecified
32+
33+
main() {
34+
print(ET1);
35+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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 A rule for <extensionTypeDeclaration> is added to the grammar,
6+
/// along with some rules for elements used in extension type declarations:
7+
///
8+
/// <extensionTypeDeclaration> ::=
9+
/// 'extension' 'type' 'const'? <typeIdentifier> <typeParameters>?
10+
/// <representationDeclaration> <interfaces>?
11+
/// '{'
12+
/// (<metadata> <extensionTypeMemberDeclaration>)*
13+
/// '}'
14+
///
15+
/// <representationDeclaration> ::=
16+
/// ('.' <identifierOrNew>)? '(' <metadata> <type> <identifier> ')'
17+
///
18+
/// <identifierOrNew> ::= <identifier> | 'new'
19+
///
20+
/// <extensionTypeMemberDeclaration> ::= <classMemberDefinition>
21+
///
22+
/// @description Checks that it is not an error if an extension type declares a
23+
/// type parameter which extends an alias of the type `void`
24+
/// @author [email protected]
25+
26+
// SharedOptions=--enable-experiment=inline-class
27+
28+
import "../../Utils/expect.dart";
29+
30+
typedef VoidAlias = void;
31+
32+
extension type ET<T extends VoidAlias>(T id) {} // Ok, no error
33+
34+
main() {
35+
Expect.equals(42, ET(42).id);
36+
Expect.equals(null, ET(null).id);
37+
Expect.equals("42", ET<String>("42").id);
38+
}

0 commit comments

Comments
 (0)