| Index: lib/compiler/implementation/typechecker.dart
|
| diff --git a/lib/compiler/implementation/typechecker.dart b/lib/compiler/implementation/typechecker.dart
|
| index f5a600fa3e08f04b40f497efe977c7630b43dbe0..440c60b7f974d75817b8d7a0a1af6f96da027bef 100644
|
| --- a/lib/compiler/implementation/typechecker.dart
|
| +++ b/lib/compiler/implementation/typechecker.dart
|
| @@ -27,14 +27,64 @@ class TypeCheckerTask extends CompilerTask {
|
| interface Type {
|
| SourceString get name();
|
| Element get element();
|
| +
|
| + /**
|
| + * 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.
|
| + */
|
| + Type subst(Link<Type> arguments, List<Type> parameters);
|
| }
|
|
|
| +/**
|
| + * Represents a type variable, that is the type parameters of a class
|
| + * or interface type. For example, in class Array<E> { ... }`,
|
| + * E is a type variable.
|
| + *
|
| + * Each class/interface should have its own unique type variables,
|
| + * one for each type parameter. A class/interface with type parameters
|
| + * is said to be parameterized or generic.
|
| + *
|
| + * Non-static members, constructors, and factories of generic
|
| + * class/interface can refer to type variables of the current class
|
| + * (not of supertypes).
|
| + *
|
| + * When using a generic type, also known as an application or
|
| + * instantiation of the type, the actual type arguments should be
|
| + * substituted for the type variables in the class declaration.
|
| + *
|
| + * For example, given a box, `class Box<T> { T value; }`, the
|
| + * type of the expression `new Box<String>().value` is
|
| + * [String] because we must substitute `String` for the
|
| + * the type variable `T`.
|
| + */
|
| class TypeVariableType implements Type {
|
| final SourceString name;
|
| TypeVariableElement element;
|
| TypeVariableType(this.name, [this.element]);
|
|
|
| - toString() => name.slowToString();
|
| + Type subst(Link<Type> arguments, List<Type> parameters) {
|
| + if (arguments.isEmpty()) {
|
| + // Return fast on empty substitutions.
|
| + return this;
|
| + }
|
| + Link<Type> argumentLink = arguments;
|
| + Iterator<Type> parameterIterator = parameters.iterator();
|
| + while (!argumentLink.isEmpty() && parameterIterator.hasNext()) {
|
| + Type parameter = parameterIterator.next();
|
| + Type argument = argumentLink.head;
|
| + if (parameter === this) {
|
| + return argument;
|
| + }
|
| + argumentLink = argumentLink.tail;
|
| + }
|
| + // The type variable was not substituted.
|
| + return this;
|
| + }
|
| +
|
| + String toString() => name.slowToString();
|
| }
|
|
|
| /**
|
| @@ -57,6 +107,11 @@ class StatementType implements Type {
|
| return (this === other) ? this : MAYBE_RETURNING;
|
| }
|
|
|
| + Type subst(Link<Type> arguments, List<Type> parameters) {
|
| + // Statement types are not substitutable.
|
| + return this;
|
| + }
|
| +
|
| String toString() => stringName;
|
| }
|
|
|
| @@ -65,7 +120,12 @@ class VoidType implements Type {
|
| SourceString get name() => element.name;
|
| final VoidElement element;
|
|
|
| - toString() => name.slowToString();
|
| + Type subst(Link<Type> arguments, List<Type> parameters) {
|
| + // Void cannot be substituted.
|
| + return this;
|
| + }
|
| +
|
| + String toString() => name.slowToString();
|
| }
|
|
|
| class InterfaceType implements Type {
|
| @@ -77,7 +137,34 @@ class InterfaceType implements Type {
|
|
|
| SourceString get name() => element.name;
|
|
|
| - toString() {
|
| + Type subst(Link<Type> replacements, List<Type> parameters) {
|
| + if (arguments.isEmpty()) {
|
| + // Return fast on non-generic types.
|
| + return this;
|
| + }
|
| + if (replacements.isEmpty()) {
|
| + // Return fast on empty substitutions.
|
| + return this;
|
| + }
|
| + bool changed = false;
|
| + var argumentsBuilder = new LinkBuilder<Type>();
|
| + Link<Type> argument = arguments;
|
| + while (!argument.isEmpty()) {
|
| + var replacement = argument.head.subst(replacements, parameters);
|
| + if (!changed && replacement !== argument.head) {
|
| + changed = true;
|
| + }
|
| + argumentsBuilder.addLast(replacement);
|
| + argument = argument.tail;
|
| + }
|
| + if (changed) {
|
| + // Create a new type only if necessary.
|
| + return new InterfaceType(element, argumentsBuilder.toLink());
|
| + }
|
| + return this;
|
| + }
|
| +
|
| + String toString() {
|
| StringBuffer sb = new StringBuffer();
|
| sb.add(name.slowToString());
|
| if (!arguments.isEmpty()) {
|
| @@ -97,7 +184,32 @@ class FunctionType implements Type {
|
| const FunctionType(Type this.returnType, Link<Type> this.parameterTypes,
|
| Element this.element);
|
|
|
| - toString() {
|
| + Type subst(Link<Type> arguments, List<Type> parameters) {
|
| + if (arguments.isEmpty()) {
|
| + // Return fast on empty substitutions.
|
| + return this;
|
| + }
|
| + var newReturnType = returnType.subst(arguments, parameters);
|
| + bool changed = newReturnType !== returnType;
|
| + var parameterBuilder = new LinkBuilder<Type>();
|
| + Link<Type> parameterType = parameterTypes;
|
| + while (!parameterType.isEmpty()) {
|
| + var replacement = parameterType.head.subst(arguments, parameters);
|
| + if (!changed && replacement !== parameterType.head) {
|
| + changed = true;
|
| + }
|
| + parameterBuilder.addLast(replacement);
|
| + parameterType = parameterType.tail;
|
| + }
|
| + if (changed) {
|
| + // Create a new type only if necessary.
|
| + return new FunctionType(newReturnType, parameterBuilder.toLink(),
|
| + element);
|
| + }
|
| + return this;
|
| + }
|
| +
|
| + String toString() {
|
| StringBuffer sb = new StringBuffer();
|
| bool first = true;
|
| sb.add('(');
|
|
|