]> git.lizzy.rs Git - rust.git/commitdiff
rustc_typeck: do not leak late-bound lifetimes from bounds to closures.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Wed, 10 May 2017 13:59:41 +0000 (16:59 +0300)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Sat, 13 May 2017 14:42:59 +0000 (17:42 +0300)
src/librustc/middle/region.rs
src/librustc/ty/mod.rs
src/librustc_typeck/check/closure.rs

index 3f707ac95f73a516be8baa7d17198cfb4773afc2..c6565b78f616defb9a5750617f85719dda39e75d 100644 (file)
@@ -198,6 +198,14 @@ pub fn span(&self, hir_map: &hir_map::Map) -> Option<Span> {
 
 /// 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 @@ fn ancestors_of<'a, 'tcx>(scope_map: &FxHashMap<CodeExtent<'tcx>, CodeExtent<'tc
     /// 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,
index 99ee4e41d1de384a5f6cc7ddc0c9128dd6128ff9..8ccaf0622d7a109adc7747c30012f86074e21c22 100644 (file)
@@ -2386,11 +2386,11 @@ pub fn empty_parameter_environment(self) -> ParameterEnvironment<'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, _| {
index 9eca2b96d62ab1dc124f4a63ee995f8ce544dc67..9e4a7ed1ddc68193e64e3a75086632f430cbef36 100644 (file)
@@ -60,6 +60,9 @@ fn check_closure(&self,
                                          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