Skip to content

Commit f1140a3

Browse files
committed
Auto merge of #41515 - eddyb:non-static-assoc-const, r=nikomatsakis
rustc: treat const bodies like fn bodies in middle::region. Allows `T::ASSOC_CONST` to be used without a `T: 'static` bound. cc @rust-lang/compiler @rust-lang/lang
2 parents 20de961 + 90af729 commit f1140a3

File tree

5 files changed

+103
-150
lines changed

5 files changed

+103
-150
lines changed

src/librustc/hir/intravisit.rs

-17
Original file line numberDiff line numberDiff line change
@@ -140,23 +140,6 @@ impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> {
140140
/// to monitor future changes to `Visitor` in case a new method with a
141141
/// new default implementation gets introduced.)
142142
pub trait Visitor<'v> : Sized {
143-
/// Invokes the suitable visitor method for the given `Node`
144-
/// extracted from the hir map.
145-
fn visit_hir_map_node(&mut self, node: map::Node<'v>) {
146-
match node {
147-
map::NodeItem(a) => self.visit_item(a),
148-
map::NodeForeignItem(a) => self.visit_foreign_item(a),
149-
map::NodeTraitItem(a) => self.visit_trait_item(a),
150-
map::NodeImplItem(a) => self.visit_impl_item(a),
151-
map::NodeExpr(a) => self.visit_expr(a),
152-
map::NodeStmt(a) => self.visit_stmt(a),
153-
map::NodeTy(a) => self.visit_ty(a),
154-
map::NodePat(a) => self.visit_pat(a),
155-
map::NodeBlock(a) => self.visit_block(a),
156-
_ => bug!("Visitor::visit_hir_map_node() not yet impl for node `{:?}`", node)
157-
}
158-
}
159-
160143
///////////////////////////////////////////////////////////////////////////
161144
// Nested items.
162145

src/librustc/hir/map/mod.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -442,27 +442,36 @@ impl<'hir> Map<'hir> {
442442
self.local_def_id(self.body_owner(id))
443443
}
444444

445-
/// Given a body owner's id, returns the `BodyId` associated with it.
446-
pub fn body_owned_by(&self, id: NodeId) -> BodyId {
445+
/// Given a node id, returns the `BodyId` associated with it,
446+
/// if the node is a body owner, otherwise returns `None`.
447+
pub fn maybe_body_owned_by(&self, id: NodeId) -> Option<BodyId> {
447448
if let Some(entry) = self.find_entry(id) {
448449
if let Some(body_id) = entry.associated_body() {
449450
// For item-like things and closures, the associated
450451
// body has its own distinct id, and that is returned
451452
// by `associated_body`.
452-
body_id
453+
Some(body_id)
453454
} else {
454455
// For some expressions, the expression is its own body.
455456
if let EntryExpr(_, expr) = entry {
456-
BodyId { node_id: expr.id }
457+
Some(BodyId { node_id: expr.id })
457458
} else {
458-
span_bug!(self.span(id), "id `{}` has no associated body: {:?}", id, entry);
459+
None
459460
}
460461
}
461462
} else {
462463
bug!("no entry for id `{}`", id)
463464
}
464465
}
465466

467+
/// Given a body owner's id, returns the `BodyId` associated with it.
468+
pub fn body_owned_by(&self, id: NodeId) -> BodyId {
469+
self.maybe_body_owned_by(id).unwrap_or_else(|| {
470+
span_bug!(self.span(id), "body_owned_by: {} has no associated body",
471+
self.node_to_string(id));
472+
})
473+
}
474+
466475
pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
467476
match self.get(id) {
468477
NodeItem(&Item { node: ItemTrait(..), .. }) => id,

src/librustc/middle/region.rs

+65-95
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,16 @@ use std::mem;
2424
use std::rc::Rc;
2525
use serialize;
2626
use syntax::codemap;
27-
use syntax::ast::{self, NodeId};
27+
use syntax::ast;
2828
use syntax_pos::Span;
2929
use ty::TyCtxt;
3030
use ty::maps::Providers;
3131

32-
use hir; use hir::def_id::DefId;
33-
use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
34-
use hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local};
32+
use hir;
33+
use hir::def_id::DefId;
34+
use hir::intravisit::{self, Visitor, NestedVisitorMap};
35+
use hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local};
36+
use mir::transform::MirSource;
3537

3638
pub type CodeExtent<'tcx> = &'tcx CodeExtentData;
3739

@@ -811,7 +813,17 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
811813
}
812814
}
813815

