diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index cddb37c7d816f..94c3a48b1c1e3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -914,12 +914,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if show_assign_sugg { struct LetVisitor { decl_span: Span, - sugg_span: Option, + sugg: Option<(Span, bool)>, } impl<'v> Visitor<'v> for LetVisitor { fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { - if self.sugg_span.is_some() { + if self.sugg.is_some() { return; } @@ -927,19 +927,23 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // but we could suggest `todo!()` for all uninitialized bindings in the pattern if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) = &ex.kind - && let hir::PatKind::Binding(..) = pat.kind + && let hir::PatKind::Binding(binding_mode, ..) = pat.kind && span.contains(self.decl_span) { - self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span)); + // Insert after the whole binding pattern so suggestions stay valid for + // bindings with `@` subpatterns like `ref mut x @ v`. + let strip_ref = matches!(binding_mode.0, hir::ByRef::Yes(..)); + self.sugg = + ty.map_or(Some((pat.span, strip_ref)), |ty| Some((ty.span, strip_ref))); } hir::intravisit::walk_stmt(self, ex); } } - let mut visitor = LetVisitor { decl_span, sugg_span: None }; + let mut visitor = LetVisitor { decl_span, sugg: None }; visitor.visit_body(&body); - if let Some(span) = visitor.sugg_span { - self.suggest_assign_value(&mut err, moved_place, span); + if let Some((span, strip_ref)) = visitor.sugg { + self.suggest_assign_value(&mut err, moved_place, span, strip_ref); } } err @@ -950,8 +954,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { err: &mut Diag<'_>, moved_place: PlaceRef<'tcx>, sugg_span: Span, + strip_ref: bool, ) { - let ty = moved_place.ty(self.body, self.infcx.tcx).ty; + let mut ty = moved_place.ty(self.body, self.infcx.tcx).ty; + if strip_ref && let ty::Ref(_, inner, _) = ty.kind() { + ty = *inner; + } debug!("ty: {:?}, kind: {:?}", ty, ty.kind()); let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.infcx.param_env, ty) diff --git a/tests/ui/moves/assign-value-after-at-pattern-issue-145564.fixed b/tests/ui/moves/assign-value-after-at-pattern-issue-145564.fixed new file mode 100644 index 0000000000000..2a1584d37e70a --- /dev/null +++ b/tests/ui/moves/assign-value-after-at-pattern-issue-145564.fixed @@ -0,0 +1,19 @@ +//@ run-rustfix +#![allow(unused_variables)] + +fn main() { + let ref mut x @ _v = 42; + *x = 1; //~ ERROR used binding `x` isn't initialized + + let a @ _b: i32 = 42; + println!("{}", a); //~ ERROR used binding `a` isn't initialized + + let ref c @ _d: i32 = 42; + println!("{:?}", c); //~ ERROR used binding `c` isn't initialized + + let ref e: i32 = 42; + println!("{:?}", e); //~ ERROR used binding `e` isn't initialized + + let ref mut y = 42; + *y = 1; //~ ERROR used binding `y` isn't initialized +} diff --git a/tests/ui/moves/assign-value-after-at-pattern-issue-145564.rs b/tests/ui/moves/assign-value-after-at-pattern-issue-145564.rs new file mode 100644 index 0000000000000..101a77fac1cec --- /dev/null +++ b/tests/ui/moves/assign-value-after-at-pattern-issue-145564.rs @@ -0,0 +1,19 @@ +//@ run-rustfix +#![allow(unused_variables)] + +fn main() { + let ref mut x @ _v; + *x = 1; //~ ERROR used binding `x` isn't initialized + + let a @ _b: i32; + println!("{}", a); //~ ERROR used binding `a` isn't initialized + + let ref c @ _d: i32; + println!("{:?}", c); //~ ERROR used binding `c` isn't initialized + + let ref e: i32; + println!("{:?}", e); //~ ERROR used binding `e` isn't initialized + + let ref mut y; + *y = 1; //~ ERROR used binding `y` isn't initialized +} diff --git a/tests/ui/moves/assign-value-after-at-pattern-issue-145564.stderr b/tests/ui/moves/assign-value-after-at-pattern-issue-145564.stderr new file mode 100644 index 0000000000000..5bfde08045d74 --- /dev/null +++ b/tests/ui/moves/assign-value-after-at-pattern-issue-145564.stderr @@ -0,0 +1,68 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/assign-value-after-at-pattern-issue-145564.rs:6:5 + | +LL | let ref mut x @ _v; + | --------- binding declared here but left uninitialized +LL | *x = 1; + | ^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let ref mut x @ _v = 42; + | ++++ + +error[E0381]: used binding `a` isn't initialized + --> $DIR/assign-value-after-at-pattern-issue-145564.rs:9:20 + | +LL | let a @ _b: i32; + | - binding declared here but left uninitialized +LL | println!("{}", a); + | ^ `a` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let a @ _b: i32 = 42; + | ++++ + +error[E0381]: used binding `c` isn't initialized + --> $DIR/assign-value-after-at-pattern-issue-145564.rs:12:22 + | +LL | let ref c @ _d: i32; + | ----- binding declared here but left uninitialized +LL | println!("{:?}", c); + | ^ `c` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let ref c @ _d: i32 = 42; + | ++++ + +error[E0381]: used binding `e` isn't initialized + --> $DIR/assign-value-after-at-pattern-issue-145564.rs:15:22 + | +LL | let ref e: i32; + | ----- binding declared here but left uninitialized +LL | println!("{:?}", e); + | ^ `e` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let ref e: i32 = 42; + | ++++ + +error[E0381]: used binding `y` isn't initialized + --> $DIR/assign-value-after-at-pattern-issue-145564.rs:18:5 + | +LL | let ref mut y; + | --------- binding declared here but left uninitialized +LL | *y = 1; + | ^^^^^^ `y` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let ref mut y = 42; + | ++++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0381`.