| Index: lib/dartdoc/frog/type.dart
|
| diff --git a/lib/dartdoc/frog/type.dart b/lib/dartdoc/frog/type.dart
|
| deleted file mode 100644
|
| index cd2b280e073a1e333d8eddfcf24bdd84a86aa189..0000000000000000000000000000000000000000
|
| --- a/lib/dartdoc/frog/type.dart
|
| +++ /dev/null
|
| @@ -1,1220 +0,0 @@
|
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -class Type extends Element {
|
| - bool isTested = false;
|
| - bool isChecked = false;
|
| - bool isWritten = false;
|
| -
|
| - /**
|
| - * For core types (int, String, etc) this is the generated type assertion
|
| - * function (uses JS "typeof"). This field is null for all other types.
|
| - */
|
| - String typeCheckCode;
|
| -
|
| - Member _typeMember;
|
| -
|
| - /** Stubs used to call into this method dynamically. */
|
| - Map<String, VarMember> varStubs;
|
| -
|
| - /** Cache of [Member]s that have been found. */
|
| - Map<String, Member> _foundMembers;
|
| -
|
| - Type(String name): _foundMembers = {}, varStubs = {}, super(name, null);
|
| -
|
| - void markUsed() {}
|
| - abstract void genMethod(Member method);
|
| -
|
| - TypeMember get typeMember() {
|
| - if (_typeMember == null) {
|
| - _typeMember = new TypeMember(this);
|
| - }
|
| - return _typeMember;
|
| - }
|
| -
|
| - Member getMember(String name) => null;
|
| - abstract MethodMember getConstructor(String name);
|
| - abstract MethodMember getFactory(Type type, String name);
|
| - abstract Type getOrMakeConcreteType(List<Type> typeArgs);
|
| - abstract Map<String, MethodMember> get constructors();
|
| - abstract addDirectSubtype(Type type);
|
| - abstract bool get isClass();
|
| - abstract Library get library();
|
| - Set<Type> get subtypes() => null;
|
| -
|
| - // TODO(jmesserly): rename to isDynamic?
|
| - bool get isVar() => false;
|
| - bool get isTop() => false;
|
| -
|
| - bool get isObject() => false;
|
| - bool get isString() => false;
|
| - bool get isBool() => false;
|
| - bool get isFunction() => false;
|
| - bool get isNum() => false;
|
| - bool get isInt() => false;
|
| - bool get isDouble() => false;
|
| - bool get isVoid() => false;
|
| -
|
| - // True for all types in the Dart type system. We track non-nullabiltity
|
| - // as an optimization for booleans to generate better code in checked mode.
|
| - bool get isNullable() => true;
|
| -
|
| - // Strangely Dart treats calls on Function much like calls on var.
|
| - bool get isVarOrFunction() => isVar || isFunction;
|
| -
|
| - bool get isVarOrObject() => isVar || isObject;
|
| -
|
| - /** Gets the :call method for a function type. */
|
| - MethodMember getCallMethod() => null;
|
| -
|
| - /** These types may not be implemented or extended by user code. */
|
| - bool get isClosed() => isString || isBool || isNum || isFunction || isVar;
|
| -
|
| - bool get isUsed() => false;
|
| -
|
| - bool get isGeneric() => false;
|
| -
|
| - // Various special bits that we track on native types.
|
| - // Generally controls how prototypes are emitted.
|
| - NativeType get nativeType() => null;
|
| - bool get isHiddenNativeType() =>
|
| - (nativeType != null && nativeType.isConstructorHidden);
|
| - bool get isSingletonNative() =>
|
| - (nativeType != null && nativeType.isSingleton);
|
| - bool get isJsGlobalObject() =>
|
| - (nativeType != null && nativeType.isJsGlobalObject);
|
| -
|
| - bool get hasTypeParams() => false;
|
| -
|
| - String get typeofName() => null;
|
| -
|
| - String get fullname() =>
|
| - library.name !== null ? '${library.name}.$name' : name;
|
| -
|
| - Map<String, Member> get members() => null;
|
| - Definition get definition() => null;
|
| - FactoryMap get factories() => null;
|
| -
|
| - List<Type> get typeArgsInOrder() => const [];
|
| - DefinedType get genericType() => this;
|
| -
|
| - /** Indicates a concrete version of a generic type, such as List<String>. */
|
| - bool get isConcreteGeneric() => genericType != this;
|
| -
|
| - // TODO(jmesserly): what should these do for ParameterType?
|
| - List<Type> get interfaces() => null;
|
| - Type get parent() => null;
|
| -
|
| - Map<String, Member> getAllMembers() => {};
|
| -
|
| - /** The native name of this element if it has one, otherwise the JS name. */
|
| - String get nativeName() => isNative ? definition.nativeType.name : jsname;
|
| -
|
| - /**
|
| - * Avoid the native name if hidden native. It might exist on some browsers
|
| - * and we want to use it if it does.
|
| - */
|
| - bool get avoidNativeName() => isHiddenNativeType;
|
| -
|
| - bool _hasNativeSubtypes;
|
| - bool get hasNativeSubtypes() {
|
| - if (_hasNativeSubtypes == null) {
|
| - _hasNativeSubtypes = subtypes.some((t) => t.isNative);
|
| - }
|
| - return _hasNativeSubtypes;
|
| - }
|
| -
|
| - void _checkExtends() {
|
| - var typeParams = genericType.typeParameters;
|
| - if (typeParams != null) {
|
| - for (int i = 0; i < typeParams.length; i++) {
|
| - if (typeParams[i].extendsType != null) {
|
| - // TODO(jimhug): This dynamic shouldn't be needed...
|
| - typeArgsInOrder[i].dynamic.ensureSubtypeOf(typeParams[i].extendsType,
|
| - typeParams[i].span, false);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Parent should be handled by the super constructor call, but we still
|
| - // need to check our interfaces.
|
| - if (interfaces != null) {
|
| - for (var i in interfaces) {
|
| - i._checkExtends();
|
| - }
|
| - }
|
| - }
|
| -
|
| - void _checkOverride(Member member) {
|
| - // always look in parents to check that any overloads are legal
|
| - var parentMember = _getMemberInParents(member.name);
|
| - if (parentMember != null) {
|
| - // TODO(jimhug): Ensure that this is only done once.
|
| - if (!member.isPrivate || member.library == parentMember.library) {
|
| - member.override(parentMember);
|
| - }
|
| - }
|
| - }
|
| -
|
| - void _createNotEqualMember() {
|
| - assert(isObject);
|
| - // Add a != method just like the == one.
|
| - MethodMember eq = members[':eq'];
|
| - if (eq == null) {
|
| - // TODO(jmesserly): should this be an error?
|
| - // Frog is being hosted by "utils/css" such that it doesn't have its
|
| - // standard lib initialized properly.
|
| - return;
|
| - }
|
| - final ne = new MethodMember(':ne', this, eq.definition);
|
| - ne.returnType = eq.returnType;
|
| - ne.parameters = eq.parameters;
|
| - ne.isStatic = eq.isStatic;
|
| - ne.isAbstract = eq.isAbstract;
|
| - // TODO - What else to fill in?
|
| - members[':ne'] = ne;
|
| - }
|
| -
|
| - Member _getMemberInParents(String memberName) {
|
| - // print('getting $memberName in parents of $name, $isClass');
|
| - // Now look in my parents.
|
| - if (isClass) {
|
| - if (parent != null) {
|
| - return parent.getMember(memberName);
|
| - } else {
|
| - return null;
|
| - }
|
| - } else {
|
| - // TODO(jimhug): Will probably check types more than once - errors?
|
| - if (interfaces != null && interfaces.length > 0) {
|
| - for (var i in interfaces) {
|
| - var ret = i.getMember(memberName);
|
| - if (ret != null) {
|
| - return ret;
|
| - }
|
| - }
|
| - }
|
| - return world.objectType.getMember(memberName);
|
| - }
|
| - }
|
| -
|
| - void ensureSubtypeOf(Type other, SourceSpan span, [bool typeErrors=false]) {
|
| - if (!isSubtypeOf(other)) {
|
| - var msg = 'type $name is not a subtype of ${other.name}';
|
| - if (typeErrors) {
|
| - world.error(msg, span);
|
| - } else {
|
| - world.warning(msg, span);
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Returns true if we need to use our .call$N$names calling convention.
|
| - * This is only needed for calls to Functions where we lack enough type info.
|
| - */
|
| - bool needsVarCall(Arguments args) {
|
| - if (isVarOrFunction) {
|
| - return true;
|
| - }
|
| -
|
| - var call = getCallMethod();
|
| - if (call != null) {
|
| - // If the call doesn't fill in all arguments, or it doesn't use the right
|
| - // named parameter order, we need to go through a "var" call because we
|
| - // don't know what arguments the callee wants to fill in.
|
| -
|
| - // TODO(jmesserly): we could be smarter if the optional calls look
|
| - // similar enough, which is probably true quite often in practice.
|
| - if (args.length != call.parameters.length || !call.namesInOrder(args)) {
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - // Use a normal JS call, or not a function type.
|
| - return false;
|
| - }
|
| -
|
| - static Type union(Type x, Type y) {
|
| - if (x == y) return x;
|
| - if (x.isNum && y.isNum) return world.numType;
|
| - if (x.isString && y.isString) return world.stringType;
|
| -
|
| - // TODO(jmesserly): make this more precise when we can. Or add UnionValue
|
| - // and have Value do the heavy lifting of tracking sets of types.
|
| - return world.varType;
|
| - }
|
| -
|
| - // This is from the "Interface Types" section of the language spec:
|
| -
|
| - /**
|
| - * A type T may be assigned to a type S, written T <=> S, i either T <: S
|
| - * or S <: T.
|
| - */
|
| - bool isAssignable(Type other) {
|
| - return isSubtypeOf(other) || other.isSubtypeOf(this);
|
| - }
|
| -
|
| - /**
|
| - * An interface I is a direct supertype of an interface J iff:
|
| - * If I is Object, and J has no extends clause
|
| - * if I is listed in the extends clause of J.
|
| - */
|
| - bool _isDirectSupertypeOf(Type other) {
|
| - if (other.isClass) {
|
| - return other.parent == this || isObject && other.parent == null;
|
| - } else {
|
| - if (other.interfaces == null || other.interfaces.isEmpty()) {
|
| - return isObject;
|
| - } else {
|
| - return other.interfaces.some((i) => i == this);
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * This implements the subtype operator <: defined in "Interface Types"
|
| - * of the language spec. It's implemented in terms of the << "more specific"
|
| - * operator. The spec is below:
|
| - *
|
| - * A type T is more specific than a type S, written T << S, if one of the
|
| - * following conditions is met:
|
| - * - T is S.
|
| - * - T is Bottom.
|
| - * - S is Dynamic.
|
| - * - S is a direct supertype of T.
|
| - * - T is a type variable and S is the upper bound of T.
|
| - * - T is of the form I<T1,...,Tn> and S is of the form I<S1,...,Sn>
|
| - * and: Ti << Si, 1 <= i <= n
|
| - * - T << U and U << S.
|
| - *
|
| - * << is a partial order on types. T is a subtype of S, written T <: S, iff
|
| - * [Bottom/Dynamic]T << S.
|
| - */
|
| - // TODO(jmesserly): this function could be expensive. Memoize results?
|
| - // TODO(jmesserly): should merge this with the subtypes/directSubtypes
|
| - // machinery? Possible issues: needing this during resolve(), integrating
|
| - // the more accurate generics/function subtype handling.
|
| - bool isSubtypeOf(Type other) {
|
| - if (this == other) return true;
|
| -
|
| - // Note: the extra "isVar" check here is the difference between << and <:
|
| - // Since we don't implement the << relation itself, we can just pretend
|
| - // "null" literals are Dynamic and not worry about the Bottom type.
|
| - if (isVar || other.isVar) return true;
|
| - if (other._isDirectSupertypeOf(this)) return true;
|
| -
|
| - var call = getCallMethod();
|
| - var otherCall = other.getCallMethod();
|
| - if (call != null && otherCall != null) {
|
| - return _isFunctionSubtypeOf(call, otherCall);
|
| - }
|
| -
|
| - if (genericType === other.genericType) {
|
| - // These must be true for matching generic types.
|
| - assert(typeArgsInOrder.length == other.typeArgsInOrder.length);
|
| -
|
| - for (int i = 0; i < typeArgsInOrder.length; i++) {
|
| - // Type args don't have subtype relationship
|
| - // TODO(jimhug): This dynamic shouldn't be needed...
|
| - if (!typeArgsInOrder[i].dynamic.isSubtypeOf(other.typeArgsInOrder[i])) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - // And now for some fun: T << U and U << S -> T << S
|
| - // To implement this, we need to enumerate a set of types C such that
|
| - // U will be an element of C. We can do this by either enumerating less
|
| - // specific types of T, or more specific types of S.
|
| - if (parent != null && parent.isSubtypeOf(other)) {
|
| - return true;
|
| - }
|
| - if (interfaces != null && interfaces.some((i) => i.isSubtypeOf(other))) {
|
| - return true;
|
| - }
|
| -
|
| - // Unrelated types
|
| - return false;
|
| - }
|
| -
|
| - int hashCode() {
|
| - var libraryCode = library == null ? 1 : library.hashCode();
|
| - var nameCode = name == null ? 1 : name.hashCode();
|
| - return (libraryCode << 4) ^ nameCode;
|
| - }
|
| -
|
| - bool operator ==(other) =>
|
| - other is Type && other.name == name && library == other.library;
|
| -
|
| - /**
|
| - * A function type (T1,...,Tn, [Tx1 x1,..., Txk xk]) -> T is a subtype of the
|
| - * function type (S1,...,Sn, [Sy1 y1,..., Sym ym]) -> S, if all of the
|
| - * following conditions are met:
|
| - * 1. Either:
|
| - * - S is void, Or
|
| - * - T <=> S.
|
| - * 2. for all i in 1..n, Ti <=> Si
|
| - * 3. k >= m and xi = yi, i is in 1..m. It is necessary, but not sufficient,
|
| - * that the optional arguments of the subtype be a subset of those of the
|
| - * supertype. We cannot treat them as just sets, because optional
|
| - * arguments can be invoked positionally, so the order matters.
|
| - * 4. For all y in {y1,..., ym}Sy <=> Ty
|
| - * We write (T1,..., Tn) => T as a shorthand for the type (T1,...,Tn,[]) => T.
|
| - * All functions implement the interface Function, so all function types are a
|
| - * subtype of Function.
|
| - */
|
| - static bool _isFunctionSubtypeOf(MethodMember t, MethodMember s) {
|
| - if (!s.returnType.isVoid && !s.returnType.isAssignable(t.returnType)) {
|
| - return false; // incompatible return types
|
| - }
|
| -
|
| - var tp = t.parameters;
|
| - var sp = s.parameters;
|
| -
|
| - // Function subtype must have >= the total number of arguments
|
| - if (tp.length < sp.length) return false;
|
| -
|
| - for (int i = 0; i < sp.length; i++) {
|
| - // Mismatched required parameter count
|
| - if (tp[i].isOptional != sp[i].isOptional) return false;
|
| -
|
| - // Mismatched optional parameter name
|
| - if (tp[i].isOptional && tp[i].name != sp[i].name) return false;
|
| -
|
| - // Parameter types not assignable
|
| - if (!tp[i].type.isAssignable(sp[i].type)) return false;
|
| - }
|
| -
|
| - // Mismatched required parameter count
|
| - if (tp.length > sp.length && !tp[sp.length].isOptional) return false;
|
| -
|
| - return true;
|
| - }
|
| -}
|
| -
|
| -
|
| -/** A type parameter within the body of the type. */
|
| -class ParameterType extends Type {
|
| - TypeParameter typeParameter;
|
| - Type extendsType;
|
| -
|
| - bool get isClass() => false;
|
| - Library get library() => null; // TODO(jimhug): Make right...
|
| - SourceSpan get span() => typeParameter.span;
|
| -
|
| - ParameterType(String name, this.typeParameter): super(name);
|
| -
|
| - Map<String, MethodMember> get constructors() {
|
| - world.internalError('no constructors on type parameters yet');
|
| - }
|
| -
|
| - MethodMember getCallMethod() => extendsType.getCallMethod();
|
| -
|
| - void genMethod(Member method) {
|
| - extendsType.genMethod(method);
|
| - }
|
| -
|
| - // TODO(jmesserly): should be like this:
|
| - //bool isSubtypeOf(Type other) => extendsType.isSubtypeOf(other);
|
| - bool isSubtypeOf(Type other) => true;
|
| -
|
| - MethodMember getConstructor(String constructorName) {
|
| - world.internalError('no constructors on type parameters yet');
|
| - }
|
| -
|
| - Type getOrMakeConcreteType(List<Type> typeArgs) {
|
| - world.internalError('no concrete types of type parameters yet', span);
|
| - }
|
| -
|
| - addDirectSubtype(Type type) {
|
| - world.internalError('no subtypes of type parameters yet', span);
|
| - }
|
| -
|
| - resolve() {
|
| - if (typeParameter.extendsType != null) {
|
| - extendsType =
|
| - enclosingElement.resolveType(typeParameter.extendsType, true, true);
|
| - } else {
|
| - extendsType = world.objectType;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Non-nullable type. Currently used for bools, so we can generate better
|
| - * asserts in checked mode. Forwards almost all operations to its real type.
|
| - */
|
| -// NOTE: there's more work to do before this would work for types other than
|
| -// bool.
|
| -class NonNullableType extends Type {
|
| -
|
| - /** The corresponding nullable [Type]. */
|
| - final Type type;
|
| -
|
| - NonNullableType(Type type): super(type.name), type = type;
|
| -
|
| - bool get isNullable() => false;
|
| -
|
| - // TODO(jmesserly): this would need to change if we support other types.
|
| - bool get isBool() => type.isBool;
|
| -
|
| - // Treat it as unused so it doesn't get JS generated
|
| - bool get isUsed() => false;
|
| -
|
| - // Augment our subtype rules with: non-nullable types are subtypes of
|
| - // themselves, their corresponding nullable types, or anything that type is a
|
| - // subtype of.
|
| - bool isSubtypeOf(Type other) =>
|
| - this == other || type == other || type.isSubtypeOf(other);
|
| -
|
| - // Forward everything. This is overkill for now; might be useful later.
|
| - Type resolveType(TypeReference node, bool isRequired, bool allowTypeParams) =>
|
| - type.resolveType(node, isRequired, allowTypeParams);
|
| - void addDirectSubtype(Type subtype) { type.addDirectSubtype(subtype); }
|
| - void markUsed() { type.markUsed(); }
|
| - void genMethod(Member method) { type.genMethod(method); }
|
| - SourceSpan get span() => type.span;
|
| - Member getMember(String name) => type.getMember(name);
|
| - MethodMember getConstructor(String name) => type.getConstructor(name);
|
| - MethodMember getFactory(Type t, String name) => type.getFactory(t, name);
|
| - Type getOrMakeConcreteType(List<Type> typeArgs) =>
|
| - type.getOrMakeConcreteType(typeArgs);
|
| - Map<String, MethodMember> get constructors() => type.constructors;
|
| - bool get isClass() => type.isClass;
|
| - Library get library() => type.library;
|
| - MethodMember getCallMethod() => type.getCallMethod();
|
| - bool get isGeneric() => type.isGeneric;
|
| - bool get hasTypeParams() => type.hasTypeParams;
|
| - String get typeofName() => type.typeofName;
|
| - String get jsname() => type.jsname;
|
| - Map<String, Member> get members() => type.members;
|
| - Definition get definition() => type.definition;
|
| - FactoryMap get factories() => type.factories;
|
| - List<Type> get typeArgsInOrder() => type.typeArgsInOrder;
|
| - DefinedType get genericType() => type.genericType;
|
| - List<Type> get interfaces() => type.interfaces;
|
| - Type get parent() => type.parent;
|
| - Map<String, Member> getAllMembers() => type.getAllMembers();
|
| - bool get isNative() => type.isNative;
|
| -}
|
| -
|
| -
|
| -/** Represents a Dart type defined as source code. */
|
| -class DefinedType extends Type {
|
| - // Not final so that we can fill this in for special types like List or num.
|
| - Definition definition;
|
| - final Library library;
|
| - final bool isClass;
|
| -
|
| - // TODO(vsm): Restore the field once Issue 280 is fixed.
|
| - // Type parent;
|
| - Type _parent;
|
| - Type get parent() => _parent;
|
| - void set parent(Type p) { _parent = p; }
|
| -
|
| - List<Type> interfaces;
|
| - DefinedType defaultType;
|
| -
|
| - Set<Type> directSubtypes;
|
| - Set<Type> _subtypes;
|
| -
|
| - List<ParameterType> typeParameters;
|
| - List<Type> typeArgsInOrder;
|
| -
|
| - Map<String, MethodMember> constructors;
|
| - Map<String, Member> members;
|
| - FactoryMap factories;
|
| -
|
| - Map<String, Type> _concreteTypes;
|
| -
|
| - /** Methods to be generated once we know for sure that the type is used. */
|
| - Map<String, Member> _lazyGenMethods;
|
| -
|
| - bool isUsed = false;
|
| - bool isNative = false;
|
| -
|
| - Type baseGenericType;
|
| -
|
| - DefinedType get genericType() =>
|
| - baseGenericType === null ? this : baseGenericType;
|
| -
|
| -
|
| - DefinedType(String name, this.library, Definition definition, this.isClass)
|
| - : super(name), directSubtypes = new Set<Type>(), constructors = {},
|
| - members = {}, factories = new FactoryMap() {
|
| - setDefinition(definition);
|
| - }
|
| -
|
| - void setDefinition(Definition def) {
|
| - assert(definition == null);
|
| - definition = def;
|
| - if (definition is TypeDefinition && definition.nativeType != null) {
|
| - isNative = true;
|
| - }
|
| - if (definition != null && definition.typeParameters != null) {
|
| - _concreteTypes = {};
|
| - typeParameters = definition.typeParameters;
|
| - // TODO(jimhug): Should share these very generic lists better.
|
| - typeArgsInOrder = new List(typeParameters.length);
|
| - for (int i=0; i < typeArgsInOrder.length; i++) {
|
| - typeArgsInOrder[i] = world.varType;
|
| - }
|
| - } else {
|
| - typeArgsInOrder = const [];
|
| - }
|
| - }
|
| -
|
| - NativeType get nativeType() =>
|
| - (definition != null ? definition.nativeType : null);
|
| -
|
| - bool get isVar() => this == world.varType;
|
| - bool get isVoid() => this == world.voidType;
|
| -
|
| - /** Is this the type that holds onto top-level code for its library? **/
|
| - bool get isTop() => name == null;
|
| -
|
| - // TODO(jimhug) -> this == world.objectType, etc.
|
| - bool get isObject() => this == world.objectType;
|
| -
|
| - // TODO(jimhug): Really hating on the interface + impl pattern by now...
|
| - bool get isString() => this == world.stringType ||
|
| - this == world.stringImplType;
|
| -
|
| - // TODO(jimhug): Where is boolImplType?
|
| - bool get isBool() => this == world.boolType;
|
| - bool get isFunction() => this == world.functionType ||
|
| - this == world.functionImplType;
|
| -
|
| - bool get isGeneric() => typeParameters != null;
|
| -
|
| - SourceSpan get span() => definition == null ? null : definition.span;
|
| -
|
| -
|
| - String get typeofName() {
|
| - if (!library.isCore) return null;
|
| -
|
| - if (isBool) return 'boolean';
|
| - else if (isNum) return 'number';
|
| - else if (isString) return 'string';
|
| - else if (isFunction) return 'function';
|
| - else return null;
|
| - }
|
| -
|
| - // TODO(jimhug): Reconcile different number types on JS.
|
| - bool get isNum() {
|
| - return this == world.numType || this == world.intType ||
|
| - this == world.doubleType || this == world.numImplType;
|
| - }
|
| -
|
| - bool get isInt() => this == world.intType;
|
| - bool get isDouble() => this == world.doubleType;
|
| -
|
| - // TODO(jimhug): Understand complicated generics here...
|
| - MethodMember getCallMethod() => genericType.members[':call'];
|
| -
|
| - Map<String, Member> getAllMembers() => new Map.from(members);
|
| -
|
| - void markUsed() {
|
| - if (isUsed) return;
|
| -
|
| - isUsed = true;
|
| -
|
| - _checkExtends();
|
| -
|
| - if (_lazyGenMethods != null) {
|
| - for (var method in orderValuesByKeys(_lazyGenMethods)) {
|
| - world.gen.genMethod(method);
|
| - }
|
| - _lazyGenMethods = null;
|
| - }
|
| -
|
| - if (parent != null) parent.markUsed();
|
| - }
|
| -
|
| - void genMethod(Member method) {
|
| - // TODO(jimhug): Remove baseGenericType check from here.
|
| - if (isUsed || baseGenericType != null) {
|
| - world.gen.genMethod(method);
|
| - } else if (isClass) {
|
| - if (_lazyGenMethods == null) _lazyGenMethods = {};
|
| - _lazyGenMethods[method.name] = method;
|
| - }
|
| - }
|
| -
|
| - List<Type> _resolveInterfaces(List<TypeReference> types) {
|
| - if (types == null) return [];
|
| - var interfaces = [];
|
| - for (final type in types) {
|
| - var resolvedInterface = resolveType(type, true, true);
|
| - if (resolvedInterface.isClosed &&
|
| - !(library.isCore || library.isCoreImpl)) {
|
| - world.error(
|
| - 'cannot implement "${resolvedInterface.name}": '
|
| - 'only native implementation allowed', type.span);
|
| - }
|
| - resolvedInterface.addDirectSubtype(this);
|
| - // TODO(jimhug): if (resolveInterface.isClass) may need special handling.
|
| - interfaces.add(resolvedInterface);
|
| - }
|
| - return interfaces;
|
| - }
|
| -
|
| - addDirectSubtype(Type type) {
|
| - directSubtypes.add(type);
|
| - // TODO(jimhug): Shouldn't need this in both places.
|
| - if (baseGenericType != null) {
|
| - baseGenericType.addDirectSubtype(type);
|
| - }
|
| - }
|
| -
|
| - Set<Type> get subtypes() {
|
| - if (_subtypes == null) {
|
| - _subtypes = new Set<Type>();
|
| - for (var st in directSubtypes) {
|
| - _subtypes.add(st);
|
| - _subtypes.addAll(st.subtypes);
|
| - }
|
| - }
|
| - return _subtypes;
|
| - }
|
| -
|
| - /** Check whether this class has a cycle in its inheritance chain. */
|
| - bool _cycleInClassExtends() {
|
| - final seen = new Set();
|
| - seen.add(this);
|
| - var ancestor = parent;
|
| - while (ancestor != null) {
|
| - if (ancestor === this) {
|
| - return true;
|
| - }
|
| - if (seen.contains(ancestor)) {
|
| - // there is a cycle above, but [this] is not part of it
|
| - return false;
|
| - }
|
| - seen.add(ancestor);
|
| - ancestor = ancestor.parent;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - /**
|
| - * Check whether this interface has a cycle in its inheritance chain. If so,
|
| - * returns which of the parent interfaces creates the cycle (for error
|
| - * reporting).
|
| - */
|
| - int _cycleInInterfaceExtends() {
|
| - final seen = new Set();
|
| - seen.add(this);
|
| -
|
| - bool _helper(var ancestor) {
|
| - if (ancestor == null) return false;
|
| - if (ancestor === this) return true;
|
| - if (seen.contains(ancestor)) {
|
| - // this detects both cycles and DAGs with interfaces not involving
|
| - // [this]. In the case of cycles, we won't report an error here (but
|
| - // where the cycle was first detected), with DAGs we just take advantage
|
| - // that we detected it to avoid traversing twice.
|
| - return false;
|
| - }
|
| - seen.add(ancestor);
|
| - if (ancestor.interfaces != null) {
|
| - for (final parent in ancestor.interfaces) {
|
| - if (_helper(parent)) return true;
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - for (int i = 0; i < interfaces.length; i++) {
|
| - if (_helper(interfaces[i])) return i;
|
| - }
|
| - return -1;
|
| - }
|
| -
|
| - resolve() {
|
| - if (definition is TypeDefinition) {
|
| - TypeDefinition typeDef = definition;
|
| - if (isClass) {
|
| - if (typeDef.extendsTypes != null && typeDef.extendsTypes.length > 0) {
|
| - if (typeDef.extendsTypes.length > 1) {
|
| - world.error('more than one base class',
|
| - typeDef.extendsTypes[1].span);
|
| - }
|
| - var extendsTypeRef = typeDef.extendsTypes[0];
|
| - if (extendsTypeRef is GenericTypeReference) {
|
| - // TODO(jimhug): Understand and verify comment below.
|
| - // If we are extending a generic type first resolve against the
|
| - // base type, then the full generic type. This makes circular
|
| - // "extends" checks on generic type args work correctly.
|
| - GenericTypeReference g = extendsTypeRef;
|
| - parent = resolveType(g.baseType, true, true);
|
| - }
|
| - parent = resolveType(extendsTypeRef, true, true);
|
| - if (!parent.isClass) {
|
| - world.error('class may not extend an interface - use implements',
|
| - typeDef.extendsTypes[0].span);
|
| - }
|
| - parent.addDirectSubtype(this);
|
| - if (_cycleInClassExtends()) {
|
| - world.error('class "$name" has a cycle in its inheritance chain',
|
| - extendsTypeRef.span);
|
| - }
|
| - } else {
|
| - if (!isObject) {
|
| - // Object is the default parent for everthing except Object.
|
| - parent = world.objectType;
|
| - parent.addDirectSubtype(this);
|
| - }
|
| - }
|
| - this.interfaces = _resolveInterfaces(typeDef.implementsTypes);
|
| - if (typeDef.defaultType != null) {
|
| - world.error('default not allowed on classes',
|
| - typeDef.defaultType.span);
|
| - }
|
| - } else {
|
| - if (typeDef.implementsTypes != null &&
|
| - typeDef.implementsTypes.length > 0) {
|
| - world.error('implements not allowed on interfaces (use extends)',
|
| - typeDef.implementsTypes[0].span);
|
| - }
|
| - this.interfaces = _resolveInterfaces(typeDef.extendsTypes);
|
| - final res = _cycleInInterfaceExtends();
|
| - if (res >= 0) {
|
| - world.error('interface "$name" has a cycle in its inheritance chain',
|
| - typeDef.extendsTypes[res].span);
|
| - }
|
| -
|
| - if (typeDef.defaultType != null) {
|
| - defaultType = resolveType(typeDef.defaultType.baseType, true, true);
|
| - if (defaultType == null) {
|
| - // TODO(jimhug): Appropriate warning levels;
|
| - world.warning('unresolved default class', typeDef.defaultType.span);
|
| - } else {
|
| - if (baseGenericType != null) {
|
| - if (!defaultType.isGeneric) {
|
| - world.error('default type of generic interface must be generic',
|
| - typeDef.defaultType.span);
|
| - }
|
| - defaultType = defaultType.getOrMakeConcreteType(typeArgsInOrder);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - } else if (definition is FunctionTypeDefinition) {
|
| - // Function types implement the Function interface.
|
| - this.interfaces = [world.functionType];
|
| - }
|
| -
|
| - _resolveTypeParams(typeParameters);
|
| -
|
| - if (isObject) _createNotEqualMember();
|
| -
|
| - // Concrete specializations of ListFactory === Array are never actually
|
| - // created as the performance suffers too badly in most JS engines.
|
| - if (baseGenericType != world.listFactoryType) world._addType(this);
|
| -
|
| - for (var c in constructors.getValues()) c.resolve();
|
| - for (var m in members.getValues()) m.resolve();
|
| - factories.forEach((f) => f.resolve());
|
| -
|
| - // All names from the JS global object need to be treated as top-level
|
| - // native names, so we don't clobber them with other Dart top-level names.
|
| - if (isJsGlobalObject) {
|
| - for (var m in members.getValues()) {
|
| - if (!m.isStatic) world._addTopName(new ExistingJsGlobal(m.name, m));
|
| - }
|
| - }
|
| - }
|
| -
|
| - _resolveTypeParams(List<ParameterType> params) {
|
| - if (params == null) return;
|
| - for (var tp in params) {
|
| - tp.enclosingElement = this;
|
| - tp.resolve();
|
| - }
|
| - }
|
| -
|
| - addMethod(String methodName, FunctionDefinition definition) {
|
| - if (methodName == null) methodName = definition.name.name;
|
| -
|
| - var method = new MethodMember(methodName, this, definition);
|
| -
|
| - if (method.isConstructor) {
|
| - if (constructors.containsKey(method.constructorName)) {
|
| - world.error('duplicate constructor definition of ${method.name}',
|
| - definition.span);
|
| - return;
|
| - }
|
| - constructors[method.constructorName] = method;
|
| - return;
|
| - }
|
| -
|
| - if (definition.modifiers != null
|
| - && definition.modifiers.length == 1
|
| - && definition.modifiers[0].kind == TokenKind.FACTORY) {
|
| - // constructorName for a factory is the type.
|
| - if (factories.getFactory(method.constructorName, method.name) != null) {
|
| - world.error('duplicate factory definition of "${method.name}"',
|
| - definition.span);
|
| - return;
|
| - }
|
| - factories.addFactory(method.constructorName, method.name, method);
|
| - return;
|
| - }
|
| -
|
| - if (methodName.startsWith('get:') || methodName.startsWith('set:')) {
|
| - var propName = methodName.substring(4);
|
| - var prop = members[propName];
|
| - if (prop == null) {
|
| - prop = new PropertyMember(propName, this);
|
| - members[propName] = prop;
|
| - }
|
| - if (prop is! PropertyMember) {
|
| - world.error('property conflicts with field "$propName"',
|
| - definition.span);
|
| - return;
|
| - }
|
| - if (methodName[0] == 'g') {
|
| - if (prop.getter != null) {
|
| - world.error('duplicate getter definition for "$propName"',
|
| - definition.span);
|
| - }
|
| - // TODO(jimhug): Validate zero parameters
|
| - prop.getter = method;
|
| - } else {
|
| - if (prop.setter != null) {
|
| - world.error('duplicate setter definition for "$propName"',
|
| - definition.span);
|
| - }
|
| - // TODO(jimhug): Validate one parameters - match with getter?
|
| - prop.setter = method;
|
| - }
|
| - return;
|
| - }
|
| -
|
| - if (members.containsKey(methodName)) {
|
| - world.error('duplicate method definition of "${method.name}"',
|
| - definition.span);
|
| - return;
|
| - }
|
| - members[methodName] = method;
|
| - }
|
| -
|
| - addField(VariableDefinition definition) {
|
| - for (int i=0; i < definition.names.length; i++) {
|
| - var name = definition.names[i].name;
|
| - if (members.containsKey(name)) {
|
| - world.error('duplicate field definition of "$name"',
|
| - definition.span);
|
| - return;
|
| - }
|
| - var value = null;
|
| - if (definition.values != null) {
|
| - value = definition.values[i];
|
| - }
|
| - var field =
|
| - new FieldMember(name, this, definition, value, isNative: isNative);
|
| - members[name] = field;
|
| - }
|
| - }
|
| -
|
| - getFactory(Type type, String constructorName) {
|
| - if (baseGenericType != null) {
|
| - var rr = baseGenericType.factories.getFactory(type.genericType.name,
|
| - constructorName);
|
| - if (rr != null) {
|
| - // TODO(jimhug): Understand and fix this case.
|
| - world.info(
|
| - 'need to remap factory on ${name} from ${rr.declaringType.name}');
|
| - return rr;
|
| - } else {
|
| - var ret = getConstructor(constructorName);
|
| - return ret;
|
| - }
|
| - }
|
| -
|
| - // Try to find factory method with the given type.
|
| - // TODO(jimhug): Use jsname as key here or something better?
|
| - var ret = factories.getFactory(type.genericType.name, constructorName);
|
| - if (ret != null) return ret;
|
| -
|
| - // TODO(ngeoffray): Here we should actually check if the current
|
| - // type implements the given type.
|
| - // Try to find a factory method of this type.
|
| - ret = factories.getFactory(name, constructorName);
|
| - if (ret != null) return ret;
|
| -
|
| - // Try to find a generative constructor of this type.
|
| - ret = constructors[constructorName];
|
| - if (ret != null) return ret;
|
| -
|
| - return _tryCreateDefaultConstructor(constructorName);
|
| - }
|
| -
|
| -
|
| - getConstructor(String constructorName) {
|
| - // cheat and reuse constructors here to be any resolved cons...
|
| - if (baseGenericType != null) {
|
| - var rr = constructors[constructorName];
|
| - if (rr != null) return rr;
|
| -
|
| - rr = baseGenericType.constructors[constructorName];
|
| - if (rr != null) {
|
| - if (defaultType != null) {
|
| - var ret = defaultType.getFactory(this, constructorName);
|
| - return ret;
|
| - }
|
| - } else {
|
| - rr = baseGenericType.factories.getFactory(baseGenericType.name,
|
| - constructorName);
|
| - }
|
| - if (rr == null) {
|
| - rr = baseGenericType.dynamic._tryCreateDefaultConstructor(
|
| - constructorName);
|
| - }
|
| - if (rr == null) return null;
|
| -
|
| - // re-resolve rr in this
|
| - var rr1 = rr.makeConcrete(this);
|
| - rr1.resolve();
|
| -
|
| - constructors[constructorName] = rr1;
|
| - return rr1;
|
| - }
|
| -
|
| -
|
| - var ret = constructors[constructorName];
|
| - if (ret != null) {
|
| - if (defaultType != null) {
|
| - return defaultType.getFactory(this, constructorName);
|
| - }
|
| - return ret;
|
| - }
|
| - ret = factories.getFactory(name, constructorName);
|
| - if (ret != null) return ret;
|
| -
|
| - return _tryCreateDefaultConstructor(constructorName);
|
| - }
|
| -
|
| - // TODO(jimhug): Can we remove this with version in resolve + new spec?
|
| - /**
|
| - * Checks that default type parameters match between all 3 locations:
|
| - * 1. the interface (this)
|
| - * 2. the "default" type parameters
|
| - * 3. the class's type parameters
|
| - *
|
| - * The only deviation is that 2 and 3 can have a tighter "extends" bound.
|
| - */
|
| - _checkDefaultTypeParams() {
|
| - // Convert null to empty list so it doesn't complicate the logic
|
| - List<ParameterType> toList(list) => (list != null ? list : const []);
|
| -
|
| - TypeDefinition typeDef = definition;
|
| - if (typeDef.defaultType.oldFactory) {
|
| - // TODO(jmesserly): for now skip checking of old factories
|
| - return;
|
| - }
|
| -
|
| - var interfaceParams = toList(typeParameters);
|
| - var defaultParams = toList(typeDef.defaultType.typeParameters);
|
| - var classParams = toList(defaultType.typeParameters);
|
| -
|
| - if (interfaceParams.length != defaultParams.length
|
| - || defaultParams.length != classParams.length) {
|
| - world.error('"default" must have the same number of type parameters as '
|
| - + 'the class and interface do', span, typeDef.defaultType.span,
|
| - defaultType.span);
|
| - return;
|
| - }
|
| -
|
| - for (int i = 0; i < interfaceParams.length; i++) {
|
| - var ip = interfaceParams[i];
|
| - var dp = defaultParams[i];
|
| - var cp = classParams[i];
|
| - dp.resolve();
|
| - if (ip.name != dp.name || dp.name != cp.name) {
|
| - world.error('default class must have the same type parameter names as '
|
| - + 'the class and interface', ip.span, dp.span, cp.span);
|
| - } else if (dp.extendsType != cp.extendsType) {
|
| - world.error('default class type parameters must have the same extends '
|
| - + 'as the class does', dp.span, cp.span);
|
| - } else if (!dp.extendsType.isSubtypeOf(ip.extendsType)) {
|
| - // TODO(jmesserly): left this as a warning; it seems harmless to me
|
| - world.warning('"default" can only have tighter type parameter "extends"'
|
| - + ' than the interface', dp.span, ip.span);
|
| - }
|
| - }
|
| - }
|
| -
|
| - _tryCreateDefaultConstructor(String name) {
|
| - // Check if we can create a default constructor.
|
| - if (name == '' && definition != null && isClass &&
|
| - constructors.length == 0) {
|
| - var span = definition.span;
|
| -
|
| - var inits = null, native = null, body = null;
|
| - if (isNative) {
|
| - native = '';
|
| - inits = null;
|
| - } else {
|
| - body = null;
|
| - inits = [new CallExpression(new SuperExpression(span), [], span)];
|
| - }
|
| -
|
| - TypeDefinition typeDef = definition;
|
| - var c = new FunctionDefinition(null, null, typeDef.name, [],
|
| - inits, native, body, span);
|
| - addMethod(null, c);
|
| - constructors[''].resolve();
|
| - return constructors[''];
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - Member getMember(String memberName) {
|
| - Member member = _foundMembers[memberName];
|
| - if (member != null) return member;
|
| -
|
| - if (baseGenericType != null) {
|
| - member = baseGenericType.getMember(memberName);
|
| - // TODO(jimhug): Need much more elaborate lookup duplication here <frown>
|
| -
|
| - if (member == null) return null;
|
| -
|
| - // TODO(jimhug): There will be a few of these we need to specialize for
|
| - // type params, skipping anything not on my direct super is not accurate
|
| - if (member.isStatic || member.declaringType != baseGenericType) {
|
| - _foundMembers[memberName] = member;
|
| - return member;
|
| - }
|
| -
|
| -
|
| - var rr = member.makeConcrete(this);
|
| - if (member.definition !== null || member is PropertyMember) {
|
| - rr.resolve();
|
| - } else {
|
| - world.info('no definition for ${member.name} on ${name}');
|
| - }
|
| - // TODO(jimhug): Why do I need to put this in both maps?
|
| - members[memberName] = rr;
|
| - _foundMembers[memberName] = rr;
|
| - return rr;
|
| - }
|
| -
|
| - member = members[memberName];
|
| - if (member != null) {
|
| - _checkOverride(member);
|
| - _foundMembers[memberName] = member;
|
| - return member;
|
| - }
|
| -
|
| - if (isTop) {
|
| - // Let's pretend classes are members of the top-level library type
|
| - // TODO(jmesserly): using "this." to workaround a VM bug with abstract
|
| - // getters.
|
| - var libType = this.library.findTypeByName(memberName);
|
| - if (libType != null) {
|
| - member = libType.typeMember;
|
| - _foundMembers[memberName] = member;
|
| - return member;
|
| - }
|
| - }
|
| -
|
| - member = _getMemberInParents(memberName);
|
| - _foundMembers[memberName] = member;
|
| - return member;
|
| - }
|
| -
|
| - Type getOrMakeConcreteType(List<Type> typeArgs) {
|
| - assert(isGeneric);
|
| - var jsnames = [];
|
| - var names = [];
|
| - var typeMap = {};
|
| - bool allVar = true;
|
| - for (int i=0; i < typeArgs.length; i++) {
|
| - var typeArg = typeArgs[i];
|
| - if (typeArg is ParameterType) {
|
| - typeArg = world.varType;
|
| - typeArgs[i] = typeArg;
|
| - }
|
| - if (!typeArg.isVar) allVar = false;
|
| -
|
| - var paramName = typeParameters[i].name;
|
| - typeMap[paramName] = typeArg;
|
| - names.add(typeArg.fullname);
|
| - jsnames.add(typeArg.jsname);
|
| - }
|
| -
|
| - // If all type args are var or effectively var, just return this
|
| - if (allVar) return this;
|
| -
|
| - var jsname = '${jsname}_${Strings.join(jsnames, '\$')}';
|
| - var simpleName = '${name}<${Strings.join(names, ', ')}>';
|
| -
|
| - var ret = _concreteTypes[simpleName];
|
| - if (ret == null) {
|
| - ret = new DefinedType(simpleName, library, definition, isClass);
|
| - ret.baseGenericType = this;
|
| - ret.typeArgsInOrder = typeArgs;
|
| - ret._jsname = jsname;
|
| - _concreteTypes[simpleName] = ret;
|
| - ret.resolve();
|
| - }
|
| - return ret;
|
| - }
|
| -
|
| - VarFunctionStub getCallStub(Arguments args) {
|
| - assert(isFunction);
|
| -
|
| - var name = _getCallStubName('call', args);
|
| - var stub = varStubs[name];
|
| - if (stub == null) {
|
| - stub = new VarFunctionStub(name, args);
|
| - varStubs[name] = stub;
|
| - }
|
| - return stub;
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Information about a native type from the native string.
|
| - *
|
| - * "Foo" - constructor function is called 'Foo'.
|
| - * "=Foo" - a singleton instance that should be patched directly. For example,
|
| - * "=window.console"
|
| - * "*Foo" - name is 'Foo', constructor function and prototype are not available
|
| - * in global scope during initialization. This is characteristic of many
|
| - * DOM types like CanvasPixelArray. However, the *type name* is presumed to
|
| - * be available at runtime from the prototype.
|
| - * "@Foo" - the type of the global object. Members will be treated as names
|
| - * that can't be shadowed in generated JS.
|
| - */
|
| -// TODO(jmesserly): we really need a richer annotation system than just encoding
|
| -// this data in strings with magic characters.
|
| -class NativeType {
|
| - String name;
|
| - bool isConstructorHidden = false;
|
| - bool isJsGlobalObject = false;
|
| - bool isSingleton = false;
|
| -
|
| - NativeType(this.name) {
|
| - while (true) {
|
| - if (name.startsWith('@')) {
|
| - name = name.substring(1);
|
| - isJsGlobalObject = true;
|
| - } else if (name.startsWith('*')) {
|
| - name = name.substring(1);
|
| - isConstructorHidden = true;
|
| - } else {
|
| - break;
|
| - }
|
| - }
|
| - if (name.startsWith('=')) {
|
| - name = name.substring(1);
|
| - isSingleton = true;
|
| - }
|
| - }
|
| -}
|
|
|