Add ConstantConstructor to ConstantExpression system.

BUG=
R=karlklose@google.com

Review URL: https://codereview.chromium.org//1115183002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@45681 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
johnniwinther@google.com 2015-05-11 12:46:17 +00:00
parent 0eaa4d4717
commit 091c7eddae
15 changed files with 1426 additions and 92 deletions

View file

@ -420,7 +420,7 @@ class LocalFunctionElementY extends ElementY
}
class ParameterElementY extends ElementY
with AnalyzableElementY, AstElementY
with AnalyzableElementY, AstElementY, VariableElementMixin
implements dart2js.ParameterElement {
analyzer.ParameterElement get element => super.element;
@ -458,12 +458,6 @@ class ParameterElementY extends ElementY
@override
get functionDeclaration => unsupported('functionDeclaration');
@override
get initializer => unsupported('initializer');
@override
get memberContext => unsupported('memberContext');
@override
get functionSignature => unsupported('functionSignature');
}
@ -718,6 +712,9 @@ abstract class VariableElementMixin
@override
get memberContext => unsupported('memberContext');
@override
get constant => unsupported('constant');
}
class TopLevelVariableElementY extends ElementY
@ -862,6 +859,14 @@ class ConstructorElementY extends ElementY
@override
get nestedClosures => unsupported('nestedClosures');
@override
get constantConstructor => unsupported('constantConstructor');
@override
get isFromEnvironmentConstructor {
unsupported('isFromEnvironmentConstructor');
}
@override
bool get isCyclicRedirection => effectiveTarget.isRedirectingFactory;

View file

@ -4,20 +4,20 @@
library closureToClassMapper;
import "elements/elements.dart";
import "dart2jslib.dart";
import "dart_types.dart";
import "js_backend/js_backend.dart" show JavaScriptBackend;
import "scanner/scannerlib.dart" show Token;
import "tree/tree.dart";
import "util/util.dart";
import "elements/modelx.dart"
import 'constants/expressions.dart';
import 'dart2jslib.dart';
import 'dart_types.dart';
import 'elements/elements.dart';
import 'elements/modelx.dart'
show BaseFunctionElementX,
ClassElementX,
ElementX,
LocalFunctionElementX;
import "elements/visitor.dart" show ElementVisitor;
import 'elements/visitor.dart' show ElementVisitor;
import 'js_backend/js_backend.dart' show JavaScriptBackend;
import 'scanner/scannerlib.dart' show Token;
import 'tree/tree.dart';
import 'util/util.dart';
import 'universe/universe.dart' show
Universe;
@ -151,6 +151,9 @@ class ClosureFieldElement extends ElementX
@override
List<FunctionElement> get nestedClosures => const <FunctionElement>[];
@override
ConstantExpression get constant => null;
}
// TODO(ahe): These classes continuously cause problems. We need to find
@ -276,6 +279,9 @@ class BoxFieldElement extends ElementX
ResolvedAst get resolvedAst {
throw new UnsupportedError("BoxFieldElement.resolvedAst");
}
@override
ConstantExpression get constant => null;
}
/// A local variable used encode the direct (uncaptured) references to [this].

View file

