Index: sdk/lib/_internal/compiler/implementation/dart_types.dart |
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart |
index cd9dff9ac36e8ce4933fb55c583aa2159ea3f573..a4603f0f6cbc10415db4b88911a20e4c907ac5f3 100644 |
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart |
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart |
@@ -1249,11 +1249,25 @@ class Types { |
this.moreSpecificVisitor, this.subtypeVisitor, |
this.potentialSubtypeVisitor); |
- /** Returns true if t is more specific than s */ |
+ /** Returns true if [t] is more specific than [s]. */ |
bool isMoreSpecific(DartType t, DartType s) { |
return moreSpecificVisitor.isMoreSpecific(t, s); |
} |
+ /** |
+ * Returns the most specific type of [t] and [s] or `null` if neither is more |
+ * specific than the other. |
+ */ |
+ DartType getMostSpecific(DartType t, DartType s) { |
+ if (isMoreSpecific(t, s)) { |
+ return t; |
+ } else if (isMoreSpecific(s, t)) { |
+ return s; |
+ } else { |
+ return null; |
+ } |
+ } |
+ |
/** Returns true if t is a subtype of s */ |
bool isSubtype(DartType t, DartType s) { |
return subtypeVisitor.isSubtype(t, s); |
@@ -1652,3 +1666,97 @@ class PotentialSubtypeVisitor extends SubtypeVisitor { |
return super.isSubtype(t, s); |
} |
} |
+ |
+/// Visitor used to compute an instantiation of a generic type that is more |
+/// specific than a given type. |
+/// |
+/// The visitor tries to compute constraints for all type variables in the |
+/// visited type by structurally matching it with the argument type. If the |
+/// constraints are too complex or the two types are too different, `false` |
+/// is returned. Otherwise, the [constraintMap] holds the valid constraints. |
+class MoreSpecificSubtypeVisitor extends DartTypeVisitor<bool, DartType> { |
+ final Compiler compiler; |
+ Map<TypeVariableType, DartType> constraintMap; |
+ |
+ MoreSpecificSubtypeVisitor(Compiler this.compiler); |
+ |
+ /// Compute an instance of [element] which is more specific than [supertype]. |
+ /// If no instance is found, `null` is returned. |
+ /// |
+ /// Note that this computation is a heuristic. It does not find a suggestion |
+ /// in all possible cases. |
+ InterfaceType computeMoreSpecific(ClassElement element, |
+ InterfaceType supertype) { |
+ InterfaceType supertypeInstance = |
+ element.thisType.asInstanceOf(supertype.element); |
+ if (supertypeInstance == null) return null; |
+ |
+ constraintMap = new Map<TypeVariableType, DartType>(); |
+ element.typeVariables.forEach((TypeVariableType typeVariable) { |
+ constraintMap[typeVariable] = compiler.types.dynamicType; |
+ }); |
+ if (supertypeInstance.accept(this, supertype)) { |
+ LinkBuilder<DartType> typeArguments = new LinkBuilder<DartType>(); |
+ element.typeVariables.forEach((TypeVariableType typeVariable) { |
+ typeArguments.addLast(constraintMap[typeVariable]); |
+ }); |
+ return element.thisType._createType(typeArguments.toLink()); |
+ } |
+ return null; |
+ } |
+ |
+ bool visitType(DartType type, DartType argument) { |
+ return compiler.types.isMoreSpecific(type, argument); |
+ } |
+ |
+ bool visitTypes(Link<DartType> a, Link<DartType> b) { |
+ while (!a.isEmpty && !b.isEmpty) { |
+ if (!a.head.accept(this, b.head)) return false; |
+ a = a.tail; |
+ b = b.tail; |
+ } |
+ return a.isEmpty && b.isEmpty; |
+ } |
+ |
+ bool visitTypeVariableType(TypeVariableType type, DartType argument) { |
+ DartType constraint = |
+ compiler.types.getMostSpecific(constraintMap[type], argument); |
+ constraintMap[type] = constraint; |
+ return constraint != null; |
+ } |
+ |
+ bool visitFunctionType(FunctionType type, DartType argument) { |
+ if (argument is FunctionType) { |
+ if (type.parameterTypes.slowLength() != |
+ argument.parameterTypes.slowLength()) { |
+ return false; |
+ } |
+ if (type.optionalParameterTypes.slowLength() != |
+ argument.optionalParameterTypes.slowLength()) { |
+ return false; |
+ } |
+ if (type.namedParameters != argument.namedParameters) { |
+ return false; |
+ } |
+ |
+ if (!type.returnType.accept(this, argument.returnType)) return false; |
+ if (visitTypes(type.parameterTypes, argument.parameterTypes)) { |
+ return false; |
+ } |
+ if (visitTypes(type.optionalParameterTypes, |
+ argument.optionalParameterTypes)) { |
+ return false; |
+ } |
+ return visitTypes(type.namedParameterTypes, argument.namedParameterTypes); |
+ } |
+ return false; |
+ } |
+ |
+ bool visitGenericType(GenericType type, DartType argument) { |
+ if (argument is GenericType) { |
+ if (type.element != argument.element) return false; |
+ return visitTypes(type.typeArguments, argument.typeArguments); |
+ } |
+ return false; |
+ } |
+} |