mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 06:41:23 +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
|
```py
|
||||||
from typing_extensions import Annotated
|
from typing_extensions import Annotated
|
||||||
|
|
||||||
# TODO: False positive
|
|
||||||
# error: [invalid-base]
|
|
||||||
class C(Annotated[int, "foo"]): ...
|
class C(Annotated[int, "foo"]): ...
|
||||||
|
|
||||||
# TODO: Should be `tuple[Literal[C], Literal[int], Literal[object]]`
|
# 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
|
### Not parameterized
|
||||||
|
|
|
@ -851,6 +851,10 @@ impl<'db> KnownClass {
|
||||||
matches!(self, Self::Bool)
|
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,
|
/// Determine whether instances of this class are always truthy, always falsy,
|
||||||
/// or have an ambiguous truthiness.
|
/// or have an ambiguous truthiness.
|
||||||
pub(crate) const fn bool(self) -> Truthiness {
|
pub(crate) const fn bool(self) -> Truthiness {
|
||||||
|
|
|
@ -5631,6 +5631,11 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
(Type::KnownInstance(KnownInstanceType::Protocol), _) => {
|
(Type::KnownInstance(KnownInstanceType::Protocol), _) => {
|
||||||
Type::Dynamic(DynamicType::TodoProtocol)
|
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) => {
|
(value_ty, slice_ty) => {
|
||||||
// If the class defines `__getitem__`, return its return type.
|
// If the class defines `__getitem__`, return its return type.
|
||||||
//
|
//
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue