Skip to content

Commit b26580f

Browse files
better error for bad LHS in binop-assign
1 parent a5c4f4c commit b26580f

File tree

6 files changed

+47
-14
lines changed

6 files changed

+47
-14
lines changed

compiler/rustc_typeck/src/check/expr.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10581058
self.check_lhs_assignable(lhs, "E0070", span, |err| {
10591059
let rhs_ty = self.check_expr(&rhs);
10601060

1061+
// FIXME: This could be done any time lhs_ty is DerefMut into something that
1062+
// is compatible with rhs_ty, and not _just_ `&mut`
10611063
if let ty::Ref(_, lhs_inner_ty, hir::Mutability::Mut) = lhs_ty.kind() {
10621064
if self.can_coerce(rhs_ty, *lhs_inner_ty) {
10631065
err.span_suggestion_verbose(

compiler/rustc_typeck/src/check/op.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4141
return_ty
4242
};
4343

44-
self.check_lhs_assignable(lhs, "E0067", op.span, |_| {});
44+
self.check_lhs_assignable(lhs, "E0067", op.span, |err| {
45+
if let Ref(_, rty, hir::Mutability::Mut) = lhs_ty.kind() {
46+
if self
47+
.lookup_op_method(*rty, Some(rhs_ty), Some(rhs), Op::Binary(op, IsAssign::Yes))
48+
.is_ok()
49+
{
50+
// Suppress this error, since we already emitted
51+
// a deref suggestion in check_overloaded_binop
52+
err.delay_as_bug();
53+
}
54+
}
55+
});
4556

4657
ty
4758
}
@@ -404,8 +415,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
404415
(err, missing_trait, use_output)
405416
}
406417
};
407-
if let Ref(_, rty, _) = lhs_ty.kind() {
408-
if self.infcx.type_is_copy_modulo_regions(self.param_env, *rty, lhs_expr.span)
418+
if let Ref(_, rty, mutability) = lhs_ty.kind() {
419+
let is_copy =
420+
self.infcx.type_is_copy_modulo_regions(self.param_env, *rty, lhs_expr.span);
421+
// We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
422+
// `a += b` => `*a += b` if a is a mut ref.
423+
// FIXME: This could be done any time lhs_ty is DerefMut into something that
424+
// is compatible with rhs_ty, and not _just_ `&mut` (for IsAssign::Yes).
425+
if ((is_assign == IsAssign::No && is_copy)
426+
|| (is_assign == IsAssign::Yes && *mutability == hir::Mutability::Mut))
409427
&& self
410428
.lookup_op_method(
411429
*rty,

src/test/ui/issues/issue-5239-1.stderr

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@ LL | let x = |ref x: isize| { x += 1; };
55
| -^^^^^
66
| |
77
| cannot use `+=` on type `&isize`
8-
|
9-
help: `+=` can be used on `isize`, you can dereference `x`
10-
|
11-
LL | let x = |ref x: isize| { *x += 1; };
12-
| +
138

149
error: aborting due to previous error
1510

src/test/ui/typeck/assign-non-lval-mut-ref.fixed

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
fn main() {
44
let mut x = vec![1usize];
5-
*x.last_mut().unwrap() = 2usize;
5+
*x.last_mut().unwrap() = 2;
66
//~^ ERROR invalid left-hand side of assignment
7+
*x.last_mut().unwrap() += 1;
8+
//~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
79
}

src/test/ui/typeck/assign-non-lval-mut-ref.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
fn main() {
44
let mut x = vec![1usize];
5-
x.last_mut().unwrap() = 2usize;
5+
x.last_mut().unwrap() = 2;
66
//~^ ERROR invalid left-hand side of assignment
7+
x.last_mut().unwrap() += 1;
8+
//~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
79
}
Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,30 @@
11
error[E0070]: invalid left-hand side of assignment
22
--> $DIR/assign-non-lval-mut-ref.rs:5:27
33
|
4-
LL | x.last_mut().unwrap() = 2usize;
4+
LL | x.last_mut().unwrap() = 2;
55
| --------------------- ^
66
| |
77
| cannot assign to this expression
88
|
99
help: consider dereferencing here to assign to the mutable borrowed piece of memory
1010
|
11-
LL | *x.last_mut().unwrap() = 2usize;
11+
LL | *x.last_mut().unwrap() = 2;
1212
| +
1313

14-
error: aborting due to previous error
14+
error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut usize`
15+
--> $DIR/assign-non-lval-mut-ref.rs:7:5
16+
|
17+
LL | x.last_mut().unwrap() += 1;
18+
| ---------------------^^^^^
19+
| |
20+
| cannot use `+=` on type `&mut usize`
21+
|
22+
help: `+=` can be used on `usize`, you can dereference `x.last_mut().unwrap()`
23+
|
24+
LL | *x.last_mut().unwrap() += 1;
25+
| +
26+
27+
error: aborting due to 2 previous errors
1528

16-
For more information about this error, try `rustc --explain E0070`.
29+
Some errors have detailed explanations: E0070, E0368.
30+
For more information about an error, try `rustc --explain E0070`.

0 commit comments

Comments
 (0)