use rustc_hir::HirId;
use rustc_target::abi::VariantIdx;
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ PartialEq,
+ Eq,
+ Hash,
+ TyEncodable,
+ TyDecodable,
+ TypeFoldable,
+ HashStable
+)]
pub enum PlaceBase {
/// A temporary variable
Rvalue,
Upvar(ty::UpvarId),
}
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ PartialEq,
+ Eq,
+ Hash,
+ TyEncodable,
+ TyDecodable,
+ TypeFoldable,
+ HashStable
+)]
pub enum ProjectionKind {
/// A dereference of a pointer, reference or `Box<T>` of the given type
Deref,
Subslice,
}
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ PartialEq,
+ Eq,
+ Hash,
+ TyEncodable,
+ TyDecodable,
+ TypeFoldable,
+ HashStable
+)]
pub struct Projection<'tcx> {
/// Type after the projection is being applied.
pub ty: Ty<'tcx>,
/// A `Place` represents how a value is located in memory.
///
/// This is an HIR version of `mir::Place`
-#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct Place<'tcx> {
/// The type of the `PlaceBase`
pub base_ty: Ty<'tcx>,
/// A `PlaceWithHirId` represents how a value is located in memory.
///
/// This is an HIR version of `mir::Place`
-#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct PlaceWithHirId<'tcx> {
/// `HirId` of the expression or pattern producing this value.
pub hir_id: HirId,
#[rustc_diagnostic_item = "Ty"]
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ PartialEq,
+ Eq,
+ Hash,
+ TyEncodable,
+ TyDecodable,
+ TypeFoldable,
+ HashStable
+)]
pub struct UpvarPath {
pub hir_id: hir::HirId,
}
/// Upvars do not get their own `NodeId`. Instead, we use the pair of
/// the original var ID (that is, the root variable that is referenced
/// by the upvar) and the ID of the closure expression.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct UpvarId {
pub var_path: UpvarPath,
pub closure_expr_id: LocalDefId,
}
}
-#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)]
+#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)]
pub enum BorrowKind {
/// Data must be immutable and is aliasable.
ImmBorrow,
/// Information describing the capture of an upvar. This is computed
/// during `typeck`, specifically by `regionck`.
-#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub enum UpvarCapture<'tcx> {
/// Upvar is captured by value. This is always true when the
/// closure is labeled `move`, but can also be true in other cases
ByRef(UpvarBorrow<'tcx>),
}
-#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct UpvarBorrow<'tcx> {
/// The kind of borrow: by-ref upvars have access to shared
/// immutable borrows, which are not part of the normal language
pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
/// A `Place` and the corresponding `CaptureInfo`.
-#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct CapturedPlace<'tcx> {
pub place: HirPlace<'tcx>,
pub info: CaptureInfo<'tcx>,
/// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
/// for a particular capture as well as identifying the part of the source code
/// that triggered this capture to occur.
-#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct CaptureInfo<'tcx> {
/// Expr Id pointing to use that resulted in selecting the current capture kind
///
hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (),
}
wbcx.visit_body(body);
+ wbcx.visit_min_capture_map();
wbcx.visit_upvar_capture_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
}
impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
+ fn visit_min_capture_map(&mut self) {
+ let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher(
+ self.fcx.typeck_results.borrow().closure_min_captures.len(),
+ Default::default(),
+ );
+ for (closure_def_id, root_min_captures) in
+ self.fcx.typeck_results.borrow().closure_min_captures.iter()
+ {
+ let mut root_var_map_wb = ty::RootVariableMinCaptureList::with_capacity_and_hasher(
+ root_min_captures.len(),
+ Default::default(),
+ );
+ for (var_hir_id, min_list) in root_min_captures.iter() {
+ let min_list_wb = min_list
+ .iter()
+ .map(|captured_place| {
+ let locatable = captured_place.info.expr_id.unwrap_or(
+ self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local()),
+ );
+
+ self.resolve(captured_place.clone(), &locatable)
+ })
+ .collect();
+ root_var_map_wb.insert(*var_hir_id, min_list_wb);
+ }
+ min_captures_wb.insert(*closure_def_id, root_var_map_wb);
+ }
+
+ self.typeck_results.closure_min_captures = min_captures_wb;
+ }
+
fn visit_upvar_capture_map(&mut self) {
for (upvar_id, upvar_capture) in self.fcx.typeck_results.borrow().upvar_capture_map.iter() {
let new_upvar_capture = match *upvar_capture {
use rustc_infer::infer::InferCtxt;
use rustc_middle::hir::place::ProjectionKind;
use rustc_middle::ty::{self, adjustment, TyCtxt};
-use rustc_span::Span;
use rustc_target::abi::VariantIdx;
use crate::mem_categorization as mc;
}));
}
- /// Walk closure captures but using `closure_caputes` instead
- /// of `closure_min_captures`.
- ///
- /// This is needed because clippy uses `ExprUseVisitor` after TypeckResults
- /// are written back. We don't currently writeback min_captures to
- /// TypeckResults.
- fn walk_captures_closure_captures(&mut self, closure_expr: &hir::Expr<'_>) {
- // FIXME(arora-aman): Remove this function once rust-lang/project-rfc-2229#18
- // is completed.
- debug!("walk_captures_closure_captures({:?}), ", closure_expr);
-
- let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
- let cl_span = self.tcx().hir().span(closure_expr.hir_id);
-
- let captures = &self.mc.typeck_results.closure_captures[&closure_def_id];
-
- for (&var_id, &upvar_id) in captures {
- let upvar_capture = self.mc.typeck_results.upvar_capture(upvar_id);
- let captured_place =
- return_if_err!(self.cat_captured_var(closure_expr.hir_id, cl_span, var_id));
- match upvar_capture {
- ty::UpvarCapture::ByValue(_) => {
- let mode = copy_or_move(&self.mc, &captured_place);
- self.delegate.consume(&captured_place, captured_place.hir_id, mode);
- }
- ty::UpvarCapture::ByRef(upvar_borrow) => {
- self.delegate.borrow(&captured_place, captured_place.hir_id, upvar_borrow.kind);
- }
- }
- }
- }
-
/// Handle the case where the current body contains a closure.
///
/// When the current body being handled is a closure, then we must make sure that
let place = &captured_place.place;
let capture_info = captured_place.info;
- let upvar_id = if body_owner_is_closure {
+ let place_base = if body_owner_is_closure {
// Mark the place to be captured by the enclosing closure
- ty::UpvarId::new(*var_hir_id, self.body_owner)
+ PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.body_owner))
} else {
- ty::UpvarId::new(*var_hir_id, closure_def_id.expect_local())
+ // If the body owner isn't a closure then the variable must
+ // be a local variable
+ PlaceBase::Local(*var_hir_id)
};
let place_with_id = PlaceWithHirId::new(
capture_info.expr_id.unwrap_or(closure_expr.hir_id),
place.base_ty,
- PlaceBase::Upvar(upvar_id),
+ place_base,
place.projections.clone(),
);
}
}
}
- } else if self.mc.typeck_results.closure_captures.contains_key(&closure_def_id) {
- // Handle the case where clippy calls ExprUseVisitor after
- self.walk_captures_closure_captures(closure_expr)
}
}
-
- fn cat_captured_var(
- &mut self,
- closure_hir_id: hir::HirId,
- closure_span: Span,
- var_id: hir::HirId,
- ) -> mc::McResult<PlaceWithHirId<'tcx>> {
- // Create the place for the variable being borrowed, from the
- // perspective of the creator (parent) of the closure.
- let var_ty = self.mc.node_ty(var_id)?;
- self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id))
- }
}
fn copy_or_move<'a, 'tcx>(