Use precise places when lowering Closures in THIR

- Closures now use closure_min_captures to figure out captured paths
- Build upvar_mutbls using closure_min_captures
- Change logic in limit_capture_mutability to differentiate b/w
  capturing parent's local variable or capturing a variable that is
  captured by the parent (in case of nested closure) using PlaceBase.

Co-authored-by: Roxane Fruytier <roxane.fruytier@hotmail.com>
This commit is contained in:
Aman Arora
2020-11-26 00:07:41 -05:00
parent 6a1d0699a4
commit e2efdd156b
4 changed files with 107 additions and 61 deletions

View File

@@ -4,6 +4,7 @@ use rustc_index::vec::Idx;
use crate::build::expr::category::{Category, RvalueFunc};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::build::expr::as_place::PlaceBase;
use crate::thir::*;
use rustc_middle::middle::region;
use rustc_middle::mir::AssertKind;
@@ -393,44 +394,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
let arg_place = unpack!(block = this.as_place(block, arg));
let arg_place_builder = unpack!(block = this.as_place_builder(block, arg));
let mutability = match arg_place.as_ref() {
PlaceRef { local, projection: &[] } => this.local_decls[local].mutability,
PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
debug_assert!(
this.local_decls[local].is_ref_for_guard(),
"Unexpected capture place",
);
this.local_decls[local].mutability
}
PlaceRef {
local,
projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
}
| PlaceRef {
local,
projection:
&[ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref],
} => {
let place = PlaceRef { local, projection: proj_base };
let mutability = match arg_place_builder.base() {
// We are capturing a path that starts off a local variable in the parent.
// The mutability of the current capture is same as the mutability
// of the local declaration in the parent.
PlaceBase::Local(local) => this.local_decls[local].mutability,
// Parent is a closure and we are capturing a path that is captured
// by the parent itself. The mutability of the current capture
// is same as that of the capture in the parent closure.
PlaceBase::Upvar { .. } => {
let enclosing_upvars_resolved = arg_place_builder.clone().into_place(
this.hir.tcx(),
this.hir.typeck_results());
// Not projected from the implicit `self` in a closure.
debug_assert!(
match place.local_or_deref_local() {
Some(local) => local == Local::new(1),
None => false,
},
"Unexpected capture place"
);
// Not in a closure
debug_assert!(
this.upvar_mutbls.len() > upvar_index.index(),
"Unexpected capture place"
);
this.upvar_mutbls[upvar_index.index()]
match enclosing_upvars_resolved.as_ref() {
PlaceRef { local, projection: &[ProjectionElem::Field(upvar_index, _), ..] }
| PlaceRef {
local,
projection: &[ProjectionElem::Deref, ProjectionElem::Field(upvar_index, _), ..] } => {
// Not in a closure
debug_assert!(
local == Local::new(1),
"Expected local to be Local(1), found {:?}",
local
);
// Not in a closure
debug_assert!(
this.upvar_mutbls.len() > upvar_index.index(),
"Unexpected capture place, upvar_mutbls={:#?}, upvar_index={:?}",
this.upvar_mutbls, upvar_index
);
this.upvar_mutbls[upvar_index.index()]
}
_ => bug!("Unexpected capture place"),
}
}
_ => bug!("Unexpected capture place"),
};
let borrow_kind = match mutability {
@@ -438,6 +438,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
};
let arg_place = arg_place_builder.into_place(
this.hir.tcx(),
this.hir.typeck_results());
this.cfg.push_assign(
block,
source_info,