From f184132d69441d53109e4e1bacae460254d5d773 Mon Sep 17 00:00:00 2001 From: David Peter Date: Mon, 24 Nov 2025 22:00:48 +0100 Subject: [PATCH] Fix value-position specializations --- .../resources/mdtest/implicit_type_aliases.md | 20 +++++++++++++++++++ .../resources/mdtest/pep613_type_aliases.md | 6 ++++-- .../src/types/infer/builder.rs | 9 +++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md b/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md index 97bce36638..77e5aaeb3a 100644 --- a/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md +++ b/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md @@ -462,19 +462,39 @@ expected: IntsOrNone = MyList[int] | None IntsOrStrs = Pair[int] | Pair[str] ListOfPairs = MyList[Pair[str]] +ListOrTupleOfInts = ListOrTuple[int] +AnnotatedInt = AnnotatedType[int] +SubclassOfInt = MyType[int] +# TODO: No error here +# error: [too-many-positional-arguments] "Too many positional arguments: expected 1, got 2" +# error: [invalid-type-form] "List literals are not allowed in this context in a type expression: Did you mean `list[int]`?" +CallableIntToStr = MyCallable[[int], str] reveal_type(IntsOrNone) # revealed: types.UnionType reveal_type(IntsOrStrs) # revealed: types.UnionType reveal_type(ListOfPairs) # revealed: +reveal_type(ListOrTupleOfInts) # revealed: types.UnionType +reveal_type(AnnotatedInt) # revealed: +reveal_type(SubclassOfInt) # revealed: GenericAlias +reveal_type(CallableIntToStr) # revealed: Unknown def _( ints_or_none: IntsOrNone, ints_or_strs: IntsOrStrs, list_of_pairs: ListOfPairs, + list_or_tuple_of_ints: ListOrTupleOfInts, + annotated_int: AnnotatedInt, + subclass_of_int: SubclassOfInt, + callable_int_to_str: CallableIntToStr, ): reveal_type(ints_or_none) # revealed: list[int] | None reveal_type(ints_or_strs) # revealed: tuple[int, int] | tuple[str, str] reveal_type(list_of_pairs) # revealed: list[tuple[str, str]] + reveal_type(list_or_tuple_of_ints) # revealed: list[int] | tuple[int, ...] + reveal_type(annotated_int) # revealed: int + reveal_type(subclass_of_int) # revealed: type[int] + # TODO: This should be `(int, /) -> str` + reveal_type(callable_int_to_str) # revealed: Unknown ``` A generic implicit type alias can also be used in another generic implicit type alias: diff --git a/crates/ty_python_semantic/resources/mdtest/pep613_type_aliases.md b/crates/ty_python_semantic/resources/mdtest/pep613_type_aliases.md index d227087d65..35c6ee9c0b 100644 --- a/crates/ty_python_semantic/resources/mdtest/pep613_type_aliases.md +++ b/crates/ty_python_semantic/resources/mdtest/pep613_type_aliases.md @@ -124,9 +124,11 @@ T = TypeVar("T") Alias1: TypeAlias = list[T] | set[T] MyAlias: TypeAlias = int | Alias1[str] +def _(): + reveal_type(Alias1) # revealed: types.UnionType + def _(x: MyAlias): - # TODO: int | list[str] | set[str] - reveal_type(x) # revealed: int | @Todo(Specialization of union type alias) + reveal_type(x) # revealed: int | list[str] | set[str] ``` ## Imported diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index c9c78a4941..ffc46a6091 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -11113,8 +11113,13 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { .map(Type::from) .unwrap_or_else(Type::unknown); } - Type::KnownInstance(KnownInstanceType::UnionType(_)) => { - return todo_type!("Specialization of union type alias"); + Type::KnownInstance( + KnownInstanceType::UnionType(_) + | KnownInstanceType::Annotated(_) + | KnownInstanceType::Callable(_) + | KnownInstanceType::TypeGenericAlias(_), + ) => { + return self.infer_explicitly_specialized_type_alias(subscript, value_ty, false); } _ => {} }