| Index: sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
|
| deleted file mode 100644
|
| index cb4e509d5d91e9510b4699cb491457e946fd8441..0000000000000000000000000000000000000000
|
| --- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
|
| +++ /dev/null
|
| @@ -1,909 +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 js_backend;
|
| -
|
| -/// For each class, stores the possible class subtype tests that could succeed.
|
| -abstract class TypeChecks {
|
| - /// Get the set of checks required for class [element].
|
| - Iterable<TypeCheck> operator[](ClassElement element);
|
| - /// Get the iterator for all classes that need type checks.
|
| - Iterator<ClassElement> get iterator;
|
| -}
|
| -
|
| -typedef jsAst.Expression OnVariableCallback(TypeVariableType variable);
|
| -typedef bool ShouldEncodeTypedefCallback(TypedefType variable);
|
| -
|
| -class RuntimeTypes {
|
| - final Compiler compiler;
|
| - final TypeRepresentationGenerator representationGenerator;
|
| -
|
| - final Map<ClassElement, Set<ClassElement>> rtiDependencies;
|
| - final Set<ClassElement> classesNeedingRti;
|
| - final Set<Element> methodsNeedingRti;
|
| - // The set of classes that use one of their type variables as expressions
|
| - // to get the runtime type.
|
| - final Set<ClassElement> classesUsingTypeVariableExpression;
|
| - // The set of type arguments tested against type variable bounds.
|
| - final Set<DartType> checkedTypeArguments;
|
| - // The set of tested type variable bounds.
|
| - final Set<DartType> checkedBounds;
|
| -
|
| - JavaScriptBackend get backend => compiler.backend;
|
| -
|
| - RuntimeTypes(Compiler compiler)
|
| - : this.compiler = compiler,
|
| - representationGenerator = new TypeRepresentationGenerator(compiler),
|
| - classesNeedingRti = new Set<ClassElement>(),
|
| - methodsNeedingRti = new Set<Element>(),
|
| - rtiDependencies = new Map<ClassElement, Set<ClassElement>>(),
|
| - classesUsingTypeVariableExpression = new Set<ClassElement>(),
|
| - checkedTypeArguments = new Set<DartType>(),
|
| - checkedBounds = new Set<DartType>();
|
| -
|
| - Set<ClassElement> directlyInstantiatedArguments;
|
| - Set<ClassElement> allInstantiatedArguments;
|
| - Set<ClassElement> checkedArguments;
|
| -
|
| - void registerRtiDependency(Element element, Element dependency) {
|
| - // We're not dealing with typedef for now.
|
| - if (!element.isClass || !dependency.isClass) return;
|
| - Set<ClassElement> classes =
|
| - rtiDependencies.putIfAbsent(element, () => new Set<ClassElement>());
|
| - classes.add(dependency);
|
| - }
|
| -
|
| - void registerTypeVariableBoundsSubtypeCheck(DartType typeArgument,
|
| - DartType bound) {
|
| - checkedTypeArguments.add(typeArgument);
|
| - checkedBounds.add(bound);
|
| - }
|
| -
|
| - bool usingFactoryWithTypeArguments = false;
|
| -
|
| - /**
|
| - * Compute type arguments of classes that use one of their type variables in
|
| - * is-checks and add the is-checks that they imply.
|
| - *
|
| - * This function must be called after all is-checks have been registered.
|
| - *
|
| - * TODO(karlklose): move these computations into a function producing an
|
| - * immutable datastructure.
|
| - */
|
| - void addImplicitChecks(Universe universe,
|
| - Iterable<ClassElement> classesUsingChecks) {
|
| - // If there are no classes that use their variables in checks, there is
|
| - // nothing to do.
|
| - if (classesUsingChecks.isEmpty) return;
|
| - Set<DartType> instantiatedTypes = universe.instantiatedTypes;
|
| - if (universe.usingFactoryWithTypeArguments) {
|
| - for (DartType type in instantiatedTypes) {
|
| - if (type.kind != TypeKind.INTERFACE) continue;
|
| - InterfaceType interface = type;
|
| - do {
|
| - for (DartType argument in interface.typeArguments) {
|
| - universe.registerIsCheck(argument, compiler);
|
| - }
|
| - interface = interface.element.supertype;
|
| - } while (interface != null && !instantiatedTypes.contains(interface));
|
| - }
|
| - } else {
|
| - // Find all instantiated types that are a subtype of a class that uses
|
| - // one of its type arguments in an is-check and add the arguments to the
|
| - // set of is-checks.
|
| - // TODO(karlklose): replace this with code that uses a subtype lookup
|
| - // datastructure in the world.
|
| - for (DartType type in instantiatedTypes) {
|
| - if (type.kind != TypeKind.INTERFACE) continue;
|
| - InterfaceType classType = type;
|
| - for (ClassElement cls in classesUsingChecks) {
|
| - InterfaceType current = classType;
|
| - do {
|
| - // We need the type as instance of its superclass anyway, so we just
|
| - // try to compute the substitution; if the result is [:null:], the
|
| - // classes are not related.
|
| - InterfaceType instance = current.asInstanceOf(cls);
|
| - if (instance == null) break;
|
| - for (DartType argument in instance.typeArguments) {
|
| - universe.registerIsCheck(argument, compiler);
|
| - }
|
| - current = current.element.supertype;
|
| - } while (current != null && !instantiatedTypes.contains(current));
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - void computeClassesNeedingRti() {
|
| - // Find the classes that need runtime type information. Such
|
| - // classes are:
|
| - // (1) used in a is check with type variables,
|
| - // (2) dependencies of classes in (1),
|
| - // (3) subclasses of (2) and (3).
|
| - void potentiallyAddForRti(ClassElement cls) {
|
| - assert(invariant(cls, cls.isDeclaration));
|
| - if (cls.typeVariables.isEmpty) return;
|
| - if (classesNeedingRti.contains(cls)) return;
|
| - classesNeedingRti.add(cls);
|
| -
|
| - // TODO(ngeoffray): This should use subclasses, not subtypes.
|
| - Iterable<ClassElement> classes = compiler.world.subtypesOf(cls);
|
| - classes.forEach((ClassElement sub) {
|
| - potentiallyAddForRti(sub);
|
| - });
|
| -
|
| - Set<ClassElement> dependencies = rtiDependencies[cls];
|
| - if (dependencies != null) {
|
| - dependencies.forEach((ClassElement other) {
|
| - potentiallyAddForRti(other);
|
| - });
|
| - }
|
| - }
|
| -
|
| - Set<ClassElement> classesUsingTypeVariableTests = new Set<ClassElement>();
|
| - compiler.resolverWorld.isChecks.forEach((DartType type) {
|
| - if (type.isTypeVariable) {
|
| - TypeVariableElement variable = type.element;
|
| - classesUsingTypeVariableTests.add(variable.typeDeclaration);
|
| - }
|
| - });
|
| - // Add is-checks that result from classes using type variables in checks.
|
| - addImplicitChecks(compiler.resolverWorld, classesUsingTypeVariableTests);
|
| - // Add the rti dependencies that are implicit in the way the backend
|
| - // generates code: when we create a new [List], we actually create
|
| - // a JSArray in the backend and we need to add type arguments to
|
| - // the calls of the list constructor whenever we determine that
|
| - // JSArray needs type arguments.
|
| - // TODO(karlklose): make this dependency visible from code.
|
| - if (backend.jsArrayClass != null) {
|
| - registerRtiDependency(backend.jsArrayClass, compiler.listClass);
|
| - }
|
| - // Compute the set of all classes and methods that need runtime type
|
| - // information.
|
| - compiler.resolverWorld.isChecks.forEach((DartType type) {
|
| - if (type.isInterfaceType) {
|
| - InterfaceType itf = type;
|
| - if (!itf.treatAsRaw) {
|
| - potentiallyAddForRti(itf.element);
|
| - }
|
| - } else {
|
| - ClassElement contextClass = Types.getClassContext(type);
|
| - if (contextClass != null) {
|
| - // [type] contains type variables (declared in [contextClass]) if
|
| - // [contextClass] is non-null. This handles checks against type
|
| - // variables and function types containing type variables.
|
| - potentiallyAddForRti(contextClass);
|
| - }
|
| - if (type.isFunctionType) {
|
| - void analyzeMethod(TypedElement method) {
|
| - DartType memberType = method.type;
|
| - ClassElement contextClass = Types.getClassContext(memberType);
|
| - if (contextClass != null &&
|
| - compiler.types.isPotentialSubtype(memberType, type)) {
|
| - potentiallyAddForRti(contextClass);
|
| - methodsNeedingRti.add(method);
|
| - }
|
| - }
|
| - compiler.resolverWorld.closuresWithFreeTypeVariables.forEach(
|
| - analyzeMethod);
|
| - compiler.resolverWorld.callMethodsWithFreeTypeVariables.forEach(
|
| - analyzeMethod);
|
| - }
|
| - }
|
| - });
|
| - if (compiler.enableTypeAssertions) {
|
| - void analyzeMethod(TypedElement method) {
|
| - DartType memberType = method.type;
|
| - ClassElement contextClass = Types.getClassContext(memberType);
|
| - if (contextClass != null) {
|
| - potentiallyAddForRti(contextClass);
|
| - methodsNeedingRti.add(method);
|
| - }
|
| - }
|
| - compiler.resolverWorld.closuresWithFreeTypeVariables.forEach(
|
| - analyzeMethod);
|
| - compiler.resolverWorld.callMethodsWithFreeTypeVariables.forEach(
|
| - analyzeMethod);
|
| - }
|
| - // Add the classes that need RTI because they use a type variable as
|
| - // expression.
|
| - classesUsingTypeVariableExpression.forEach(potentiallyAddForRti);
|
| - }
|
| -
|
| - TypeChecks cachedRequiredChecks;
|
| -
|
| - TypeChecks get requiredChecks {
|
| - if (cachedRequiredChecks == null) {
|
| - computeRequiredChecks();
|
| - }
|
| - assert(cachedRequiredChecks != null);
|
| - return cachedRequiredChecks;
|
| - }
|
| -
|
| - /// Compute the required type checkes and substitutions for the given
|
| - /// instantitated and checked classes.
|
| - TypeChecks computeChecks(Set<ClassElement> instantiated,
|
| - Set<ClassElement> checked) {
|
| - // Run through the combination of instantiated and checked
|
| - // arguments and record all combination where the element of a checked
|
| - // argument is a superclass of the element of an instantiated type.
|
| - TypeCheckMapping result = new TypeCheckMapping();
|
| - for (ClassElement element in instantiated) {
|
| - if (checked.contains(element)) {
|
| - result.add(element, element, null);
|
| - }
|
| - // Find all supertypes of [element] in [checkedArguments] and add checks
|
| - // and precompute the substitutions for them.
|
| - assert(invariant(element, element.allSupertypes != null,
|
| - message: 'Supertypes have not been computed for $element.'));
|
| - for (DartType supertype in element.allSupertypes) {
|
| - ClassElement superelement = supertype.element;
|
| - if (checked.contains(superelement)) {
|
| - Substitution substitution =
|
| - computeSubstitution(element, superelement);
|
| - result.add(element, superelement, substitution);
|
| - }
|
| - }
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - void computeRequiredChecks() {
|
| - Set<DartType> isChecks = compiler.codegenWorld.isChecks;
|
| - bool hasFunctionTypeCheck =
|
| - isChecks.any((type) => identical(type.kind, TypeKind.FUNCTION));
|
| - Set<DartType> instantiatedTypesAndClosures = hasFunctionTypeCheck
|
| - ? computeInstantiatedTypesAndClosures(compiler.codegenWorld)
|
| - : compiler.codegenWorld.instantiatedTypes;
|
| - computeInstantiatedArguments(instantiatedTypesAndClosures, isChecks);
|
| - computeCheckedArguments(instantiatedTypesAndClosures, isChecks);
|
| - cachedRequiredChecks =
|
| - computeChecks(allInstantiatedArguments, checkedArguments);
|
| - }
|
| -
|
| - Set<DartType> computeInstantiatedTypesAndClosures(Universe universe) {
|
| - Set<DartType> instantiatedTypes =
|
| - new Set<DartType>.from(universe.instantiatedTypes);
|
| - for (DartType instantiatedType in universe.instantiatedTypes) {
|
| - if (instantiatedType.isInterfaceType) {
|
| - InterfaceType interface = instantiatedType;
|
| - FunctionType callType = interface.callType;
|
| - if (callType != null) {
|
| - instantiatedTypes.add(callType);
|
| - }
|
| - }
|
| - }
|
| - for (FunctionElement element in universe.staticFunctionsNeedingGetter) {
|
| - instantiatedTypes.add(element.type);
|
| - }
|
| - // TODO(johnniwinther): We should get this information through the
|
| - // [neededClasses] computed in the emitter instead of storing it and pulling
|
| - // it from resolution, but currently it would introduce a cyclic dependency
|
| - // between [computeRequiredChecks] and [computeNeededClasses].
|
| - for (TypedElement element in compiler.resolverWorld.closurizedMembers) {
|
| - instantiatedTypes.add(element.type);
|
| - }
|
| - return instantiatedTypes;
|
| - }
|
| -
|
| - /**
|
| - * Collects all types used in type arguments of instantiated types.
|
| - *
|
| - * This includes type arguments used in supertype relations, because we may
|
| - * have a type check against this supertype that includes a check against
|
| - * the type arguments.
|
| - */
|
| - void computeInstantiatedArguments(Set<DartType> instantiatedTypes,
|
| - Set<DartType> isChecks) {
|
| - ArgumentCollector superCollector = new ArgumentCollector(backend);
|
| - ArgumentCollector directCollector = new ArgumentCollector(backend);
|
| - FunctionArgumentCollector functionArgumentCollector =
|
| - new FunctionArgumentCollector(backend);
|
| -
|
| - // We need to add classes occuring in function type arguments, like for
|
| - // instance 'I' for [: o is C<f> :] where f is [: typedef I f(); :].
|
| - void collectFunctionTypeArguments(Iterable<DartType> types) {
|
| - for (DartType type in types) {
|
| - functionArgumentCollector.collect(type);
|
| - }
|
| - }
|
| - collectFunctionTypeArguments(isChecks);
|
| - collectFunctionTypeArguments(checkedBounds);
|
| -
|
| - void collectTypeArguments(Iterable<DartType> types,
|
| - {bool isTypeArgument: false}) {
|
| - for (DartType type in types) {
|
| - directCollector.collect(type, isTypeArgument: isTypeArgument);
|
| - if (type.isInterfaceType) {
|
| - ClassElement cls = type.element;
|
| - for (DartType supertype in cls.allSupertypes) {
|
| - superCollector.collect(supertype, isTypeArgument: isTypeArgument);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - collectTypeArguments(instantiatedTypes);
|
| - collectTypeArguments(checkedTypeArguments, isTypeArgument: true);
|
| -
|
| - for (ClassElement cls in superCollector.classes.toList()) {
|
| - for (DartType supertype in cls.allSupertypes) {
|
| - superCollector.collect(supertype);
|
| - }
|
| - }
|
| -
|
| - directlyInstantiatedArguments =
|
| - directCollector.classes..addAll(functionArgumentCollector.classes);
|
| - allInstantiatedArguments =
|
| - superCollector.classes..addAll(directlyInstantiatedArguments);
|
| - }
|
| -
|
| - /// Collects all type arguments used in is-checks.
|
| - void computeCheckedArguments(Set<DartType> instantiatedTypes,
|
| - Set<DartType> isChecks) {
|
| - ArgumentCollector collector = new ArgumentCollector(backend);
|
| - FunctionArgumentCollector functionArgumentCollector =
|
| - new FunctionArgumentCollector(backend);
|
| -
|
| - // We need to add types occuring in function type arguments, like for
|
| - // instance 'J' for [: (J j) {} is f :] where f is
|
| - // [: typedef void f(I i); :] and 'J' is a subtype of 'I'.
|
| - void collectFunctionTypeArguments(Iterable<DartType> types) {
|
| - for (DartType type in types) {
|
| - functionArgumentCollector.collect(type);
|
| - }
|
| - }
|
| - collectFunctionTypeArguments(instantiatedTypes);
|
| - collectFunctionTypeArguments(checkedTypeArguments);
|
| -
|
| - void collectTypeArguments(Iterable<DartType> types,
|
| - {bool isTypeArgument: false}) {
|
| - for (DartType type in types) {
|
| - collector.collect(type, isTypeArgument: isTypeArgument);
|
| - }
|
| - }
|
| - collectTypeArguments(isChecks);
|
| - collectTypeArguments(checkedBounds, isTypeArgument: true);
|
| -
|
| - checkedArguments =
|
| - collector.classes..addAll(functionArgumentCollector.classes);
|
| - }
|
| -
|
| - Set<ClassElement> getClassesUsedInSubstitutions(JavaScriptBackend backend,
|
| - TypeChecks checks) {
|
| - Set<ClassElement> instantiated = new Set<ClassElement>();
|
| - ArgumentCollector collector = new ArgumentCollector(backend);
|
| - for (ClassElement target in checks) {
|
| - instantiated.add(target);
|
| - for (TypeCheck check in checks[target]) {
|
| - Substitution substitution = check.substitution;
|
| - if (substitution != null) {
|
| - collector.collectAll(substitution.arguments);
|
| - }
|
| - }
|
| - }
|
| - return instantiated..addAll(collector.classes);
|
| - }
|
| -
|
| - Set<ClassElement> getRequiredArgumentClasses(JavaScriptBackend backend) {
|
| - Set<ClassElement> requiredArgumentClasses =
|
| - new Set<ClassElement>.from(
|
| - getClassesUsedInSubstitutions(backend, requiredChecks));
|
| - return requiredArgumentClasses
|
| - ..addAll(directlyInstantiatedArguments)
|
| - ..addAll(checkedArguments);
|
| - }
|
| -
|
| - String getTypeRepresentationForTypeConstant(DartType type) {
|
| - JavaScriptBackend backend = compiler.backend;
|
| - Namer namer = backend.namer;
|
| - if (type.isDynamic) return namer.getRuntimeTypeName(null);
|
| - String name = namer.uniqueNameForTypeConstantElement(type.element);
|
| - if (!type.element.isClass) return name;
|
| - InterfaceType interface = type;
|
| - List<DartType> variables = interface.element.typeVariables;
|
| - // Type constants can currently only be raw types, so there is no point
|
| - // adding ground-term type parameters, as they would just be 'dynamic'.
|
| - // TODO(sra): Since the result string is used only in constructing constant
|
| - // names, it would result in more readable names if the final string was a
|
| - // legal JavaScript identifer.
|
| - if (variables.isEmpty) return name;
|
| - String arguments =
|
| - new List.filled(variables.length, 'dynamic').join(', ');
|
| - return '$name<$arguments>';
|
| - }
|
| -
|
| - // TODO(karlklose): maybe precompute this value and store it in typeChecks?
|
| - bool isTrivialSubstitution(ClassElement cls, ClassElement check) {
|
| - if (cls.isClosure) {
|
| - // TODO(karlklose): handle closures.
|
| - return true;
|
| - }
|
| -
|
| - // If there are no type variables or the type is the same, we do not need
|
| - // a substitution.
|
| - if (check.typeVariables.isEmpty || cls == check) {
|
| - return true;
|
| - }
|
| -
|
| - InterfaceType originalType = cls.thisType;
|
| - InterfaceType type = originalType.asInstanceOf(check);
|
| - // [type] is not a subtype of [check]. we do not generate a check and do not
|
| - // need a substitution.
|
| - if (type == null) return true;
|
| -
|
| - // Run through both lists of type variables and check if the type variables
|
| - // are identical at each position. If they are not, we need to calculate a
|
| - // substitution function.
|
| - List<DartType> variables = cls.typeVariables;
|
| - List<DartType> arguments = type.typeArguments;
|
| - if (variables.length != arguments.length) {
|
| - return false;
|
| - }
|
| - for (int index = 0; index < variables.length; index++) {
|
| - if (variables[index].element != arguments[index].element) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - /**
|
| - * Compute a JavaScript expression that describes the necessary substitution
|
| - * for type arguments in a subtype test.
|
| - *
|
| - * The result can be:
|
| - * 1) [:null:], if no substituted check is necessary, because the
|
| - * type variables are the same or there are no type variables in the class
|
| - * that is checked for.
|
| - * 2) A list expression describing the type arguments to be used in the
|
| - * subtype check, if the type arguments to be used in the check do not
|
| - * depend on the type arguments of the object.
|
| - * 3) A function mapping the type variables of the object to be checked to
|
| - * a list expression.
|
| - */
|
| - jsAst.Expression getSupertypeSubstitution(
|
| - ClassElement cls,
|
| - ClassElement check,
|
| - {bool alwaysGenerateFunction: false}) {
|
| - Substitution substitution = getSubstitution(cls, check);
|
| - if (substitution != null) {
|
| - return substitution.getCode(this, alwaysGenerateFunction);
|
| - } else {
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - Substitution getSubstitution(ClassElement cls, ClassElement other) {
|
| - // Look for a precomputed check.
|
| - for (TypeCheck check in cachedRequiredChecks[cls]) {
|
| - if (check.cls == other) {
|
| - return check.substitution;
|
| - }
|
| - }
|
| - // There is no precomputed check for this pair (because the check is not
|
| - // done on type arguments only. Compute a new substitution.
|
| - return computeSubstitution(cls, other);
|
| - }
|
| -
|
| - Substitution computeSubstitution(ClassElement cls, ClassElement check,
|
| - { bool alwaysGenerateFunction: false }) {
|
| - if (isTrivialSubstitution(cls, check)) return null;
|
| -
|
| - // Unnamed mixin application classes do not need substitutions, because they
|
| - // are never instantiated and their checks are overwritten by the class that
|
| - // they are mixed into.
|
| - InterfaceType type = cls.thisType;
|
| - InterfaceType target = type.asInstanceOf(check);
|
| - List<DartType> typeVariables = cls.typeVariables;
|
| - if (typeVariables.isEmpty && !alwaysGenerateFunction) {
|
| - return new Substitution.list(target.typeArguments);
|
| - } else {
|
| - return new Substitution.function(target.typeArguments, typeVariables);
|
| - }
|
| - }
|
| -
|
| - jsAst.Expression getSubstitutionRepresentation(
|
| - List<DartType> types,
|
| - OnVariableCallback onVariable) {
|
| - List<jsAst.ArrayElement> elements = <jsAst.ArrayElement>[];
|
| - int index = 0;
|
| - for (DartType type in types) {
|
| - jsAst.Expression representation = getTypeRepresentation(type, onVariable);
|
| - elements.add(new jsAst.ArrayElement(index++, representation));
|
| - }
|
| - return new jsAst.ArrayInitializer(index, elements);
|
| - }
|
| -
|
| - jsAst.Expression getTypeEncoding(DartType type,
|
| - {bool alwaysGenerateFunction: false}) {
|
| - ClassElement contextClass = Types.getClassContext(type);
|
| - jsAst.Expression onVariable(TypeVariableType v) {
|
| - return new jsAst.VariableUse(v.name);
|
| - };
|
| - jsAst.Expression encoding = getTypeRepresentation(type, onVariable);
|
| - if (contextClass == null && !alwaysGenerateFunction) {
|
| - return encoding;
|
| - } else {
|
| - List<String> parameters = const <String>[];
|
| - if (contextClass != null) {
|
| - parameters = contextClass.typeVariables.map((type) {
|
| - return type.toString();
|
| - }).toList();
|
| - }
|
| - return js('function(#) { return # }', [parameters, encoding]);
|
| - }
|
| - }
|
| -
|
| - jsAst.Expression getSignatureEncoding(DartType type, jsAst.Expression this_) {
|
| - ClassElement contextClass = Types.getClassContext(type);
|
| - jsAst.Expression encoding =
|
| - getTypeEncoding(type, alwaysGenerateFunction: true);
|
| - if (contextClass != null) {
|
| - JavaScriptBackend backend = compiler.backend;
|
| - String contextName = backend.namer.getNameOfClass(contextClass);
|
| - return js('function () { return #(#, #, #); }',
|
| - [ backend.namer.elementAccess(backend.getComputeSignature()),
|
| - encoding, this_, js.string(contextName) ]);
|
| - } else {
|
| - return encoding;
|
| - }
|
| - }
|
| -
|
| - String getTypeRepresentationWithHashes(DartType type,
|
| - OnVariableCallback onVariable) {
|
| - // Create a type representation. For type variables call the original
|
| - // callback for side effects and return a template placeholder.
|
| - jsAst.Expression representation = getTypeRepresentation(type, (variable) {
|
| - onVariable(variable);
|
| - return new jsAst.LiteralString('#');
|
| - });
|
| - return jsAst.prettyPrint(representation, compiler).buffer.toString();
|
| - }
|
| -
|
| - jsAst.Expression getTypeRepresentation(
|
| - DartType type,
|
| - OnVariableCallback onVariable,
|
| - [ShouldEncodeTypedefCallback shouldEncodeTypedef]) {
|
| - return representationGenerator.getTypeRepresentation(
|
| - type, onVariable, shouldEncodeTypedef);
|
| - }
|
| -
|
| - bool isSimpleFunctionType(FunctionType type) {
|
| - if (!type.returnType.isDynamic) return false;
|
| - if (!type.optionalParameterTypes.isEmpty) return false;
|
| - if (!type.namedParameterTypes.isEmpty) return false;
|
| - for (DartType parameter in type.parameterTypes ) {
|
| - if (!parameter.isDynamic) return false;
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - static bool hasTypeArguments(DartType type) {
|
| - if (type is InterfaceType) {
|
| - InterfaceType interfaceType = type;
|
| - return !interfaceType.treatAsRaw;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - static int getTypeVariableIndex(TypeVariableElement variable) {
|
| - ClassElement classElement = variable.enclosingClass;
|
| - List<DartType> variables = classElement.typeVariables;
|
| - for (int index = 0; index < variables.length; index++) {
|
| - if (variables[index].element == variable) return index;
|
| - }
|
| - throw invariant(variable, false,
|
| - message: "Couldn't find type-variable index");
|
| - }
|
| -
|
| - /// Return all classes that are referenced in the type of the function, i.e.,
|
| - /// in the return type or the argument types.
|
| - Set<ClassElement> getReferencedClasses(FunctionType type) {
|
| - FunctionArgumentCollector collector =
|
| - new FunctionArgumentCollector(backend);
|
| - collector.collect(type);
|
| - return collector.classes;
|
| - }
|
| -}
|
| -
|
| -class TypeRepresentationGenerator extends DartTypeVisitor {
|
| - final Compiler compiler;
|
| - OnVariableCallback onVariable;
|
| - ShouldEncodeTypedefCallback shouldEncodeTypedef;
|
| -
|
| - JavaScriptBackend get backend => compiler.backend;
|
| - Namer get namer => backend.namer;
|
| -
|
| - TypeRepresentationGenerator(Compiler this.compiler);
|
| -
|
| - /**
|
| - * Creates a type representation for [type]. [onVariable] is called to provide
|
| - * the type representation for type variables.
|
| - */
|
| - jsAst.Expression getTypeRepresentation(
|
| - DartType type,
|
| - OnVariableCallback onVariable,
|
| - ShouldEncodeTypedefCallback encodeTypedef) {
|
| - this.onVariable = onVariable;
|
| - this.shouldEncodeTypedef =
|
| - (encodeTypedef != null) ? encodeTypedef : (TypedefType type) => false;
|
| - jsAst.Expression representation = visit(type);
|
| - this.onVariable = null;
|
| - this.shouldEncodeTypedef = null;
|
| - return representation;
|
| - }
|
| -
|
| - jsAst.Expression getJavaScriptClassName(Element element) {
|
| - return namer.elementAccess(element);
|
| - }
|
| -
|
| - visit(DartType type) {
|
| - return type.accept(this, null);
|
| - }
|
| -
|
| - visitTypeVariableType(TypeVariableType type, _) {
|
| - return onVariable(type);
|
| - }
|
| -
|
| - visitDynamicType(DynamicType type, _) {
|
| - return js('null');
|
| - }
|
| -
|
| - visitInterfaceType(InterfaceType type, _) {
|
| - jsAst.Expression name = getJavaScriptClassName(type.element);
|
| - return type.treatAsRaw ? name : visitList(type.typeArguments, head: name);
|
| - }
|
| -
|
| - jsAst.Expression visitList(List<DartType> types, {jsAst.Expression head}) {
|
| - int index = 0;
|
| - List<jsAst.ArrayElement> elements = <jsAst.ArrayElement>[];
|
| - if (head != null) {
|
| - elements.add(new jsAst.ArrayElement(0, head));
|
| - index++;
|
| - }
|
| - for (DartType type in types) {
|
| - elements.add(new jsAst.ArrayElement(index++, visit(type)));
|
| - }
|
| - return new jsAst.ArrayInitializer(elements.length, elements);
|
| - }
|
| -
|
| - visitFunctionType(FunctionType type, _) {
|
| - List<jsAst.Property> properties = <jsAst.Property>[];
|
| -
|
| - void addProperty(String name, jsAst.Expression value) {
|
| - properties.add(new jsAst.Property(js.string(name), value));
|
| - }
|
| -
|
| - jsAst.LiteralString name = js.string(namer.getFunctionTypeName(type));
|
| - addProperty(namer.functionTypeTag(), name);
|
| - if (type.returnType.isVoid) {
|
| - addProperty(namer.functionTypeVoidReturnTag(), js('true'));
|
| - } else if (!type.returnType.treatAsDynamic) {
|
| - addProperty(namer.functionTypeReturnTypeTag(), visit(type.returnType));
|
| - }
|
| - if (!type.parameterTypes.isEmpty) {
|
| - addProperty(namer.functionTypeRequiredParametersTag(),
|
| - visitList(type.parameterTypes));
|
| - }
|
| - if (!type.optionalParameterTypes.isEmpty) {
|
| - addProperty(namer.functionTypeOptionalParametersTag(),
|
| - visitList(type.optionalParameterTypes));
|
| - }
|
| - if (!type.namedParameterTypes.isEmpty) {
|
| - List<jsAst.Property> namedArguments = <jsAst.Property>[];
|
| - List<String> names = type.namedParameters;
|
| - List<DartType> types = type.namedParameterTypes;
|
| - assert(types.length == names.length);
|
| - for (int index = 0; index < types.length; index++) {
|
| - jsAst.Expression name = js.string(names[index]);
|
| - namedArguments.add(new jsAst.Property(name, visit(types[index])));
|
| - }
|
| - addProperty(namer.functionTypeNamedParametersTag(),
|
| - new jsAst.ObjectInitializer(namedArguments));
|
| - }
|
| - return new jsAst.ObjectInitializer(properties);
|
| - }
|
| -
|
| - visitMalformedType(MalformedType type, _) {
|
| - // Treat malformed types as dynamic at runtime.
|
| - return js('null');
|
| - }
|
| -
|
| - visitVoidType(VoidType type, _) {
|
| - // TODO(ahe): Reify void type ("null" means "dynamic").
|
| - return js('null');
|
| - }
|
| -
|
| - visitTypedefType(TypedefType type, _) {
|
| - bool shouldEncode = shouldEncodeTypedef(type);
|
| - DartType unaliasedType = type.unalias(compiler);
|
| - if (shouldEncode) {
|
| - jsAst.ObjectInitializer initializer = unaliasedType.accept(this, null);
|
| - // We have to encode the aliased type.
|
| - jsAst.Expression name = getJavaScriptClassName(type.element);
|
| - jsAst.Expression encodedTypedef =
|
| - type.treatAsRaw ? name : visitList(type.typeArguments, head: name);
|
| -
|
| - // Add it to the function-type object.
|
| - jsAst.LiteralString tag = js.string(namer.typedefTag());
|
| - initializer.properties.add(new jsAst.Property(tag, encodedTypedef));
|
| - return initializer;
|
| - } else {
|
| - return unaliasedType.accept(this, null);
|
| - }
|
| - }
|
| -
|
| - visitType(DartType type, _) {
|
| - compiler.internalError(NO_LOCATION_SPANNABLE,
|
| - 'Unexpected type: $type (${type.kind}).');
|
| - }
|
| -}
|
| -
|
| -
|
| -class TypeCheckMapping implements TypeChecks {
|
| - final Map<ClassElement, Set<TypeCheck>> map =
|
| - new Map<ClassElement, Set<TypeCheck>>();
|
| -
|
| - Iterable<TypeCheck> operator[](ClassElement element) {
|
| - Set<TypeCheck> result = map[element];
|
| - return result != null ? result : const <TypeCheck>[];
|
| - }
|
| -
|
| - void add(ClassElement cls, ClassElement check, Substitution substitution) {
|
| - map.putIfAbsent(cls, () => new Set<TypeCheck>());
|
| - map[cls].add(new TypeCheck(check, substitution));
|
| - }
|
| -
|
| - Iterator<ClassElement> get iterator => map.keys.iterator;
|
| -
|
| - String toString() {
|
| - StringBuffer sb = new StringBuffer();
|
| - for (ClassElement holder in this) {
|
| - for (ClassElement check in [holder]) {
|
| - sb.write('${holder.name}.' '${check.name}, ');
|
| - }
|
| - }
|
| - return '[$sb]';
|
| - }
|
| -}
|
| -
|
| -class ArgumentCollector extends DartTypeVisitor {
|
| - final JavaScriptBackend backend;
|
| - final Set<ClassElement> classes = new Set<ClassElement>();
|
| -
|
| - ArgumentCollector(this.backend);
|
| -
|
| - collect(DartType type, {bool isTypeArgument: false}) {
|
| - type.accept(this, isTypeArgument);
|
| - }
|
| -
|
| - /// Collect all types in the list as if they were arguments of an
|
| - /// InterfaceType.
|
| - collectAll(List<DartType> types) {
|
| - for (DartType type in types) {
|
| - type.accept(this, true);
|
| - }
|
| - }
|
| -
|
| - visitType(DartType type, _) {
|
| - // Do nothing.
|
| - }
|
| -
|
| - visitDynamicType(DynamicType type, _) {
|
| - // Do not collect [:dynamic:].
|
| - }
|
| -
|
| - visitTypedefType(TypedefType type, bool isTypeArgument) {
|
| - type.unalias(backend.compiler).accept(this, isTypeArgument);
|
| - }
|
| -
|
| - visitInterfaceType(InterfaceType type, bool isTypeArgument) {
|
| - if (isTypeArgument) classes.add(type.element);
|
| - type.visitChildren(this, true);
|
| - }
|
| -
|
| - visitFunctionType(FunctionType type, _) {
|
| - type.visitChildren(this, true);
|
| - }
|
| -}
|
| -
|
| -class FunctionArgumentCollector extends DartTypeVisitor {
|
| - final JavaScriptBackend backend;
|
| - final Set<ClassElement> classes = new Set<ClassElement>();
|
| -
|
| - FunctionArgumentCollector(this.backend);
|
| -
|
| - collect(DartType type) {
|
| - type.accept(this, false);
|
| - }
|
| -
|
| - /// Collect all types in the list as if they were arguments of an
|
| - /// InterfaceType.
|
| - collectAll(Link<DartType> types) {
|
| - for (Link<DartType> link = types; !link.isEmpty; link = link.tail) {
|
| - link.head.accept(this, true);
|
| - }
|
| - }
|
| -
|
| - visitType(DartType type, _) {
|
| - // Do nothing.
|
| - }
|
| -
|
| - visitDynamicType(DynamicType type, _) {
|
| - // Do not collect [:dynamic:].
|
| - }
|
| -
|
| - visitTypedefType(TypedefType type, bool inFunctionType) {
|
| - type.unalias(backend.compiler).accept(this, inFunctionType);
|
| - }
|
| -
|
| - visitInterfaceType(InterfaceType type, bool inFunctionType) {
|
| - if (inFunctionType) {
|
| - classes.add(type.element);
|
| - }
|
| - type.visitChildren(this, inFunctionType);
|
| - }
|
| -
|
| - visitFunctionType(FunctionType type, _) {
|
| - type.visitChildren(this, true);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Representation of the substitution of type arguments
|
| - * when going from the type of a class to one of its supertypes.
|
| - *
|
| - * For [:class B<T> extends A<List<T>, int>:], the substitution is
|
| - * the representation of [: (T) => [<List, T>, int] :]. For more details
|
| - * of the representation consult the documentation of
|
| - * [getSupertypeSubstitution].
|
| - */
|
| -class Substitution {
|
| - final bool isFunction;
|
| - final List<DartType> arguments;
|
| - final List<DartType> parameters;
|
| -
|
| - Substitution.list(this.arguments)
|
| - : isFunction = false,
|
| - parameters = const <DartType>[];
|
| -
|
| - Substitution.function(this.arguments, this.parameters)
|
| - : isFunction = true;
|
| -
|
| - jsAst.Expression getCode(RuntimeTypes rti, bool ensureIsFunction) {
|
| - jsAst.Expression declaration(TypeVariableType variable) {
|
| - return new jsAst.Parameter(
|
| - rti.backend.namer.safeVariableName(variable.name));
|
| - }
|
| -
|
| - jsAst.Expression use(TypeVariableType variable) {
|
| - return new jsAst.VariableUse(
|
| - rti.backend.namer.safeVariableName(variable.name));
|
| - }
|
| -
|
| - jsAst.Expression value =
|
| - rti.getSubstitutionRepresentation(arguments, use);
|
| - if (isFunction) {
|
| - Iterable<jsAst.Expression> formals = parameters.map(declaration);
|
| - return js('function(#) { return # }', [formals, value]);
|
| - } else if (ensureIsFunction) {
|
| - return js('function() { return # }', value);
|
| - } else {
|
| - return value;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * A pair of a class that we need a check against and the type argument
|
| - * substition for this check.
|
| - */
|
| -class TypeCheck {
|
| - final ClassElement cls;
|
| - final Substitution substitution;
|
| - final int hashCode = (nextHash++) & 0x3fffffff;
|
| - static int nextHash = 49;
|
| -
|
| - TypeCheck(this.cls, this.substitution);
|
| -}
|
|
|