Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b74ae33

Browse files
committed
Fix various issues with a generic method test
Fix various issues with language_2/generic_function_bounds_tests, including: - Overly specific expectations on print formats of types - Outdated expectation of contra-variance for generic method bounds Change-Id: I5135a743cc58773af144b2d9e6685667c9be7d41 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/109726 Reviewed-by: Lasse R.H. Nielsen <[email protected]>
1 parent ba72890 commit b74ae33

File tree

1 file changed

+81
-42
lines changed

1 file changed

+81
-42
lines changed

tests/language_2/generic_function_bounds_test.dart

Lines changed: 81 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,74 +5,113 @@
55
import 'dart:math';
66
import 'package:expect/expect.dart';
77

8+
Type getType<T>() => T;
9+
810
void testInstantiateToBounds() {
911
f<T extends num, U extends T>() => [T, U];
1012
g<T extends List<U>, U extends int>() => [T, U];
11-
h<T extends num, U extends T>(T x, U y) => h.runtimeType.toString();
13+
h<T extends U, U extends num>(T x, U y) => [T, U];
1214

15+
// Check that instantiate to bounds creates the correct type arguments
16+
// during dynamic calls.
1317
Expect.listEquals([num, num], (f as dynamic)());
14-
Expect.equals('List<int>|int', (g as dynamic)().join('|'));
15-
Expect.equals('<T extends num, U extends T>(T, U) => String',
16-
(h as dynamic)(null, null));
18+
Expect.listEquals([getType<List<int>>(), int], (g as dynamic)());
19+
Expect.listEquals([num, num], (h as dynamic)(null, null));
1720

21+
// Check that when instantiate to bounds creates a super-bounded type argument
22+
// during a dynamic call, an error is thrown.
1823
i<T extends Iterable<T>>() => null;
1924
j<T extends Iterable<S>, S extends T>() => null;
20-
Expect.throws(
21-
() => (i as dynamic)(), (e) => '$e'.contains('Instantiate to bounds'));
22-
Expect.throws(
23-
() => (j as dynamic)(), (e) => '$e'.contains('Instantiate to bounds'));
25+
Expect.throwsTypeError(() => (i as dynamic)(), "Super bounded type argument");
26+
Expect.throwsTypeError(() => (j as dynamic)(), "Super bounded type argument");
2427
}
2528

2629
void testChecksBound() {
2730
f<T extends num>(T x) => x;
28-
Expect.equals((f as dynamic)(42), 42);
29-
Expect.throws(() => (f as dynamic)('42'));
30-
31-
msg(t1, t2, tf) => Expect.throws(() => (f as dynamic)<Object>(42),
32-
(e) => '$e' == 'type `Object` does not extend `num` of `T');
33-
3431
g<T extends U, U extends num>(T x, U y) => x;
32+
33+
// Check that arguments are checked against the correct types when instantiate
34+
// to bounds produces a type argument during a dynamic call.
35+
Expect.equals((f as dynamic)(42), 42);
3536
Expect.equals((g as dynamic)(42.0, 100), 42.0);
36-
Expect.throws(() => (g as dynamic)('hi', 100));
37-
Expect.throws(() => (g as dynamic)<double, int>(42.0, 100),
38-
(e) => '$e' == 'type `double` does not extend `int` of `T`.');
37+
Expect.throwsTypeError(() => (f as dynamic)('42'), "Argument check");
38+
Expect.throwsTypeError(() => (g as dynamic)('hi', 100), "Argument check");
3939

40-
Expect.throws(() => (g as dynamic)<num, Object>(42.0, 100),
41-
(e) => '$e' == 'type `Object` does not extend `num` of `U`.');
40+
// Check that an actual type argument is checked against the bound during a
41+
// dynamic call.
42+
Expect.equals((f as dynamic)<int>(42), 42);
43+
Expect.equals((g as dynamic)<double, num>(42.0, 100), 42.0);
44+
Expect.throwsTypeError(() => (g as dynamic)<double, int>(42.0, 100),
45+
"Type argument bounds check");
46+
Expect.throwsTypeError(
47+
() => (f as dynamic)<Object>(42), "Type argument bounds check");
48+
Expect.throwsTypeError(() => (g as dynamic)<double, int>(42.0, 100),
49+
"Type argument bounds check");
50+
Expect.throwsTypeError(() => (g as dynamic)<num, Object>(42.0, 100),
51+
"Type argument bounds check");
4252
}
4353

