mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:25:17 +00:00
[red-knot] Infer type of if-expression if test has statically known truthiness (#14048)
## Summary Detecting statically known truthy or falsy test in if expressions (ternary). ## Test Plan new mdtest
This commit is contained in:
parent
487941ea66
commit
34a5d7cb7f
3 changed files with 33 additions and 6 deletions
|
@ -0,0 +1,24 @@
|
||||||
|
# If expression
|
||||||
|
|
||||||
|
## Union
|
||||||
|
|
||||||
|
```py
|
||||||
|
def bool_instance() -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
reveal_type(1 if bool_instance() else 2) # revealed: Literal[1, 2]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Statically known branches
|
||||||
|
|
||||||
|
```py
|
||||||
|
reveal_type(1 if True else 2) # revealed: Literal[1]
|
||||||
|
reveal_type(1 if "not empty" else 2) # revealed: Literal[1]
|
||||||
|
reveal_type(1 if (1,) else 2) # revealed: Literal[1]
|
||||||
|
reveal_type(1 if 1 else 2) # revealed: Literal[1]
|
||||||
|
|
||||||
|
reveal_type(1 if False else 2) # revealed: Literal[2]
|
||||||
|
reveal_type(1 if None else 2) # revealed: Literal[2]
|
||||||
|
reveal_type(1 if "" else 2) # revealed: Literal[2]
|
||||||
|
reveal_type(1 if 0 else 2) # revealed: Literal[2]
|
||||||
|
```
|
|
@ -39,7 +39,8 @@ reveal_type(UnionClassGetItem[0]) # revealed: str | int
|
||||||
## Class getitem with class union
|
## Class getitem with class union
|
||||||
|
|
||||||
```py
|
```py
|
||||||
flag = True
|
def bool_instance() -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
def __class_getitem__(cls, item: int) -> str:
|
def __class_getitem__(cls, item: int) -> str:
|
||||||
|
@ -49,7 +50,7 @@ class B:
|
||||||
def __class_getitem__(cls, item: int) -> int:
|
def __class_getitem__(cls, item: int) -> int:
|
||||||
return item
|
return item
|
||||||
|
|
||||||
x = A if flag else B
|
x = A if bool_instance() else B
|
||||||
|
|
||||||
reveal_type(x) # revealed: Literal[A, B]
|
reveal_type(x) # revealed: Literal[A, B]
|
||||||
reveal_type(x[0]) # revealed: str | int
|
reveal_type(x[0]) # revealed: str | int
|
||||||
|
|
|
@ -2362,13 +2362,15 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
orelse,
|
orelse,
|
||||||
} = if_expression;
|
} = if_expression;
|
||||||
|
|
||||||
self.infer_expression(test);
|
let test_ty = self.infer_expression(test);
|
||||||
|
|
||||||
// TODO detect statically known truthy or falsy test
|
|
||||||
let body_ty = self.infer_expression(body);
|
let body_ty = self.infer_expression(body);
|
||||||
let orelse_ty = self.infer_expression(orelse);
|
let orelse_ty = self.infer_expression(orelse);
|
||||||
|
|
||||||
UnionType::from_elements(self.db, [body_ty, orelse_ty])
|
match test_ty.bool(self.db) {
|
||||||
|
Truthiness::AlwaysTrue => body_ty,
|
||||||
|
Truthiness::AlwaysFalse => orelse_ty,
|
||||||
|
Truthiness::Ambiguous => UnionType::from_elements(self.db, [body_ty, orelse_ty]),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_lambda_body(&mut self, lambda_expression: &ast::ExprLambda) {
|
fn infer_lambda_body(&mut self, lambda_expression: &ast::ExprLambda) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue