]> git.lizzy.rs Git - rust.git/commitdiff
rustc: treat const bodies like fn bodies in middle::region.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Mon, 24 Apr 2017 19:03:47 +0000 (22:03 +0300)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Sat, 6 May 2017 15:35:43 +0000 (18:35 +0300)
src/librustc/hir/intravisit.rs
src/librustc/hir/map/mod.rs
src/librustc/middle/region.rs
src/librustc/ty/mod.rs
src/test/run-pass/associated-const-type-parameters.rs

index def6b2b3421f6f4135e0741b575506381f5a2e10..836d9775a3f69b7f5292897801ec0eb30b85310d 100644 (file)
@@ -140,23 +140,6 @@ pub fn inter(self) -> Option<&'this Map<'tcx>> {
 /// to monitor future changes to `Visitor` in case a new method with a
 /// new default implementation gets introduced.)
 pub trait Visitor<'v> : Sized {
-    /// Invokes the suitable visitor method for the given `Node`
-    /// extracted from the hir map.
-    fn visit_hir_map_node(&mut self, node: map::Node<'v>) {
-        match node {
-            map::NodeItem(a) => self.visit_item(a),
-            map::NodeForeignItem(a) => self.visit_foreign_item(a),
-            map::NodeTraitItem(a) => self.visit_trait_item(a),
-            map::NodeImplItem(a) => self.visit_impl_item(a),
-            map::NodeExpr(a) => self.visit_expr(a),
-            map::NodeStmt(a) => self.visit_stmt(a),
-            map::NodeTy(a) => self.visit_ty(a),
-            map::NodePat(a) => self.visit_pat(a),
-            map::NodeBlock(a) => self.visit_block(a),
-            _ => bug!("Visitor::visit_hir_map_node() not yet impl for node `{:?}`", node)
-        }
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // Nested items.
 
index abc967dec905c23459cfc9fc567679316d5467af..c715484a934df37afc1ed353c9cc0fd73cbff14b 100644 (file)
@@ -442,20 +442,21 @@ pub fn body_owner_def_id(&self, id: BodyId) -> DefId {
         self.local_def_id(self.body_owner(id))
     }
 
-    /// Given a body owner's id, returns the `BodyId` associated with it.
-    pub fn body_owned_by(&self, id: NodeId) -> BodyId {
+    /// Given a node id, returns the `BodyId` associated with it,
+    /// if the node is a body owner, otherwise returns `None`.
+    pub fn maybe_body_owned_by(&self, id: NodeId) -> Option<BodyId> {
         if let Some(entry) = self.find_entry(id) {
             if let Some(body_id) = entry.associated_body() {
                 // For item-like things and closures, the associated
                 // body has its own distinct id, and that is returned
                 // by `associated_body`.
-                body_id
+                Some(body_id)
             } else {
                 // For some expressions, the expression is its own body.
                 if let EntryExpr(_, expr) = entry {
-                    BodyId { node_id: expr.id }
+                    Some(BodyId { node_id: expr.id })
                 } else {
-                    span_bug!(self.span(id), "id `{}` has no associated body: {:?}", id, entry);
+                    None
                 }
             }
         } else {
@@ -463,6 +464,14 @@ pub fn body_owned_by(&self, id: NodeId) -> BodyId {
         }
     }
 
+    /// Given a body owner's id, returns the `BodyId` associated with it.
+    pub fn body_owned_by(&self, id: NodeId) -> BodyId {
+        self.maybe_body_owned_by(id).unwrap_or_else(|| {
+            span_bug!(self.span(id), "body_owned_by: {} has no associated body",
+                      self.node_to_string(id));
+        })
+    }
+
     pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
         match self.get(id) {
             NodeItem(&Item { node: ItemTrait(..), .. }) => id,
index d1d5e9d6cb18f78b52fea08b19b6a6dbc17afda8..087ab4b94da3d254f2678bd6011748de0b197106 100644 (file)
 use std::rc::Rc;
 use serialize;
 use syntax::codemap;
-use syntax::ast::{self, NodeId};
+use syntax::ast;
 use syntax_pos::Span;
 use ty::TyCtxt;
 use ty::maps::Providers;
 
-use hir; use hir::def_id::DefId;
-use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
-use hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local};
+use hir;
+use hir::def_id::DefId;
+use hir::intravisit::{self, Visitor, NestedVisitorMap};
+use hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local};
+use mir::transform::MirSource;
 
 pub type CodeExtent<'tcx> = &'tcx CodeExtentData;
 
@@ -811,7 +813,17 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
         }
     }
 
-    intravisit::walk_expr(visitor, expr);
+    match expr.node {
+        // Manually recurse over closures, because they are the only
+        // case of nested bodies that share the parent environment.
+        hir::ExprClosure(.., body, _) => {
+            let body = visitor.tcx.hir.body(body);
+            visitor.visit_body(body);
+        }
+
+        _ => intravisit::walk_expr(visitor, expr)
+    }
+
     visitor.cx = prev_cx;
 }
 
