mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 18:31:32 +00:00
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:
parent
1a812bb6bb
commit
12c1b43365
|
@ -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);
|
||||
|
|
|
@ -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');
|
||||
|
|
Loading…
Reference in a new issue