@ -827,15 +827,6 @@ class CompileTimeConstantEvaluator extends Visitor<AstConstant> {
CallStructure callStructure,
List<AstConstant> normalizedArguments,
List<AstConstant> concreteArguments) {
AstConstant createEvaluatedConstant(ConstantValue value) {
return new AstConstant(
context, node, new ConstructedConstantExpression(
value,
type,
constructor,
callStructure,
concreteArguments.map((e) => e.expression).toList()));
}
var firstArgument = normalizedArguments[0].value;
ConstantValue defaultValue = normalizedArguments[1].value;
@ -863,6 +854,27 @@ class CompileTimeConstantEvaluator extends Visitor<AstConstant> {
return null;
}
String name =
firstArgument.primitiveValue.slowToString();
String value =
compiler.fromEnvironment(name);
AstConstant createEvaluatedConstant(ConstantValue value) {
ConstantExpression expression;
if (constructor == compiler.intEnvironment) {
expression = new IntFromEnvironmentConstantExpression(
value, name, normalizedArguments[1].expression);
} else if (constructor == compiler.boolEnvironment) {
expression = new BoolFromEnvironmentConstantExpression(
value, name, normalizedArguments[1].expression);
} else if (constructor == compiler.stringEnvironment) {
expression = new StringFromEnvironmentConstantExpression(
value, name, normalizedArguments[1].expression);
}
return new AstConstant(context, node, expression);
}
if (constructor == compiler.boolEnvironment &&
!(defaultValue.isNull || defaultValue.isBool)) {
DartType type = defaultValue.getType(compiler.coreTypes);
@ -881,9 +893,6 @@ class CompileTimeConstantEvaluator extends Visitor<AstConstant> {
return null;
}
String value =
compiler.fromEnvironment(firstArgument.primitiveValue.slowToString());
if (value == null) {
return createEvaluatedConstant(defaultValue);
} else if (constructor == compiler.intEnvironment) {

View file

@ -867,9 +867,15 @@ abstract class Compiler implements DiagnosticListener {
Element identicalFunction;
Element loadLibraryFunction;
Element functionApplyMethod;
Element intEnvironment;
Element boolEnvironment;
Element stringEnvironment;
/// The [int.fromEnvironment] constructor.
ConstructorElement intEnvironment;
/// The [bool.fromEnvironment] constructor.
ConstructorElement boolEnvironment;
/// The [String.fromEnvironment] constructor.
ConstructorElement stringEnvironment;
/// Tracks elements with compile-time errors.
final Set<Element> elementsWithCompileTimeErrors = new Set<Element>();

View file

@ -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);
}
}

View file

@ -9,6 +9,7 @@ import '../dart_types.dart';
import '../elements/elements.dart' show
ConstructorElement,
Element,
FieldElement,
FunctionElement,
PrefixElement,
VariableElement;
@ -19,6 +20,7 @@ import 'values.dart';
enum ConstantExpressionKind {
BINARY,
BOOL,
BOOL_FROM_ENVIRONMENT,
CONCATENATE,
CONDITIONAL,
CONSTRUCTED,
@ -28,14 +30,209 @@ enum ConstantExpressionKind {
FUNCTION,
IDENTICAL,
INT,
INT_FROM_ENVIRONMENT,
LIST,
MAP,
NULL,
STRING,
STRING_FROM_ENVIRONMENT,
SYMBOL,
TYPE,
UNARY,
VARIABLE,
POSITIONAL_REFERENCE,
NAMED_REFERENCE,
}
/// The normalized arguments passed to a const constructor computed from the
/// actual [arguments] and the [defaultValues] of the called construrctor.
class NormalizedArguments {
final Map<dynamic/*int|String*/, ConstantExpression> defaultValues;
final CallStructure callStructure;
final List<ConstantExpression> arguments;
NormalizedArguments(this.defaultValues, this.callStructure, this.arguments);
/// Returns the normalized named argument [name].
ConstantExpression getNamedArgument(String name) {
int index = callStructure.namedArguments.indexOf(name);
if (index == -1) {
// The named argument is not provided.
return defaultValues[name];
}
return arguments[index + callStructure.positionalArgumentCount];
}
/// Returns the normalized [index]th positional argument.
ConstantExpression getPositionalArgument(int index) {
if (index >= callStructure.positionalArgumentCount) {
// The positional argument is not provided.
return defaultValues[index];
}
return arguments[index];
}
}
enum ConstantConstructorKind {
GENERATIVE,
REDIRECTING_GENERATIVE,
REDIRECTING_FACTORY,
}
/// Definition of a constant constructor.
abstract class ConstantConstructor {
ConstantConstructorKind get kind;
/// Computes the type of the instance created in a const constructor
/// invocation with type [newType].
InterfaceType computeInstanceType(InterfaceType newType);
/// Computes the constant expressions of the fields of the created instance
/// in a const constructor invocation with [arguments].
Map<FieldElement, ConstantExpression> computeInstanceFields(
List<ConstantExpression> arguments,
CallStructure callStructure);
}
/// A generative constant constructor.
class GenerativeConstantConstructor implements ConstantConstructor{
final InterfaceType type;
final Map<dynamic/*int|String*/, ConstantExpression> defaultValues;
final Map<FieldElement, ConstantExpression> fieldMap;
final ConstructedConstantExpression superConstructorInvocation;
GenerativeConstantConstructor(
this.type,
this.defaultValues,
this.fieldMap,
this.superConstructorInvocation);
ConstantConstructorKind get kind => ConstantConstructorKind.GENERATIVE;
InterfaceType computeInstanceType(InterfaceType newType) {
return type.substByContext(newType);
}
Map<FieldElement, ConstantExpression> computeInstanceFields(
List<ConstantExpression> arguments,
CallStructure callStructure) {
NormalizedArguments args = new NormalizedArguments(
defaultValues, callStructure, arguments);
Map<FieldElement, ConstantExpression> appliedFieldMap =
applyFields(args, superConstructorInvocation);
fieldMap.forEach((FieldElement field, ConstantExpression constant) {
appliedFieldMap[field] = constant.apply(args);
});
return appliedFieldMap;
}
String toString() {
StringBuffer sb = new StringBuffer();
sb.write("{'type': $type");
defaultValues.forEach((key, ConstantExpression expression) {
sb.write(",\n 'default:${key}': ${expression.getText()}");
});
fieldMap.forEach((FieldElement field, ConstantExpression expression) {
sb.write(",\n 'field:${field}': ${expression.getText()}");
});
if (superConstructorInvocation != null) {
sb.write(",\n 'constructor: ${superConstructorInvocation.getText()}");
}
sb.write("}");
return sb.toString();
}
/// Creates the field-to-constant map from applying [args] to
/// [constructorInvocation]. If [constructorInvocation] is `null`, an empty
/// map is created.
static Map<FieldElement, ConstantExpression> applyFields(
NormalizedArguments args,
ConstructedConstantExpression constructorInvocation) {
Map<FieldElement, ConstantExpression> appliedFieldMap =
<FieldElement, ConstantExpression>{};
if (constructorInvocation != null) {
Map<FieldElement, ConstantExpression> fieldMap =
constructorInvocation.computeInstanceFields();
fieldMap.forEach((FieldElement field, ConstantExpression constant) {
appliedFieldMap[field] = constant.apply(args);
});
}
return appliedFieldMap;
}
}
/// A redirecting generative constant constructor.
class RedirectingGenerativeConstantConstructor implements ConstantConstructor {
final Map<dynamic/*int|String*/, ConstantExpression> defaultValues;
final ConstructedConstantExpression thisConstructorInvocation;
RedirectingGenerativeConstantConstructor(
this.defaultValues,
this.thisConstructorInvocation);
ConstantConstructorKind get kind {
return ConstantConstructorKind.REDIRECTING_GENERATIVE;
}
InterfaceType computeInstanceType(InterfaceType newType) {
return thisConstructorInvocation.computeInstanceType()
.substByContext(newType);
}
Map<FieldElement, ConstantExpression> computeInstanceFields(
List<ConstantExpression> arguments,
CallStructure callStructure) {
NormalizedArguments args =
new NormalizedArguments(defaultValues, callStructure, arguments);
Map<FieldElement, ConstantExpression> appliedFieldMap =
GenerativeConstantConstructor.applyFields(
args, thisConstructorInvocation);
return appliedFieldMap;
}
String toString() {
StringBuffer sb = new StringBuffer();
sb.write("{'type': ${thisConstructorInvocation.type}");
defaultValues.forEach((key, ConstantExpression expression) {
sb.write(",\n 'default:${key}': ${expression.getText()}");
});
sb.write(",\n 'constructor': ${thisConstructorInvocation.getText()}");
sb.write("}");
return sb.toString();
}
}
/// A redirecting factory constant constructor.
class RedirectingFactoryConstantConstructor implements ConstantConstructor {
final ConstructedConstantExpression targetConstructorInvocation;
RedirectingFactoryConstantConstructor(this.targetConstructorInvocation);
ConstantConstructorKind get kind {
return ConstantConstructorKind.REDIRECTING_FACTORY;
}
InterfaceType computeInstanceType(InterfaceType newType) {
return targetConstructorInvocation.computeInstanceType()
.substByContext(newType);
}
Map<FieldElement, ConstantExpression> computeInstanceFields(
List<ConstantExpression> arguments,
CallStructure callStructure) {
ConstantConstructor constantConstructor =
targetConstructorInvocation.target.constantConstructor;
return constantConstructor.computeInstanceFields(arguments, callStructure);
}
String toString() {
StringBuffer sb = new StringBuffer();
sb.write("{");
sb.write("'constructor': ${targetConstructorInvocation.getText()}");
sb.write("}");
return sb.toString();
}
}
/// An expression that is a compile-time constant.
@ -53,6 +250,8 @@ abstract class ConstantExpression {
ConstantExpressionKind get kind;
/// Returns the value of this constant expression.
// TODO(johnniwinther): Replace this with an evaluation method that takes
// a constant system and an environment.
ConstantValue get value;
// TODO(johnniwinther): Unify precedence handled between constants, front-end
@ -61,6 +260,9 @@ abstract class ConstantExpression {
accept(ConstantExpressionVisitor visitor, [context]);
/// Substitute free variables using arguments.
ConstantExpression apply(NormalizedArguments arguments) => this;
String getText() {
ConstExpPrinter printer = new ConstExpPrinter();
accept(printer);
@ -118,10 +320,6 @@ abstract class PrimitiveConstantExpression extends ConstantExpression {
/// The primitive value of this contant expression.
get primitiveValue;
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitPrimitive(this, context);
}
}
/// Boolean literal constant.
@ -133,6 +331,10 @@ class BoolConstantExpression extends PrimitiveConstantExpression {
ConstantExpressionKind get kind => ConstantExpressionKind.BOOL;
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitBool(this, context);
}
@override
int _computeHashCode() => 13 * primitiveValue.hashCode;
@ -151,6 +353,10 @@ class IntConstantExpression extends PrimitiveConstantExpression {
ConstantExpressionKind get kind => ConstantExpressionKind.INT;
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitInt(this, context);
}
@override
int _computeHashCode() => 17 * primitiveValue.hashCode;
@ -169,6 +375,10 @@ class DoubleConstantExpression extends PrimitiveConstantExpression {
ConstantExpressionKind get kind => ConstantExpressionKind.DOUBLE;
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitDouble(this, context);
}
@override
int _computeHashCode() => 19 * primitiveValue.hashCode;
@ -187,6 +397,10 @@ class StringConstantExpression extends PrimitiveConstantExpression {
ConstantExpressionKind get kind => ConstantExpressionKind.STRING;
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitString(this, context);
}
@override
int _computeHashCode() => 23 * primitiveValue.hashCode;
@ -202,6 +416,10 @@ class NullConstantExpression extends PrimitiveConstantExpression {
ConstantExpressionKind get kind => ConstantExpressionKind.NULL;
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitNull(this, context);
}
get primitiveValue => null;
@override
@ -226,6 +444,11 @@ class ListConstantExpression extends ConstantExpression {
}
@override
ConstantExpression apply(NormalizedArguments arguments) {
return new ListConstantExpression(null, type,
values.map((v) => v.apply(arguments)).toList());
}
int _computeHashCode() {
int hashCode = 13 * type.hashCode + 17 * values.length;
for (ConstantExpression value in values) {
@ -261,6 +484,12 @@ class MapConstantExpression extends ConstantExpression {
}
@override
ConstantExpression apply(NormalizedArguments arguments) {
return new MapConstantExpression(null, type,
keys.map((k) => k.apply(arguments)).toList(),
values.map((v) => v.apply(arguments)).toList());
}
int _computeHashCode() {
int hashCode = 13 * type.hashCode + 17 * values.length;
for (ConstantExpression value in values) {
@ -296,6 +525,7 @@ class ConstructedConstantExpression extends ConstantExpression {
this.callStructure,
this.arguments) {
assert(type.element == target.enclosingClass);
assert(!arguments.contains(null));
}
ConstantExpressionKind get kind => ConstantExpressionKind.CONSTRUCTED;
@ -304,6 +534,21 @@ class ConstructedConstantExpression extends ConstantExpression {
return visitor.visitConstructed(this, context);
}
Map<FieldElement, ConstantExpression> computeInstanceFields() {
return target.constantConstructor.computeInstanceFields(
arguments, callStructure);
}
InterfaceType computeInstanceType() {
return target.constantConstructor.computeInstanceType(type);
}
ConstructedConstantExpression apply(NormalizedArguments arguments) {
return new ConstructedConstantExpression(null,
type, target, callStructure,
this.arguments.map((a) => a.apply(arguments)).toList());
}
@override
int _computeHashCode() {
int hashCode =
@ -331,9 +576,9 @@ class ConstructedConstantExpression extends ConstantExpression {
/// String literal with juxtaposition and/or interpolations.
class ConcatenateConstantExpression extends ConstantExpression {
final StringConstantValue value;
final List<ConstantExpression> arguments;
final List<ConstantExpression> expressions;
ConcatenateConstantExpression(this.value, this.arguments);
ConcatenateConstantExpression(this.value, this.expressions);
ConstantExpressionKind get kind => ConstantExpressionKind.CONCATENATE;
@ -341,10 +586,15 @@ class ConcatenateConstantExpression extends ConstantExpression {
return visitor.visitConcatenate(this, context);
}
ConstantExpression apply(NormalizedArguments arguments) {
return new ConcatenateConstantExpression(null,
expressions.map((a) => a.apply(arguments)).toList());
}
@override
int _computeHashCode() {
int hashCode = 17 * arguments.length;
for (ConstantExpression value in arguments) {
int hashCode = 17 * expressions.length;
for (ConstantExpression value in expressions) {
hashCode ^= 19 * value.hashCode;
}
return hashCode;
@ -352,9 +602,9 @@ class ConcatenateConstantExpression extends ConstantExpression {
@override
bool _equals(ConcatenateConstantExpression other) {
if (arguments.length != other.arguments.length) return false;
for (int i = 0; i < arguments.length; i++) {
if (arguments[i] != other.arguments[i]) return false;
if (expressions.length != other.expressions.length) return false;
for (int i = 0; i < expressions.length; i++) {
if (expressions[i] != other.expressions[i]) return false;
}
return true;
}
@ -468,6 +718,14 @@ class BinaryConstantExpression extends ConstantExpression {
return visitor.visitBinary(this, context);
}
ConstantExpression apply(NormalizedArguments arguments) {
return new BinaryConstantExpression(
value,
left.apply(arguments),
operator,
right.apply(arguments));
}
int get precedence => PRECEDENCE_MAP[operator.kind];
@override
@ -521,6 +779,13 @@ class IdenticalConstantExpression extends ConstantExpression {
return visitor.visitIdentical(this, context);
}
ConstantExpression apply(NormalizedArguments arguments) {
return new IdenticalConstantExpression(
value,
left.apply(arguments),
right.apply(arguments));
}
int get precedence => 15;
@override
@ -552,6 +817,13 @@ class UnaryConstantExpression extends ConstantExpression {
return visitor.visitUnary(this, context);
}
ConstantExpression apply(NormalizedArguments arguments) {
return new UnaryConstantExpression(
value,
operator,
expression.apply(arguments));
}
int get precedence => PRECEDENCE_MAP[operator.kind];
@override
@ -591,6 +863,14 @@ class ConditionalConstantExpression extends ConstantExpression {
return visitor.visitConditional(this, context);
}
ConstantExpression apply(NormalizedArguments arguments) {
return new ConditionalConstantExpression(
value,
condition.apply(arguments),
trueExp.apply(arguments),
falseExp.apply(arguments));
}
int get precedence => 3;
@override
@ -608,6 +888,157 @@ class ConditionalConstantExpression extends ConstantExpression {
}
}
/// A reference to a position parameter.
class PositionalArgumentReference extends ConstantExpression {
final int index;
PositionalArgumentReference(this.index);
ConstantExpressionKind get kind {
return ConstantExpressionKind.POSITIONAL_REFERENCE;
}
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitPositional(this, context);
}
ConstantValue get value {
throw new UnsupportedError('PositionalArgumentReference.value');
}
ConstantExpression apply(NormalizedArguments arguments) {
return arguments.getPositionalArgument(index);
}
@override
int _computeHashCode() => 13 * index.hashCode;
@override
bool _equals(PositionalArgumentReference other) => index == other.index;
}
/// A reference to a named parameter.
class NamedArgumentReference extends ConstantExpression {
final String name;
NamedArgumentReference(this.name);
ConstantExpressionKind get kind {
return ConstantExpressionKind.NAMED_REFERENCE;
}
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitNamed(this, context);
}
ConstantValue get value {
throw new UnsupportedError('NamedArgumentReference.value');
}
ConstantExpression apply(NormalizedArguments arguments) {
return arguments.getNamedArgument(name);
}
@override
int _computeHashCode() => 13 * name.hashCode;
@override
bool _equals(NamedArgumentReference other) => name == other.name;
}
abstract class FromEnvironmentConstantExpression extends ConstantExpression {
final ConstantValue value;
final String name;
final ConstantExpression defaultValue;
FromEnvironmentConstantExpression(this.value, this.name, this.defaultValue);
@override
int _computeHashCode() {
return 13 * name.hashCode +
17 * defaultValue.hashCode;
}
@override
bool _equals(FromEnvironmentConstantExpression other) {
return name == other.name &&
defaultValue == other.defaultValue;
}
}
/// A `const bool.fromEnvironment` constant.
class BoolFromEnvironmentConstantExpression
extends FromEnvironmentConstantExpression {
BoolFromEnvironmentConstantExpression(
ConstantValue value,
String name,
ConstantExpression defaultValue)
: super(value, name, defaultValue);
ConstantExpressionKind get kind {
return ConstantExpressionKind.BOOL_FROM_ENVIRONMENT;
}
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitBoolFromEnvironment(this, context);
}
ConstantExpression apply(NormalizedArguments arguments) {
return new BoolFromEnvironmentConstantExpression(
null, name, defaultValue.apply(arguments));
}
}
/// A `const int.fromEnvironment` constant.
class IntFromEnvironmentConstantExpression
extends FromEnvironmentConstantExpression {
IntFromEnvironmentConstantExpression(
ConstantValue value,
String name,
ConstantExpression defaultValue)
: super(value, name, defaultValue);
ConstantExpressionKind get kind {
return ConstantExpressionKind.INT_FROM_ENVIRONMENT;
}
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitIntFromEnvironment(this, context);
}
ConstantExpression apply(NormalizedArguments arguments) {
return new IntFromEnvironmentConstantExpression(
null, name, defaultValue.apply(arguments));
}
}
/// A `const String.fromEnvironment` constant.
class StringFromEnvironmentConstantExpression
extends FromEnvironmentConstantExpression {
StringFromEnvironmentConstantExpression(
ConstantValue value,
String name,
ConstantExpression defaultValue)
: super(value, name, defaultValue);
ConstantExpressionKind get kind {
return ConstantExpressionKind.STRING_FROM_ENVIRONMENT;
}
accept(ConstantExpressionVisitor visitor, [context]) {
return visitor.visitStringFromEnvironment(this, context);
}
ConstantExpression apply(NormalizedArguments arguments) {
return new StringFromEnvironmentConstantExpression(
null, name, defaultValue.apply(arguments));
}
}
/// A constant expression referenced with a deferred prefix.
/// For example `lib.C`.
class DeferredConstantExpression extends ConstantExpression {
@ -635,27 +1066,40 @@ class DeferredConstantExpression extends ConstantExpression {
}
}
abstract class ConstantExpressionVisitor<C, R> {
abstract class ConstantExpressionVisitor<R, A> {
const ConstantExpressionVisitor();
R visit(ConstantExpression constant, C context) {
R visit(ConstantExpression constant, A context) {
return constant.accept(this, context);
}
R visitPrimitive(PrimitiveConstantExpression exp, C context);
R visitList(ListConstantExpression exp, C context);
R visitMap(MapConstantExpression exp, C context);
R visitConstructed(ConstructedConstantExpression exp, C context);
R visitConcatenate(ConcatenateConstantExpression exp, C context);
R visitSymbol(SymbolConstantExpression exp, C context);
R visitType(TypeConstantExpression exp, C context);
R visitVariable(VariableConstantExpression exp, C context);
R visitFunction(FunctionConstantExpression exp, C context);
R visitBinary(BinaryConstantExpression exp, C context);
R visitIdentical(IdenticalConstantExpression exp, C context);
R visitUnary(UnaryConstantExpression exp, C context);
R visitConditional(ConditionalConstantExpression exp, C context);
R visitDeferred(DeferredConstantExpression exp, C context);
R visitBool(BoolConstantExpression exp, A context);
R visitInt(IntConstantExpression exp, A context);
R visitDouble(DoubleConstantExpression exp, A context);
R visitString(StringConstantExpression exp, A context);
R visitNull(NullConstantExpression exp, A context);
R visitList(ListConstantExpression exp, A context);
R visitMap(MapConstantExpression exp, A context);
R visitConstructed(ConstructedConstantExpression exp, A context);
R visitConcatenate(ConcatenateConstantExpression exp, A context);
R visitSymbol(SymbolConstantExpression exp, A context);
R visitType(TypeConstantExpression exp, A context);
R visitVariable(VariableConstantExpression exp, A context);
R visitFunction(FunctionConstantExpression exp, A context);
R visitBinary(BinaryConstantExpression exp, A context);
R visitIdentical(IdenticalConstantExpression exp, A context);
R visitUnary(UnaryConstantExpression exp, A context);
R visitConditional(ConditionalConstantExpression exp, A context);
R visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp,
A context);
R visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp,
A context);
R visitStringFromEnvironment(StringFromEnvironmentConstantExpression exp,
A context);
R visitDeferred(DeferredConstantExpression exp, A context);
R visitPositional(PositionalArgumentReference exp, A context);
R visitNamed(NamedArgumentReference exp, A context);
}
/// Represents the declaration of a constant [element] with value [expression].
@ -702,9 +1146,34 @@ class ConstExpPrinter extends ConstantExpressionVisitor {
return constant.accept(this, null);
}
void visitPrimitive(PrimitiveConstantExpression exp) {
sb.write(exp.primitiveValue);
}
@override
void visitPrimitive(PrimitiveConstantExpression exp, [_]) {
sb.write(exp.value.unparse());
void visitBool(BoolConstantExpression exp, [_]) {
visitPrimitive(exp);
}
@override
void visitDouble(DoubleConstantExpression exp, [_]) {
visitPrimitive(exp);
}
@override
void visitInt(IntConstantExpression exp, [_]) {
visitPrimitive(exp);
}
@override
void visitNull(NullConstantExpression exp, [_]) {
visitPrimitive(exp);
}
@override
void visitString(StringConstantExpression exp, [_]) {
// TODO(johnniwinther): Ensure correct escaping.
sb.write('"${exp.primitiveValue}"');
}
@override
@ -839,11 +1308,46 @@ class ConstExpPrinter extends ConstantExpressionVisitor {
}
@override
visitDeferred(DeferredConstantExpression exp, context) {
void visitPositional(PositionalArgumentReference exp, [_]) {
// TODO(johnniwinther): Maybe this should throw.
sb.write('args[${exp.index}]');
}
@override
void visitNamed(NamedArgumentReference exp, [_]) {
// TODO(johnniwinther): Maybe this should throw.
sb.write('args[${exp.name}]');
}
@override
void visitDeferred(DeferredConstantExpression exp, context) {
sb.write(exp.prefix.deferredImport.prefix.source);
sb.write('.');
write(exp, exp.expression);
}
@override
void visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp,
[_]) {
sb.write('const bool.fromEnvironment("${exp.name}", defaultValue: ');
visit(exp.defaultValue);
sb.write(')');
}
@override
void visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp, [_]) {
sb.write('const int.fromEnvironment("${exp.name}", defaultValue: ');
visit(exp.defaultValue);
sb.write(')');
}
@override
void visitStringFromEnvironment(StringFromEnvironmentConstantExpression exp,
[_]) {
sb.write('const String.fromEnvironment("${exp.name}", defaultValue: ');
visit(exp.defaultValue);
sb.write(')');
}
String toString() => sb.toString();
}

View file

@ -1119,7 +1119,7 @@ class TypeGenerator {
class ConstantEmitter
extends ConstantExpressionVisitor<BuilderContext<Statement>, Expression> {
extends ConstantExpressionVisitor<Expression, BuilderContext<Statement>> {
const ConstantEmitter();
/// Creates the [Expression] for the constant [exp].
@ -1152,8 +1152,32 @@ class ConstantEmitter
}
@override
Expression visitPrimitive(PrimitiveConstantExpression exp,
BuilderContext<Statement> context) {
Expression visitBool(BoolConstantExpression exp,
BuilderContext<Statement> context) {
return handlePrimitiveConstant(exp.value);
}
@override
Expression visitInt(IntConstantExpression exp,
BuilderContext<Statement> context) {
return handlePrimitiveConstant(exp.value);
}
@override
Expression visitDouble(DoubleConstantExpression exp,
BuilderContext<Statement> context) {
return handlePrimitiveConstant(exp.value);
}
@override
Expression visitString(StringConstantExpression exp,
BuilderContext<Statement> context) {
return handlePrimitiveConstant(exp.value);
}
@override
Expression visitNull(NullConstantExpression exp,
BuilderContext<Statement> context) {
return handlePrimitiveConstant(exp.value);
}
@ -1221,7 +1245,7 @@ class ConstantEmitter
Expression visitConcatenate(ConcatenateConstantExpression exp,
BuilderContext<Statement> context) {
return new StringConcat(visitExpressions(exp.arguments, context));
return new StringConcat(visitExpressions(exp.expressions, context));
}
@override
@ -1285,6 +1309,39 @@ class ConstantEmitter
return handlePrimitiveConstant(exp.value);
}
@override
Expression visitNamed(NamedArgumentReference exp,
BuilderContext<Statement> context) {
throw new UnsupportedError("ConstantEmitter.visitNamed");
}
@override
Expression visitPositional(PositionalArgumentReference exp,
BuilderContext<Statement> context) {
throw new UnsupportedError("ConstantEmitter.visitPositional");
}
@override
Expression visitBoolFromEnvironment(
BoolFromEnvironmentConstantExpression exp,
BuilderContext<Statement> context) {
return handlePrimitiveConstant(exp.value);
}
@override
Expression visitIntFromEnvironment(
IntFromEnvironmentConstantExpression exp,
BuilderContext<Statement> context) {
return handlePrimitiveConstant(exp.value);
}
@override
Expression visitStringFromEnvironment(
StringFromEnvironmentConstantExpression exp,
BuilderContext<Statement> context) {
return handlePrimitiveConstant(exp.value);
}
@override
Expression visitDeferred(DeferredConstantExpression exp,
BuilderContext<Statement> context) {

View file

@ -998,6 +998,10 @@ abstract class LocalElement extends Element implements TypedElement, Local {
/// A top level, static or instance field, a formal parameter or local variable.
abstract class VariableElement extends ExecutableElement {
Expression get initializer;
/// The constant expression defining the value of the variable if `const`,
/// `null` otherwise.
ConstantExpression get constant;
}
/// An entity that defines a local entity (memory slot) in generated code.
@ -1262,6 +1266,13 @@ abstract class ConstructorElement extends FunctionElement
/// is `C.c`.
ConstructorElement get definingConstructor;
/// The constant constructor defining the binding of fields if `const`,
/// `null` otherwise.
ConstantConstructor get constantConstructor;
/// `true` if this constructor is either `bool.fromEnviroment`
bool get isFromEnvironmentConstructor;
/// Use [enclosingClass] instead.
@deprecated
get enclosingElement;

View file

@ -6,6 +6,7 @@ library elements.modelx;
import 'elements.dart';
import '../constants/expressions.dart';
import '../constants/constructors.dart';
import '../helpers/helpers.dart'; // Included for debug helpers.
import '../tree/tree.dart';
import '../util/util.dart';
@ -310,6 +311,7 @@ class ErroneousElementX extends ElementX implements ErroneousElement {
get memberContext => unsupported();
get executableContext => unsupported();
get isExternal => unsupported();
get constantConstructor => null;
bool get isRedirectingGenerative => unsupported();
bool get isRedirectingFactory => unsupported();
@ -333,11 +335,16 @@ class ErroneousElementX extends ElementX implements ErroneousElement {
accept(ElementVisitor visitor, arg) {
return visitor.visitErroneousElement(this, arg);
}
@override
bool get isFromEnvironmentConstructor => false;
}
/// A constructor that was synthesized to recover from a compile-time error.
class ErroneousConstructorElementX extends ErroneousElementX
with PatchMixin<FunctionElement>, AnalyzableElementX
with PatchMixin<FunctionElement>,
AnalyzableElementX,
ConstantConstructorMixin
implements ConstructorElementX {
// TODO(ahe): Instead of subclassing [ErroneousElementX], this class should
// be more like [ErroneousFieldElementX]. In particular, its kind should be
@ -1263,7 +1270,24 @@ class VariableList implements DeclarationSite {
DartType computeType(Element element, Compiler compiler) => type;
}
abstract class VariableElementX extends ElementX with AstElementMixin
abstract class ConstantVariableMixin implements VariableElement {
ConstantExpression _constant;
ConstantExpression get constant {
assert(invariant(this, _constant != null,
message: "Constant has not been computed for $this."));
return _constant;
}
void set constant(ConstantExpression value) {
assert(invariant(this, _constant == null || _constant == value,
message: "Constant has already been computed for $this."));
_constant = value;
}
}
abstract class VariableElementX extends ElementX
with AstElementMixin, ConstantVariableMixin
implements VariableElement {
final Token token;
final VariableList variables;
@ -1422,7 +1446,8 @@ class FieldElementX extends VariableElementX
}
/// A field that was synthesized to recover from a compile-time error.
class ErroneousFieldElementX extends ElementX implements FieldElementX {
class ErroneousFieldElementX extends ElementX
with ConstantVariableMixin implements FieldElementX {
final VariableList variables;
ErroneousFieldElementX(Identifier name, Element enclosingElement)
@ -1567,7 +1592,8 @@ class FormalElementX extends ElementX
/// to ensure that default values on parameters are computed once (on the
/// origin parameter) but can be found through both the origin and the patch.
abstract class ParameterElementX extends FormalElementX
with PatchMixin<ParameterElement> implements ParameterElement {
with PatchMixin<ParameterElement>, ConstantVariableMixin
implements ParameterElement {
final Expression initializer;
final bool isOptional;
final bool isNamed;
@ -1957,8 +1983,32 @@ class LocalFunctionElementX extends BaseFunctionElementX
bool get isLocal => true;
}
abstract class ConstantConstructorMixin implements ConstructorElement {
ConstantConstructor _constantConstructor;
ConstantConstructor get constantConstructor {
if (isPatch) {
ConstructorElement originConstructor = origin;
return originConstructor.constantConstructor;
}
if (!isConst || isFromEnvironmentConstructor) return null;
if (_constantConstructor == null) {
_constantConstructor = computeConstantConstructor(resolvedAst);
}
return _constantConstructor;
}
bool get isFromEnvironmentConstructor {
return name == 'fromEnvironment' &&
library.isDartCore &&
(enclosingClass.name == 'bool' ||
enclosingClass.name == 'int' ||
enclosingClass.name == 'String');
}
}
abstract class ConstructorElementX extends FunctionElementX
implements ConstructorElement {
with ConstantConstructorMixin implements ConstructorElement {
bool isRedirectingGenerative = false;
ConstructorElementX(String name,

View file

@ -714,7 +714,7 @@ class ResolverTask extends CompilerTask {
if (Elements.isStaticOrTopLevelField(element)) {
visitor.addDeferredAction(element, () {
if (element.modifiers.isConst) {
constantCompiler.compileConstant(element);
element.constant = constantCompiler.compileConstant(element);
} else {
constantCompiler.compileVariable(element);
}
@ -2427,8 +2427,10 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
parameterNodes = parameterNodes.tail;
});
addDeferredAction(enclosingElement, () {
functionParameters.forEachOptionalParameter((Element parameter) {
compiler.resolver.constantCompiler.compileConstant(parameter);
functionParameters.forEachOptionalParameter(
(ParameterElementX parameter) {
parameter.constant =
compiler.resolver.constantCompiler.compileConstant(parameter);
});
});
if (inCheckContext) {
@ -4877,14 +4879,15 @@ class VariableDefinitionsVisitor extends CommonResolverVisitor<Identifier> {
visitNodeList(NodeList node) {
for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
Identifier name = visit(link.head);
LocalVariableElement element = new LocalVariableElementX(
LocalVariableElementX element = new LocalVariableElementX(
name.source, resolver.enclosingElement,
variables, name.token);
resolver.defineLocalVariable(link.head, element);
resolver.addToScope(element);
if (definitions.modifiers.isConst) {
compiler.enqueuer.resolution.addDeferredAction(element, () {
compiler.resolver.constantCompiler.compileConstant(element);
element.constant =
compiler.resolver.constantCompiler.compileConstant(element);
});
}
}

View file

@ -760,16 +760,15 @@ abstract class DeclarationResolverMixin {
return new RequiredParameterStructure(
definitions, node, element, index);
} else {
ConstantExpression defaultValue;
if (element.initializer != null) {
defaultValue = elements.getConstant(element.initializer);
}
// TODO(johnniwinther): Should we differentiate between implicit (null)
// and explicit values? What about optional parameters on redirecting
// factories?
if (isNamed) {
return new NamedParameterStructure(
definitions, node, element, defaultValue);
definitions, node, element, element.constant);
} else {
return new OptionalParameterStructure(
definitions, node, element, defaultValue, index);
definitions, node, element, element.constant, index);
}
}
}

View file

@ -12,6 +12,7 @@ import '../compiler.dart' as api;
import 'colors.dart' as colors;
import 'constants/constant_system.dart' as constants;
import 'constants/expressions.dart' as constants;
import 'constants/values.dart' as constants;
import 'cps_ir/cps_ir_builder.dart' as ir_builder;
import 'cps_ir/cps_ir_builder_task.dart' as ir_builder;
@ -51,7 +52,7 @@ void main(List<String> arguments) {
useApi();
dart2js.main(arguments);
dart2jslib.isPublicName(null);
useConstant(null, null);
useConstant(null, null, null);
useNode(null);
useUtil(null);
useSetlet(null);
@ -84,9 +85,12 @@ useApi() {
}
void useConstant(constants.ConstantValue constant,
constants.ConstructedConstantExpression constructedConstant,
constants.ConstantSystem cs) {
constant.isObject;
cs.isBool(constant);
constructedConstant.computeInstanceType();
constructedConstant.computeInstanceFields();
}
void useNode(tree.Node node) {

View file

@ -79,7 +79,7 @@ class AnnotationInfo {
}
class AnnotationCreator
extends ConstantExpressionVisitor<AnnotationInfo, Annotation> {
extends ConstantExpressionVisitor<Annotation, AnnotationInfo> {
const AnnotationCreator();
@ -143,12 +143,6 @@ class AnnotationCreator
return null;
}
@override
Annotation visitPrimitive(PrimitiveConstantExpression exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitSymbol(SymbolConstantExpression exp,
AnnotationInfo context) {
@ -173,6 +167,67 @@ class AnnotationCreator
return createAnnotation(exp.element, context);
}
@override
Annotation visitBool(BoolConstantExpression exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitDouble(DoubleConstantExpression exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitInt(IntConstantExpression exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitNamed(NamedArgumentReference exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitNull(NullConstantExpression exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitPositional(PositionalArgumentReference exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitString(StringConstantExpression exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitStringFromEnvironment(
StringFromEnvironmentConstantExpression exp,
AnnotationInfo context) {
return null;
}
@override
Annotation visitDeferred(DeferredConstantExpression exp,
AnnotationInfo context) {

View file

@ -0,0 +1,247 @@
// 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 constant_expression_test;
import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
import 'package:compiler/src/constants/expressions.dart';
import 'package:compiler/src/dart2jslib.dart';
import 'package:compiler/src/elements/elements.dart';
import 'memory_compiler.dart';
class TestData {
/// Declarations needed for the [constants].
final String declarations;
/// Tested constants.
final List constants;
const TestData(this.declarations, this.constants);
}
class ConstantData {
/// Source code for the constant expression.
final String code;
/// The expected constant expression kind.
final ConstantExpressionKind kind;
/// ConstantExpression.getText() result if different from [code].
final String text;
/// The expected instance type for ConstructedConstantExpression.
final String type;
/// The expected instance fields for ConstructedConstantExpression.
final Map<String, String> fields;
const ConstantData(String code,
this.kind,
{String text,
this.type,
this.fields})
: this.code = code,
this.text = text != null ? text : code;
}
const List<TestData> DATA = const [
const TestData('', const [
const ConstantData('null', ConstantExpressionKind.NULL),
const ConstantData('false', ConstantExpressionKind.BOOL),
const ConstantData('true', ConstantExpressionKind.BOOL),
const ConstantData('0', ConstantExpressionKind.INT),
const ConstantData('0.0', ConstantExpressionKind.DOUBLE),
const ConstantData('"foo"', ConstantExpressionKind.STRING),
const ConstantData('1 + 2', ConstantExpressionKind.BINARY),
const ConstantData('-(1)', ConstantExpressionKind.UNARY, text: '-1'),
const ConstantData('identical(0, 1)', ConstantExpressionKind.IDENTICAL),
const ConstantData('"a" "b"', ConstantExpressionKind.CONCATENATE,
text: '"ab"'),
const ConstantData('identical', ConstantExpressionKind.FUNCTION),
const ConstantData('true ? 0 : 1', ConstantExpressionKind.CONDITIONAL),
const ConstantData('proxy', ConstantExpressionKind.VARIABLE),
const ConstantData('Object', ConstantExpressionKind.TYPE),
const ConstantData('#name', ConstantExpressionKind.SYMBOL),
const ConstantData('const [0, 1]', ConstantExpressionKind.LIST),
const ConstantData('const <int>[0, 1]', ConstantExpressionKind.LIST),
const ConstantData('const {0: 1, 2: 3}', ConstantExpressionKind.MAP),
const ConstantData('const <int, int>{0: 1, 2: 3}',
ConstantExpressionKind.MAP),
const ConstantData(
'const bool.fromEnvironment("foo", defaultValue: false)',
ConstantExpressionKind.BOOL_FROM_ENVIRONMENT),
const ConstantData(
'const int.fromEnvironment("foo", defaultValue: 42)',
ConstantExpressionKind.INT_FROM_ENVIRONMENT),
const ConstantData(
'const String.fromEnvironment("foo", defaultValue: "bar")',
ConstantExpressionKind.STRING_FROM_ENVIRONMENT),
]),
const TestData('''
class A {
const A();
}
class B {
final field1;
const B(this.field1);
}
class C extends B {
final field2;
const C({field1: 42, this.field2: false}) : super(field1);
const C.named([field = false]) : this(field1: field, field2: field);
}
''', const [
const ConstantData('const Object()',
ConstantExpressionKind.CONSTRUCTED,
type: 'Object', fields: const {}),
const ConstantData('const A()',
ConstantExpressionKind.CONSTRUCTED,
type: 'A', fields: const {}),
const ConstantData('const B(0)',
ConstantExpressionKind.CONSTRUCTED,
type: 'B',
fields: const {'field(B#field1)': '0'}),
const ConstantData('const B(const A())',
ConstantExpressionKind.CONSTRUCTED,
type: 'B',
fields: const {'field(B#field1)': 'const A()'}),
const ConstantData('const C()',
ConstantExpressionKind.CONSTRUCTED,
type: 'C',
fields: const {
'field(B#field1)': '42',
'field(C#field2)': 'false',
}),
const ConstantData('const C(field1: 87)',
ConstantExpressionKind.CONSTRUCTED,
type: 'C',
fields: const {
'field(B#field1)': '87',
'field(C#field2)': 'false',
}),
const ConstantData('const C(field2: true)',
ConstantExpressionKind.CONSTRUCTED,
type: 'C',
fields: const {
'field(B#field1)': '42',
'field(C#field2)': 'true',
}),
const ConstantData('const C.named()',
ConstantExpressionKind.CONSTRUCTED,
type: 'C',
fields: const {
'field(B#field1)': 'false',
'field(C#field2)': 'false',
}),
const ConstantData('const C.named(87)',
ConstantExpressionKind.CONSTRUCTED,
type: 'C',
fields: const {
'field(B#field1)': '87',
'field(C#field2)': '87',
}),
]),
const TestData('''
class A<T> implements B {
final field1;
const A({this.field1:42});
}
class B<S> implements C {
const factory B({field1}) = A<B<S>>;
// TODO(johnniwinther): Enable this when the constructor evaluator doesn't
// crash:
/*const factory B.named() = A<S>;*/
}
class C<U> {
const factory C({field1}) = A<B<double>>;
}
''', const [
const ConstantData('const A()', ConstantExpressionKind.CONSTRUCTED,
type: 'A<dynamic>',
fields: const {'field(A#field1)': '42'}),
const ConstantData('const A<int>(field1: 87)',
ConstantExpressionKind.CONSTRUCTED,
type: 'A<int>',
fields: const {'field(A#field1)': '87'}),
const ConstantData('const B()', ConstantExpressionKind.CONSTRUCTED,
type: 'A<B<dynamic>>',
fields: const {
'field(A#field1)': '42',
}),
const ConstantData('const B<int>()', ConstantExpressionKind.CONSTRUCTED,
type: 'A<B<int>>',
fields: const {
'field(A#field1)': '42',
}),
const ConstantData('const B<int>(field1: 87)',
ConstantExpressionKind.CONSTRUCTED,
type: 'A<B<int>>',
fields: const {
'field(A#field1)': '87',
}),
const ConstantData('const C<int>(field1: 87)',
ConstantExpressionKind.CONSTRUCTED,
type: 'A<B<double>>',
fields: const {
'field(A#field1)': '87',
}),
// TODO(johnniwinther): Enable this when the constructor evaluator doesn't
// crash:
/*const ConstantData('const B<int>.named()',
ConstantExpressionKind.CONSTRUCTED,
type: 'A<int>',
fields: const {
'field(A#field1)': '42',
}),*/
]),
];
main() {
asyncTest(() => Future.forEach(DATA, testData));
}
Future testData(TestData data) {
StringBuffer sb = new StringBuffer();
sb.write('${data.declarations}\n');
Map constants = {};
data.constants.forEach((ConstantData constantData) {
String name = 'c${constants.length}';
sb.write('const $name = ${constantData.code};\n');
constants[name] = constantData;
});
sb.write('main() {}\n');
String source = sb.toString();
Compiler compiler = compilerFor(
{'main.dart': source}, options: ['--analyze-all']);
return compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
var library = compiler.mainApp;
constants.forEach((String name, ConstantData data) {
FieldElement field = library.localLookup(name);
var constant = field.constant;
Expect.equals(data.kind, constant.kind,
"Unexpected kind '${constant.kind}' for contant "
"`${constant.getText()}`, expected '${data.kind}'.");
Expect.equals(data.text, constant.getText(),
"Unexpected text '${constant.getText()}' for contant, "
"expected '${data.text}'.");
if (data.type != null) {
String instanceType = constant.computeInstanceType().toString();
Expect.equals(data.type, instanceType,
"Unexpected type '$instanceType' for contant "
"`${constant.getText()}`, expected '${data.type}'.");
}
if (data.fields != null) {
Map instanceFields = constant.computeInstanceFields();
Expect.equals(data.fields.length, instanceFields.length,
"Unexpected field count ${instanceFields.length} for contant "
"`${constant.getText()}`, expected '${data.fields.length}'.");
instanceFields.forEach((field, expression) {
String name = '$field';
String expression = instanceFields[field].getText();
String expected = data.fields[name];
Expect.equals(expected, expression,
"Unexpected field expression ${expression} for field '$name' in "
"contant `${constant.getText()}`, expected '${expected}'.");
});
}
});
});
}

View file

@ -2379,7 +2379,8 @@ const Map<String, List<Test>> DECL_TESTS = const {
index: 0),
const Visit(VisitKind.VISIT_OPTIONAL_PARAMETER_DECL,
element: 'parameter(m#b)',
index: 1),
index: 1,
constant: 'null'),
]),
const Test(
'''
@ -2428,7 +2429,8 @@ const Map<String, List<Test>> DECL_TESTS = const {
element: 'parameter(m#a)',
index: 0),
const Visit(VisitKind.VISIT_NAMED_PARAMETER_DECL,
element: 'parameter(m#b)'),
element: 'parameter(m#b)',
constant: 'null'),
]),
const Test(
'''