Skip to content

Commit 98d25ed

Browse files
Jenny Messerlycommit-bot@chromium.org
authored andcommitted
fix #34450, implement boolean bitwise operators in dartdevc
These will be added in https://dart-review.googlesource.com/c/sdk/+/74664. Change-Id: I9712d8f9df72e686dd49e0b5198aa37e17815eb5 Reviewed-on: https://dart-review.googlesource.com/71228 Reviewed-by: Lasse R.H. Nielsen <lrn@google.com> Reviewed-by: Vijay Menon <vsm@google.com> Commit-Queue: Jenny Messerly <jmesserly@google.com>
1 parent 229d793 commit 98d25ed

File tree

3 files changed

+51
-14
lines changed

3 files changed

+51
-14
lines changed

pkg/dev_compiler/lib/src/analyzer/code_generator.dart

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4635,10 +4635,12 @@ class CodeGenerator extends Object
46354635

46364636
if (jsTypeRep.binaryOperationIsPrimitive(leftType, rightType) ||
46374637
leftType == types.stringType && op.type == TokenType.PLUS) {
4638-
// special cases where we inline the operation
4639-
// these values are assumed to be non-null (determined by the checker)
4640-
// TODO(jmesserly): it would be nice to just inline the method from core,
4641-
// instead of special cases here.
4638+
// Inline operations on primitive types where possible.
4639+
// TODO(jmesserly): inline these from dart:core instead of hardcoding
4640+
// the implementation details here.
4641+
4642+
/// Emits an inlined binary operation using the JS [code], adding null
4643+
/// checks if needed to ensure we throw the appropriate error.
46424644
JS.Expression binary(String code) {
46434645
return js.call(code, [notNull(left), notNull(right)])
46444646
..sourceInformation = _getLocation(node.operator.offset);
@@ -4648,6 +4650,16 @@ class CodeGenerator extends Object
46484650
return _coerceBitOperationResultToUnsigned(node, binary(code));
46494651
}
46504652

4653+
/// Similar to [binary] but applies a boolean conversion to the right
4654+
/// operand, to match the boolean bitwise operators in dart:core.
4655+
///
4656+
/// Short circuiting operators should not be used in [code], because the
4657+
/// null checks for both operands must happen unconditionally.
4658+
JS.Expression bitwiseBool(String code) {
4659+
return js.call(code, [notNull(left), _visitTest(right)])
4660+
..sourceInformation = _getLocation(node.operator.offset);
4661+
}
4662+
46514663
switch (op.type) {
46524664
case TokenType.TILDE_SLASH:
46534665
// `a ~/ b` is equivalent to `(a / b).truncate()`
@@ -4662,13 +4674,19 @@ class CodeGenerator extends Object
46624674
return operatorCall();
46634675

46644676
case TokenType.AMPERSAND:
4665-
return bitwise('# & #');
4677+
return jsTypeRep.isBoolean(leftType)
4678+
? bitwiseBool('!!(# & #)')
4679+
: bitwise('# & #');
46664680

46674681
case TokenType.BAR:
4668-
return bitwise('# | #');
4682+
return jsTypeRep.isBoolean(leftType)
4683+
? bitwiseBool('!!(# | #)')
4684+
: bitwise('# | #');
46694685

46704686
case TokenType.CARET:
4671-
return bitwise('# ^ #');
4687+
return jsTypeRep.isBoolean(leftType)
4688+
? bitwiseBool('# !== #')
4689+
: bitwise('# ^ #');
46724690

46734691
case TokenType.GT_GT:
46744692
int shiftCount = _asIntInRange(right, 0, 31);

pkg/dev_compiler/lib/src/compiler/js_typerep.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ abstract class SharedJSTypeRep<DartType> {
8989

9090
bool isNumber(DartType type) => typeFor(type) is JSNumber;
9191

92+
bool isBoolean(DartType type) => typeFor(type) is JSBoolean;
93+
9294
/// Is this type known to be represented as Object or Null in JS.
9395
bool isObjectOrNull(DartType t) {
9496
var rep = typeFor(t);

pkg/dev_compiler/lib/src/kernel/compiler.dart

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4043,10 +4043,12 @@ class ProgramCompiler extends Object
40434043

40444044
if (_typeRep.binaryOperationIsPrimitive(leftType, rightType) ||
40454045
leftType == types.stringType && op == '+') {
4046-
// special cases where we inline the operation
4047-
// these values are assumed to be non-null (determined by the checker)
4048-
// TODO(jmesserly): it would be nice to just inline the method from core,
4049-
// instead of special cases here.
4046+
// Inline operations on primitive types where possible.
4047+
// TODO(jmesserly): inline these from dart:core instead of hardcoding
4048+
// the implementation details here.
4049+
4050+
/// Emits an inlined binary operation using the JS [code], adding null
4051+
/// checks if needed to ensure we throw the appropriate error.
40504052
JS.Expression binary(String code) {
40514053
return js.call(code, [notNull(left), notNull(right)]);
40524054
}
@@ -4055,6 +4057,15 @@ class ProgramCompiler extends Object
40554057
return _coerceBitOperationResultToUnsigned(node, binary(code));
40564058
}
40574059

4060+
/// Similar to [binary] but applies a boolean conversion to the right
4061+
/// operand, to match the boolean bitwise operators in dart:core.
4062+
///
4063+
/// Short circuiting operators should not be used in [code], because the
4064+
/// null checks for both operands must happen unconditionally.
4065+
JS.Expression bitwiseBool(String code) {
4066+
return js.call(code, [notNull(left), _visitTest(right)]);
4067+
}
4068+
40584069
switch (op) {
40594070
case '~/':
40604071
// `a ~/ b` is equivalent to `(a / b).truncate()`
@@ -4070,13 +4081,19 @@ class ProgramCompiler extends Object
40704081
return _emitOperatorCall(left, target, op, [right]);
40714082

40724083
case '&':
4073-
return bitwise('# & #');
4084+
return _typeRep.isBoolean(leftType)
4085+
? bitwiseBool('!!(# & #)')
4086+
: bitwise('# & #');
40744087

40754088
case '|':
4076-
return bitwise('# | #');
4089+
return _typeRep.isBoolean(leftType)
4090+
? bitwiseBool('!!(# | #)')
4091+
: bitwise('# | #');
40774092

40784093
case '^':
4079-
return bitwise('# ^ #');
4094+
return _typeRep.isBoolean(leftType)
4095+
? bitwiseBool('# !== #')
4096+
: bitwise('# ^ #');
40804097

40814098
case '>>':
40824099
int shiftCount = _asIntInRange(right, 0, 31);

0 commit comments

Comments
 (0)