Substitute bounds of fresh type parameters using all fresh type parameters.

R=brianwilkerson@google.com, paulberry@google.com

Bug: https://github.com/dart-lang/sdk/issues/38365
Change-Id: I7603126bb7a5578b9ce2c74a7b130a591be0d4b9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/117640
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2019-09-18 00:21:16 +00:00 committed by commit-bot@chromium.org
parent 1a812bb6bb
commit 12c1b43365
2 changed files with 106 additions and 38 deletions

View file

@ -201,6 +201,34 @@ class _FreshTypeParametersSubstitutor extends _TypeSubstitutor {
return freshElement;
}
@override
List<TypeParameterElement> freshTypeParameters(
List<TypeParameterElement> elements) {
if (elements.isEmpty) {
return const <TypeParameterElement>[];
}
var freshElements = List<TypeParameterElement>(elements.length);
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
var freshElement = TypeParameterElementImpl(element.name, -1);
freshElements[i] = freshElement;
var freshType = TypeParameterTypeImpl(freshElement);
freshElement.type = freshType;
substitution[element] = freshType;
}
for (var i = 0; i < freshElements.length; i++) {
var element = elements[i];
if (element.bound != null) {
TypeParameterElementImpl freshElement = freshElements[i];
freshElement.bound = visit(element.bound);
}
}
return freshElements;
}
DartType lookup(TypeParameterElement parameter, bool upperBound) {
return substitution[parameter];
}
@ -247,8 +275,8 @@ class _TopSubstitutor extends _TypeSubstitutor {
}
}
@override
TypeParameterElement freshTypeParameter(TypeParameterElement element) {
List<TypeParameterElement> freshTypeParameters(
List<TypeParameterElement> parameters) {
throw 'Create a fresh environment first';
}
@ -283,15 +311,8 @@ abstract class _TypeSubstitutor extends DartTypeVisitor<DartType> {
target.useCounter++;
}
TypeParameterElement freshTypeParameter(TypeParameterElement element);
List<TypeParameterElement> freshTypeParameters(
List<TypeParameterElement> parameters) {
if (parameters.isEmpty) {
return const <TypeParameterElement>[];
}
return parameters.map(freshTypeParameter).toList();
}
List<TypeParameterElement> elements);
DartType getSubstitute(TypeParameterElement parameter) {
var environment = this;
@ -339,14 +360,18 @@ abstract class _TypeSubstitutor extends DartTypeVisitor<DartType> {
// any uses, but does not tell if the resulting function type is distinct.
// Our own use counter will get incremented if something from our
// environment has been used inside the function.
var inner = type.typeFormals.isEmpty ? this : newInnerEnvironment();
int before = this.useCounter;
var inner = this;
var typeFormals = type.typeFormals;
if (typeFormals.isNotEmpty) {
inner = newInnerEnvironment();
typeFormals = inner.freshTypeParameters(typeFormals);
}
// Invert the variance when translating parameters.
inner.invertVariance();
var typeFormals = inner.freshTypeParameters(type.typeFormals);
var parameters = type.parameters.map((parameter) {
var type = inner.visit(parameter.type);
return _parameterElement(parameter, type);
@ -376,14 +401,18 @@ abstract class _TypeSubstitutor extends DartTypeVisitor<DartType> {
// any uses, but does not tell if the resulting function type is distinct.
// Our own use counter will get incremented if something from our
// environment has been used inside the function.
var inner = type.typeFormals.isEmpty ? this : newInnerEnvironment();
int before = this.useCounter;
var inner = this;
var typeFormals = type.typeFormals;
if (typeFormals.isNotEmpty) {
inner = newInnerEnvironment();
typeFormals = inner.freshTypeParameters(typeFormals);
}
// Invert the variance when translating parameters.
inner.invertVariance();
var typeFormals = inner.freshTypeParameters(type.typeFormals);
var parameters = type.parameters.map((parameter) {
var type = inner.visit(parameter.type);
return _parameterElement(parameter, type);

View file

@ -113,34 +113,14 @@ class SubstituteTest extends _Base {
_assertIdenticalType(typeProvider.dynamicType, {T: intType});
}
test_function_noTypeParameters() async {
test_function_noSubstitutions() async {
var type = functionType(required: [intType], returns: boolType);
var T = typeParameter('T');
_assertIdenticalType(type, {T: intType});
}
test_function_typeFormals() async {
// typedef F<T> = T Function<U extends T>(U);
var T = typeParameter('T');
var U = typeParameter('U', bound: typeParameterType(T));
var type = functionType(
typeFormals: [U],
required: [
typeParameterType(U),
],
returns: typeParameterType(T),
);
assertElementTypeString(type, 'T Function<U extends T>(U)');
_assertSubstitution(
type,
{T: intType},
'int Function<U extends int>(U)',
);
}
test_function_typeParameters() async {
test_function_parameters_returnType() async {
// typedef F<T, U> = T Function(U u, bool);
var T = typeParameter('T');
var U = typeParameter('U');
@ -165,6 +145,65 @@ class SubstituteTest extends _Base {
);
}
test_function_typeFormals() async {
// typedef F<T> = T Function<U extends T>(U);
var T = typeParameter('T');
var U = typeParameter('U', bound: typeParameterType(T));
var type = functionType(
typeFormals: [U],
required: [
typeParameterType(U),
],
returns: typeParameterType(T),
);
assertElementTypeString(type, 'T Function<U extends T>(U)');
_assertSubstitution(
type,
{T: intType},
'int Function<U extends int>(U)',
);
}
test_function_typeFormals_bounds() async {
// class Triple<X, Y, Z> {}
// typedef F<V> = bool Function<T extends Triplet<T, U, V>, U>();
var classTriplet = class_(name: 'Triple', typeParameters: [
typeParameter('X'),
typeParameter('Y'),
typeParameter('Z'),
]);
var T = typeParameter('T');
var U = typeParameter('U');
var V = typeParameter('V');
T.bound = interfaceType(classTriplet, typeArguments: [
typeParameterType(T),
typeParameterType(U),
typeParameterType(V),
]);
var type = functionType(
typeFormals: [T, U],
returns: boolType,
);
assertElementTypeString(
type,
'bool Function<T extends Triple<T, U, V>,U>()',
);
var result = substitute(type, {V: intType}) as FunctionType;
assertElementTypeString(
result,
'bool Function<T extends Triple<T, U, int>,U>()',
);
var T2 = result.typeFormals[0];
var U2 = result.typeFormals[1];
var T2boundArgs = (T2.bound as InterfaceType).typeArguments;
expect((T2boundArgs[0] as TypeParameterType).element, same(T2));
expect((T2boundArgs[1] as TypeParameterType).element, same(U2));
}
test_interface_arguments() async {
// class A<T> {}
var T = typeParameter('T');