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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user