| 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 1adb9af459d4fbb04b0b439043047896878fb293..f68e0317aa31697af4a226edb8419b711d6ef6fa 100644
|
| --- a/pkg/analyzer/lib/src/generated/type_system.dart
|
| +++ b/pkg/analyzer/lib/src/generated/type_system.dart
|
| @@ -144,6 +144,41 @@ class StrongTypeSystemImpl implements TypeSystem {
|
| return fnType.instantiate(inferredTypes);
|
| }
|
|
|
| + /**
|
| + * Given a [FunctionType] [function], of the form
|
| + * <T0 extends B0, ... Tn extends Bn>.F (where Bi is implicitly
|
| + * dynamic if absent, and F is a non-generic function type)
|
| + * compute {I0/T0, ..., In/Tn}F
|
| + * where I_(i+1) = {I0/T0, ..., Ii/Ti, dynamic/T_(i+1)}B_(i+1).
|
| + * That is, we instantiate the generic with its bounds, replacing
|
| + * each Ti in Bi with dynamic to get Ii, and then replacing Ti with
|
| + * Ii in all of the remaining bounds.
|
| + */
|
| + DartType instantiateToBounds(FunctionType function) {
|
| + int count = function.boundTypeParameters.length;
|
| + if (count == 0) {
|
| + return function;
|
| + }
|
| + // We build up a substitution replacing bound parameters with
|
| + // their instantiated bounds, {substituted/variables}
|
| + List<DartType> substituted = new List<DartType>();
|
| + List<DartType> variables = new List<DartType>();
|
| + for (int i = 0; i < count; i++) {
|
| + TypeParameterElement param = function.boundTypeParameters[i];
|
| + DartType bound = param.bound ?? DynamicTypeImpl.instance;
|
| + DartType variable = param.type;
|
| + // For each Ti extends Bi, first compute Ii by replacing
|
| + // Ti in Bi with dynamic (simultaneously replacing all
|
| + // of the previous Tj (j < i) with their instantiated bounds.
|
| + substituted.add(DynamicTypeImpl.instance);
|
| + variables.add(variable);
|
| + // Now update the substitution to replace Ti with Ii instead
|
| + // of dynamic in subsequent rounds.
|
| + substituted[i] = bound.substitute2(substituted, variables);
|
| + }
|
| + return function.instantiate(substituted);
|
| + }
|
| +
|
| @override
|
| bool isAssignableTo(DartType fromType, DartType toType) {
|
| // TODO(leafp): Document the rules in play here
|
| @@ -208,6 +243,9 @@ class StrongTypeSystemImpl implements TypeSystem {
|
| return _isSubtypeOf(leftType, rightType, null);
|
| }
|
|
|
| + /**
|
| + * Guard against loops in the class hierarchy
|
| + */
|
| _GuardedSubtypeChecker<DartType> _guard(
|
| _GuardedSubtypeChecker<DartType> check) {
|
| return (DartType t1, DartType t2, Set<Element> visited) {
|
| @@ -238,7 +276,6 @@ class StrongTypeSystemImpl implements TypeSystem {
|
| return (t.isDynamic && dynamicIsBottom) || t.isBottom;
|
| }
|
|
|
| - // Guard against loops in the class hierarchy
|
| /**
|
| * Check that [f1] is a subtype of [f2].
|
| * [fuzzyArrows] indicates whether or not the f1 and f2 should be
|
| @@ -247,14 +284,22 @@ class StrongTypeSystemImpl implements TypeSystem {
|
| */
|
| bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2,
|
| {bool fuzzyArrows: true}) {
|
| - final r1s = f1.normalParameterTypes;
|
| - final o1s = f1.optionalParameterTypes;
|
| - final n1s = f1.namedParameterTypes;
|
| - final r2s = f2.normalParameterTypes;
|
| - final o2s = f2.optionalParameterTypes;
|
| - final n2s = f2.namedParameterTypes;
|
| - final ret1 = f1.returnType;
|
| - final ret2 = f2.returnType;
|
| + if (!f1.boundTypeParameters.isEmpty) {
|
| + if (f2.boundTypeParameters.isEmpty) {
|
| + f1 = instantiateToBounds(f1);
|
| + return _isFunctionSubtypeOf(f1, f2);
|
| + } else {
|
| + return _isGenericFunctionSubtypeOf(f1, f2, fuzzyArrows: fuzzyArrows);
|
| + }
|
| + }
|
| + final List<DartType> r1s = f1.normalParameterTypes;
|
| + final List<DartType> r2s = f2.normalParameterTypes;
|
| + final List<DartType> o1s = f1.optionalParameterTypes;
|
| + final List<DartType> o2s = f2.optionalParameterTypes;
|
| + final Map<String, DartType> n1s = f1.namedParameterTypes;
|
| + final Map<String, DartType> n2s = f2.namedParameterTypes;
|
| + final DartType ret1 = f1.returnType;
|
| + final DartType ret2 = f2.returnType;
|
|
|
| // A -> B <: C -> D if C <: A and
|
| // either D is void or B <: D
|
| @@ -326,6 +371,54 @@ class StrongTypeSystemImpl implements TypeSystem {
|
| return true;
|
| }
|
|
|
| + /**
|
| + * Check that [f1] is a subtype of [f2] where f1 and f2 are known
|
| + * to be generic function types (both have type parameters)
|
| + * [fuzzyArrows] indicates whether or not the f1 and f2 should be
|
| + * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
|
| + * as bottom).
|
| + */
|
| + bool _isGenericFunctionSubtypeOf(FunctionType f1, FunctionType f2,
|
| + {bool fuzzyArrows: true}) {
|
| + List<TypeParameterElement> params1 = f1.boundTypeParameters;
|
| + List<TypeParameterElement> params2 = f2.boundTypeParameters;
|
| + int count = params1.length;
|
| + if (params2.length != count) {
|
| + return false;
|
| + }
|
| + // We build up a substitution matching up the type parameters
|
| + // from the two types, {variablesFresh/variables1} and
|
| + // {variablesFresh/variables2}
|
| + List<DartType> variables1 = new List<DartType>();
|
| + List<DartType> variables2 = new List<DartType>();
|
| + List<DartType> variablesFresh = new List<DartType>();
|
| + for (int i = 0; i < count; i++) {
|
| + TypeParameterElement p1 = params1[i];
|
| + TypeParameterElement p2 = params2[i];
|
| + TypeParameterElementImpl pFresh =
|
| + new TypeParameterElementImpl(p2.name, -1);
|
| +
|
| + DartType variable1 = p1.type;
|
| + DartType variable2 = p2.type;
|
| + DartType variableFresh = new TypeParameterTypeImpl(pFresh);
|
| +
|
| + variables1.add(variable1);
|
| + variables2.add(variable2);
|
| + variablesFresh.add(variableFresh);
|
| + DartType bound1 = p1.bound ?? DynamicTypeImpl.instance;
|
| + DartType bound2 = p2.bound ?? DynamicTypeImpl.instance;
|
| + bound1 = bound1.substitute2(variablesFresh, variables1);
|
| + bound2 = bound2.substitute2(variablesFresh, variables2);
|
| + pFresh.bound = bound2;
|
| + if (!isSubtypeOf(bound2, bound1)) {
|
| + return false;
|
| + }
|
| + }
|
| + return _isFunctionSubtypeOf(
|
| + f1.instantiate(variablesFresh), f2.instantiate(variablesFresh),
|
| + fuzzyArrows: fuzzyArrows);
|
| + }
|
| +
|
| bool _isInterfaceSubtypeOf(
|
| InterfaceType i1, InterfaceType i2, Set<Element> visited) {
|
| // Guard recursive calls
|
|
|