| Index: sdk/lib/_internal/compiler/implementation/typechecker.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
|
| index 965d95ff54392f7a13e8396fcf5e667a9da9d4e8..614cae34d74212ba749f08d253e50ebad3ea25e7 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
|
| @@ -897,6 +897,41 @@ class TypeCheckerVisitor extends Visitor<DartType> {
|
| return type;
|
| }
|
|
|
| + /// Compute a version of [shownType] that is more specific that [knownType].
|
| + /// This is used to provided better hints when trying to promote a supertype
|
| + /// to a raw subtype. For instance trying to promote `Iterable<int>` to `List`
|
| + /// we suggest the use of `List<int>`, which would make promotion valid.
|
| + DartType computeMoreSpecificType(DartType shownType,
|
| + DartType knownType) {
|
| + if (knownType.kind == TypeKind.INTERFACE &&
|
| + shownType.kind == TypeKind.INTERFACE &&
|
| + types.isSubtype(shownType.asRaw(), knownType)) {
|
| + // For the comments in the block, assume the hierarchy:
|
| + // class A<T, V> {}
|
| + // class B<S, U> extends A<S, int> {}
|
| + // and a promotion from a [knownType] of `A<double, int>` to a
|
| + // [shownType] of `B`.
|
| + InterfaceType knownInterfaceType = knownType;
|
| + ClassElement shownClass = shownType.element;
|
| +
|
| + // Compute `B<double, dynamic>` as the subtype of `A<double, int>` using
|
| + // the relation between `A<S, int>` and `A<double, int>`.
|
| + MoreSpecificSubtypeVisitor visitor =
|
| + new MoreSpecificSubtypeVisitor(compiler);
|
| + InterfaceType shownTypeGeneric = visitor.computeMoreSpecific(
|
| + shownClass, knownInterfaceType);
|
| +
|
| + if (shownTypeGeneric != null &&
|
| + types.isMoreSpecific(shownTypeGeneric, knownType)) {
|
| + // This should be the case but we double-check.
|
| + // TODO(johnniwinther): Ensure that we don't suggest malbounded types.
|
| + return shownTypeGeneric;
|
| + }
|
| + }
|
| + return null;
|
| +
|
| + }
|
| +
|
| DartType visitSend(Send node) {
|
| Element element = elements[node];
|
|
|
| @@ -953,13 +988,30 @@ class TypeCheckerVisitor extends Visitor<DartType> {
|
| new TypePromotion(node, variable, shownType);
|
| if (!types.isMoreSpecific(shownType, knownType)) {
|
| String variableName = variable.name;
|
| - // TODO(johnniwinther): Provide a how-to-fix in the case one tries
|
| - // to promote a generic type to a raw type.
|
| - typePromotion.addHint(node,
|
| - MessageKind.NOT_MORE_SPECIFIC,
|
| - {'variableName': variableName,
|
| - 'shownType': shownType,
|
| - 'knownType': knownType});
|
| + if (!types.isSubtype(shownType, knownType)) {
|
| + typePromotion.addHint(node,
|
| + MessageKind.NOT_MORE_SPECIFIC_SUBTYPE,
|
| + {'variableName': variableName,
|
| + 'shownType': shownType,
|
| + 'knownType': knownType});
|
| + } else {
|
| + DartType shownTypeSuggestion =
|
| + computeMoreSpecificType(shownType, knownType);
|
| + if (shownTypeSuggestion != null) {
|
| + typePromotion.addHint(node,
|
| + MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
|
| + {'variableName': variableName,
|
| + 'shownType': shownType,
|
| + 'shownTypeSuggestion': shownTypeSuggestion,
|
| + 'knownType': knownType});
|
| + } else {
|
| + typePromotion.addHint(node,
|
| + MessageKind.NOT_MORE_SPECIFIC,
|
| + {'variableName': variableName,
|
| + 'shownType': shownType,
|
| + 'knownType': knownType});
|
| + }
|
| + }
|
| }
|
| showTypePromotion(node, typePromotion);
|
| }
|
|
|