Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

rustc: treat const bodies like fn bodies in middle::region. #41515

Merged
merged 1 commit into from
May 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
19 changes: 14 additions & 5 deletions src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,27 +442,36 @@ 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<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 {
bug!("no entry for id `{}`", id)
}
}

/// 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,
Expand Down
160 changes: 65 additions & 95 deletions src/librustc/middle/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand All @@ -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<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,
Expand All @@ -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)
Expand Down
48 changes: 15 additions & 33 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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),
Expand All @@ -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,
Expand Down
9 changes: 9 additions & 0 deletions src/test/run-pass/associated-const-type-parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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>>());
}