Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/argument-suggestions/missing-comma-before-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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
t1(() | a);
//~^ ERROR no implementation for `() | ()`
//~| ERROR this function takes 2 arguments but 1 argument was supplied
}
132 changes: 132 additions & 0 deletions tests/ui/argument-suggestions/missing-comma-before-closure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
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: add a comma
|
LL | t1((), |c| c);
| +
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: add a comma
|
LL | t1((()), |c| c);
| +
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: add a comma
|
LL | t1((), |a| c);
| +
help: provide the argument
|
LL | t1(() |a| c, /* _ */);
| +++++++++

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`.
Loading