Skip to content

Commit 47d5ca0

Browse files
committed
restructure CollectItem dep-node to separate fn sigs from bodies
Setup two tasks, one of which only processes the signatures, in order to isolate the typeck entries for signatures from those for bodies. Fixes rust-lang#36078 Fixes rust-lang#37720
1 parent c7d6981 commit 47d5ca0

File tree

5 files changed

+62
-16
lines changed

5 files changed

+62
-16
lines changed

src/librustc/dep_graph/dep_node.rs

+2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub enum DepNode<D: Clone + Debug> {
6262
PluginRegistrar,
6363
StabilityIndex,
6464
CollectItem(D),
65+
CollectItemSig(D),
6566
Coherence,
6667
EffectCheck,
6768
Liveness,
@@ -207,6 +208,7 @@ impl<D: Clone + Debug> DepNode<D> {
207208
HirBody(ref d) => op(d).map(HirBody),
208209
MetaData(ref d) => op(d).map(MetaData),
209210
CollectItem(ref d) => op(d).map(CollectItem),
211+
CollectItemSig(ref d) => op(d).map(CollectItemSig),
210212
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
211213
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
212214
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),

src/librustc_typeck/collect.rs

+53-2
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,62 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
128128
ccx: &'a CrateCtxt<'a, 'tcx>
129129
}
130130

131+
impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> {
132+
/// Collect item types is structured into two tasks. The outer
133+
/// task, `CollectItem`, walks the entire content of an item-like
134+
/// thing, including its body. It also spawns an inner task,
135+
/// `CollectItemSig`, which walks only the signature. This inner
136+
/// task is the one that writes the item-type into the various
137+
/// maps. This setup ensures that the item body is never
138+
/// accessible to the task that computes its signature, so that
139+
/// changes to the body don't affect the signature.
140+
///
141+
/// Consider an example function `foo` that also has a closure in its body:
142+
///
143+
/// ```
144+
/// fn foo(<sig>) {
145+
/// ...
146+
/// let bar = || ...; // we'll label this closure as "bar" below
147+
/// }
148+
/// ```
149+
///
150+
/// This results in a dep-graph like so. I've labeled the edges to
151+
/// document where they arise.
152+
///
153+
/// ```
154+
/// [HirBody(foo)] -2--> [CollectItem(foo)] -4-> [ItemSignature(bar)]
155+
/// ^ ^
156+
/// 1 3
157+
/// [Hir(foo)] -----------+-6-> [CollectItemSig(foo)] -5-> [ItemSignature(foo)]
158+
/// ```
159+
///
160+
/// 1. This is added by the `visit_all_item_likes_in_krate`.
161+
/// 2. This is added when we fetch the item body.
162+
/// 3. This is added because `CollectItem` launches `CollectItemSig`.
163+
/// - it is arguably false; if we refactor the `with_task` system;
164+
/// we could get probably rid of it, but it is also harmless enough.
165+
/// 4. This is added by the code in `visit_expr` when we write to `item_types`.
166+
/// 5. This is added by the code in `convert_item` when we write to `item_types`;
167+
/// note that this write occurs inside the `CollectItemSig` task.
168+
/// 6. Added by explicit `read` below
169+
fn with_collect_item_sig<OP>(&self, id: ast::NodeId, op: OP)
170+
where OP: FnOnce()
171+
{
172+
let def_id = self.ccx.tcx.map.local_def_id(id);
173+
self.ccx.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || {
174+
self.ccx.tcx.map.read(id);
175+
op();
176+
});
177+
}
178+
}
179+
131180
impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
132181
fn nested_visit_map(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
133182
Some((&self.ccx.tcx.map, NestedVisitMode::OnlyBodies))
134183
}
135184

136185
fn visit_item(&mut self, item: &'tcx hir::Item) {
137-
convert_item(self.ccx, item);
186+
self.with_collect_item_sig(item.id, || convert_item(self.ccx, item));
138187
intravisit::walk_item(self, item);
139188
}
140189

@@ -154,7 +203,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
154203
}
155204

156205
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
157-
convert_impl_item(self.ccx, impl_item);
206+
self.with_collect_item_sig(impl_item.id, || {
207+
convert_impl_item(self.ccx, impl_item)
208+
});
158209
intravisit::walk_impl_item(self, impl_item);
159210
}
160211
}

src/test/incremental/change_private_impl_method_cc/struct_point.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,16 @@
2323
#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")]
2424
#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
2525

26-
// FIXME(#37720) these two should be reused, but data gets entangled across crates
27-
#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
28-
#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
26+
#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
27+
#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
2928

3029
extern crate point;
3130

3231
/// A fn item that calls (public) methods on `Point` from the same impl which changed
3332
mod fn_calls_methods_in_same_impl {
3433
use point::Point;
3534

36-
// FIXME(#37720) data gets entangled across crates
37-
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
35+
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
3836
pub fn check() {
3937
let x = Point { x: 2.0, y: 2.0 };
4038
x.distance_from_origin();
@@ -45,8 +43,7 @@ mod fn_calls_methods_in_same_impl {
4543
mod fn_calls_methods_in_another_impl {
4644
use point::Point;
4745

48-
// FIXME(#37720) data gets entangled across crates
49-
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
46+
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
5047
pub fn dirty() {
5148
let mut x = Point { x: 2.0, y: 2.0 };
5249
x.translate(3.0, 3.0);

src/test/incremental/change_pub_inherent_method_body/struct_point.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919

2020
#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")]
2121

22-
// FIXME(#35078) -- this gets recompiled because we don't separate sig from body
23-
#![rustc_partition_translated(module="struct_point-fn_calls_changed_method", cfg="rpass2")]
24-
22+
#![rustc_partition_reused(module="struct_point-fn_calls_changed_method", cfg="rpass2")]
2523
#![rustc_partition_reused(module="struct_point-fn_calls_another_method", cfg="rpass2")]
2624
#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
2725
#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")]
@@ -52,8 +50,7 @@ mod point {
5250
mod fn_calls_changed_method {
5351
use point::Point;
5452

55-
// FIXME(#35078) -- this gets recompiled because we don't separate sig from body
56-
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
53+
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
5754
pub fn check() {
5855
let p = Point { x: 2.0, y: 2.0 };
5956
p.distance_from_origin();

src/test/incremental/hello_world.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ mod x {
3131
mod y {
3232
use x;
3333

34-
// FIXME: This should be clean
35-
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
34+
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
3635
pub fn yyyy() {
3736
x::xxxx();
3837
}

0 commit comments

Comments
 (0)