Skip to content

Commit e0af56d

Browse files
authored
Rollup merge of rust-lang#85100 - HKalbasi:issue-68049-fix, r=Aaron1011
Fix invalid suggestion of changing impl trait signature Fix rust-lang#68049
2 parents 9243c1e + 8f5585a commit e0af56d

File tree

5 files changed

+153
-10
lines changed

5 files changed

+153
-10
lines changed

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

Lines changed: 86 additions & 10 deletions
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);
@@ -502,6 +515,69 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
502515

503516
err.buffer(&mut self.errors_buffer);
504517
}
518+
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) = self.infcx.tcx.impl_of_method(my_def).and_then(|x| {
530+
self.infcx.tcx.trait_id_of_impl(x)
531+
}) {
532+
a
533+
} else {
534+
return (false, None);
535+
};
536+
(true, td.as_local().and_then(|tld| {
537+
let h = hir_map.local_def_id_to_hir_id(tld);
538+
match hir_map.find(h) {
539+
Some(Node::Item(hir::Item {
540+
kind: hir::ItemKind::Trait(
541+
_, _, _, _,
542+
items
543+
),
544+
..
545+
})) => {
546+
let mut f_in_trait_opt = None;
547+
for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
548+
let hi = fi.hir_id();
549+
if !matches!(k, hir::AssocItemKind::Fn { .. }) {
550+
continue;
551+
}
552+
if hir_map.name(hi) != hir_map.name(my_hir) {
553+
continue;
554+
}
555+
f_in_trait_opt = Some(hi);
556+
break;
557+
}
558+
f_in_trait_opt.and_then(|f_in_trait| {
559+
match hir_map.find(f_in_trait) {
560+
Some(Node::TraitItem(hir::TraitItem {
561+
kind: hir::TraitItemKind::Fn(hir::FnSig {
562+
decl: hir::FnDecl {
563+
inputs,
564+
..
565+
},
566+
..
567+
}, _),
568+
..
569+
})) => {
570+
let hir::Ty { span, .. } = inputs[local.index() - 1];
571+
Some(span)
572+
},
573+
_ => None,
574+
}
575+
})
576+
}
577+
_ => None
578+
}
579+
}))
580+
}
505581

506582
// point to span of upvar making closure call require mutable borrow
507583
fn show_mutating_upvar(
Lines changed: 16 additions & 0 deletions
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;
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() { }
Lines changed: 9 additions & 0 deletions
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`.
Lines changed: 21 additions & 0 deletions
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;
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;
18+
}
19+
}
20+
21+
fn main() { }
Lines changed: 21 additions & 0 deletions
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)