Skip to content

Commit 51d578c

Browse files
stereotype441Commit Bot
authored and
Commit Bot
committed
Fix horizontal inference logic for extension method invocations.
The front end desugars extension methods by inserting a synthetic `this` argument before all other arguments. But this synthetic argument isn't included in the `formalTypes` and `actualTypes` arrays. So when recording a value into `_DeferredParamInfo.evaluationOrderIndex` we may need to subtract 1 in order to ensure that later logic will find the correct argument. Fixes a corner case of dart-lang/language#731. Change-Id: Idbf136195e40555199f7c5b61a575a430f6ec6bd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243854 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Chloe Stefantsova <[email protected]>
1 parent a67c07c commit 51d578c

9 files changed

+1399
-1
lines changed

pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ List<_ParamInfo> _computeUndeferredParamInfo(List<DartType> formalTypes,
128128
for (_DeferredParamInfo functionLiteral in deferredFunctionLiterals)
129129
functionLiteral.evaluationOrderIndex
130130
};
131+
assert(evaluationOrderIndicesAlreadyCovered
132+
.every((i) => 0 <= i && i < formalTypes.length));
131133
return [
132134
for (int i = 0; i < formalTypes.length; i++)
133135
if (!evaluationOrderIndicesAlreadyCovered.contains(i))
@@ -2527,7 +2529,9 @@ class TypeInferrerImpl implements TypeInferrer {
25272529
argumentExpression: argumentExpression,
25282530
unparenthesizedExpression: unparenthesizedExpression,
25292531
isNamed: !isExpression,
2530-
evaluationOrderIndex: evaluationOrderIndex,
2532+
evaluationOrderIndex: isImplicitExtensionMember
2533+
? evaluationOrderIndex - 1
2534+
: evaluationOrderIndex,
25312535
index: index));
25322536
// We don't have `identical` info yet, so fill it in with `null` for
25332537
// now. Later, when we visit the function literal, we'll replace it.
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
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+
// Tests that horizontal inference works properly when the invocation is an
6+
// extension member. This is an important corner case because the front end
7+
// adds an implicit `this` argument to extension members as part of the lowering
8+
// process. We need to make sure that the dependency tracking logic properly
9+
// accounts for this extra argument.
10+
11+
// SharedOptions=--enable-experiment=inference-update-1
12+
13+
testLaterUnnamedParameter(int i) {
14+
i._laterUnnamedParameter(0, (x) {
15+
x;
16+
});
17+
}
18+
19+
/// This special case verifies that the implementations correctly associate the
20+
/// zeroth positional parameter with the corresponding argument (even if that
21+
/// argument isn't in the zeroth position at the call site).
22+
testLaterUnnamedParameterDependsOnNamedParameter(int i) {
23+
i._laterUnnamedParameterDependsOnNamedParameter(a: 0, (x) {
24+
x;
25+
});
26+
}
27+
28+
testEarlierUnnamedParameter(int i) {
29+
i._earlierUnnamedParameter((x) {
30+
x;
31+
}, 0);
32+
}
33+
34+
testLaterNamedParameter(int i) {
35+
i._laterNamedParameter(
36+
a: 0,
37+
b: (x) {
38+
x;
39+
});
40+
}
41+
42+
testEarlierNamedParameter(int i) {
43+
i._earlierNamedParameter(
44+
a: (x) {
45+
x;
46+
},
47+
b: 0);
48+
}
49+
50+
/// This special case verifies that the implementations correctly associate the
51+
/// zeroth positional parameter with the corresponding argument (even if that
52+
/// argument isn't in the zeroth position at the call site).
53+
testEarlierNamedParameterDependsOnUnnamedParameter(int i) {
54+
i._earlierNamedParameterDependsOnUnnamedParameter(a: (x) {
55+
x;
56+
}, 0);
57+
}
58+
59+
testPropagateToReturnType(int i) {
60+
i._propagateToReturnType(0, (x) => [x]);
61+
}
62+
63+
// The test cases below exercise situations where there are multiple closures in
64+
// the invocation, and they need to be inferred in the right order.
65+
66+
testClosureAsParameterType(int i) {
67+
i._closureAsParameterType(() => 0, (h) => [h()])
68+
;
69+
}
70+
71+
testPropagateToEarlierClosure(int i) {
72+
i._propagateToEarlierClosure((x) => [x], () => 0)
73+
;
74+
}
75+
76+
testPropagateToLaterClosure(int i) {
77+
i._propagateToLaterClosure(() => 0, (x) => [x])
78+
;
79+
}
80+
81+
testLongDependencyChain(int i) {
82+
i._longDependencyChain(() => [0], (x) => x.single,
83+
(y) => {y})
84+
;
85+
}
86+
87+
testDependencyCycle(int i) {
88+
i._dependencyCycle((x) => [x],
89+
(y) => {y})
90+
;
91+
}
92+
93+
testPropagateFromContravariantReturnType(int i) {
94+
i._propagateFromContravariantReturnType(() => (int i) {}, (x) => [x])
95+
;
96+
}
97+
98+
testPropagateToContravariantParameterType(int i) {
99+
i._propagateToContravariantParameterType(() => 0, (x) => [x])
100+
;
101+
}
102+
103+
testReturnTypeRefersToMultipleTypeVars(int i) {
104+
i._returnTypeRefersToMultipleTypeVars(() => {0: ''}, (k) {
105+
k;
106+
}, (v) {
107+
v;
108+
});
109+
}
110+
111+
testUnnecessaryDueToNoDependency(int i) {
112+
i._unnecessaryDueToNoDependency(() => 0, null);
113+
}
114+
115+
testUnnecessaryDueToExplicitParameterTypeNamed(int i) {
116+
var a = i._unnecessaryDueToExplicitParameterTypeNamed(null, ({int? x, required y}) => (x ?? 0) + y);
117+
a;
118+
}
119+
120+
testParenthesized(int i) {
121+
i._parenthesized(0, ((x) {
122+
x;
123+
}));
124+
}
125+
126+
testParenthesizedNamed(int i) {
127+
i._parenthesizedNamed(
128+
a: 0,
129+
b: ((x) {
130+
x;
131+
}));
132+
}
133+
134+
testParenthesizedTwice(int i) {
135+
i._parenthesizedTwice(0, (((x) {
136+
x;
137+
})));
138+
}
139+
140+
testParenthesizedTwiceNamed(int i) {
141+
i._parenthesizedTwiceNamed(
142+
a: 0,
143+
b: (((x) {
144+
x;
145+
})));
146+
}
147+
148+
extension on int {
149+
T _laterUnnamedParameter<T>(T x, void Function(T) y) => throw '';
150+
void _laterUnnamedParameterDependsOnNamedParameter<T>(void Function(T) x, {required T a}) => throw '';
151+
void _earlierUnnamedParameter<T>(void Function(T) x, T y) => throw '';
152+
void _laterNamedParameter<T>({required T a, required void Function(T) b}) => throw '';
153+
void _earlierNamedParameter<T>({required void Function(T) a, required T b}) => throw '';
154+
void _earlierNamedParameterDependsOnUnnamedParameter<T>(T b, {required void Function(T) a}) => throw '';
155+
U _propagateToReturnType<T, U>(T x, U Function(T) y) => throw '';
156+
U _closureAsParameterType<T, U>(T x, U Function(T) y) => throw '';
157+
U _propagateToEarlierClosure<T, U>(U Function(T) x, T Function() y) => throw '';
158+
U _propagateToLaterClosure<T, U>(T Function() x, U Function(T) y) => throw '';
159+
V _longDependencyChain<T, U, V>(T Function() x, U Function(T) y, V Function(U) z) => throw '';
160+
Map<T, U> _dependencyCycle<T, U>(T Function(U) x, U Function(T) y) => throw '';
161+
U _propagateFromContravariantReturnType<T, U>(void Function(T) Function() x, U Function(T) y) => throw '';
162+
U _propagateToContravariantParameterType<T, U>(T Function() x, U Function(void Function(T)) y) => throw '';
163+
void _returnTypeRefersToMultipleTypeVars<T, U>(
164+
Map<T, U> Function() x, void Function(T) y, void Function(U) z) => throw '';
165+
T _unnecessaryDueToNoDependency<T>(T Function() x, T y) => throw '';
166+
T _unnecessaryDueToExplicitParameterTypeNamed<T>(T x, T Function({required T x, required int y}) y) => throw '';
167+
void _parenthesized<T>(T x, void Function(T) y) => throw '';
168+
void _parenthesizedNamed<T>({required T a, required void Function(T) b}) => throw '';
169+
void _parenthesizedTwice<T>(T x, void Function(T) y) => throw '';
170+
void _parenthesizedTwiceNamed<T>({required T a, required void Function(T) b}) => throw '';
171+
}
172+
173+
main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
testLaterUnnamedParameter(int i) {}
2+
testLaterUnnamedParameterDependsOnNamedParameter(int i) {}
3+
testEarlierUnnamedParameter(int i) {}
4+
testLaterNamedParameter(int i) {}
5+
testEarlierNamedParameter(int i) {}
6+
testEarlierNamedParameterDependsOnUnnamedParameter(int i) {}
7+
testPropagateToReturnType(int i) {}
8+
testClosureAsParameterType(int i) {}
9+
testPropagateToEarlierClosure(int i) {}
10+
testPropagateToLaterClosure(int i) {}
11+
testLongDependencyChain(int i) {}
12+
testDependencyCycle(int i) {}
13+
testPropagateFromContravariantReturnType(int i) {}
14+
testPropagateToContravariantParameterType(int i) {}
15+
testReturnTypeRefersToMultipleTypeVars(int i) {}
16+
testUnnecessaryDueToNoDependency(int i) {}
17+
testUnnecessaryDueToExplicitParameterTypeNamed(int i) {}
18+
testParenthesized(int i) {}
19+
testParenthesizedNamed(int i) {}
20+
testParenthesizedTwice(int i) {}
21+
testParenthesizedTwiceNamed(int i) {}
22+
23+
extension on int {
24+
T _laterUnnamedParameter<T>(T x, void Function(T) y) => throw '';
25+
void _laterUnnamedParameterDependsOnNamedParameter<T>(void Function(T) x,
26+
{required T a}) =>
27+
throw '';
28+
void _earlierUnnamedParameter<T>(void Function(T) x, T y) => throw '';
29+
void _laterNamedParameter<T>({required T a, required void Function(T) b}) =>
30+
throw '';
31+
void _earlierNamedParameter<T>({required void Function(T) a, required T b}) =>
32+
throw '';
33+
void _earlierNamedParameterDependsOnUnnamedParameter<T>(T b,
34+
{required void Function(T) a}) =>
35+
throw '';
36+
U _propagateToReturnType<T, U>(T x, U Function(T) y) => throw '';
37+
U _closureAsParameterType<T, U>(T x, U Function(T) y) => throw '';
38+
U _propagateToEarlierClosure<T, U>(U Function(T) x, T Function() y) =>
39+
throw '';
40+
U _propagateToLaterClosure<T, U>(T Function() x, U Function(T) y) => throw '';
41+
V _longDependencyChain<T, U, V>(
42+
T Function() x, U Function(T) y, V Function(U) z) =>
43+
throw '';
44+
Map<T, U> _dependencyCycle<T, U>(T Function(U) x, U Function(T) y) =>
45+
throw '';
46+
U _propagateFromContravariantReturnType<T, U>(
47+
void Function(T) Function() x, U Function(T) y) =>
48+
throw '';
49+
U _propagateToContravariantParameterType<T, U>(
50+
T Function() x, U Function(void Function(T)) y) =>
51+
throw '';
52+
void _returnTypeRefersToMultipleTypeVars<T, U>(
53+
Map<T, U> Function() x, void Function(T) y, void Function(U) z) =>
54+
throw '';
55+
T _unnecessaryDueToNoDependency<T>(T Function() x, T y) => throw '';
56+
T _unnecessaryDueToExplicitParameterTypeNamed<T>(
57+
T x, T Function({required T x, required int y}) y) =>
58+
throw '';
59+
void _parenthesized<T>(T x, void Function(T) y) => throw '';
60+
void _parenthesizedNamed<T>({required T a, required void Function(T) b}) =>
61+
throw '';
62+
void _parenthesizedTwice<T>(T x, void Function(T) y) => throw '';
63+
void _parenthesizedTwiceNamed<T>(
64+
{required T a, required void Function(T) b}) =>
65+
throw '';
66+
}
67+
68+
main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
extension on int {
2+
Map<T, U> _dependencyCycle<T, U>(T Function(U) x, U Function(T) y) =>
3+
throw '';
4+
T _laterUnnamedParameter<T>(T x, void Function(T) y) => throw '';
5+
T _unnecessaryDueToExplicitParameterTypeNamed<T>(
6+
T x, T Function({required T x, required int y}) y) =>
7+
throw '';
8+
T _unnecessaryDueToNoDependency<T>(T Function() x, T y) => throw '';
9+
U _closureAsParameterType<T, U>(T x, U Function(T) y) => throw '';
10+
U _propagateFromContravariantReturnType<T, U>(
11+
void Function(T) Function() x, U Function(T) y) =>
12+
throw '';
13+
U _propagateToContravariantParameterType<T, U>(
14+
T Function() x, U Function(void Function(T)) y) =>
15+
throw '';
16+
U _propagateToEarlierClosure<T, U>(U Function(T) x, T Function() y) =>
17+
throw '';
18+
U _propagateToLaterClosure<T, U>(T Function() x, U Function(T) y) => throw '';
19+
U _propagateToReturnType<T, U>(T x, U Function(T) y) => throw '';
20+
V _longDependencyChain<T, U, V>(
21+
T Function() x, U Function(T) y, V Function(U) z) =>
22+
throw '';
23+
void _earlierNamedParameter<T>({required void Function(T) a, required T b}) =>
24+
throw '';
25+
void _earlierNamedParameterDependsOnUnnamedParameter<T>(T b,
26+
{required void Function(T) a}) =>
27+
throw '';
28+
void _earlierUnnamedParameter<T>(void Function(T) x, T y) => throw '';
29+
void _laterNamedParameter<T>({required T a, required void Function(T) b}) =>
30+
throw '';
31+
void _laterUnnamedParameterDependsOnNamedParameter<T>(void Function(T) x,
32+
{required T a}) =>
33+
throw '';
34+
void _parenthesized<T>(T x, void Function(T) y) => throw '';
35+
void _parenthesizedNamed<T>({required T a, required void Function(T) b}) =>
36+
throw '';
37+
void _parenthesizedTwice<T>(T x, void Function(T) y) => throw '';
38+
void _parenthesizedTwiceNamed<T>(
39+
{required T a, required void Function(T) b}) =>
40+
throw '';
41+
void _returnTypeRefersToMultipleTypeVars<T, U>(
42+
Map<T, U> Function() x, void Function(T) y, void Function(U) z) =>
43+
throw '';
44+
}
45+
46+
main() {}
47+
testClosureAsParameterType(int i) {}
48+
testDependencyCycle(int i) {}
49+
testEarlierNamedParameter(int i) {}
50+
testEarlierNamedParameterDependsOnUnnamedParameter(int i) {}
51+
testEarlierUnnamedParameter(int i) {}
52+
testLaterNamedParameter(int i) {}
53+
testLaterUnnamedParameter(int i) {}
54+
testLaterUnnamedParameterDependsOnNamedParameter(int i) {}
55+
testLongDependencyChain(int i) {}
56+
testParenthesized(int i) {}
57+
testParenthesizedNamed(int i) {}
58+
testParenthesizedTwice(int i) {}
59+
testParenthesizedTwiceNamed(int i) {}
60+
testPropagateFromContravariantReturnType(int i) {}
61+
testPropagateToContravariantParameterType(int i) {}
62+
testPropagateToEarlierClosure(int i) {}
63+
testPropagateToLaterClosure(int i) {}
64+
testPropagateToReturnType(int i) {}
65+
testReturnTypeRefersToMultipleTypeVars(int i) {}
66+
testUnnecessaryDueToExplicitParameterTypeNamed(int i) {}
67+
testUnnecessaryDueToNoDependency(int i) {}

0 commit comments

Comments
 (0)