blob: a92edcccf186006216f034b23ae4cbeea354e007 [file] [log] [blame]
// 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 '../dart2jslib.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
import '../resolution/resolution.dart';
import '../resolution/operators.dart';
import '../resolution/semantic_visitor.dart';
import '../resolution/send_structure.dart';
import '../tree/tree.dart';
import '../universe/universe.dart' show CallStructure;
import 'expressions.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(node, _);
return new GenerativeConstantConstructor(
currentClass.thisType, defaultValues, fieldMap, constructorInvocation);
}
ConstantConstructor visitRedirectingGenerativeConstructorDeclaration(
FunctionExpression node,
ConstructorElement constructor,
NodeList parameters,
NodeList initializers,
_) {
applyParameters(parameters, _);
ConstructedConstantExpression constructorInvocation =
applyInitializers(node, _);
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(
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(
FunctionExpression constructor, _) {
ConstructedConstantExpression constructorInvocation;
InitializersStructure initializers =
computeInitializersStructure(constructor);
for (InitializerStructure structure in initializers.initializers) {
if (structure.isConstructorInvoke) {
constructorInvocation = structure.dispatch(this, _);
} else {
structure.dispatch(this, _);
}
}
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,
CallStructure callStructure,
_) {
List<ConstantExpression> argumentExpression =
arguments.nodes.map((a) => apply(a)).toList();
return new ConstructedConstantExpression(
type,
superConstructor,
callStructure,
argumentExpression);
}
ConstructedConstantExpression visitImplicitSuperConstructorInvoke(
FunctionExpression node,
ConstructorElement superConstructor,
InterfaceType type,
_) {
return new ConstructedConstantExpression(
type,
superConstructor,
CallStructure.NO_ARGS,
const <ConstantExpression>[]);
}
ConstructedConstantExpression visitThisConstructorInvoke(
Send node,
ConstructorElement thisConstructor,
NodeList arguments,
CallStructure callStructure,
_) {
List<ConstantExpression> argumentExpression =
arguments.nodes.map((a) => apply(a)).toList();
return new ConstructedConstantExpression(
currentClass.thisType,
thisConstructor,
callStructure,
argumentExpression);
}
@override
ConstantExpression visitBinary(
Send node,
Node left,
BinaryOperator operator,
Node right,
_) {
return new BinaryConstantExpression(
apply(left), operator, apply(right));
}
@override
ConstantExpression visitUnary(
Send node,
UnaryOperator operator,
Node expression,
_) {
return new UnaryConstantExpression(
operator, apply(expression));
}
@override
ConstantExpression visitStaticFieldGet(
Send node,
FieldElement field,
_) {
return new VariableConstantExpression(field);
}
@override
ConstantExpression visitTopLevelFieldGet(
Send node,
FieldElement field,
_) {
return new VariableConstantExpression(field);
}
@override
ConstantExpression visitLiteralInt(LiteralInt node) {
return new IntConstantExpression(node.value);
}
@override
ConstantExpression visitLiteralBool(LiteralBool node) {
return new BoolConstantExpression(node.value);
}
@override
ConstantExpression visitLiteralNull(LiteralNull node) {
return new NullConstantExpression();
}
@override
ConstantExpression visitLiteralString(LiteralString node) {
return new StringConstantExpression(node.dartString.slowToString());
}
@override
ConstantExpression visitConditional(Conditional node) {
return new ConditionalConstantExpression(
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(
apply(arguments.nodes.head), apply(arguments.nodes.tail.head));
}
@override
ConstantExpression visitNamedArgument(NamedArgument node) {
return apply(node.expression);
}
}