Skip to content

Commit 38593fb

Browse files
authored
Check operand types in bool or, and, xor to be PyInt (RustPython#5461)
* Added Tests for Bitwise or, and, xor type error * Sync binary operator order comment with actual implementation * Check operand types in bool or, and, xor to be PyInt PyNumber methods are expected to type check both arguments. Dispatch is not done by inverting parameter order for __r<op>__ (example __ror__) when calls are handled via PyNumberMethods
1 parent 8d187fd commit 38593fb

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

extra_tests/snippets/operator_arithmetic.py

+20
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,23 @@
3232

3333
# Right shift raises value error on negative
3434
assert_raises(ValueError, lambda: 1 >> -1)
35+
36+
# Bitwise or, and, xor raises value error on incompatible types
37+
assert_raises(TypeError, lambda: "abc" | True)
38+
assert_raises(TypeError, lambda: "abc" & True)
39+
assert_raises(TypeError, lambda: "abc" ^ True)
40+
assert_raises(TypeError, lambda: True | "abc")
41+
assert_raises(TypeError, lambda: True & "abc")
42+
assert_raises(TypeError, lambda: True ^ "abc")
43+
assert_raises(TypeError, lambda: "abc" | 1.5)
44+
assert_raises(TypeError, lambda: "abc" & 1.5)
45+
assert_raises(TypeError, lambda: "abc" ^ 1.5)
46+
assert_raises(TypeError, lambda: 1.5 | "abc")
47+
assert_raises(TypeError, lambda: 1.5 & "abc")
48+
assert_raises(TypeError, lambda: 1.5 ^ "abc")
49+
assert_raises(TypeError, lambda: True | 1.5)
50+
assert_raises(TypeError, lambda: True & 1.5)
51+
assert_raises(TypeError, lambda: True ^ 1.5)
52+
assert_raises(TypeError, lambda: 1.5 | True)
53+
assert_raises(TypeError, lambda: 1.5 & True)
54+
assert_raises(TypeError, lambda: 1.5 ^ True)

vm/src/builtins/bool.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,10 @@ impl PyBool {
127127
let lhs = get_value(&lhs);
128128
let rhs = get_value(&rhs);
129129
(lhs || rhs).to_pyobject(vm)
130+
} else if let Some(lhs) = lhs.payload::<PyInt>() {
131+
lhs.or(rhs, vm).to_pyobject(vm)
130132
} else {
131-
get_py_int(&lhs).or(rhs, vm).to_pyobject(vm)
133+
vm.ctx.not_implemented()
132134
}
133135
}
134136

@@ -141,8 +143,10 @@ impl PyBool {
141143
let lhs = get_value(&lhs);
142144
let rhs = get_value(&rhs);
143145
(lhs && rhs).to_pyobject(vm)
146+
} else if let Some(lhs) = lhs.payload::<PyInt>() {
147+
lhs.and(rhs, vm).to_pyobject(vm)
144148
} else {
145-
get_py_int(&lhs).and(rhs, vm).to_pyobject(vm)
149+
vm.ctx.not_implemented()
146150
}
147151
}
148152

@@ -155,8 +159,10 @@ impl PyBool {
155159
let lhs = get_value(&lhs);
156160
let rhs = get_value(&rhs);
157161
(lhs ^ rhs).to_pyobject(vm)
162+
} else if let Some(lhs) = lhs.payload::<PyInt>() {
163+
lhs.xor(rhs, vm).to_pyobject(vm)
158164
} else {
159-
get_py_int(&lhs).xor(rhs, vm).to_pyobject(vm)
165+
vm.ctx.not_implemented()
160166
}
161167
}
162168
}
@@ -207,7 +213,3 @@ pub(crate) fn init(context: &Context) {
207213
pub(crate) fn get_value(obj: &PyObject) -> bool {
208214
!obj.payload::<PyInt>().unwrap().as_bigint().is_zero()
209215
}
210-
211-
fn get_py_int(obj: &PyObject) -> &PyInt {
212-
obj.payload::<PyInt>().unwrap()
213-
}

0 commit comments

Comments
 (0)