-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Add Literal special form to types #13874
base: main
Are you sure you want to change the base?
Conversation
3fe84bd
to
fbcc66c
Compare
|
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 work! This task is actually quite a bit harder than I made it sound, I was forgetting some of the complexity in recognizing special forms :) This is a really good initial effort. Let me know if any of the comments below don't make sense or need further clarification.
crates/red_knot_python_semantic/resources/mdtest/literal/literal.md
Outdated
Show resolved
Hide resolved
crates/red_knot_python_semantic/resources/mdtest/literal/literal.md
Outdated
Show resolved
Hide resolved
crates/red_knot_python_semantic/resources/mdtest/unary/instance.md
Outdated
Show resolved
Hide resolved
self.infer_subscript_expression(subscript); | ||
Type::Todo | ||
} | ||
ast::Expr::Subscript(subscript) => self.infer_subscript_expression(subscript), |
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 is where we need the code to recognize special forms, but we should not be falling back to infer_subscript_expression
here (that's for value expressions), instead we should have a dedicated infer_subscript_type_expression
method, which should use infer_type_expression
on the value and the index, and for now handle only the case where the value is typing.Literal
special form, otherwise just return Todo
.
(The fact that infer_subscript_expression
was previously called here was just an easy placeholder way to ensure we cover all the sub-expressions, until we added proper support for inferring types correctly in type expressions.)
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.
That makes sense. Just one question, should we use infer_type_expression
for all indexes?
For example Literal in here is defined with an expression in the index. Others have annotation_expression
in their grammar. So here I use infer_type_expression
for other things but if it's Literal I use infer_expression
.
My reasoning behind it was when the value is True
. The True
itself should not have any meaning when used alone in the type annotation.
a0cf7af
to
855405c
Compare
bb69a4c
to
a5a4f7f
Compare
/// Lookup the type of `symbol` in the `_typeshed` module namespace. | ||
/// | ||
/// Returns `Unbound` if the `_typeshed` module isn't available for some reason. |
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.
/// Lookup the type of `symbol` in the `_typeshed` module namespace. | |
/// | |
/// Returns `Unbound` if the `_typeshed` module isn't available for some reason. | |
/// Lookup the type of `symbol` in the `typing` module namespace. | |
/// | |
/// Returns `Unbound` if the `typing` module isn't available for some reason. |
Handling
Literal
type in annotations.Resolves: #13672
Implementation
Since Literals are not a fully defined type in typeshed. I used a trick to figure out when a special form is a literal.
When we are inferring assignment types I am checking if the type of that assignment was resolved to typing.SpecialForm and the name of the target is
Literal
if that is the case then I am re creating a new instance type and set the known instance field toKnownInstance:Literal
.Why not defining a new type?
From this issue I learned that we want to resolve members to SpecialMethod class. So if we create a new instance here we can rely on the member resolving in that already exists.
Test
I'm adding the spec tests. Not completed yet.
https://typing.readthedocs.io/en/latest/spec/literal.html#equivalence-of-two-literals
Since the type of the value inside Literal is evaluated as a Literal(LiteralString, LiteralInt, ...) then the equality is only true when types and value are equal.
https://typing.readthedocs.io/en/latest/spec/literal.html#legal-and-illegal-parameterizations
The illegal parameterizations are mostly implemented I'm currently checking the slice expression and the slice type to make sure it's valid.
The union creation with Literals is not working because we don't have unions right now.
https://typing.readthedocs.io/en/latest/spec/literal.html#shortening-unions-of-literals
Questions
Should we continue to infer type of booleans as unknown in type annotation context?
ruff/crates/red_knot_python_semantic/src/types/infer.rs
Line 3638 in 66c3aaa
Summary
Test Plan