From e611357309530f70e060bb35dccfd3a131344604 Mon Sep 17 00:00:00 2001 From: Aske Simon Christensen Date: Fri, 16 Aug 2019 11:11:27 +0000 Subject: [PATCH] [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 Commit-Queue: Aske Simon Christensen --- .../src/fasta/kernel/constant_evaluator.dart | 53 +++++++++++++------ .../const_double_in_int_op_test.dart | 40 ++++++++++++++ tests/language_2/language_2_dartdevc.status | 4 ++ 3 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 tests/language_2/const_double_in_int_op_test.dart diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart index 9d31aeb8e9f..f0405f0a31c 100644 --- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart +++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart @@ -1215,9 +1215,11 @@ class ConstantEvaluator extends RecursiveVisitor { 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 { // 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 { } } 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 { } } 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 { .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 { : (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 { ? 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 { ? 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 { 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 { return report(node, messageConstEvalNullValue); } - return report( - node, - templateConstEvalInvalidMethodInvocation.withArguments( - node.name.name, receiver)); + return report(node, + templateConstEvalInvalidMethodInvocation.withArguments(op, receiver)); } visitLogicalExpression(LogicalExpression node) { diff --git a/tests/language_2/const_double_in_int_op_test.dart b/tests/language_2/const_double_in_int_op_test.dart new file mode 100644 index 00000000000..d9432f17070 --- /dev/null +++ b/tests/language_2/const_double_in_int_op_test.dart @@ -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); +} diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status index f23a8de310b..eb9a51ef568 100644 --- a/tests/language_2/language_2_dartdevc.status +++ b/tests/language_2/language_2_dartdevc.status @@ -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