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