814-
intravisit::walk_expr(visitor, expr);
816+
match expr.node {
817+
// Manually recurse over closures, because they are the only
818+
// case of nested bodies that share the parent environment.
819+
hir::ExprClosure(.., body, _) => {
820+
let body = visitor.tcx.hir.body(body);
821+
visitor.visit_body(body);
822+
}
823+
824+
_ => intravisit::walk_expr(visitor, expr)
825+
}
826+
815827
visitor.cx = prev_cx;
816828
}
817829

@@ -1041,74 +1053,6 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
10411053
}
10421054
}
10431055

1044-
fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, walk: F)
1045-
where F: FnOnce(&mut RegionResolutionVisitor<'a, 'tcx>)
1046-
{
1047-
// Items create a new outer block scope as far as we're concerned.
1048-
let prev_cx = visitor.cx;
1049-
let prev_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
1050-
visitor.cx = Context {
1051-
root_id: None,
1052-
var_parent: None,
1053-
parent: None,
1054-
};
1055-
walk(visitor);
1056-
visitor.cx = prev_cx;
1057-
visitor.terminating_scopes = prev_ts;
1058-
}
1059-
1060-
fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
1061-
kind: FnKind<'tcx>,
1062-
decl: &'tcx hir::FnDecl,
1063-
body_id: hir::BodyId,
1064-
sp: Span,
1065-
id: ast::NodeId) {
1066-
visitor.cx.parent = Some(visitor.new_code_extent(
1067-
CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id }));
1068-
1069-
debug!("region::resolve_fn(id={:?}, \
1070-
span={:?}, \
1071-
body.id={:?}, \
1072-
cx.parent={:?})",
1073-
id,
1074-
visitor.tcx.sess.codemap().span_to_string(sp),
1075-
body_id,
1076-
visitor.cx.parent);
1077-
1078-
let fn_decl_scope = visitor.new_code_extent(
1079-
CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id });
1080-
1081-
if let Some(root_id) = visitor.cx.root_id {
1082-
visitor.region_maps.record_fn_parent(body_id.node_id, root_id);
1083-
}
1084-
1085-
let outer_cx = visitor.cx;
1086-
let outer_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
1087-
visitor.terminating_scopes.insert(body_id.node_id);
1088-
1089-
// The arguments and `self` are parented to the fn.
1090-
visitor.cx = Context {
1091-
root_id: Some(body_id.node_id),
1092-
parent: None,
1093-
var_parent: Some(fn_decl_scope),
1094-
};
1095-
1096-
intravisit::walk_fn_decl(visitor, decl);
1097-
intravisit::walk_fn_kind(visitor, kind);
1098-
1099-
// The body of the every fn is a root scope.
1100-
visitor.cx = Context {
1101-
root_id: Some(body_id.node_id),
1102-
parent: Some(fn_decl_scope),
1103-
var_parent: Some(fn_decl_scope),
1104-
};
1105-
visitor.visit_nested_body(body_id);
1106-
1107-
// Restore context we had at the start.
1108-
visitor.cx = outer_cx;
1109-
visitor.terminating_scopes = outer_ts;
1110-
}
1111-
11121056
impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
11131057
pub fn intern_code_extent(&mut self,
11141058
data: CodeExtentData,
@@ -1152,29 +1096,57 @@ impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
11521096

11531097
impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
11541098
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
1155-
NestedVisitorMap::OnlyBodies(&self.map)
1099+
NestedVisitorMap::None
11561100
}
11571101

11581102
fn visit_block(&mut self, b: &'tcx Block) {
11591103
resolve_block(self, b);
11601104
}
11611105

1162-
fn visit_item(&mut self, i: &'tcx Item) {
1163-
resolve_item_like(self, |this| intravisit::walk_item(this, i));
1164-
}
1106+
fn visit_body(&mut self, body: &'tcx hir::Body) {
1107+
let body_id = body.id();
1108+
let owner_id = self.map.body_owner(body_id);
11651109

1166-
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
1167-
resolve_item_like(self, |this| intravisit::walk_impl_item(this, ii));
1168-
}
1110+
debug!("visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})",
1111+
owner_id,
1112+
self.tcx.sess.codemap().span_to_string(body.value.span),
1113+
body_id,
1114+
self.cx.parent);
11691115

