mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-28 02:39:59 +00:00
[ty] Support single-starred argument for overload call (#20223)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
## Summary closes: https://github.com/astral-sh/ty/issues/247 This PR adds support for variadic arguments to overload call evaluation. This basically boils down to making sure that the overloads are not filtered out incorrectly during the step 5 in the overload call evaluation algorithm. For context, the step 5 tries to filter out the remaining overloads after finding an overload where the materialization of argument types are assignable to the parameter types. The issue with the previous implementation was that it wouldn't unpack the variadic argument and wouldn't consider the many-to-one (multiple arguments mapping to a single variadic parameter) correctly. This PR fixes that. ## Test Plan Update existing test cases and resolve the TODOs.
This commit is contained in:
parent
0639da2552
commit
4e94b22815
2 changed files with 99 additions and 71 deletions
|
|
@ -139,8 +139,7 @@ reveal_type(f(A())) # revealed: A
|
|||
reveal_type(f(*(A(),))) # revealed: A
|
||||
|
||||
reveal_type(f(B())) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(B(),))) # revealed: Unknown
|
||||
reveal_type(f(*(B(),))) # revealed: A
|
||||
|
||||
# But, in this case, the arity check filters out the first overload, so we only have one match:
|
||||
reveal_type(f(B(), 1)) # revealed: B
|
||||
|
|
@ -551,16 +550,13 @@ from overloaded import MyEnumSubclass, ActualEnum, f
|
|||
|
||||
def _(actual_enum: ActualEnum, my_enum_instance: MyEnumSubclass):
|
||||
reveal_type(f(actual_enum)) # revealed: Both
|
||||
# TODO: revealed: Both
|
||||
reveal_type(f(*(actual_enum,))) # revealed: Unknown
|
||||
reveal_type(f(*(actual_enum,))) # revealed: Both
|
||||
|
||||
reveal_type(f(ActualEnum.A)) # revealed: OnlyA
|
||||
# TODO: revealed: OnlyA
|
||||
reveal_type(f(*(ActualEnum.A,))) # revealed: Unknown
|
||||
reveal_type(f(*(ActualEnum.A,))) # revealed: OnlyA
|
||||
|
||||
reveal_type(f(ActualEnum.B)) # revealed: OnlyB
|
||||
# TODO: revealed: OnlyB
|
||||
reveal_type(f(*(ActualEnum.B,))) # revealed: Unknown
|
||||
reveal_type(f(*(ActualEnum.B,))) # revealed: OnlyB
|
||||
|
||||
reveal_type(f(my_enum_instance)) # revealed: MyEnumSubclass
|
||||
reveal_type(f(*(my_enum_instance,))) # revealed: MyEnumSubclass
|
||||
|
|
@ -1097,12 +1093,10 @@ reveal_type(f(*(1,))) # revealed: str
|
|||
|
||||
def _(list_int: list[int], list_any: list[Any]):
|
||||
reveal_type(f(list_int)) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*(list_int,))) # revealed: Unknown
|
||||
reveal_type(f(*(list_int,))) # revealed: int
|
||||
|
||||
reveal_type(f(list_any)) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*(list_any,))) # revealed: Unknown
|
||||
reveal_type(f(*(list_any,))) # revealed: int
|
||||
```
|
||||
|
||||
### Single list argument (ambiguous)
|
||||
|
|
@ -1136,8 +1130,7 @@ def _(list_int: list[int], list_any: list[Any]):
|
|||
# All materializations of `list[int]` are assignable to `list[int]`, so it matches the first
|
||||
# overload.
|
||||
reveal_type(f(list_int)) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*(list_int,))) # revealed: Unknown
|
||||
reveal_type(f(*(list_int,))) # revealed: int
|
||||
|
||||
# All materializations of `list[Any]` are assignable to `list[int]` and `list[Any]`, but the
|
||||
# return type of first and second overloads are not equivalent, so the overload matching
|
||||
|
|
@ -1170,25 +1163,21 @@ reveal_type(f("a")) # revealed: str
|
|||
reveal_type(f(*("a",))) # revealed: str
|
||||
|
||||
reveal_type(f((1, "b"))) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*((1, "b"),))) # revealed: Unknown
|
||||
reveal_type(f(*((1, "b"),))) # revealed: int
|
||||
|
||||
reveal_type(f((1, 2))) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*((1, 2),))) # revealed: Unknown
|
||||
reveal_type(f(*((1, 2),))) # revealed: int
|
||||
|
||||
def _(int_str: tuple[int, str], int_any: tuple[int, Any], any_any: tuple[Any, Any]):
|
||||
# All materializations are assignable to first overload, so second and third overloads are
|
||||
# eliminated
|
||||
reveal_type(f(int_str)) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*(int_str,))) # revealed: Unknown
|
||||
reveal_type(f(*(int_str,))) # revealed: int
|
||||
|
||||
# All materializations are assignable to second overload, so the third overload is eliminated;
|
||||
# the return type of first and second overload is equivalent
|
||||
reveal_type(f(int_any)) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*(int_any,))) # revealed: Unknown
|
||||
reveal_type(f(*(int_any,))) # revealed: int
|
||||
|
||||
# All materializations of `tuple[Any, Any]` are assignable to the parameters of all the
|
||||
# overloads, but the return types aren't equivalent, so the overload matching is ambiguous
|
||||
|
|
@ -1266,26 +1255,22 @@ def _(list_int: list[int], list_any: list[Any], int_str: tuple[int, str], int_an
|
|||
# All materializations of both argument types are assignable to the first overload, so the
|
||||
# second and third overloads are filtered out
|
||||
reveal_type(f(list_int, int_str)) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(list_int, int_str))) # revealed: Unknown
|
||||
reveal_type(f(*(list_int, int_str))) # revealed: A
|
||||
|
||||
# All materialization of first argument is assignable to first overload and for the second
|
||||
# argument, they're assignable to the second overload, so the third overload is filtered out
|
||||
reveal_type(f(list_int, int_any)) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(list_int, int_any))) # revealed: Unknown
|
||||
reveal_type(f(*(list_int, int_any))) # revealed: A
|
||||
|
||||
# All materialization of first argument is assignable to second overload and for the second
|
||||
# argument, they're assignable to the first overload, so the third overload is filtered out
|
||||
reveal_type(f(list_any, int_str)) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(list_any, int_str))) # revealed: Unknown
|
||||
reveal_type(f(*(list_any, int_str))) # revealed: A
|
||||
|
||||
# All materializations of both arguments are assignable to the second overload, so the third
|
||||
# overload is filtered out
|
||||
reveal_type(f(list_any, int_any)) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(list_any, int_any))) # revealed: Unknown
|
||||
reveal_type(f(*(list_any, int_any))) # revealed: A
|
||||
|
||||
# All materializations of first argument is assignable to the second overload and for the second
|
||||
# argument, they're assignable to the third overload, so no overloads are filtered out; the
|
||||
|
|
@ -1316,8 +1301,7 @@ from overloaded import f
|
|||
|
||||
def _(literal: LiteralString, string: str, any: Any):
|
||||
reveal_type(f(literal)) # revealed: LiteralString
|
||||
# TODO: revealed: LiteralString
|
||||
reveal_type(f(*(literal,))) # revealed: Unknown
|
||||
reveal_type(f(*(literal,))) # revealed: LiteralString
|
||||
|
||||
reveal_type(f(string)) # revealed: str
|
||||
reveal_type(f(*(string,))) # revealed: str
|
||||
|
|
@ -1355,12 +1339,10 @@ from overloaded import f
|
|||
|
||||
def _(list_int: list[int], list_str: list[str], list_any: list[Any], any: Any):
|
||||
reveal_type(f(list_int)) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(list_int,))) # revealed: Unknown
|
||||
reveal_type(f(*(list_int,))) # revealed: A
|
||||
|
||||
reveal_type(f(list_str)) # revealed: str
|
||||
# TODO: Should be `str`
|
||||
reveal_type(f(*(list_str,))) # revealed: Unknown
|
||||
reveal_type(f(*(list_str,))) # revealed: str
|
||||
|
||||
reveal_type(f(list_any)) # revealed: Unknown
|
||||
reveal_type(f(*(list_any,))) # revealed: Unknown
|
||||
|
|
@ -1561,12 +1543,10 @@ def _(any: Any):
|
|||
reveal_type(f(*(any,), flag=False)) # revealed: str
|
||||
|
||||
def _(args: tuple[Any, Literal[True]]):
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*args)) # revealed: Unknown
|
||||
reveal_type(f(*args)) # revealed: int
|
||||
|
||||
def _(args: tuple[Any, Literal[False]]):
|
||||
# TODO: revealed: str
|
||||
reveal_type(f(*args)) # revealed: Unknown
|
||||
reveal_type(f(*args)) # revealed: str
|
||||
```
|
||||
|
||||
### Argument type expansion
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue