Skip to content

Commit 94acff1

Browse files
committed
replace graph rewriting with detecting inlined ids
We now detect inlined id's earlier (in the HIR map) and rewrite a read of them to be a read of the metadata for the associated item.
1 parent 903142a commit 94acff1

File tree

12 files changed

+154
-129
lines changed

12 files changed

+154
-129
lines changed

src/librustc/dep_graph/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ to read from it. Similarly, reading from the `tcache` map for item `X`
134134
(which is a `DepTrackingMap`, described below) automatically invokes
135135
`dep_graph.read(ItemSignature(X))`.
136136

137+
**Note:** adding `Hir` nodes requires a bit of caution due to the
138+
"inlining" that old trans and constant evaluation still use. See the
139+
section on inlining below.
140+
137141
To make this strategy work, a certain amount of indirection is
138142
required. For example, modules in the HIR do not have direct pointers
139143
to the items that they contain. Rather, they contain node-ids -- one
@@ -387,3 +391,24 @@ RUST_DEP_GRAPH_FILTER='Hir&foo -> TypeckItemBody & bar'
387391
This will dump out all the nodes that lead from `Hir(foo)` to
388392
`TypeckItemBody(bar)`, from which you can (hopefully) see the source
389393
of the erroneous edge.
394+
395+
### Inlining of HIR nodes
396+
397+
For the time being, at least, we still sometimes "inline" HIR nodes
398+
from other crates into the current HIR map. This creates a weird
399+
scenario where the same logical item (let's call it `X`) has two
400+
def-ids: the original def-id `X` and a new, inlined one `X'`. `X'` is
401+
in the current crate, but it's not like other HIR nodes: in
402+
particular, when we restart compilation, it will not be available to
403+
hash. Therefore, we do not want `Hir(X')` nodes appearing in our
404+
graph. Instead, we want a "read" of `Hir(X')` to be represented as a
405+
read of `MetaData(X)`, since the metadata for `X` is where the inlined
406+
representation originated in the first place.
407+
408+
To achieve this, the HIR map will detect if the def-id originates in
409+
an inlined node and add a dependency to a suitable `MetaData` node
410+
instead. If you are reading a HIR node and are not sure if it may be
411+
inlined or not, you can use `tcx.map.read(node_id)` and it will detect
412+
whether the node is inlined or not and do the right thing. You can
413+
also use `tcx.map.is_inlined_def_id()` and
414+
`tcx.map.is_inlined_node_id()` to test.

src/librustc/dep_graph/visit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
4141
let task_id = (self.dep_node_fn)(item_def_id);
4242
let _task = self.tcx.dep_graph.in_task(task_id.clone());
4343
debug!("Started task {:?}", task_id);
44+
assert!(!self.tcx.map.is_inlined_def_id(item_def_id));
4445
self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
4546
self.visitor.visit_item(i);
4647
debug!("Ended task {:?}", task_id);

src/librustc/hir/map/mod.rs

Lines changed: 90 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -226,60 +226,99 @@ impl<'ast> Map<'ast> {
226226
/// otherwise have had access to those contents, and hence needs a
227227
/// read recorded). If the function just returns a DefId or
228228
/// NodeId, no actual content was returned, so no read is needed.
229-
fn read(&self, id: NodeId) {
229+
pub fn read(&self, id: NodeId) {
230230
self.dep_graph.read(self.dep_node(id));
231231
}
232232

233233
fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
234234
let map = self.map.borrow();
235235
let mut id = id0;
236-
loop {
237-
match map[id as usize] {
238-
EntryItem(_, item) => {
239-
let def_id = self.local_def_id(item.id);
240-
// NB ^~~~~~~
241-
//
242-
// You would expect that `item.id == id`, but this
243-
// is not always the case. In particular, for a
244-
// ViewPath item like `use self::{mem, foo}`, we
245-
// map the ids for `mem` and `foo` to the
246-
// enclosing view path item. This seems mega super
247-
// ultra wrong, but then who am I to judge?
248-
// -nmatsakis
249-
return DepNode::Hir(def_id);
250-
}
236+
if !self.is_inlined_node_id(id) {
237+
loop {
238+
match map[id as usize] {
239+
EntryItem(_, item) => {
240+
let def_id = self.local_def_id(item.id);
241+
// NB ^~~~~~~
242+
//
243+
// You would expect that `item.id == id`, but this
244+
// is not always the case. In particular, for a
245+
// ViewPath item like `use self::{mem, foo}`, we
246+
// map the ids for `mem` and `foo` to the
247+
// enclosing view path item. This seems mega super
248+
// ultra wrong, but then who am I to judge?
249+
// -nmatsakis
250+
assert!(!self.is_inlined_def_id(def_id));
251+
return DepNode::Hir(def_id);
252+
}
251253

252-
EntryForeignItem(p, _) |
253-
EntryTraitItem(p, _) |
254-
EntryImplItem(p, _) |
255-
EntryVariant(p, _) |
256-
EntryExpr(p, _) |
257-
EntryStmt(p, _) |
258-
EntryLocal(p, _) |
259-
EntryPat(p, _) |
260-
EntryBlock(p, _) |
261-
EntryStructCtor(p, _) |
262-
EntryLifetime(p, _) |
263-
EntryTyParam(p, _) =>
264-
id = p,
265-
266-
RootCrate |
267-
RootInlinedParent(_) =>
268-
// FIXME(#32015) clarify story about cross-crate dep tracking
269-
return DepNode::Krate,
270-
271-
NotPresent =>
272-
// Some nodes, notably struct fields, are not
273-
// present in the map for whatever reason, but
274-
// they *do* have def-ids. So if we encounter an
275-
// empty hole, check for that case.
276-
return self.opt_local_def_id(id)
277-
.map(|def_id| DepNode::Hir(def_id))
278-
.unwrap_or_else(|| {
279-
bug!("Walking parents from `{}` \
280-
led to `NotPresent` at `{}`",
281-
id0, id)
282-
}),
254+
EntryForeignItem(p, _) |
255+
EntryTraitItem(p, _) |
256+
EntryImplItem(p, _) |
257+
EntryVariant(p, _) |
258+
EntryExpr(p, _) |
259+
EntryStmt(p, _) |
260+
EntryLocal(p, _) |
261+
EntryPat(p, _) |
262+
EntryBlock(p, _) |
263+
EntryStructCtor(p, _) |
264+
EntryLifetime(p, _) |
265+
EntryTyParam(p, _) =>
266+
id = p,
267+
268+
RootCrate =>
269+
return DepNode::Krate,
270+
271+
RootInlinedParent(_) =>
272+
bug!("node {} has inlined ancestor but is not inlined", id0),
273+
274+
NotPresent =>
275+
// Some nodes, notably struct fields, are not
276+
// present in the map for whatever reason, but
277+
// they *do* have def-ids. So if we encounter an
278+
// empty hole, check for that case.
279+
return self.opt_local_def_id(id)
280+
.map(|def_id| DepNode::Hir(def_id))
281+
.unwrap_or_else(|| {
282+
bug!("Walking parents from `{}` \
283+
led to `NotPresent` at `{}`",
284+
id0, id)
285+
}),
286+
}
287+
}
288+
} else {
289+
// reading from an inlined def-id is really a read out of
290+
// the metadata from which we loaded the item.
291+
loop {
292+
match map[id as usize] {
293+
EntryItem(p, _) |
294+
EntryForeignItem(p, _) |
295+
EntryTraitItem(p, _) |
296+
EntryImplItem(p, _) |
297+
EntryVariant(p, _) |
298+
EntryExpr(p, _) |
299+
EntryStmt(p, _) |
300+
EntryLocal(p, _) |
301+
EntryPat(p, _) |
302+
EntryBlock(p, _) |
303+
EntryStructCtor(p, _) |
304+
EntryLifetime(p, _) |
305+
EntryTyParam(p, _) =>
306+
id = p,
307+
308+
RootInlinedParent(parent) => match *parent {
309+
InlinedItem::Item(def_id, _) |
310+
InlinedItem::TraitItem(def_id, _) |
311+
InlinedItem::ImplItem(def_id, _) |
312+
InlinedItem::Foreign(def_id, _) =>
313+
return DepNode::MetaData(def_id)
314+
},
315+
316+
RootCrate =>
317+
bug!("node {} has crate ancestor but is inlined", id0),
318+
319+
NotPresent =>
320+
bug!("node {} is inlined but not present in map", id0),
321+
}
283322
}
284323
}
285324
}
@@ -876,7 +915,8 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
876915
-> &'ast InlinedItem {
877916
let mut fld = IdAndSpanUpdater::new(fold_ops);
878917
let ii = match ii {
879-
II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))),
918+
II::Item(d, i) => II::Item(fld.fold_ops.new_def_id(d),
919+
i.map(|i| fld.fold_item(i))),
880920
II::TraitItem(d, ti) => {
881921
II::TraitItem(fld.fold_ops.new_def_id(d),
882922
ti.map(|ti| fld.fold_trait_item(ti)))
@@ -885,7 +925,8 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
885925
II::ImplItem(fld.fold_ops.new_def_id(d),
886926
ii.map(|ii| fld.fold_impl_item(ii)))
887927
}
888-
II::Foreign(i) => II::Foreign(i.map(|i| fld.fold_foreign_item(i)))
928+
II::Foreign(d, i) => II::Foreign(fld.fold_ops.new_def_id(d),
929+
i.map(|i| fld.fold_foreign_item(i)))
889930
};
890931

891932
let ii = map.forest.inlined_items.alloc(ii);

src/librustc/middle/cstore.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,19 @@ pub enum DefLike {
9494
/// that we trans.
9595
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
9696
pub enum InlinedItem {
97-
Item(P<hir::Item>),
97+
Item(DefId /* def-id in source crate */, P<hir::Item>),
9898
TraitItem(DefId /* impl id */, P<hir::TraitItem>),
9999
ImplItem(DefId /* impl id */, P<hir::ImplItem>),
100-
Foreign(P<hir::ForeignItem>),
100+
Foreign(DefId /* extern item */, P<hir::ForeignItem>),
101101
}
102102

103103
/// A borrowed version of `hir::InlinedItem`.
104104
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
105105
pub enum InlinedItemRef<'a> {
106-
Item(&'a hir::Item),
106+
Item(DefId, &'a hir::Item),
107107
TraitItem(DefId, &'a hir::TraitItem),
108108
ImplItem(DefId, &'a hir::ImplItem),
109-
Foreign(&'a hir::ForeignItem)
109+
Foreign(DefId, &'a hir::ForeignItem)
110110
}
111111

112112
/// Item definitions in the currently-compiled crate would have the CrateNum
@@ -283,8 +283,8 @@ impl InlinedItem {
283283
where V: Visitor<'ast>
284284
{
285285
match *self {
286-
InlinedItem::Item(ref i) => visitor.visit_item(&i),
287-
InlinedItem::Foreign(ref i) => visitor.visit_foreign_item(&i),
286+
InlinedItem::Item(_, ref i) => visitor.visit_item(&i),
287+
InlinedItem::Foreign(_, ref i) => visitor.visit_foreign_item(&i),
288288
InlinedItem::TraitItem(_, ref ti) => visitor.visit_trait_item(ti),
289289
InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii),
290290
}

src/librustc_const_eval/eval.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
142142
}
143143
let mut used_substs = false;
144144
let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
145-
Some((&InlinedItem::Item(ref item), _)) => match item.node {
145+
Some((&InlinedItem::Item(_, ref item), _)) => match item.node {
146146
hir::ItemConst(ref ty, ref const_expr) => {
147147
Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
148148
},
@@ -198,7 +198,7 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
198198
}
199199

200200
let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
201-
Some((&InlinedItem::Item(ref item), _)) => Some(item.id),
201+
Some((&InlinedItem::Item(_, ref item), _)) => Some(item.id),
202202
Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id),
203203
_ => None
204204
};

src/librustc_incremental/persist/hash.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
7070
def_id,
7171
self.tcx.item_path_str(def_id));
7272

73+
assert!(!self.tcx.map.is_inlined_def_id(def_id),
74+
"cannot hash HIR for inlined def-id {:?} => {:?}",
75+
def_id,
76+
self.tcx.item_path_str(def_id));
77+
7378
// FIXME(#32753) -- should we use a distinct hash here
7479
self.tcx.calculate_item_hash(def_id)
7580
}

src/librustc_incremental/persist/save.rs

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
106106
encoder: &mut Encoder)
107107
-> io::Result<()>
108108
{
109-
let (nodes, edges) = post_process_graph(hcx, query);
109+
let (nodes, edges) = (query.nodes(), query.edges());
110110

111111
// Create hashes for inputs.
112112
let hashes =
@@ -142,57 +142,6 @@ pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
142142
Ok(())
143143
}
144144

145-
pub fn post_process_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
146-
query: &DepGraphQuery<DefId>)
147-
-> (Vec<DepNode<DefId>>, Vec<(DepNode<DefId>, DepNode<DefId>)>)
148-
{
149-
let tcx = hcx.tcx;
150-
let mut cache = FnvHashMap();
151-
152-
let mut uninline_def_id = |def_id: DefId| -> Option<DefId> {
153-
if tcx.map.is_inlined_def_id(def_id) {
154-
Some(
155-
cache.entry(def_id)
156-
.or_insert_with(|| {
157-
let def_path = tcx.def_path(def_id);
158-
debug!("post_process_graph: uninlining def-id {:?} to yield {:?}",
159-
def_id, def_path);
160-
let retraced_def_id = tcx.retrace_path(&def_path).unwrap();
161-
debug!("post_process_graph: retraced to {:?}", retraced_def_id);
162-
retraced_def_id
163-
})
164-
.clone())
165-
} else {
166-
None
167-
}
168-
};
169-
170-
let mut uninline_metadata = |node: &DepNode<DefId>| -> DepNode<DefId> {
171-
match *node {
172-
DepNode::Hir(def_id) => {
173-
match uninline_def_id(def_id) {
174-
Some(uninlined_def_id) => DepNode::MetaData(uninlined_def_id),
175-
None => DepNode::Hir(def_id)
176-
}
177-
}
178-
_ => node.clone()
179-
}
180-
};
181-
182-
let nodes = query.nodes()
183-
.into_iter()
184-
.map(|node| uninline_metadata(node))
185-
.collect();
186-
187-
let edges = query.edges()
188-
.into_iter()
189-
.map(|(from, to)| (uninline_metadata(from), uninline_metadata(to)))
190-
.collect();
191-
192-
(nodes, edges)
193-
}
194-
195-
196145
pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
197146
builder: &mut DefIdDirectoryBuilder,
198147
query: &DepGraphQuery<DefId>,

0 commit comments

Comments
 (0)