Skip to content

Commit

Permalink
#2420. Add cast-pattern tests for extension types (#2458)
Browse files Browse the repository at this point in the history
Add cast-pattern tests for extension types.
  • Loading branch information
sgrekhov authored Jan 29, 2024
1 parent af2ac96 commit 9e9e32c
Show file tree
Hide file tree
Showing 9 changed files with 1,053 additions and 0 deletions.
96 changes: 96 additions & 0 deletions LanguageFeatures/Extension-types/exhaustiveness_cast_A01_t01.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// 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 a
// BSD-style license that can be found in the LICENSE file.

/// @assertion The lifted space union for a pattern with matched value type M is
/// ...
/// Cast pattern:
/// ...
/// Let S be the lifted space union of the cast's subpattern in context C.
/// i. If C is a subset (see below about type subsetting) of S then the result
/// spaces is the lifted space union of M.
/// ii. Otherwise, the result spaces is S plus the lifted space union of Null
/// when C is a non-nullable type, and spaces is S when C is potentially
/// nullable.
///
/// @description Check a lifted space of a cast pattern in case of not a sealed
/// type. Test switch statement which is not exhausted from a float analysis
/// point of view
/// @author sgrekhov22@gmail.com
/// @issue 54460
// SharedOptions=--enable-experiment=inline-class

extension type ObjectET1(Object _) {}
extension type ObjectET2(Object _) implements Object {}

extension type IntET1(int _) {}
extension type IntET2(int _) implements int {}

int test1_1(ObjectET1 obj) {
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
switch (obj) {
case int(isEven: true) as int:
return 1;
case int _:
return 2;
}
}

int test1_2(ObjectET2 obj) {
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
switch (obj) {
case int(isEven: true) as int:
return 1;
case int _:
return 2;
}
}

int test2(Object obj) {
// ^^^^^
// [analyzer] unspecified
// [cfe] unspecified
switch (obj) {
case int(isEven: true) as IntET1:
return 1;
case int _:
return 2;
}
}

int test3_1(ObjectET1 obj) {
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
switch (obj) {
case IntET2(isEven: true) as IntET1:
return 1;
case int _:
return 2;
}
}

int test3_2(ObjectET2 obj) {
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
switch (obj) {
case IntET2(isEven: true) as int:
return 1;
case IntET1 _:
return 2;
}
}

main() {
print(test1_1);
print(test1_2);
print(test2);
print(test3_1);
print(test3_2);
}
89 changes: 89 additions & 0 deletions LanguageFeatures/Extension-types/exhaustiveness_cast_A01_t02.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// 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 a
// BSD-style license that can be found in the LICENSE file.

/// @assertion The lifted space union for a pattern with matched value type M is
/// ...
/// Cast pattern:
/// ...
/// Let S be the lifted space union of the cast's subpattern in context C.
/// i. If C is a subset (see below about type subsetting) of S then the result
/// spaces is the lifted space union of M.
/// ii. Otherwise, the result spaces is S plus the lifted space union of Null
/// when C is a non-nullable type, and spaces is S when C is potentially
/// nullable.
///
/// @description Check a lifted space of a cast pattern in case of not sealed
/// type. Test switch expression
/// @author sgrekhov22@gmail.com
// SharedOptions=--enable-experiment=inline-class

extension type ObjectET1(Object _) {}
extension type ObjectET2(Object _) implements Object {}

extension type IntET1(int _) {}
extension type IntET2(int _) implements int {}

// The corresponding switch statement (can be found in
// `exhaustiveness_cast_A01_t01.dart`) will not complete normally in this case
// (which means that there is no "returns null" error), but this switch
// expression is an error because it can not be recognized as exhaustive. This
// discrepancy is expected. For more details see
// https://github.com/dart-lang/sdk/issues/51986#issuecomment-1864237801
int test1_1(ObjectET1 obj) => switch (obj) {
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
int(isEven: true) as int => 1,
int _ => 2
};

int test1_2(ObjectET2 obj) => switch (obj) {
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
int(isEven: true) as int => 1,
int _ => 2
};

int test2_1(Object obj) => switch (obj) {
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
int(isEven: true) as IntET1 => 1,
int _ => 2
};

int test2_2(Object obj) => switch (obj) {
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
int(isEven: true) as IntET2 => 1,
int _ => 2
};

