Skip to content

Commit 382f748

Browse files
committed
Auto merge of #85100 - HKalbasi:issue-68049-fix, r=Aaron1011
Fix invalid suggestion of changing impl trait signature Fix #68049
2 parents fe62c6e + 1f20966 commit 382f748

File tree

5 files changed

+149
-10
lines changed

5 files changed

+149
-10
lines changed

compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs

+82-10
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
66
use rustc_middle::ty::{self, Ty, TyCtxt};
77
use rustc_middle::{
88
hir::place::PlaceBase,
9-
mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location},
9+
mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
1010
};
1111
use rustc_span::source_map::DesugaringKind;
1212
use rustc_span::symbol::{kw, Symbol};
@@ -424,15 +424,28 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
424424

425425
match label {
426426
Some((true, err_help_span, suggested_code)) => {
427-
err.span_suggestion(
428-
err_help_span,
429-
&format!(
430-
"consider changing this to be a mutable {}",
431-
pointer_desc
432-
),
433-
suggested_code,
434-
Applicability::MachineApplicable,
435-
);
427+
let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
428+
if !is_trait_sig {
429+
err.span_suggestion(
430+
err_help_span,
431+
&format!(
432+
"consider changing this to be a mutable {}",
433+
pointer_desc
434+
),
435+
suggested_code,
436+
Applicability::MachineApplicable,
437+
);
438+
} else if let Some(x) = local_trait {
439+
err.span_suggestion(
440+
x,
441+
&format!(
442+
"consider changing that to be a mutable {}",
443+
pointer_desc
444+
),
445+
suggested_code,
446+
Applicability::MachineApplicable,
447+
);
448+
}
436449
}
437450
Some((false, err_label_span, message)) => {
438451
err.span_label(err_label_span, &message);
@@ -503,6 +516,65 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
503516
err.buffer(&mut self.errors_buffer);
504517
}
505518

519+
/// User cannot make signature of a trait mutable without changing the
520+
/// trait. So we find if this error belongs to a trait and if so we move
521+
/// suggestion to the trait or disable it if it is out of scope of this crate
522+
fn is_error_in_trait(&self, local: Local) -> (bool, Option<Span>) {
523+
if self.body.local_kind(local) != LocalKind::Arg {
524+
return (false, None);
525+
}
526+
let hir_map = self.infcx.tcx.hir();
527+
let my_def = self.body.source.def_id();
528+
let my_hir = hir_map.local_def_id_to_hir_id(my_def.as_local().unwrap());
529+
let td = if let Some(a) =
530+
self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
531+
{
532+
a
533+
} else {
534+
return (false, None);
535+
};
536+
(
537+
true,
538+
td.as_local().and_then(|tld| {
539+
let h = hir_map.local_def_id_to_hir_id(tld);
540+
match hir_map.find(h) {
541+
Some(Node::Item(hir::Item {
542+
kind: hir::ItemKind::Trait(_, _, _, _, items),
543+
..
544+
})) => {
545+
let mut f_in_trait_opt = None;
546+
for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
547+
let hi = fi.hir_id();
548+
if !matches!(k, hir::AssocItemKind::Fn { .. }) {
549+
continue;
550+
}
551+
if hir_map.name(hi) != hir_map.name(my_hir) {
552+
continue;
553+
}
554+
f_in_trait_opt = Some(hi);
555+
break;
556+
}
557+
f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) {
558+
Some(Node::TraitItem(hir::TraitItem {
559+
kind:
560+
hir::TraitItemKind::Fn(
561+
hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
562+
_,
563+
),
564+
..
565+
})) => {
566+
let hir::Ty { span, .. } = inputs[local.index() - 1];
567+
Some(span)
568+
}
569+
_ => None,
570+
})
571+
}
572+
_ => None,
573+
}
574+
}),
575+
)
576+
}
577+
506578
// point to span of upvar making closure call require mutable borrow
507579
fn show_mutating_upvar(
508580
&self,
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use std::alloc::{GlobalAlloc, Layout};
2+
3+
struct Test(u32);
4+
5+
unsafe impl GlobalAlloc for Test {
6+
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
7+
self.0 += 1; //~ ERROR cannot assign
8+
0 as *mut u8
9+
}
10+
11+
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
12+
unimplemented!();
13+
}
14+
}
15+
16+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0594]: cannot assign to `self.0` which is behind a `&` reference
2+
--> $DIR/issue-68049-1.rs:7:9
3+
|
4+
LL | self.0 += 1;
5+
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0594`.
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
trait Hello {
2+
fn example(&self, input: &i32); // should suggest here
3+
}
4+
5+
struct Test1(i32);
6+
7+
impl Hello for Test1 {
8+
fn example(&self, input: &i32) { // should not suggest here
9+
*input = self.0; //~ ERROR cannot assign
10+
}
11+
}
12+
13+
struct Test2(i32);
14+
15+
impl Hello for Test2 {
16+
fn example(&self, input: &i32) { // should not suggest here
17+
self.0 += *input; //~ ERROR cannot assign
18+
}
19+
}
20+
21+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0594]: cannot assign to `*input` which is behind a `&` reference
2+
--> $DIR/issue-68049-2.rs:9:7
3+
|
4+
LL | fn example(&self, input: &i32); // should suggest here
5+
| ---- help: consider changing that to be a mutable reference: `&mut i32`
6+
...
7+
LL | *input = self.0;
8+
| ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written
9+
10+
error[E0594]: cannot assign to `self.0` which is behind a `&` reference
11+
--> $DIR/issue-68049-2.rs:17:5
12+
|
13+
LL | fn example(&self, input: &i32); // should suggest here
14+
| ----- help: consider changing that to be a mutable reference: `&mut self`
15+
...
16+
LL | self.0 += *input;
17+
| ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0594`.

0 commit comments

Comments
 (0)