| 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 4e575ab17ab0f42447c3363adbe48832d6772dbd..8507bf368cfbd86dbd030a9cab1634db56b936ea 100644
|
| --- a/pkg/analyzer/lib/src/generated/type_system.dart
|
| +++ b/pkg/analyzer/lib/src/generated/type_system.dart
|
| @@ -497,19 +497,25 @@ class StrongTypeSystemImpl extends TypeSystem {
|
| !nonnullableTypes.contains(_getTypeFullyQualifiedName(type));
|
| }
|
|
|
| - /// Check that [f1] is a subtype of [f2] for an override.
|
| + /// Check that [f1] is a subtype of [f2] for a member override.
|
| ///
|
| /// This is different from the normal function subtyping in two ways:
|
| /// - we know the function types are strict arrows,
|
| /// - it allows opt-in covariant parameters.
|
| bool isOverrideSubtypeOf(FunctionType f1, FunctionType f2) {
|
| - return FunctionTypeImpl.relate(
|
| - f1,
|
| - f2,
|
| - (t1, t2, t1Covariant, _) =>
|
| - isSubtypeOf(t2, t1) || t1Covariant && isSubtypeOf(t1, t2),
|
| - instantiateToBounds,
|
| - returnRelation: isSubtypeOf);
|
| + return FunctionTypeImpl.relate(f1, f2, isSubtypeOf, instantiateToBounds,
|
| + parameterRelation: isOverrideSubtypeOfParameter);
|
| + }
|
| +
|
| + /// Check that parameter [p2] is a subtype of [p1], given that we are
|
| + /// checking `f1 <: f2` where `p1` is a parameter of `f1` and `p2` is a
|
| + /// parameter of `f2`.
|
| + ///
|
| + /// Parameters are contravariant, so we must check `p2 <: p1` to
|
| + /// determine if `f1 <: f2`. This is used by [isOverrideSubtypeOf].
|
| + bool isOverrideSubtypeOfParameter(ParameterElement p1, ParameterElement p2) {
|
| + return isSubtypeOf(p2.type, p1.type) ||
|
| + p1.isCovariant && isSubtypeOf(p1.type, p2.type);
|
| }
|
|
|
| @override
|
| @@ -789,13 +795,10 @@ class StrongTypeSystemImpl extends TypeSystem {
|
| /// that dynamic parameters of f1 and f2 are treated as bottom.
|
| bool _isFunctionSubtypeOf(
|
| FunctionType f1, FunctionType f2, Set<TypeImpl> visitedTypes) {
|
| - return FunctionTypeImpl.relate(
|
| - f1,
|
| - f2,
|
| - (t1, t2, _, __) =>
|
| - _isSubtypeOf(t2, t1, visitedTypes, dynamicIsBottom: true),
|
| - instantiateToBounds,
|
| - returnRelation: isSubtypeOf);
|
| + return FunctionTypeImpl.relate(f1, f2, isSubtypeOf, instantiateToBounds,
|
| + parameterRelation: (p1, p2) => _isSubtypeOf(
|
| + p2.type, p1.type, visitedTypes,
|
| + dynamicIsBottom: true));
|
| }
|
|
|
| bool _isInterfaceSubtypeOf(
|
| @@ -2176,14 +2179,16 @@ class _GenericInferrer {
|
| FunctionTypeImpl.relate(
|
| t1,
|
| t2,
|
| - (t1, t2, _, __) {
|
| - _matchSubtypeOf(t2, t1, null, origin,
|
| - covariant: !covariant, dynamicIsBottom: true);
|
| + (t1, t2) {
|
| + // TODO(jmesserly): should we flip covariance when we're relating
|
| + // type formal bounds? They're more like parameters.
|
| + matchSubtype(t1, t2);
|
| return true;
|
| },
|
| _typeSystem.instantiateToBounds,
|
| - returnRelation: (t1, t2) {
|
| - matchSubtype(t1, t2);
|
| + parameterRelation: (p1, p2) {
|
| + _matchSubtypeOf(p2.type, p1.type, null, origin,
|
| + covariant: !covariant, dynamicIsBottom: true);
|
| return true;
|
| });
|
| }
|
|
|