-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[red-knot] Infer boolean literal expression #12688
Conversation
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. These changes all look good to me.
I have a concern about union types, though. How do we want a union of boolean literals to be represented internally? For an object that could be the True
constant or could be the False
constant, should we infer Literal[True] | Literal[False]
(a union of literals), or should we eagerly normalize it to <instance of bool>
(since we know that the bool
class is special: there will only be two possible instance of bool
).
- If the former, I think we will want to modify the
Display
implementation forDisplayUnionType
so thatLiteral[True] | Literal[False]
is simplified toLiteral[True, False]
, the same as we do for numeric literals - If the latter, some larger changes will be required
Mypy appears never to normalize Literal[True, False]
to bool
; pyright appears to always do so. (Link, link.) I think I weakly favour pyright's approach here, but not sure.
A separate question (which I think can almost certainly be deferred for now) is that @carljm added some fancy logic for int literals in infer_binary_expression
. We could also add some understanding of bool
literals to that method, since True + True == True + 1 == 1 + 1 == 2
@@ -175,6 +177,7 @@ impl<'db> Type<'db> { | |||
// TODO raise error | |||
Type::Unknown | |||
} | |||
Type::BooleanLiteral(_) => Type::Unknown, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we'll want to fall back to looking up attributes and methods on the builtins.bool
class in our vendored typeshed stubs. But I think we can defer that for this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the meaning of "member" in this context? From what I understand, it's the type of an attribute on the given type. So, for instance, set.append
would be a function type. Is this understanding correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, your understanding is correct there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually think even the concern I have about union types can probably be deferred for now. So I'm happy with this landing as-is, as long as we keep track of these open questions somewhere.
What's the benefit of the one or the other? I think I'd prefer Pyright's approach as well because it can be resolved.
Yes, I started playing around with binary expressions as well but thought to have it as it's own PR which would include all possible combinations. |
I think one "benefit" of mypy's approach is that you don't have to apply quite so much special casing to boolean literals specifically inside the type checker implementation when figuring out how unions of boolean literals resolve. One case where normalizing from typing import Literal
def f(x: Literal[True, False]):
match x:
case True:
...
case False:
...
case unreachable:
... However: we'll need to apply that special casing to from typing import Literal
def f(x: bool):
match x:
case True:
...
case False:
...
case unreachable:
... So leaving the union unnormalized as I also... wouldn't necessarily jump to the conclusion that this is a deliberate choice by mypy with an explicit motivation 😄 it's a very old type checker, and support for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thank you!
Enums are a similar case where we'll need to understand sealed types (i.e. types with a finite number of inhabitants). I'm fine with delaying handling of the equivalence of bool
and Literal[True, False]
for now. I added #12694 to track this issue.
## Summary This PR implements type inference for boolean literal expressions. ## Test Plan Add test cases for `True` and `False`.
Summary
This PR implements type inference for boolean literal expressions.
Test Plan
Add test cases for
True
andFalse
.