Skip to content

Commit a8f3c76

Browse files
committed
fixes #114896
1 parent b14b074 commit a8f3c76

File tree

3 files changed

+96
-6
lines changed

3 files changed

+96
-6
lines changed

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+78-6
Original file line numberDiff line numberDiff line change
@@ -370,12 +370,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
370370
err.span_label(span, format!("cannot {act}"));
371371
}
372372
if suggest {
373-
err.span_suggestion_verbose(
374-
local_decl.source_info.span.shrink_to_lo(),
375-
"consider changing this to be mutable",
376-
"mut ",
377-
Applicability::MachineApplicable,
378-
);
373+
self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local);
379374
let tcx = self.infcx.tcx;
380375
if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
381376
self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
@@ -710,6 +705,83 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
710705
)
711706
}
712707

708+
fn construct_mut_suggestion_for_local_binding_patterns(
709+
&self,
710+
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
711+
local: Local,
712+
) {
713+
let local_decl = &self.body.local_decls[local];
714+
debug!("local_decl: {:?}", local_decl);
715+
let pat_span = match *local_decl.local_info() {
716+
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
717+
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
718+
opt_ty_info: _,
719+
opt_match_place: _,
720+
pat_span,
721+
})) => pat_span,
722+
_ => local_decl.source_info.span,
723+
};
724+
725+
struct BindingFinder {
726+
span: Span,
727+
hir_id: Option<hir::HirId>,
728+
}
729+
730+
impl<'tcx> Visitor<'tcx> for BindingFinder {
731+
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
732+
if let hir::StmtKind::Local(local) = s.kind {
733+
if local.pat.span == self.span {
734+
self.hir_id = Some(local.hir_id);
735+
}
736+
}
737+
hir::intravisit::walk_stmt(self, s);
738+
}
739+
}
740+
741+
let hir_map = self.infcx.tcx.hir();
742+
let def_id = self.body.source.def_id();
743+
let hir_id = if let Some(local_def_id) = def_id.as_local()
744+
&& let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
745+
{
746+
let body = hir_map.body(body_id);
747+
let mut v = BindingFinder {
748+
span: pat_span,
749+
hir_id: None,
750+
};
751+
v.visit_body(body);
752+
v.hir_id
753+
} else {
754+
None
755+
};
756+
757+
// With ref-binding patterns, the mutability suggestion has to apply to
758+
// the binding, not the reference (which would be a type error):
759+
//
760+
// `let &b = a;` -> `let &(mut b) = a;`
761+
if let Some(hir_id) = hir_id
762+
&& let Some(hir::Node::Local(hir::Local {
763+
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
764+
..
765+
})) = hir_map.find(hir_id)
766+
&& let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
767+
{
768+
err.span_suggestion(
769+
pat_span,
770+
"consider changing this to be mutable",
771+
format!("&(mut {name})"),
772+
Applicability::MachineApplicable,
773+
);
774+
return;
775+
}
776+
777+
err.span_suggestion_verbose(
778+
local_decl.source_info.span.shrink_to_lo(),
779+
"consider changing this to be mutable",
780+
"mut ",
781+
Applicability::MachineApplicable,
782+
);
783+
}
784+
713785
// point to span of upvar making closure call require mutable borrow
714786
fn show_mutating_upvar(
715787
&self,

tests/ui/pattern/issue-114896.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
fn x(a: &char) {
3+
let &b = a;
4+
b.make_ascii_uppercase();
5+
//~^ cannot borrow `b` as mutable, as it is not declared as mutable
6+
}
7+
}

tests/ui/pattern/issue-114896.stderr

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
2+
--> $DIR/issue-114896.rs:4:9
3+
|
4+
LL | let &b = a;
5+
| -- help: consider changing this to be mutable: `&(mut b)`
6+
LL | b.make_ascii_uppercase();
7+
| ^ cannot borrow as mutable
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0596`.

0 commit comments

Comments
 (0)