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>
This commit is contained in:
Lasse R.H. Nielsen 2018-09-17 12:33:12 +00:00 committed by commit-bot@chromium.org
parent 5af9844382
commit cc08d0e1da
11 changed files with 157 additions and 53 deletions

View file

@ -20,6 +20,7 @@
be unmodifiable incorrectly allowed new methods added in Dart 2 to
succeed.
* Exported `Future` and `Stream` from `dart:core`.
* Added operators `&`, `|` and `^` to `bool`.
#### `dart:async`

View file

@ -42,6 +42,15 @@ class JSBool extends Interceptor implements bool {
@notNull
int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811);
@notNull
bool operator &(@nullCheck bool other) => JS('bool', "# && #", other, this);
@notNull
bool operator |(@nullCheck bool other) => JS('bool', "# || #", other, this);
@notNull
bool operator ^(@nullCheck bool other) => !identical(this, other);
Type get runtimeType => bool;
}

View file

@ -543,7 +543,13 @@ class Expect {
// A test failure doesn't count as throwing.
if (e is ExpectException) rethrow;
if (e is T && (check == null || check(e))) return;
_fail("Expect.throws$msg: Unexpected '$e'\n$s");
// Throws something unexpected.
String type = "";
if (T != dynamic && T != Object) {
type = "<$T>";
}
_fail("Expect.throws$type$msg: "
"Unexpected '${Error.safeToString(e)}'\n$s");
}
_fail('Expect.throws$msg fails: Did not throw');
}
@ -602,14 +608,16 @@ class Expect {
static void type<T>(Object object, [String reason]) {
if (object is T) return;
String msg = _getMessage(reason);
_fail("Expect.type($object is $T$msg) fails, was ${object.runtimeType}");
_fail("Expect.type($object is $T$msg) fails "
"on ${Error.safeToString(object)}");
}
/// Checks that [object] does not have type [T].
static void notType<T>(Object object, [String reason]) {
if (object is! T) return;
String msg = _getMessage(reason);
_fail("Expect.type($object is! $T$msg) fails, was ${object.runtimeType}");
_fail("Expect.type($object is! $T$msg) fails"
"on ${Error.safeToString(object)}");
}
static String _getMessage(String reason) =>

View file

@ -330,9 +330,6 @@ ThisAsIdentifier/example: Fail
ThisOrSuperAccessInFieldInitializer/example: Fail
TooFewArguments/example: Fail
TooManyArguments/example: Fail
TopLevelOperator/script1: Fail
TopLevelOperator/script2: Fail
TopLevelOperator/script3: Fail
TypeAfterVar/example: Fail
TypeArgumentMismatch/example: Fail
TypeArgumentsOnTypeVariable/script1: Fail

View file

@ -16,6 +16,7 @@ import 'dart:_js_helper'
JSSyntaxRegExp,
Primitives,
argumentErrorValue,
checkBool,
checkInt,
checkNull,
checkNum,
@ -364,6 +365,12 @@ class JSBool extends Interceptor implements bool {
// Note: if you change this, also change the function [S].
String toString() => JS('String', r'String(#)', this);
bool operator &(bool other) => JS('bool', "# && #", checkBool(other), this);
bool operator |(bool other) => JS('bool', "# || #", checkBool(other), this);
bool operator ^(bool other) => !identical(this, checkBool(other));
// The values here are SMIs, co-prime and differ about half of the bit
// positions, including the low bit, so they are different mod 2^k.
int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811);

View file

@ -5,7 +5,7 @@
part of dart.core;
/**
* The reserved words [:true:] and [:false:] denote objects that are the only
* The reserved words `true` and `false` denote objects that are the only two
* instances of this class.
*
* It is a compile-time error for a class to attempt to extend or implement
@ -23,21 +23,22 @@ class bool {
* the result is the [defaultValue].
*
* The result is the same as would be returned by:
*
* (const String.fromEnvironment(name) == "true")
* ? true
* : (const String.fromEnvironment(name) == "false")
* ? false
* : defaultValue
*
* ```dart
* (const String.fromEnvironment(name) == "true")
* ? true
* : (const String.fromEnvironment(name) == "false")
* ? false
* : defaultValue
* ```
* Example:
*
* const loggingFlag = const bool.fromEnvironment("logging");
*
* ```dart
* const loggingFlag = const bool.fromEnvironment("logging");
* ```
* If you want to use a different truth-string than `"true"`, you can use the
* [String.fromEnvironment] constructor directly:
*
* const isLoggingOn = (const String.fromEnvironment("logging") == "on");
* ```dart
* const isLoggingOn = (const String.fromEnvironment("logging") == "on");
* ```
*/
// The .fromEnvironment() constructors are special in that we do not want
// users to call them using "new". We prohibit that by giving them bodies
@ -50,9 +51,24 @@ class bool {
external int get hashCode;
/// The logical conjuncton ("and") of this and [other].
///
/// Returns `true` if both this and [other] are `true`, and `false` otherwise.
//TODO(lrn): Remove "as bool" in Dart 2.
bool operator &(bool other) => (other as bool) && this;
/// The logical disjunction ("inclusive or") of this and [other].
///
/// Returns `true` if either this or [other] is `true`, and `false` otherwise.
bool operator |(bool other) => (other as bool) || this;
/// The logical exclusive disjuction ("exclusive or") of this and [other].
///
/// Returns whether this and [other] are neither both `true` nor both `false`.
bool operator ^(bool other) => !(other as bool) == this;
/**
* Returns [:"true":] if the receiver is [:true:], or [:"false":] if the
* receiver is [:false:].
* Returns either `"true"` for `true` and `"false"` for `false`.
*/
String toString() {
return this ? "true" : "false";

View file

@ -10,6 +10,7 @@
# Tests that produce compile-time errors even in legacy mode.
[ $runtime == none ]
Language/Expressions/Bitwise_Expressions/syntax_t01/02: Skip
Language/Variables/constant_initialization_t03: CompileTimeError # Uppercase constants removed
Language/Variables/constant_variable_t09: CompileTimeError # Uppercase constants removed
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
# Tests that fail either at compile-time or at runtime.
[ $runtime != none ]
Language/Expressions/Bitwise_Expressions/syntax_t01/02: Skip
Language/Expressions/Numbers/static_type_of_double_t01: RuntimeError # Uppercase constants removed
Language/Expressions/Object_Identity/constant_objects_t01: RuntimeError # Uppercase constants removed
Language/Expressions/Object_Identity/double_t02: RuntimeError # Uppercase constants removed

View file

@ -2,6 +2,7 @@
# 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.
core_runtime_types_test: RuntimeError # Does not expect bool to have operators.
maps_test: Skip # Maps class no longer exists
[ $compiler == dart2analyzer ]

View file

@ -0,0 +1,46 @@
// Copyright (c) 2017, 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.
import "package:expect/expect.dart";
main() {
void test(bool b1, bool b2) {
var and1 = b1 && b2;
var and2 = b1 & b2;
var and3 = b1 ? b2 ? true : false : false;
var or1 = b1 || b2;
var or2 = b1 | b2;
var or3 = b1 ? true : b2 ? true : false;
var xor1 = b1 != b2;
var xor2 = b1 ^ b2;
var xor3 = b1 ? b2 ? false : true : b2 ? true : false;
var nb1 = !b1;
var nb2 = !b2;
Expect.equals(and3, and1);
Expect.equals(and3, and2);
Expect.equals(or3, or1);
Expect.equals(or3, or2);
Expect.equals(xor3, xor1);
Expect.equals(xor3, xor2);
Expect.notEquals(nb1, b1);
Expect.notEquals(nb2, b2);
}
test(true, false);
test(true, true);
test(false, true);
test(false, false);
Expect.isTrue(true || (throw "unreachable"));
Expect.throws(() => false || (throw "unreachable"));
Expect.isFalse(false && (throw "unreachable"));
Expect.throws(() => true && (throw "unreachable"));
Expect.throws(() => true | (throw "unreachable"));
Expect.throws(() => false | (throw "unreachable"));
Expect.throws(() => true & (throw "unreachable"));
Expect.throws(() => false & (throw "unreachable"));
}

View file

@ -46,13 +46,16 @@ class CoreRuntimeTypesTest {
assertListEquals(a, b);
}
static assertTypeError(void f()) {
Expect.throws(
static assertTypeError(void f(), [String message]) {
Expect.throws<Error>(
f,
(exception) =>
(exception is TypeError) ||
(exception is CastError) ||
(exception is AssertionError) ||
(exception is NoSuchMethodError) ||
(exception is ArgumentError));
(exception is ArgumentError),
message);
}
static testBooleanOperators() {
@ -94,46 +97,49 @@ class CoreRuntimeTypesTest {
for (var i = 0; i < objs.length; i++) {
for (var j = i + 1; j < objs.length; j++) {
testBinaryOperatorErrors(objs[i], objs[j]);
// Allow "String * int".
if (j > 2) testBinaryOperatorErrors(objs[j], objs[i]);
}
if (objs[i] != 1) {
testUnaryOperatorErrors(objs[i]);
testBinaryOperatorErrors(objs[j], objs[i]);
}
testUnaryOperatorErrors(objs[i]);
}
}
static testBinaryOperatorErrors(x, y) {
assertTypeError(() {
x - y;
});
x + y;
}, "$x+$y");
assertTypeError(() {
x * y;
});
x - y;
}, "$x-$y");
// String.* is the only non-same-type binary operator we have.
if (x is! String && y is! int) {
assertTypeError(() {
x * y;
}, "$x*$y");
}
assertTypeError(() {
x / y;
});
}, "$x/$y");
assertTypeError(() {
x | y;
});
}, "$x|$y");
assertTypeError(() {
x ^ y;
});
}, "$x^$y");
assertTypeError(() {
x & y;
});
}, "$x&$y");
assertTypeError(() {
x << y;
});
}, "$x<<$y");
assertTypeError(() {
x >> y;
});
}, "$x>>$y");
assertTypeError(() {
x ~/ y;
});
}, "$x~/$y");
assertTypeError(() {
x % y;
});
}, "$x%$y");
testComparisonOperatorErrors(x, y);
}
@ -143,27 +149,34 @@ class CoreRuntimeTypesTest {
assertEquals(x != y, true);
assertTypeError(() {
x < y;
});
}, "$x<$y");
assertTypeError(() {
x <= y;
});
}, "$x<=$y");
assertTypeError(() {
x > y;
});
}, "$x>$y");
assertTypeError(() {
x >= y;
});
}, "$x>=$y");
}
static testUnaryOperatorErrors(x) {
// TODO(jimhug): Add guard for 'is num' when 'is' is working
assertTypeError(() {
~x;
});
assertTypeError(() {
-x;
});
// TODO(jimhug): Add check for !x as an error when x is not a bool
if (x is! int) {
assertTypeError(() {
~x;
}, "~$x");
}
if (x is! num) {
assertTypeError(() {
-x;
}, "-$x");
}
if (x is! bool) {
assertTypeError(() {
!x;
}, "!$x");
}
}
static testRationalMethods() {

View file

@ -20,6 +20,7 @@ bigint_from_test: RuntimeError # Issue 32589
bigint_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
bit_twiddling_test/int64: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
compare_to2_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
core_runtime_types_test: RuntimeError # Issue 34147
date_time11_test: RuntimeError, Pass # Fails when US is on winter time, issue 31285.
date_time_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
double_ceil_test/int64: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
@ -288,6 +289,9 @@ symbol_reserved_word_test/12: RuntimeError # Issues 11669 and 31936 - throwing c
symbol_test/none: RuntimeError # Issues 11669 and 31936 - throwing const constructors.
unicode_test: RuntimeError # Issue 18061: German double S.
[ $compiler != fasta && !$strong ]
core_runtime_types_test: SkipByDesign
[ $compiler == none && $runtime == vm ]
from_environment_const_type_undefined_test/09: MissingCompileTimeError
from_environment_const_type_undefined_test/11: MissingCompileTimeError