Revert "[dartdevc] Remove explicit calls of the constant evaluator in DDC."
This reverts commit fb8df61606faf1564fbb53f53115017fc4d76483.
Reason for revert: Breaking Dart SDK -> Flutter engine build.
Original change's description:
> [dartdevc] Remove explicit calls of the constant evaluator in DDC.
>
> These are unnecessary now that constant evaluation is performed as
> part of the front-end transformations.
>
> Change-Id: I5de9bbf7ebab09528431f764895eb3e3b1b45379
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/111430
> Commit-Queue: Aske Simon Christensen <askesc@google.com>
> Reviewed-by: Vijay Menon <vsm@google.com>
TBR=vsm@google.com,askesc@google.com
Change-Id: Ife7c6f207c38d86e390c98de8af81f9cc5b863c4
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/113746
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 7805e71..c4ab9cf 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -360,7 +360,8 @@
outFiles.add(File(outPaths.first + '.txt').writeAsString(sb.toString()));
}
- var compiler = ProgramCompiler(component, result.classHierarchy, options);
+ var compiler = ProgramCompiler(
+ component, result.classHierarchy, options, declaredVariables);
var jsModule = compiler.emitModule(
component, result.inputSummaries, inputSummaries, summaryModules);
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 8bd144f..0cd7d86 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -216,10 +216,10 @@
final NullableInference _nullableInference;
factory ProgramCompiler(Component component, ClassHierarchy hierarchy,
- SharedCompilerOptions options) {
+ SharedCompilerOptions options, Map<String, String> declaredVariables) {
var coreTypes = CoreTypes(component);
var types = TypeSchemaEnvironment(coreTypes, hierarchy);
- var constants = DevCompilerConstants();
+ var constants = DevCompilerConstants(types, declaredVariables);
var nativeTypes = NativeTypeSet(coreTypes, constants);
var jsTypeRep = JSTypeRep(types, hierarchy);
return ProgramCompiler._(coreTypes, coreTypes.index, nativeTypes, constants,
@@ -4919,19 +4919,73 @@
@override
js_ast.Expression visitListConcatenation(ListConcatenation node) {
// Only occurs inside unevaluated constants.
- throw UnsupportedError("List concatenation");
+ List<js_ast.Expression> entries = [];
+ _concatenate(Expression node) {
+ if (node is ListConcatenation) {
+ node.lists.forEach(_concatenate);
+ } else {
+ node.accept(this);
+ if (node is ConstantExpression) {
+ var list = node.constant as ListConstant;
+ entries.addAll(list.entries.map(visitConstant));
+ } else if (node is ListLiteral) {
+ entries.addAll(node.expressions.map(_visitExpression));
+ }
+ }
+ }
+
+ node.lists.forEach(_concatenate);
+ return _emitConstList(node.typeArgument, entries);
}
@override
js_ast.Expression visitSetConcatenation(SetConcatenation node) {
// Only occurs inside unevaluated constants.
- throw UnsupportedError("Set concatenation");
+ List<js_ast.Expression> entries = [];
+ _concatenate(Expression node) {
+ if (node is SetConcatenation) {
+ node.sets.forEach(_concatenate);
+ } else {
+ node.accept(this);
+ if (node is ConstantExpression) {
+ var set = node.constant as SetConstant;
+ entries.addAll(set.entries.map(visitConstant));
+ } else if (node is SetLiteral) {
+ entries.addAll(node.expressions.map(_visitExpression));
+ }
+ }
+ }
+
+ node.sets.forEach(_concatenate);
+ return _emitConstSet(node.typeArgument, entries);
}
@override
js_ast.Expression visitMapConcatenation(MapConcatenation node) {
// Only occurs inside unevaluated constants.
- throw UnsupportedError("Map concatenation");
+ List<js_ast.Expression> entries = [];
+ _concatenate(Expression node) {
+ if (node is MapConcatenation) {
+ node.maps.forEach(_concatenate);
+ } else {
+ node.accept(this);
+ if (node is ConstantExpression) {
+ var map = node.constant as MapConstant;
+ for (var entry in map.entries) {
+ entries.add(visitConstant(entry.key));
+ entries.add(visitConstant(entry.value));
+ }
+ } else if (node is MapLiteral) {
+ for (var entry in node.entries) {
+ entries.add(_visitExpression(entry.key));
+ entries.add(_visitExpression(entry.value));
+ }
+ }
+ }
+ }
+
+ node.maps.forEach(_concatenate);
+ return _emitConstMap(node.keyType, node.valueType, entries);
}
@override
diff --git a/pkg/dev_compiler/lib/src/kernel/constants.dart b/pkg/dev_compiler/lib/src/kernel/constants.dart
index 2059f37..9044034 100644
--- a/pkg/dev_compiler/lib/src/kernel/constants.dart
+++ b/pkg/dev_compiler/lib/src/kernel/constants.dart
@@ -2,25 +2,43 @@
// 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.
+// TODO(askesc): We should not need to call the constant evaluator
+// explicitly once constant-update-2018 is shipped.
+import 'package:front_end/src/api_prototype/constant_evaluator.dart'
+ show ConstantEvaluator, SimpleErrorReporter;
+
+import 'package:kernel/core_types.dart';
import 'package:kernel/kernel.dart';
import 'package:kernel/target/targets.dart';
+import 'package:kernel/type_environment.dart';
+import 'kernel_helpers.dart';
/// Implements constant evaluation for dev compiler:
///
/// [isConstant] determines if an expression is constant.
/// [evaluate] computes the value of a constant expression, if available.
class DevCompilerConstants {
- DevCompilerConstants();
+ final _ConstantVisitor _visitor;
+ final ConstantEvaluator _evaluator;
+
+ DevCompilerConstants(
+ TypeEnvironment types, Map<String, String> declaredVariables)
+ : _visitor = _ConstantVisitor(types.coreTypes),
+ _evaluator = ConstantEvaluator(const DevCompilerConstantsBackend(),
+ declaredVariables, types, const _ErrorReporter());
/// Determines if an expression is constant.
- bool isConstant(Expression e) => e is ConstantExpression;
+ bool isConstant(Expression e) => _visitor.isConstant(e);
/// Evaluates [e] to find its constant value, returning `null` if evaluation
/// failed, or if the constant was unavailable.
///
/// Returns [NullConstant] to represent the `null` value.
Constant evaluate(Expression e) {
- return e is ConstantExpression ? e.constant : null;
+ if (e == null) return null;
+
+ Constant result = _evaluator.evaluate(e);
+ return result is UnevaluatedConstant ? null : result;
}
/// If [node] is an annotation with a field named [name], returns that field's
@@ -42,6 +60,7 @@
///
/// Given the node for `@MyAnnotation('FooBar')` this will return `'FooBar'`.
Object getFieldValueFromAnnotation(Expression node, String name) {
+ node = unwrapUnevaluatedConstant(node);
if (node is ConstantExpression) {
var constant = node.constant;
if (constant is InstanceConstant) {
@@ -78,6 +97,7 @@
}
Object _evaluateAnnotationArgument(Expression node) {
+ node = unwrapUnevaluatedConstant(node);
if (node is ConstantExpression) {
var constant = node.constant;
if (constant is PrimitiveConstant) return constant.value;
@@ -92,6 +112,88 @@
}
}
+/// Finds constant expressions as defined in Dart language spec 4th ed,
+/// 16.1 Constants.
+class _ConstantVisitor extends ExpressionVisitor<bool> {
+ final CoreTypes coreTypes;
+ _ConstantVisitor(this.coreTypes);
+
+ bool isConstant(Expression e) => e.accept(this) as bool;
+
+ @override
+ defaultExpression(node) => false;
+ @override
+ defaultBasicLiteral(node) => true;
+ @override
+ visitTypeLiteral(node) => true; // TODO(jmesserly): deferred libraries?
+ @override
+ visitSymbolLiteral(node) => true;
+ @override
+ visitListLiteral(node) => node.isConst;
+ @override
+ visitMapLiteral(node) => node.isConst;
+ @override
+ visitStaticInvocation(node) {
+ return node.isConst ||
+ node.target == coreTypes.identicalProcedure &&
+ node.arguments.positional.every(isConstant) ||
+ isFromEnvironmentInvocation(coreTypes, node) &&
+ node.arguments.positional.every(isConstant) &&
+ node.arguments.named.every((n) => isConstant(n.value));
+ }
+
+ @override
+ visitDirectMethodInvocation(node) {
+ return node.receiver is BasicLiteral &&
+ isOperatorMethodName(node.name.name) &&
+ node.arguments.positional.every((p) => p is BasicLiteral);
+ }
+
+ @override
+ visitMethodInvocation(node) {
+ return node.receiver is BasicLiteral &&
+ isOperatorMethodName(node.name.name) &&
+ node.arguments.positional.every((p) => p is BasicLiteral);
+ }
+
+ @override
+ visitConstructorInvocation(node) => node.isConst;
+ @override
+ visitStringConcatenation(node) =>
+ node.expressions.every((e) => e is BasicLiteral);
+ @override
+ visitStaticGet(node) {
+ var target = node.target;
+ return target is Procedure || target is Field && target.isConst;
+ }
+
+ @override
+ visitVariableGet(node) => node.variable.isConst;
+ @override
+ visitNot(node) {
+ var operand = node.operand;
+ return operand is BoolLiteral ||
+ operand is DirectMethodInvocation &&
+ visitDirectMethodInvocation(operand) ||
+ operand is MethodInvocation && visitMethodInvocation(operand);
+ }
+
+ @override
+ visitLogicalExpression(node) =>
+ node.left is BoolLiteral && node.right is BoolLiteral;
+ @override
+ visitConditionalExpression(node) =>
+ node.condition is BoolLiteral &&
+ node.then is BoolLiteral &&
+ node.otherwise is BoolLiteral;
+
+ @override
+ visitLet(Let node) {
+ var init = node.variable.initializer;
+ return (init == null || isConstant(init)) && isConstant(node.body);
+ }
+}
+
/// Implement the class for compiler specific behavior.
class DevCompilerConstantsBackend extends ConstantsBackend {
const DevCompilerConstantsBackend();
@@ -116,3 +218,11 @@
}
}
}
+
+class _ErrorReporter extends SimpleErrorReporter {
+ const _ErrorReporter();
+
+ // Ignore reported errors.
+ @override
+ reportMessage(Uri uri, int offset, String message) {}
+}
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 9708afa..3b3b66a 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -101,6 +101,7 @@
/// This function works regardless of whether the CFE is evaluating constants,
/// or whether the constant is a field reference (such as "anonymous" above).
Class getAnnotationClass(Expression node) {
+ node = unwrapUnevaluatedConstant(node);
if (node is ConstantExpression) {
var constant = node.constant;
if (constant is InstanceConstant) return constant.classNode;
@@ -113,6 +114,19 @@
return null;
}
+Expression unwrapUnevaluatedConstant(Expression node) {
+ // TODO(jmesserly): see if we can configure CFE to preseve the original
+ // expression, rather than wrapping in an UnevaluatedConstant and then
+ // a ConstantExpression.
+ if (node is ConstantExpression) {
+ var constant = node.constant;
+ if (constant is UnevaluatedConstant) {
+ return constant.expression;
+ }
+ }
+ return node;
+}
+
/// Returns true if [name] is an operator method that is available on primitive
/// types (`int`, `double`, `num`, `String`, `bool`).
///
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index e472a73..33242c9 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -249,6 +249,7 @@
bool _isInternalAnnotationField(
Expression node, String fieldName, String className) {
+ node = unwrapUnevaluatedConstant(node);
if (node is ConstantExpression) {
var constant = node.constant;
return constant is InstanceConstant &&
diff --git a/pkg/dev_compiler/tool/kernel_sdk.dart b/pkg/dev_compiler/tool/kernel_sdk.dart
index 004097b..11e2a33 100755
--- a/pkg/dev_compiler/tool/kernel_sdk.dart
+++ b/pkg/dev_compiler/tool/kernel_sdk.dart
@@ -75,9 +75,11 @@
File(librarySpecPath)
.copySync(p.join(p.dirname(outputDir), p.basename(librarySpecPath)));
- var jsModule = ProgramCompiler(component, compilerResult.classHierarchy,
- SharedCompilerOptions(moduleName: 'dart_sdk'))
- .emitModule(component, [], [], {});
+ var jsModule = ProgramCompiler(
+ component,
+ compilerResult.classHierarchy,
+ SharedCompilerOptions(moduleName: 'dart_sdk'),
+ {}).emitModule(component, [], [], {});
var moduleFormats = {
'amd': ModuleFormat.amd,
'common': ModuleFormat.common,