int test3_1(ObjectET1 obj) => switch (obj) {
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
IntET2(isEven: true) as IntET1 => 1,
int _ => 2
};

int test3_2(ObjectET2 obj) => switch (obj) {
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
IntET2(isEven: true) as int => 1,
IntET1 _ => 2
};

main() {
print(test1_1);
print(test1_2);
print(test2_1);
print(test2_2);
print(test3_1);
print(test3_2);
}
51 changes: 51 additions & 0 deletions LanguageFeatures/Extension-types/exhaustiveness_cast_A01_t03.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// @assertion The lifted space union for a pattern with matched value type M is
/// ...
/// Cast pattern:
/// ...
/// Let S be the lifted space union of the cast's subpattern in context C.
/// i. If C is a subset (see below about type subsetting) of S then the result
/// spaces is the lifted space union of M.
/// ii. Otherwise, the result spaces is S plus the lifted space union of Null
/// when C is a non-nullable type, and spaces is S when C is potentially
/// nullable.
///
/// @description Check a lifted space of a cast pattern in case of not a sealed
/// type. Test switch statement which is exhausted from a float analysis point
/// of view
/// @author sgrekhov22@gmail.com
// SharedOptions=--enable-experiment=inline-class

import "../../Utils/expect.dart";

extension type IntET1(int _) {}
extension type IntET2(int _) implements int {}

int test1(Object obj) {
switch (obj) {
case int(isEven: true) as IntET2:
return 1;
case int _:
return 2;
}
}

int test2(Object obj) {
switch (obj) {
case int(isEven: true) as int:
return 1;
case IntET2 _:
return 2;
}
}

main() {
Expect.equals(2 ,test1(1));
Expect.equals(1 ,test1(2));
Expect.equals(2 ,test2(1));
Expect.equals(1 ,test2(2));
}
129 changes: 129 additions & 0 deletions LanguageFeatures/Extension-types/exhaustiveness_cast_A02_t01.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// 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 a
// BSD-style license that can be found in the LICENSE file.

/// @assertion The lifted space union for a pattern with matched value type M is
/// ...
/// Cast pattern:
/// ...
/// Let S be the lifted space union of the cast's subpattern in context C.
/// i. If C is a subset (see below about type subsetting) of S then the result
/// spaces is the lifted space union of M.
/// ii. Otherwise, the result spaces is S plus the lifted space union of Null
/// when C is a non-nullable type, and spaces is S when C is potentially
/// nullable.
///
/// @description Check a lifted space of a cast pattern in case of a sealed type
/// @author sgrekhov22@gmail.com
sealed class A {
final int field;
A(this.field);
}

class B extends A {
B(int field) : super(field);
}

class C extends A {
C(int field) : super(field);
}

extension type AET1(A _) {}
extension type AET2(A _) implements A {}
extension type BET1(B _) {}
extension type BET2(B _) implements B {}
extension type CET1(C _) {}
extension type CET2(C _) implements C {}

int test1_1(AET1 a) {
switch (a) {
//^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
case C(field: 0) as C:
return 0;
case C _:
return 1;
}
}

int test1_2(AET2 a) {
switch (a) {
//^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
case C(field: 0) as C:
return 0;
case C _:
return 1;
}
}

int test1_3(AET1 a) => switch (a) {
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
C(field: 0) as C => 0,
C _ => 1
};

int test1_4(AET2 a) => switch (a) {
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
C(field: 0) as C => 0,
C _ => 1
};

int test2_1(A a) {
switch (a) {
//^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
case C(field: 0) as CET1:
return 0;
case CET1 _:
return 1;
}
}

int test2_2(A a) {
switch (a) {
//^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
case CET2(field: 0) as CET2:
return 0;
case C _:
return 1;
}
}

int test2_3(A a) => switch (a) {
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
C(field: 0) as CET1 => 0,
C _ => 1
};

int test2_4(A a) => switch (a) {
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
CET2(field: 0) as CET2 => 0,
CET2 _ => 1
};

main() {
test1_1(AET1(C(0)));
test1_2(AET2(C(0)));
test1_3(AET1(C(0)));
test1_4(AET2(C(0)));

test2_1(C(0));
test2_2(C(0));
test2_3(C(0));
test2_4(C(0));
}
Loading

0 comments on commit 9e9e32c

Please sign in to comment.