Skip to content

Commit ab8a67c

Browse files
committed
Auto merge of #51729 - matthewjasper:move-errors, r=nikomatsakis
[NLL] Better move errors Make a number of changes to improve the quality of NLL cannot move errors. * Group errors that occur in the same `match` with the same cause. * Suggest `ref`, `&` or removing `*` to avoid the move. * Show the place being matched on. Differences from AST borrowck: * `&` is suggested over `ref` when matching on a place that can't be moved from. * Removing `*` is suggested instead of adding `&` when applicable. * Sub-pattern spans aren't used, this would probably need Spans on Places. Closes #45699 Closes #46627 Closes #51187 Closes #51189 r? @pnkfelix
2 parents 6e5e63a + 2cb0a06 commit ab8a67c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+997
-321
lines changed

src/librustc/mir/mod.rs

+39-9
Original file line numberDiff line numberDiff line change
@@ -497,8 +497,8 @@ pub enum LocalKind {
497497
ReturnPointer,
498498
}
499499

500-
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
501-
pub struct VarBindingForm {
500+
#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
501+
pub struct VarBindingForm<'tcx> {
502502
/// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`?
503503
pub binding_mode: ty::BindingMode,
504504
/// If an explicit type was provided for this variable binding,
@@ -508,21 +508,49 @@ pub struct VarBindingForm {
508508
/// doing so breaks incremental compilation (as of this writing),
509509
/// while a `Span` does not cause our tests to fail.
510510
pub opt_ty_info: Option<Span>,
511+
/// Place of the RHS of the =, or the subject of the `match` where this
512+
/// variable is initialized. None in the case of `let PATTERN;`.
513+
/// Some((None, ..)) in the case of and `let [mut] x = ...` because
514+
/// (a) the right-hand side isn't evaluated as a place expression.
515+
/// (b) it gives a way to separate this case from the remaining cases
516+
/// for diagnostics.
517+
pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
511518
}
512519

513-
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
514-
pub enum BindingForm {
520+
#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
521+
pub enum BindingForm<'tcx> {
515522
/// This is a binding for a non-`self` binding, or a `self` that has an explicit type.
516-
Var(VarBindingForm),
523+
Var(VarBindingForm<'tcx>),
517524
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
518525
ImplicitSelf,
519526
}
520527

521-
CloneTypeFoldableAndLiftImpls! { BindingForm, }
528+
CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, }
522529

523-
impl_stable_hash_for!(struct self::VarBindingForm { binding_mode, opt_ty_info });
530+
impl_stable_hash_for!(struct self::VarBindingForm<'tcx> {
531+
binding_mode,
532+
opt_ty_info,
533+
opt_match_place
534+
});
535+
536+
mod binding_form_impl {
537+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
538+
use ich::StableHashingContext;
524539

525-
impl_stable_hash_for!(enum self::BindingForm { Var(binding), ImplicitSelf, });
540+
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> {
541+
fn hash_stable<W: StableHasherResult>(&self,
542+
hcx: &mut StableHashingContext<'a>,
543+
hasher: &mut StableHasher<W>) {
544+
use super::BindingForm::*;
545+
::std::mem::discriminant(self).hash_stable(hcx, hasher);
546+
547+
match self {
548+
Var(binding) => binding.hash_stable(hcx, hasher),
549+
ImplicitSelf => (),
550+
}
551+
}
552+
}
553+
}
526554

527555
/// A MIR local.
528556
///
@@ -542,7 +570,7 @@ pub struct LocalDecl<'tcx> {
542570
/// therefore it need not be visible across crates. pnkfelix
543571
/// currently hypothesized we *need* to wrap this in a
544572
/// `ClearCrossCrate` as long as it carries as `HirId`.
545-
pub is_user_variable: Option<ClearCrossCrate<BindingForm>>,
573+
pub is_user_variable: Option<ClearCrossCrate<BindingForm<'tcx>>>,
546574

547575
/// True if this is an internal local
548576
///
@@ -670,6 +698,7 @@ impl<'tcx> LocalDecl<'tcx> {
670698
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
671699
binding_mode: ty::BindingMode::BindByValue(_),
672700
opt_ty_info: _,
701+
opt_match_place: _,
673702
}))) => true,
674703

675704
// FIXME: might be able to thread the distinction between
@@ -688,6 +717,7 @@ impl<'tcx> LocalDecl<'tcx> {
688717
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
689718
binding_mode: ty::BindingMode::BindByValue(_),
690719
opt_ty_info: _,
720+
opt_match_place: _,
691721
}))) => true,
692722

693723
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true,

src/librustc_mir/borrow_check/mod.rs

+2-35
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ use syntax_pos::Span;
3535

3636
use dataflow::indexes::BorrowIndex;
3737
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
38-
use dataflow::move_paths::{IllegalMoveOriginKind, MoveError};
3938
use dataflow::Borrows;
4039
use dataflow::DataflowResultsConsumer;
4140
use dataflow::FlowAtLocation;
@@ -62,6 +61,7 @@ mod path_utils;
6261
crate mod place_ext;
6362
mod prefixes;
6463
mod used_muts;
64+
mod move_errors;
6565

6666
pub(crate) mod nll;
6767

@@ -147,40 +147,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
147147
let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) {
148148
Ok(move_data) => move_data,
149149
Err((move_data, move_errors)) => {
150-
for move_error in move_errors {
151-
let (span, kind): (Span, IllegalMoveOriginKind) = match move_error {
152-
MoveError::UnionMove { .. } => {
153-
unimplemented!("don't know how to report union move errors yet.")
154-
}
155-
MoveError::IllegalMove {
156-
cannot_move_out_of: o,
157-
} => (o.span, o.kind),
158-
};
159-
let origin = Origin::Mir;
160-
let mut err = match kind {
161-
IllegalMoveOriginKind::Static => {
162-
tcx.cannot_move_out_of(span, "static item", origin)
163-
}
164-
IllegalMoveOriginKind::BorrowedContent { target_ty: ty } => {
165-
// Inspect the type of the content behind the
166-
// borrow to provide feedback about why this
167-
// was a move rather than a copy.
168-
match ty.sty {
169-
ty::TyArray(..) | ty::TySlice(..) => {
170-
tcx.cannot_move_out_of_interior_noncopy(span, ty, None, origin)
171-
}
172-
_ => tcx.cannot_move_out_of(span, "borrowed content", origin),
173-
}
174-
}
175-
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
176-
tcx.cannot_move_out_of_interior_of_drop(span, ty, origin)
177-
}
178-
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
179-
tcx.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index), origin)
180-
}
181-
};
182-
err.emit();
183-
}
150+
move_errors::report_move_errors(&mir, tcx, move_errors, &move_data);
184151
move_data
185152
}
186153
};

0 commit comments

Comments
 (0)