From 77d36822e00f0a5529ea1d2ea18ec12e795de05f Mon Sep 17 00:00:00 2001 From: Raushan singh Date: Thu, 5 Nov 2026 05:27:03 +0000 Subject: [PATCH 1/2] test(typeck): capture current behavior for missing comma before closure in call args --- .../missing-comma-before-closure.rs | 17 ++++ .../missing-comma-before-closure.stderr | 96 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 tests/ui/argument-suggestions/missing-comma-before-closure.rs create mode 100644 tests/ui/argument-suggestions/missing-comma-before-closure.stderr diff --git a/tests/ui/argument-suggestions/missing-comma-before-closure.rs b/tests/ui/argument-suggestions/missing-comma-before-closure.rs new file mode 100644 index 0000000000000..38c9d0b5cbc98 --- /dev/null +++ b/tests/ui/argument-suggestions/missing-comma-before-closure.rs @@ -0,0 +1,17 @@ +fn t1(_: (), _: impl Fn(bool) -> bool) {} + +fn main() { + t1(() |c| c); + //~^ ERROR cannot find value `c` in this scope + //~| ERROR cannot find value `c` in this scope + //~| ERROR this function takes 2 arguments but 1 argument was supplied + t1((()) |c| c); + //~^ ERROR cannot find value `c` in this scope + //~| ERROR cannot find value `c` in this scope + //~| ERROR this function takes 2 arguments but 1 argument was supplied + let a = (); + t1(() |a| c); + //~^ ERROR no implementation for `() | ()` + //~| ERROR cannot find value `c` in this scope + //~| ERROR this function takes 2 arguments but 1 argument was supplied +} diff --git a/tests/ui/argument-suggestions/missing-comma-before-closure.stderr b/tests/ui/argument-suggestions/missing-comma-before-closure.stderr new file mode 100644 index 0000000000000..d76130121ac87 --- /dev/null +++ b/tests/ui/argument-suggestions/missing-comma-before-closure.stderr @@ -0,0 +1,96 @@ +error[E0425]: cannot find value `c` in this scope + --> $DIR/missing-comma-before-closure.rs:4:12 + | +LL | t1(() |c| c); + | ^ not found in this scope + +error[E0425]: cannot find value `c` in this scope + --> $DIR/missing-comma-before-closure.rs:4:15 + | +LL | t1(() |c| c); + | ^ not found in this scope + +error[E0425]: cannot find value `c` in this scope + --> $DIR/missing-comma-before-closure.rs:8:14 + | +LL | t1((()) |c| c); + | ^ not found in this scope + +error[E0425]: cannot find value `c` in this scope + --> $DIR/missing-comma-before-closure.rs:8:17 + | +LL | t1((()) |c| c); + | ^ not found in this scope + +error[E0425]: cannot find value `c` in this scope + --> $DIR/missing-comma-before-closure.rs:13:15 + | +LL | t1(() |a| c); + | ^ not found in this scope + | +help: a local variable with a similar name exists + | +LL - t1(() |a| c); +LL + t1(() |a| a); + | + +error[E0061]: this function takes 2 arguments but 1 argument was supplied + --> $DIR/missing-comma-before-closure.rs:4:5 + | +LL | t1(() |c| c); + | ^^---------- argument #2 is missing + | +note: function defined here + --> $DIR/missing-comma-before-closure.rs:1:4 + | +LL | fn t1(_: (), _: impl Fn(bool) -> bool) {} + | ^^ ------------------------ +help: provide the argument + | +LL | t1(() |c| c, /* _ */); + | +++++++++ + +error[E0061]: this function takes 2 arguments but 1 argument was supplied + --> $DIR/missing-comma-before-closure.rs:8:5 + | +LL | t1((()) |c| c); + | ^^------------ argument #2 is missing + | +note: function defined here + --> $DIR/missing-comma-before-closure.rs:1:4 + | +LL | fn t1(_: (), _: impl Fn(bool) -> bool) {} + | ^^ ------------------------ +help: provide the argument + | +LL | t1((()) |c| c, /* _ */); + | +++++++++ + +error[E0369]: no implementation for `() | ()` + --> $DIR/missing-comma-before-closure.rs:13:11 + | +LL | t1(() |a| c); + | -- ^- () + | | + | () + +error[E0061]: this function takes 2 arguments but 1 argument was supplied + --> $DIR/missing-comma-before-closure.rs:13:5 + | +LL | t1(() |a| c); + | ^^---------- argument #2 is missing + | +note: function defined here + --> $DIR/missing-comma-before-closure.rs:1:4 + | +LL | fn t1(_: (), _: impl Fn(bool) -> bool) {} + | ^^ ------------------------ +help: provide the argument + | +LL | t1(() |a| c, /* _ */); + | +++++++++ + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0061, E0369, E0425. +For more information about an error, try `rustc --explain E0061`. From 4aa7bd83ef89216dc9bed897e56b8d3ce251a749 Mon Sep 17 00:00:00 2001 From: Raushan singh Date: Thu, 5 Nov 2026 08:16:02 +0000 Subject: [PATCH 2/2] fix(typeck): suggest adding a comma when `()` followed by a closure is parsed as bitor --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 33 ++++++++++++++++ .../missing-comma-before-closure.rs | 3 ++ .../missing-comma-before-closure.stderr | 38 ++++++++++++++++++- 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 3183f4101fdd3..3ae24d038e496 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -925,6 +925,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = fn_call_diag_ctxt.initial_final_diagnostic(); fn_call_diag_ctxt.suggest_confusable(&mut err); fn_call_diag_ctxt.detect_missing_turbofish(&mut err); + fn_call_diag_ctxt.suggest_missing_comma_before_closure(&mut err); // As we encounter issues, keep track of what we want to provide for the suggestion. @@ -3315,6 +3316,38 @@ impl<'a, 'tcx> ArgMatchingCtxt<'a, 'tcx> { } } + fn suggest_missing_comma_before_closure(&self, err: &mut Diag<'_>) { + if self.formal_and_expected_inputs.len() <= self.provided_args.len() { + return; + } + + for &arg in &self.provided_args { + let mut curr = arg; + let mut bitor_count = 0; + while let hir::ExprKind::Binary(op, lhs, _) = curr.kind + && op.node == hir::BinOpKind::BitOr + { + bitor_count += 1; + curr = lhs; + } + + // `t(() |c| c)` is greedily parsed as `((() | c) | c)`. Unit cannot BitOr, + // and closure params need two `|` delimiters. + if bitor_count >= 2 + && matches!(curr.kind, hir::ExprKind::Tup([])) + && curr.span.can_be_used_for_suggestions() + { + err.span_suggestion_verbose( + curr.span.shrink_to_hi(), + "add a comma", + ",", + Applicability::MaybeIncorrect, + ); + break; + } + } + } + /// A "softer" version of the `demand_compatible`, which checks types without persisting them, /// and treats error types differently /// This will allow us to "probe" for other argument orders that would likely have been correct diff --git a/tests/ui/argument-suggestions/missing-comma-before-closure.rs b/tests/ui/argument-suggestions/missing-comma-before-closure.rs index 38c9d0b5cbc98..6b01b41fbcbc7 100644 --- a/tests/ui/argument-suggestions/missing-comma-before-closure.rs +++ b/tests/ui/argument-suggestions/missing-comma-before-closure.rs @@ -14,4 +14,7 @@ fn main() { //~^ ERROR no implementation for `() | ()` //~| ERROR cannot find value `c` in this scope //~| ERROR this function takes 2 arguments but 1 argument was supplied + t1(() | a); + //~^ ERROR no implementation for `() | ()` + //~| ERROR this function takes 2 arguments but 1 argument was supplied } diff --git a/tests/ui/argument-suggestions/missing-comma-before-closure.stderr b/tests/ui/argument-suggestions/missing-comma-before-closure.stderr index d76130121ac87..20d447b0a73bf 100644 --- a/tests/ui/argument-suggestions/missing-comma-before-closure.stderr +++ b/tests/ui/argument-suggestions/missing-comma-before-closure.stderr @@ -45,6 +45,10 @@ note: function defined here | LL | fn t1(_: (), _: impl Fn(bool) -> bool) {} | ^^ ------------------------ +help: add a comma + | +LL | t1((), |c| c); + | + help: provide the argument | LL | t1(() |c| c, /* _ */); @@ -61,6 +65,10 @@ note: function defined here | LL | fn t1(_: (), _: impl Fn(bool) -> bool) {} | ^^ ------------------------ +help: add a comma + | +LL | t1((()), |c| c); + | + help: provide the argument | LL | t1((()) |c| c, /* _ */); @@ -85,12 +93,40 @@ note: function defined here | LL | fn t1(_: (), _: impl Fn(bool) -> bool) {} | ^^ ------------------------ +help: add a comma + | +LL | t1((), |a| c); + | + help: provide the argument | LL | t1(() |a| c, /* _ */); | +++++++++ -error: aborting due to 9 previous errors +error[E0369]: no implementation for `() | ()` + --> $DIR/missing-comma-before-closure.rs:17:11 + | +LL | t1(() | a); + | -- ^ - () + | | + | () + +error[E0061]: this function takes 2 arguments but 1 argument was supplied + --> $DIR/missing-comma-before-closure.rs:17:5 + | +LL | t1(() | a); + | ^^-------- argument #2 is missing + | +note: function defined here + --> $DIR/missing-comma-before-closure.rs:1:4 + | +LL | fn t1(_: (), _: impl Fn(bool) -> bool) {} + | ^^ ------------------------ +help: provide the argument + | +LL | t1(() | a, /* _ */); + | +++++++++ + +error: aborting due to 11 previous errors Some errors have detailed explanations: E0061, E0369, E0425. For more information about an error, try `rustc --explain E0061`.