diff --git a/crates/ty_python_semantic/resources/mdtest/type_properties/is_subtype_of.md b/crates/ty_python_semantic/resources/mdtest/type_properties/is_subtype_of.md index f7cd8704391328..70e4d2e57a105f 100644 --- a/crates/ty_python_semantic/resources/mdtest/type_properties/is_subtype_of.md +++ b/crates/ty_python_semantic/resources/mdtest/type_properties/is_subtype_of.md @@ -1313,7 +1313,7 @@ Variadic parameter in a subtype can only be used to match against an unmatched p parameters from the supertype, not any other parameter kind. ```py -from ty_extensions import CallableTypeOf, is_subtype_of, static_assert +from ty_extensions import CallableTypeOf, is_subtype_of, is_assignable_to, static_assert def variadic(*args: int) -> None: ... @@ -1376,6 +1376,16 @@ static_assert(is_subtype_of(CallableTypeOf[variadic_a], CallableTypeOf[standard_ static_assert(not is_subtype_of(CallableTypeOf[variadic_b], CallableTypeOf[standard_int])) ``` +A variadic positional parameter alone cannot match a positional-or-keyword parameter because +variadic positional parameters can only be called positionally. + +```py +def only_variadic(*args: int) -> None: ... + +static_assert(not is_subtype_of(CallableTypeOf[only_variadic], CallableTypeOf[standard_int])) +static_assert(not is_assignable_to(CallableTypeOf[only_variadic], CallableTypeOf[standard_int])) +``` + #### Keyword-only For keyword-only parameters, the name should be the same: diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index cac7f1caf92421..4ba5644671e267 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -1404,9 +1404,15 @@ impl<'db> Signature<'db> { loop { let Some(next_parameter) = parameters.next() else { - // All parameters have been checked or both the parameter lists were empty. In - // either case, `self` is a subtype of `other`. - return result; + if other_keywords.is_empty() { + // All parameters have been checked or both the parameter lists were empty. + // In either case, `self` is a subtype of `other`. + return result; + } + // There are keyword parameters in `other` that were only matched positionally + // against a variadic parameter in `self`. We need to verify that they can also + // be matched as keyword arguments, which is done after this loop. + break; }; match next_parameter {