Skip to content

Commit cc08d0e

Browse files
lrhncommit-bot@chromium.org
authored andcommitted
Add operators &, | and ^ to bool.
Change-Id: Idd6472f239445914c1ff1ab68fc7b38fa6b320ae Reviewed-on: https://dart-review.googlesource.com/25240 Commit-Queue: Lasse R.H. Nielsen <lrn@google.com> Reviewed-by: Leaf Petersen <leafp@google.com> Reviewed-by: Lasse R.H. Nielsen <lrn@google.com> Reviewed-by: Florian Loitsch <floitsch@google.com>
1 parent 5af9844 commit cc08d0e

File tree

11 files changed

+157
-53
lines changed

11 files changed

+157
-53
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
be unmodifiable incorrectly allowed new methods added in Dart 2 to
2121
succeed.
2222
* Exported `Future` and `Stream` from `dart:core`.
23+
* Added operators `&`, `|` and `^` to `bool`.
2324

2425
#### `dart:async`
2526

pkg/dev_compiler/tool/input_sdk/private/interceptors.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ class JSBool extends Interceptor implements bool {
4242
@notNull
4343
int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811);
4444

45+
@notNull
46+
bool operator &(@nullCheck bool other) => JS('bool', "# && #", other, this);
47+
48+
@notNull
49+
bool operator |(@nullCheck bool other) => JS('bool', "# || #", other, this);
50+
51+
@notNull
52+
bool operator ^(@nullCheck bool other) => !identical(this, other);
53+
4554
Type get runtimeType => bool;
4655
}
4756