1170-
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
1171-
resolve_item_like(self, |this| intravisit::walk_trait_item(this, ti));
1172-
}
1116+
let outer_cx = self.cx;
1117+
let outer_ts = mem::replace(&mut self.terminating_scopes, NodeSet());
11731118

1174-
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx FnDecl,
1175-
b: hir::BodyId, s: Span, n: NodeId) {
1176-
resolve_fn(self, fk, fd, b, s, n);
1119+
// Only functions have an outer terminating (drop) scope,
1120+
// while temporaries in constant initializers are 'static.
1121+
if let MirSource::Fn(_) = MirSource::from_node(self.tcx, owner_id) {
1122+
self.terminating_scopes.insert(body_id.node_id);
1123+
}
1124+
1125+
if let Some(root_id) = self.cx.root_id {
1126+
self.region_maps.record_fn_parent(body_id.node_id, root_id);
1127+
}
1128+
self.cx.root_id = Some(body_id.node_id);
1129+
1130+
self.cx.parent = Some(self.new_code_extent(
1131+
CodeExtentData::CallSiteScope { fn_id: owner_id, body_id: body_id.node_id }));
1132+
self.cx.parent = Some(self.new_code_extent(
1133+
CodeExtentData::ParameterScope { fn_id: owner_id, body_id: body_id.node_id }));
1134+
1135+
// The arguments and `self` are parented to the fn.
1136+
self.cx.var_parent = self.cx.parent.take();
1137+
for argument in &body.arguments {
1138+
self.visit_pat(&argument.pat);
1139+
}
1140+
1141+
// The body of the every fn is a root scope.
1142+
self.cx.parent = self.cx.var_parent;
1143+
self.visit_expr(&body.value);
1144+
1145+
// Restore context we had at the start.
1146+
self.cx = outer_cx;
1147+
self.terminating_scopes = outer_ts;
11771148
}
1149+
11781150
fn visit_arm(&mut self, a: &'tcx Arm) {
11791151
resolve_arm(self, a);
11801152
}
@@ -1192,21 +1164,18 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
11921164
}
11931165
}
11941166