@@ -1041,74 +1053,6 @@ fn record_rvalue_scope<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>
     }
 }
 
-fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, walk: F)
-    where F: FnOnce(&mut RegionResolutionVisitor<'a, 'tcx>)
-{
-    // Items create a new outer block scope as far as we're concerned.
-    let prev_cx = visitor.cx;
-    let prev_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
-    visitor.cx = Context {
-        root_id: None,
-        var_parent: None,
-        parent: None,
-    };
-    walk(visitor);
-    visitor.cx = prev_cx;
-    visitor.terminating_scopes = prev_ts;
-}
-
-fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
-                        kind: FnKind<'tcx>,
-                        decl: &'tcx hir::FnDecl,
-                        body_id: hir::BodyId,
-                        sp: Span,
-                        id: ast::NodeId) {
-    visitor.cx.parent = Some(visitor.new_code_extent(
-        CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id }));
-
-    debug!("region::resolve_fn(id={:?}, \
-            span={:?}, \
-            body.id={:?}, \
-            cx.parent={:?})",
-           id,
-           visitor.tcx.sess.codemap().span_to_string(sp),
-           body_id,
-           visitor.cx.parent);
-
-    let fn_decl_scope = visitor.new_code_extent(
-        CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id });
-
-    if let Some(root_id) = visitor.cx.root_id {
-        visitor.region_maps.record_fn_parent(body_id.node_id, root_id);
-    }
-
-    let outer_cx = visitor.cx;
-    let outer_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
-    visitor.terminating_scopes.insert(body_id.node_id);
-
-    // The arguments and `self` are parented to the fn.
-    visitor.cx = Context {
-        root_id: Some(body_id.node_id),
-        parent: None,
-        var_parent: Some(fn_decl_scope),
-    };
-
-    intravisit::walk_fn_decl(visitor, decl);
-    intravisit::walk_fn_kind(visitor, kind);
-
-    // The body of the every fn is a root scope.
-    visitor.cx = Context {
-        root_id: Some(body_id.node_id),
-        parent: Some(fn_decl_scope),
-        var_parent: Some(fn_decl_scope),
-    };
-    visitor.visit_nested_body(body_id);
-
-    // Restore context we had at the start.
-    visitor.cx = outer_cx;
-    visitor.terminating_scopes = outer_ts;
-}
-
 impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
     pub fn intern_code_extent(&mut self,
                               data: CodeExtentData,
@@ -1152,29 +1096,57 @@ fn new_node_extent_with_dtor(&mut self, id: ast::NodeId) -> CodeExtent<'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.map)
+        NestedVisitorMap::None
     }
 
     fn visit_block(&mut self, b: &'tcx Block) {
         resolve_block(self, b);
     }
 
-    fn visit_item(&mut self, i: &'tcx Item) {
-        resolve_item_like(self, |this| intravisit::walk_item(this, i));
-    }
+    fn visit_body(&mut self, body: &'tcx hir::Body) {
+        let body_id = body.id();
+        let owner_id = self.map.body_owner(body_id);
 
-    fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
-        resolve_item_like(self, |this| intravisit::walk_impl_item(this, ii));
-    }
+        debug!("visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})",
+               owner_id,
+               self.tcx.sess.codemap().span_to_string(body.value.span),
+               body_id,
+               self.cx.parent);
 
