Skip to content
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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

Glyphack
Copy link
Contributor

@Glyphack Glyphack commented Oct 22, 2024

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 to KnownInstance: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?

Summary

Test Plan

@Glyphack Glyphack force-pushed the literal-type branch 4 times, most recently from 3fe84bd to fbcc66c Compare October 22, 2024 22:13
@Glyphack Glyphack marked this pull request as ready for review October 22, 2024 22:26
Copy link
Contributor

github-actions bot commented Oct 22, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Copy link
Contributor

@carljm carljm left a 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/src/types.rs Show resolved Hide resolved
crates/red_knot_python_semantic/src/types.rs Outdated Show resolved Hide resolved
crates/red_knot_python_semantic/src/types/infer.rs Outdated Show resolved Hide resolved
crates/red_knot_python_semantic/src/types/infer.rs Outdated Show resolved Hide resolved
crates/red_knot_python_semantic/src/types/infer.rs Outdated Show resolved Hide resolved
self.infer_subscript_expression(subscript);
Type::Todo
}
ast::Expr::Subscript(subscript) => self.infer_subscript_expression(subscript),
Copy link
Contributor

@carljm carljm Oct 23, 2024

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.)

Copy link
Contributor Author

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.

@carljm carljm added the red-knot Multi-file analysis & type inference label Oct 23, 2024
Comment on lines +76 to +78
/// Lookup the type of `symbol` in the `_typeshed` module namespace.
///
/// Returns `Unbound` if the `_typeshed` module isn't available for some reason.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
red-knot Multi-file analysis & type inference
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[red-knot] understand the Literal[] special form in annotations
3 participants