1195-
fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_id: DefId)
1167+
fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
11961168
-> Rc<RegionMaps<'tcx>>
11971169
{
1198-
let closure_base_def_id = tcx.closure_base_def_id(fn_id);
1199-
if closure_base_def_id != fn_id {
1170+
let closure_base_def_id = tcx.closure_base_def_id(def_id);
1171+
if closure_base_def_id != def_id {
12001172
return tcx.region_maps(closure_base_def_id);
12011173
}
12021174

12031175
let mut maps = RegionMaps::new();
12041176

1205-
let fn_node_id = tcx.hir.as_local_node_id(fn_id)
1206-
.expect("fn DefId should be for LOCAL_CRATE");
1207-
let node = tcx.hir.get(fn_node_id);
1208-
1209-
{
1177+
let id = tcx.hir.as_local_node_id(def_id).unwrap();
1178+
if let Some(body) = tcx.hir.maybe_body_owned_by(id) {
12101179
let mut visitor = RegionResolutionVisitor {
12111180
tcx: tcx,
12121181
region_maps: &mut maps,
@@ -1218,7 +1187,8 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_id: DefId)
12181187
},
12191188
terminating_scopes: NodeSet(),
12201189
};
1221-
visitor.visit_hir_map_node(node);
1190+
1191+
visitor.visit_body(tcx.hir.body(body));
12221192
}
12231193

12241194
Rc::new(maps)

src/librustc/ty/mod.rs

+15-33
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
12381238
match tcx.hir.find(id) {
12391239
Some(hir_map::NodeImplItem(ref impl_item)) => {
12401240
match impl_item.node {
1241-
hir::ImplItemKind::Type(_) | hir::ImplItemKind::Const(..) => {
1241+
hir::ImplItemKind::Type(_) => {
12421242
// associated types don't have their own entry (for some reason),
12431243
// so for now just grab environment for the impl
12441244
let impl_id = tcx.hir.get_parent(id);
@@ -1247,7 +1247,8 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
12471247
impl_def_id,
12481248
Some(tcx.item_extent(id)))
12491249
}
1250-
hir::ImplItemKind::Method(_, ref body) => {
1250+
hir::ImplItemKind::Const(_, body) |
1251+
hir::ImplItemKind::Method(_, body) => {
12511252
tcx.construct_parameter_environment(
12521253
impl_item.span,
12531254
tcx.hir.local_def_id(id),
@@ -1257,56 +1258,37 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
12571258
}
12581259
Some(hir_map::NodeTraitItem(trait_item)) => {
12591260
match trait_item.node {
1260-
hir::TraitItemKind::Type(..) | hir::TraitItemKind::Const(..) => {
1261-
// associated types don't have their own entry (for some reason),
1262-
// so for now just grab environment for the trait
1263-
let trait_id = tcx.hir.get_parent(id);
1264-
let trait_def_id = tcx.hir.local_def_id(trait_id);
1261+
hir::TraitItemKind::Type(..) |
1262+
hir::TraitItemKind::Const(_, None) |
1263+
hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_))=> {
12651264
tcx.construct_parameter_environment(trait_item.span,
1266-
trait_def_id,
1265+
tcx.hir.local_def_id(id),
12671266
Some(tcx.item_extent(id)))
12681267
}
1269-
hir::TraitItemKind::Method(_, ref body) => {
1270-
// Use call-site for extent (unless this is a
1271-
// trait method with no default; then fallback
1272-
// to the method id).
1273-
let extent = if let hir::TraitMethod::Provided(body_id) = *body {
1274-
// default impl: use call_site extent as free_id_outlive bound.
1275-
tcx.call_site_extent(id, body_id.node_id)
1276-
} else {
1277-
// no default impl: use item extent as free_id_outlive bound.
1278-
tcx.item_extent(id)
1279-
};
1268+
hir::TraitItemKind::Const(_, Some(body)) |
1269+
hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body)) => {
12801270
tcx.construct_parameter_environment(
12811271
trait_item.span,
12821272
tcx.hir.local_def_id(id),
1283-
Some(extent))
1273+
Some(tcx.call_site_extent(id, body.node_id)))
12841274
}
12851275
}
12861276
}
12871277
Some(hir_map::NodeItem(item)) => {
12881278
match item.node {
1289-
hir::ItemFn(.., body_id) => {
1290-
// We assume this is a function.
1291-
let fn_def_id = tcx.hir.local_def_id(id);
1292-
1279+
hir::ItemConst(_, body) |
1280+
hir::ItemStatic(.., body) |
1281+
hir::ItemFn(.., body) => {
12931282
tcx.construct_parameter_environment(
12941283
item.span,
1295-
fn_def_id,
1296-
Some(tcx.call_site_extent(id, body_id.node_id)))
1284+
tcx.hir.local_def_id(id),
1285+
Some(tcx.call_site_extent(id, body.node_id)))
12971286
}
12981287
hir::ItemEnum(..) |
12991288
hir::ItemStruct(..) |
13001289
hir::ItemUnion(..) |
13011290
hir::ItemTy(..) |
13021291
hir::ItemImpl(..) |
1303-
hir::ItemConst(..) |
1304-
hir::ItemStatic(..) => {
1305-
let def_id = tcx.hir.local_def_id(id);
1306-
tcx.construct_parameter_environment(item.span,
1307-
def_id,
1308-
Some(tcx.item_extent(id)))
1309-
}
13101292
hir::ItemTrait(..) => {
13111293
let def_id = tcx.hir.local_def_id(id);
13121294
tcx.construct_parameter_environment(item.span,

src/test/run-pass/associated-const-type-parameters.rs

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ impl Foo for Def {
2727
const X: i32 = 97;
2828
}
2929

30+
struct Proxy<T>(T);
31+
32+
impl<T: Foo> Foo for Proxy<T> {
33+
const X: i32 = T::X;
34+
}
35+
3036
fn sub<A: Foo, B: Foo>() -> i32 {
3137
A::X - B::X
3238
}
@@ -38,4 +44,7 @@ fn main() {
3844
assert_eq!(97, Def::get_x());
3945
assert_eq!(-86, sub::<Abc, Def>());
4046
assert_eq!(86, sub::<Def, Abc>());
47+
assert_eq!(-86, sub::<Proxy<Abc>, Def>());
48+
assert_eq!(-86, sub::<Abc, Proxy<Def>>());
49+
assert_eq!(86, sub::<Proxy<Def>, Proxy<Abc>>());
4150
}

0 commit comments

Comments
 (0)