Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(187)

Unified Diff: sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
-}

Powered by Google App Engine
This is Rietveld 408576698