Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1171)

Unified Diff: frog/type.dart

Issue 9270048: Lots of frog cleanup (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« frog/gen.dart ('K') | « frog/tree.g.dart ('k') | frog/utils.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
}
« frog/gen.dart ('K') | « frog/tree.g.dart ('k') | frog/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698