| Index: pkg/kernel/lib/type_algebra.dart | 
| diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart | 
| index 19508b1ab630d540caaad498d6bfae759e8c54a4..ce4a553dc4a851e34e003d9e907e98002f8abd15 100644 | 
| --- a/pkg/kernel/lib/type_algebra.dart | 
| +++ b/pkg/kernel/lib/type_algebra.dart | 
| @@ -30,6 +30,18 @@ Map<TypeParameter, DartType> getSubstitutionMap(Supertype type) { | 
| type.classNode.typeParameters, type.typeArguments); | 
| } | 
|  | 
| +Map<TypeParameter, DartType> getUpperBoundSubstitutionMap(Class host) { | 
| +  if (host.typeParameters.isEmpty) return const <TypeParameter, DartType>{}; | 
| +  var result = <TypeParameter, DartType>{}; | 
| +  for (var parameter in host.typeParameters) { | 
| +    result[parameter] = const DynamicType(); | 
| +  } | 
| +  for (var parameter in host.typeParameters) { | 
| +    result[parameter] = substitute(parameter.bound, result); | 
| +  } | 
| +  return result; | 
| +} | 
| + | 
| /// Like [substitute], except when a type in the [substitution] map references | 
| /// another substituted type variable, the mapping for that type is recursively | 
| /// inserted. | 
| @@ -180,6 +192,21 @@ abstract class Substitution { | 
| return new _ClassBottomSubstitution(class_); | 
| } | 
|  | 
| +  /// Substitutes covariant uses of [class_]'s type parameters with the upper | 
| +  /// bound of that type parameter.  Recursive references in the bound have | 
| +  /// been replaced by dynamic. | 
| +  static Substitution upperBoundForClass(Class class_) { | 
| +    if (class_.typeParameters.isEmpty) return _NullSubstitution.instance; | 
| +    var upper = <TypeParameter, DartType>{}; | 
| +    for (var parameter in class_.typeParameters) { | 
| +      upper[parameter] = const DynamicType(); | 
| +    } | 
| +    for (var parameter in class_.typeParameters) { | 
| +      upper[parameter] = substitute(parameter.bound, upper); | 
| +    } | 
| +    return fromUpperAndLowerBounds(upper, {}); | 
| +  } | 
| + | 
| /// Substitutes both variables from [first] and [second], favoring those from | 
| /// [first] if they overlap. | 
| /// | 
|  |