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 c8c1fe652f592e4f2370799c199f87c3a6652164..5d08b0aeb19d421856da7acd06647a676799748b 100644 |
--- a/pkg/analyzer/lib/src/generated/type_system.dart |
+++ b/pkg/analyzer/lib/src/generated/type_system.dart |
@@ -13,6 +13,7 @@ import 'package:analyzer/dart/element/element.dart'; |
import 'package:analyzer/dart/element/type.dart'; |
import 'package:analyzer/error/listener.dart' show ErrorReporter; |
import 'package:analyzer/src/dart/element/element.dart'; |
+import 'package:analyzer/src/dart/element/member.dart' show TypeParameterMember; |
import 'package:analyzer/src/dart/element/type.dart'; |
import 'package:analyzer/src/error/codes.dart' show StrongModeCode; |
import 'package:analyzer/src/generated/engine.dart' |
@@ -170,7 +171,7 @@ class StrongTypeSystemImpl extends TypeSystem { |
} |
@override |
- bool canPromoteToType(DartType to, DartType from) { |
+ DartType tryPromoteToType(DartType to, DartType from) { |
// Allow promoting to a subtype, for example: |
// |
// f(Base b) { |
@@ -182,25 +183,17 @@ class StrongTypeSystemImpl extends TypeSystem { |
// This allows the variable to be used wherever the supertype (here `Base`) |
// is expected, while gaining a more precise type. |
if (isSubtypeOf(to, from)) { |
- return true; |
+ return to; |
} |
- // For a type parameter `T extends U`, allow promoting from the upper bound |
- // `U` to `S` where `S <: U`. |
- // |
- // This does restrict the variable, because `S </: T`, it can no longer be |
- // used as a `T` without another cast. |
- // |
- // However the members you could access from a variable of type `T`, were |
- // already those on the upper bound `U`. So all members on `U` will be |
- // accessible, as well as those on `S`. Pragmatically this feels like a |
- // useful enough trade-off to allow promotion. |
- // |
- // (In general we would need union types to support this feature precisely.) |
+ // For a type parameter `T extends U`, allow promoting the upper bound |
+ // `U` to `S` where `S <: U`, yielding a type parameter `T extends S`. |
if (from is TypeParameterType) { |
- return isSubtypeOf(to, from.resolveToBound(DynamicTypeImpl.instance)); |
+ if (isSubtypeOf(to, from.resolveToBound(DynamicTypeImpl.instance))) { |
+ return new TypeParameterMember(from.element, null, to).type; |
+ } |
} |
- return false; |
+ return null; |
} |
@override |
@@ -922,7 +915,9 @@ class StrongTypeSystemImpl extends TypeSystem { |
// True if T == S |
// Or true if bound of S is S' and S' <: T |
if (t1 is TypeParameterType) { |
- if (t1 == t2) { |
+ if (t2 is TypeParameterType && |
+ t1.definition == t2.definition && |
+ guardedSubtype(t1.bound, t2.bound, visited)) { |
return true; |
} |
if (guardedInferTypeParameter(t1, t2, visited)) { |
@@ -1051,15 +1046,18 @@ class StrongTypeSystemImpl extends TypeSystem { |
*/ |
abstract class TypeSystem { |
/** |
- * Returns `true` if we can promote to the first type from the second type. |
+ * Tries to promote from the first type from the second type, and returns the |
+ * promoted type if it succeeds, otherwise null. |
* |
- * In the standard Dart type system, it is not possible to promote from or to |
+ * In the Dart 1 type system, it is not possible to promote from or to |
* `dynamic`, and we must be promoting to a more specific type, see |
- * [isMoreSpecificThan]. |
+ * [isMoreSpecificThan]. Also it will always return the promote [to] type or |
+ * null. |
* |
- * In strong mode, this is equivalent to [isSubtypeOf]. |
+ * In strong mode, this can potentially return a different type, see |
+ * the override in [StrongTypeSystemImpl]. |
*/ |
- bool canPromoteToType(DartType to, DartType from); |
+ DartType tryPromoteToType(DartType to, DartType from); |
/** |
* Make a function type concrete. |
@@ -1425,11 +1423,15 @@ class TypeSystemImpl extends TypeSystem { |
TypeSystemImpl(); |
@override |
- bool canPromoteToType(DartType to, DartType from) { |
+ DartType tryPromoteToType(DartType to, DartType from) { |
// Declared type should not be "dynamic". |
// Promoted type should not be "dynamic". |
// Promoted type should be more specific than declared. |
- return !from.isDynamic && !to.isDynamic && to.isMoreSpecificThan(from); |
+ if (!from.isDynamic && !to.isDynamic && to.isMoreSpecificThan(from)) { |
+ return to; |
+ } else { |
+ return null; |
+ } |
} |
@override |