From f019cfd15f8947b95ab0f200551d14558705f6e7 Mon Sep 17 00:00:00 2001 From: Dhruv Manilawala Date: Wed, 20 Aug 2025 09:39:05 +0530 Subject: [PATCH] [ty] Use specialized parameter type for overload filter (#19964) ## Summary Closes: https://github.com/astral-sh/ty/issues/669 (This turned out to be simpler that I thought :)) ## Test Plan Update existing test cases. ### Ecosystem report Most of them are basically because ty has now started inferring more precise types for the return type to an overloaded call and a lot of the types are defined using type aliases, here's some examples:
Details

> attrs (https://github.com/python-attrs/attrs) > + tests/test_make.py:146:14: error[unresolved-attribute] Type `Literal[42]` has no attribute `default` > - Found 555 diagnostics > + Found 556 diagnostics This is accurate now that we infer the type as `Literal[42]` instead of `Unknown` (Pyright infers it as `int`) > optuna (https://github.com/optuna/optuna) > + optuna/_gp/search_space.py:181:53: error[invalid-argument-type] Argument to function `_round_one_normalized_param` is incorrect: Expected `tuple[int | float, int | float]`, found `tuple[Unknown | ndarray[Unknown, ], Unknown | ndarray[Unknown, ]]` > + optuna/_gp/search_space.py:181:83: error[invalid-argument-type] Argument to function `_round_one_normalized_param` is incorrect: Expected `int | float`, found `Unknown | ndarray[Unknown, ]` > + tests/gp_tests/test_search_space.py:109:13: error[invalid-argument-type] Argument to function `_unnormalize_one_param` is incorrect: Expected `tuple[int | float, int | float]`, found `Unknown | ndarray[Unknown, ]` > + tests/gp_tests/test_search_space.py:110:13: error[invalid-argument-type] Argument to function `_unnormalize_one_param` is incorrect: Expected `int | float`, found `Unknown | ndarray[Unknown, ]` > - Found 559 diagnostics > + Found 563 diagnostics Same as above where ty is now inferring a more precise type like `Unknown | ndarray[tuple[int, int], ]` instead of just `Unknown` as before > jinja (https://github.com/pallets/jinja) > + src/jinja2/bccache.py:298:39: error[invalid-argument-type] Argument to bound method `write_bytecode` is incorrect: Expected `IO[bytes]`, found `_TemporaryFileWrapper[str]` > - Found 186 diagnostics > + Found 187 diagnostics This requires support for type aliases to match the correct overload. > hydra-zen (https://github.com/mit-ll-responsible-ai/hydra-zen) > + src/hydra_zen/wrapper/_implementations.py:945:16: error[invalid-return-type] Return type does not match returned value: expected `DataClass_ | type[@Todo(type[T] for protocols)] | ListConfig | DictConfig`, found `@Todo(unsupported type[X] special form) | (((...) -> Any) & dict[Unknown, Unknown]) | (DataClass_ & dict[Unknown, Unknown]) | dict[Any, Any] | (ListConfig & dict[Unknown, Unknown]) | (DictConfig & dict[Unknown, Unknown]) | (((...) -> Any) & list[Unknown]) | (DataClass_ & list[Unknown]) | list[Any] | (ListConfig & list[Unknown]) | (DictConfig & list[Unknown])` > + tests/annotations/behaviors.py:60:28: error[call-non-callable] Object of type `Path` is not callable > + tests/annotations/behaviors.py:64:21: error[call-non-callable] Object of type `Path` is not callable > + tests/annotations/declarations.py:167:17: error[call-non-callable] Object of type `Path` is not callable > + tests/annotations/declarations.py:524:17: error[unresolved-attribute] Type `` has no attribute `_target_` > - Found 561 diagnostics > + Found 566 diagnostics Same as above, this requires support for type aliases to match the correct overload. > paasta (https://github.com/yelp/paasta) > + paasta_tools/utils.py:4188:19: warning[redundant-cast] Value is already of type `list[str]` > - Found 888 diagnostics > + Found 889 diagnostics This is correct. > colour (https://github.com/colour-science/colour) > + colour/plotting/diagrams.py:448:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[@Todo(Support for `typing.TypeAlias`)]`, found `ndarray[tuple[int, int, int], dtype[Unknown]]` > + colour/plotting/diagrams.py:462:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[@Todo(Support for `typing.TypeAlias`)]`, found `ndarray[tuple[int, int, int], dtype[Unknown]]` > + colour/plotting/models.py:419:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[@Todo(Support for `typing.TypeAlias`)]`, found `ndarray[tuple[int, int, int], dtype[Unknown]]` > + colour/plotting/temperature.py:230:9: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[@Todo(Support for `typing.TypeAlias`)]`, found `ndarray[tuple[int, int, int], dtype[Unknown]]` > + colour/plotting/temperature.py:474:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[@Todo(Support for `typing.TypeAlias`)]`, found `ndarray[tuple[int, int, int], dtype[Unknown]]` > + colour/plotting/temperature.py:495:17: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[@Todo(Support for `typing.TypeAlias`)]`, found `ndarray[tuple[int, int, int], dtype[Unknown]]` > + colour/plotting/temperature.py:513:13: error[invalid-argument-type] Argument to bound method `text` is incorrect: Expected `int | float`, found `ndarray[@Todo(Support for `typing.TypeAlias`), dtype[Unknown]]` > + colour/plotting/temperature.py:514:13: error[invalid-argument-type] Argument to bound method `text` is incorrect: Expected `int | float`, found `ndarray[@Todo(Support for `typing.TypeAlias`), dtype[Unknown]]` > - Found 480 diagnostics > + Found 488 diagnostics Most of them are correct except for the last two diagnostics which I'm not sure what's happening, it's trying to index into an `np.ndarray` type (which is inferred correctly) but I think it might be picking up an incorrect overload for the `__getitem__` method. Scipy's diagnostics also requires support for type alises to pick the correct overload.

--- .../resources/mdtest/call/overloads.md | 3 +-- crates/ty_python_semantic/src/types/call/bind.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/call/overloads.md b/crates/ty_python_semantic/resources/mdtest/call/overloads.md index 8d1f2930cd..ca447b6063 100644 --- a/crates/ty_python_semantic/resources/mdtest/call/overloads.md +++ b/crates/ty_python_semantic/resources/mdtest/call/overloads.md @@ -876,8 +876,7 @@ def _(list_int: list[int], list_str: list[str], list_any: list[Any], any: Any): # TODO: revealed: A reveal_type(f(*(list_int,))) # revealed: Unknown - # TODO: Should be `str` - reveal_type(f(list_str)) # revealed: Unknown + reveal_type(f(list_str)) # revealed: str # TODO: Should be `str` reveal_type(f(*(list_str,))) # revealed: Unknown diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs index e064212225..226454e748 100644 --- a/crates/ty_python_semantic/src/types/call/bind.rs +++ b/crates/ty_python_semantic/src/types/call/bind.rs @@ -1497,9 +1497,17 @@ impl<'db> CallableBinding<'db> { } // TODO: For an unannotated `self` / `cls` parameter, the type should be // `typing.Self` / `type[typing.Self]` - let parameter_type = overload.signature.parameters()[*parameter_index] + let mut parameter_type = overload.signature.parameters()[*parameter_index] .annotated_type() .unwrap_or(Type::unknown()); + if let Some(specialization) = overload.specialization { + parameter_type = + parameter_type.apply_specialization(db, specialization); + } + if let Some(inherited_specialization) = overload.inherited_specialization { + parameter_type = + parameter_type.apply_specialization(db, inherited_specialization); + } current_parameter_types.push(parameter_type); } }