Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -914,32 +914,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if show_assign_sugg {
struct LetVisitor {
decl_span: Span,
sugg_span: Option<Span>,
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;
}

// FIXME: We make sure that this is a normal top-level binding,
// 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
Expand All @@ -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)
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/moves/assign-value-after-at-pattern-issue-145564.fixed
Original file line number Diff line number Diff line change
@@ -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
}
19 changes: 19 additions & 0 deletions tests/ui/moves/assign-value-after-at-pattern-issue-145564.rs
Original file line number Diff line number Diff line change
@@ -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
}
68 changes: 68 additions & 0 deletions tests/ui/moves/assign-value-after-at-pattern-issue-145564.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Loading