Skip to content

Commit 12c1b43

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Substitute bounds of fresh type parameters using all fresh type parameters.
[email protected], [email protected] Bug: #38365 Change-Id: I7603126bb7a5578b9ce2c74a7b130a591be0d4b9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/117640 Reviewed-by: Paul Berry <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 1a812bb commit 12c1b43

File tree

2 files changed

+100
-32
lines changed

2 files changed

+100
-32
lines changed

pkg/analyzer/lib/src/dart/element/type_algebra.dart

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,34 @@ class _FreshTypeParametersSubstitutor extends _TypeSubstitutor {
201201
return freshElement;
202202
}
203203

204+
@override
205+
List<TypeParameterElement> freshTypeParameters(
206+
List<TypeParameterElement> elements) {
207+
if (elements.isEmpty) {
208+
return const <TypeParameterElement>[];
209+
}
210+
211+
var freshElements = List<TypeParameterElement>(elements.length);
212+
for (var i = 0; i < elements.length; i++) {
213+
var element = elements[i];
214+
var freshElement = TypeParameterElementImpl(element.name, -1);
215+
freshElements[i] = freshElement;
216+
var freshType = TypeParameterTypeImpl(freshElement);
217+
freshElement.type = freshType;
218+
substitution[element] = freshType;
219+
}
220+
221+
for (var i = 0; i < freshElements.length; i++) {
222+
var element = elements[i];
223+
if (element.bound != null) {
224+
TypeParameterElementImpl freshElement = freshElements[i];
225+
freshElement.bound = visit(element.bound);
226+
}
227+
}
228+
229+
return freshElements;
230+
}
231+
204232
DartType lookup(TypeParameterElement parameter, bool upperBound) {
205233
return substitution[parameter];
206234
}
@@ -247,8 +275,8 @@ class _TopSubstitutor extends _TypeSubstitutor {
247275
}
248276
}
249277

250-
@override
251-
TypeParameterElement freshTypeParameter(TypeParameterElement element) {
278+
List<TypeParameterElement> freshTypeParameters(
279+
List<TypeParameterElement> parameters) {
252280
throw 'Create a fresh environment first';
253281
}
254282

@@ -283,15 +311,8 @@ abstract class _TypeSubstitutor extends DartTypeVisitor<DartType> {
283311
target.useCounter++;
284312
}
285313

286-
TypeParameterElement freshTypeParameter(TypeParameterElement element);
287-
288314
List<TypeParameterElement> freshTypeParameters(
289-
List<TypeParameterElement> parameters) {
290-
if (parameters.isEmpty) {
291-
return const <TypeParameterElement>[];
292-
}
293-
return parameters.map(freshTypeParameter).toList();
294-
}
315+
List<TypeParameterElement> elements);
295316