44-
typedef G<U> = T Function<T extends U>(T x);
54+
typedef G<U> = num Function<T extends U>(T x);
4555

46-
void testSubtype() {
47-
f<T extends num>(T x) => x + 2;
56+
typedef F<U> = Object Function<T extends U>(T x);
4857

58+
void testSubtype() {
59+
num f<T extends num>(T x) => x + 2;
4960
dynamic d = f;
50-
Expect.equals(d(40.0), 42.0);
51-
Expect.equals((f as G<int>)(40), 42);
52-
Expect.equals((d as G<int>)(40), 42);
53-
Expect.equals((f as G<double>)(40.0), 42.0);
54-
Expect.equals((d as G<double>)(40.0), 42.0);
55-
56-
d as G<Null>;
57-
Expect.throws(() => d as G);
58-
Expect.throws(() => d as G<Object>);
59-
Expect.throws(() => d as G<String>);
61+
62+
// Check that casting to an equal generic function type works
63+
Expect.equals((f as G<num>)(40), 42);
64+
Expect.equals((d as G<num>)(40), 42);
65+
66+
// Check that casting to a more general generic function type works
67+
Expect.equals((f as F<num>)(40), 42);
68+
Expect.equals((d as F<num>)(40), 42);
69+
70+
// Check that casting to a generic function with more specific bounds fails
71+
Expect.throwsCastError(
72+
() => (f as G<int>), "Generic functions are invariant");
73+
Expect.throwsCastError(
74+
() => (d as G<int>), "Generic functions are invariant");
75+
Expect.throwsCastError(
76+
() => (f as G<double>), "Generic functions are invariant");
77+
Expect.throwsCastError(
78+
() => (d as G<double>), "Generic functions are invariant");
79+
Expect.throwsCastError(
80+
() => (f as G<Null>), "Generic functions are invariant");
81+
Expect.throwsCastError(
82+
() => (d as G<Null>), "Generic functions are invariant");
83+
84+
// Check that casting to a generic function with a more general bound fails
85+
Expect.throwsCastError(
86+
() => (f as G<Object>), "Generic functions are invariant");
87+
Expect.throwsCastError(
88+
() => (d as G<Object>), "Generic functions are invariant");
89+
90+
// Check that casting to a generic function with an unrelated bound fails
91+
Expect.throwsCastError(
92+
() => (f as G<String>), "Generic functions are invariant");
93+
Expect.throwsCastError(
94+
() => (d as G<String>), "Generic functions are invariant");
6095
}
6196

6297
void testToString() {
63-
// TODO(jmesserly): I don't think the cast on `y` should be required.
64-
num f<T extends num, U extends T>(T x, U y) => min(x, y as num);
98+
num f<T extends num, U extends T>(T x, U y) => min(x, y);
6599
num g<T, U>(T x, U y) => max(x as num, y as num);
66100
String h<T, U>(T x, U y) => h.runtimeType.toString();
67-
Expect.equals(
68-
f.runtimeType.toString(), '<T extends num, U extends T>(T, U) => num');
69-
Expect.equals(g.runtimeType.toString(), '<T, U>(T, U) => num');
70-
Expect.equals(h(42, 123.0), '<T, U>(T, U) => String');
101+
102+
// Check that generic method types are printed in a reasonable way
103+
Expect.isTrue(
104+
new RegExp(r'<(\w+) extends num, (\w+) extends \1>\(\1, \2\) => num')
105+
.hasMatch(f.runtimeType.toString()));
106+
Expect.isTrue(new RegExp(r'<(\w+), (\w+)>\(\1, \2\) => num')
107+
.hasMatch(g.runtimeType.toString()));
108+
Expect.isTrue(
109+
new RegExp(r'<(\w+), (\w+)>\(\1, \2\) => String').hasMatch(h(42, 123.0)));
71110
}
72111

73112
main() {
74-
testInstantiateToBounds();
75-
testToString();
76-
testChecksBound();
77-
testSubtype();
113+
testInstantiateToBounds(); //# 01: ok
114+
testToString(); //# 02: ok
115+
testChecksBound(); //# 03: ok
116+
testSubtype(); //# 04: ok
78117
}

0 commit comments

Comments
 (0)