Chromium Code Reviews| Index: frog/gen.dart |
| diff --git a/frog/gen.dart b/frog/gen.dart |
| index 74291fa7157be50fb590c26cd30d121d06009b0b..44c5a275bfcd50da307723e65c8db01ea0ce1839 100644 |
| --- a/frog/gen.dart |
| +++ b/frog/gen.dart |
| @@ -17,6 +17,7 @@ |
| class WorldGenerator { |
| MethodMember main; |
| CodeWriter writer; |
| + CodeWriter _mixins; |
| Map<String, GlobalValue> globals; |
| CoreJs corejs; |
| bool _inheritsGenerated = false; |
| @@ -52,6 +53,9 @@ class WorldGenerator { |
| // the topographic sort order. |
| writeTypes(main.declaringType.library); |
| + // Write out any inherited concrete members. |
| + if (_mixins != null) writer.write(_mixins.text); |
| + |
| _writeGlobals(); |
| writer.writeln('${mainCall.code};'); |
| } |
| @@ -192,9 +196,19 @@ class WorldGenerator { |
| if (!type.isTop) { |
| if (type is ConcreteType) { |
| + ConcreteType c = type; |
| _ensureInheritsHelper(); |
| - writer.writeln( |
| - '\$inherits(${type.jsname}, ${type.genericType.jsname});'); |
| + writer.writeln('\$inherits(${c.jsname}, ${c.genericType.jsname});'); |
| + |
| + // Mixin members from concrete specializations of base types too. |
| + // TODO(jmesserly): emit this sooner instead of at the end. |
| + // But it needs to come after we've emitted both types. |
| + // TODO(jmesserly): HACK: using _parent instead of parent so we don't |
| + // try to inherit things that we didn't actually use. |
| + for (var p = c._parent; p is ConcreteType; p = p._parent) { |
| + _ensureInheritMembersHelper(); |
| + _mixins.writeln('\$inheritsMembers(${c.jsname}, ${p.jsname});'); |
| + } |
| } else if (!type.isNativeType) { |
| if (type.parent != null && !type.parent.isObject) { |
| _ensureInheritsHelper(); |
| @@ -278,6 +292,25 @@ function $inherits(child, parent) { |
| }"""); |
| } |
| + /** |
| + * Generates the $inheritsMembers function when it's first used. |
| + * This is used to mix in specialized generic members from the base class. |
| + */ |
| + _ensureInheritMembersHelper() { |
| + if (_mixins != null) return; |
| + _mixins = new CodeWriter(); |
| + _mixins.comment('// ********** Generic Type Inheritance **************'); |
| + _mixins.writeln(@""" |
| +/** Implements extends for generic types. */ |
| +function $inheritsMembers(child, parent) { |
| + child = child.prototype; |
| + parent = parent.prototype; |
| + Object.getOwnPropertyNames(parent).forEach(function(name) { |
|
Jennifer Messerly
2011/11/18 18:51:29
Not sure if it makes sense to do this on the JS si
|
| + if (typeof(child[name]) == 'undefined') child[name] = parent[name]; |
| + }); |
| +}"""); |
| + } |
| + |
| _writeDynamicStubs(Type type) { |
| if (type.varStubs != null) { |
| for (var stub in orderValuesByKeys(type.varStubs)) { |
| @@ -787,11 +820,13 @@ class MethodGenerator implements TreeVisitor { |
| writeBody() { |
| var initializers = null; |
| var initializedFields = null; // to check that final fields are initialized |
| + var allMembers = null; |
| if (method.isConstructor) { |
| initializers = []; |
| initializedFields = new Set(); |
| - for (var f in world.gen._orderValues(method.declaringType.getAllMembers())) { |
| - if (f is FieldMember && !f.isStatic) { |
| + allMembers = world.gen._orderValues(method.declaringType.getAllMembers()); |
| + for (var f in allMembers) { |
| + if (f.isField && !f.isStatic) { |
|
Jennifer Messerly
2011/11/18 18:51:29
these can be ConcreteMembers too
|
| var cv = f.computeValue(); |
| if (cv != null) { |
| initializers.add('this.${f.jsname} = ${cv.code}'); |
| @@ -916,11 +951,10 @@ class MethodGenerator implements TreeVisitor { |
| // check that initialization was correct |
| if (initializedFields != null) { |
| - for (var name in method.declaringType.members.getKeys()) { |
| - var member = method.declaringType.members[name]; |
| - if (member is FieldMember && member.isFinal && !member.isStatic |
| - && !initializedFields.contains(name)) { |
| - world.error('Field "${name}" is final and was not initialized', |
| + for (var member in allMembers) { |
|
Jennifer Messerly
2011/11/18 18:51:29
this fixes an inconsistency: the loop above was us
|
| + if (member.isField && member.isFinal && !member.isStatic |
| + && !initializedFields.contains(member.name)) { |
| + world.error('Field "${member.name}" is final and was not initialized', |
| method.definition.span); |
| } |
| } |