Skip to content

Commit 028a699

Browse files
author
sgrekhov
committed
dart-lang#1354. Horizontal inference tests added
1 parent f94a68c commit 028a699

9 files changed

+489
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) 2022, 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 First, we form a dependency graph among the invocation arguments
6+
/// based on the following rule: there is a dependency edge from argument A to
7+
/// argument B if and only if the type of the invocation target is generic, and
8+
/// the following relationship exists among A, B, and at least one of the
9+
/// invocation target’s type parameters T:
10+
///
11+
/// A is a function literal expression,
12+
/// AND the parameter in the invocation target corresponding to A is function
13+
/// typed,
14+
/// AND T is a free variable in the type of at least one of the parameters of
15+
/// that function type,
16+
/// AND the corresponding parameter in A does not have a type annotation,
17+
/// AND EITHER:
18+
/// The parameter in the invocation target corresponding to B is function typed,
19+
/// and T is a free variable in its return type
20+
/// OR the parameter in the invocation target corresponding to B is not function
21+
/// typed, and T is a free variable in its type.
22+
///
23+
/// The idea here is that we're trying to draw a dependency edge from A to B in
24+
/// precisely those circumstances in which there is likely to be a benefit to
25+
/// performing a round of horizontal inference after type inferring B and before
26+
/// type inferring A.
27+
///
28+
/// Stage selection
29+
/// After building the dependency graph, we condense it into its strongly
30+
/// connected components (a.k.a. "dependency cycles"). The resulting
31+
/// condensation is guaranteed to be acyclic (that is, considering the nodes of
32+
/// the condensed graph, the arguments in each node depend transitively on each
33+
/// other, and possibly on the arguments in other nodes, but no dependency cycle
34+
/// exists between one node and another).
35+
///
36+
/// @description Checks that type inferred from non-function types and return
37+
/// types of the functions to function types
38+
/// @author [email protected]
39+
40+
import "../../Utils/expect.dart";
41+
42+
var aType;
43+
var bType;
44+
var cType;
45+
var dType;
46+
47+
void f<T, U, V>(void Function(T, U) a, T b, U Function(V) c, V Function(U) d) {
48+
aType = a.runtimeType;
49+
bType = b.runtimeType;
50+
cType = c.runtimeType;
51+
dType = d.runtimeType;
52+
}
53+
54+
typedef expectedA = void Function(String s, int i);
55+
typedef expectedB = String;
56+
typedef expectedC = int Function(Object? o);
57+
typedef expectedD = bool Function(Object? o);
58+
59+
typedef Str = String;
60+
typedef Int = int;
61+
typedef Boolean = bool;
62+
63+
main() {
64+
// T = String, U = int, V = bool
65+
f((t, u) {}, "x", (v) => 42, (u) => true);
66+
Expect.equals(expectedA, aType);
67+
Expect.equals(expectedB, bType);
68+
Expect.equals(expectedC, cType);
69+
Expect.equals(expectedD, dType);
70+
71+
Str s = "Lily was here";
72+
Int i = 0;
73+
Boolean b = true;
74+
75+
f((t, u) {}, s, (v) => i, (u) => b);
76+
Expect.equals(expectedA, aType);
77+
Expect.equals(expectedB, bType);
78+
Expect.equals(expectedC, cType);
79+
Expect.equals(expectedD, dType);
80+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (c) 2022, 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 First, we form a dependency graph among the invocation arguments
6+
/// based on the following rule: there is a dependency edge from argument A to
7+
/// argument B if and only if the type of the invocation target is generic, and
8+
/// the following relationship exists among A, B, and at least one of the
9+
/// invocation target’s type parameters T:
10+
///
11+
/// A is a function literal expression,
12+
/// AND the parameter in the invocation target corresponding to A is function
13+
/// typed,
14+
/// AND T is a free variable in the type of at least one of the parameters of
15+
/// that function type,
16+
/// AND the corresponding parameter in A does not have a type annotation,
17+
/// AND EITHER:
18+
/// The parameter in the invocation target corresponding to B is function typed,
19+
/// and T is a free variable in its return type
20+
/// OR the parameter in the invocation target corresponding to B is not function
21+
/// typed, and T is a free variable in its type.
22+
///
23+
/// The idea here is that we're trying to draw a dependency edge from A to B in
24+
/// precisely those circumstances in which there is likely to be a benefit to
25+
/// performing a round of horizontal inference after type inferring B and before
26+
/// type inferring A.
27+
///
28+
/// Stage selection
29+
/// After building the dependency graph, we condense it into its strongly
30+
/// connected components (a.k.a. "dependency cycles"). The resulting
31+
/// condensation is guaranteed to be acyclic (that is, considering the nodes of
32+
/// the condensed graph, the arguments in each node depend transitively on each
33+
/// other, and possibly on the arguments in other nodes, but no dependency cycle
34+
/// exists between one node and another).
35+
///
36+
/// @description Checks that type is not inferred from function arguments to
37+
/// non-function types and return types of the functions
38+
/// @author [email protected]
39+
40+
void f<T, U, V>(void Function(T, U) a, T b, U Function(V) c) {}
41+
42+
main() {
43+
dynamic s = "Lily was here";
44+
f((String t, u) {}, s, (v) => 42);
45+
// ^^^^^^^^^^^^^^^^
46+
// [analyzer] unspecified
47+
// [cfe] unspecified
48+
49+
f((t, String u) {}, "s", (v) => v);
50+
// ^^^^^^^^^^^^^^^^
51+
// [analyzer] unspecified
52+
// [cfe] unspecified
53+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2022, 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 First, we form a dependency graph among the invocation arguments
6+
/// based on the following rule: there is a dependency edge from argument A to
7+
/// argument B if and only if the type of the invocation target is generic, and
8+
/// the following relationship exists among A, B, and at least one of the
9+
/// invocation target’s type parameters T:
10+
///
11+
/// A is a function literal expression,
12+
/// AND the parameter in the invocation target corresponding to A is function
13+
/// typed,
14+
/// AND T is a free variable in the type of at least one of the parameters of
15+
/// that function type,
16+
/// AND the corresponding parameter in A does not have a type annotation,
17+
/// AND EITHER:
18+
/// The parameter in the invocation target corresponding to B is function typed,
19+
/// and T is a free variable in its return type
20+
/// OR the parameter in the invocation target corresponding to B is not function
21+
/// typed, and T is a free variable in its type.
22+
///
23+
/// The idea here is that we're trying to draw a dependency edge from A to B in
24+
/// precisely those circumstances in which there is likely to be a benefit to
25+
/// performing a round of horizontal inference after type inferring B and before
26+
/// type inferring A.
27+
///
28+
/// Stage selection
29+
/// After building the dependency graph, we condense it into its strongly
30+
/// connected components (a.k.a. "dependency cycles"). The resulting
31+
/// condensation is guaranteed to be acyclic (that is, considering the nodes of
32+
/// the condensed graph, the arguments in each node depend transitively on each
33+
/// other, and possibly on the arguments in other nodes, but no dependency cycle
34+
/// exists between one node and another).
35+
///
36+
/// @description Checks that type is not inferred from function arguments to
37+
/// non-function types and return types of the functions. Test dependency loop
38+
/// @author [email protected]
39+
40+
void f<U, V>(U Function(V) c, V Function(U) d) {}
41+
42+
main() {
43+
f((v) => 42, (String u) => true);
44+
// ^^
45+
// [analyzer] unspecified
46+
// [cfe] unspecified
47+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright (c) 2022, 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 First, we form a dependency graph among the invocation arguments
6+
/// based on the following rule: there is a dependency edge from argument A to
7+
/// argument B if and only if the type of the invocation target is generic, and
8+
/// the following relationship exists among A, B, and at least one of the
9+
/// invocation target’s type parameters T:
10+
///
11+
/// A is a function literal expression,
12+
/// AND the parameter in the invocation target corresponding to A is function
13+
/// typed,
14+
/// AND T is a free variable in the type of at least one of the parameters of
15+
/// that function type,
16+
/// AND the corresponding parameter in A does not have a type annotation,
17+
/// AND EITHER:
18+
/// The parameter in the invocation target corresponding to B is function typed,
19+
/// and T is a free variable in its return type
20+
/// OR the parameter in the invocation target corresponding to B is not function
21+
/// typed, and T is a free variable in its type.
22+
///
23+
/// The idea here is that we're trying to draw a dependency edge from A to B in
24+
/// precisely those circumstances in which there is likely to be a benefit to
25+
/// performing a round of horizontal inference after type inferring B and before
26+
/// type inferring A.
27+
///
28+
/// Stage selection
29+
/// After building the dependency graph, we condense it into its strongly
30+
/// connected components (a.k.a. "dependency cycles"). The resulting
31+
/// condensation is guaranteed to be acyclic (that is, considering the nodes of
32+
/// the condensed graph, the arguments in each node depend transitively on each
33+
/// other, and possibly on the arguments in other nodes, but no dependency cycle
34+
/// exists between one node and another).
35+
///
36+
/// @description Checks that type inferred from non-function types and return
37+
/// types of the functions to function types
38+
/// @author [email protected]
39+
40+
import "../../Utils/expect.dart";
41+
42+
var aType;
43+
var bType;
44+
var cType;
45+
var dType;
46+
47+
void f<T, U, V>(void Function(T, U) a, List<T> b, List<U> Function(V) c,
48+
List<V> Function(U) d) {
49+
aType = a.runtimeType;
50+
bType = b.runtimeType;
51+
cType = c.runtimeType;
52+
dType = d.runtimeType;
53+
}
54+
55+
typedef expectedA = void Function(String s, int i);
56+
typedef expectedB = List<String>;
57+
typedef expectedC = List<int> Function(Object? o);
58+
typedef expectedD = List<bool> Function(Object? o);
59+
60+
main() {
61+
// T = String, U = int, V = bool
62+
f((t, u) {}, ["x"], (v) => [42], (u) => [true]);
63+
Expect.equals(expectedA, aType);
64+
Expect.equals(expectedB, bType);
65+
Expect.equals(expectedC, cType);
66+
Expect.equals(expectedD, dType);
67+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) 2022, 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 First, we form a dependency graph among the invocation arguments
6+
/// based on the following rule: there is a dependency edge from argument A to
7+
/// argument B if and only if the type of the invocation target is generic, and
8+
/// the following relationship exists among A, B, and at least one of the
9+
/// invocation target’s type parameters T:
10+
///
11+
/// A is a function literal expression,
12+
/// AND the parameter in the invocation target corresponding to A is function
13+
/// typed,
14+
/// AND T is a free variable in the type of at least one of the parameters of
15+
/// that function type,
16+
/// AND the corresponding parameter in A does not have a type annotation,
17+
/// AND EITHER:
18+
/// The parameter in the invocation target corresponding to B is function typed,
19+
/// and T is a free variable in its return type
20+
/// OR the parameter in the invocation target corresponding to B is not function
21+
/// typed, and T is a free variable in its type.
22+
///
23+
/// The idea here is that we're trying to draw a dependency edge from A to B in
24+
/// precisely those circumstances in which there is likely to be a benefit to
25+
/// performing a round of horizontal inference after type inferring B and before
26+
/// type inferring A.
27+
///
28+
/// Stage selection
29+
/// After building the dependency graph, we condense it into its strongly
30+
/// connected components (a.k.a. "dependency cycles"). The resulting
31+
/// condensation is guaranteed to be acyclic (that is, considering the nodes of
32+
/// the condensed graph, the arguments in each node depend transitively on each
33+
/// other, and possibly on the arguments in other nodes, but no dependency cycle
34+
/// exists between one node and another).
35+
///
36+
/// @description Checks that type inferred from non-function types and return
37+
/// types of the functions to function types
38+
/// @author [email protected]
39+
40+
import "../../Utils/expect.dart";
41+
42+
var aType;
43+
var bType;
44+
var cType;
45+
var dType;
46+
47+
void f<T, U, V>(void Function(T, U) a, Map<T, U> b, Map<U, V> c, V Function(U) d) {
48+
aType = a.runtimeType;
49+
bType = b.runtimeType;
50+
cType = c.runtimeType;
51+
dType = d.runtimeType;
52+
}
53+
54+
typedef expectedA = void Function(String s, int i);
55+
typedef expectedB = Map<String, int>;
56+
typedef expectedC = Map<int, List<String>>;
57+
typedef expectedD = List<String> Function(int i);
58+
59+
main() {
60+
// T = String, U = int, V = List<String>
61+
f((t, u) {}, {"x": 42}, {42: ["x", "y"]}, (u) => ["Lily", "was", "here"]);
62+
Expect.equals(expectedA, aType);
63+
Expect.equals(expectedD, dType);
64+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) 2022, 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 First, we form a dependency graph among the invocation arguments
6+
/// based on the following rule: there is a dependency edge from argument A to
7+
/// argument B if and only if the type of the invocation target is generic, and
8+
/// the following relationship exists among A, B, and at least one of the
9+
/// invocation target’s type parameters T:
10+
///
11+
/// A is a function literal expression,
12+
/// AND the parameter in the invocation target corresponding to A is function
13+
/// typed,
14+
/// AND T is a free variable in the type of at least one of the parameters of
15+
/// that function type,
16+
/// AND the corresponding parameter in A does not have a type annotation,
17+
/// AND EITHER:
18+
/// The parameter in the invocation target corresponding to B is function typed,
19+
/// and T is a free variable in its return type
20+
/// OR the parameter in the invocation target corresponding to B is not function
21+
/// typed, and T is a free variable in its type.
22+
///
23+
/// The idea here is that we're trying to draw a dependency edge from A to B in
24+
/// precisely those circumstances in which there is likely to be a benefit to
25+
/// performing a round of horizontal inference after type inferring B and before
26+
/// type inferring A.
27+
///
28+
/// Stage selection
29+
/// After building the dependency graph, we condense it into its strongly
30+
/// connected components (a.k.a. "dependency cycles"). The resulting
31+
/// condensation is guaranteed to be acyclic (that is, considering the nodes of
32+
/// the condensed graph, the arguments in each node depend transitively on each
33+
/// other, and possibly on the arguments in other nodes, but no dependency cycle
34+
/// exists between one node and another).
35+
///
36+
/// @description Checks that type is not inferred from function arguments to
37+
/// non-function types and return types of the functions
38+
/// @author [email protected]
39+
40+
void f1<X, Y>(X Function(Y) a, void Function(X) b) {}
41+
void f2<X, Y>(void Function(Y) a, Y Function(X) b) {}
42+
void f3<T, U>(Map<T, U> a, void Function(T, U) b) {}
43+
44+
main() {
45+
f1((v) => 42, (String u) {});
46+
// ^^^^^^^^^^^^^
47+
// [analyzer] unspecified
48+
// [cfe] unspecified
49+
50+
f2((int v) {}, (u) => "Lily was here");
51+
// ^^^^^^^^^^
52+
// [analyzer] unspecified
53+
// [cfe] unspecified
54+
55+
f3({"x": "42"}, (String t, int u) {});
56+
// ^^^^^^^^^^^^^^^^^^^^
57+
// [analyzer] unspecified
58+
// [cfe] unspecified
59+
}

0 commit comments

Comments
 (0)