[red-knot] Disambiguate display for intersection types (#16914)

## Summary

Fixes #16912 

Create a new type `DisplayMaybeParenthesizedType` that is now used in
Union and Intersection display

## Test Plan

Update callable annotations
This commit is contained in:
Matthew Mckee 2025-03-23 14:18:30 +00:00 committed by GitHub
parent 2d892bc9f7
commit 08a0995108
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 44 additions and 9 deletions

View file

@ -167,6 +167,24 @@ def _(
reveal_type(e) # revealed: None | ((int | str, /) -> int) | int
```
## Intersection
```py
from typing import Callable, Union
from knot_extensions import Intersection, Not
def _(
c: Intersection[Callable[[Union[int, str]], int], int],
d: Intersection[int, Callable[[Union[int, str]], int]],
e: Intersection[int, Callable[[Union[int, str]], int], str],
f: Intersection[Not[Callable[[int, str], Intersection[int, str]]]],
):
reveal_type(c) # revealed: ((int | str, /) -> int) & int
reveal_type(d) # revealed: int & ((int | str, /) -> int)
reveal_type(e) # revealed: int & ((int | str, /) -> int) & str
reveal_type(f) # revealed: ~((int, str, /) -> int & str)
```
## Nested
A nested `Callable` as one of the parameter types:

View file

@ -292,14 +292,10 @@ impl Display for DisplayUnionType<'_> {
db: self.db,
});
} else {
if let Type::Callable(
CallableType::General(_) | CallableType::MethodWrapperDunderGet(_),
) = element
{
join.entry(&format_args!("({})", element.display(self.db)));
} else {
join.entry(&element.display(self.db));
}
join.entry(&DisplayMaybeParenthesizedType {
ty: *element,
db: self.db,
});
}
}
@ -411,8 +407,29 @@ impl Display for DisplayMaybeNegatedType<'_> {
if self.negated {
f.write_str("~")?;
}
DisplayMaybeParenthesizedType {
ty: self.ty,
db: self.db,
}
.fmt(f)
}
}
struct DisplayMaybeParenthesizedType<'db> {
ty: Type<'db>,
db: &'db dyn Db,
}
impl Display for DisplayMaybeParenthesizedType<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if let Type::Callable(CallableType::General(_) | CallableType::MethodWrapperDunderGet(_)) =
self.ty
{
write!(f, "({})", self.ty.display(self.db))
} else {
self.ty.display(self.db).fmt(f)
}
}
}
pub(crate) trait TypeArrayDisplay<'db> {