[ty] Avoid showing misleading hint for unpacked tuple arguments (#22286)

## Summary

We could implement support for showing multiple argument names, though
this seems to match PyCharm.

Closes https://github.com/astral-sh/ty/issues/2250.
This commit is contained in:
Charlie Marsh
2025-12-29 13:25:08 -05:00
committed by GitHub
parent ebc1323ccb
commit 3d8ae2e476
2 changed files with 110 additions and 0 deletions

View File

@@ -4465,6 +4465,110 @@ mod tests {
");
}
#[test]
fn test_function_call_with_unpacked_tuple_argument() {
// When an unpacked tuple fills multiple parameters, no hint should be shown
// for that argument because showing a single parameter name would be misleading.
let mut test = inlay_hint_test(
"
def foo(a: str, b: int, c: int, d: str): ...
t: tuple[int, int] = (23, 42)
foo('foo', *t, d='bar')",
);
// `*t` fills both `b` and `c`, so no hint is shown for it
assert_snapshot!(test.inlay_hints(), @r"
def foo(a: str, b: int, c: int, d: str): ...
t: tuple[int, int] = (23, 42)
foo([a=]'foo', *t, d='bar')
---------------------------------------------
info[inlay-hint-location]: Inlay Hint Target
--> main.py:2:9
|
2 | def foo(a: str, b: int, c: int, d: str): ...
| ^
3 | t: tuple[int, int] = (23, 42)
4 | foo('foo', *t, d='bar')
|
info: Source
--> main2.py:4:6
|
2 | def foo(a: str, b: int, c: int, d: str): ...
3 | t: tuple[int, int] = (23, 42)
4 | foo([a=]'foo', *t, d='bar')
| ^
|
");
}
#[test]
fn test_function_call_with_unpacked_tuple_argument_single_element() {
// When an unpacked tuple fills only one parameter, a hint should be shown.
let mut test = inlay_hint_test(
"
def foo(a: str, b: int, c: str): ...
t: tuple[int] = (42,)
foo('foo', *t, 'bar')",
);
assert_snapshot!(test.inlay_hints(), @r"
def foo(a: str, b: int, c: str): ...
t: tuple[int] = (42,)
foo([a=]'foo', [b=]*t, [c=]'bar')
---------------------------------------------
info[inlay-hint-location]: Inlay Hint Target
--> main.py:2:9
|
2 | def foo(a: str, b: int, c: str): ...
| ^
3 | t: tuple[int] = (42,)
4 | foo('foo', *t, 'bar')
|
info: Source
--> main2.py:4:6
|
2 | def foo(a: str, b: int, c: str): ...
3 | t: tuple[int] = (42,)
4 | foo([a=]'foo', [b=]*t, [c=]'bar')
| ^
|
info[inlay-hint-location]: Inlay Hint Target
--> main.py:2:17
|
2 | def foo(a: str, b: int, c: str): ...
| ^
3 | t: tuple[int] = (42,)
4 | foo('foo', *t, 'bar')
|
info: Source
--> main2.py:4:17
|
2 | def foo(a: str, b: int, c: str): ...
3 | t: tuple[int] = (42,)
4 | foo([a=]'foo', [b=]*t, [c=]'bar')
| ^
|
info[inlay-hint-location]: Inlay Hint Target
--> main.py:2:25
|
2 | def foo(a: str, b: int, c: str): ...
| ^
3 | t: tuple[int] = (42,)
4 | foo('foo', *t, 'bar')
|
info: Source
--> main2.py:4:25
|
2 | def foo(a: str, b: int, c: str): ...
3 | t: tuple[int] = (42,)
4 | foo([a=]'foo', [b=]*t, [c=]'bar')
| ^
|
");
}
#[test]
fn test_function_call_positional_only_and_positional_or_keyword_parameters() {
let mut test = inlay_hint_test(

View File

@@ -788,6 +788,12 @@ pub fn inlay_hint_call_argument_details<'db>(
continue;
}
// Skip if this argument maps to multiple parameters (e.g., unpacked tuple filling
// multiple slots). Showing a single parameter name would be misleading.
if arg_mapping.parameters.len() > 1 {
continue;
}
let Some(param_index) = arg_mapping.parameters.first() else {
continue;
};