Skip to content

Commit f50dbd5

Browse files
authored
Auto merge of #37918 - flodiebold:separate-bodies, r=nikomatsakis
Separate function bodies from their signatures in HIR Also give them their own dep map node. I'm still unhappy with the handling of inlined items (1452edc1), but maybe you have a suggestion how to improve it. Fixes #35078. r? @nikomatsakis
2 parents 5de15be + 593b273 commit f50dbd5

File tree

81 files changed

+1807
-908
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1807
-908
lines changed

src/librustc/dep_graph/dep_node.rs

+8
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ pub enum DepNode<D: Clone + Debug> {
4242
// Represents the HIR node with the given node-id
4343
Hir(D),
4444

45+
// Represents the body of a function or method. The def-id is that of the
46+
// function/method.
47+
HirBody(D),
48+
4549
// Represents the metadata for a given HIR node, typically found
4650
// in an extern crate.
4751
MetaData(D),
@@ -59,6 +63,7 @@ pub enum DepNode<D: Clone + Debug> {
5963
PluginRegistrar,
6064
StabilityIndex,
6165
CollectItem(D),
66+
CollectItemSig(D),
6267
Coherence,
6368
EffectCheck,
6469
Liveness,
@@ -150,6 +155,7 @@ impl<D: Clone + Debug> DepNode<D> {
150155
CollectItem,
151156
BorrowCheck,
152157
Hir,
158+
HirBody,
153159
TransCrateItem,
154160
TypeckItemType,
155161
TypeckItemBody,
@@ -199,8 +205,10 @@ impl<D: Clone + Debug> DepNode<D> {
199205
WorkProduct(ref id) => Some(WorkProduct(id.clone())),
200206

201207
Hir(ref d) => op(d).map(Hir),
208+
HirBody(ref d) => op(d).map(HirBody),
202209
MetaData(ref d) => op(d).map(MetaData),
203210
CollectItem(ref d) => op(d).map(CollectItem),
211+
CollectItemSig(ref d) => op(d).map(CollectItemSig),
204212
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
205213
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
206214
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),

src/librustc/hir/intravisit.rs

+120-38
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,62 @@ impl<'a> FnKind<'a> {
6767
}
6868
}
6969

70+
/// Specifies what nested things a visitor wants to visit. The most
71+
/// common choice is `OnlyBodies`, which will cause the visitor to
72+
/// visit fn bodies for fns that it encounters, but skip over nested
73+
/// item-like things.
74+
///
75+
/// See the comments on `ItemLikeVisitor` for more details on the overall
76+
/// visit strategy.
77+
pub enum NestedVisitorMap<'this, 'tcx: 'this> {
78+
/// Do not visit any nested things. When you add a new
79+
/// "non-nested" thing, you will want to audit such uses to see if
80+
/// they remain valid.
81+
///
82+
/// Use this if you are only walking some particular kind of tree
83+
/// (i.e., a type, or fn signature) and you don't want to thread a
84+
/// HIR map around.
85+
None,
86+
87+
/// Do not visit nested item-like things, but visit nested things
88+
/// that are inside of an item-like.
89+
///
90+
/// **This is the most common choice.** A very commmon pattern is
91+
/// to use `tcx.visit_all_item_likes_in_krate()` as an outer loop,
92+
/// and to have the visitor that visits the contents of each item
93+
/// using this setting.
94+
OnlyBodies(&'this Map<'tcx>),
95+
96+
/// Visit all nested things, including item-likes.
97+
///
98+
/// **This is an unusual choice.** It is used when you want to
99+
/// process everything within their lexical context. Typically you
100+
/// kick off the visit by doing `walk_krate()`.
101+
All(&'this Map<'tcx>),
102+
}
103+
104+
impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> {
105+
/// Returns the map to use for an "intra item-like" thing (if any).
106+
/// e.g., function body.
107+
pub fn intra(self) -> Option<&'this Map<'tcx>> {
108+
match self {
109+
NestedVisitorMap::None => None,
110+
NestedVisitorMap::OnlyBodies(map) => Some(map),
111+
NestedVisitorMap::All(map) => Some(map),
112+
}
113+
}
114+
115+
/// Returns the map to use for an "item-like" thing (if any).
116+
/// e.g., item, impl-item.
117+
pub fn inter(self) -> Option<&'this Map<'tcx>> {
118+
match self {
119+
NestedVisitorMap::None => None,
120+
NestedVisitorMap::OnlyBodies(_) => None,
121+
NestedVisitorMap::All(map) => Some(map),
122+
}
123+
}
124+
}
125+
70126
/// Each method of the Visitor trait is a hook to be potentially
71127
/// overridden. Each method's default implementation recursively visits
72128
/// the substructure of the input via the corresponding `walk` method;
@@ -88,23 +144,22 @@ pub trait Visitor<'v> : Sized {
88144
// Nested items.
89145

90146
/// The default versions of the `visit_nested_XXX` routines invoke
91-
/// this method to get a map to use; if they get back `None`, they
92-
/// just skip nested things. Otherwise, they will lookup the
93-
/// nested item-like things in the map and visit it. So the best
94-
/// way to implement a nested visitor is to override this method
95-
/// to return a `Map`; one advantage of this is that if we add
96-
/// more types of nested things in the future, they will
97-
/// automatically work.
147+
/// this method to get a map to use. By selecting an enum variant,
148+
/// you control which kinds of nested HIR are visited; see
149+
/// `NestedVisitorMap` for details. By "nested HIR", we are
150+
/// referring to bits of HIR that are not directly embedded within
151+
/// one another but rather indirectly, through a table in the
152+
/// crate. This is done to control dependencies during incremental
153+
/// compilation: the non-inline bits of HIR can be tracked and
154+
/// hashed separately.
98155
///
99156
/// **If for some reason you want the nested behavior, but don't
100157
/// have a `Map` are your disposal:** then you should override the
101158
/// `visit_nested_XXX` methods, and override this method to
102159
/// `panic!()`. This way, if a new `visit_nested_XXX` variant is
103160
/// added in the future, we will see the panic in your code and
104161
/// fix it appropriately.
105-
fn nested_visit_map(&mut self) -> Option<&Map<'v>> {
106-
None
107-
}
162+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v>;
108163