296317
DartType getSubstitute(TypeParameterElement parameter) {
297318
var environment = this;
@@ -339,14 +360,18 @@ abstract class _TypeSubstitutor extends DartTypeVisitor<DartType> {
339360
// any uses, but does not tell if the resulting function type is distinct.
340361
// Our own use counter will get incremented if something from our
341362
// environment has been used inside the function.
342-
var inner = type.typeFormals.isEmpty ? this : newInnerEnvironment();
343363
int before = this.useCounter;
344364

365+
var inner = this;
366+
var typeFormals = type.typeFormals;
367+
if (typeFormals.isNotEmpty) {
368+
inner = newInnerEnvironment();
369+
typeFormals = inner.freshTypeParameters(typeFormals);
370+
}
371+
345372
// Invert the variance when translating parameters.
346373
inner.invertVariance();
347374

348-
var typeFormals = inner.freshTypeParameters(type.typeFormals);
349-
350375
var parameters = type.parameters.map((parameter) {
351376
var type = inner.visit(parameter.type);
352377
return _parameterElement(parameter, type);
@@ -376,14 +401,18 @@ abstract class _TypeSubstitutor extends DartTypeVisitor<DartType> {
376401
// any uses, but does not tell if the resulting function type is distinct.
377402
// Our own use counter will get incremented if something from our
378403
// environment has been used inside the function.
379-
var inner = type.typeFormals.isEmpty ? this : newInnerEnvironment();
380404
int before = this.useCounter;
381405

406+
var inner = this;
407+
var typeFormals = type.typeFormals;
408+
if (typeFormals.isNotEmpty) {
409+
inner = newInnerEnvironment();
410+
typeFormals = inner.freshTypeParameters(typeFormals);
411+
}
412+
382413
// Invert the variance when translating parameters.
383414
inner.invertVariance();
384415

385-
var typeFormals = inner.freshTypeParameters(type.typeFormals);
386-
387416
var parameters = type.parameters.map((parameter) {
388417
var type = inner.visit(parameter.type);
389418
return _parameterElement(parameter, type);

pkg/analyzer/test/src/dart/element/type_algebra_test.dart

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -113,56 +113,95 @@ class SubstituteTest extends _Base {
113113
_assertIdenticalType(typeProvider.dynamicType, {T: intType});
114114
}
115115

116-
test_function_noTypeParameters() async {
116+
test_function_noSubstitutions() async {
117117
var type = functionType(required: [intType], returns: boolType);
118118

119119
var T = typeParameter('T');
120120
_assertIdenticalType(type, {T: intType});
121121
}
122122

123-
test_function_typeFormals() async {
124-
// typedef F<T> = T Function<U extends T>(U);
123+
test_function_parameters_returnType() async {
124+
// typedef F<T, U> = T Function(U u, bool);
125125
var T = typeParameter('T');
126-
var U = typeParameter('U', bound: typeParameterType(T));
126+
var U = typeParameter('U');
127127
var type = functionType(
128-
typeFormals: [U],
129128
required: [
130129
typeParameterType(U),
130+
boolType,
131131
],
132132
returns: typeParameterType(T),
133133
);
134134

135-
assertElementTypeString(type, 'T Function<U extends T>(U)');
135+
assertElementTypeString(type, 'T Function(U, bool)');
136136
_assertSubstitution(
137137
type,
138138
{T: intType},
139-
'int Function<U extends int>(U)',
139+
'int Function(U, bool)',
140+
);
141+
_assertSubstitution(
142+
type,
143+
{T: intType, U: doubleType},
144+
'int Function(double, bool)',
140145
);
141146
}
142147

143-
test_function_typeParameters() async {
144-
// typedef F<T, U> = T Function(U u, bool);
148+
test_function_typeFormals() async {
149+
// typedef F<T> = T Function<U extends T>(U);
145150
var T = typeParameter('T');
146-
var U = typeParameter('U');
151+
var U = typeParameter('U', bound: typeParameterType(T));
147152
var type = functionType(
153+
typeFormals: [U],
148154
required: [
149155
typeParameterType(U),
150-
boolType,
151156
],
152157
returns: typeParameterType(T),
153158
);
154159

155-
assertElementTypeString(type, 'T Function(U, bool)');
160+
assertElementTypeString(type, 'T Function<U extends T>(U)');
156161
_assertSubstitution(
157162
type,
158163
{T: intType},
159-
'int Function(U, bool)',
164+
'int Function<U extends int>(U)',
160165
);
161-
_assertSubstitution(
166+
}
167+
168+
test_function_typeFormals_bounds() async {
169+
// class Triple<X, Y, Z> {}
170+
// typedef F<V> = bool Function<T extends Triplet<T, U, V>, U>();
171+
var classTriplet = class_(name: 'Triple', typeParameters: [
172+
typeParameter('X'),
173+
typeParameter('Y'),
174+
typeParameter('Z'),
175+
]);
176+
177+
var T = typeParameter('T');
178+
var U = typeParameter('U');
179+
var V = typeParameter('V');
180+
T.bound = interfaceType(classTriplet, typeArguments: [
181+
typeParameterType(T),
182+
typeParameterType(U),
183+
typeParameterType(V),
184+
]);
185+
var type = functionType(
186+
typeFormals: [T, U],
187+
returns: boolType,
188+
);
189+
190+
assertElementTypeString(
162191
type,
163-
{T: intType, U: doubleType},
164-
'int Function(double, bool)',
192+
'bool Function<T extends Triple<T, U, V>,U>()',
193+
);
194+
195+
var result = substitute(type, {V: intType}) as FunctionType;
196+
assertElementTypeString(
197+
result,
198+
'bool Function<T extends Triple<T, U, int>,U>()',
165199
);
200+
var T2 = result.typeFormals[0];
201+
var U2 = result.typeFormals[1];
202+
var T2boundArgs = (T2.bound as InterfaceType).typeArguments;
203+
expect((T2boundArgs[0] as TypeParameterType).element, same(T2));
204+
expect((T2boundArgs[1] as TypeParameterType).element, same(U2));
166205
}
167206

168207
test_interface_arguments() async {

0 commit comments

Comments
 (0)