Skip to content

Commit

Permalink
Rollup merge of rust-lang#56906 - blitzerr:master, r=nikomatsakis
Browse files Browse the repository at this point in the history
Issue rust-lang#56905

Adding a map to TypeckTables to get the list of all the Upvars
given a closureID. This is help us get rid of the recurring
pattern in the codebase of iterating over the free vars
using with_freevars.
  • Loading branch information
Centril committed Jan 12, 2019
2 parents e69a5cb + 69e4918 commit 53aa8a1
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 26 deletions.
10 changes: 10 additions & 0 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,12 @@ pub struct TypeckTables<'tcx> {
/// All the existential types that are restricted to concrete types
/// by this function
pub concrete_existential_types: FxHashMap<DefId, Ty<'tcx>>,

/// Given the closure ID this map provides the list of UpvarIDs used by it.
/// The upvarID contains the HIR node ID and it also contains the full path
/// leading to the member of the struct or tuple that is used instead of the
/// entire variable.
pub upvar_list: ty::UpvarListMap,
}

impl<'tcx> TypeckTables<'tcx> {
Expand All @@ -441,6 +447,7 @@ impl<'tcx> TypeckTables<'tcx> {
tainted_by_errors: false,
free_region_map: Default::default(),
concrete_existential_types: Default::default(),
upvar_list: Default::default(),
}
}

Expand Down Expand Up @@ -741,6 +748,8 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
tainted_by_errors,
ref free_region_map,
ref concrete_existential_types,
ref upvar_list,

} = *self;

hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
Expand Down Expand Up @@ -783,6 +792,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
tainted_by_errors.hash_stable(hcx, hasher);
free_region_map.hash_stable(hcx, hasher);
concrete_existential_types.hash_stable(hcx, hasher);
upvar_list.hash_stable(hcx, hasher);
})
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,7 @@ pub struct UpvarBorrow<'tcx> {
pub region: ty::Region<'tcx>,
}

pub type UpvarListMap = FxHashMap<DefId, Vec<UpvarId>>;
pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;

#[derive(Copy, Clone)]
Expand Down
42 changes: 24 additions & 18 deletions src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use hair::cx::Cx;
use hair::{LintLevel, BindingMode, PatternKind};
use rustc::hir;
use rustc::hir::Node;
use rustc::hir::def_id::{DefId, LocalDefId};
use rustc::hir::def_id::DefId;
use rustc::middle::region;
use rustc::mir::*;
use rustc::mir::visit::{MutVisitor, TyContext};
Expand Down Expand Up @@ -640,32 +640,39 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
let arguments: Vec<_> = arguments.collect();

let tcx = hir.tcx();
let span = tcx.hir().span(fn_id);
let tcx_hir = tcx.hir();
let span = tcx_hir.span(fn_id);

let hir_tables = hir.tables();
let fn_def_id = tcx_hir.local_def_id(fn_id);

// Gather the upvars of a closure, if any.
let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
freevars.iter().map(|fv| {
let var_id = fv.var_id();
let var_hir_id = tcx.hir().node_to_hir_id(var_id);
let closure_expr_id = tcx.hir().local_def_id(fn_id);
let capture = hir.tables().upvar_capture(ty::UpvarId {
var_path: ty::UpvarPath {hir_id: var_hir_id},
closure_expr_id: LocalDefId::from_def_id(closure_expr_id),
});
// In analyze_closure() in upvar.rs we gathered a list of upvars used by a
// closure and we stored in a map called upvar_list in TypeckTables indexed
// with the closure's DefId. Here, we run through that vec of UpvarIds for
// the given closure and use the necessary information to create UpvarDecl.
let upvar_decls: Vec<_> = hir_tables
.upvar_list
.get(&fn_def_id)
.into_iter()
.flatten()
.map(|upvar_id| {
let var_hir_id = upvar_id.var_path.hir_id;
let var_node_id = tcx_hir.hir_to_node_id(var_hir_id);
let capture = hir_tables.upvar_capture(*upvar_id);
let by_ref = match capture {
ty::UpvarCapture::ByValue => false,
ty::UpvarCapture::ByRef(..) => true
ty::UpvarCapture::ByRef(..) => true,
};
let mut decl = UpvarDecl {
debug_name: keywords::Invalid.name(),
var_hir_id: ClearCrossCrate::Set(var_hir_id),
by_ref,
mutability: Mutability::Not,
};
if let Some(Node::Binding(pat)) = tcx.hir().find(var_id) {
if let Some(Node::Binding(pat)) = tcx_hir.find(var_node_id) {
if let hir::PatKind::Binding(_, _, ident, _) = pat.node {
decl.debug_name = ident.name;

if let Some(&bm) = hir.tables.pat_binding_modes().get(pat.hir_id) {
if bm == ty::BindByValue(hir::MutMutable) {
decl.mutability = Mutability::Mut;
Expand All @@ -678,8 +685,8 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
}
}
decl
}).collect()
});
})
.collect();

let mut builder = Builder::new(hir,
span,
Expand All @@ -689,7 +696,6 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
return_ty_span,
upvar_decls);

let fn_def_id = tcx.hir().local_def_id(fn_id);
let call_site_scope = region::Scope {
id: body.value.hir_id.local_id,
data: region::ScopeData::CallSite
Expand Down Expand Up @@ -732,7 +738,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
// RustCall pseudo-ABI untuples the last argument.
spread_arg = Some(Local::new(arguments.len()));
}
let closure_expr_id = tcx.hir().local_def_id(fn_id);
let closure_expr_id = tcx_hir.local_def_id(fn_id);
info!("fn_id {:?} has attrs {:?}", closure_expr_id,
tcx.get_attrs(closure_expr_id));

Expand Down
25 changes: 19 additions & 6 deletions src/librustc_typeck/check/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
};

