Skip to content

Commit fb61292

Browse files
committed
Auto merge of rust-lang#117292 - estebank:issue-80446, r=davidtwco
Detect misparsed binop caused by missing semi When encountering ```rust foo() *bar = baz; ``` We currently emit potentially two errors, one for the return type of `foo` not being multiplicative by the type of `bar`, and another for `foo() * bar` not being assignable. We now check for this case and suggest adding a semicolon in the right place and emit only a single error. Fix rust-lang#80446.
2 parents aea82b2 + 4b7aaca commit fb61292

File tree

5 files changed

+71
-0
lines changed

5 files changed

+71
-0
lines changed

compiler/rustc_hir_typeck/src/expr.rs

+27
Original file line numberDiff line numberDiff line change
@@ -959,12 +959,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
959959
Applicability::MachineApplicable,
960960
);
961961
});
962+
self.check_for_missing_semi(lhs, &mut err);
962963

963964
adjust_err(&mut err);
964965

965966
err.emit();
966967
}
967968

969+
/// Check if the expression that could not be assigned to was a typoed expression that
970+
pub fn check_for_missing_semi(
971+
&self,
972+
expr: &'tcx hir::Expr<'tcx>,
973+
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
974+
) -> bool {
975+
if let hir::ExprKind::Binary(binop, lhs, rhs) = expr.kind
976+
&& let hir::BinOpKind::Mul = binop.node
977+
&& self.tcx.sess.source_map().is_multiline(lhs.span.between(rhs.span))
978+
&& rhs.is_syntactic_place_expr()
979+
{
980+
// v missing semicolon here
981+
// foo()
982+
// *bar = baz;
983+
// (#80446).
984+
err.span_suggestion_verbose(
985+
lhs.span.shrink_to_hi(),
986+
"you might have meant to write a semicolon here",
987+
";".to_string(),
988+
Applicability::MachineApplicable,
989+
);
990+
return true;
991+
}
992+
false
993+
}
994+
968995
// Check if an expression `original_expr_id` comes from the condition of a while loop,
969996
/// as opposed from the body of a while loop, which we can naively check by iterating
970997
/// parents until we find a loop...

compiler/rustc_hir_typeck/src/op.rs

+7
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
379379
(err, output_def_id)
380380
}
381381
};
382+
if self.check_for_missing_semi(expr, &mut err)
383+
&& let hir::Node::Expr(expr) = self.tcx.hir().get_parent(expr.hir_id)
384+
&& let hir::ExprKind::Assign(..) = expr.kind
385+
{
386+
// We defer to the later error produced by `check_lhs_assignable`.
387+
err.delay_as_bug();
388+
}
382389

383390
let suggest_deref_binop =
384391
|err: &mut DiagnosticBuilder<'_, _>, lhs_deref_ty: Ty<'tcx>| {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// run-rustfix
2+
fn foo() {}
3+
fn main() {
4+
let mut y = 42;
5+
let x = &mut y;
6+
foo();
7+
*x = 0; //~ ERROR invalid left-hand side of assignment
8+
let _ = x;
9+
println!("{y}");
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// run-rustfix
2+
fn foo() {}
3+
fn main() {
4+
let mut y = 42;
5+
let x = &mut y;
6+
foo()
7+
*x = 0; //~ ERROR invalid left-hand side of assignment
8+
let _ = x;
9+
println!("{y}");
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0070]: invalid left-hand side of assignment
2+
--> $DIR/false-binop-caused-by-missing-semi.rs:7:8
3+
|
4+
LL | / foo()
5+
LL | | *x = 0;
6+
| | - ^
7+
| |______|
8+
| cannot assign to this expression
9+
|
10+
help: you might have meant to write a semicolon here
11+
|
12+
LL | foo();
13+
| +
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0070`.

0 commit comments

Comments
 (0)