diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index def6b2b3421f6..836d9775a3f69 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -140,23 +140,6 @@ impl<'this, 'tcx> NestedVisitorMap<'this, '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. diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index abc967dec905c..c715484a934df 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -442,20 +442,21 @@ impl<'hir> Map<'hir> { 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 { 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 @@ impl<'hir> Map<'hir> { } } + /// 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, diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index d1d5e9d6cb18f..087ab4b94da3d 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -24,14 +24,16 @@ use std::mem; 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 resolve_local<'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 @@ impl<'a, 'tcx> RegionResolutionVisitor<'a, '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 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> { } } -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> { - 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) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a361c80a2529f..99a5f6325ac75 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1238,7 +1238,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { 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 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { 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 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { } 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, diff --git a/src/test/run-pass/associated-const-type-parameters.rs b/src/test/run-pass/associated-const-type-parameters.rs index e3d1761dfffdb..b276589f0c47b 100644 --- a/src/test/run-pass/associated-const-type-parameters.rs +++ b/src/test/run-pass/associated-const-type-parameters.rs @@ -27,6 +27,12 @@ impl Foo for Def { const X: i32 = 97; } +struct Proxy(T); + +impl Foo for Proxy { + const X: i32 = T::X; +} + fn sub() -> i32 { A::X - B::X } @@ -38,4 +44,7 @@ fn main() { assert_eq!(97, Def::get_x()); assert_eq!(-86, sub::()); assert_eq!(86, sub::()); + assert_eq!(-86, sub::, Def>()); + assert_eq!(-86, sub::>()); + assert_eq!(86, sub::, Proxy>()); }