use core::unicode::property::Pattern_White_Space;
use rustc::mir::*;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty;
use rustc_errors::{DiagnosticBuilder,Applicability};
use syntax_pos::Span;
use crate::borrow_check::prefixes::PrefixSet;
use crate::borrow_check::error_reporting::UseSpans;
use crate::dataflow::move_paths::{
- IllegalMoveOrigin, IllegalMoveOriginKind, InitLocation,
+ IllegalMoveOrigin, IllegalMoveOriginKind,
LookupResult, MoveError, MovePathIndex,
};
-use crate::util::borrowck_errors::{BorrowckErrors, Origin};
// Often when desugaring a pattern match we may have many individual moves in
// MIR that are all part of one operation from the user's point-of-view. For
},
}
-enum BorrowedContentSource<'tcx> {
- DerefRawPointer,
- DerefMutableRef,
- DerefSharedRef,
- OverloadedDeref(Ty<'tcx>),
- OverloadedIndex(Ty<'tcx>),
-}
-
-impl BorrowedContentSource<'tcx> {
- fn describe_for_unnamed_place(&self) -> String {
- match *self {
- BorrowedContentSource::DerefRawPointer => format!("a raw pointer"),
- BorrowedContentSource::DerefSharedRef => format!("a shared reference"),
- BorrowedContentSource::DerefMutableRef => {
- format!("a mutable reference")
- }
- BorrowedContentSource::OverloadedDeref(ty) => {
- if ty.is_rc() {
- format!("an `Rc`")
- } else if ty.is_arc() {
- format!("an `Arc`")
- } else {
- format!("dereference of `{}`", ty)
- }
- }
- BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
- }
- }
-
- fn describe_for_named_place(&self) -> Option<&'static str> {
- match *self {
- BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
- BorrowedContentSource::DerefSharedRef => Some("shared reference"),
- BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
- // Overloaded deref and index operators should be evaluated into a
- // temporary. So we don't need a description here.
- BorrowedContentSource::OverloadedDeref(_)
- | BorrowedContentSource::OverloadedIndex(_) => None
- }
- }
-
- fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
- match func.sty {
- ty::FnDef(def_id, substs) => {
- let trait_id = tcx.trait_of_item(def_id)?;
-
- let lang_items = tcx.lang_items();
- if Some(trait_id) == lang_items.deref_trait()
- || Some(trait_id) == lang_items.deref_mut_trait()
- {
- Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0)))
- } else if Some(trait_id) == lang_items.index_trait()
- || Some(trait_id) == lang_items.index_mut_trait()
- {
- Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0)))
- } else {
- None
- }
- }
- _ => None,
- }
- }
-}
-
impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) {
let grouped_errors = self.group_move_errors(move_errors);
// If that ever stops being the case, then the ever initialized
// flow could be used.
if let Some(StatementKind::Assign(
- Place::Base(PlaceBase::Local(local)),
+ Place {
+ base: PlaceBase::Local(local),
+ projection: None,
+ },
box Rvalue::Use(Operand::Move(move_from)),
)) = self.body.basic_blocks()[location.block]
.statements
}
}
- let move_spans = self.move_spans(&original_path, location);
+ let move_spans = self.move_spans(original_path.as_ref(), location);
grouped_errors.push(GroupedMoveError::OtherIllegalMove {
use_spans: move_spans,
original_path,
let from_simple_let = match_place.is_none();
let match_place = match_place.as_ref().unwrap_or(move_from);
- match self.move_data.rev_lookup.find(match_place) {
+ match self.move_data.rev_lookup.find(match_place.as_ref()) {
// Error with the match place
LookupResult::Parent(_) => {
for ge in &mut *grouped_errors {
}
// Error with the pattern
LookupResult::Exact(_) => {
- let mpi = match self.move_data.rev_lookup.find(move_from) {
+ let mpi = match self.move_data.rev_lookup.find(move_from.as_ref()) {
LookupResult::Parent(Some(mpi)) => mpi,
// move_from should be a projection from match_place.
_ => unreachable!("Probably not unreachable..."),
};
debug!("report: original_path={:?} span={:?}, kind={:?} \
original_path.is_upvar_field_projection={:?}", original_path, span, kind,
- self.is_upvar_field_projection(original_path));
+ self.is_upvar_field_projection(original_path.as_ref()));
(
match kind {
IllegalMoveOriginKind::Static => {
)
}
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
- self.infcx.tcx
- .cannot_move_out_of_interior_of_drop(span, ty, Origin::Mir)
+ self.cannot_move_out_of_interior_of_drop(span, ty)
}
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
- self.infcx.tcx.cannot_move_out_of_interior_noncopy(
- span, ty, Some(*is_index), Origin::Mir
+ self.cannot_move_out_of_interior_noncopy(
+ span, ty, Some(*is_index),
),
},
span,
place: &Place<'tcx>,
span: Span
) -> DiagnosticBuilder<'a> {
- let mut base_static = place;
- loop {
- match base_static {
- Place::Base(_) => break,
- Place::Projection(box Projection { base, .. }) => base_static = base,
+ let description = if place.projection.is_none() {
+ format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
+ } else {
+ let mut base_static = &place.projection;
+ while let Some(box Projection { base: Some(ref proj), .. }) = base_static {
+ base_static = &proj.base;
}
- }
+ let base_static = PlaceRef {
+ base: &place.base,
+ projection: base_static,
+ };
- let description = if let Place::Base(_) = place {
- format!("static item `{}`", self.describe_place(place).unwrap())
- } else {
format!(
"`{:?}` as `{:?}` is a static item",
- self.describe_place(place).unwrap(),
+ self.describe_place(place.as_ref()).unwrap(),
self.describe_place(base_static).unwrap(),
)
};
- self.infcx.tcx.cannot_move_out_of(span, &description, Origin::Mir)
+ self.cannot_move_out_of(span, &description)
}
fn report_cannot_move_from_borrowed_content(
deref_target_place: &Place<'tcx>,
span: Span,
) -> DiagnosticBuilder<'a> {
- let origin = Origin::Mir;
-
// Inspect the type of the content behind the
// borrow to provide feedback about why this
// was a move rather than a copy.
let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty;
- let upvar_field = self.prefixes(&move_place, PrefixSet::All)
+ let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
.find_map(|p| self.is_upvar_field_projection(p));
- let deref_base = match deref_target_place {
- Place::Projection(box Projection { base, elem: ProjectionElem::Deref }) => base,
+ let deref_base = match deref_target_place.projection {
+ Some(box Projection { ref base, elem: ProjectionElem::Deref }) => PlaceRef {
+ base: &deref_target_place.base,
+ projection: base,
+ },
_ => bug!("deref_target_place is not a deref projection"),
};
- if let Place::Base(PlaceBase::Local(local)) = *deref_base {
- let decl = &self.body.local_decls[local];
+ if let PlaceRef {
+ base: PlaceBase::Local(local),
+ projection: None,
+ } = deref_base {
+ let decl = &self.body.local_decls[*local];
if decl.is_ref_for_guard() {
- let mut err = self.infcx.tcx.cannot_move_out_of(
+ let mut err = self.cannot_move_out_of(
span,
&format!("`{}` in pattern guard", decl.name.unwrap()),
- origin,
);
err.note(
"variables bound in patterns cannot be moved from \
debug!("report: ty={:?}", ty);
let mut err = match ty.sty {
ty::Array(..) | ty::Slice(..) =>
- self.infcx.tcx.cannot_move_out_of_interior_noncopy(
- span, ty, None, origin
- ),
+ self.cannot_move_out_of_interior_noncopy(span, ty, None),
ty::Closure(def_id, closure_substs)
if def_id == self.mir_def_id && upvar_field.is_some()
=> {
let upvar_name = upvar.name;
let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
- let place_name = self.describe_place(move_place).unwrap();
+ let place_name = self.describe_place(move_place.as_ref()).unwrap();
- let place_description = if self.is_upvar_field_projection(move_place).is_some() {
+ let place_description = if self
+ .is_upvar_field_projection(move_place.as_ref())
+ .is_some()
+ {
format!("`{}`, a {}", place_name, capture_description)
} else {
format!(
closure_kind_ty, closure_kind, place_description,
);
- let mut diag = self.infcx.tcx.cannot_move_out_of(span, &place_description, origin);
+ let mut diag = self.cannot_move_out_of(span, &place_description);
diag.span_label(upvar_span, "captured outer variable");
}
_ => {
let source = self.borrowed_content_source(deref_base);
- match (self.describe_place(move_place), source.describe_for_named_place()) {
+ match (
+ self.describe_place(move_place.as_ref()),
+ source.describe_for_named_place(),
+ ) {
(Some(place_desc), Some(source_desc)) => {
- self.infcx.tcx.cannot_move_out_of(
+ self.cannot_move_out_of(
span,
&format!("`{}` which is behind a {}", place_desc, source_desc),
- origin,
)
}
(_, _) => {
- self.infcx.tcx.cannot_move_out_of(
+ self.cannot_move_out_of(
span,
&source.describe_for_unnamed_place(),
- origin,
)
}
}
if binds_to.is_empty() {
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
- let place_desc = match self.describe_place(&move_from) {
+ let place_desc = match self.describe_place(move_from.as_ref()) {
Some(desc) => format!("`{}`", desc),
None => format!("value"),
};
GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
let span = use_spans.var_or_use();
let place_ty = original_path.ty(self.body, self.infcx.tcx).ty;
- let place_desc = match self.describe_place(original_path) {
+ let place_desc = match self.describe_place(original_path.as_ref()) {
Some(desc) => format!("`{}`", desc),
None => format!("value"),
};
);
}
}
-
- fn borrowed_content_source(&self, deref_base: &Place<'tcx>) -> BorrowedContentSource<'tcx> {
- let tcx = self.infcx.tcx;
-
- // Look up the provided place and work out the move path index for it,
- // we'll use this to check whether it was originally from an overloaded
- // operator.
- match self.move_data.rev_lookup.find(deref_base) {
- LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
- debug!("borrowed_content_source: mpi={:?}", mpi);
-
- for i in &self.move_data.init_path_map[mpi] {
- let init = &self.move_data.inits[*i];
- debug!("borrowed_content_source: init={:?}", init);
- // We're only interested in statements that initialized a value, not the
- // initializations from arguments.
- let loc = match init.location {
- InitLocation::Statement(stmt) => stmt,
- _ => continue,
- };
-
- let bbd = &self.body[loc.block];
- let is_terminator = bbd.statements.len() == loc.statement_index;
- debug!(
- "borrowed_content_source: loc={:?} is_terminator={:?}",
- loc,
- is_terminator,
- );
- if !is_terminator {
- continue;
- } else if let Some(Terminator {
- kind: TerminatorKind::Call {
- ref func,
- from_hir_call: false,
- ..
- },
- ..
- }) = bbd.terminator {
- if let Some(source)
- = BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
- {
- return source;
- }
- }
- }
- }
- // Base is a `static` so won't be from an overloaded operator
- _ => (),
- };
-
- // If we didn't find an overloaded deref or index, then assume it's a
- // built in deref and check the type of the base.
- let base_ty = deref_base.ty(self.body, tcx).ty;
- if base_ty.is_unsafe_ptr() {
- BorrowedContentSource::DerefRawPointer
- } else if base_ty.is_mutable_pointer() {
- BorrowedContentSource::DerefMutableRef
- } else {
- BorrowedContentSource::DerefSharedRef
- }
- }
}