Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions crates/ty_python_semantic/resources/mdtest/binary/booleans.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,65 @@ def _(a: bool):
reveal_type(x / y) # revealed: int | float
reveal_type(x % y) # revealed: int
```

## Bitwise operations with a variable

```py
import random

def _(a: bool):
def lhs_is_int(x: int):
reveal_type(x | a) # revealed: int
reveal_type(x & a) # revealed: int
reveal_type(x ^ a) # revealed: int

def rhs_is_int(x: int):
reveal_type(a | x) # revealed: int
reveal_type(a & x) # revealed: int
reveal_type(a ^ x) # revealed: int

def lhs_is_int_literal():
reveal_type(0 | a) # revealed: int
reveal_type(0 & a) # revealed: int
reveal_type(0 ^ a) # revealed: int

reveal_type(1 | a) # revealed: int
reveal_type(1 & a) # revealed: int
reveal_type(1 ^ a) # revealed: int

def lhs_is_true():
reveal_type(True | a) # revealed: bool
reveal_type(True & a) # revealed: bool
reveal_type(True ^ a) # revealed: bool

def rhs_is_true():
reveal_type(a | True) # revealed: bool
reveal_type(a & True) # revealed: bool
reveal_type(a ^ True) # revealed: bool

def lhs_is_false():
reveal_type(False | a) # revealed: bool
reveal_type(False & a) # revealed: bool
reveal_type(False ^ a) # revealed: bool

def rhs_is_false():
reveal_type(a | False) # revealed: bool
reveal_type(a & False) # revealed: bool
reveal_type(a ^ False) # revealed: bool

def both_are_bool(x: bool, y: bool):
reveal_type(x | y) # revealed: bool
reveal_type(x & y) # revealed: bool
reveal_type(x ^ y) # revealed: bool

def lhs_is_int_literal_rhs_is_bool_literal():
reveal_type(0 & True) # revealed: Literal[0]
reveal_type(0 | True) # revealed: Literal[1]
reveal_type(3 & True) # revealed: Literal[1]
reveal_type(3 | True) # revealed: Literal[3]

reveal_type(0 & False) # revealed: Literal[0]
reveal_type(0 | False) # revealed: Literal[0]
reveal_type(3 & False) # revealed: Literal[0]
reveal_type(3 | False) # revealed: Literal[3]
```
34 changes: 18 additions & 16 deletions crates/ty_python_semantic/src/types/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6701,22 +6701,22 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
(Type::BooleanLiteral(b1), Type::BooleanLiteral(b2), ast::Operator::BitXor) => {
Some(Type::BooleanLiteral(b1 ^ b2))
}

(Type::BooleanLiteral(bool_value), right, op) => self.infer_binary_expression_type(
node,
emitted_division_by_zero_diagnostic,
Type::IntLiteral(i64::from(bool_value)),
right,
op,
),
(left, Type::BooleanLiteral(bool_value), op) => self.infer_binary_expression_type(
node,
emitted_division_by_zero_diagnostic,
left,
Type::IntLiteral(i64::from(bool_value)),
op,
),

(Type::BooleanLiteral(b1), Type::BooleanLiteral(_) | Type::IntLiteral(_), op) => self
.infer_binary_expression_type(
node,
emitted_division_by_zero_diagnostic,
Type::IntLiteral(i64::from(b1)),
right_ty,
op,
),
(Type::IntLiteral(_), Type::BooleanLiteral(b2), op) => self
.infer_binary_expression_type(
node,
emitted_division_by_zero_diagnostic,
left_ty,
Type::IntLiteral(i64::from(b2)),
op,
),
(Type::Tuple(lhs), Type::Tuple(rhs), ast::Operator::Add) => {
// Note: this only works on heterogeneous tuples.
let lhs_elements = lhs.elements(self.db());
Expand All @@ -6735,6 +6735,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
// fall back on looking for dunder methods on one of the operand types.
(
Type::FunctionLiteral(_)
| Type::BooleanLiteral(_)
| Type::Callable(..)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
Expand All @@ -6761,6 +6762,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
| Type::BoundSuper(_)
| Type::TypeVar(_),
Type::FunctionLiteral(_)
| Type::BooleanLiteral(_)
| Type::Callable(..)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
Expand Down
Loading