| Index: sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/class_emitter.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/class_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/class_emitter.dart
|
| deleted file mode 100644
|
| index 13e2df190681008572bc6c6b58a45d41942953b3..0000000000000000000000000000000000000000
|
| --- a/sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/class_emitter.dart
|
| +++ /dev/null
|
| @@ -1,609 +0,0 @@
|
| -// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -part of dart2js.js_emitter;
|
| -
|
| -class ClassEmitter extends CodeEmitterHelper {
|
| -
|
| - ClassStubGenerator get _stubGenerator =>
|
| - new ClassStubGenerator(compiler, namer, backend);
|
| -
|
| - /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: [classElement] must be a declaration element.
|
| - */
|
| - void generateClass(ClassElement classElement,
|
| - ClassBuilder properties,
|
| - Map<String, jsAst.Expression> additionalProperties) {
|
| - final onlyForRti =
|
| - emitter.typeTestEmitter.rtiNeededClasses.contains(classElement);
|
| -
|
| - assert(invariant(classElement, classElement.isDeclaration));
|
| - assert(invariant(classElement, !classElement.isNative || onlyForRti));
|
| -
|
| - emitter.needsDefineClass = true;
|
| - String className = namer.getNameOfClass(classElement);
|
| -
|
| - ClassElement superclass = classElement.superclass;
|
| - String superName = "";
|
| - if (superclass != null) {
|
| - superName = namer.getNameOfClass(superclass);
|
| - }
|
| -
|
| - if (classElement.isMixinApplication) {
|
| - String mixinName = namer.getNameOfClass(computeMixinClass(classElement));
|
| - superName = '$superName+$mixinName';
|
| - emitter.needsMixinSupport = true;
|
| - }
|
| -
|
| - ClassBuilder builder = new ClassBuilder(classElement, namer);
|
| - emitClassConstructor(classElement, builder, onlyForRti: onlyForRti);
|
| - emitFields(classElement, builder, superName, onlyForRti: onlyForRti);
|
| - emitClassGettersSetters(classElement, builder, onlyForRti: onlyForRti);
|
| - emitInstanceMembers(classElement, builder, onlyForRti: onlyForRti);
|
| - emitter.typeTestEmitter.emitIsTests(classElement, builder);
|
| - if (additionalProperties != null) {
|
| - additionalProperties.forEach(builder.addProperty);
|
| - }
|
| -
|
| - if (classElement == backend.closureClass) {
|
| - // We add a special getter here to allow for tearing off a closure from
|
| - // itself.
|
| - String name = namer.getMappedInstanceName(Compiler.CALL_OPERATOR_NAME);
|
| - jsAst.Fun function = js('function() { return this; }');
|
| - builder.addProperty(namer.getterNameFromAccessorName(name), function);
|
| - }
|
| -
|
| - emitTypeVariableReaders(classElement, builder);
|
| -
|
| - emitClassBuilderWithReflectionData(
|
| - className, classElement, builder, properties);
|
| - }
|
| -
|
| - void emitClassConstructor(ClassElement classElement,
|
| - ClassBuilder builder,
|
| - {bool onlyForRti: false}) {
|
| - List<String> fields = <String>[];
|
| - if (!onlyForRti && !classElement.isNative) {
|
| - visitFields(classElement, false,
|
| - (Element member,
|
| - String name,
|
| - String accessorName,
|
| - bool needsGetter,
|
| - bool needsSetter,
|
| - bool needsCheckedSetter) {
|
| - fields.add(name);
|
| - });
|
| - }
|
| -
|
| - jsAst.Expression constructorAst =
|
| - _stubGenerator.generateClassConstructor(classElement, fields);
|
| -
|
| - String constructorName = namer.getNameOfClass(classElement);
|
| - OutputUnit outputUnit =
|
| - compiler.deferredLoadTask.outputUnitForElement(classElement);
|
| - emitter.emitPrecompiledConstructor(
|
| - outputUnit, constructorName, constructorAst);
|
| - }
|
| -
|
| - /// Returns `true` if fields added.
|
| - bool emitFields(Element element,
|
| - ClassBuilder builder,
|
| - String superName,
|
| - { bool classIsNative: false,
|
| - bool emitStatics: false,
|
| - bool onlyForRti: false }) {
|
| - assert(!emitStatics || !onlyForRti);
|
| - if (element.isLibrary) {
|
| - assert(invariant(element, emitStatics));
|
| - } else if (!element.isClass) {
|
| - throw new SpannableAssertionFailure(
|
| - element, 'Must be a ClassElement or a LibraryElement');
|
| - }
|
| - if (emitStatics) {
|
| - assert(invariant(element, superName == null, message: superName));
|
| - } else {
|
| - assert(invariant(element, superName != null));
|
| - builder.superName = superName;
|
| - }
|
| - var fieldMetadata = [];
|
| - bool hasMetadata = false;
|
| - bool fieldsAdded = false;
|
| -
|
| - if (!onlyForRti) {
|
| - visitFields(element, emitStatics,
|
| - (VariableElement field,
|
| - String name,
|
| - String accessorName,
|
| - bool needsGetter,
|
| - bool needsSetter,
|
| - bool needsCheckedSetter) {
|
| - // Ignore needsCheckedSetter - that is handled below.
|
| - bool needsAccessor = (needsGetter || needsSetter);
|
| - // We need to output the fields for non-native classes so we can auto-
|
| - // generate the constructor. For native classes there are no
|
| - // constructors, so we don't need the fields unless we are generating
|
| - // accessors at runtime.
|
| - if (!classIsNative || needsAccessor) {
|
| - var metadata = emitter.metadataEmitter.buildMetadataFunction(field);
|
| - if (metadata != null) {
|
| - hasMetadata = true;
|
| - } else {
|
| - metadata = new jsAst.LiteralNull();
|
| - }
|
| - fieldMetadata.add(metadata);
|
| - recordMangledField(field, accessorName,
|
| - namer.privateName(field.library, field.name));
|
| - String fieldName = name;
|
| - String fieldCode = '';
|
| - String reflectionMarker = '';
|
| - if (!needsAccessor) {
|
| - // Emit field for constructor generation.
|
| - assert(!classIsNative);
|
| - } else {
|
| - // Emit (possibly renaming) field name so we can add accessors at
|
| - // runtime.
|
| - if (name != accessorName) {
|
| - fieldName = '$accessorName:$name';
|
| - }
|
| -
|
| - int getterCode = 0;
|
| - if (needsAccessor && backend.fieldHasInterceptedGetter(field)) {
|
| - emitter.interceptorEmitter.interceptorInvocationNames.add(
|
| - namer.getterName(field));
|
| - }
|
| - if (needsAccessor && backend.fieldHasInterceptedGetter(field)) {
|
| - emitter.interceptorEmitter.interceptorInvocationNames.add(
|
| - namer.setterName(field));
|
| - }
|
| - if (needsGetter) {
|
| - if (field.isInstanceMember) {
|
| - // 01: function() { return this.field; }
|
| - // 10: function(receiver) { return receiver.field; }
|
| - // 11: function(receiver) { return this.field; }
|
| - bool isIntercepted = backend.fieldHasInterceptedGetter(field);
|
| - getterCode += isIntercepted ? 2 : 0;
|
| - getterCode += backend.isInterceptorClass(element) ? 0 : 1;
|
| - // TODO(sra): 'isInterceptorClass' might not be the correct test
|
| - // for methods forced to use the interceptor convention because
|
| - // the method's class was elsewhere mixed-in to an interceptor.
|
| - assert(!field.isInstanceMember || getterCode != 0);
|
| - if (isIntercepted) {
|
| - emitter.interceptorEmitter.interceptorInvocationNames.add(
|
| - namer.getterName(field));
|
| - }
|
| - } else {
|
| - getterCode = 1;
|
| - }
|
| - }
|
| - int setterCode = 0;
|
| - if (needsSetter) {
|
| - if (field.isInstanceMember) {
|
| - // 01: function(value) { this.field = value; }
|
| - // 10: function(receiver, value) { receiver.field = value; }
|
| - // 11: function(receiver, value) { this.field = value; }
|
| - bool isIntercepted = backend.fieldHasInterceptedSetter(field);
|
| - setterCode += isIntercepted ? 2 : 0;
|
| - setterCode += backend.isInterceptorClass(element) ? 0 : 1;
|
| - assert(!field.isInstanceMember || setterCode != 0);
|
| - if (isIntercepted) {
|
| - emitter.interceptorEmitter.interceptorInvocationNames.add(
|
| - namer.setterName(field));
|
| - }
|
| - } else {
|
| - setterCode = 1;
|
| - }
|
| - }
|
| - int code = getterCode + (setterCode << 2);
|
| - if (code == 0) {
|
| - compiler.internalError(field,
|
| - 'Field code is 0 ($element/$field).');
|
| - } else {
|
| - fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE];
|
| - }
|
| - }
|
| - if (backend.isAccessibleByReflection(field)) {
|
| - DartType type = field.type;
|
| - reflectionMarker = '-${emitter.metadataEmitter.reifyType(type)}';
|
| - }
|
| - String builtFieldname = '$fieldName$fieldCode$reflectionMarker';
|
| - builder.addField(builtFieldname);
|
| - // Add 1 because adding a field to the class also requires a comma
|
| - compiler.dumpInfoTask.recordFieldNameSize(field,
|
| - builtFieldname.length + 1);
|
| - fieldsAdded = true;
|
| - }
|
| - });
|
| - }
|
| -
|
| - if (hasMetadata) {
|
| - builder.fieldMetadata = fieldMetadata;
|
| - }
|
| - return fieldsAdded;
|
| - }
|
| -
|
| - void emitClassGettersSetters(ClassElement classElement,
|
| - ClassBuilder builder,
|
| - {bool onlyForRti: false}) {
|
| - if (onlyForRti) return;
|
| -
|
| - visitFields(classElement, false,
|
| - (VariableElement member,
|
| - String name,
|
| - String accessorName,
|
| - bool needsGetter,
|
| - bool needsSetter,
|
| - bool needsCheckedSetter) {
|
| - compiler.withCurrentElement(member, () {
|
| - if (needsCheckedSetter) {
|
| - assert(!needsSetter);
|
| - generateCheckedSetter(member, name, accessorName, builder);
|
| - }
|
| - if (needsGetter) {
|
| - generateGetter(member, name, accessorName, builder);
|
| - }
|
| - if (needsSetter) {
|
| - generateSetter(member, name, accessorName, builder);
|
| - }
|
| - });
|
| - });
|
| - }
|
| -
|
| - /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: [classElement] must be a declaration element.
|
| - */
|
| - void emitInstanceMembers(ClassElement classElement,
|
| - ClassBuilder builder,
|
| - {bool onlyForRti: false}) {
|
| - assert(invariant(classElement, classElement.isDeclaration));
|
| -
|
| - if (onlyForRti || classElement.isMixinApplication) return;
|
| -
|
| - void visitMember(ClassElement enclosing, Element member) {
|
| - assert(invariant(classElement, member.isDeclaration));
|
| - if (member.isInstanceMember) {
|
| - emitter.containerBuilder.addMember(member, builder);
|
| - }
|
| - }
|
| -
|
| - classElement.implementation.forEachMember(
|
| - visitMember,
|
| - includeBackendMembers: true);
|
| -
|
| - if (identical(classElement, compiler.objectClass)
|
| - && compiler.enabledNoSuchMethod) {
|
| - // Emit the noSuchMethod handlers on the Object prototype now,
|
| - // so that the code in the dynamicFunction helper can find
|
| - // them. Note that this helper is invoked before analyzing the
|
| - // full JS script.
|
| - if (!emitter.nativeEmitter.handleNoSuchMethod) {
|
| - emitter.nsmEmitter.emitNoSuchMethodHandlers(builder.addProperty);
|
| - }
|
| - }
|
| - }
|
| -
|
| - void emitClassBuilderWithReflectionData(String className,
|
| - ClassElement classElement,
|
| - ClassBuilder classBuilder,
|
| - ClassBuilder enclosingBuilder) {
|
| - var metadata = emitter.metadataEmitter.buildMetadataFunction(classElement);
|
| - if (metadata != null) {
|
| - classBuilder.addProperty("@", metadata);
|
| - }
|
| -
|
| - if (backend.isAccessibleByReflection(classElement)) {
|
| - List<DartType> typeVars = classElement.typeVariables;
|
| - Iterable typeVariableProperties = emitter.typeVariableHandler
|
| - .typeVariablesOf(classElement).map(js.number);
|
| -
|
| - ClassElement superclass = classElement.superclass;
|
| - bool hasSuper = superclass != null;
|
| - if ((!typeVariableProperties.isEmpty && !hasSuper) ||
|
| - (hasSuper && !equalElements(superclass.typeVariables, typeVars))) {
|
| - classBuilder.addProperty('<>',
|
| - new jsAst.ArrayInitializer.from(typeVariableProperties));
|
| - }
|
| - }
|
| -
|
| - List<jsAst.Property> statics = new List<jsAst.Property>();
|
| - ClassBuilder staticsBuilder = new ClassBuilder(classElement, namer);
|
| - if (emitFields(classElement, staticsBuilder, null, emitStatics: true)) {
|
| - jsAst.ObjectInitializer initializer =
|
| - staticsBuilder.toObjectInitializer();
|
| - compiler.dumpInfoTask.registerElementAst(classElement,
|
| - initializer);
|
| - jsAst.Node property = initializer.properties.single;
|
| - compiler.dumpInfoTask.registerElementAst(classElement, property);
|
| - statics.add(property);
|
| - }
|
| -
|
| - ClassBuilder classProperties =
|
| - emitter.elementDescriptors.remove(classElement);
|
| - if (classProperties != null) {
|
| - statics.addAll(classProperties.properties);
|
| - }
|
| -
|
| - if (!statics.isEmpty) {
|
| - classBuilder.addProperty('static', new jsAst.ObjectInitializer(statics));
|
| - }
|
| -
|
| - // TODO(ahe): This method (generateClass) should return a jsAst.Expression.
|
| - jsAst.ObjectInitializer propertyValue = classBuilder.toObjectInitializer();
|
| - compiler.dumpInfoTask.registerElementAst(classBuilder.element, propertyValue);
|
| - enclosingBuilder.addProperty(className, propertyValue);
|
| -
|
| - String reflectionName = emitter.getReflectionName(classElement, className);
|
| - if (reflectionName != null) {
|
| - if (!backend.isAccessibleByReflection(classElement)) {
|
| - enclosingBuilder.addProperty("+$reflectionName", js.number(0));
|
| - } else {
|
| - List<int> types = <int>[];
|
| - if (classElement.supertype != null) {
|
| - types.add(emitter.metadataEmitter.reifyType(classElement.supertype));
|
| - }
|
| - for (DartType interface in classElement.interfaces) {
|
| - types.add(emitter.metadataEmitter.reifyType(interface));
|
| - }
|
| - enclosingBuilder.addProperty("+$reflectionName",
|
| - new jsAst.ArrayInitializer.from(types.map(js.number)));
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Invokes [f] for each of the fields of [element].
|
| - *
|
| - * [element] must be a [ClassElement] or a [LibraryElement].
|
| - *
|
| - * If [element] is a [ClassElement], the static fields of the class are
|
| - * visited if [visitStatics] is true and the instance fields are visited if
|
| - * [visitStatics] is false.
|
| - *
|
| - * If [element] is a [LibraryElement], [visitStatics] must be true.
|
| - *
|
| - * When visiting the instance fields of a class, the fields of its superclass
|
| - * are also visited if the class is instantiated.
|
| - *
|
| - * Invariant: [element] must be a declaration element.
|
| - */
|
| - void visitFields(Element element, bool visitStatics, AcceptField f) {
|
| - assert(invariant(element, element.isDeclaration));
|
| -
|
| - bool isClass = false;
|
| - bool isLibrary = false;
|
| - if (element.isClass) {
|
| - isClass = true;
|
| - } else if (element.isLibrary) {
|
| - isLibrary = true;
|
| - assert(invariant(element, visitStatics));
|
| - } else {
|
| - throw new SpannableAssertionFailure(
|
| - element, 'Expected a ClassElement or a LibraryElement.');
|
| - }
|
| -
|
| - // If the class is never instantiated we still need to set it up for
|
| - // inheritance purposes, but we can simplify its JavaScript constructor.
|
| - bool isInstantiated =
|
| - compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
|
| -
|
| - void visitField(Element holder, VariableElement field) {
|
| - assert(invariant(element, field.isDeclaration));
|
| - String name = field.name;
|
| -
|
| - // Keep track of whether or not we're dealing with a field mixin
|
| - // into a native class.
|
| - bool isMixinNativeField =
|
| - isClass && element.isNative && holder.isMixinApplication;
|
| -
|
| - // See if we can dynamically create getters and setters.
|
| - // We can only generate getters and setters for [element] since
|
| - // the fields of super classes could be overwritten with getters or
|
| - // setters.
|
| - bool needsGetter = false;
|
| - bool needsSetter = false;
|
| - if (isLibrary || isMixinNativeField || holder == element) {
|
| - needsGetter = fieldNeedsGetter(field);
|
| - needsSetter = fieldNeedsSetter(field);
|
| - }
|
| -
|
| - if ((isInstantiated && !holder.isNative)
|
| - || needsGetter
|
| - || needsSetter) {
|
| - String accessorName = namer.fieldAccessorName(field);
|
| - String fieldName = namer.fieldPropertyName(field);
|
| - bool needsCheckedSetter = false;
|
| - if (compiler.enableTypeAssertions
|
| - && needsSetter
|
| - && !canAvoidGeneratedCheckedSetter(field)) {
|
| - needsCheckedSetter = true;
|
| - needsSetter = false;
|
| - }
|
| - // Getters and setters with suffixes will be generated dynamically.
|
| - f(field, fieldName, accessorName, needsGetter, needsSetter,
|
| - needsCheckedSetter);
|
| - }
|
| - }
|
| -
|
| - if (isLibrary) {
|
| - LibraryElement library = element;
|
| - library.implementation.forEachLocalMember((Element member) {
|
| - if (member.isField) visitField(library, member);
|
| - });
|
| - } else if (visitStatics) {
|
| - ClassElement cls = element;
|
| - cls.implementation.forEachStaticField(visitField);
|
| - } else {
|
| - ClassElement cls = element;
|
| - // TODO(kasperl): We should make sure to only emit one version of
|
| - // overridden fields. Right now, we rely on the ordering so the
|
| - // fields pulled in from mixins are replaced with the fields from
|
| - // the class definition.
|
| -
|
| - // If a class is not instantiated then we add the field just so we can
|
| - // generate the field getter/setter dynamically. Since this is only
|
| - // allowed on fields that are in [element] we don't need to visit
|
| - // superclasses for non-instantiated classes.
|
| - cls.implementation.forEachInstanceField(
|
| - visitField, includeSuperAndInjectedMembers: isInstantiated);
|
| - }
|
| - }
|
| -
|
| - void recordMangledField(Element member,
|
| - String accessorName,
|
| - String memberName) {
|
| - if (!backend.shouldRetainGetter(member)) return;
|
| - String previousName;
|
| - if (member.isInstanceMember) {
|
| - previousName = emitter.mangledFieldNames.putIfAbsent(
|
| - '${namer.getterPrefix}$accessorName',
|
| - () => memberName);
|
| - } else {
|
| - previousName = emitter.mangledGlobalFieldNames.putIfAbsent(
|
| - accessorName,
|
| - () => memberName);
|
| - }
|
| - assert(invariant(member, previousName == memberName,
|
| - message: '$previousName != ${memberName}'));
|
| - }
|
| -
|
| - bool fieldNeedsGetter(VariableElement field) {
|
| - assert(field.isField);
|
| - if (fieldAccessNeverThrows(field)) return false;
|
| - return backend.shouldRetainGetter(field)
|
| - || compiler.codegenWorld.hasInvokedGetter(field, compiler.world);
|
| - }
|
| -
|
| - bool fieldNeedsSetter(VariableElement field) {
|
| - assert(field.isField);
|
| - if (fieldAccessNeverThrows(field)) return false;
|
| - return (!field.isFinal && !field.isConst)
|
| - && (backend.shouldRetainSetter(field)
|
| - || compiler.codegenWorld.hasInvokedSetter(field, compiler.world));
|
| - }
|
| -
|
| - // We never access a field in a closure (a captured variable) without knowing
|
| - // that it is there. Therefore we don't need to use a getter (that will throw
|
| - // if the getter method is missing), but can always access the field directly.
|
| - static bool fieldAccessNeverThrows(VariableElement field) {
|
| - return field is ClosureFieldElement;
|
| - }
|
| -
|
| - bool canAvoidGeneratedCheckedSetter(VariableElement member) {
|
| - // We never generate accessors for top-level/static fields.
|
| - if (!member.isInstanceMember) return true;
|
| - DartType type = member.type;
|
| - return type.treatAsDynamic || (type.element == compiler.objectClass);
|
| - }
|
| -
|
| - void generateCheckedSetter(Element member,
|
| - String fieldName,
|
| - String accessorName,
|
| - ClassBuilder builder) {
|
| - jsAst.Expression code = backend.generatedCode[member];
|
| - assert(code != null);
|
| - String setterName = namer.setterNameFromAccessorName(accessorName);
|
| - compiler.dumpInfoTask.registerElementAst(member,
|
| - builder.addProperty(setterName, code));
|
| - generateReflectionDataForFieldGetterOrSetter(
|
| - member, setterName, builder, isGetter: false);
|
| - }
|
| -
|
| - void generateGetter(Element member, String fieldName, String accessorName,
|
| - ClassBuilder builder) {
|
| - jsAst.Expression function =
|
| - _stubGenerator.generateGetter(member, fieldName);
|
| -
|
| - String getterName = namer.getterNameFromAccessorName(accessorName);
|
| - ClassElement cls = member.enclosingClass;
|
| - String className = namer.getNameOfClass(cls);
|
| - OutputUnit outputUnit =
|
| - compiler.deferredLoadTask.outputUnitForElement(member);
|
| - emitter.cspPrecompiledFunctionFor(outputUnit).add(
|
| - js('#.prototype.# = #', [className, getterName, function]));
|
| - if (backend.isAccessibleByReflection(member)) {
|
| - emitter.cspPrecompiledFunctionFor(outputUnit).add(
|
| - js('#.prototype.#.${namer.reflectableField} = 1',
|
| - [className, getterName]));
|
| - }
|
| - }
|
| -
|
| - void generateSetter(Element member, String fieldName, String accessorName,
|
| - ClassBuilder builder) {
|
| - jsAst.Expression function =
|
| - _stubGenerator.generateSetter(member, fieldName);
|
| -
|
| - String setterName = namer.setterNameFromAccessorName(accessorName);
|
| - ClassElement cls = member.enclosingClass;
|
| - String className = namer.getNameOfClass(cls);
|
| - OutputUnit outputUnit =
|
| - compiler.deferredLoadTask.outputUnitForElement(member);
|
| - emitter.cspPrecompiledFunctionFor(outputUnit).add(
|
| - js('#.prototype.# = #', [className, setterName, function]));
|
| - if (backend.isAccessibleByReflection(member)) {
|
| - emitter.cspPrecompiledFunctionFor(outputUnit).add(
|
| - js('#.prototype.#.${namer.reflectableField} = 1',
|
| - [className, setterName]));
|
| - }
|
| - }
|
| -
|
| - void generateReflectionDataForFieldGetterOrSetter(Element member,
|
| - String name,
|
| - ClassBuilder builder,
|
| - {bool isGetter}) {
|
| - Selector selector = isGetter
|
| - ? new Selector.getter(member.name, member.library)
|
| - : new Selector.setter(member.name, member.library);
|
| - String reflectionName = emitter.getReflectionName(selector, name);
|
| - if (reflectionName != null) {
|
| - var reflectable =
|
| - js(backend.isAccessibleByReflection(member) ? '1' : '0');
|
| - builder.addProperty('+$reflectionName', reflectable);
|
| - }
|
| - }
|
| -
|
| - void emitTypeVariableReaders(ClassElement cls, ClassBuilder builder) {
|
| - List typeVariables = [];
|
| - ClassElement superclass = cls;
|
| - while (superclass != null) {
|
| - for (TypeVariableType parameter in superclass.typeVariables) {
|
| - if (backend.emitter.readTypeVariables.contains(parameter.element)) {
|
| - emitTypeVariableReader(cls, builder, parameter.element);
|
| - }
|
| - }
|
| - superclass = superclass.superclass;
|
| - }
|
| - }
|
| -
|
| - void emitTypeVariableReader(ClassElement cls,
|
| - ClassBuilder builder,
|
| - TypeVariableElement element) {
|
| - String name = namer.readTypeVariableName(element);
|
| - jsAst.Expression index =
|
| - js.number(RuntimeTypes.getTypeVariableIndex(element));
|
| - jsAst.Expression computeTypeVariable;
|
| -
|
| - Substitution substitution =
|
| - backend.rti.computeSubstitution(
|
| - cls, element.typeDeclaration, alwaysGenerateFunction: true);
|
| - if (substitution != null) {
|
| - jsAst.Expression typeArguments =
|
| - js(r'#.apply(null, this.$builtinTypeInfo)',
|
| - substitution.getCode(backend.rti, true));
|
| - computeTypeVariable = js('#[#]', [typeArguments, index]);
|
| - } else {
|
| - // TODO(ahe): These can be generated dynamically.
|
| - computeTypeVariable =
|
| - js(r'this.$builtinTypeInfo && this.$builtinTypeInfo[#]', index);
|
| - }
|
| - jsAst.Expression convertRtiToRuntimeType =
|
| - namer.elementAccess(backend.findHelper('convertRtiToRuntimeType'));
|
| - compiler.dumpInfoTask.registerElementAst(element,
|
| - builder.addProperty(name,
|
| - js('function () { return #(#) }',
|
| - [convertRtiToRuntimeType, computeTypeVariable])));
|
| - }
|
| -}
|
|
|