mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 14:21:24 +00:00
Special-case value-expression inference of special form subscriptions (#16877)
## Summary Currently for something like `X = typing.Tuple[str, str]`, we infer the value of `X` as `object`. That's because `Tuple` (like many of the symbols in the typing module) is annotated as a `_SpecialForm` instance in typeshed's stubs:23382f5f8c/crates/red_knot_vendored/vendor/typeshed/stdlib/typing.pyi (L215)
and we don't understand implicit type aliases yet, and the stub for `_SpecialForm.__getitem__` says it always returns `object`:23382f5f8c/crates/red_knot_vendored/vendor/typeshed/stdlib/typing.pyi (L198-L200)
We have existing false positives in our test suite due to this:23382f5f8c/crates/red_knot_python_semantic/resources/mdtest/annotations/annotated.md (L76-L78)
and it's causing _many_ new false positives in #16872, which tries to make our annotation-expression parsing stricter in some ways. This PR therefore adds some small special casing for `KnownInstanceType` variants that fallback to `_SpecialForm`, so that these false positives can be avoided. ## Test Plan Existing mdtest altered. Cc. @MatthewMckee4
This commit is contained in:
parent
42cbce538b
commit
296d67a496
3 changed files with 10 additions and 3 deletions
|
@ -73,12 +73,10 @@ Inheriting from `Annotated[T, ...]` is equivalent to inheriting from `T` itself.
|
|||
```py
|
||||
from typing_extensions import Annotated
|
||||
|
||||
# TODO: False positive
|
||||
# error: [invalid-base]
|
||||
class C(Annotated[int, "foo"]): ...
|
||||
|
||||
# TODO: Should be `tuple[Literal[C], Literal[int], Literal[object]]`
|
||||
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Unknown, Literal[object]]
|
||||
reveal_type(C.__mro__) # revealed: tuple[Literal[C], @Todo(Inference of subscript on special form), Literal[object]]
|
||||
```
|
||||
|
||||
### Not parameterized
|
||||
|
|
|
@ -851,6 +851,10 @@ impl<'db> KnownClass {
|
|||
matches!(self, Self::Bool)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_special_form(self) -> bool {
|
||||
matches!(self, Self::SpecialForm)
|
||||
}
|
||||
|
||||
/// Determine whether instances of this class are always truthy, always falsy,
|
||||
/// or have an ambiguous truthiness.
|
||||
pub(crate) const fn bool(self) -> Truthiness {
|
||||
|
|
|
@ -5631,6 +5631,11 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
(Type::KnownInstance(KnownInstanceType::Protocol), _) => {
|
||||
Type::Dynamic(DynamicType::TodoProtocol)
|
||||
}
|
||||
(Type::KnownInstance(known_instance), _)
|
||||
if known_instance.class().is_special_form() =>
|
||||
{
|
||||
todo_type!("Inference of subscript on special form")
|
||||
}
|
||||
(value_ty, slice_ty) => {
|
||||
// If the class defines `__getitem__`, return its return type.
|
||||
//
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue