diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 70953483f9130..1334dfab03b43 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -817,8 +817,16 @@ impl<'db> CallOutcome<'db> { node, "call-non-callable", format_args!( - "Union element '{}' of type '{}' is not callable.", + "Object of type '{}' is not callable (due to union element '{}').", + called_ty.display(db), elem.display(db), + ), + ), + _ if not_callable.len() == outcomes.len() => builder.add_diagnostic( + node, + "call-non-callable", + format_args!( + "Object of type '{}' is not callable.", called_ty.display(db) ), ), @@ -826,9 +834,9 @@ impl<'db> CallOutcome<'db> { node, "call-non-callable", format_args!( - "Union elements {} of type '{}' are not callable.", + "Object of type '{}' is not callable (due to union elements {}).", + called_ty.display(db), not_callable.display(db), - called_ty.display(db) ), ), } diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 611c6307b13b1..c41ec34a21996 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -3486,7 +3486,7 @@ mod tests { assert_file_diagnostics( &db, "src/a.py", - &["Union element 'Literal[1]' of type 'Literal[1] | Literal[f]' is not callable."], + &["Object of type 'Literal[1] | Literal[f]' is not callable (due to union element 'Literal[1]')."], ); assert_public_ty(&db, "src/a.py", "x", "Unknown | int"); @@ -3515,7 +3515,7 @@ mod tests { &db, "src/a.py", &[ - r#"Union elements Literal[1], Literal["foo"] of type 'Literal[1] | Literal["foo"] | Literal[f]' are not callable."#, + r#"Object of type 'Literal[1] | Literal["foo"] | Literal[f]' is not callable (due to union elements Literal[1], Literal["foo"])."#, ], ); assert_public_ty(&db, "src/a.py", "x", "Unknown | int"); @@ -3523,6 +3523,31 @@ mod tests { Ok(()) } + #[test] + fn call_union_with_all_not_callable() -> anyhow::Result<()> { + let mut db = setup_db(); + + db.write_dedented( + "src/a.py", + " + if flag: + f = 1 + else: + f = 'foo' + x = f() + ", + )?; + + assert_file_diagnostics( + &db, + "src/a.py", + &[r#"Object of type 'Literal[1] | Literal["foo"]' is not callable."#], + ); + assert_public_ty(&db, "src/a.py", "x", "Unknown"); + + Ok(()) + } + #[test] fn invalid_callable() { let mut db = setup_db();