| Index: frog/type.dart
|
| diff --git a/frog/type.dart b/frog/type.dart
|
| index fd413ca34e6ae987ded7afed589c2d53ce8720ec..872adbafe2a9929a95019f38428273fb498ca7f0 100644
|
| --- a/frog/type.dart
|
| +++ b/frog/type.dart
|
| @@ -33,8 +33,6 @@ class Type extends Element {
|
| return _typeMember;
|
| }
|
|
|
| - abstract Type resolveTypeParams(ConcreteType inType);
|
| -
|
| Member getMember(String name) => null;
|
| abstract MethodMember getConstructor(String name);
|
| abstract MethodMember getFactory(Type type, String name);
|
| @@ -53,7 +51,6 @@ class Type extends Element {
|
| bool get isString() => false;
|
| bool get isBool() => false;
|
| bool get isFunction() => false;
|
| - bool get isList() => false;
|
| bool get isNum() => false;
|
| bool get isInt() => false;
|
| bool get isDouble() => false;
|
| @@ -96,11 +93,12 @@ class Type extends Element {
|
| Definition get definition() => null;
|
| FactoryMap get factories() => null;
|
|
|
| - // TODO(jmesserly): should try using a const list instead of null to represent
|
| - // the absence of type parameters.
|
| - Collection<Type> get typeArgsInOrder() => 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;
|
| @@ -111,8 +109,8 @@ class Type extends Element {
|
| 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.
|
| + * 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;
|
|
|
| @@ -126,16 +124,12 @@ class Type extends Element {
|
|
|
| void _checkExtends() {
|
| var typeParams = genericType.typeParameters;
|
| - if (typeParams != null && typeArgsInOrder != null) {
|
| - // TODO(jmesserly): making typeArgsInOrder be a List instead of a
|
| - // Collection would clean this up.
|
| - var args = typeArgsInOrder.iterator();
|
| - var params = typeParams.iterator();
|
| - while (args.hasNext() && params.hasNext()) {
|
| - var typeParam = params.next();
|
| - var typeArg = args.next();
|
| - if (typeParam.extendsType != null && typeArg != null) {
|
| - typeArg.ensureSubtypeOf(typeParam.extendsType, typeParam.span, true);
|
| + 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);
|
| }
|
| }
|
| }
|
| @@ -171,7 +165,6 @@ class Type extends Element {
|
| return;
|
| }
|
| final ne = new MethodMember(':ne', this, eq.definition);
|
| - ne.isGenerated = true;
|
| ne.returnType = eq.returnType;
|
| ne.parameters = eq.parameters;
|
| ne.isStatic = eq.isStatic;
|
| @@ -301,23 +294,12 @@ class Type extends Element {
|
| // machinery? Possible issues: needing this during resolve(), integrating
|
| // the more accurate generics/function subtype handling.
|
| bool isSubtypeOf(Type other) {
|
| - if (other is ParameterType) {
|
| - // TODO(jmesserly): treating type variables as Dynamic is totally busted.
|
| - // It's a workaround for bugs in our our current type system, where
|
| - // "new List()" produces a ListFactory that inherits from List<E>
|
| - // instead of List<Dynamic>.
|
| -
|
| - //ParameterType p = other;
|
| - //other = p.extendsType;
|
| - return true;
|
| - }
|
| -
|
| 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) return true;
|
| - if (other.isVar) return true;
|
| + if (isVar || other.isVar) return true;
|
| if (other._isDirectSupertypeOf(this)) return true;
|
|
|
| var call = getCallMethod();
|
| @@ -326,15 +308,16 @@ class Type extends Element {
|
| return _isFunctionSubtypeOf(call, otherCall);
|
| }
|
|
|
| - if (genericType == other.genericType
|
| - && typeArgsInOrder != null && other.typeArgsInOrder != null
|
| - && typeArgsInOrder.length == other.typeArgsInOrder.length) {
|
| + if (genericType === other.genericType) {
|
| + // These must be true for matching generic types.
|
| + assert(typeArgsInOrder.length == other.typeArgsInOrder.length);
|
|
|
| - var t = typeArgsInOrder.iterator();
|
| - var s = other.typeArgsInOrder.iterator();
|
| - while (t.hasNext()) {
|
| + for (int i = 0; i < typeArgsInOrder.length; i++) {
|
| // Type args don't have subtype relationship
|
| - if (!t.next().isSubtypeOf(s.next())) return false;
|
| + // TODO(jimhug): This dynamic shouldn't be needed...
|
| + if (!typeArgsInOrder[i].dynamic.isSubtypeOf(other.typeArgsInOrder[i])) {
|
| + return false;
|
| + }
|
| }
|
| return true;
|
| }
|
| @@ -443,17 +426,14 @@ class ParameterType extends Type {
|
| world.internalError('no concrete types of type parameters yet', span);
|
| }
|
|
|
| - Type resolveTypeParams(ConcreteType inType) {
|
| - return inType.typeArguments[name];
|
| - }
|
| -
|
| addDirectSubtype(Type type) {
|
| world.internalError('no subtypes of type parameters yet', span);
|
| }
|
|
|
| resolve() {
|
| if (typeParameter.extendsType != null) {
|
| - extendsType = enclosingElement.resolveType(typeParameter.extendsType, true);
|
| + extendsType =
|
| + enclosingElement.resolveType(typeParameter.extendsType, true, true);
|
| } else {
|
| extendsType = world.objectType;
|
| }
|
| @@ -488,9 +468,8 @@ class NonNullableType extends Type {
|
| this == other || type == other || type.isSubtypeOf(other);
|
|
|
| // Forward everything. This is overkill for now; might be useful later.
|
| - Type resolveType(TypeReference node, bool isRequired) =>
|
| - type.resolveType(node, isRequired);
|
| - Type resolveTypeParams(ConcreteType inType) => type.resolveTypeParams(inType);
|
| + 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); }
|
| @@ -511,7 +490,7 @@ class NonNullableType extends Type {
|
| Map<String, Member> get members() => type.members;
|
| Definition get definition() => type.definition;
|
| FactoryMap get factories() => type.factories;
|
| - Collection<Type> get typeArgsInOrder() => type.typeArgsInOrder;
|
| + List<Type> get typeArgsInOrder() => type.typeArgsInOrder;
|
| DefinedType get genericType() => type.genericType;
|
| List<Type> get interfaces() => type.interfaces;
|
| Type get parent() => type.parent;
|
| @@ -519,190 +498,6 @@ class NonNullableType extends Type {
|
| bool get isNative() => type.isNative;
|
| }
|
|
|
| -/** A concrete version of a generic type. */
|
| -class ConcreteType extends Type {
|
| - final DefinedType genericType;
|
| - Map<String, Type> typeArguments;
|
| - List<Type> _interfaces;
|
| - Type _parent;
|
| - Set<Type> _subtypes;
|
| - List<Type> typeArgsInOrder;
|
| -
|
| - bool get isList() => genericType.isList;
|
| - bool get isClass() => genericType.isClass;
|
| - Library get library() => genericType.library;
|
| - SourceSpan get span() => genericType.span;
|
| -
|
| - bool get hasTypeParams() =>
|
| - typeArguments.getValues().some((e) => e is ParameterType);
|
| -
|
| - bool isUsed = false;
|
| -
|
| - /**
|
| - * Keeps a collection of members for which a concrete version needed to
|
| - * be created. For constructors we always create this. For other methods,
|
| - * we will do this for methods whose bodies need to be specialized for
|
| - * a type parameter and in checked mode for methods that we need to
|
| - * generate appropriate concrete checks on.
|
| - */
|
| - Map<String, Member> members;
|
| - Map<String, MethodMember> constructors;
|
| - FactoryMap factories;
|
| -
|
| - ConcreteType(String name,
|
| - this.genericType,
|
| - this.typeArguments,
|
| - this.typeArgsInOrder):
|
| - super(name), constructors = {}, members = {}, factories = new FactoryMap();
|
| -
|
| - Type resolveTypeParams(ConcreteType inType) {
|
| - var newTypeArgs = [];
|
| - var needsNewType = false;
|
| - for (var t in typeArgsInOrder) {
|
| - var newType = t.resolveTypeParams(inType);
|
| - if (newType != t) needsNewType = true;
|
| - newTypeArgs.add(newType);
|
| - }
|
| - if (!needsNewType) return this;
|
| - return genericType.getOrMakeConcreteType(newTypeArgs);
|
| - }
|
| -
|
| - Type getOrMakeConcreteType(List<Type> typeArgs) {
|
| - return genericType.getOrMakeConcreteType(typeArgs);
|
| - }
|
| -
|
| - Type get parent() {
|
| - if (_parent == null && genericType.parent != null) {
|
| - _parent = genericType.parent.resolveTypeParams(this);
|
| - }
|
| - return _parent;
|
| - }
|
| -
|
| - List<Type> get interfaces() {
|
| - if (_interfaces == null && genericType.interfaces != null) {
|
| - _interfaces = [];
|
| - for (var i in genericType.interfaces) {
|
| - _interfaces.add(i.resolveTypeParams(this));
|
| - }
|
| - }
|
| - return _interfaces;
|
| - }
|
| -
|
| - Set<Type> get subtypes() {
|
| - if (_subtypes == null) {
|
| - _subtypes = new Set<Type>();
|
| - for (var s in genericType.subtypes) {
|
| - // TODO(jmesserly): this substitution is not right if type names are
|
| - // different in the subtype.
|
| - _subtypes.add(s.resolveTypeParams(this));
|
| - }
|
| - }
|
| - return _subtypes;
|
| - }
|
| -
|
| - // TODO(jmesserly): fill in type args?
|
| - // We can't look in our own members, because we'll get a ConcreteMember
|
| - // which is not fully compatible with MethodMember.
|
| - MethodMember getCallMethod() => genericType.getCallMethod();
|
| -
|
| - /**
|
| - * Gets all members in the type. Some of these are concrete, others are
|
| - * generic, depending on if we've decided to specialize it.
|
| - */
|
| - Map<String, Member> getAllMembers() {
|
| - var result = genericType.getAllMembers();
|
| - for (var memberName in result.getKeys()) {
|
| - var myMember = members[memberName];
|
| - if (myMember != null) {
|
| - result[memberName] = myMember;
|
| - }
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - void markUsed() {
|
| - if (isUsed) return;
|
| -
|
| - isUsed = true;
|
| - _checkExtends();
|
| - genericType.markUsed();
|
| - }
|
| -
|
| - void genMethod(Member method) => genericType.genMethod(method);
|
| -
|
| - getFactory(Type type, String constructorName) {
|
| - return genericType.getFactory(type, constructorName);
|
| - }
|
| -
|
| - getConstructor(String constructorName) {
|
| - var ret = constructors[constructorName];
|
| - if (ret != null) return ret;
|
| -
|
| - ret = factories.getFactory(name, constructorName);
|
| - if (ret != null) return ret;
|
| -
|
| - var genericMember = genericType.getConstructor(constructorName);
|
| - if (genericMember == null) return null;
|
| -
|
| - // In case the constructor is defined in another class.
|
| - if (genericMember.declaringType != genericType) {
|
| - if (!genericMember.declaringType.isGeneric) return genericMember;
|
| - var newDeclaringType =
|
| - genericMember.declaringType.getOrMakeConcreteType(typeArgsInOrder);
|
| - var factory = newDeclaringType.getFactory(genericType, constructorName);
|
| - if (factory != null) return factory;
|
| - return newDeclaringType.getConstructor(constructorName);
|
| - }
|
| -
|
| - if (genericMember.isFactory) {
|
| - ret = new ConcreteMember(genericMember.name, this, genericMember);
|
| - factories.addFactory(name, constructorName, ret);
|
| - } else {
|
| - ret = new ConcreteMember(name, this, genericMember);
|
| - constructors[constructorName] = ret;
|
| - }
|
| - return ret;
|
| - }
|
| -
|
| - Member getMember(String memberName) {
|
| - Member member = _foundMembers[memberName];
|
| - if (member != null) return member;
|
| -
|
| -
|
| - member = members[memberName];
|
| - if (member != null) {
|
| - _checkOverride(member);
|
| - _foundMembers[memberName] = member;
|
| - return member;
|
| - }
|
| -
|
| - // Note: only look directly in the generic type. The transitive search
|
| - // through superclass/interfaces is handled below.
|
| - var genericMember = genericType.members[memberName];
|
| - if (genericMember != null) {
|
| - member = new ConcreteMember(genericMember.name, this, genericMember);
|
| - members[memberName] = member;
|
| - _foundMembers[memberName] = member;
|
| - return member;
|
| - }
|
| -
|
| - member = _getMemberInParents(memberName);
|
| - _foundMembers[memberName] = member;
|
| - return member;
|
| - }
|
| -
|
| - Type resolveType(TypeReference node, bool isRequired) {
|
| - var ret = genericType.resolveType(node, isRequired);
|
| - // add type info
|
| - return ret;
|
| - }
|
| -
|
| - addDirectSubtype(Type type) {
|
| - // TODO(jimhug): Does this go on the generic type or the concrete one?
|
| - genericType.addDirectSubtype(type);
|
| - }
|
| -}
|
| -
|
|
|
| /** Represents a Dart type defined as source code. */
|
| class DefinedType extends Type {
|
| @@ -724,13 +519,13 @@ class DefinedType extends Type {
|
| Set<Type> _subtypes;
|
|
|
| List<ParameterType> typeParameters;
|
| - Collection<Type> _typeArgsInOrder;
|
| + List<Type> typeArgsInOrder;
|
|
|
| Map<String, MethodMember> constructors;
|
| Map<String, Member> members;
|
| FactoryMap factories;
|
|
|
| - Map<String, ConcreteType> _concreteTypes;
|
| + Map<String, Type> _concreteTypes;
|
|
|
| /** Methods to be generated once we know for sure that the type is used. */
|
| Map<String, Member> _lazyGenMethods;
|
| @@ -738,6 +533,12 @@ class DefinedType extends Type {
|
| 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() {
|
| @@ -753,23 +554,19 @@ class DefinedType extends Type {
|
| 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);
|
|
|
| - // TODO(jmesserly): this is a workaround for generic types not filling in
|
| - // "Dynamic" as their type arguments.
|
| - Collection<Type> get typeArgsInOrder() {
|
| - if (typeParameters == null) return null;
|
| - if (_typeArgsInOrder == null) {
|
| - _typeArgsInOrder = new FixedCollection<Type>(
|
| - world.varType, typeParameters.length);
|
| - }
|
| - return _typeArgsInOrder;
|
| - }
|
| -
|
| bool get isVar() => this == world.varType;
|
| bool get isVoid() => this == world.voidType;
|
|
|
| @@ -777,15 +574,16 @@ class DefinedType extends Type {
|
| bool get isTop() => name == null;
|
|
|
| // TODO(jimhug) -> this == world.objectType, etc.
|
| - bool get isObject() => library.isCore && name == 'Object';
|
| + bool get isObject() => this == world.objectType;
|
|
|
| // TODO(jimhug): Really hating on the interface + impl pattern by now...
|
| - bool get isString() => library.isCore && name == 'String' ||
|
| - library.isCoreImpl && name == 'StringImplementation';
|
| + bool get isString() => this == world.stringType ||
|
| + this == world.stringImplType;
|
|
|
| - bool get isBool() => library.isCore && name == 'bool';
|
| - bool get isFunction() => library.isCore && name == 'Function';
|
| - bool get isList() => library.isCore && name == 'List';
|
| + // 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;
|
|
|
| @@ -811,7 +609,8 @@ class DefinedType extends Type {
|
| bool get isInt() => this == world.intType;
|
| bool get isDouble() => this == world.doubleType;
|
|
|
| - MethodMember getCallMethod() => members[':call'];
|
| + // TODO(jimhug): Understand complicated generics here...
|
| + MethodMember getCallMethod() => genericType.members[':call'];
|
|
|
| Map<String, Member> getAllMembers() => new Map.from(members);
|
|
|
| @@ -833,7 +632,8 @@ class DefinedType extends Type {
|
| }
|
|
|
| void genMethod(Member method) {
|
| - if (isUsed) {
|
| + // TODO(jimhug): Remove baseGenericType check from here.
|
| + if (isUsed || baseGenericType != null) {
|
| world.gen.genMethod(method);
|
| } else if (isClass) {
|
| if (_lazyGenMethods == null) _lazyGenMethods = {};
|
| @@ -845,7 +645,7 @@ class DefinedType extends Type {
|
| if (types == null) return [];
|
| var interfaces = [];
|
| for (final type in types) {
|
| - var resolvedInterface = resolveType(type, true);
|
| + var resolvedInterface = resolveType(type, true, true);
|
| if (resolvedInterface.isClosed &&
|
| !(library.isCore || library.isCoreImpl)) {
|
| world.error(
|
| @@ -861,6 +661,10 @@ class DefinedType extends Type {
|
|
|
| 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() {
|
| @@ -938,13 +742,14 @@ class DefinedType extends Type {
|
| }
|
| 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);
|
| + parent = resolveType(g.baseType, true, true);
|
| }
|
| - parent = resolveType(extendsTypeRef, true);
|
| + parent = resolveType(extendsTypeRef, true, true);
|
| if (!parent.isClass) {
|
| world.error('class may not extend an interface - use implements',
|
| typeDef.extendsTypes[0].span);
|
| @@ -980,12 +785,18 @@ class DefinedType extends Type {
|
| }
|
|
|
| if (typeDef.defaultType != null) {
|
| - defaultType = resolveType(typeDef.defaultType.baseType, true);
|
| + defaultType = resolveType(typeDef.defaultType.baseType, true, true);
|
| if (defaultType == null) {
|
| // TODO(jimhug): Appropriate warning levels;
|
| world.warning('unresolved default class', typeDef.defaultType.span);
|
| } else {
|
| - defaultType._resolveTypeParams(typeDef.defaultType.typeParameters);
|
| + if (baseGenericType != null) {
|
| + if (!defaultType.isGeneric) {
|
| + world.error('default type of generic interface must be generic',
|
| + typeDef.defaultType.span);
|
| + }
|
| + defaultType = defaultType.getOrMakeConcreteType(typeArgsInOrder);
|
| + }
|
| }
|
| }
|
| }
|
| @@ -998,7 +809,9 @@ class DefinedType extends Type {
|
|
|
| if (isObject) _createNotEqualMember();
|
|
|
| - world._addType(this);
|
| + // 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();
|
| @@ -1108,9 +921,23 @@ class DefinedType extends Type {
|
| }
|
|
|
| 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.name, constructorName);
|
| + var ret = factories.getFactory(type.genericType.name, constructorName);
|
| if (ret != null) return ret;
|
|
|
| // TODO(ngeoffray): Here we should actually check if the current
|
| @@ -1128,11 +955,39 @@ class DefinedType extends Type {
|
|
|
|
|
| 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) {
|
| - // TODO(jmesserly): only need to check once.
|
| - _checkDefaultTypeParams();
|
| return defaultType.getFactory(this, constructorName);
|
| }
|
| return ret;
|
| @@ -1143,6 +998,7 @@ class DefinedType extends Type {
|
| 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)
|
| @@ -1217,11 +1073,35 @@ class DefinedType extends Type {
|
| return null;
|
| }
|
|
|
| - // TODO(jimhug): Too much copy-paster with ConcreteType...
|
| 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) {
|
| @@ -1247,20 +1127,29 @@ class DefinedType extends Type {
|
| return member;
|
| }
|
|
|
| - Type resolveTypeParams(ConcreteType inType) => this;
|
| -
|
| 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] = typeArgs[i];
|
| - names.add(typeArgs[i].name);
|
| - jsnames.add(typeArgs[i].jsname);
|
| + typeMap[paramName] = typeArg;
|
| + names.add(typeArg.name);
|
| + 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, ', ')}>';
|
|
|
| @@ -1268,10 +1157,12 @@ class DefinedType extends Type {
|
| var key = Strings.join(names, '\$');
|
| var ret = _concreteTypes[key];
|
| if (ret == null) {
|
| - ret = new ConcreteType(simpleName, this, typeMap, typeArgs);
|
| + ret = new DefinedType(simpleName, library, definition, isClass);
|
| + ret.baseGenericType = this;
|
| + ret.typeArgsInOrder = typeArgs;
|
| ret._jsname = jsname;
|
| -
|
| _concreteTypes[key] = ret;
|
| + ret.resolve();
|
| }
|
| return ret;
|
| }
|
|
|