| Index: frog/type.dart
|
| diff --git a/frog/type.dart b/frog/type.dart
|
| index 1fd10fa339a1457705b62a926937020c4b281fb5..4dc7c97a06c77d2cd1040f95543a4485c53dba8d 100644
|
| --- a/frog/type.dart
|
| +++ b/frog/type.dart
|
| @@ -19,7 +19,10 @@ class Type implements Named, Hashable {
|
| /** Stubs used to call into this method dynamically. Lazy initialized. */
|
| Map<String, VarMember> varStubs;
|
|
|
| - Type(this.name): isTested = false;
|
| + /** Cache of [MemberSet]s that have been resolved. */
|
| + Map<String, MemberSet> _resolvedMembers;
|
| +
|
| + Type(this.name): isTested = false, _resolvedMembers = {};
|
|
|
| void markUsed() {}
|
| abstract void genMethod(Member method);
|
| @@ -37,7 +40,6 @@ class Type implements Named, Hashable {
|
|
|
| abstract Type resolveTypeParams(ConcreteType inType);
|
|
|
| - abstract MemberSet resolveMember(String name);
|
| Member getMember(String name) => null;
|
| abstract MethodMember getConstructor(String name);
|
| abstract MethodMember getFactory(Type type, String name);
|
| @@ -46,6 +48,7 @@ class Type implements Named, Hashable {
|
| 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;
|
| @@ -167,6 +170,41 @@ class Type implements Named, Hashable {
|
| }
|
| }
|
|
|
| + MemberSet resolveMember(String memberName) {
|
| + MemberSet ret = _resolvedMembers[memberName];
|
| + if (ret != null) return ret;
|
| +
|
| + Member member = getMember(memberName);
|
| + if (member == null) {
|
| + // TODO(jimhug): Check for members on subtypes given dart's dynamism.
|
| + return null;
|
| + }
|
| +
|
| + // TODO(jimhug): Move this adding subtypes logic to MemberSet?
|
| + ret = new MemberSet(member);
|
| + _resolvedMembers[memberName] = ret;
|
| + if (member.isStatic) {
|
| + return ret;
|
| + } else {
|
| + for (var t in subtypes) {
|
| + if (!isClass && t.isClass) {
|
| + // If this is an interface, the actual implementation may
|
| + // come from a class that does not implement this interface.
|
| + // TODO(vsm): Use a more efficient lookup strategy.
|
| + // TODO(jimhug): This is made uglier by need to avoid dups.
|
| + final m = t.getMember(memberName);
|
| + if (m != null && ret.members.indexOf(m) == -1) {
|
| + ret.add(m);
|
| + }
|
| + } else {
|
| + final m = t.members[memberName];
|
| + if (m != null) ret.add(m);
|
| + }
|
| + }
|
| + return ret;
|
| + }
|
| + }
|
| +
|
| void ensureSubtypeOf(Type other, SourceSpan span, [bool typeErrors=false]) {
|
| if (!isSubtypeOf(other)) {
|
| var msg = 'type $name is not a subtype of ${other.name}';
|
| @@ -485,6 +523,7 @@ class ConcreteType extends Type {
|
| Map<String, Type> typeArguments;
|
| List<Type> _interfaces;
|
| Type _parent;
|
| + Set<Type> _subtypes;
|
| List<Type> typeArgsInOrder;
|
|
|
| bool get isList() => genericType.isList;
|
| @@ -546,6 +585,16 @@ class ConcreteType extends Type {
|
| return _interfaces;
|
| }
|
|
|
| + Set<Type> get subtypes() {
|
| + if (_subtypes == null) {
|
| + _subtypes = new Set<Type>();
|
| + for (var s in genericType.subtypes) {
|
| + _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.
|
| @@ -627,29 +676,12 @@ class ConcreteType extends Type {
|
| return _getMemberInParents(memberName);
|
| }
|
|
|
| - MemberSet resolveMember(String memberName) {
|
| - var mem = getMember(memberName);
|
| - if (mem == null) return null;
|
| -
|
| - var ret = new MemberSet(mem);
|
| - if (mem.isStatic) return ret;
|
| -
|
| - for (var t in genericType.subtypes) {
|
| - // TODO(jimhug): Do I resolve any type params here?
|
| - var m = t.members[memberName];
|
| - if (m != null) ret.add(m);
|
| - }
|
| -
|
| - return ret;
|
| - }
|
| -
|
| 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);
|
| @@ -683,8 +715,6 @@ class DefinedType extends Type {
|
| Map<String, Member> members;
|
| FactoryMap factories;
|
|
|
| - Map<String, MemberSet> _resolvedMembers;
|
| -
|
| Map<String, ConcreteType> _concreteTypes;
|
|
|
| /** Methods to be generated once we know for sure that the type is used. */
|
| @@ -695,7 +725,7 @@ class DefinedType extends Type {
|
|
|
| DefinedType(String name, this.library, Definition definition, this.isClass)
|
| : super(name), directSubtypes = new Set<Type>(), constructors = {},
|
| - members = {}, factories = new FactoryMap(), _resolvedMembers = {} {
|
| + members = {}, factories = new FactoryMap() {
|
| setDefinition(definition);
|
| }
|
|
|
| @@ -1129,41 +1159,6 @@ class DefinedType extends Type {
|
| return _getMemberInParents(memberName);
|
| }
|
|
|
| - MemberSet resolveMember(String memberName) {
|
| - MemberSet ret = _resolvedMembers[memberName];
|
| - if (ret != null) return ret;
|
| -
|
| - Member member = getMember(memberName);
|
| - if (member == null) {
|
| - // TODO(jimhug): Check for members on subtypes given dart's dynamism.
|
| - return null;
|
| - }
|
| -
|
| - // TODO(jimhug): Move this adding subtypes logic to MemberSet?
|
| - ret = new MemberSet(member);
|
| - _resolvedMembers[memberName] = ret;
|
| - if (member.isStatic) {
|
| - return ret;
|
| - } else {
|
| - for (var t in subtypes) {
|
| - if (!isClass && t.isClass) {
|
| - // If this is an interface, the actual implementation may
|
| - // come from a class that does not implement this interface.
|
| - // TODO(vsm): Use a more efficient lookup strategy.
|
| - // TODO(jimhug): This is made uglier by need to avoid dups.
|
| - final m = t.getMember(memberName);
|
| - if (m != null && ret.members.indexOf(m) == -1) {
|
| - ret.add(m);
|
| - }
|
| - } else {
|
| - final m = t.members[memberName];
|
| - if (m != null) ret.add(m);
|
| - }
|
| - }
|
| - return ret;
|
| - }
|
| - }
|
| -
|
| static String _getDottedName(NameTypeReference type) {
|
| if (type.names != null) {
|
| var names = map(type.names, (n) => n.name);
|
|
|