| 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 799ec44bfbdfec6271969111e4fb6b56b558c613..78d246f91a1648b515b6a582df5978ee70eb5138 100644
|
| --- a/pkg/analyzer/lib/src/generated/type_system.dart
|
| +++ b/pkg/analyzer/lib/src/generated/type_system.dart
|
| @@ -45,7 +45,38 @@ class StrongTypeSystemImpl extends TypeSystem {
|
| }
|
|
|
| @override
|
| - bool canPromoteToType(DartType to, DartType from) => isSubtypeOf(to, from);
|
| + bool canPromoteToType(DartType to, DartType from) {
|
| + // Allow promoting to a subtype, for example:
|
| + //
|
| + // f(Base b) {
|
| + // if (b is SubTypeOfBase) {
|
| + // // promote `b` to SubTypeOfBase for this block
|
| + // }
|
| + // }
|
| + //
|
| + // 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;
|
| + }
|
| + // 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.)
|
| + if (from is TypeParameterType) {
|
| + return isSubtypeOf(to, from.resolveToBound(DynamicTypeImpl.instance));
|
| + }
|
| +
|
| + return false;
|
| + }
|
|
|
| @override
|
| FunctionType functionTypeToConcreteType(
|
|
|