-    fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
-        resolve_item_like(self, |this| intravisit::walk_trait_item(this, ti));
-    }
+        let outer_cx = self.cx;
+        let outer_ts = mem::replace(&mut self.terminating_scopes, NodeSet());
 
-    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx FnDecl,
-                b: hir::BodyId, s: Span, n: NodeId) {
-        resolve_fn(self, fk, fd, b, s, n);
+        // Only functions have an outer terminating (drop) scope,
+        // while temporaries in constant initializers are 'static.
+        if let MirSource::Fn(_) = MirSource::from_node(self.tcx, owner_id) {
+            self.terminating_scopes.insert(body_id.node_id);
+        }
+
+        if let Some(root_id) = self.cx.root_id {
+            self.region_maps.record_fn_parent(body_id.node_id, root_id);
+        }
+        self.cx.root_id = Some(body_id.node_id);
+
+        self.cx.parent = Some(self.new_code_extent(
+            CodeExtentData::CallSiteScope { fn_id: owner_id, body_id: body_id.node_id }));
+        self.cx.parent = Some(self.new_code_extent(
+            CodeExtentData::ParameterScope { fn_id: owner_id, body_id: body_id.node_id }));
+
+        // The arguments and `self` are parented to the fn.
+        self.cx.var_parent = self.cx.parent.take();
+        for argument in &body.arguments {
+            self.visit_pat(&argument.pat);
+        }
+
+        // The body of the every fn is a root scope.
+        self.cx.parent = self.cx.var_parent;
+        self.visit_expr(&body.value);
+
+        // Restore context we had at the start.
+        self.cx = outer_cx;
+        self.terminating_scopes = outer_ts;
     }
+
     fn visit_arm(&mut self, a: &'tcx Arm) {
         resolve_arm(self, a);
     }
@@ -1192,21 +1164,18 @@ fn visit_local(&mut self, l: &'tcx Local) {
     }
 }
 
-fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_id: DefId)
+fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     -> Rc<RegionMaps<'tcx>>
 {
-    let closure_base_def_id = tcx.closure_base_def_id(fn_id);
-    if closure_base_def_id != fn_id {
+    let closure_base_def_id = tcx.closure_base_def_id(def_id);
+    if closure_base_def_id != def_id {
         return tcx.region_maps(closure_base_def_id);
     }
 
     let mut maps = RegionMaps::new();
 
-    let fn_node_id = tcx.hir.as_local_node_id(fn_id)
-                            .expect("fn DefId should be for LOCAL_CRATE");
-    let node = tcx.hir.get(fn_node_id);
-
-    {
+    let id = tcx.hir.as_local_node_id(def_id).unwrap();
+    if let Some(body) = tcx.hir.maybe_body_owned_by(id) {
         let mut visitor = RegionResolutionVisitor {
             tcx: tcx,
             region_maps: &mut maps,
@@ -1218,7 +1187,8 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_id: DefId)
             },
             terminating_scopes: NodeSet(),
         };
-        visitor.visit_hir_map_node(node);
+
+        visitor.visit_body(tcx.hir.body(body));
     }
 
     Rc::new(maps)
index a361c80a2529f34090920688e728b255a6ffb2da..99a5f6325ac7515242f3c9322af7ded3fb295b8c 100644 (file)
@@ -1238,7 +1238,7 @@ pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId)
         match tcx.hir.find(id) {
             Some(hir_map::NodeImplItem(ref impl_item)) => {
                 match impl_item.node {
-                    hir::ImplItemKind::Type(_) | hir::ImplItemKind::Const(..) => {
+                    hir::ImplItemKind::Type(_) => {
                         // associated types don't have their own entry (for some reason),
                         // so for now just grab environment for the impl
                         let impl_id = tcx.hir.get_parent(id);
@@ -1247,7 +1247,8 @@ pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId)
                                                             impl_def_id,
                                                             Some(tcx.item_extent(id)))
                     }
-                    hir::ImplItemKind::Method(_, ref body) => {
+                    hir::ImplItemKind::Const(_, body) |
+                    hir::ImplItemKind::Method(_, body) => {
                         tcx.construct_parameter_environment(
                             impl_item.span,
                             tcx.hir.local_def_id(id),
@@ -1257,56 +1258,37 @@ pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId)
             }
             Some(hir_map::NodeTraitItem(trait_item)) => {
                 match trait_item.node {
-                    hir::TraitItemKind::Type(..) | hir::TraitItemKind::Const(..) => {
-                        // associated types don't have their own entry (for some reason),
-                        // so for now just grab environment for the trait
-                        let trait_id = tcx.hir.get_parent(id);
-                        let trait_def_id = tcx.hir.local_def_id(trait_id);
+                    hir::TraitItemKind::Type(..) |
+                    hir::TraitItemKind::Const(_, None) |
+                    hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_))=> {
                         tcx.construct_parameter_environment(trait_item.span,
-                                                            trait_def_id,
+                                                            tcx.hir.local_def_id(id),
                                                             Some(tcx.item_extent(id)))
                     }
-                    hir::TraitItemKind::Method(_, ref body) => {
-                        // Use call-site for extent (unless this is a
-                        // trait method with no default; then fallback
-                        // to the method id).
-                        let extent = if let hir::TraitMethod::Provided(body_id) = *body {
-                            // default impl: use call_site extent as free_id_outlive bound.
-                            tcx.call_site_extent(id, body_id.node_id)
-                        } else {
-                            // no default impl: use item extent as free_id_outlive bound.
-                            tcx.item_extent(id)
-                        };
+                    hir::TraitItemKind::Const(_, Some(body)) |
+                    hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body)) => {
                         tcx.construct_parameter_environment(
                             trait_item.span,
                             tcx.hir.local_def_id(id),
-                            Some(extent))
+                            Some(tcx.call_site_extent(id, body.node_id)))
                     }
                 }
             }
             Some(hir_map::NodeItem(item)) => {
                 match item.node {
-                    hir::ItemFn(.., body_id) => {
-                        // We assume this is a function.
-                        let fn_def_id = tcx.hir.local_def_id(id);
-
+                    hir::ItemConst(_, body) |
+                    hir::ItemStatic(.., body) |
+                    hir::ItemFn(.., body) => {
                         tcx.construct_parameter_environment(
                             item.span,
-                            fn_def_id,
-                            Some(tcx.call_site_extent(id, body_id.node_id)))
+                            tcx.hir.local_def_id(id),
+                            Some(tcx.call_site_extent(id, body.node_id)))
                     }
                     hir::ItemEnum(..) |
                     hir::ItemStruct(..) |
                     hir::ItemUnion(..) |
                     hir::ItemTy(..) |
                     hir::ItemImpl(..) |
-                    hir::ItemConst(..) |
-                    hir::ItemStatic(..) => {
-                        let def_id = tcx.hir.local_def_id(id);
-                        tcx.construct_parameter_environment(item.span,
-                                                            def_id,
-                                                            Some(tcx.item_extent(id)))
-                    }
                     hir::ItemTrait(..) => {
                         let def_id = tcx.hir.local_def_id(id);
                         tcx.construct_parameter_environment(item.span,
index e3d1761dfffdbe6f3ce1c9029f211fea9e693f95..b276589f0c47b1ed0b4136853d07799664f34238 100644 (file)
@@ -27,6 +27,12 @@ impl Foo for Def {
     const X: i32 = 97;
 }
 
+struct Proxy<T>(T);
+
+impl<T: Foo> Foo for Proxy<T> {
+    const X: i32 = T::X;
+}
+
 fn sub<A: Foo, B: Foo>() -> i32 {
     A::X - B::X
 }
@@ -38,4 +44,7 @@ fn main() {
     assert_eq!(97, Def::get_x());
     assert_eq!(-86, sub::<Abc, Def>());
     assert_eq!(86, sub::<Def, Abc>());
+    assert_eq!(-86, sub::<Proxy<Abc>, Def>());
+    assert_eq!(-86, sub::<Abc, Proxy<Def>>());
+    assert_eq!(86, sub::<Proxy<Def>, Proxy<Abc>>());
 }