| Index: pkg/compiler/lib/src/elements/types.dart
|
| diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
|
| index e61b313ce0b764323a69be838e30bdd6aec46619..946a03590ed907810a83c7cab589a6e6c23d143a 100644
|
| --- a/pkg/compiler/lib/src/elements/types.dart
|
| +++ b/pkg/compiler/lib/src/elements/types.dart
|
| @@ -66,6 +66,17 @@ abstract class DartType {
|
| /// Applies [f] to each occurence of a [ResolutionTypeVariableType] within
|
| /// this type.
|
| void forEachTypeVariable(f(TypeVariableType variable)) {}
|
| +
|
| + /// Performs the substitution `[arguments[i]/parameters[i]]this`.
|
| + ///
|
| + /// The notation is known from this lambda calculus rule:
|
| + ///
|
| + /// (lambda x.e0)e1 -> [e1/x]e0.
|
| + ///
|
| + /// See [TypeVariableType] for a motivation for this method.
|
| + ///
|
| + /// Invariant: There must be the same number of [arguments] and [parameters].
|
| + DartType subst(List<DartType> arguments, List<DartType> parameters);
|
| }
|
|
|
| class InterfaceType extends DartType {
|
| @@ -81,6 +92,25 @@ class InterfaceType extends DartType {
|
| typeArguments.forEach((type) => type.forEachTypeVariable(f));
|
| }
|
|
|
| + InterfaceType subst(List<DartType> arguments, List<DartType> parameters) {
|
| + if (typeArguments.isEmpty) {
|
| + // Return fast on non-generic types.
|
| + return this;
|
| + }
|
| + if (parameters.isEmpty) {
|
| + assert(arguments.isEmpty);
|
| + // Return fast on empty substitutions.
|
| + return this;
|
| + }
|
| + List<DartType> newTypeArguments =
|
| + _substTypes(typeArguments, arguments, parameters);
|
| + if (!identical(typeArguments, newTypeArguments)) {
|
| + // Create a new type only if necessary.
|
| + return new InterfaceType(element, newTypeArguments);
|
| + }
|
| + return this;
|
| + }
|
| +
|
| int get hashCode {
|
| int hash = element.hashCode;
|
| for (DartType argument in typeArguments) {
|
| @@ -128,6 +158,20 @@ class TypeVariableType extends DartType {
|
| f(this);
|
| }
|
|
|
| + DartType subst(List<DartType> arguments, List<DartType> parameters) {
|
| + assert(arguments.length == parameters.length);
|
| + if (parameters.isEmpty) {
|
| + // Return fast on empty substitutions.
|
| + return this;
|
| + }
|
| + int index = parameters.indexOf(this);
|
| + if (index != -1) {
|
| + return arguments[index];
|
| + }
|
| + // The type variable was not substituted.
|
| + return this;
|
| + }
|
| +
|
| int get hashCode => 17 * element.hashCode;
|
|
|
| bool operator ==(other) {
|
| @@ -143,6 +187,11 @@ class VoidType extends DartType {
|
|
|
| bool get isVoid => true;
|
|
|
| + DartType subst(List<DartType> arguments, List<DartType> parameters) {
|
| + // `void` cannot be substituted.
|
| + return this;
|
| + }
|
| +
|
| int get hashCode => 6007;
|
|
|
| String toString() => 'void';
|
| @@ -157,6 +206,11 @@ class DynamicType extends DartType {
|
| @override
|
| bool get treatAsDynamic => true;
|
|
|
| + DartType subst(List<DartType> arguments, List<DartType> parameters) {
|
| + // `dynamic` cannot be substituted.
|
| + return this;
|
| + }
|
| +
|
| int get hashCode => 91;
|
|
|
| String toString() => 'dynamic';
|
| @@ -197,6 +251,34 @@ class FunctionType extends DartType {
|
|
|
| bool get isFunctionType => true;
|
|
|
| + DartType subst(List<DartType> arguments, List<DartType> parameters) {
|
| + if (parameters.isEmpty) {
|
| + assert(arguments.isEmpty);
|
| + // Return fast on empty substitutions.
|
| + return this;
|
| + }
|
| + DartType newReturnType = returnType.subst(arguments, parameters);
|
| + bool changed = !identical(newReturnType, returnType);
|
| + List<DartType> newParameterTypes =
|
| + _substTypes(parameterTypes, arguments, parameters);
|
| + List<DartType> newOptionalParameterTypes =
|
| + _substTypes(optionalParameterTypes, arguments, parameters);
|
| + List<DartType> newNamedParameterTypes =
|
| + _substTypes(namedParameterTypes, arguments, parameters);
|
| + if (!changed &&
|
| + (!identical(parameterTypes, newParameterTypes) ||
|
| + !identical(optionalParameterTypes, newOptionalParameterTypes) ||
|
| + !identical(namedParameterTypes, newNamedParameterTypes))) {
|
| + changed = true;
|
| + }
|
| + if (changed) {
|
| + // Create a new type only if necessary.
|
| + return new FunctionType(newReturnType, newParameterTypes,
|
| + newOptionalParameterTypes, namedParameters, newNamedParameterTypes);
|
| + }
|
| + return this;
|
| + }
|
| +
|
| int get hashCode {
|
| int hash = 3 * returnType.hashCode;
|
| for (DartType parameter in parameterTypes) {
|
| @@ -271,3 +353,23 @@ class FunctionType extends DartType {
|
| return sb.toString();
|
| }
|
| }
|
| +
|
| +/// Helper method for performing substitution of a list of types.
|
| +///
|
| +/// If no types are changed by the substitution, the [types] is returned
|
| +/// instead of a newly created list.
|
| +List<DartType> _substTypes(
|
| + List<DartType> types, List<DartType> arguments, List<DartType> parameters) {
|
| + bool changed = false;
|
| + List<DartType> result =
|
| + new List<DartType>.generate(types.length, (int index) {
|
| + DartType type = types[index];
|
| + DartType argument = type.subst(arguments, parameters);
|
| + if (!changed && !identical(argument, type)) {
|
| + changed = true;
|
| + }
|
| + return argument;
|
| + });
|
| + // Use the new List only if necessary.
|
| + return changed ? result : types;
|
| +}
|
|
|