diff --git a/crates/red_knot_python_semantic/resources/mdtest/call/function.md b/crates/red_knot_python_semantic/resources/mdtest/call/function.md index b68aaf6675..dafe8a89f8 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/call/function.md +++ b/crates/red_knot_python_semantic/resources/mdtest/call/function.md @@ -169,6 +169,15 @@ def f(*args: int) -> int: reveal_type(f(1, 2, 3)) # revealed: int ``` +### Multiple keyword arguments map to keyword variadic parameter + +```py +def f(**kwargs: int) -> int: + return 1 + +reveal_type(f(foo=1, bar=2)) # revealed: int +``` + ## Missing arguments ### No defaults or variadic diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 3bec7b5e46..0e6eb9b305 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -2021,11 +2021,11 @@ impl<'db> Type<'db> { return CallOutcome::callable(binding); }; - let Some(casted_ty) = arguments.first_argument() else { - return CallOutcome::callable(binding); + if let Some(casted_ty) = arguments.first_argument() { + binding.set_return_ty(casted_ty); }; - CallOutcome::casted(binding, casted_ty) + CallOutcome::callable(binding) } _ => CallOutcome::callable(binding), @@ -3877,7 +3877,6 @@ impl<'db> Class<'db> { | CallOutcome::RevealType { binding, .. } | CallOutcome::StaticAssertionError { binding, .. } | CallOutcome::AssertType { binding, .. } => Ok(binding.return_ty()), - CallOutcome::Cast { casted_ty, .. } => Ok(casted_ty), }; return return_ty_result.map(|ty| ty.to_meta_type(db)); diff --git a/crates/red_knot_python_semantic/src/types/call.rs b/crates/red_knot_python_semantic/src/types/call.rs index b31ac891eb..c23660f76d 100644 --- a/crates/red_knot_python_semantic/src/types/call.rs +++ b/crates/red_knot_python_semantic/src/types/call.rs @@ -48,14 +48,10 @@ pub(super) enum CallOutcome<'db> { binding: CallBinding<'db>, asserted_ty: Type<'db>, }, - Cast { - binding: CallBinding<'db>, - casted_ty: Type<'db>, - }, } impl<'db> CallOutcome<'db> { - /// Create a new `CallOutcome::Callable` with given return type. + /// Create a new `CallOutcome::Callable` with given binding. pub(super) fn callable(binding: CallBinding<'db>) -> CallOutcome<'db> { CallOutcome::Callable { binding } } @@ -92,11 +88,6 @@ impl<'db> CallOutcome<'db> { } } - /// Create a new `CallOutcome::Casted` with given casted and return types. - pub(super) fn casted(binding: CallBinding<'db>, casted_ty: Type<'db>) -> CallOutcome<'db> { - CallOutcome::Cast { binding, casted_ty } - } - /// Get the return type of the call, or `None` if not callable. pub(super) fn return_ty(&self, db: &'db dyn Db) -> Option> { match self { @@ -128,10 +119,6 @@ impl<'db> CallOutcome<'db> { binding, asserted_ty: _, } => Some(binding.return_ty()), - Self::Cast { - binding: _, - casted_ty, - } => Some(*casted_ty), } } @@ -360,10 +347,6 @@ impl<'db> CallOutcome<'db> { Ok(binding.return_ty()) } - Self::Cast { - binding: _, - casted_ty, - } => Ok(*casted_ty), } } } diff --git a/crates/red_knot_python_semantic/src/types/call/bind.rs b/crates/red_knot_python_semantic/src/types/call/bind.rs index 0aec770197..f84d0d1f0f 100644 --- a/crates/red_knot_python_semantic/src/types/call/bind.rs +++ b/crates/red_knot_python_semantic/src/types/call/bind.rs @@ -84,7 +84,7 @@ pub(crate) fn bind_call<'db>( } } if let Some(existing) = parameter_tys[index].replace(*argument_ty) { - if parameter.is_variadic() { + if parameter.is_variadic() || parameter.is_keyword_variadic() { let union = UnionType::from_elements(db, [existing, *argument_ty]); parameter_tys[index].replace(union); } else {