| Index: sdk/lib/_internal/compiler/implementation/dart_types.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
|
| index 5f14cc2ccd40144b62d26137bc1495141d9f6ecc..2698f8956fa5cfd8173b9083f810810620fa3e5d 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
|
| @@ -121,6 +121,12 @@ abstract class DartType {
|
| /// Is [: true :] if this type contains any type variables.
|
| bool get containsTypeVariables => typeVariableOccurrence != null;
|
|
|
| + /// Returns a textual representation of this type as if it was the type
|
| + /// of a member named [name].
|
| + String getStringAsDeclared(String name) {
|
| + return new TypeDeclarationFormatter().format(this, name);
|
| + }
|
| +
|
| accept(DartTypeVisitor visitor, var argument);
|
|
|
| void visitChildren(DartTypeVisitor visitor, var argument) {}
|
| @@ -421,6 +427,9 @@ abstract class GenericType extends DartType {
|
| && typeArguments == other.typeArguments;
|
| }
|
|
|
| + /// Returns `true` if the declaration of this type has type variables.
|
| + bool get isGeneric => !typeArguments.isEmpty;
|
| +
|
| bool get isRaw => typeArguments.isEmpty || identical(this, element.rawType);
|
|
|
| GenericType asRaw() => element.rawType;
|
| @@ -485,13 +494,14 @@ class InterfaceType extends GenericType {
|
| * Finds the method, field or property named [name] declared or inherited
|
| * on this interface type.
|
| */
|
| - Member lookupMember(String name, {bool isSetter: false}) {
|
| + InterfaceTypeMember lookupMember(String name, {bool isSetter: false}) {
|
| // Abstract field returned when setter was needed but only a getter was
|
| // present and vice-versa.
|
| - Member fallbackAbstractField;
|
| + InterfaceTypeMember fallbackAbstractField;
|
|
|
| - Member createMember(ClassElement classElement,
|
| - InterfaceType receiver, InterfaceType declarer) {
|
| + InterfaceTypeMember createMember(ClassElement classElement,
|
| + InterfaceType receiver,
|
| + InterfaceType declarer) {
|
| Element member = classElement.implementation.lookupLocalMember(name);
|
| if (member == null) return null;
|
| if (member.isConstructor() || member.isPrefix()) return null;
|
| @@ -503,7 +513,8 @@ class InterfaceType extends GenericType {
|
| AbstractFieldElement abstractFieldElement = member;
|
| if (fallbackAbstractField == null) {
|
| fallbackAbstractField =
|
| - new Member(receiver, declarer, member, isSetter: isSetter);
|
| + new InterfaceTypeMember(receiver, declarer, member,
|
| + isSetter: isSetter);
|
| }
|
| if (isSetter && abstractFieldElement.setter == null) {
|
| // Keep searching further up the hierarchy.
|
| @@ -514,7 +525,9 @@ class InterfaceType extends GenericType {
|
| }
|
| }
|
| return member != null
|
| - ? new Member(receiver, declarer, member, isSetter: isSetter) : null;
|
| + ? new InterfaceTypeMember(receiver, declarer, member,
|
| + isSetter: isSetter)
|
| + : null;
|
| }
|
|
|
| ClassElement classElement = element;
|
| @@ -522,7 +535,7 @@ class InterfaceType extends GenericType {
|
| InterfaceType declarer = receiver;
|
| // TODO(johnniwinther): Lookup and callers should handle private members and
|
| // injected members.
|
| - Member member = createMember(classElement, receiver, declarer);
|
| + InterfaceTypeMember member = createMember(classElement, receiver, declarer);
|
| if (member != null) return member;
|
|
|
| assert(invariant(element, classElement.allSupertypes != null,
|
| @@ -533,7 +546,8 @@ class InterfaceType extends GenericType {
|
| if (supertype.element.isMixinApplication) continue;
|
| declarer = supertype;
|
| ClassElement lookupTarget = declarer.element;
|
| - Member member = createMember(lookupTarget, receiver, declarer);
|
| + InterfaceTypeMember member =
|
| + createMember(lookupTarget, receiver, declarer);
|
| if (member != null) return member;
|
| }
|
|
|
| @@ -605,10 +619,10 @@ class FunctionType extends DartType {
|
|
|
| FunctionType(Element this.element,
|
| DartType this.returnType,
|
| - Link<DartType> this.parameterTypes,
|
| - Link<DartType> this.optionalParameterTypes,
|
| - Link<String> this.namedParameters,
|
| - Link<DartType> this.namedParameterTypes) {
|
| + [this.parameterTypes = const Link<DartType>(),
|
| + this.optionalParameterTypes = const Link<DartType>(),
|
| + this.namedParameters = const Link<String>(),
|
| + this.namedParameterTypes = const Link<DartType>()]) {
|
| assert(invariant(element, element.isDeclaration));
|
| // Assert that optional and named parameters are not used at the same time.
|
| assert(optionalParameterTypes.isEmpty || namedParameterTypes.isEmpty);
|
| @@ -833,37 +847,38 @@ class DynamicType extends InterfaceType {
|
| }
|
|
|
| /**
|
| - * Member encapsulates a member (method, field, property) with the types of the
|
| - * declarer and receiver in order to do substitution on the member type.
|
| + * [InterfaceTypeMember] encapsulates a member (method, field, property) with
|
| + * the types of the declarer and receiver in order to do substitution on the
|
| + * member type.
|
| *
|
| - * Consider for instance these classes and the variable [: B<String> b :]:
|
| + * Consider for instance these classes and the variable `B<String> b`:
|
| *
|
| * class A<E> {
|
| * E field;
|
| * }
|
| * class B<F> extends A<F> {}
|
| *
|
| - * In a [Member] for [: b.field :] the [receiver] is the type [: B<String> :]
|
| - * and the declarer is the type [: A<F> :], which is the supertype of [: B<F> :]
|
| - * from which [: field :] has been inherited. To compute the type of
|
| - * [: b.field :] we must first substitute [: E :] by [: F :] using the relation
|
| - * between [: A<E> :] and [: A<F> :], and then [: F :] by [: String :] using the
|
| - * relation between [: B<F> :] and [: B<String> :].
|
| + * In an [InterfaceTypeMember] for `b.field` the [receiver] is the type
|
| + * `B<String>` and the declarer is the type `A<F>`, which is the supertype of
|
| + * `B<F>` from which `field` has been inherited. To compute the type of
|
| + * `b.field` we must first substitute `E` by `F` using the relation between
|
| + * `A<E>` and `A<F>`, and then `F` by `String` using the relation between
|
| + * `B<F>` and `B<String>`.
|
| */
|
| // TODO(johnniwinther): Add [isReadable] and [isWritable] predicates.
|
| -class Member {
|
| +class InterfaceTypeMember {
|
| final InterfaceType receiver;
|
| final InterfaceType declarer;
|
| final Element element;
|
| DartType cachedType;
|
| final bool isSetter;
|
|
|
| - Member(this.receiver, this.declarer, this.element,
|
| + InterfaceTypeMember(this.receiver, this.declarer, this.element,
|
| {bool this.isSetter: false}) {
|
| assert(invariant(element, element.isAbstractField() ||
|
| - element.isField() ||
|
| - element.isFunction(),
|
| - message: "Unsupported Member element: $element"));
|
| + element.isField() ||
|
| + element.isFunction(),
|
| + message: "Unsupported InterfaceTypeMember element: $element"));
|
| }
|
|
|
| DartType computeType(Compiler compiler) {
|
| @@ -1204,7 +1219,7 @@ class SubtypeVisitor extends MoreSpecificVisitor {
|
| lookupCall(t) != null) {
|
| return true;
|
| } else if (s is FunctionType) {
|
| - Member call = lookupCall(t);
|
| + InterfaceTypeMember call = lookupCall(t);
|
| if (call == null) return false;
|
| return isSubtype(call.computeType(compiler), s);
|
| }
|
| @@ -1757,4 +1772,116 @@ class MoreSpecificSubtypeVisitor extends DartTypeVisitor<bool, DartType> {
|
| }
|
| return false;
|
| }
|
| -}
|
| +}
|
| +
|
| +/// Visitor used to print type annotation like they used in the source code.
|
| +/// The visitor is especially for printing a function type like
|
| +/// `(Foo,[Bar])->Baz` as `Baz m(Foo a1, [Bar a2])`.
|
| +class TypeDeclarationFormatter extends DartTypeVisitor<dynamic, String> {
|
| + Set<String> usedNames;
|
| + StringBuffer sb;
|
| +
|
| + /// Creates textual representation of [type] as if a member by the [name] were
|
| + /// declared. For instance 'String foo' for `format(String, 'foo')`.
|
| + String format(DartType type, String name) {
|
| + sb = new StringBuffer();
|
| + usedNames = new Set<String>();
|
| + type.accept(this, name);
|
| + usedNames = null;
|
| + return sb.toString();
|
| + }
|
| +
|
| + String createName(String name) {
|
| + if (name != null && !usedNames.contains(name)) {
|
| + usedNames.add(name);
|
| + return name;
|
| + }
|
| + int index = usedNames.length;
|
| + String proposal;
|
| + do {
|
| + proposal = '${name}${index++}';
|
| + } while (usedNames.contains(proposal));
|
| + usedNames.add(proposal);
|
| + return proposal;
|
| + }
|
| +
|
| + void visit(DartType type) {
|
| + type.accept(this, null);
|
| + }
|
| +
|
| + void visitTypes(Link<DartType> types, String prefix) {
|
| + bool needsComma = false;
|
| + for (Link<DartType> link = types;
|
| + !link.isEmpty;
|
| + link = link.tail) {
|
| + if (needsComma) {
|
| + sb.write(', ');
|
| + }
|
| + link.head.accept(this, prefix);
|
| + needsComma = true;
|
| + } }
|
| +
|
| + void visitType(DartType type, String name) {
|
| + if (name == null) {
|
| + sb.write(type);
|
| + } else {
|
| + sb.write('$type ${createName(name)}');
|
| + }
|
| + }
|
| +
|
| + void visitGenericType(GenericType type, String name) {
|
| + sb.write(type.name);
|
| + if (!type.treatAsRaw) {
|
| + sb.write('<');
|
| + visitTypes(type.typeArguments, null);
|
| + sb.write('>');
|
| + }
|
| + if (name != null) {
|
| + sb.write(' ');
|
| + sb.write(createName(name));
|
| + }
|
| + }
|
| +
|
| + void visitFunctionType(FunctionType type, String name) {
|
| + visit(type.returnType);
|
| + sb.write(' ');
|
| + if (name != null) {
|
| + sb.write(name);
|
| + } else {
|
| + sb.write(createName('f'));
|
| + }
|
| + sb.write('(');
|
| + visitTypes(type.parameterTypes, 'a');
|
| + bool needsComma = !type.parameterTypes.isEmpty;
|
| + if (!type.optionalParameterTypes.isEmpty) {
|
| + if (needsComma) {
|
| + sb.write(', ');
|
| + }
|
| + sb.write('[');
|
| + visitTypes(type.optionalParameterTypes, 'a');
|
| + sb.write(']');
|
| + needsComma = true;
|
| + }
|
| + if (!type.namedParameterTypes.isEmpty) {
|
| + if (needsComma) {
|
| + sb.write(', ');
|
| + }
|
| + sb.write('{');
|
| + Link<String> namedParameter = type.namedParameters;
|
| + Link<DartType> namedParameterType = type.namedParameterTypes;
|
| + needsComma = false;
|
| + while (!namedParameter.isEmpty && !namedParameterType.isEmpty) {
|
| + if (needsComma) {
|
| + sb.write(', ');
|
| + }
|
| + namedParameterType.head.accept(this, namedParameter.head);
|
| + namedParameter = namedParameter.tail;
|
| + namedParameterType = namedParameterType.tail;
|
| + needsComma = true;
|
| + }
|
| + sb.write('}');
|
| + }
|
| + sb.write(')');
|
| + }
|
| +}
|
| +
|
|
|