Chromium Code Reviews| Index: pkg/analyzer/lib/src/generated/type_system.dart |
| diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart |
| index af7319888abb1324268ad314fce4fe792a13b473..f1abdf5c2d5321acc8d0a1daaab6b0bea114dbda 100644 |
| --- a/pkg/analyzer/lib/src/generated/type_system.dart |
| +++ b/pkg/analyzer/lib/src/generated/type_system.dart |
| @@ -422,32 +422,80 @@ class StrongTypeSystemImpl extends TypeSystem { |
| * each Ti in Bi with dynamic to get Ii, and then replacing Ti with |
| * Ii in all of the remaining bounds. |
|
Leaf
2017/01/20 20:31:53
It's probably fine for now to have this on type_sy
scheglov
2017/01/21 02:11:23
Done.
|
| */ |
| - DartType instantiateToBounds(DartType type) { |
| + DartType instantiateToBounds(DartType type, {List<bool> hasError}) { |
|
Leaf
2017/01/20 20:31:52
Is this just to avoid a breaking change to the API
scheglov
2017/01/21 02:11:23
I cannot return `null`.
This method should return
|
| List<TypeParameterElement> typeFormals = typeFormalsAsElements(type); |
| int count = typeFormals.length; |
| if (count == 0) { |
| return type; |
| } |
| - // We build up a substitution replacing bound parameters with |
| - // their instantiated bounds, {substituted/variables} |
| - List<DartType> substituted = new List<DartType>(); |
| - List<DartType> variables = new List<DartType>(); |
| + List<TypeParameterType> getFreeParameters(DartType type) { |
|
Leaf
2017/01/20 20:31:53
This needs to be restricted to considering only ty
scheglov
2017/01/21 02:11:23
Done.
|
| + List<TypeParameterType> parameters = null; |
| + |
| + void appendParameters(DartType type) { |
| + if (type is TypeParameterType) { |
| + parameters ??= <TypeParameterType>[]; |
| + parameters.add(type); |
| + } else if (type is ParameterizedType) { |
| + type.typeArguments.forEach(appendParameters); |
| + } |
| + } |
| + |
| + appendParameters(type); |
| + return parameters; |
| + } |
| + |
| + List<bool> isGround = new List<bool>.filled(count, false); |
|
Leaf
2017/01/20 20:31:52
I think this section of code is right. I wonder i
scheglov
2017/01/21 02:11:23
I update the code to be more like this.
|
| + |
| + Map<TypeParameterType, int> parameterToIndex = {}; |
| for (int i = 0; i < count; i++) { |
| - TypeParameterElement param = typeFormals[i]; |
| - DartType bound = param.bound ?? DynamicTypeImpl.instance; |
| - DartType variable = param.type; |
| - // For each Ti extends Bi, first compute Ii by replacing |
| - // Ti in Bi with dynamic (simultaneously replacing all |
| - // of the previous Tj (j < i) with their instantiated bounds. |
| - substituted.add(DynamicTypeImpl.instance); |
| - variables.add(variable); |
| - // Now update the substitution to replace Ti with Ii instead |
| - // of dynamic in subsequent rounds. |
| - substituted[i] = bound.substitute2(substituted, variables); |
| - } |
| - |
| - return instantiateType(type, substituted); |
| + TypeParameterElement parameter = typeFormals[i]; |
| + parameterToIndex[parameter.type] = i; |
| + } |
| + |
| + List<DartType> arguments = |
| + typeFormals.map((p) => p.bound ?? DynamicTypeImpl.instance).toList(); |
| + |
| + bool hasProgress = true; |
| + while (hasProgress) { |
| + hasProgress = false; |
| + for (int i = 0; i < count; i++) { |
| + if (!isGround[i]) { |
| + DartType argument = arguments[i]; |
| + List<TypeParameterType> freeParameters = getFreeParameters(argument); |
| + if (freeParameters == null) { |
| + isGround[i] = true; |
| + hasProgress = true; |
| + } else { |
| + List<TypeParameterType> subParameters = []; |
| + List<DartType> subArguments = []; |
| + for (TypeParameterType freeParameter in freeParameters) { |
| + int freeParameterIndex = parameterToIndex[freeParameter]; |
| + if (isGround[freeParameterIndex]) { |
| + DartType value = arguments[freeParameterIndex]; |
| + subParameters.add(freeParameter); |
| + subArguments.add(value); |
| + } |
| + } |
| + if (subParameters.isNotEmpty) { |
| + arguments[i] = argument.substitute2(subArguments, subParameters); |
| + hasProgress = true; |
| + } |
| + } |
| + } |
| + } |
| + } |
| + |
| + // If we stopped making progress, and not all types are ground, |
| + // then the whole type is malbounded and an error should be reported. |
| + if (isGround.any((f) => !f)) { |
| + arguments = new List<DartType>.filled(count, DynamicTypeImpl.instance); |
| + if (hasError != null) { |
| + hasError[0] = true; |
| + } |
| + } |
| + |
| + return instantiateType(type, arguments); |
| } |
| @override |
| @@ -1129,7 +1177,7 @@ abstract class TypeSystem { |
| * classic Dart `dynamic` will be used for all type arguments, whereas |
| * strong mode prefers the actual bound type if it was specified. |
| */ |
| - DartType instantiateToBounds(DartType type); |
| + DartType instantiateToBounds(DartType type, {List<bool> hasError}); |
| /** |
| * Given a [DartType] [type] and a list of types |
| @@ -1424,7 +1472,7 @@ class TypeSystemImpl extends TypeSystem { |
| * Instantiate a parameterized type using `dynamic` for all generic |
| * parameters. Returns the type unchanged if there are no parameters. |
| */ |
| - DartType instantiateToBounds(DartType type) { |
| + DartType instantiateToBounds(DartType type, {List<bool> hasError}) { |
| List<DartType> typeFormals = typeFormalsAsTypes(type); |
| int count = typeFormals.length; |
| if (count > 0) { |