| Index: sdk/lib/_internal/compiler/implementation/typechecker.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
|
| index 9572643066b468c27a90d0a62e17b7200f0a6716..7a8e0c3a2a74a2db4016ff1f76a15572950fd0f9 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
|
| @@ -60,6 +60,19 @@ abstract class DartType {
|
| 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.
|
| + *
|
| + * Invariant: There must be the same number of [arguments] and [parameters].
|
| + */
|
| + DartType subst(Link<DartType> arguments, Link<DartType> parameters);
|
| +
|
| + /**
|
| * Returns the unaliased type of this type.
|
| *
|
| * The unaliased type of a typedef'd type is the unaliased type to which its
|
| @@ -76,6 +89,28 @@ abstract class DartType {
|
| DartType asRaw() => this;
|
| }
|
|
|
| +/**
|
| + * Represents a type variable, that is the type parameters of a class type.
|
| + *
|
| + * For example, in [: class Array<E> { ... } :], E is a type variable.
|
| + *
|
| + * Each class should have its own unique type variables, one for each type
|
| + * parameter. A class 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 extends DartType {
|
| final TypeVariableElement element;
|
|
|
| @@ -85,6 +120,29 @@ class TypeVariableType extends DartType {
|
|
|
| SourceString get name => element.name;
|
|
|
| + DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
|
| + if (parameters.isEmpty) {
|
| + assert(arguments.isEmpty);
|
| + // Return fast on empty substitutions.
|
| + return this;
|
| + }
|
| + Link<DartType> parameterLink = parameters;
|
| + Link<DartType> argumentLink = arguments;
|
| + while (!argumentLink.isEmpty && !parameterLink.isEmpty) {
|
| + TypeVariableType parameter = parameterLink.head;
|
| + DartType argument = argumentLink.head;
|
| + if (parameter == this) {
|
| + assert(argumentLink.tail.isEmpty == parameterLink.tail.isEmpty);
|
| + return argument;
|
| + }
|
| + parameterLink = parameterLink.tail;
|
| + argumentLink = argumentLink.tail;
|
| + }
|
| + assert(argumentLink.isEmpty && parameterLink.isEmpty);
|
| + // The type variable was not substituted.
|
| + return this;
|
| + }
|
| +
|
| DartType unalias(Compiler compiler) => this;
|
|
|
| int get hashCode => 17 * element.hashCode;
|
| @@ -120,6 +178,11 @@ class StatementType extends DartType {
|
| return (identical(this, other)) ? this : MAYBE_RETURNING;
|
| }
|
|
|
| + DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
|
| + // Statement types are not substitutable.
|
| + return this;
|
| + }
|
| +
|
| DartType unalias(Compiler compiler) => this;
|
|
|
| int get hashCode => 17 * stringName.hashCode;
|
| @@ -141,6 +204,11 @@ class VoidType extends DartType {
|
|
|
| final VoidElement element;
|
|
|
| + DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
|
| + // Void cannot be substituted.
|
| + return this;
|
| + }
|
| +
|
| DartType unalias(Compiler compiler) => this;
|
|
|
| int get hashCode => 1729;
|
| @@ -150,12 +218,38 @@ class VoidType extends DartType {
|
| String toString() => name.slowToString();
|
| }
|
|
|
| +/**
|
| + * Helper method for performing substitution of a linked list of types.
|
| + *
|
| + * If no types are changed by the substitution, the [types] is returned instead
|
| + * of a newly created linked list.
|
| + */
|
| +Link<DartType> substTypes(Link<DartType> types,
|
| + Link<DartType> arguments, Link<DartType> parameters) {
|
| + bool changed = false;
|
| + var builder = new LinkBuilder<DartType>();
|
| + Link<DartType> typeLink = types;
|
| + while (!typeLink.isEmpty) {
|
| + var argument = typeLink.head.subst(arguments, parameters);
|
| + if (!changed && !identical(argument, typeLink.head)) {
|
| + changed = true;
|
| + }
|
| + builder.addLast(argument);
|
| + typeLink = typeLink.tail;
|
| + }
|
| + if (changed) {
|
| + // Create a new link only if necessary.
|
| + return builder.toLink();
|
| + }
|
| + return types;
|
| +}
|
| +
|
| class InterfaceType extends DartType {
|
| final Element element;
|
| - final Link<DartType> arguments;
|
| + final Link<DartType> typeArguments;
|
|
|
| InterfaceType(this.element,
|
| - [this.arguments = const Link<DartType>()]) {
|
| + [this.typeArguments = const Link<DartType>()]) {
|
| assert(invariant(element, element.isDeclaration));
|
| }
|
|
|
| @@ -163,14 +257,33 @@ class InterfaceType extends DartType {
|
|
|
| SourceString get name => element.name;
|
|
|
| + DartType subst(Link<DartType> arguments, Link<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;
|
| + }
|
| + Link<DartType> newTypeArguments =
|
| + substTypes(typeArguments, arguments, parameters);
|
| + if (!identical(typeArguments, newTypeArguments)) {
|
| + // Create a new type only if necessary.
|
| + return new InterfaceType(element, newTypeArguments);
|
| + }
|
| + return this;
|
| + }
|
| +
|
| DartType unalias(Compiler compiler) => this;
|
|
|
| String toString() {
|
| StringBuffer sb = new StringBuffer();
|
| sb.add(name.slowToString());
|
| - if (!arguments.isEmpty) {
|
| + if (!typeArguments.isEmpty) {
|
| sb.add('<');
|
| - arguments.printOn(sb, ', ');
|
| + typeArguments.printOn(sb, ', ');
|
| sb.add('>');
|
| }
|
| return sb.toString();
|
| @@ -178,7 +291,7 @@ class InterfaceType extends DartType {
|
|
|
| int get hashCode {
|
| int hash = element.hashCode;
|
| - for (Link<DartType> arguments = this.arguments;
|
| + for (Link<DartType> arguments = this.typeArguments;
|
| !arguments.isEmpty;
|
| arguments = arguments.tail) {
|
| int argumentHash = arguments.head != null ? arguments.head.hashCode : 0;
|
| @@ -190,11 +303,11 @@ class InterfaceType extends DartType {
|
| bool operator ==(other) {
|
| if (other is !InterfaceType) return false;
|
| if (!identical(element, other.element)) return false;
|
| - return arguments == other.arguments;
|
| + return typeArguments == other.typeArguments;
|
| }
|
|
|
| InterfaceType asRaw() {
|
| - if (arguments.isEmpty) return this;
|
| + if (typeArguments.isEmpty) return this;
|
| return new InterfaceType(element);
|
| }
|
| }
|
| @@ -211,6 +324,25 @@ class FunctionType extends DartType {
|
|
|
| TypeKind get kind => TypeKind.FUNCTION;
|
|
|
| + DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
|
| + if (parameters.isEmpty) {
|
| + assert(arguments.isEmpty);
|
| + // Return fast on empty substitutions.
|
| + return this;
|
| + }
|
| + var newReturnType = returnType.subst(arguments, parameters);
|
| + bool changed = !identical(newReturnType, returnType);
|
| + var newParameterTypes = substTypes(parameterTypes, arguments, parameters);
|
| + if (!changed && !identical(parameterTypes, newParameterTypes)) {
|
| + changed = true;
|
| + }
|
| + if (changed) {
|
| + // Create a new type only if necessary.
|
| + return new FunctionType(newReturnType, newParameterTypes, element);
|
| + }
|
| + return this;
|
| + }
|
| +
|
| DartType unalias(Compiler compiler) => this;
|
|
|
| String toString() {
|
| @@ -259,15 +391,35 @@ class TypedefType extends DartType {
|
| final Link<DartType> typeArguments;
|
|
|
| const TypedefType(this.element,
|
| - [this.typeArguments = const Link<DartType>()]);
|
| + [this.typeArguments = const Link<DartType>()]);
|
|
|
| TypeKind get kind => TypeKind.TYPEDEF;
|
|
|
| SourceString get name => element.name;
|
|
|
| + DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
|
| + if (typeArguments.isEmpty) {
|
| + // Return fast on non-generic typedefs.
|
| + return this;
|
| + }
|
| + if (parameters.isEmpty) {
|
| + assert(arguments.isEmpty);
|
| + // Return fast on empty substitutions.
|
| + return this;
|
| + }
|
| + Link<DartType> newTypeArguments =
|
| + substTypes(typeArguments, arguments, parameters);
|
| + if (!identical(typeArguments, newTypeArguments)) {
|
| + // Create a new type only if necessary.
|
| + return new TypedefType(element, newTypeArguments);
|
| + }
|
| + return this;
|
| + }
|
| +
|
| DartType unalias(Compiler compiler) {
|
| // TODO(ahe): This should be [ensureResolved].
|
| compiler.resolveTypedef(element);
|
| + // TODO(johnniwinther): Perform substitution on the unaliased type.
|
| return element.alias.unalias(compiler);
|
| }
|
|
|
| @@ -291,21 +443,34 @@ class TypedefType extends DartType {
|
| }
|
| }
|
|
|
| +/**
|
| + * Special type to hold the [dynamic] type. Used for correctly returning
|
| + * 'dynamic' on [toString].
|
| + */
|
| +class DynamicType extends InterfaceType {
|
| + DynamicType(ClassElement element) : super(element);
|
| +
|
| + String toString() => 'dynamic';
|
| +}
|
| +
|
| +
|
| class Types {
|
| final Compiler compiler;
|
| // TODO(karlklose): should we have a class Void?
|
| final VoidType voidType;
|
| final InterfaceType dynamicType;
|
|
|
| - Types(Compiler compiler, Element dynamicElement)
|
| + Types(Compiler compiler, ClassElement dynamicElement)
|
| : this.with(compiler, dynamicElement,
|
| new LibraryElement(new Script(null, null)));
|
|
|
| Types.with(Compiler this.compiler,
|
| - Element dynamicElement,
|
| + ClassElement dynamicElement,
|
| LibraryElement library)
|
| : voidType = new VoidType(new VoidElement(library)),
|
| - dynamicType = new InterfaceType(dynamicElement);
|
| + dynamicType = new DynamicType(dynamicElement) {
|
| + dynamicElement.type = dynamicType;
|
| + }
|
|
|
| /** Returns true if t is a subtype of s */
|
| bool isSubtype(DartType t, DartType s) {
|
|
|