[ty] Fix panic when trying to pull types for subscript expressions inside Callable type expressions (#18534)

This commit is contained in:
Alex Waygood 2025-06-09 11:26:10 +01:00 committed by GitHub
parent 475a02b725
commit aa3c312f5f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 61 additions and 17 deletions

View file

@ -252,6 +252,31 @@ def _(c: Callable[[Concatenate[int, str, ...], int], int]):
reveal_type(c) # revealed: (...) -> int
```
Other type expressions can be nested inside `Concatenate`:
```py
def _(c: Callable[[Concatenate[int | str, type[str], ...], int], int]):
# TODO: Should reveal the correct signature
reveal_type(c) # revealed: (...) -> int
```
But providing fewer than 2 arguments to `Concatenate` is an error:
```py
# fmt: off
def _(
c: Callable[Concatenate[int], int], # error: [invalid-type-form] "Special form `typing.Concatenate` expected at least 2 parameters but got 1"
d: Callable[Concatenate[(int,)], int], # error: [invalid-type-form] "Special form `typing.Concatenate` expected at least 2 parameters but got 1"
e: Callable[Concatenate[()], int] # error: [invalid-type-form] "Special form `typing.Concatenate` expected at least 2 parameters but got 0"
):
reveal_type(c) # revealed: (...) -> int
reveal_type(d) # revealed: (...) -> int
reveal_type(e) # revealed: (...) -> int
# fmt: on
```
## Using `typing.ParamSpec`
```toml

View file

@ -9441,8 +9441,29 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
todo_type!("`TypeGuard[]` special form")
}
SpecialFormType::Concatenate => {
self.infer_type_expression(arguments_slice);
todo_type!("`Concatenate[]` special form")
let arguments = if let ast::Expr::Tuple(tuple) = arguments_slice {
&*tuple.elts
} else {
std::slice::from_ref(arguments_slice)
};
for argument in arguments {
self.infer_type_expression(argument);
}
let num_arguments = arguments.len();
let inferred_type = if num_arguments < 2 {
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
"Special form `{special_form}` expected at least 2 parameters but got {num_arguments}",
));
}
Type::unknown()
} else {
todo_type!("`Concatenate[]` special form")
};
if arguments_slice.is_tuple_expr() {
self.store_expression_type(arguments_slice, inferred_type);
}
inferred_type
}
SpecialFormType::Unpack => {
self.infer_type_expression(arguments_slice);
@ -9622,7 +9643,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}))
});
}
ast::Expr::Subscript(_) => {
ast::Expr::Subscript(subscript) => {
let value_ty = self.infer_expression(&subscript.value);
self.infer_subscript_type_expression(subscript, value_ty);
// TODO: Support `Concatenate[...]`
return Some(Parameters::todo());
}