Auto merge of #115595 - surechen:114896, r=davidtwco
Fix incorrect mutable suggestion information for binding in ref pattern like: `let &b = a;` fixes #114896 I find we have to get pat_span but not local_decl.source_info.span for suggestion. In `let &b = a;` pat_span is &b. I think check `let &b = a` in hir to make sure it is hir::Node::Local(hir::Local {pat: hir::Pat{kind: hir::PatKind::Ref(....... can distinguish it from other situation, but I'm not sure. If my processing method is not accurate, please guide me to modify it, thank you. r? `@davidtwco`
This commit is contained in:
commit
3ebb5629d1
@ -371,12 +371,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
err.span_label(span, format!("cannot {act}"));
|
err.span_label(span, format!("cannot {act}"));
|
||||||
}
|
}
|
||||||
if suggest {
|
if suggest {
|
||||||
err.span_suggestion_verbose(
|
self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local);
|
||||||
local_decl.source_info.span.shrink_to_lo(),
|
|
||||||
"consider changing this to be mutable",
|
|
||||||
"mut ",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
|
if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
|
||||||
self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
|
self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
|
||||||
@ -712,6 +707,83 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn construct_mut_suggestion_for_local_binding_patterns(
|
||||||
|
&self,
|
||||||
|
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
|
||||||
|
local: Local,
|
||||||
|
) {
|
||||||
|
let local_decl = &self.body.local_decls[local];
|
||||||
|
debug!("local_decl: {:?}", local_decl);
|
||||||
|
let pat_span = match *local_decl.local_info() {
|
||||||
|
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
|
||||||
|
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
|
||||||
|
opt_ty_info: _,
|
||||||
|
opt_match_place: _,
|
||||||
|
pat_span,
|
||||||
|
})) => pat_span,
|
||||||
|
_ => local_decl.source_info.span,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BindingFinder {
|
||||||
|
span: Span,
|
||||||
|
hir_id: Option<hir::HirId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Visitor<'tcx> for BindingFinder {
|
||||||
|
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
|
||||||
|
if let hir::StmtKind::Local(local) = s.kind {
|
||||||
|
if local.pat.span == self.span {
|
||||||
|
self.hir_id = Some(local.hir_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hir::intravisit::walk_stmt(self, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let hir_map = self.infcx.tcx.hir();
|
||||||
|
let def_id = self.body.source.def_id();
|
||||||
|
let hir_id = if let Some(local_def_id) = def_id.as_local()
|
||||||
|
&& let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
|
||||||
|
{
|
||||||
|
let body = hir_map.body(body_id);
|
||||||
|
let mut v = BindingFinder {
|
||||||
|
span: pat_span,
|
||||||
|
hir_id: None,
|
||||||
|
};
|
||||||
|
v.visit_body(body);
|
||||||
|
v.hir_id
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// With ref-binding patterns, the mutability suggestion has to apply to
|
||||||
|
// the binding, not the reference (which would be a type error):
|
||||||
|
//
|
||||||
|
// `let &b = a;` -> `let &(mut b) = a;`
|
||||||
|
if let Some(hir_id) = hir_id
|
||||||
|
&& let Some(hir::Node::Local(hir::Local {
|
||||||
|
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
||||||
|
..
|
||||||
|
})) = hir_map.find(hir_id)
|
||||||
|
&& let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
|
||||||
|
{
|
||||||
|
err.span_suggestion(
|
||||||
|
pat_span,
|
||||||
|
"consider changing this to be mutable",
|
||||||
|
format!("&(mut {name})"),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
local_decl.source_info.span.shrink_to_lo(),
|
||||||
|
"consider changing this to be mutable",
|
||||||
|
"mut ",
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// point to span of upvar making closure call require mutable borrow
|
// point to span of upvar making closure call require mutable borrow
|
||||||
fn show_mutating_upvar(
|
fn show_mutating_upvar(
|
||||||
&self,
|
&self,
|
||||||
|
7
tests/ui/pattern/issue-114896.rs
Normal file
7
tests/ui/pattern/issue-114896.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fn main() {
|
||||||
|
fn x(a: &char) {
|
||||||
|
let &b = a;
|
||||||
|
b.make_ascii_uppercase();
|
||||||
|
//~^ cannot borrow `b` as mutable, as it is not declared as mutable
|
||||||
|
}
|
||||||
|
}
|
11
tests/ui/pattern/issue-114896.stderr
Normal file
11
tests/ui/pattern/issue-114896.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
|
||||||
|
--> $DIR/issue-114896.rs:4:9
|
||||||
|
|
|
||||||
|
LL | let &b = a;
|
||||||
|
| -- help: consider changing this to be mutable: `&(mut b)`
|
||||||
|
LL | b.make_ascii_uppercase();
|
||||||
|
| ^ cannot borrow as mutable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0596`.
|
Loading…
x
Reference in New Issue
Block a user