pkg/expect/lib/expect.dart

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,13 @@ class Expect {
543543
// A test failure doesn't count as throwing.
544544
if (e is ExpectException) rethrow;
545545
if (e is T && (check == null || check(e))) return;
546-
_fail("Expect.throws$msg: Unexpected '$e'\n$s");
546+
// Throws something unexpected.
547+
String type = "";
548+
if (T != dynamic && T != Object) {
549+
type = "<$T>";
550+
}
551+
_fail("Expect.throws$type$msg: "
552+
"Unexpected '${Error.safeToString(e)}'\n$s");
547553
}
548554
_fail('Expect.throws$msg fails: Did not throw');
549555
}
@@ -602,14 +608,16 @@ class Expect {
602608
static void type<T>(Object object, [String reason]) {
603609
if (object is T) return;
604610
String msg = _getMessage(reason);
605-
_fail("Expect.type($object is $T$msg) fails, was ${object.runtimeType}");
611+
_fail("Expect.type($object is $T$msg) fails "
612+
"on ${Error.safeToString(object)}");
606613
}
607614

608615
/// Checks that [object] does not have type [T].
609616
static void notType<T>(Object object, [String reason]) {
610617
if (object is! T) return;
611618
String msg = _getMessage(reason);
612-
_fail("Expect.type($object is! $T$msg) fails, was ${object.runtimeType}");
619+
_fail("Expect.type($object is! $T$msg) fails"
620+
"on ${Error.safeToString(object)}");
613621
}
614622

615623
static String _getMessage(String reason) =>

pkg/front_end/messages.status

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,9 +330,6 @@ ThisAsIdentifier/example: Fail
330330
ThisOrSuperAccessInFieldInitializer/example: Fail
331331
TooFewArguments/example: Fail
332332
TooManyArguments/example: Fail
333-
TopLevelOperator/script1: Fail
334-
TopLevelOperator/script2: Fail
335-
TopLevelOperator/script3: Fail
336333
TypeAfterVar/example: Fail
337334
TypeArgumentMismatch/example: Fail
338335
TypeArgumentsOnTypeVariable/script1: Fail

sdk/lib/_internal/js_runtime/lib/interceptors.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import 'dart:_js_helper'
1616
JSSyntaxRegExp,
1717
Primitives,
1818
argumentErrorValue,
19+
checkBool,
1920
checkInt,
2021
checkNull,
2122
checkNum,
@@ -364,6 +365,12 @@ class JSBool extends Interceptor implements bool {
364365
// Note: if you change this, also change the function [S].
365366
String toString() => JS('String', r'String(#)', this);
366367

368+
bool operator &(bool other) => JS('bool', "# && #", checkBool(other), this);
369+
370+
bool operator |(bool other) => JS('bool', "# || #", checkBool(other), this);
371+
372+
bool operator ^(bool other) => !identical(this, checkBool(other));
373+
367374
// The values here are SMIs, co-prime and differ about half of the bit
368375
// positions, including the low bit, so they are different mod 2^k.
369376
int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811);

sdk/lib/core/bool.dart

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
part of dart.core;
66

77
/**
8-
* The reserved words [:true:] and [:false:] denote objects that are the only
8+
* The reserved words `true` and `false` denote objects that are the only two
99
* instances of this class.
1010
*
1111
* It is a compile-time error for a class to attempt to extend or implement
@@ -23,21 +23,22 @@ class bool {
2323
* the result is the [defaultValue].
2424
*
2525
* The result is the same as would be returned by:
26-
*
27-
* (const String.fromEnvironment(name) == "true")
28-
* ? true
29-
* : (const String.fromEnvironment(name) == "false")
30-
* ? false
31-
* : defaultValue
32-
*
26+
* ```dart
27+
* (const String.fromEnvironment(name) == "true")
28+
* ? true
29+
* : (const String.fromEnvironment(name) == "false")
30+
* ? false
31+
* : defaultValue
32+
* ```
3333
* Example:
34-
*
35-
* const loggingFlag = const bool.fromEnvironment("logging");
36-
*
34+
* ```dart
35+
* const loggingFlag = const bool.fromEnvironment("logging");
36+
* ```
3737
* If you want to use a different truth-string than `"true"`, you can use the
3838
* [String.fromEnvironment] constructor directly:
39-
*
40-
* const isLoggingOn = (const String.fromEnvironment("logging") == "on");
39+
* ```dart
40+
* const isLoggingOn = (const String.fromEnvironment("logging") == "on");
41+
* ```
4142
*/
4243
// The .fromEnvironment() constructors are special in that we do not want
4344
// users to call them using "new". We prohibit that by giving them bodies
@@ -50,9 +51,24 @@ class bool {
5051

5152
external int get hashCode;
5253

54+
/// The logical conjuncton ("and") of this and [other].
55+
///
56+
/// Returns `true` if both this and [other] are `true`, and `false` otherwise.
57+
//TODO(lrn): Remove "as bool" in Dart 2.
58+
bool operator &(bool other) => (other as bool) && this;
59+
60+
/// The logical disjunction ("inclusive or") of this and [other].
61+
///
62+
/// Returns `true` if either this or [other] is `true`, and `false` otherwise.
63+
bool operator |(bool other) => (other as bool) || this;
64+
65+
/// The logical exclusive disjuction ("exclusive or") of this and [other].
66+
///
67+
/// Returns whether this and [other] are neither both `true` nor both `false`.
68+
bool operator ^(bool other) => !(other as bool) == this;
69+
5370
/**
54-
* Returns [:"true":] if the receiver is [:true:], or [:"false":] if the
55-
* receiver is [:false:].
71+
* Returns either `"true"` for `true` and `"false"` for `false`.
5672
*/
5773
String toString() {
5874
return this ? "true" : "false";

tests/co19/co19-co19.status

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
# Tests that produce compile-time errors even in legacy mode.
1212
[ $runtime == none ]
13+
Language/Expressions/Bitwise_Expressions/syntax_t01/02: Skip
1314
Language/Variables/constant_initialization_t03: CompileTimeError # Uppercase constants removed
1415
Language/Variables/constant_variable_t09: CompileTimeError # Uppercase constants removed
1516
LibTest/core/double/operator_GE_A01_t03: CompileTimeError # Uppercase constants removed
@@ -42,6 +43,7 @@ LibTest/math/Rectangle/operator_equality_A04_t01: CompileTimeError # Uppercase c
4243

4344
# Tests that fail either at compile-time or at runtime.
4445
[ $runtime != none ]
46+
Language/Expressions/Bitwise_Expressions/syntax_t01/02: Skip
4547
Language/Expressions/Numbers/static_type_of_double_t01: RuntimeError # Uppercase constants removed
4648
Language/Expressions/Object_Identity/constant_objects_t01: RuntimeError # Uppercase constants removed
4749
Language/Expressions/Object_Identity/double_t02: RuntimeError # Uppercase constants removed

tests/corelib/corelib.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# for details. All rights reserved. Use of this source code is governed by a
33
# BSD-style license that can be found in the LICENSE file.
44

5+
core_runtime_types_test: RuntimeError # Does not expect bool to have operators.
56
maps_test: Skip # Maps class no longer exists
67

78
[ $compiler == dart2analyzer ]
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import "package:expect/expect.dart";
6+
7+
main() {
8+
void test(bool b1, bool b2) {
9+
var and1 = b1 && b2;
10+
var and2 = b1 & b2;
11+
var and3 = b1 ? b2 ? true : false : false;
12+
var or1 = b1 || b2;
13+
var or2 = b1 | b2;
14+
var or3 = b1 ? true : b2 ? true : false;
15+
var xor1 = b1 != b2;
16+
var xor2 = b1 ^ b2;
17+
var xor3 = b1 ? b2 ? false : true : b2 ? true : false;
18+
var nb1 = !b1;
19+
var nb2 = !b2;
20+
Expect.equals(and3, and1);
21+
Expect.equals(and3, and2);
22+
Expect.equals(or3, or1);
23+
Expect.equals(or3, or2);
24+
Expect.equals(xor3, xor1);
25+
Expect.equals(xor3, xor2);
26+
Expect.notEquals(nb1, b1);
27+
Expect.notEquals(nb2, b2);
28+
}
29+
30+
test(true, false);
31+
test(true, true);
32+
test(false, true);
33+
test(false, false);
34+
35+
Expect.isTrue(true || (throw "unreachable"));
36+
Expect.throws(() => false || (throw "unreachable"));
37+
38+
Expect.isFalse(false && (throw "unreachable"));
39+
Expect.throws(() => true && (throw "unreachable"));
40+
41+
Expect.throws(() => true | (throw "unreachable"));
42+
Expect.throws(() => false | (throw "unreachable"));
43+
44+
Expect.throws(() => true & (throw "unreachable"));
45+
Expect.throws(() => false & (throw "unreachable"));
46+
}

tests/corelib_2/core_runtime_types_test.dart

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,16 @@ class CoreRuntimeTypesTest {
4646
assertListEquals(a, b);
4747
}
4848

49-
static assertTypeError(void f()) {
50-
Expect.throws(
49+
static assertTypeError(void f(), [String message]) {
50+
Expect.throws<Error>(
5151
f,
5252
(exception) =>
5353
(exception is TypeError) ||
54+
(exception is CastError) ||
55+
(exception is AssertionError) ||
5456
(exception is NoSuchMethodError) ||
55-
(exception is ArgumentError));
57+
(exception is ArgumentError),
58+
message);
5659
}
5760

5861
static testBooleanOperators() {
@@ -94,46 +97,49 @@ class CoreRuntimeTypesTest {
9497
for (var i = 0; i < objs.length; i++) {
9598
for (var j = i + 1; j < objs.length; j++) {
9699
testBinaryOperatorErrors(objs[i], objs[j]);
97-
// Allow "String * int".
98-
if (j > 2) testBinaryOperatorErrors(objs[j], objs[i]);
99-
}
100-
if (objs[i] != 1) {
101-
testUnaryOperatorErrors(objs[i]);
100+
testBinaryOperatorErrors(objs[j], objs[i]);
102101
}
102+
testUnaryOperatorErrors(objs[i]);
103103
}
104104
}
105105

106106
static testBinaryOperatorErrors(x, y) {
107107
assertTypeError(() {
108-
x - y;
109-
});
108+
x + y;
109+
}, "$x+$y");
110110
assertTypeError(() {
111-
x * y;
112-
});
111+
x - y;
112+
}, "$x-$y");
113+
// String.* is the only non-same-type binary operator we have.
114+
if (x is! String && y is! int) {
115+
assertTypeError(() {
116+
x * y;
117+
}, "$x*$y");
118+
}
113119
assertTypeError(() {
114120
x / y;
115-
});
121+
}, "$x/$y");
116122
assertTypeError(() {
117123
x | y;
118-
});
124+
}, "$x|$y");
119125
assertTypeError(() {
120126
x ^ y;
121-
});
127+
}, "$x^$y");
122128
assertTypeError(() {
123129
x & y;
124-
});
130+
}, "$x&$y");
125131
assertTypeError(() {
126132
x << y;
127-
});
133+
}, "$x<<$y");
128134
assertTypeError(() {
129135
x >> y;
130-
});
136+
}, "$x>>$y");
131137
assertTypeError(() {
132138
x ~/ y;
133-
});
139+
}, "$x~/$y");
134140
assertTypeError(() {
135141
x % y;
136-
});
142+
}, "$x%$y");
137143

