rustc_typeck: do not leak late-bound lifetimes from bounds to closures.

This commit is contained in:
Eduard-Mihai Burtescu 2017-05-10 16:59:41 +03:00
parent 74c6788d9c
commit dbae169ac1
3 changed files with 61 additions and 4 deletions

View File

@ -198,6 +198,14 @@ impl CodeExtentData {
/// The region maps encode information about region relationships.
pub struct RegionMaps<'tcx> {
/// If not empty, this body is the root of this region hierarchy.
root_body: Option<hir::BodyId>,
/// The parent of the root body owner, if the latter is an
/// an associated const or method, as impls/traits can also
/// have lifetime parameters free in this body.
root_parent: Option<ast::NodeId>,
/// `scope_map` maps from a scope id to the enclosing scope id;
/// this is usually corresponding to the lexical nesting, though
/// in the case of closures the parent scope is the innermost
@ -295,6 +303,8 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> {
impl<'tcx> RegionMaps<'tcx> {
pub fn new() -> Self {
RegionMaps {
root_body: None,
root_parent: None,
scope_map: FxHashMap(),
destruction_scopes: FxHashMap(),
var_map: NodeMap(),
@ -600,8 +610,39 @@ impl<'tcx> RegionMaps<'tcx> {
/// returns the outermost `CodeExtent` that the region outlives.
pub fn free_extent<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, fr: &ty::FreeRegion)
-> CodeExtent<'tcx> {
let scope_id = tcx.hir.as_local_node_id(fr.scope).unwrap();
tcx.call_site_extent(scope_id)
let param_owner = match fr.bound_region {
ty::BoundRegion::BrNamed(def_id, _) => {
tcx.parent_def_id(def_id).unwrap()
}
_ => fr.scope
};
let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
let body_id = tcx.hir.maybe_body_owned_by(param_owner_id)
.map(|body| {
assert_eq!(param_owner, fr.scope);
body
})
.unwrap_or_else(|| {
let root = tcx.hir.as_local_node_id(fr.scope).unwrap();
assert_eq!(Some(param_owner_id), self.root_parent,
"free_extent: {:?} not recognized by the region maps for {:?}",
param_owner, fr.scope);
let root_body = tcx.hir.body_owned_by(root);
assert!(Some(root_body) == self.root_body,
"free_extent: {:?} not inside {:?}",
param_owner, self.root_body.map(|body| tcx.hir.body_owner_def_id(body)));
root_body
});
tcx.intern_code_extent(CodeExtentData::CallSiteScope {
fn_id: tcx.hir.body_owner(body_id),
body_id: body_id.node_id
})
}
}
@ -1167,6 +1208,19 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
let id = tcx.hir.as_local_node_id(def_id).unwrap();
if let Some(body) = tcx.hir.maybe_body_owned_by(id) {
maps.root_body = Some(body);
// If the item is an associated const or a method,
// record its impl/trait parent, as it can also have
// lifetime parameters free in this body.
match tcx.hir.get(id) {
hir::map::NodeImplItem(_) |
hir::map::NodeTraitItem(_) => {
maps.root_parent = Some(tcx.hir.get_parent(id));
}
_ => {}
}
let mut visitor = RegionResolutionVisitor {
tcx: tcx,
region_maps: &mut maps,

View File

@ -2386,11 +2386,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// free parameters. Since we currently represent bound/free type
/// parameters in the same way, this only has an effect on regions.
pub fn construct_free_substs(self, def_id: DefId) -> &'gcx Substs<'gcx> {
let scope = self.closure_base_def_id(def_id);
let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| {
// map bound 'a => free 'a
self.global_tcx().mk_region(ReFree(FreeRegion {
scope: def_id,
scope,
bound_region: def.to_bound_region()
}))
}, |def, _| {

View File

@ -60,6 +60,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
decl,
Abi::RustCall,
expected_sig);
// `deduce_expectations_from_expected_type` introduces late-bound
// lifetimes defined elsewhere, which we need to anonymize away.
let sig = self.tcx.anonymize_late_bound_regions(&sig);
// Create type variables (for now) to represent the transformed
// types of upvars. These will be unified during the upvar