Chromium Code Reviews| Index: pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart |
| diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart |
| index ef01a9f19d18e7a76d8e3867ff4e8ed37f82adca..e8bc2e3518fc7b6b0f58bbbd3837d43aac0e4dce 100644 |
| --- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart |
| +++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart |
| @@ -149,6 +149,48 @@ class TypeSchemaEnvironment extends TypeEnvironment { |
| return const DynamicType(); |
| } |
| + /// Given a [DartType] [type], if [type] is an uninstantiated |
| + /// parameterized type then instantiate the parameters to their |
| + /// bounds. See the issue for the algorithm description. |
| + /// |
| + /// https://github.com/dart-lang/sdk/issues/27526#issuecomment-260021397 |
| + /// |
| + /// TODO(paulberry) Compute lazily and cache. |
| + DartType instantiateToBounds(DartType type, |
| + {Map<TypeParameter, DartType> knownTypes}) { |
| + List<TypeParameter> typeFormals = _typeFormalsAsParameters(type); |
| + int count = typeFormals.length; |
| + if (count == 0) { |
| + return type; |
| + } |
| + var substitution = <TypeParameter, DartType>{}; |
| + for (TypeParameter parameter in typeFormals) { |
| + // Note: we treat class<T extends Object> as equivalent to class<T>; in |
| + // both cases they instantiate to class<dynamic>. See dartbug.com/29561 |
| + if (_isObjectOrDynamic(parameter.bound)) { |
| + substitution[parameter] = const DynamicType(); |
| + } else { |
| + substitution[parameter] = parameter.bound; |
| + } |
| + } |
| + if (knownTypes != null) { |
| + type = Substitution.fromMap(knownTypes).substituteType(type); |
|
scheglov
2017/05/04 22:09:20
There is some asymmetry here.
This construct also
Paul Berry
2017/05/04 22:14:04
Good point. Switched to substitute() for symmetry
|
| + } |
| + var result = substituteDeep(type, substitution); |
| + if (result != null) return result; |
| + |
| + // Instantiation failed due to a circularity. |
| + // TODO(paulberry): report the error. |
| + // Substitute `dynamic` for all parameters to try to allow compilation to |
| + // continue. Note that [substituteDeep] is destructive of the |
| + // [substitution] so we create a fresh one. |
| + substitution = <TypeParameter, DartType>{}; |
| + for (TypeParameter parameter in typeFormals) { |
| + substitution[parameter] = const DynamicType(); |
| + } |
| + return Substitution.fromMap(substitution).substituteType(type); |
| + } |
| + |
| @override |
| bool isBottom(DartType t) { |
| if (t is UnknownType) { |
| @@ -397,6 +439,23 @@ class TypeSchemaEnvironment extends TypeEnvironment { |
| return hierarchy.getClassicLeastUpperBound(type1, type2); |
| } |
| + bool _isObjectOrDynamic(DartType type) => |
| + type is DynamicType || |
| + (type is InterfaceType && |
| + identical(type.classNode, coreTypes.objectClass)); |
| + |
| + /// Given a [type], returns the [TypeParameter]s corresponding to its formal |
| + /// type parameters (if any). |
| + List<TypeParameter> _typeFormalsAsParameters(DartType type) { |
| + if (type is TypedefType) { |
| + return type.typedefNode.typeParameters; |
| + } else if (type is InterfaceType) { |
| + return type.classNode.typeParameters; |
| + } else { |
| + return const []; |
| + } |
| + } |
| + |
| DartType _typeParameterLeastUpperBound(DartType type1, DartType type2) { |
| // This currently just implements a simple least upper bound to |
| // handle some common cases. It also avoids some termination issues |