138144
testComparisonOperatorErrors(x, y);
139145
}
@@ -143,27 +149,34 @@ class CoreRuntimeTypesTest {
143149
assertEquals(x != y, true);
144150
assertTypeError(() {
145151
x < y;
146-
});
152+
}, "$x<$y");
147153
assertTypeError(() {
148154
x <= y;
149-
});
155+
}, "$x<=$y");
150156
assertTypeError(() {
151157
x > y;
152-
});
158+
}, "$x>$y");
153159
assertTypeError(() {
154160
x >= y;
155-
});
161+
}, "$x>=$y");
156162
}
157163

158164
static testUnaryOperatorErrors(x) {
159-
// TODO(jimhug): Add guard for 'is num' when 'is' is working
160-
assertTypeError(() {
161-
~x;
162-
});
163-
assertTypeError(() {
164-
-x;
165-
});
166-
// TODO(jimhug): Add check for !x as an error when x is not a bool
165+
if (x is! int) {
166+
assertTypeError(() {
167+
~x;
168+
}, "~$x");
169+
}
170+
if (x is! num) {
171+
assertTypeError(() {
172+
-x;
173+
}, "-$x");
174+
}
175+
if (x is! bool) {
176+
assertTypeError(() {
177+
!x;
178+
}, "!$x");
179+
}
167180
}
168181

169182
static testRationalMethods() {

0 commit comments

Comments
 (0)