109164
/// Invoked when a nested item is encountered. By default does
110165
/// nothing unless you override `nested_visit_map` to return
@@ -116,8 +171,7 @@ pub trait Visitor<'v> : Sized {
116171
/// but cannot supply a `Map`; see `nested_visit_map` for advice.
117172
#[allow(unused_variables)]
118173
fn visit_nested_item(&mut self, id: ItemId) {
119-
let opt_item = self.nested_visit_map()
120-
.map(|map| map.expect_item(id.id));
174+
let opt_item = self.nested_visit_map().inter().map(|map| map.expect_item(id.id));
121175
if let Some(item) = opt_item {
122176
self.visit_item(item);
123177
}
@@ -128,13 +182,23 @@ pub trait Visitor<'v> : Sized {
128182
/// method.
129183
#[allow(unused_variables)]
130184
fn visit_nested_impl_item(&mut self, id: ImplItemId) {
131-
let opt_item = self.nested_visit_map()
132-
.map(|map| map.impl_item(id));
185+
let opt_item = self.nested_visit_map().inter().map(|map| map.impl_item(id));
133186
if let Some(item) = opt_item {
134187
self.visit_impl_item(item);
135188
}
136189
}
137190

191+
/// Invoked to visit the body of a function, method or closure. Like
192+
/// visit_nested_item, does nothing by default unless you override
193+
/// `nested_visit_map` to return `Some(_)`, in which case it will walk the
194+
/// body.
195+
fn visit_body(&mut self, id: ExprId) {
196+
let opt_expr = self.nested_visit_map().intra().map(|map| map.expr(id));
197+
if let Some(expr) = opt_expr {
198+
self.visit_expr(expr);
199+
}
200+
}
201+
138202
/// Visit the top-level item and (optionally) nested items / impl items. See
139203
/// `visit_nested_item` for details.
140204
fn visit_item(&mut self, i: &'v Item) {
@@ -200,7 +264,7 @@ pub trait Visitor<'v> : Sized {
200264
fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) {
201265
walk_where_predicate(self, predicate)
202266
}
203-
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Expr, s: Span, id: NodeId) {
267+
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: ExprId, s: Span, id: NodeId) {
204268
walk_fn(self, fk, fd, b, s, id)
205269
}
206270
fn visit_trait_item(&mut self, ti: &'v TraitItem) {
@@ -363,7 +427,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
363427
visitor.visit_ty(typ);
364428
visitor.visit_expr(expr);
365429
}
366-
ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => {
430+
ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => {
367431
visitor.visit_fn(FnKind::ItemFn(item.name,
368432
generics,
369433
unsafety,
@@ -372,7 +436,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
372436
&item.vis,
373437
&item.attrs),
374438
declaration,
375-
body,
439+
body_id,
376440
item.span,
377441
item.id)
378442
}
@@ -697,13 +761,25 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
697761
pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
698762
function_kind: FnKind<'v>,
699763
function_declaration: &'v FnDecl,
700-
function_body: &'v Expr,
764+
body_id: ExprId,
701765
_span: Span,
702766
id: NodeId) {
703767
visitor.visit_id(id);
704768
walk_fn_decl(visitor, function_declaration);
705769
walk_fn_kind(visitor, function_kind);
706-
visitor.visit_expr(function_body)
770+
visitor.visit_body(body_id)
771+
}
772+
773+
pub fn walk_fn_with_body<'v, V: Visitor<'v>>(visitor: &mut V,
774+
function_kind: FnKind<'v>,
775+
function_declaration: &'v FnDecl,
776+
body: &'v Expr,
777+
_span: Span,
778+
id: NodeId) {
779+
visitor.visit_id(id);
780+
walk_fn_decl(visitor, function_declaration);
781+
walk_fn_kind(visitor, function_kind);
782+
visitor.visit_expr(body)
707783
}
708784

