mirror of https://github.com/astral-sh/ruff
add tests for bools and make helper method private
This commit is contained in:
parent
59570beb57
commit
3aa91a853e
|
|
@ -57,6 +57,25 @@ reveal_type(a ^ a) # revealed: Literal[False]
|
||||||
reveal_type(a ^ b) # revealed: Literal[True]
|
reveal_type(a ^ b) # revealed: Literal[True]
|
||||||
reveal_type(b ^ a) # revealed: Literal[True]
|
reveal_type(b ^ a) # revealed: Literal[True]
|
||||||
reveal_type(b ^ b) # revealed: Literal[False]
|
reveal_type(b ^ b) # revealed: Literal[False]
|
||||||
|
|
||||||
|
# left-shift
|
||||||
|
reveal_type(a << a) # revealed: Literal[2]
|
||||||
|
reveal_type(a << b) # revealed: Literal[1]
|
||||||
|
reveal_type(b << a) # revealed: Literal[0]
|
||||||
|
reveal_type(b << b) # revealed: Literal[0]
|
||||||
|
reveal_type(True << 100) # revealed: int
|
||||||
|
|
||||||
|
# error: [literal-math-error] "Cannot left shift object of type `Literal[True]` by a negative value"
|
||||||
|
reveal_type(True << -1) # revealed: int
|
||||||
|
|
||||||
|
# right-shift
|
||||||
|
reveal_type(a >> a) # revealed: Literal[0]
|
||||||
|
reveal_type(a >> b) # revealed: Literal[1]
|
||||||
|
reveal_type(b >> a) # revealed: Literal[0]
|
||||||
|
reveal_type(b >> b) # revealed: Literal[0]
|
||||||
|
|
||||||
|
# error: [literal-math-error] "Cannot right shift object of type `Literal[False]` by a negative value"
|
||||||
|
reveal_type(False >> -1) # revealed: int
|
||||||
```
|
```
|
||||||
|
|
||||||
## Arithmetic with a variable
|
## Arithmetic with a variable
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ reveal_type(MyInt(3) / 0) # revealed: int | float
|
||||||
|
|
||||||
## Bit-shifting
|
## Bit-shifting
|
||||||
|
|
||||||
Literal artithmetic is supported for bit-shifting operations on `int`s:
|
Literal arithmetic is supported for bit-shifting operations on `int`s:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
reveal_type(42 << 3) # revealed: Literal[336]
|
reveal_type(42 << 3) # revealed: Literal[336]
|
||||||
|
|
|
||||||
|
|
@ -1512,48 +1512,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit a diagnostic if the given type cannot be divided by zero, or is shifted by a negative
|
|
||||||
/// value.
|
|
||||||
///
|
|
||||||
/// Expects the resolved type of the left side of the binary expression.
|
|
||||||
fn check_bad_rhs(&mut self, node: AnyNodeRef<'_>, op: ast::Operator, left: Type<'db>) -> bool {
|
|
||||||
let lhs_int = match left {
|
|
||||||
Type::BooleanLiteral(_) | Type::IntLiteral(_) => true,
|
|
||||||
Type::NominalInstance(instance)
|
|
||||||
if matches!(
|
|
||||||
instance.class.known(self.db()),
|
|
||||||
Some(KnownClass::Int | KnownClass::Bool)
|
|
||||||
) =>
|
|
||||||
{
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Type::NominalInstance(instance)
|
|
||||||
if matches!(instance.class.known(self.db()), Some(KnownClass::Float)) =>
|
|
||||||
{
|
|
||||||
false
|
|
||||||
}
|
|
||||||
_ => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let (op, by_what) = match (op, lhs_int) {
|
|
||||||
(ast::Operator::Div, _) => ("divide", "by zero"),
|
|
||||||
(ast::Operator::FloorDiv, _) => ("floor divide", "by zero"),
|
|
||||||
(ast::Operator::Mod, _) => ("reduce", "modulo zero"),
|
|
||||||
(ast::Operator::LShift, true) => ("left shift", "by a negative value"),
|
|
||||||
(ast::Operator::RShift, true) => ("right shift", "by a negative value"),
|
|
||||||
_ => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(builder) = self.context.report_lint(&LITERAL_MATH_ERROR, node) {
|
|
||||||
builder.into_diagnostic(format_args!(
|
|
||||||
"Cannot {op} object of type `{}` {by_what}",
|
|
||||||
left.display(self.db())
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_binding(&mut self, node: AnyNodeRef, binding: Definition<'db>, ty: Type<'db>) {
|
fn add_binding(&mut self, node: AnyNodeRef, binding: Definition<'db>, ty: Type<'db>) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
binding
|
binding
|
||||||
|
|
@ -6474,6 +6432,44 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
right_ty: Type<'db>,
|
right_ty: Type<'db>,
|
||||||
op: ast::Operator,
|
op: ast::Operator,
|
||||||
) -> Option<Type<'db>> {
|
) -> Option<Type<'db>> {
|
||||||
|
let check_bad_rhs = || {
|
||||||
|
let lhs_int = match left_ty {
|
||||||
|
Type::BooleanLiteral(_) | Type::IntLiteral(_) => true,
|
||||||
|
Type::NominalInstance(instance)
|
||||||
|
if matches!(
|
||||||
|
instance.class.known(self.db()),
|
||||||
|
Some(KnownClass::Int | KnownClass::Bool)
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Type::NominalInstance(instance)
|
||||||
|
if matches!(instance.class.known(self.db()), Some(KnownClass::Float)) =>
|
||||||
|
{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let (op, by_what) = match (op, lhs_int) {
|
||||||
|
(ast::Operator::Div, _) => ("divide", "by zero"),
|
||||||
|
(ast::Operator::FloorDiv, _) => ("floor divide", "by zero"),
|
||||||
|
(ast::Operator::Mod, _) => ("reduce", "modulo zero"),
|
||||||
|
(ast::Operator::LShift, true) => ("left shift", "by a negative value"),
|
||||||
|
(ast::Operator::RShift, true) => ("right shift", "by a negative value"),
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(builder) = self.context.report_lint(&LITERAL_MATH_ERROR, node) {
|
||||||
|
builder.into_diagnostic(format_args!(
|
||||||
|
"Cannot {op} object of type `{}` {by_what}",
|
||||||
|
left_ty.display(self.db())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
// Check for division by zero or shift by a negative value; this doesn't change the inferred
|
// Check for division by zero or shift by a negative value; this doesn't change the inferred
|
||||||
// type for the expression, but may emit a diagnostic
|
// type for the expression, but may emit a diagnostic
|
||||||
if !emitted_bad_rhs_diagnostic {
|
if !emitted_bad_rhs_diagnostic {
|
||||||
|
|
@ -6481,9 +6477,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
(
|
(
|
||||||
ast::Operator::Div | ast::Operator::FloorDiv | ast::Operator::Mod,
|
ast::Operator::Div | ast::Operator::FloorDiv | ast::Operator::Mod,
|
||||||
Type::IntLiteral(0) | Type::BooleanLiteral(false),
|
Type::IntLiteral(0) | Type::BooleanLiteral(false),
|
||||||
) => self.check_bad_rhs(node, op, left_ty),
|
) => check_bad_rhs(),
|
||||||
(ast::Operator::LShift | ast::Operator::RShift, Type::IntLiteral(n)) if n < 0 => {
|
(ast::Operator::LShift | ast::Operator::RShift, Type::IntLiteral(n)) if n < 0 => {
|
||||||
self.check_bad_rhs(node, op, left_ty)
|
check_bad_rhs()
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue