diff --git a/crates/red_knot_python_semantic/resources/mdtest/annotations/callable.md b/crates/red_knot_python_semantic/resources/mdtest/annotations/callable.md index 8ca50c5b69..50de1fa7dd 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/annotations/callable.md +++ b/crates/red_knot_python_semantic/resources/mdtest/annotations/callable.md @@ -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: diff --git a/crates/red_knot_python_semantic/src/types/display.rs b/crates/red_knot_python_semantic/src/types/display.rs index d99d74e3d6..3d4fb84c8c 100644 --- a/crates/red_knot_python_semantic/src/types/display.rs +++ b/crates/red_knot_python_semantic/src/types/display.rs @@ -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,7 +407,28 @@ impl Display for DisplayMaybeNegatedType<'_> { if self.negated { f.write_str("~")?; } - self.ty.display(self.db).fmt(f) + 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) + } } }