709785
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
@@ -720,13 +796,13 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
720796
visitor.visit_generics(&sig.generics);
721797
walk_fn_decl(visitor, &sig.decl);
722798
}
723-
MethodTraitItem(ref sig, Some(ref body)) => {
799+
MethodTraitItem(ref sig, Some(body_id)) => {
724800
visitor.visit_fn(FnKind::Method(trait_item.name,
725801
sig,
726802
None,
727803
&trait_item.attrs),
728804
&sig.decl,
729-
body,
805+
body_id,
730806
trait_item.span,
731807
trait_item.id);
732808
}
@@ -752,13 +828,13 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
752828
visitor.visit_ty(ty);
753829
visitor.visit_expr(expr);
754830
}
755-
ImplItemKind::Method(ref sig, ref body) => {
831+
ImplItemKind::Method(ref sig, body_id) => {
756832
visitor.visit_fn(FnKind::Method(impl_item.name,
757833
sig,
758834
Some(&impl_item.vis),
759835
&impl_item.attrs),
760836
&sig.decl,
761-
body,
837+
body_id,
762838
impl_item.span,
763839
impl_item.id);
764840
}
@@ -883,7 +959,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
883959
visitor.visit_expr(subexpression);
884960
walk_list!(visitor, visit_arm, arms);
885961
}
886-
ExprClosure(_, ref function_declaration, ref body, _fn_decl_span) => {
962+
ExprClosure(_, ref function_declaration, body, _fn_decl_span) => {
887963
visitor.visit_fn(FnKind::Closure(&expression.attrs),
888964
function_declaration,
889965
body,
@@ -998,34 +1074,40 @@ impl IdRange {
9981074
}
9991075

10001076

1001-
pub struct IdRangeComputingVisitor {
1002-
pub result: IdRange,
1077+
pub struct IdRangeComputingVisitor<'a, 'ast: 'a> {
1078+
result: IdRange,
1079+
map: &'a map::Map<'ast>,
10031080
}
10041081

1005-
impl IdRangeComputingVisitor {
1006-
pub fn new() -> IdRangeComputingVisitor {
1007-
IdRangeComputingVisitor { result: IdRange::max() }
1082+
impl<'a, 'ast> IdRangeComputingVisitor<'a, 'ast> {
1083+
pub fn new(map: &'a map::Map<'ast>) -> IdRangeComputingVisitor<'a, 'ast> {
1084+
IdRangeComputingVisitor { result: IdRange::max(), map: map }
10081085
}
10091086

10101087
pub fn result(&self) -> IdRange {
10111088
self.result
10121089
}
10131090
}
10141091

1015-
impl<'v> Visitor<'v> for IdRangeComputingVisitor {
1092+
impl<'a, 'ast> Visitor<'ast> for IdRangeComputingVisitor<'a, 'ast> {
1093+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'ast> {
1094+
NestedVisitorMap::OnlyBodies(&self.map)
1095+
}
1096+
10161097
fn visit_id(&mut self, id: NodeId) {
10171098
self.result.add(id);
10181099
}
10191100
}
10201101

10211102
/// Computes the id range for a single fn body, ignoring nested items.
1022-
pub fn compute_id_range_for_fn_body(fk: FnKind,
1023-
decl: &FnDecl,
1024-
body: &Expr,
1025-
sp: Span,
1026-
id: NodeId)
1027-
-> IdRange {
1028-
let mut visitor = IdRangeComputingVisitor::new();
1029-
visitor.visit_fn(fk, decl, body, sp, id);
1103+
pub fn compute_id_range_for_fn_body<'v>(fk: FnKind<'v>,
1104+
decl: &'v FnDecl,
1105+
body: &'v Expr,
1106+
sp: Span,
1107+
id: NodeId,
1108+
map: &map::Map<'v>)
1109+
-> IdRange {
1110+
let mut visitor = IdRangeComputingVisitor::new(map);
1111+
walk_fn_with_body(&mut visitor, fk, decl, body, sp, id);
10301112
visitor.result()
10311113
}

src/librustc/hir/itemlikevisit.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ use super::intravisit::Visitor;
4141
/// item-like things.
4242
/// - Example: Lifetime resolution, which wants to bring lifetimes declared on the
4343
/// impl into scope while visiting the impl-items, and then back out again.
44-
/// - How: Implement `intravisit::Visitor` and override the `visit_nested_foo()` foo methods
45-
/// as needed. Walk your crate with `intravisit::walk_crate()` invoked on `tcx.map.krate()`.
44+
/// - How: Implement `intravisit::Visitor` and override the
45+
/// `visit_nested_map()` methods to return
46+
/// `NestedVisitorMap::All`. Walk your crate with
47+
/// `intravisit::walk_crate()` invoked on `tcx.map.krate()`.
4648
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
4749
/// - Pro: Preserves nesting information
4850
/// - Con: Does not integrate well into dependency tracking.

0 commit comments

Comments
 (0)