Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
| 6 | 6 |
| 7 class ClassEmitter extends CodeEmitterHelper { | 7 class ClassEmitter extends CodeEmitterHelper { |
| 8 | 8 |
| 9 ClassStubGenerator get _stubGenerator => | 9 ClassStubGenerator get _stubGenerator => |
| 10 new ClassStubGenerator(compiler, namer, backend); | 10 new ClassStubGenerator(compiler, namer, backend); |
| 11 | 11 |
| 12 /** | 12 /** |
| 13 * Documentation wanted -- johnniwinther | 13 * Documentation wanted -- johnniwinther |
| 14 */ | 14 */ |
| 15 void emitClass(Class cls, | 15 void emitClass(Class cls, |
| 16 ClassBuilder enclosingBuilder, | 16 ClassBuilder enclosingBuilder, |
| 17 Map<String, jsAst.Expression> additionalProperties) { | 17 Map<String, jsAst.Expression> additionalProperties) { |
| 18 ClassElement classElement = cls.element; | 18 ClassElement classElement = cls.element; |
| 19 final onlyForRti = | 19 final onlyForRti = cls.onlyForRti; |
|
zarah
2015/01/23 10:47:30
Inline in the assert?
floitsch
2015/01/23 12:27:31
It's also used in emitInstanceMembers as argument.
| |
| 20 emitter.typeTestRegistry.rtiNeededClasses.contains(classElement); | |
| 21 | 20 |
| 22 assert(invariant(classElement, classElement.isDeclaration)); | 21 assert(invariant(classElement, classElement.isDeclaration)); |
| 23 assert(invariant(classElement, !classElement.isNative || onlyForRti)); | 22 assert(invariant(classElement, !classElement.isNative || onlyForRti)); |
|
zarah
2015/01/23 10:47:30
Use cls.isNative for consistency?
floitsch
2015/01/23 12:27:31
Done.
| |
| 24 | 23 |
| 25 emitter.needsClassSupport = true; | 24 emitter.needsClassSupport = true; |
| 26 String className = namer.getNameOfClass(classElement); | |
| 27 | 25 |
| 28 ClassElement superclass = classElement.superclass; | 26 ClassElement superclass = classElement.superclass; |
| 29 String superName = ""; | 27 String superName = ""; |
| 30 if (superclass != null) { | 28 if (superclass != null) { |
| 31 superName = namer.getNameOfClass(superclass); | 29 superName = namer.getNameOfClass(superclass); |
| 32 } | 30 } |
| 33 | 31 |
| 34 if (cls.isMixinApplication) { | 32 if (cls.isMixinApplication) { |
| 35 MixinApplication mixinApplication = cls; | 33 MixinApplication mixinApplication = cls; |
| 36 String mixinName = mixinApplication.mixinClass.name; | 34 String mixinName = mixinApplication.mixinClass.name; |
| 37 superName = '$superName+$mixinName'; | 35 superName = '$superName+$mixinName'; |
| 38 emitter.needsMixinSupport = true; | 36 emitter.needsMixinSupport = true; |
| 39 } | 37 } |
| 40 | 38 |
| 41 ClassBuilder builder = new ClassBuilder(classElement, namer); | 39 ClassBuilder builder = new ClassBuilder(classElement, namer); |
| 42 builder.superName = superName; | 40 builder.superName = superName; |
| 43 emitConstructorsForCSP(classElement, onlyForRti: onlyForRti); | 41 emitConstructorsForCSP(cls); |
| 44 emitFields(classElement, builder, onlyForRti: onlyForRti); | 42 emitFields(cls, builder); |
| 45 emitCheckedClassSetters(classElement, builder, onlyForRti: onlyForRti); | 43 emitCheckedClassSetters(cls, builder); |
| 46 emitClassGettersSettersForCSP(classElement, builder, | 44 emitClassGettersSettersForCSP(cls, builder); |
| 47 onlyForRti: onlyForRti); | |
| 48 emitInstanceMembers(classElement, builder, onlyForRti: onlyForRti); | 45 emitInstanceMembers(classElement, builder, onlyForRti: onlyForRti); |
| 49 emitRuntimeTypeInformation(cls, builder); | 46 emitRuntimeTypeInformation(cls, builder); |
| 50 if (additionalProperties != null) { | 47 if (additionalProperties != null) { |
| 51 additionalProperties.forEach(builder.addProperty); | 48 additionalProperties.forEach(builder.addProperty); |
| 52 } | 49 } |
| 53 | 50 |
| 54 if (classElement == backend.closureClass) { | 51 if (classElement == backend.closureClass) { |
| 55 // We add a special getter here to allow for tearing off a closure from | 52 // We add a special getter here to allow for tearing off a closure from |
| 56 // itself. | 53 // itself. |
| 57 String name = namer.getMappedInstanceName(Compiler.CALL_OPERATOR_NAME); | 54 String name = namer.getMappedInstanceName(Compiler.CALL_OPERATOR_NAME); |
| 58 jsAst.Fun function = js('function() { return this; }'); | 55 jsAst.Fun function = js('function() { return this; }'); |
| 59 builder.addProperty(namer.getterNameFromAccessorName(name), function); | 56 builder.addProperty(namer.getterNameFromAccessorName(name), function); |
| 60 } | 57 } |
| 61 | 58 |
| 62 emitTypeVariableReaders(classElement, builder); | 59 emitTypeVariableReaders(classElement, builder); |
| 63 | 60 |
| 64 emitClassBuilderWithReflectionData( | 61 emitClassBuilderWithReflectionData(cls, builder, enclosingBuilder); |
| 65 className, classElement, builder, enclosingBuilder); | |
| 66 } | 62 } |
| 67 /** | 63 /** |
| 68 * Emits the precompiled constructor when in CSP mode. | 64 * Emits the precompiled constructor when in CSP mode. |
| 69 */ | 65 */ |
| 70 void emitConstructorsForCSP(ClassElement classElement, | 66 void emitConstructorsForCSP(Class cls) { |
| 71 {bool onlyForRti: false}) { | 67 List<String> fieldNames = <String>[]; |
| 72 List<String> fields = <String>[]; | |
| 73 | 68 |
| 74 if (!compiler.useContentSecurityPolicy) return; | 69 if (!compiler.useContentSecurityPolicy) return; |
| 75 | 70 |
| 76 if (!onlyForRti && !classElement.isNative) { | 71 if (!cls.onlyForRti && !cls.isNative) { |
| 77 visitFields(classElement, false, | 72 fieldNames = cls.fields.map((Field field) => field.name).toList(); |
| 78 (Element member, | |
| 79 String name, | |
| 80 String accessorName, | |
| 81 bool needsGetter, | |
| 82 bool needsSetter, | |
| 83 bool needsCheckedSetter) { | |
| 84 fields.add(name); | |
| 85 }); | |
| 86 } | 73 } |
| 74 | |
| 75 ClassElement classElement = cls.element; | |
| 76 | |
| 87 jsAst.Expression constructorAst = | 77 jsAst.Expression constructorAst = |
| 88 _stubGenerator.generateClassConstructor(classElement, fields); | 78 _stubGenerator.generateClassConstructor(classElement, fieldNames); |
| 89 | 79 |
| 90 String constructorName = namer.getNameOfClass(classElement); | 80 String constructorName = namer.getNameOfClass(classElement); |
| 91 OutputUnit outputUnit = | 81 OutputUnit outputUnit = |
| 92 compiler.deferredLoadTask.outputUnitForElement(classElement); | 82 compiler.deferredLoadTask.outputUnitForElement(classElement); |
| 93 emitter.emitPrecompiledConstructor( | 83 emitter.emitPrecompiledConstructor( |
| 94 outputUnit, constructorName, constructorAst, fields); | 84 outputUnit, constructorName, constructorAst, fieldNames); |
| 95 } | 85 } |
| 96 | 86 |
| 97 /// Returns `true` if fields added. | 87 /// Returns `true` if fields added. |
| 98 bool emitFields(Element element, | 88 bool emitFields(FieldContainer container, |
| 99 ClassBuilder builder, | 89 ClassBuilder builder, |
| 100 { bool classIsNative: false, | 90 { bool classIsNative: false, |
| 101 bool emitStatics: false, | 91 bool emitStatics: false }) { |
| 102 bool onlyForRti: false }) { | 92 Iterable<Field> fields; |
| 103 assert(!emitStatics || !onlyForRti); | 93 if (container is Class) { |
| 104 if (element.isLibrary) { | 94 if (emitStatics) { |
| 105 assert(invariant(element, emitStatics)); | 95 fields = container.staticFieldsForReflection; |
| 106 } else if (!element.isClass) { | 96 } else if (container.onlyForRti) { |
| 107 throw new SpannableAssertionFailure( | 97 return false; |
| 108 element, 'Must be a ClassElement or a LibraryElement'); | 98 } else { |
| 99 fields = container.fields; | |
| 100 } | |
| 101 } else { | |
| 102 assert(container is Library); | |
| 103 assert(emitStatics); | |
| 104 fields = container.staticFieldsForReflection; | |
| 109 } | 105 } |
| 106 | |
| 110 var fieldMetadata = []; | 107 var fieldMetadata = []; |
| 111 bool hasMetadata = false; | 108 bool hasMetadata = false; |
| 112 bool fieldsAdded = false; | 109 bool fieldsAdded = false; |
| 113 | 110 |
| 114 if (!onlyForRti) { | 111 for (Field field in fields) { |
| 115 visitFields(element, emitStatics, | 112 VariableElement fieldElement = field.element; |
| 116 (VariableElement field, | 113 String name = field.name; |
| 117 String name, | 114 String accessorName = field.accessorName; |
| 118 String accessorName, | 115 bool needsGetter = field.needsGetter; |
| 119 bool needsGetter, | 116 bool needsSetter = field.needsUncheckedSetter; |
| 120 bool needsSetter, | 117 |
| 121 bool needsCheckedSetter) { | |
| 122 // Ignore needsCheckedSetter - that is handled below. | 118 // Ignore needsCheckedSetter - that is handled below. |
| 123 bool needsAccessor = (needsGetter || needsSetter); | 119 bool needsAccessor = (needsGetter || needsSetter); |
| 124 // We need to output the fields for non-native classes so we can auto- | 120 // We need to output the fields for non-native classes so we can auto- |
| 125 // generate the constructor. For native classes there are no | 121 // generate the constructor. For native classes there are no |
| 126 // constructors, so we don't need the fields unless we are generating | 122 // constructors, so we don't need the fields unless we are generating |
| 127 // accessors at runtime. | 123 // accessors at runtime. |
| 128 bool needsFieldsForConstructor = !emitStatics && !classIsNative; | 124 bool needsFieldsForConstructor = !emitStatics && !classIsNative; |
| 129 if (needsFieldsForConstructor || needsAccessor) { | 125 if (needsFieldsForConstructor || needsAccessor) { |
| 130 var metadata = emitter.metadataEmitter.buildMetadataFunction(field); | 126 var metadata = |
| 131 if (metadata != null) { | 127 emitter.metadataEmitter.buildMetadataFunction(fieldElement); |
| 132 hasMetadata = true; | 128 if (metadata != null) { |
| 129 hasMetadata = true; | |
| 130 } else { | |
| 131 metadata = new jsAst.LiteralNull(); | |
| 132 } | |
| 133 fieldMetadata.add(metadata); | |
| 134 recordMangledField(fieldElement, accessorName, | |
| 135 namer.privateName(fieldElement.library, fieldElement.name)); | |
| 136 String fieldName = name; | |
| 137 String fieldCode = ''; | |
| 138 String reflectionMarker = ''; | |
| 139 if (!needsAccessor) { | |
| 140 // Emit field for constructor generation. | |
| 141 assert(!classIsNative); | |
| 142 } else { | |
| 143 // Emit (possibly renaming) field name so we can add accessors at | |
| 144 // runtime. | |
| 145 if (name != accessorName) { | |
| 146 fieldName = '$accessorName:$name'; | |
| 147 } | |
| 148 | |
| 149 if (field.needsInterceptedGetter) { | |
| 150 emitter.interceptorEmitter.interceptorInvocationNames.add( | |
| 151 namer.getterName(fieldElement)); | |
| 152 } | |
| 153 // TODO(16168): The setter creator only looks at the getter-name. | |
| 154 // Even though the setter could avoid the interceptor convention we | |
| 155 // currently still need to add the additional argument. | |
| 156 if (field.needsInterceptedGetter || field.needsInterceptedSetter) { | |
| 157 emitter.interceptorEmitter.interceptorInvocationNames.add( | |
| 158 namer.setterName(fieldElement)); | |
| 159 } | |
| 160 | |
| 161 int code = field.getterFlags + (field.setterFlags << 2); | |
| 162 if (code == 0) { | |
| 163 compiler.internalError(fieldElement, | |
| 164 'Field code is 0 ($fieldElement).'); | |
| 133 } else { | 165 } else { |
| 134 metadata = new jsAst.LiteralNull(); | 166 fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]; |
| 135 } | 167 } |
| 136 fieldMetadata.add(metadata); | |
| 137 recordMangledField(field, accessorName, | |
| 138 namer.privateName(field.library, field.name)); | |
| 139 String fieldName = name; | |
| 140 String fieldCode = ''; | |
| 141 String reflectionMarker = ''; | |
| 142 if (!needsAccessor) { | |
| 143 // Emit field for constructor generation. | |
| 144 assert(!classIsNative); | |
| 145 } else { | |
| 146 // Emit (possibly renaming) field name so we can add accessors at | |
| 147 // runtime. | |
| 148 if (name != accessorName) { | |
| 149 fieldName = '$accessorName:$name'; | |
| 150 } | |
| 151 | |
| 152 int getterCode = 0; | |
| 153 if (needsAccessor && backend.fieldHasInterceptedGetter(field)) { | |
| 154 emitter.interceptorEmitter.interceptorInvocationNames.add( | |
| 155 namer.getterName(field)); | |
| 156 } | |
| 157 if (needsAccessor && backend.fieldHasInterceptedGetter(field)) { | |
| 158 emitter.interceptorEmitter.interceptorInvocationNames.add( | |
| 159 namer.setterName(field)); | |
| 160 } | |
| 161 if (needsGetter) { | |
| 162 if (field.isInstanceMember) { | |
| 163 // 01: function() { return this.field; } | |
| 164 // 10: function(receiver) { return receiver.field; } | |
| 165 // 11: function(receiver) { return this.field; } | |
| 166 bool isIntercepted = backend.fieldHasInterceptedGetter(field); | |
| 167 getterCode += isIntercepted ? 2 : 0; | |
| 168 getterCode += backend.isInterceptorClass(element) ? 0 : 1; | |
| 169 // TODO(sra): 'isInterceptorClass' might not be the correct test | |
| 170 // for methods forced to use the interceptor convention because | |
| 171 // the method's class was elsewhere mixed-in to an interceptor. | |
| 172 assert(!field.isInstanceMember || getterCode != 0); | |
| 173 if (isIntercepted) { | |
| 174 emitter.interceptorEmitter.interceptorInvocationNames.add( | |
| 175 namer.getterName(field)); | |
| 176 } | |
| 177 } else { | |
| 178 getterCode = 1; | |
| 179 } | |
| 180 } | |
| 181 int setterCode = 0; | |
| 182 if (needsSetter) { | |
| 183 if (field.isInstanceMember) { | |
| 184 // 01: function(value) { this.field = value; } | |
| 185 // 10: function(receiver, value) { receiver.field = value; } | |
| 186 // 11: function(receiver, value) { this.field = value; } | |
| 187 bool isIntercepted = backend.fieldHasInterceptedSetter(field); | |
| 188 setterCode += isIntercepted ? 2 : 0; | |
| 189 setterCode += backend.isInterceptorClass(element) ? 0 : 1; | |
| 190 assert(!field.isInstanceMember || setterCode != 0); | |
| 191 if (isIntercepted) { | |
| 192 emitter.interceptorEmitter.interceptorInvocationNames.add( | |
| 193 namer.setterName(field)); | |
| 194 } | |
| 195 } else { | |
| 196 setterCode = 1; | |
| 197 } | |
| 198 } | |
| 199 int code = getterCode + (setterCode << 2); | |
| 200 if (code == 0) { | |
| 201 compiler.internalError(field, | |
| 202 'Field code is 0 ($element/$field).'); | |
| 203 } else { | |
| 204 fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]; | |
| 205 } | |
| 206 } | |
| 207 if (backend.isAccessibleByReflection(field)) { | |
| 208 DartType type = field.type; | |
| 209 reflectionMarker = '-${emitter.metadataEmitter.reifyType(type)}'; | |
| 210 } | |
| 211 String builtFieldname = '$fieldName$fieldCode$reflectionMarker'; | |
| 212 builder.addField(builtFieldname); | |
| 213 // Add 1 because adding a field to the class also requires a comma | |
| 214 compiler.dumpInfoTask.recordFieldNameSize(field, | |
| 215 builtFieldname.length + 1); | |
| 216 fieldsAdded = true; | |
| 217 } | 168 } |
| 218 }); | 169 if (backend.isAccessibleByReflection(fieldElement)) { |
| 170 DartType type = fieldElement.type; | |
| 171 reflectionMarker = '-${emitter.metadataEmitter.reifyType(type)}'; | |
| 172 } | |
| 173 String builtFieldname = '$fieldName$fieldCode$reflectionMarker'; | |
| 174 builder.addField(builtFieldname); | |
| 175 // Add 1 because adding a field to the class also requires a comma | |
| 176 compiler.dumpInfoTask.recordFieldNameSize(fieldElement, | |
| 177 builtFieldname.length + 1); | |
| 178 fieldsAdded = true; | |
| 179 } | |
| 219 } | 180 } |
| 220 | 181 |
| 221 if (hasMetadata) { | 182 if (hasMetadata) { |
| 222 builder.fieldMetadata = fieldMetadata; | 183 builder.fieldMetadata = fieldMetadata; |
| 223 } | 184 } |
| 224 return fieldsAdded; | 185 return fieldsAdded; |
| 225 } | 186 } |
| 226 | 187 |
| 227 /// Emits checked setters for fields. | 188 /// Emits checked setters for fields. |
| 228 void emitCheckedClassSetters(ClassElement classElement, | 189 void emitCheckedClassSetters(Class cls, ClassBuilder builder) { |
| 229 ClassBuilder builder, | 190 if (cls.onlyForRti) return; |
| 230 {bool onlyForRti: false}) { | |
| 231 if (onlyForRti) return; | |
| 232 | 191 |
| 233 visitFields(classElement, false, | 192 for (Field field in cls.fields) { |
| 234 (VariableElement member, | 193 if (field.needsCheckedSetter) { |
| 235 String name, | 194 assert(!field.needsUncheckedSetter); |
| 236 String accessorName, | 195 compiler.withCurrentElement(field.element, () { |
| 237 bool needsGetter, | 196 generateCheckedSetter( |
| 238 bool needsSetter, | 197 field.element, field.name, field.accessorName, builder); |
| 239 bool needsCheckedSetter) { | 198 }); |
| 240 compiler.withCurrentElement(member, () { | 199 } |
| 241 if (needsCheckedSetter) { | 200 } |
| 242 assert(!needsSetter); | |
| 243 generateCheckedSetter(member, name, accessorName, builder); | |
| 244 } | |
| 245 }); | |
| 246 }); | |
| 247 } | 201 } |
| 248 | 202 |
| 249 /// Emits getters/setters for fields if compiling in CSP mode. | 203 /// Emits getters/setters for fields if compiling in CSP mode. |
| 250 void emitClassGettersSettersForCSP(ClassElement classElement, | 204 void emitClassGettersSettersForCSP(Class cls, ClassBuilder builder) { |
| 251 ClassBuilder builder, | |
| 252 {bool onlyForRti: false}) { | |
| 253 | 205 |
| 254 if (!compiler.useContentSecurityPolicy || onlyForRti) return; | 206 if (!compiler.useContentSecurityPolicy || cls.onlyForRti) return; |
| 255 | 207 |
| 256 visitFields(classElement, false, | 208 for (Field field in cls.fields) { |
| 257 (VariableElement member, | 209 Element member = field.element; |
| 258 String name, | |
| 259 String accessorName, | |
| 260 bool needsGetter, | |
| 261 bool needsSetter, | |
| 262 bool needsCheckedSetter) { | |
| 263 compiler.withCurrentElement(member, () { | 210 compiler.withCurrentElement(member, () { |
| 264 if (needsGetter) { | 211 if (field.needsGetter) { |
| 265 emitGetterForCSP(member, name, accessorName, builder); | 212 emitGetterForCSP(member, field.name, field.accessorName, builder); |
| 266 } | 213 } |
| 267 if (needsSetter) { | 214 if (field.needsUncheckedSetter) { |
| 268 emitSetterForCSP(member, name, accessorName, builder); | 215 emitSetterForCSP(member, field.name, field.accessorName, builder); |
| 269 } | 216 } |
| 270 }); | 217 }); |
| 271 }); | 218 } |
| 272 } | 219 } |
| 273 | 220 |
| 274 /** | 221 /** |
| 275 * Documentation wanted -- johnniwinther | 222 * Documentation wanted -- johnniwinther |
| 276 * | 223 * |
| 277 * Invariant: [classElement] must be a declaration element. | 224 * Invariant: [classElement] must be a declaration element. |
| 278 */ | 225 */ |
| 279 void emitInstanceMembers(ClassElement classElement, | 226 void emitInstanceMembers(ClassElement classElement, |
| 280 ClassBuilder builder, | 227 ClassBuilder builder, |
| 281 {bool onlyForRti: false}) { | 228 {bool onlyForRti: false}) { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 311 assert(builder.functionType == null); | 258 assert(builder.functionType == null); |
| 312 if (cls.functionTypeIndex != null) { | 259 if (cls.functionTypeIndex != null) { |
| 313 builder.functionType = '${cls.functionTypeIndex}'; | 260 builder.functionType = '${cls.functionTypeIndex}'; |
| 314 } | 261 } |
| 315 | 262 |
| 316 for (Method method in cls.isChecks) { | 263 for (Method method in cls.isChecks) { |
| 317 builder.addProperty(method.name, method.code); | 264 builder.addProperty(method.name, method.code); |
| 318 } | 265 } |
| 319 } | 266 } |
| 320 | 267 |
| 321 void emitClassBuilderWithReflectionData(String className, | 268 void emitClassBuilderWithReflectionData(Class cls, |
| 322 ClassElement classElement, | |
| 323 ClassBuilder classBuilder, | 269 ClassBuilder classBuilder, |
| 324 ClassBuilder enclosingBuilder) { | 270 ClassBuilder enclosingBuilder) { |
| 271 ClassElement classElement = cls.element; | |
| 272 String className = cls.name; | |
| 273 | |
| 325 var metadata = emitter.metadataEmitter.buildMetadataFunction(classElement); | 274 var metadata = emitter.metadataEmitter.buildMetadataFunction(classElement); |
| 326 if (metadata != null) { | 275 if (metadata != null) { |
| 327 classBuilder.addProperty("@", metadata); | 276 classBuilder.addProperty("@", metadata); |
| 328 } | 277 } |
| 329 | 278 |
| 330 if (backend.isAccessibleByReflection(classElement)) { | 279 if (backend.isAccessibleByReflection(classElement)) { |
| 331 List<DartType> typeVars = classElement.typeVariables; | 280 List<DartType> typeVars = classElement.typeVariables; |
| 332 Iterable typeVariableProperties = emitter.typeVariableHandler | 281 Iterable typeVariableProperties = emitter.typeVariableHandler |
| 333 .typeVariablesOf(classElement).map(js.number); | 282 .typeVariablesOf(classElement).map(js.number); |
| 334 | 283 |
| 335 ClassElement superclass = classElement.superclass; | 284 ClassElement superclass = classElement.superclass; |
| 336 bool hasSuper = superclass != null; | 285 bool hasSuper = superclass != null; |
| 337 if ((!typeVariableProperties.isEmpty && !hasSuper) || | 286 if ((!typeVariableProperties.isEmpty && !hasSuper) || |
| 338 (hasSuper && !equalElements(superclass.typeVariables, typeVars))) { | 287 (hasSuper && !equalElements(superclass.typeVariables, typeVars))) { |
| 339 classBuilder.addProperty('<>', | 288 classBuilder.addProperty('<>', |
| 340 new jsAst.ArrayInitializer(typeVariableProperties.toList())); | 289 new jsAst.ArrayInitializer(typeVariableProperties.toList())); |
| 341 } | 290 } |
| 342 } | 291 } |
| 343 | 292 |
| 344 List<jsAst.Property> statics = new List<jsAst.Property>(); | 293 List<jsAst.Property> statics = new List<jsAst.Property>(); |
| 345 ClassBuilder staticsBuilder = new ClassBuilder(classElement, namer); | 294 ClassBuilder staticsBuilder = new ClassBuilder(classElement, namer); |
| 346 if (emitFields(classElement, staticsBuilder, emitStatics: true)) { | 295 if (emitFields(cls, staticsBuilder, emitStatics: true)) { |
| 347 jsAst.ObjectInitializer initializer = | 296 jsAst.ObjectInitializer initializer = |
| 348 staticsBuilder.toObjectInitializer(); | 297 staticsBuilder.toObjectInitializer(); |
| 349 compiler.dumpInfoTask.registerElementAst(classElement, | 298 compiler.dumpInfoTask.registerElementAst(classElement, |
| 350 initializer); | 299 initializer); |
| 351 jsAst.Node property = initializer.properties.single; | 300 jsAst.Node property = initializer.properties.single; |
| 352 compiler.dumpInfoTask.registerElementAst(classElement, property); | 301 compiler.dumpInfoTask.registerElementAst(classElement, property); |
| 353 statics.add(property); | 302 statics.add(property); |
| 354 } | 303 } |
| 355 | 304 |
| 356 ClassBuilder classProperties = | 305 ClassBuilder classProperties = |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 631 js.number(index)); | 580 js.number(index)); |
| 632 } | 581 } |
| 633 jsAst.Expression convertRtiToRuntimeType = emitter | 582 jsAst.Expression convertRtiToRuntimeType = emitter |
| 634 .staticFunctionAccess(backend.findHelper('convertRtiToRuntimeType')); | 583 .staticFunctionAccess(backend.findHelper('convertRtiToRuntimeType')); |
| 635 compiler.dumpInfoTask.registerElementAst(element, | 584 compiler.dumpInfoTask.registerElementAst(element, |
| 636 builder.addProperty(name, | 585 builder.addProperty(name, |
| 637 js('function () { return #(#) }', | 586 js('function () { return #(#) }', |
| 638 [convertRtiToRuntimeType, computeTypeVariable]))); | 587 [convertRtiToRuntimeType, computeTypeVariable]))); |
| 639 } | 588 } |
| 640 } | 589 } |
| OLD | NEW |