diff --git a/crates/red_knot_python_semantic/resources/mdtest/call/union.md b/crates/red_knot_python_semantic/resources/mdtest/call/union.md index 086bfa8447da3..d2ae8875a88cf 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/call/union.md +++ b/crates/red_knot_python_semantic/resources/mdtest/call/union.md @@ -56,6 +56,7 @@ def _(flag: bool, flag2: bool): else: def f() -> int: return 1 + # TODO we should mention all non-callable elements of the union # error: [call-non-callable] "Object of type `Literal[1]` is not callable" # revealed: int | Unknown reveal_type(f()) @@ -108,3 +109,38 @@ def _(flag: bool): x = f(3) reveal_type(x) # revealed: Unknown ``` + +## Union of binding errors + +```py +def f1(): ... +def f2(): ... +def _(flag: bool): + if flag: + f = f1 + else: + f = f2 + + # TODO: we should show all errors from the union, not arbitrarily pick one union element + # error: [too-many-positional-arguments] "Too many positional arguments to function `f1`: expected 0, got 1" + x = f(3) + reveal_type(x) # revealed: Unknown +``` + +## One not-callable, one wrong argument + +```py +class C: ... + +def f1(): ... +def _(flag: bool): + if flag: + f = f1 + else: + f = C() + + # TODO: we should either show all union errors here, or prioritize the not-callable error + # error: [too-many-positional-arguments] "Too many positional arguments to function `f1`: expected 0, got 1" + x = f(3) + reveal_type(x) # revealed: Unknown +``` diff --git a/crates/red_knot_python_semantic/src/types/call.rs b/crates/red_knot_python_semantic/src/types/call.rs index e108a6656ae32..0fd81de9f4975 100644 --- a/crates/red_knot_python_semantic/src/types/call.rs +++ b/crates/red_knot_python_semantic/src/types/call.rs @@ -35,7 +35,7 @@ impl<'db> CallOutcome<'db> { let elements = union.elements(db); let mut bindings = Vec::with_capacity(elements.len()); let mut errors = Vec::new(); - let mut not_callable = true; + let mut all_errors_not_callable = true; for element in elements { match call(*element) { @@ -44,7 +44,7 @@ impl<'db> CallOutcome<'db> { bindings.extend(inner_bindings); } Err(error) => { - not_callable |= error.is_not_callable(); + all_errors_not_callable &= error.is_not_callable(); errors.push(error); } } @@ -52,7 +52,7 @@ impl<'db> CallOutcome<'db> { if errors.is_empty() { Ok(CallOutcome::Union(bindings.into())) - } else if bindings.is_empty() && not_callable { + } else if bindings.is_empty() && all_errors_not_callable { Err(CallError::NotCallable { not_callable_type: Type::Union(union), })