mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
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:
parent
0eaa4d4717
commit
091c7eddae
15 changed files with 1426 additions and 92 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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].
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>();
|
||||
|
|
376
pkg/compiler/lib/src/constants/constructors.dart
Normal file
376
pkg/compiler/lib/src/constants/constructors.dart
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
247
tests/compiler/dart2js/constant_expression_test.dart
Normal file
247
tests/compiler/dart2js/constant_expression_test.dart
Normal 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}'.");
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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(
|
||||
'''
|
||||
|
|
Loading…
Reference in a new issue