[CFE] Error on bitwise or shift operation on a double constant.

Fixes https://github.com/dart-lang/sdk/issues/36823

Change-Id: I9aeb34b9f80261889434f85bf39af3d78a38202e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112391
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
This commit is contained in:
Aske Simon Christensen
2019-08-16 11:11:27 +00:00
committed by commit-bot@chromium.org
parent 2d9246000f
commit e611357309
3 changed files with 80 additions and 17 deletions
@@ -1215,9 +1215,11 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
unevaluatedArguments(arguments, {}, node.arguments.types)));
}
final String op = node.name.name;
// Handle == and != first (it's common between all types). Since `a != b` is
// parsed as `!(a == b)` it is handled implicitly through ==.
if (arguments.length == 1 && node.name.name == '==') {
if (arguments.length == 1 && op == '==') {
final right = arguments[0];
// [DoubleConstant] uses [identical] to determine equality, so we need two
@@ -1250,7 +1252,7 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
// This is a white-listed set of methods we need to support on constants.
if (receiver is StringConstant) {
if (arguments.length == 1) {
switch (node.name.name) {
switch (op) {
case '+':
final Constant other = arguments[0];
if (other is StringConstant) {
@@ -1268,7 +1270,7 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
}
} else if (receiver is IntConstant || receiver is JavaScriptIntConstant) {
if (arguments.length == 0) {
switch (node.name.name) {
switch (op) {
case 'unary-':
if (targetingJavaScript) {
BigInt value = (receiver as JavaScriptIntConstant).bigIntValue;
@@ -1290,7 +1292,6 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
}
} else if (arguments.length == 1) {
final Constant other = arguments[0];
final op = node.name.name;
if (other is IntConstant || other is JavaScriptIntConstant) {
if ((op == '<<' || op == '>>' || op == '>>>')) {
var receiverValue = receiver is IntConstant
@@ -1342,7 +1343,7 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
.toUnsigned(32)
.toInt();
return evaluateBinaryBitOperation(
node.name.name, receiverValue, otherValue, node);
op, receiverValue, otherValue, node);
case '<<':
case '>>':
case '>>>':
@@ -1361,7 +1362,7 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
: (other as JavaScriptIntConstant).bigIntValue.toInt();
return evaluateBinaryShiftOperation(
node.name.name, receiverValue, otherValue, node,
op, receiverValue, otherValue, node,
negativeReceiver: negative);
default:
num receiverValue = receiver is IntConstant
@@ -1371,26 +1372,46 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
? other.value
: (other as DoubleConstant).value;
return evaluateBinaryNumericOperation(
node.name.name, receiverValue, otherValue, node);
op, receiverValue, otherValue, node);
}
} else if (other is DoubleConstant) {
if ((op == '|' || op == '&' || op == '^') ||
(op == '<<' || op == '>>' || op == '>>>')) {
return report(
node,
templateConstEvalInvalidBinaryOperandType.withArguments(
op,
other,
typeEnvironment.intType,
other.getType(typeEnvironment)));
}
num receiverValue = receiver is IntConstant
? receiver.value
: (receiver as DoubleConstant).value;
return evaluateBinaryNumericOperation(
node.name.name, receiverValue, other.value, node);
op, receiverValue, other.value, node);
}
return report(
node,
templateConstEvalInvalidBinaryOperandType.withArguments(
node.name.name,
op,
receiver,
typeEnvironment.numType,
other.getType(typeEnvironment)));
}
} else if (receiver is DoubleConstant) {
if ((op == '|' || op == '&' || op == '^') ||
(op == '<<' || op == '>>' || op == '>>>')) {
return report(
node,
templateConstEvalInvalidBinaryOperandType.withArguments(
op,
receiver,
typeEnvironment.intType,
receiver.getType(typeEnvironment)));
}
if (arguments.length == 0) {
switch (node.name.name) {
switch (op) {
case 'unary-':
return canonicalize(makeDoubleConstant(-receiver.value));
}
@@ -1402,12 +1423,12 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
? other.value
: (other as DoubleConstant).value;
return evaluateBinaryNumericOperation(
node.name.name, receiver.value, value, node);
op, receiver.value, value, node);
}
return report(
node,
templateConstEvalInvalidBinaryOperandType.withArguments(
node.name.name,
op,
receiver,
typeEnvironment.numType,
other.getType(typeEnvironment)));
@@ -1416,7 +1437,7 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
if (arguments.length == 1) {
final Constant other = arguments[0];
if (other is BoolConstant) {
switch (node.name.name) {
switch (op) {
case '|':
return canonicalize(
new BoolConstant(receiver.value || other.value));
@@ -1433,10 +1454,8 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
return report(node, messageConstEvalNullValue);
}
return report(
node,
templateConstEvalInvalidMethodInvocation.withArguments(
node.name.name, receiver));
return report(node,
templateConstEvalInvalidMethodInvocation.withArguments(op, receiver));
}
visitLogicalExpression(LogicalExpression node) {
@@ -0,0 +1,40 @@
// Copyright (c) 2019, 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.
// SharedOptions=--enable-experiment=constant-update-2018,triple-shift
main() {
const dynamic i1 = 3;
const dynamic i2 = 2;
const dynamic d1 = 3.3;
const dynamic d2 = 2.2;
const sum = 0 + //
(i1 | i2) + //# ii1: ok
(i1 & i2) + //# ii2: ok
(i1 ^ i2) + //# ii3: ok
(i1 << i2) + //# ii4: ok
(i1 >> i2) + //# ii5: ok
(i1 >>> i2) + //# ii6: ok
(i1 | d2) + //# id1: compile-time error
(i1 & d2) + //# id2: compile-time error
(i1 ^ d2) + //# id3: compile-time error
(i1 << d2) + //# id4: compile-time error
(i1 >> d2) + //# id5: compile-time error
(i1 >>> d2) + //# id6: compile-time error
(d1 | i2) + //# di1: compile-time error
(d1 & i2) + //# di2: compile-time error
(d1 ^ i2) + //# di3: compile-time error
(d1 << i2) + //# di4: compile-time error
(d1 >> i2) + //# di5: compile-time error
(d1 >>> i2) + //# di6: compile-time error
(d1 | d2) + //# dd1: compile-time error
(d1 & d2) + //# dd2: compile-time error
(d1 ^ d2) + //# dd3: compile-time error
(d1 << d2) + //# dd4: compile-time error
(d1 >> d2) + //# dd5: compile-time error
(d1 >>> d2) + //# dd6: compile-time error
0;
print(sum);
}
@@ -30,6 +30,10 @@ cascaded_forwarding_stubs_test: CompileTimeError
const_cast2_test/01: CompileTimeError
const_cast2_test/none: CompileTimeError
const_constructor3_test/04: MissingCompileTimeError # Side-effect of working around issue 33441 for int-to-double
const_double_in_int_op_test/dd6: Skip # Triple shift
const_double_in_int_op_test/di6: Skip # Triple shift
const_double_in_int_op_test/id6: Skip # Triple shift
const_double_in_int_op_test/ii6: Skip # Triple shift
covariant_override/tear_off_type_test: RuntimeError # Issue 28395
covariant_subtyping_with_mixin_test: CompileTimeError # Issue 34329
deferred_load_library_wrong_args_test/01: MissingRuntimeError, RuntimeError # Issue 29920