rustc_typeck: do not mutate tables directly during upvar inference.
This commit is contained in:
parent
8b1b05bceb
commit
5175bc18b5
8 changed files with 107 additions and 219 deletions
|
@ -1521,10 +1521,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
!traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
|
!traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
|
|
||||||
self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn closure_kind(&self,
|
pub fn closure_kind(&self,
|
||||||
def_id: DefId)
|
def_id: DefId)
|
||||||
-> Option<ty::ClosureKind>
|
-> Option<ty::ClosureKind>
|
||||||
|
|
|
@ -270,23 +270,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>)
|
param_env: ty::ParamEnv<'tcx>)
|
||||||
-> Self
|
-> Self
|
||||||
{
|
|
||||||
ExprUseVisitor::with_options(delegate,
|
|
||||||
infcx,
|
|
||||||
param_env,
|
|
||||||
region_maps,
|
|
||||||
mc::MemCategorizationOptions::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
|
|
||||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
region_maps: &'a RegionMaps,
|
|
||||||
options: mc::MemCategorizationOptions)
|
|
||||||
-> Self
|
|
||||||
{
|
{
|
||||||
ExprUseVisitor {
|
ExprUseVisitor {
|
||||||
mc: mc::MemCategorizationContext::with_options(infcx, region_maps, options),
|
mc: mc::MemCategorizationContext::new(infcx, region_maps),
|
||||||
delegate,
|
delegate,
|
||||||
param_env,
|
param_env,
|
||||||
}
|
}
|
||||||
|
@ -678,8 +664,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
// consumed or borrowed as part of the automatic adjustment
|
// consumed or borrowed as part of the automatic adjustment
|
||||||
// process.
|
// process.
|
||||||
fn walk_adjustment(&mut self, expr: &hir::Expr) {
|
fn walk_adjustment(&mut self, expr: &hir::Expr) {
|
||||||
//NOTE(@jroesch): mixed RefCell borrow causes crash
|
let tables = self.mc.infcx.tables.borrow();
|
||||||
let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec();
|
let adjustments = tables.expr_adjustments(expr);
|
||||||
let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||||
for adjustment in adjustments {
|
for adjustment in adjustments {
|
||||||
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
|
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
|
||||||
|
@ -896,7 +882,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
let id_var = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
let id_var = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
||||||
let upvar_id = ty::UpvarId { var_id: id_var,
|
let upvar_id = ty::UpvarId { var_id: id_var,
|
||||||
closure_expr_id: closure_expr.id };
|
closure_expr_id: closure_expr.id };
|
||||||
let upvar_capture = self.mc.infcx.upvar_capture(upvar_id).unwrap();
|
let upvar_capture = self.mc.infcx.tables.borrow().upvar_capture(upvar_id);
|
||||||
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
|
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
|
||||||
fn_decl_span,
|
fn_decl_span,
|
||||||
freevar.def));
|
freevar.def));
|
||||||
|
|
|
@ -283,18 +283,6 @@ impl ast_node for hir::Pat {
|
||||||
pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||||
pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
pub region_maps: &'a RegionMaps,
|
pub region_maps: &'a RegionMaps,
|
||||||
options: MemCategorizationOptions,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default)]
|
|
||||||
pub struct MemCategorizationOptions {
|
|
||||||
// If true, then when analyzing a closure upvar, if the closure
|
|
||||||
// has a missing kind, we treat it like a Fn closure. When false,
|
|
||||||
// we ICE if the closure has a missing kind. Should be false
|
|
||||||
// except during closure kind inference. It is used by the
|
|
||||||
// mem-categorization code to be able to have stricter assertions
|
|
||||||
// (which are always true except during upvar inference).
|
|
||||||
pub during_closure_kind_inference: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type McResult<T> = Result<T, ()>;
|
pub type McResult<T> = Result<T, ()>;
|
||||||
|
@ -400,20 +388,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||||
region_maps: &'a RegionMaps)
|
region_maps: &'a RegionMaps)
|
||||||
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
MemCategorizationContext::with_options(infcx,
|
MemCategorizationContext { infcx, region_maps }
|
||||||
region_maps,
|
|
||||||
MemCategorizationOptions::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
|
||||||
region_maps: &'a RegionMaps,
|
|
||||||
options: MemCategorizationOptions)
|
|
||||||
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|
||||||
MemCategorizationContext {
|
|
||||||
infcx: infcx,
|
|
||||||
region_maps: region_maps,
|
|
||||||
options: options,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
|
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
@ -620,38 +595,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
Def::Upvar(def_id, _, fn_node_id) => {
|
Def::Upvar(def_id, _, fn_node_id) => {
|
||||||
let var_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
let var_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
||||||
let ty = self.node_ty(fn_node_id)?;
|
let closure_id = self.tcx().hir.local_def_id(fn_node_id);
|
||||||
match ty.sty {
|
match self.infcx.closure_kind(closure_id) {
|
||||||
ty::TyClosure(closure_id, _) => {
|
Some(kind) => {
|
||||||
match self.infcx.closure_kind(closure_id) {
|
self.cat_upvar(id, span, var_id, fn_node_id, kind)
|
||||||
Some(kind) => {
|
}
|
||||||
self.cat_upvar(id, span, var_id, fn_node_id, kind)
|
None => {
|
||||||
}
|
span_bug!(span, "No closure kind for {:?}", closure_id);
|
||||||
None => {
|
}
|
||||||
if !self.options.during_closure_kind_inference {
|
|
||||||
span_bug!(
|
|
||||||
span,
|
|
||||||
"No closure kind for {:?}",
|
|
||||||
closure_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// during closure kind inference, we
|
|
||||||
// don't know the closure kind yet, but
|
|
||||||
// it's ok because we detect that we are
|
|
||||||
// accessing an upvar and handle that
|
|
||||||
// case specially anyhow. Use Fn
|
|
||||||
// arbitrarily.
|
|
||||||
self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
span_bug!(
|
|
||||||
span,
|
|
||||||
"Upvar of non-closure {} - {:?}",
|
|
||||||
fn_node_id,
|
|
||||||
ty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,7 +694,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
// for that.
|
// for that.
|
||||||
let upvar_id = ty::UpvarId { var_id: var_id,
|
let upvar_id = ty::UpvarId { var_id: var_id,
|
||||||
closure_expr_id: fn_node_id };
|
closure_expr_id: fn_node_id };
|
||||||
let upvar_capture = self.infcx.upvar_capture(upvar_id).unwrap();
|
let upvar_capture = self.infcx.tables.borrow().upvar_capture(upvar_id);
|
||||||
let cmt_result = match upvar_capture {
|
let cmt_result = match upvar_capture {
|
||||||
ty::UpvarCapture::ByValue => {
|
ty::UpvarCapture::ByValue => {
|
||||||
cmt_result
|
cmt_result
|
||||||
|
|
|
@ -376,8 +376,8 @@ impl<'tcx> TypeckTables<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
|
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
|
||||||
Some(self.upvar_capture_map.get(&upvar_id).unwrap().clone())
|
self.upvar_capture_map[&upvar_id]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -365,13 +365,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
|
||||||
let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
|
let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
|
||||||
freevars.iter().map(|fv| {
|
freevars.iter().map(|fv| {
|
||||||
let var_id = tcx.hir.as_local_node_id(fv.def.def_id()).unwrap();
|
let var_id = tcx.hir.as_local_node_id(fv.def.def_id()).unwrap();
|
||||||
let by_ref = hir.tables().upvar_capture(ty::UpvarId {
|
let capture = hir.tables().upvar_capture(ty::UpvarId {
|
||||||
var_id: var_id,
|
var_id: var_id,
|
||||||
closure_expr_id: fn_id
|
closure_expr_id: fn_id
|
||||||
}).map_or(false, |capture| match capture {
|
});
|
||||||
|
let by_ref = match capture {
|
||||||
ty::UpvarCapture::ByValue => false,
|
ty::UpvarCapture::ByValue => false,
|
||||||
ty::UpvarCapture::ByRef(..) => true
|
ty::UpvarCapture::ByRef(..) => true
|
||||||
});
|
};
|
||||||
let mut decl = UpvarDecl {
|
let mut decl = UpvarDecl {
|
||||||
debug_name: keywords::Invalid.name(),
|
debug_name: keywords::Invalid.name(),
|
||||||
by_ref: by_ref
|
by_ref: by_ref
|
||||||
|
|
|
@ -758,13 +758,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
var_id: id_var,
|
var_id: id_var,
|
||||||
closure_expr_id: closure_expr_id,
|
closure_expr_id: closure_expr_id,
|
||||||
};
|
};
|
||||||
let upvar_capture = match cx.tables().upvar_capture(upvar_id) {
|
match cx.tables().upvar_capture(upvar_id) {
|
||||||
Some(c) => c,
|
|
||||||
None => {
|
|
||||||
span_bug!(expr.span, "no upvar_capture for {:?}", upvar_id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match upvar_capture {
|
|
||||||
ty::UpvarCapture::ByValue => field_kind,
|
ty::UpvarCapture::ByValue => field_kind,
|
||||||
ty::UpvarCapture::ByRef(borrow) => {
|
ty::UpvarCapture::ByRef(borrow) => {
|
||||||
ExprKind::Deref {
|
ExprKind::Deref {
|
||||||
|
@ -878,7 +872,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
var_id: id_var,
|
var_id: id_var,
|
||||||
closure_expr_id: closure_expr.id,
|
closure_expr_id: closure_expr.id,
|
||||||
};
|
};
|
||||||
let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap();
|
let upvar_capture = cx.tables().upvar_capture(upvar_id);
|
||||||
let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.id);
|
let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.id);
|
||||||
let var_ty = cx.tables().node_id_to_type(id_var);
|
let var_ty = cx.tables().node_id_to_type(id_var);
|
||||||
let captured_var = Expr {
|
let captured_var = Expr {
|
||||||
|
|
|
@ -834,8 +834,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||||
mc.cat_expr_unadjusted(expr)?
|
mc.cat_expr_unadjusted(expr)?
|
||||||
};
|
};
|
||||||
|
|
||||||
//NOTE(@jroesch): mixed RefCell borrow causes crash
|
let tables = self.tables.borrow();
|
||||||
let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec();
|
let adjustments = tables.expr_adjustments(&expr);
|
||||||
if adjustments.is_empty() {
|
if adjustments.is_empty() {
|
||||||
return Ok(cmt);
|
return Ok(cmt);
|
||||||
}
|
}
|
||||||
|
@ -1215,8 +1215,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||||
// Detect by-ref upvar `x`:
|
// Detect by-ref upvar `x`:
|
||||||
let cause = match note {
|
let cause = match note {
|
||||||
mc::NoteUpvarRef(ref upvar_id) => {
|
mc::NoteUpvarRef(ref upvar_id) => {
|
||||||
let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map;
|
match self.tables.borrow().upvar_capture_map.get(upvar_id) {
|
||||||
match upvar_capture_map.get(upvar_id) {
|
|
||||||
Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
|
Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
|
||||||
// The mutability of the upvar may have been modified
|
// The mutability of the upvar may have been modified
|
||||||
// by the above adjustment, so update our local variable.
|
// by the above adjustment, so update our local variable.
|
||||||
|
|
|
@ -53,31 +53,22 @@ use rustc::hir;
|
||||||
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||||
use rustc::util::nodemap::NodeMap;
|
use rustc::util::nodemap::NodeMap;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
use std::collections::hash_map::Entry;
|
||||||
// PUBLIC ENTRY POINTS
|
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
pub fn closure_analyze(&self, body: &'gcx hir::Body) {
|
pub fn closure_analyze(&self, body: &'gcx hir::Body) {
|
||||||
let mut seed = SeedBorrowKind::new(self);
|
InferBorrowKindVisitor { fcx: self }.visit_body(body);
|
||||||
seed.visit_body(body);
|
|
||||||
|
|
||||||
let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
|
|
||||||
adjust.visit_body(body);
|
|
||||||
|
|
||||||
// it's our job to process these.
|
// it's our job to process these.
|
||||||
assert!(self.deferred_call_resolutions.borrow().is_empty());
|
assert!(self.deferred_call_resolutions.borrow().is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
struct InferBorrowKindVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||||
// SEED BORROW KIND
|
|
||||||
|
|
||||||
struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|
||||||
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
||||||
temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> {
|
||||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
|
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
|
||||||
NestedVisitorMap::None
|
NestedVisitorMap::None
|
||||||
}
|
}
|
||||||
|
@ -87,7 +78,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
hir::ExprClosure(cc, _, body_id, _) => {
|
hir::ExprClosure(cc, _, body_id, _) => {
|
||||||
let body = self.fcx.tcx.hir.body(body_id);
|
let body = self.fcx.tcx.hir.body(body_id);
|
||||||
self.visit_body(body);
|
self.visit_body(body);
|
||||||
self.check_closure(expr, cc);
|
self.fcx.analyze_closure(expr.id, expr.span, body, cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => { }
|
_ => { }
|
||||||
|
@ -97,26 +88,33 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>) -> SeedBorrowKind<'a, 'gcx, 'tcx> {
|
fn analyze_closure(&self,
|
||||||
SeedBorrowKind { fcx: fcx, temp_closure_kinds: NodeMap() }
|
id: ast::NodeId,
|
||||||
}
|
span: Span,
|
||||||
|
body: &hir::Body,
|
||||||
|
capture_clause: hir::CaptureClause) {
|
||||||
|
/*!
|
||||||
|
* Analysis starting point.
|
||||||
|
*/
|
||||||
|
|
||||||
fn check_closure(&mut self,
|
debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
|
||||||
expr: &hir::Expr,
|
|
||||||
capture_clause: hir::CaptureClause)
|
|
||||||
{
|
|
||||||
if !self.fcx.tables.borrow().closure_kinds.contains_key(&expr.id) {
|
|
||||||
self.temp_closure_kinds.insert(expr.id, (ty::ClosureKind::Fn, None));
|
|
||||||
debug!("check_closure: adding closure {:?} as Fn", expr.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fcx.tcx.with_freevars(expr.id, |freevars| {
|
let infer_kind = match self.tables.borrow_mut().closure_kinds.entry(id) {
|
||||||
|
Entry::Occupied(_) => false,
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
debug!("check_closure: adding closure {:?} as Fn", id);
|
||||||
|
entry.insert((ty::ClosureKind::Fn, None));
|
||||||
|
true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.tcx.with_freevars(id, |freevars| {
|
||||||
for freevar in freevars {
|
for freevar in freevars {
|
||||||
let def_id = freevar.def.def_id();
|
let def_id = freevar.def.def_id();
|
||||||
let var_node_id = self.fcx.tcx.hir.as_local_node_id(def_id).unwrap();
|
let var_node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
|
||||||
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
||||||
closure_expr_id: expr.id };
|
closure_expr_id: id };
|
||||||
debug!("seed upvar_id {:?}", upvar_id);
|
debug!("seed upvar_id {:?}", upvar_id);
|
||||||
|
|
||||||
let capture_kind = match capture_clause {
|
let capture_kind = match capture_clause {
|
||||||
|
@ -124,58 +122,37 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
ty::UpvarCapture::ByValue
|
ty::UpvarCapture::ByValue
|
||||||
}
|
}
|
||||||
hir::CaptureByRef => {
|
hir::CaptureByRef => {
|
||||||
let origin = UpvarRegion(upvar_id, expr.span);
|
let origin = UpvarRegion(upvar_id, span);
|
||||||
let freevar_region = self.fcx.next_region_var(origin);
|
let freevar_region = self.next_region_var(origin);
|
||||||
let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
|
let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
|
||||||
region: freevar_region };
|
region: freevar_region };
|
||||||
ty::UpvarCapture::ByRef(upvar_borrow)
|
ty::UpvarCapture::ByRef(upvar_borrow)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.fcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
|
self.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// ADJUST BORROW KIND
|
|
||||||
|
|
||||||
struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|
||||||
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
|
||||||
temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
|
||||||
fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
|
||||||
temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>)
|
|
||||||
-> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
|
||||||
AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn analyze_closure(&mut self,
|
|
||||||
id: ast::NodeId,
|
|
||||||
span: Span,
|
|
||||||
body: &hir::Body) {
|
|
||||||
/*!
|
|
||||||
* Analysis starting point.
|
|
||||||
*/
|
|
||||||
|
|
||||||
debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let body_owner_def_id = self.fcx.tcx.hir.body_owner_def_id(body.id());
|
let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id());
|
||||||
let region_maps = &self.fcx.tcx.region_maps(body_owner_def_id);
|
let region_maps = &self.tcx.region_maps(body_owner_def_id);
|
||||||
let param_env = self.fcx.param_env;
|
let mut delegate = InferBorrowKind {
|
||||||
let mut euv =
|
fcx: self,
|
||||||
euv::ExprUseVisitor::with_options(self,
|
adjust_closure_kinds: NodeMap(),
|
||||||
self.fcx,
|
adjust_upvar_captures: ty::UpvarCaptureMap::default(),
|
||||||
param_env,
|
};
|
||||||
region_maps,
|
euv::ExprUseVisitor::new(&mut delegate, region_maps, self, self.param_env)
|
||||||
mc::MemCategorizationOptions {
|
.consume_body(body);
|
||||||
during_closure_kind_inference: true
|
|
||||||
});
|
// Write the adjusted values back into the main tables.
|
||||||
euv.consume_body(body);
|
if infer_kind {
|
||||||
|
if let Some(kind) = delegate.adjust_closure_kinds.remove(&id) {
|
||||||
|
self.tables.borrow_mut().closure_kinds.insert(id, kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.tables.borrow_mut().upvar_capture_map.extend(
|
||||||
|
delegate.adjust_upvar_captures);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we've analyzed the closure, we know how each
|
// Now that we've analyzed the closure, we know how each
|
||||||
|
@ -191,7 +168,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
// inference algorithm will reject it).
|
// inference algorithm will reject it).
|
||||||
|
|
||||||
// Extract the type variables UV0...UVn.
|
// Extract the type variables UV0...UVn.
|
||||||
let (def_id, closure_substs) = match self.fcx.node_ty(id).sty {
|
let (def_id, closure_substs) = match self.node_ty(id).sty {
|
||||||
ty::TyClosure(def_id, substs) => (def_id, substs),
|
ty::TyClosure(def_id, substs) => (def_id, substs),
|
||||||
ref t => {
|
ref t => {
|
||||||
span_bug!(
|
span_bug!(
|
||||||
|
@ -206,44 +183,41 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
|
debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
|
||||||
id, closure_substs, final_upvar_tys);
|
id, closure_substs, final_upvar_tys);
|
||||||
for (upvar_ty, final_upvar_ty) in
|
for (upvar_ty, final_upvar_ty) in
|
||||||
closure_substs.upvar_tys(def_id, self.fcx.tcx).zip(final_upvar_tys)
|
closure_substs.upvar_tys(def_id, self.tcx).zip(final_upvar_tys)
|
||||||
{
|
{
|
||||||
self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty);
|
self.demand_eqtype(span, final_upvar_ty, upvar_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are also inferred the closure kind here, update the
|
// If we are also inferred the closure kind here,
|
||||||
// main table and process any deferred resolutions.
|
// process any deferred resolutions.
|
||||||
if let Some(&(kind, context)) = self.temp_closure_kinds.get(&id) {
|
if infer_kind {
|
||||||
self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, context));
|
let closure_def_id = self.tcx.hir.local_def_id(id);
|
||||||
let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
|
|
||||||
debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
|
|
||||||
|
|
||||||
let deferred_call_resolutions =
|
let deferred_call_resolutions =
|
||||||
self.fcx.remove_deferred_call_resolutions(closure_def_id);
|
self.remove_deferred_call_resolutions(closure_def_id);
|
||||||
for deferred_call_resolution in deferred_call_resolutions {
|
for deferred_call_resolution in deferred_call_resolutions {
|
||||||
deferred_call_resolution.resolve(self.fcx);
|
deferred_call_resolution.resolve(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a list of `ClosureUpvar`s for each upvar.
|
// Returns a list of `ClosureUpvar`s for each upvar.
|
||||||
fn final_upvar_tys(&mut self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
|
fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
|
||||||
// Presently an unboxed closure type cannot "escape" out of a
|
// Presently an unboxed closure type cannot "escape" out of a
|
||||||
// function, so we will only encounter ones that originated in the
|
// function, so we will only encounter ones that originated in the
|
||||||
// local crate or were inlined into it along with some function.
|
// local crate or were inlined into it along with some function.
|
||||||
// This may change if abstract return types of some sort are
|
// This may change if abstract return types of some sort are
|
||||||
// implemented.
|
// implemented.
|
||||||
let tcx = self.fcx.tcx;
|
let tcx = self.tcx;
|
||||||
tcx.with_freevars(closure_id, |freevars| {
|
tcx.with_freevars(closure_id, |freevars| {
|
||||||
freevars.iter().map(|freevar| {
|
freevars.iter().map(|freevar| {
|
||||||
let def_id = freevar.def.def_id();
|
let def_id = freevar.def.def_id();
|
||||||
let var_id = tcx.hir.as_local_node_id(def_id).unwrap();
|
let var_id = tcx.hir.as_local_node_id(def_id).unwrap();
|
||||||
let freevar_ty = self.fcx.node_ty(var_id);
|
let freevar_ty = self.node_ty(var_id);
|
||||||
let upvar_id = ty::UpvarId {
|
let upvar_id = ty::UpvarId {
|
||||||
var_id: var_id,
|
var_id: var_id,
|
||||||
closure_expr_id: closure_id
|
closure_expr_id: closure_id
|
||||||
};
|
};
|
||||||
let capture = self.fcx.upvar_capture(upvar_id).unwrap();
|
let capture = self.tables.borrow().upvar_capture(upvar_id);
|
||||||
|
|
||||||
debug!("var_id={:?} freevar_ty={:?} capture={:?}",
|
debug!("var_id={:?} freevar_ty={:?} capture={:?}",
|
||||||
var_id, freevar_ty, capture);
|
var_id, freevar_ty, capture);
|
||||||
|
@ -260,7 +234,15 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
}).collect()
|
}).collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InferBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||||
|
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
adjust_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
|
||||||
|
adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
fn adjust_upvar_borrow_kind_for_consume(&mut self,
|
fn adjust_upvar_borrow_kind_for_consume(&mut self,
|
||||||
cmt: mc::cmt<'tcx>,
|
cmt: mc::cmt<'tcx>,
|
||||||
mode: euv::ConsumeMode)
|
mode: euv::ConsumeMode)
|
||||||
|
@ -297,9 +279,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
guarantor.span,
|
guarantor.span,
|
||||||
tcx.hir.name(upvar_id.var_id));
|
tcx.hir.name(upvar_id.var_id));
|
||||||
|
|
||||||
let upvar_capture_map =
|
self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue);
|
||||||
&mut self.fcx.tables.borrow_mut().upvar_capture_map;
|
|
||||||
upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue);
|
|
||||||
}
|
}
|
||||||
mc::NoteClosureEnv(upvar_id) => {
|
mc::NoteClosureEnv(upvar_id) => {
|
||||||
// we get just a closureenv ref if this is a
|
// we get just a closureenv ref if this is a
|
||||||
|
@ -410,11 +390,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
// upvar, then we need to modify the
|
// upvar, then we need to modify the
|
||||||
// borrow_kind of the upvar to make sure it
|
// borrow_kind of the upvar to make sure it
|
||||||
// is inferred to mutable if necessary
|
// is inferred to mutable if necessary
|
||||||
{
|
self.adjust_upvar_borrow_kind(upvar_id, borrow_kind);
|
||||||
let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map;
|
|
||||||
let ub = upvar_capture_map.get_mut(&upvar_id).unwrap();
|
|
||||||
self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
// also need to be in an FnMut closure since this is not an ImmBorrow
|
// also need to be in an FnMut closure since this is not an ImmBorrow
|
||||||
self.adjust_closure_kind(upvar_id.closure_expr_id,
|
self.adjust_closure_kind(upvar_id.closure_expr_id,
|
||||||
|
@ -448,22 +424,25 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
/// some particular use.
|
/// some particular use.
|
||||||
fn adjust_upvar_borrow_kind(&mut self,
|
fn adjust_upvar_borrow_kind(&mut self,
|
||||||
upvar_id: ty::UpvarId,
|
upvar_id: ty::UpvarId,
|
||||||
upvar_capture: &mut ty::UpvarCapture,
|
|
||||||
kind: ty::BorrowKind) {
|
kind: ty::BorrowKind) {
|
||||||
|
let upvar_capture = self.adjust_upvar_captures.get(&upvar_id).cloned()
|
||||||
|
.unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id));
|
||||||
debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
|
debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
|
||||||
upvar_id, upvar_capture, kind);
|
upvar_id, upvar_capture, kind);
|
||||||
|
|
||||||
match *upvar_capture {
|
match upvar_capture {
|
||||||
ty::UpvarCapture::ByValue => {
|
ty::UpvarCapture::ByValue => {
|
||||||
// Upvar is already by-value, the strongest criteria.
|
// Upvar is already by-value, the strongest criteria.
|
||||||
}
|
}
|
||||||
ty::UpvarCapture::ByRef(ref mut upvar_borrow) => {
|
ty::UpvarCapture::ByRef(mut upvar_borrow) => {
|
||||||
match (upvar_borrow.kind, kind) {
|
match (upvar_borrow.kind, kind) {
|
||||||
// Take RHS:
|
// Take RHS:
|
||||||
(ty::ImmBorrow, ty::UniqueImmBorrow) |
|
(ty::ImmBorrow, ty::UniqueImmBorrow) |
|
||||||
(ty::ImmBorrow, ty::MutBorrow) |
|
(ty::ImmBorrow, ty::MutBorrow) |
|
||||||
(ty::UniqueImmBorrow, ty::MutBorrow) => {
|
(ty::UniqueImmBorrow, ty::MutBorrow) => {
|
||||||
upvar_borrow.kind = kind;
|
upvar_borrow.kind = kind;
|
||||||
|
self.adjust_upvar_captures.insert(upvar_id,
|
||||||
|
ty::UpvarCapture::ByRef(upvar_borrow));
|
||||||
}
|
}
|
||||||
// Take LHS:
|
// Take LHS:
|
||||||
(ty::ImmBorrow, ty::ImmBorrow) |
|
(ty::ImmBorrow, ty::ImmBorrow) |
|
||||||
|
@ -484,7 +463,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
debug!("adjust_closure_kind(closure_id={}, new_kind={:?}, upvar_span={:?}, var_name={})",
|
debug!("adjust_closure_kind(closure_id={}, new_kind={:?}, upvar_span={:?}, var_name={})",
|
||||||
closure_id, new_kind, upvar_span, var_name);
|
closure_id, new_kind, upvar_span, var_name);
|
||||||
|
|
||||||
if let Some(&(existing_kind, _)) = self.temp_closure_kinds.get(&closure_id) {
|
let closure_kind = self.adjust_closure_kinds.get(&closure_id).cloned()
|
||||||
|
.or_else(|| self.fcx.tables.borrow().closure_kinds.get(&closure_id).cloned());
|
||||||
|
if let Some((existing_kind, _)) = closure_kind {
|
||||||
debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
|
debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
|
||||||
closure_id, existing_kind, new_kind);
|
closure_id, existing_kind, new_kind);
|
||||||
|
|
||||||
|
@ -500,7 +481,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
|
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
|
||||||
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
|
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
|
||||||
// new kind is stronger than the old kind
|
// new kind is stronger than the old kind
|
||||||
self.temp_closure_kinds.insert(
|
self.adjust_closure_kinds.insert(
|
||||||
closure_id,
|
closure_id,
|
||||||
(new_kind, Some((upvar_span, var_name)))
|
(new_kind, Some((upvar_span, var_name)))
|
||||||
);
|
);
|
||||||
|
@ -510,27 +491,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> {
|
||||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
|
|
||||||
NestedVisitorMap::None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_fn(&mut self,
|
|
||||||
fn_kind: intravisit::FnKind<'gcx>,
|
|
||||||
decl: &'gcx hir::FnDecl,
|
|
||||||
body: hir::BodyId,
|
|
||||||
span: Span,
|
|
||||||
id: ast::NodeId)
|
|
||||||
{
|
|
||||||
intravisit::walk_fn(self, fn_kind, decl, body, span, id);
|
|
||||||
|
|
||||||
let body = self.fcx.tcx.hir.body(body);
|
|
||||||
self.visit_body(body);
|
|
||||||
self.analyze_closure(id, span, body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
|
|
||||||
fn consume(&mut self,
|
fn consume(&mut self,
|
||||||
_consume_id: ast::NodeId,
|
_consume_id: ast::NodeId,
|
||||||
_consume_span: Span,
|
_consume_span: Span,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue