Index: pkg/compiler/lib/src/constants/constructors.dart |
diff --git a/pkg/compiler/lib/src/constants/constructors.dart b/pkg/compiler/lib/src/constants/constructors.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3c09a94bc6086b6fdc761009017603dee8b6b718 |
--- /dev/null |
+++ b/pkg/compiler/lib/src/constants/constructors.dart |
@@ -0,0 +1,376 @@ |
+// Copyright (c) 2015, 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. |
+ |
+library dart2js.constants.constructors; |
+ |
+import '../elements/elements.dart'; |
+import 'expressions.dart'; |
+import 'values.dart'; |
+import '../dart_types.dart'; |
+import '../resolution/resolution.dart'; |
+import '../resolution/operators.dart'; |
+import '../resolution/semantic_visitor.dart'; |
+import '../resolution/send_structure.dart'; |
+import '../dart2jslib.dart'; |
+import '../tree/tree.dart'; |
+ |
+ConstantConstructor computeConstantConstructor(ResolvedAst resolvedAst) { |
+ ConstantConstructorComputer visitor = |
+ new ConstantConstructorComputer(resolvedAst.elements); |
+ return resolvedAst.node.accept(visitor); |
+} |
+ |
+class ConstantConstructorComputer extends SemanticVisitor |
+ with SemanticDeclarationResolvedMixin, |
+ DeclarationResolverMixin, |
+ GetBulkMixin, |
+ SetBulkMixin, |
+ ErrorBulkMixin, |
+ InvokeBulkMixin, |
+ IndexSetBulkMixin, |
+ CompoundBulkMixin, |
+ UnaryBulkMixin, |
+ BaseBulkMixin, |
+ BinaryBulkMixin, |
+ PrefixBulkMixin, |
+ PostfixBulkMixin, |
+ NewBulkMixin, |
+ InitializerBulkMixin, |
+ FunctionBulkMixin, |
+ VariableBulkMixin |
+ implements SemanticDeclarationVisitor, SemanticSendVisitor { |
+ final Map<FieldElement, ConstantExpression> fieldMap = |
+ <FieldElement, ConstantExpression>{}; |
+ final Map<dynamic/*int|String*/, ConstantExpression> defaultValues = |
+ <dynamic/*int|String*/, ConstantExpression>{}; |
+ |
+ ConstantConstructorComputer(TreeElements elements) |
+ : super(elements); |
+ |
+ SemanticDeclarationVisitor get declVisitor => this; |
+ |
+ SemanticSendVisitor get sendVisitor => this; |
+ |
+ ClassElement get currentClass => currentConstructor.enclosingClass; |
+ |
+ ConstructorElement get currentConstructor => elements.analyzedElement; |
+ |
+ apply(Node node, [_]) => node.accept(this); |
+ |
+ visitNode(Node node) { |
+ internalError(node, 'Unhandled node $node: ${node.toDebugString()}'); |
+ } |
+ |
+ @override |
+ bulkHandleNode(Node node, String template, _) { |
+ internalError(node, template.replaceFirst('#' , '$node')); |
+ } |
+ |
+ internalError(Node node, String message) { |
+ throw new UnsupportedError(message); |
+ } |
+ |
+ ConstantConstructor visitGenerativeConstructorDeclaration( |
+ FunctionExpression node, |
+ ConstructorElement constructor, |
+ NodeList parameters, |
+ NodeList initializers, |
+ Node body, |
+ _) { |
+ applyParameters(parameters, _); |
+ ConstructedConstantExpression constructorInvocation = |
+ applyInitializers(initializers, _); |
+ return new GenerativeConstantConstructor( |
+ currentClass.thisType, defaultValues, fieldMap, constructorInvocation); |
+ } |
+ |
+ ConstantConstructor visitRedirectingGenerativeConstructorDeclaration( |
+ FunctionExpression node, |
+ ConstructorElement constructor, |
+ NodeList parameters, |
+ NodeList initializers, |
+ _) { |
+ applyParameters(parameters, _); |
+ ConstructedConstantExpression constructorInvocation = |
+ applyInitializers(initializers, _); |
+ return new RedirectingGenerativeConstantConstructor( |
+ defaultValues, constructorInvocation); |
+ } |
+ |
+ ConstantConstructor visitRedirectingFactoryConstructorDeclaration( |
+ FunctionExpression node, |
+ ConstructorElement constructor, |
+ NodeList parameters, |
+ InterfaceType redirectionType, |
+ ConstructorElement redirectionTarget, |
+ _) { |
+ List<String> argumentNames = []; |
+ List<ConstantExpression> arguments = []; |
+ int index = 0; |
+ for (ParameterElement parameter in constructor.parameters) { |
+ if (parameter.isNamed) { |
+ String name = parameter.name; |
+ argumentNames.add(name); |
+ arguments.add(new NamedArgumentReference(name)); |
+ } else { |
+ arguments.add(new PositionalArgumentReference(index)); |
+ } |
+ index++; |
+ } |
+ CallStructure callStructure = new CallStructure(index, argumentNames); |
+ |
+ return new RedirectingFactoryConstantConstructor( |
+ new ConstructedConstantExpression(null, |
+ redirectionType, |
+ redirectionTarget, |
+ callStructure, |
+ arguments)); |
+ } |
+ |
+ @override |
+ visitFactoryConstructorDeclaration( |
+ FunctionExpression node, |
+ ConstructorElement constructor, |
+ NodeList parameters, |
+ Node body, _) { |
+ // TODO(johnniwinther): Handle constant constructors with errors. |
+ internalError(node, "Factory constructor cannot be constant."); |
+ } |
+ |
+ applyParameters(NodeList parameters, _) { |
+ computeParameterStructures(parameters).forEach((s) => s.dispatch(this, _)); |
+ } |
+ |
+ visitParameterDeclaration( |
+ VariableDefinitions node, |
+ Node definition, |
+ ParameterElement parameter, |
+ int index, |
+ _) { |
+ // Do nothing. |
+ } |
+ |
+ visitOptionalParameterDeclaration( |
+ VariableDefinitions node, |
+ Node definition, |
+ ParameterElement parameter, |
+ ConstantExpression defaultValue, |
+ int index, |
+ _) { |
+ assert(invariant(node, defaultValue != null)); |
+ defaultValues[index] = defaultValue; |
+ } |
+ |
+ visitNamedParameterDeclaration( |
+ VariableDefinitions node, |
+ Node definition, |
+ ParameterElement parameter, |
+ ConstantExpression defaultValue, |
+ _) { |
+ assert(invariant(node, defaultValue != null)); |
+ String name = parameter.name; |
+ defaultValues[name] = defaultValue; |
+ } |
+ |
+ visitInitializingFormalDeclaration( |
+ VariableDefinitions node, |
+ Node definition, |
+ InitializingFormalElement parameter, |
+ int index, |
+ _) { |
+ fieldMap[parameter.fieldElement] = new PositionalArgumentReference(index); |
+ } |
+ |
+ visitOptionalInitializingFormalDeclaration( |
+ VariableDefinitions node, |
+ Node definition, |
+ InitializingFormalElement parameter, |
+ ConstantExpression defaultValue, |
+ int index, |
+ _) { |
+ assert(invariant(node, defaultValue != null)); |
+ defaultValues[index] = defaultValue; |
+ fieldMap[parameter.fieldElement] = new PositionalArgumentReference(index); |
+ } |
+ |
+ visitNamedInitializingFormalDeclaration( |
+ VariableDefinitions node, |
+ Node definition, |
+ InitializingFormalElement parameter, |
+ ConstantExpression defaultValue, |
+ _) { |
+ assert(invariant(node, defaultValue != null)); |
+ String name = parameter.name; |
+ defaultValues[name] = defaultValue; |
+ fieldMap[parameter.fieldElement] = new NamedArgumentReference(name); |
+ } |
+ |
+ /// Apply this visitor to the constructor [initializers]. |
+ ConstructedConstantExpression applyInitializers(NodeList initializers, _) { |
+ ConstructedConstantExpression constructorInvocation; |
+ if (initializers != null) { |
+ for (Node initializer in initializers) { |
+ InitializerStructure structure = |
+ computeInitializerStructure(initializer); |
+ if (structure is SuperConstructorInvokeStructure || |
+ structure is ThisConstructorInvokeStructure) { |
+ constructorInvocation = structure.dispatch(this, initializer, _); |
+ } else { |
+ structure.dispatch(this, initializer, _); |
+ } |
+ } |
+ } |
+ if (constructorInvocation == null && !currentClass.isObject) { |
+ constructorInvocation = |
+ new ConstructedConstantExpression(null, |
+ currentClass.supertype, |
+ currentClass.superclass.lookupDefaultConstructor(), |
+ CallStructure.NO_ARGS, |
+ const <ConstantExpression>[]); |
+ } |
+ return constructorInvocation; |
+ } |
+ |
+ visitFieldInitializer( |
+ SendSet node, |
+ FieldElement field, |
+ Node initializer, |
+ _) { |
+ fieldMap[field] = apply(initializer); |
+ } |
+ |
+ visitParameterGet( |
+ Send node, |
+ ParameterElement parameter, |
+ _) { |
+ if (parameter.isNamed) { |
+ return new NamedArgumentReference(parameter.name); |
+ } else { |
+ return new PositionalArgumentReference( |
+ parameter.functionDeclaration.parameters.indexOf(parameter)); |
+ } |
+ } |
+ |
+ ConstructedConstantExpression visitSuperConstructorInvoke( |
+ Send node, |
+ ConstructorElement superConstructor, |
+ InterfaceType type, |
+ NodeList arguments, |
+ Selector selector, |
+ _) { |
+ List<ConstantExpression> argumentExpression = |
+ arguments.nodes.map((a) => apply(a)).toList(); |
+ return new ConstructedConstantExpression(null, |
+ type, |
+ superConstructor, |
+ selector.callStructure, |
+ argumentExpression); |
+ } |
+ |
+ ConstructedConstantExpression visitThisConstructorInvoke( |
+ Send node, |
+ ConstructorElement thisConstructor, |
+ NodeList arguments, |
+ Selector selector, |
+ _) { |
+ List<ConstantExpression> argumentExpression = |
+ arguments.nodes.map((a) => apply(a)).toList(); |
+ return new ConstructedConstantExpression(null, |
+ currentClass.thisType, |
+ thisConstructor, |
+ selector.callStructure, |
+ argumentExpression); |
+ } |
+ |
+ @override |
+ ConstantExpression visitBinary( |
+ Send node, |
+ Node left, |
+ BinaryOperator operator, |
+ Node right, |
+ _) { |
+ return new BinaryConstantExpression(null, |
+ apply(left), operator, apply(right)); |
+ } |
+ |
+ |
+ @override |
+ ConstantExpression visitUnary( |
+ Send node, |
+ UnaryOperator operator, |
+ Node expression, |
+ _) { |
+ return new UnaryConstantExpression(null, |
+ operator, apply(expression)); |
+ } |
+ |
+ @override |
+ ConstantExpression visitStaticFieldGet( |
+ Send node, |
+ FieldElement field, |
+ _) { |
+ return new VariableConstantExpression(null, field); |
+ } |
+ |
+ @override |
+ ConstantExpression visitTopLevelFieldGet( |
+ Send node, |
+ FieldElement field, |
+ _) { |
+ return new VariableConstantExpression(null, field); |
+ } |
+ |
+ @override |
+ ConstantExpression visitLiteralInt(LiteralInt node) { |
+ return new IntConstantExpression( |
+ node.value, new IntConstantValue(node.value)); |
+ } |
+ |
+ @override |
+ ConstantExpression visitLiteralBool(LiteralBool node) { |
+ return new BoolConstantExpression(node.value, null); |
+ } |
+ |
+ @override |
+ ConstantExpression visitLiteralNull(LiteralNull node) { |
+ return new NullConstantExpression(new NullConstantValue()); |
+ } |
+ |
+ @override |
+ ConstantExpression visitLiteralString(LiteralString node) { |
+ return new StringConstantExpression(node.dartString.slowToString(), null); |
+ } |
+ |
+ @override |
+ ConstantExpression visitConditional(Conditional node) { |
+ return new ConditionalConstantExpression(null, |
+ apply(node.condition), |
+ apply(node.thenExpression), |
+ apply(node.elseExpression)); |
+ } |
+ |
+ @override |
+ ConstantExpression visitParenthesizedExpression(ParenthesizedExpression node) { |
+ return apply(node.expression); |
+ } |
+ |
+ @override |
+ ConstantExpression visitTopLevelFunctionInvoke( |
+ Send node, |
+ MethodElement function, |
+ NodeList arguments, |
+ CallStructure callStructure, |
+ _) { |
+ if (function.name != 'identical' || !function.library.isDartCore) { |
+ throw new UnsupportedError("Unexpected function call: $function"); |
+ } |
+ return new IdenticalConstantExpression( |
+ null, apply(arguments.nodes.head), apply(arguments.nodes.tail.head)); |
+ } |
+ |
+ @override |
+ ConstantExpression visitNamedArgument(NamedArgument node) { |
+ return apply(node.expression); |
+ } |
+} |