self.tcx.with_freevars(closure_node_id, |freevars| {
let mut freevar_list: Vec<ty::UpvarId> = Vec::with_capacity(freevars.len());
for freevar in freevars {
let upvar_id = ty::UpvarId {
var_path: ty::UpvarPath {
hir_id : self.tcx.hir().node_to_hir_id(freevar.var_id()),
hir_id: self.tcx.hir().node_to_hir_id(freevar.var_id()),
},
closure_expr_id: LocalDefId::from_def_id(closure_def_id),
};
debug!("seed upvar_id {:?}", upvar_id);
// Adding the upvar Id to the list of Upvars, which will be added
// to the map for the closure at the end of the for loop.
freevar_list.push(upvar_id);

let capture_kind = match capture_clause {
hir::CaptureByValue => ty::UpvarCapture::ByValue,
Expand All @@ -149,6 +153,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
.upvar_capture_map
.insert(upvar_id, capture_kind);
}
// Add the vector of freevars to the map keyed with the closure id.
// This gives us an easier access to them without having to call
// with_freevars again..
if !freevar_list.is_empty() {
self.tables
.borrow_mut()
.upvar_list
.insert(closure_def_id, freevar_list);
}
});

let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id());
Expand All @@ -166,7 +179,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.param_env,
region_scope_tree,
&self.tables.borrow(),
).consume_body(body);
)
.consume_body(body);

if let Some(closure_substs) = infer_kind {
// Unify the (as yet unbound) type variable in the closure
Expand Down Expand Up @@ -240,9 +254,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let var_hir_id = tcx.hir().node_to_hir_id(var_node_id);
let freevar_ty = self.node_ty(var_hir_id);
let upvar_id = ty::UpvarId {
var_path: ty::UpvarPath {
hir_id: var_hir_id,
},
var_path: ty::UpvarPath { hir_id: var_hir_id },
closure_expr_id: LocalDefId::from_def_id(closure_def_index),
};
let capture = self.tables.borrow().upvar_capture(upvar_id);
Expand All @@ -262,7 +274,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
},
),
}
}).collect()
})
.collect()
})
}
}
Expand Down
29 changes: 27 additions & 2 deletions src/librustc_typeck/check/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ use syntax_pos::Span;
///////////////////////////////////////////////////////////////////////////
// Entry point

// During type inference, partially inferred types are
// represented using Type variables (ty::Infer). These don't appear in
// the final TypeckTables since all of the types should have been
// inferred once typeck_tables_of is done.
// When type inference is running however, having to update the typeck
// tables every time a new type is inferred would be unreasonably slow,
// so instead all of the replacement happens at the end in
// resolve_type_vars_in_body, which creates a new TypeTables which
// doesn't contain any inference types.
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) -> &'gcx ty::TypeckTables<'gcx> {
let item_id = self.tcx.hir().body_owner(body.id());
Expand All @@ -35,7 +44,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
wbcx.visit_node_id(arg.pat.span, arg.hir_id);
}
wbcx.visit_body(body);
wbcx.visit_upvar_borrow_map();
wbcx.visit_upvar_capture_map();
wbcx.visit_upvar_list_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types();
Expand Down Expand Up @@ -291,7 +301,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
}

impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn visit_upvar_borrow_map(&mut self) {
fn visit_upvar_capture_map(&mut self) {
for (upvar_id, upvar_capture) in self.fcx.tables.borrow().upvar_capture_map.iter() {
let new_upvar_capture = match *upvar_capture {
ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
Expand All @@ -314,6 +324,21 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
}
}

/// Runs through the function context's upvar list map and adds the same to
/// the TypeckTables. upvarlist is a hashmap of the list of upvars referred
/// to in a closure..
fn visit_upvar_list_map(&mut self) {
for (closure_def_id, upvar_list) in self.fcx.tables.borrow().upvar_list.iter() {
debug!(
"UpvarIDs captured by closure {:?} are: {:?}",
closure_def_id, upvar_list
);
self.tables
.upvar_list
.insert(*closure_def_id, upvar_list.to_vec());
}
}

fn visit_closures(&mut self) {
let fcx_tables = self.fcx.tables.borrow();
debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
Expand Down

0 comments on commit 53aa8a1

Please sign in to comment.