Rollup merge of #96733 - SparrowLii:place_to_string, r=davidtwco

turn `append_place_to_string` from recursion into iteration

This PR fixes the FIXME in the impl of `append_place_to_string` which turns `append_place_to_string` from recursion into iteration, meanwhile simplifying the code relatively.
This commit is contained in:
Guillaume Gomez 2022-05-06 20:05:40 +02:00 committed by GitHub
commit c3ddd59f5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,5 +1,6 @@
//! Borrow checker diagnostics. //! Borrow checker diagnostics.
use itertools::Itertools;
use rustc_const_eval::util::{call_kind, CallDesugaringKind}; use rustc_const_eval::util::{call_kind, CallDesugaringKind};
use rustc_errors::{Applicability, Diagnostic}; use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir; use rustc_hir as hir;
@ -161,158 +162,103 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
/// End-user visible description of `place` if one can be found. /// End-user visible description of `place` if one can be found.
/// If the place is a temporary for instance, None will be returned. /// If the place is a temporary for instance, `None` will be returned.
pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> { pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
self.describe_place_with_options(place_ref, IncludingDowncast(false)) self.describe_place_with_options(place_ref, IncludingDowncast(false))
} }
/// End-user visible description of `place` if one can be found. If the /// End-user visible description of `place` if one can be found. If the place is a temporary
/// place is a temporary for instance, None will be returned. /// for instance, `None` will be returned.
/// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is /// `IncludingDowncast` parameter makes the function return `None` if `ProjectionElem` is
/// `Downcast` and `IncludingDowncast` is true /// `Downcast` and `IncludingDowncast` is true
pub(super) fn describe_place_with_options( pub(super) fn describe_place_with_options(
&self, &self,
place: PlaceRef<'tcx>, place: PlaceRef<'tcx>,
including_downcast: IncludingDowncast, including_downcast: IncludingDowncast,
) -> Option<String> { ) -> Option<String> {
let local = place.local;
let mut autoderef_index = None;
let mut buf = String::new(); let mut buf = String::new();
match self.append_place_to_string(place, &mut buf, false, &including_downcast) { let mut ok = self.append_local_to_string(local, &mut buf);
Ok(()) => Some(buf),
Err(()) => None,
}
}
/// Appends end-user visible description of `place` to `buf`. for (index, elem) in place.projection.into_iter().enumerate() {
fn append_place_to_string( match elem {
&self, ProjectionElem::Deref => {
place: PlaceRef<'tcx>, if index == 0 {
buf: &mut String, if self.body.local_decls[local].is_ref_for_guard() {
mut autoderef: bool, continue;
including_downcast: &IncludingDowncast, }
) -> Result<(), ()> { if let Some(box LocalInfo::StaticRef { def_id, .. }) =
match place { &self.body.local_decls[local].local_info
PlaceRef { local, projection: [] } => { {
self.append_local_to_string(local, buf)?; buf.push_str(self.infcx.tcx.item_name(*def_id).as_str());
} ok = Ok(());
PlaceRef { local, projection: [ProjectionElem::Deref] } continue;
if self.body.local_decls[local].is_ref_for_guard() => }
{ }
self.append_place_to_string( if let Some(field) = self.is_upvar_field_projection(PlaceRef {
PlaceRef { local, projection: &[] }, local,
buf, projection: place.projection.split_at(index + 1).0,
autoderef, }) {
&including_downcast, let var_index = field.index();
)?; buf = self.upvars[var_index].place.to_string(self.infcx.tcx);
} ok = Ok(());
PlaceRef { local, projection: [ProjectionElem::Deref] } if !self.upvars[var_index].by_ref {
if self.body.local_decls[local].is_ref_to_static() => buf.insert(0, '*');
{ }
let local_info = &self.body.local_decls[local].local_info; } else {
if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { if autoderef_index.is_none() {
buf.push_str(self.infcx.tcx.item_name(def_id).as_str()); autoderef_index =
} else { match place.projection.into_iter().rev().find_position(|elem| {
unreachable!(); !matches!(
elem,
ProjectionElem::Deref | ProjectionElem::Downcast(..)
)
}) {
Some((index, _)) => Some(place.projection.len() - index),
None => Some(0),
};
}
if index >= autoderef_index.unwrap() {
buf.insert(0, '*');
}
}
}
ProjectionElem::Downcast(..) if including_downcast.0 => return None,
ProjectionElem::Downcast(..) => (),
ProjectionElem::Field(field, _ty) => {
// FIXME(project-rfc_2229#36): print capture precisely here.
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
local,
projection: place.projection.split_at(index + 1).0,
}) {
buf = self.upvars[field.index()].place.to_string(self.infcx.tcx);
ok = Ok(());
} else {
let field_name = self.describe_field(
PlaceRef { local, projection: place.projection.split_at(index).0 },
*field,
);
buf.push('.');
buf.push_str(&field_name);
}
}
ProjectionElem::Index(index) => {
buf.push('[');
if self.append_local_to_string(*index, &mut buf).is_err() {
buf.push('_');
}
buf.push(']');
}
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
// Since it isn't possible to borrow an element on a particular index and
// then use another while the borrow is held, don't output indices details
// to avoid confusing the end-user
buf.push_str("[..]");
} }
} }
PlaceRef { local, projection: [proj_base @ .., elem] } => {
match elem {
ProjectionElem::Deref => {
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
let var_index = field.index();
let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
if self.upvars[var_index].by_ref {
buf.push_str(&name);
} else {
buf.push('*');
buf.push_str(&name);
}
} else {
if autoderef {
// FIXME turn this recursion into iteration
self.append_place_to_string(
PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
)?;
} else {
buf.push('*');
self.append_place_to_string(
PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
)?;
}
}
}
ProjectionElem::Downcast(..) => {
self.append_place_to_string(
PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
)?;
if including_downcast.0 {
return Err(());
}
}
ProjectionElem::Field(field, _ty) => {
autoderef = true;
// FIXME(project-rfc_2229#36): print capture precisely here.
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
let var_index = field.index();
let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
buf.push_str(&name);
} else {
let field_name = self
.describe_field(PlaceRef { local, projection: proj_base }, *field);
self.append_place_to_string(
PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
)?;
buf.push('.');
buf.push_str(&field_name);
}
}
ProjectionElem::Index(index) => {
autoderef = true;
self.append_place_to_string(
PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
)?;
buf.push('[');
if self.append_local_to_string(*index, buf).is_err() {
buf.push('_');
}
buf.push(']');
}
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
autoderef = true;
// Since it isn't possible to borrow an element on a particular index and
// then use another while the borrow is held, don't output indices details
// to avoid confusing the end-user
self.append_place_to_string(
PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
)?;
buf.push_str("[..]");
}
};
}
} }
ok.ok().map(|_| buf)
Ok(())
} }
/// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have