1
Fork 0

Introduce new fake reads

This commit is contained in:
Roxane 2021-02-02 21:07:52 -05:00
parent 9320b121b5
commit ec10b71d42
11 changed files with 195 additions and 21 deletions

View file

@ -34,6 +34,7 @@ use super::writeback::Resolver;
use super::FnCtxt;
use crate::expr_use_visitor as euv;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@ -145,6 +146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM,
current_origin: None,
capture_information: Default::default(),
fake_reads: Default::default(),
};
euv::ExprUseVisitor::new(
&mut delegate,
@ -246,6 +248,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter());
self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
let fake_reads = delegate.fake_reads.into_iter().map(|fake_read| fake_read).collect();
self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads);
// If we are also inferred the closure kind here,
// process any deferred resolutions.
let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);
@ -1148,6 +1153,8 @@ struct InferBorrowKind<'a, 'tcx> {
/// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow }
/// ```
capture_information: InferredCaptureInformation<'tcx>,
// [FIXME] RFC2229 Change Vec to FxHashSet
fake_reads: FxHashSet<Place<'tcx>>, // these need to be fake read.
}
impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
@ -1409,6 +1416,12 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
}
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
fn fake_read(&mut self, place: PlaceWithHirId<'tcx>) {
if let PlaceBase::Upvar(_) = place.place.base {
self.fake_reads.insert(place.place);
}
}
fn consume(
&mut self,
place_with_id: &PlaceWithHirId<'tcx>,

View file

@ -4,11 +4,14 @@
use crate::check::FnCtxt;
use rustc_data_structures::stable_map::FxHashMap;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::InferCtxt;
use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::{self, Ty, TyCtxt};
@ -56,6 +59,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
wbcx.visit_body(body);
wbcx.visit_min_capture_map();
wbcx.visit_fake_reads_map();
wbcx.visit_upvar_capture_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
@ -363,6 +367,25 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
self.typeck_results.closure_min_captures = min_captures_wb;
}
fn visit_fake_reads_map(&mut self) {
let mut resolved_closure_fake_reads: FxHashMap<DefId, Vec<HirPlace<'tcx>>> =
Default::default();
for (closure_def_id, fake_reads) in
self.fcx.typeck_results.borrow().closure_fake_reads.iter()
{
let mut resolved_fake_reads = Vec::<HirPlace<'tcx>>::new();
for fake_read in fake_reads.iter() {
let locatable =
self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local());
let resolved_fake_read = self.resolve(fake_read.clone(), &locatable);
resolved_fake_reads.push(resolved_fake_read);
}
resolved_closure_fake_reads.insert(*closure_def_id, resolved_fake_reads);
}
self.typeck_results.closure_fake_reads = resolved_closure_fake_reads;
}
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 {

View file

@ -10,6 +10,7 @@ pub use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId, Projection};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::LocalDefId;
// use rustc_hir::Pat;
use rustc_hir::PatKind;
use rustc_index::vec::Idx;
use rustc_infer::infer::InferCtxt;
@ -51,6 +52,9 @@ pub trait Delegate<'tcx> {
// The path at `assignee_place` is being assigned to.
// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
// [FIXME] RFC2229 This should also affect clippy ref: https://github.com/sexxi-goose/rust/pull/27
fn fake_read(&mut self, place: PlaceWithHirId<'tcx>);
}
#[derive(Copy, Clone, PartialEq, Debug)]
@ -229,7 +233,24 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
hir::ExprKind::Match(ref discr, arms, _) => {
let discr_place = return_if_err!(self.mc.cat_expr(&discr));
self.borrow_expr(&discr, ty::ImmBorrow);
// We only want to borrow discr if the pattern contain something other
// than wildcards
let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
let mut res = false;
for arm in arms.iter() {
return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |_place, pat| {
if let PatKind::Binding(_, _, _, opt_sub_pat) = pat.kind {
if let None = opt_sub_pat {
res = true;
}
}
}));
}
if res {
self.borrow_expr(&discr, ty::ImmBorrow);
}
// treatment of the discriminant is handled while walking the arms.
for arm in arms {
@ -537,6 +558,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat);
self.delegate.fake_read(discr_place.clone());
let tcx = self.tcx();
let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self;
return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
@ -599,6 +622,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
debug!("walk_captures({:?})", closure_expr);
// Over here we walk a closure that is nested inside the current body
// If the current body is a closure, then we also want to report back any fake reads,
// starting off of variables that are captured by our parent as well.
let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
let upvars = self.tcx().upvars_mentioned(self.body_owner);
@ -611,6 +638,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id)
{
for (var_hir_id, min_list) in min_captures.iter() {
// Use this as a reference for if we should promote the fake read
if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) {
// The nested closure might be capturing the current (enclosing) closure's local variables.
// We check if the root variable is ever mentioned within the enclosing closure, if not
@ -636,6 +664,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
place.projections.clone(),
);
// [FIXME] RFC2229 We want to created another loop that iterates mc.typeck_results.fake_reads()
// [FIXME] RFC2229 Add tests for nested closures
if body_owner_is_closure {
self.delegate.fake_read(place_with_id.clone());
}
match capture_info.capture_kind {
ty::UpvarCapture::ByValue(_) => {
let mode = copy_or_move(&self.mc, &place_with_id);