Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(797)

Unified Diff: pkg/compiler/lib/src/constants/evaluation.dart

Issue 1559233002: WIP: Compute constant expressions in resolution. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/constants/constructors.dart ('k') | pkg/compiler/lib/src/constants/expressions.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/constants/evaluation.dart
diff --git a/pkg/compiler/lib/src/constants/evaluation.dart b/pkg/compiler/lib/src/constants/evaluation.dart
index 176d736ed2599de93cbac9028f9bb9b7b7d25a56..1636d61d663500d057dfd9568c3eda10639fb309 100644
--- a/pkg/compiler/lib/src/constants/evaluation.dart
+++ b/pkg/compiler/lib/src/constants/evaluation.dart
@@ -6,17 +6,45 @@ library dart2js.constants.evaluation;
import '../compiler.dart' show
Compiler;
+import '../core_types.dart';
+import '../dart_types.dart';
+import '../diagnostics/messages.dart' show
+ MessageKind;
+import '../elements/elements.dart' show
+ ConstructorElement,
+ VariableElement;
+import '../resolution/operators.dart';
import '../universe/call_structure.dart' show
CallStructure;
import 'expressions.dart';
+import 'values.dart';
/// Environment used for evaluating constant expressions.
abstract class Environment {
// TODO(johnniwinther): Replace this with [CoreTypes] and maybe [Backend].
Compiler get compiler;
+ /// The core types in the evaluation environment.
+ CoreTypes get coreTypes;
+
/// Read environments string passed in using the '-Dname=value' option.
String readFromEnvironment(String name);
+
+ void reportWarning(ConstantExpression expression,
+ MessageKind kind,
+ Map arguments);
+
+ void reportError(ConstantExpression expression,
+ MessageKind kind,
+ Map arguments);
+
+ ConstantValue evaluateConstructor(
+ ConstructorElement constructor,
+ ConstantValue evaluate());
+
+ ConstantValue evaluateVariable(
+ VariableElement variable,
+ ConstantValue evaluate());
}
/// The normalized arguments passed to a const constructor computed from the
@@ -47,3 +75,496 @@ class NormalizedArguments {
return arguments[index];
}
}
+
+abstract class ConstantTypeChecker<T> {
+ CoreTypes get coreTypes;
+ bool get isRequired;
+ bool get allowUnknown;
+
+ void reportError(T position, MessageKind messageKind, Map arguments);
+
+ bool isBool(DartType type, {bool allowUnknown}) {
+ if (allowUnknown == null) allowUnknown = this.allowUnknown;
+ return
+ type == coreTypes.boolType ||
+ (type == null && allowUnknown);
+ }
+
+ bool isBoolOrNull(DartType type, {bool allowUnknown}) {
+ if (allowUnknown == null) allowUnknown = this.allowUnknown;
+ return
+ type == coreTypes.boolType ||
+ type == coreTypes.nullType ||
+ (type == null && allowUnknown);
+ }
+
+ bool isInt(DartType type, {bool allowUnknown}) {
+ if (allowUnknown == null) allowUnknown = this.allowUnknown;
+ return
+ type == coreTypes.intType ||
+ (type == null && allowUnknown);
+ }
+
+ bool isIntOrNull(DartType type, {bool allowUnknown}) {
+ if (allowUnknown == null) allowUnknown = this.allowUnknown;
+ return
+ type == coreTypes.intType ||
+ type == coreTypes.nullType ||
+ (type == null && allowUnknown);
+ }
+
+ bool isNum(DartType type, {bool allowUnknown}) {
+ if (allowUnknown == null) allowUnknown = this.allowUnknown;
+ return
+ type == coreTypes.intType ||
+ type == coreTypes.doubleType ||
+ (type == null && allowUnknown);
+ }
+
+ bool isString(DartType type, {bool allowUnknown}) {
+ if (allowUnknown == null) allowUnknown = this.allowUnknown;
+ return
+ type == coreTypes.stringType ||
+ (type == null && allowUnknown);
+ }
+
+ bool isStringOrNull(DartType type, {bool allowUnknown}) {
+ if (allowUnknown == null) allowUnknown = this.allowUnknown;
+ return
+ type == coreTypes.stringType ||
+ type == coreTypes.nullType ||
+ (type == null && allowUnknown);
+ }
+
+ bool isPrimitive(DartType type, {bool allowUnknown}) {
+ if (allowUnknown == null) allowUnknown = this.allowUnknown;
+ return
+ type == coreTypes.intType ||
+ type == coreTypes.doubleType ||
+ type == coreTypes.stringType ||
+ type == coreTypes.boolType ||
+ type == coreTypes.nullType ||
+ (type == null && allowUnknown);
+ }
+
+ bool isNonNullPrimitive(DartType type, {bool allowUnknown}) {
+ if (allowUnknown == null) allowUnknown = this.allowUnknown;
+ return
+ type == coreTypes.boolType ||
+ type == coreTypes.intType ||
+ type == coreTypes.doubleType ||
+ type == coreTypes.stringType ||
+ (type == null && allowUnknown);
+ }
+
+ bool checkBinaryExpression(
+ T position,
+ ConstantTypeInfo<T> left,
+ BinaryOperator operator,
+ ConstantTypeInfo<T> right) {
+ bool isValid = true;
+ switch (operator.kind) {
+ case BinaryOperatorKind.EQ:
+ case BinaryOperatorKind.NOT_EQ:
+ if (!isPrimitive(left.type)) {
+ if (isRequired) {
+ reportError(
+ left.position,
+ MessageKind.INVALID_CONSTANT_BINARY_PRIMITIVE_TYPE,
+ {'constant': left.constant,
+ 'type': left.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ if (!isPrimitive(right.type)) {
+ if (isRequired) {
+ reportError(
+ right.position,
+ MessageKind.INVALID_CONSTANT_BINARY_PRIMITIVE_TYPE,
+ {'constant': right.constant,
+ 'type': right.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ break;
+ case BinaryOperatorKind.ADD:
+ if (isString(left.type, allowUnknown: false)) {
+ if (!isString(right.type)) {
+ if (isRequired) {
+ reportError(
+ right.position,
+ MessageKind.INVALID_CONSTANT_STRING_ADD_TYPE,
+ {'constant': right.constant,
+ 'type': right.type});
+ }
+ isValid = false;
+ }
+ } else if (isNum(left.type, allowUnknown: false)) {
+ if (!isNum(right.type)) {
+ if (isRequired) {
+ reportError(
+ right.position,
+ MessageKind.INVALID_CONSTANT_NUM_ADD_TYPE,
+ {'constant': right.constant,
+ 'type': right.type});
+ }
+ isValid = false;
+ }
+ } else if (isString(right.type, allowUnknown: false)) {
+ if (!isString(left.type)) {
+ if (isRequired) {
+ reportError(
+ left.position,
+ MessageKind.INVALID_CONSTANT_STRING_ADD_TYPE,
+ {'constant': left.constant,
+ 'type': left.type});
+ }
+ isValid = false;
+ }
+ } else if (isNum(right.type, allowUnknown: false)) {
+ if (!isNum(left.type)) {
+ if (isRequired) {
+ reportError(
+ left.position,
+ MessageKind.INVALID_CONSTANT_NUM_ADD_TYPE,
+ {'constant': left.constant,
+ 'type': left.type});
+ }
+ isValid = false;
+ }
+ } else if (allowUnknown && (left.type == null || right.type == null)) {
+ // Assume valid on unknown types.
+ } else {
+ if (isRequired) {
+ assert(left.type != null);
+ assert(right.type != null);
+ reportError(
+ position,
+ MessageKind.INVALID_CONSTANT_ADD_TYPES,
+ {'leftConstant': left.constant,
+ 'leftType': left.type,
+ 'rightConstant': right.constant,
+ 'rightType': right.type});
+ }
+ isValid = false;
+ }
+ break;
+ case BinaryOperatorKind.SUB:
+ case BinaryOperatorKind.MUL:
+ case BinaryOperatorKind.DIV:
+ case BinaryOperatorKind.IDIV:
+ case BinaryOperatorKind.MOD:
+ case BinaryOperatorKind.GTEQ:
+ case BinaryOperatorKind.GT:
+ case BinaryOperatorKind.LTEQ:
+ case BinaryOperatorKind.LT:
+ if (!isNum(left.type)) {
+ if (isRequired) {
+ reportError(
+ left.position,
+ MessageKind.INVALID_CONSTANT_BINARY_NUM_TYPE,
+ {'constant': left.constant,
+ 'type': left.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ if (!isNum(right.type)) {
+ if (isRequired) {
+ reportError(
+ right.position,
+ MessageKind.INVALID_CONSTANT_BINARY_NUM_TYPE,
+ {'constant': right.constant,
+ 'type': right.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ break;
+ case BinaryOperatorKind.SHL:
+ case BinaryOperatorKind.SHR:
+ case BinaryOperatorKind.AND:
+ case BinaryOperatorKind.OR:
+ case BinaryOperatorKind.XOR:
+ if (!isInt(left.type)) {
+ if (isRequired) {
+ reportError(
+ left.position,
+ MessageKind.INVALID_CONSTANT_BINARY_INT_TYPE,
+ {'constant': left.constant,
+ 'type': left.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ if (!isInt(right.type)) {
+ if (isRequired) {
+ reportError(
+ right.position,
+ MessageKind.INVALID_CONSTANT_BINARY_INT_TYPE,
+ {'constant': right.constant,
+ 'type': right.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ break;
+ case BinaryOperatorKind.LOGICAL_AND:
+ if (!isBool(left.type)) {
+ if (isRequired) {
+ reportError(
+ left.position,
+ MessageKind.INVALID_LOGICAL_AND_OPERAND_TYPE,
+ {'constant': left.constant,
+ 'type': left.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ if (!isBool(right.type)) {
+ if (isRequired) {
+ reportError(
+ right.position,
+ MessageKind.INVALID_LOGICAL_AND_OPERAND_TYPE,
+ {'constant': right.constant,
+ 'type': right.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ break;
+ case BinaryOperatorKind.LOGICAL_OR:
+ if (!isBool(left.type)) {
+ if (isRequired) {
+ reportError(
+ left.position,
+ MessageKind.INVALID_LOGICAL_OR_OPERAND_TYPE,
+ {'constant': left.constant,
+ 'type': left.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ if (!isBool(right.type)) {
+ if (isRequired) {
+ reportError(
+ right.position,
+ MessageKind.INVALID_LOGICAL_OR_OPERAND_TYPE,
+ {'constant': right.constant,
+ 'type': right.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ break;
+ case BinaryOperatorKind.INDEX:
+ if (isRequired) {
+ reportError(position, MessageKind.INVALID_CONSTANT_INDEX, {});
+ }
+ isValid = false;
+ break;
+ case BinaryOperatorKind.IF_NULL:
+ if (isRequired) {
+ reportError(position, MessageKind.INVALID_CONSTANT_IF_NULL, {});
+ }
+ isValid = false;
+ break;
+ }
+ return isValid;
+ }
+
+ bool checkFromEnvironment(ConstantTypeInfo<T> name) {
+ bool isValidAsConstant = true;
+ if (!isString(name.type)) {
+ if (isRequired) {
+ reportError(
+ name.position,
+ MessageKind.INVALID_FROM_ENVIRONMENT_NAME_TYPE,
+ {'constant': name.constant,
+ 'type': name.type});
+ }
+ isValidAsConstant = false;
+ }
+ return isValidAsConstant;
+ }
+
+ bool checkBoolFromEnvironment(
+ ConstantTypeInfo<T> name,
+ ConstantTypeInfo<T> defaultValue) {
+ bool isValidAsConstant = checkFromEnvironment(name);
+ if (defaultValue != null) {
+ if (!isBoolOrNull(defaultValue.type)) {
+ if (isRequired) {
+ reportError(
+ defaultValue.position,
+ MessageKind.INVALID_BOOL_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE,
+ {'constant': defaultValue.constant,
+ 'type': defaultValue.type});
+ }
+ isValidAsConstant = false;
+ }
+ }
+ return isValidAsConstant;
+ }
+
+ bool checkIntFromEnvironment(
+ ConstantTypeInfo<T> name,
+ ConstantTypeInfo<T> defaultValue) {
+ bool isValidAsConstant = checkFromEnvironment(name);
+ if (defaultValue != null) {
+ if (!isIntOrNull(defaultValue.type)) {
+ if (isRequired) {
+ reportError(
+ defaultValue.position,
+ MessageKind.INVALID_INT_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE,
+ {'constant': defaultValue.constant,
+ 'type': defaultValue.type});
+ }
+ isValidAsConstant = false;
+ }
+ }
+ return isValidAsConstant;
+ }
+
+ bool checkStringFromEnvironment(
+ ConstantTypeInfo<T> name,
+ ConstantTypeInfo<T> defaultValue) {
+ bool isValidAsConstant = checkFromEnvironment(name);
+ if (defaultValue != null) {
+ if (!isStringOrNull(defaultValue.type)) {
+ if (isRequired) {
+ reportError(
+ defaultValue.position,
+ MessageKind.INVALID_STRING_FROM_ENVIRONMENT_DEFAULT_VALUE_TYPE,
+ {'constant': defaultValue.constant,
+ 'type': defaultValue.type});
+ }
+ isValidAsConstant = false;
+ }
+ }
+ return isValidAsConstant;
+ }
+
+ bool checkConcatenate(ConstantTypeInfo<T> part) {
+ bool isValidAsConstant = true;
+ if (!isNonNullPrimitive(part.type)) {
+ if (isRequired) {
+ reportError(
+ part.position,
+ MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE,
+ {'constant': part.constant,
+ 'type': part.type});
+ }
+ isValidAsConstant = false;
+ }
+ return isValidAsConstant;
+ }
+
+ bool checkConditional(ConstantTypeInfo<T> condition) {
+ bool isValidAsConstant = true;
+ if (!isBool(condition.type)) {
+ reportError(
+ condition.position,
+ MessageKind.INVALID_CONSTANT_CONDITIONAL_TYPE,
+ {'constant': condition.constant,
+ 'type': condition.type});
+ isValidAsConstant = false;
+ }
+ return isValidAsConstant;
+ }
+
+
+ bool checkUnary(
+ UnaryOperator operator,
+ ConstantTypeInfo<T> expression) {
+ bool isValid = true;
+ switch (operator.kind) {
+ case UnaryOperatorKind.NOT:
+ if (!isBool(expression.type)) {
+ if (isRequired) {
+ reportError(
+ expression.position,
+ MessageKind.INVALID_CONSTANT_NOT_TYPE,
+ {'constant': expression.constant,
+ 'type': expression.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ break;
+ case UnaryOperatorKind.NEGATE:
+ if (!isNum(expression.type)) {
+ if (isRequired) {
+ reportError(
+ expression.position,
+ MessageKind.INVALID_CONSTANT_NEGATE_TYPE,
+ {'constant': expression.constant,
+ 'type': expression.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ break;
+ case UnaryOperatorKind.COMPLEMENT:
+ if (!isInt(expression.type)) {
+ if (isRequired) {
+ reportError(
+ expression.position,
+ MessageKind.INVALID_CONSTANT_COMPLEMENT_TYPE,
+ {'constant': expression.constant,
+ 'type': expression.type,
+ 'operator': operator});
+ }
+ isValid = false;
+ }
+ break;
+ }
+ return isValid;
+ }
+}
+
+abstract class ConstantTypeInfo<T> {
+ T get position;
+ ConstantExpression get constant;
+ DartType get type;
+}
+
+class ConstantExpressionChecker
+ extends ConstantTypeChecker<ConstantExpression> {
+ final Environment environment;
+
+ ConstantExpressionChecker(this.environment);
+
+ @override
+ bool get allowUnknown => false;
+
+ @override
+ CoreTypes get coreTypes => environment.coreTypes;
+
+ @override
+ bool get isRequired => true;
+
+ @override
+ void reportError(ConstantExpression position,
+ MessageKind messageKind,
+ Map arguments) {
+ environment.reportError(position, messageKind, arguments);
+ }
+
+ ConstantValueTypeInfo createInfo(ConstantExpression expression,
+ ConstantValue value) {
+ if (expression == null) return null;
+ return new ConstantValueTypeInfo(expression, value.getType(coreTypes));
+ }
+}
+
+class ConstantValueTypeInfo implements ConstantTypeInfo<ConstantExpression> {
+ final ConstantExpression constant;
+ final DartType type;
+
+ ConstantValueTypeInfo(this.constant, this.type);
+
+ ConstantExpression get position => constant;
+}
« no previous file with comments | « pkg/compiler/lib/src/constants/constructors.dart ('k') | pkg/compiler/lib/src/constants/expressions.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698