Skip to content

Commit aff6161

Browse files
committed
Auto merge of #39912 - nikomatsakis:incr-comp-trait-select-no-vec, r=eddyb
rework `TraitSelect` to avoid a vec and just use two def-ids r? @eddyb
2 parents 306035c + 4749175 commit aff6161

File tree

3 files changed

+56
-23
lines changed

3 files changed

+56
-23
lines changed

Diff for: src/librustc/dep_graph/dep_node.rs

+42-4
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,37 @@ pub enum DepNode<D: Clone + Debug> {
131131
// which would yield an overly conservative dep-graph.
132132
TraitItems(D),
133133
ReprHints(D),
134-
TraitSelect(Vec<D>),
134+
135+
// Trait selection cache is a little funny. Given a trait
136+
// reference like `Foo: SomeTrait<Bar>`, there could be
137+
// arbitrarily many def-ids to map on in there (e.g., `Foo`,
138+
// `SomeTrait`, `Bar`). We could have a vector of them, but it
139+
// requires heap-allocation, and trait sel in general can be a
140+
// surprisingly hot path. So instead we pick two def-ids: the
141+
// trait def-id, and the first def-id in the input types. If there
142+
// is no def-id in the input types, then we use the trait def-id
143+
// again. So for example:
144+
//
145+
// - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
146+
// - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
147+
// - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
148+
// - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }`
149+
// - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }`
150+
// - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
151+
// - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
152+
// - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
153+
// - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
154+
//
155+
// You can see that we map many trait refs to the same
156+
// trait-select node. This is not a problem, it just means
157+
// imprecision in our dep-graph tracking. The important thing is
158+
// that for any given trait-ref, we always map to the **same**
159+
// trait-select node.
160+
TraitSelect { trait_def_id: D, input_def_id: D },
161+
162+
// For proj. cache, we just keep a list of all def-ids, since it is
163+
// not a hotspot.
164+
ProjectionCache { def_ids: Vec<D> },
135165
}
136166

137167
impl<D: Clone + Debug> DepNode<D> {
@@ -236,9 +266,17 @@ impl<D: Clone + Debug> DepNode<D> {
236266
TraitImpls(ref d) => op(d).map(TraitImpls),
237267
TraitItems(ref d) => op(d).map(TraitItems),
238268
ReprHints(ref d) => op(d).map(ReprHints),
239-
TraitSelect(ref type_ds) => {
240-
let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect());
241-
Some(TraitSelect(type_ds))
269+
TraitSelect { ref trait_def_id, ref input_def_id } => {
270+
op(trait_def_id).and_then(|trait_def_id| {
271+
op(input_def_id).and_then(|input_def_id| {
272+
Some(TraitSelect { trait_def_id: trait_def_id,
273+
input_def_id: input_def_id })
274+
})
275+
})
276+
}
277+
ProjectionCache { ref def_ids } => {
278+
let def_ids: Option<Vec<E>> = def_ids.iter().map(op).collect();
279+
def_ids.map(|d| ProjectionCache { def_ids: d })
242280
}
243281
}
244282
}

Diff for: src/librustc/ty/mod.rs

+12-18
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ use serialize::{self, Encodable, Encoder};
3434
use std::borrow::Cow;
3535
use std::cell::{Cell, RefCell, Ref};
3636
use std::hash::{Hash, Hasher};
37-
use std::iter;
3837
use std::ops::Deref;
3938
use std::rc::Rc;
4039
use std::slice;
@@ -843,27 +842,22 @@ impl<'tcx> TraitPredicate<'tcx> {
843842

844843
/// Creates the dep-node for selecting/evaluating this trait reference.
845844
fn dep_node(&self) -> DepNode<DefId> {
846-
// Ideally, the dep-node would just have all the input types
847-
// in it. But they are limited to including def-ids. So as an
848-
// approximation we include the def-ids for all nominal types
849-
// found somewhere. This means that we will e.g. conflate the
850-
// dep-nodes for `u32: SomeTrait` and `u64: SomeTrait`, but we
851-
// would have distinct dep-nodes for `Vec<u32>: SomeTrait`,
852-
// `Rc<u32>: SomeTrait`, and `(Vec<u32>, Rc<u32>): SomeTrait`.
853-
// Note that it's always sound to conflate dep-nodes, it just
854-
// leads to more recompilation.
855-
let def_ids: Vec<_> =
845+
// Extact the trait-def and first def-id from inputs. See the
846+
// docs for `DepNode::TraitSelect` for more information.
847+
let trait_def_id = self.def_id();
848+
let input_def_id =
856849
self.input_types()
857850
.flat_map(|t| t.walk())
858851
.filter_map(|t| match t.sty {
859-
ty::TyAdt(adt_def, _) =>
860-
Some(adt_def.did),
861-
_ =>
862-
None
852+
ty::TyAdt(adt_def, _) => Some(adt_def.did),
853+
_ => None
863854
})
864-
.chain(iter::once(self.def_id()))
865-
.collect();
866-
DepNode::TraitSelect(def_ids)
855+
.next()
856+
.unwrap_or(trait_def_id);
857+
DepNode::TraitSelect {
858+
trait_def_id: trait_def_id,
859+
input_def_id: input_def_id
860+
}
867861
}
868862

869863
pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {

Diff for: src/librustc_trans/context.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,8 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
208208
_ => None,
209209
})
210210
.collect();
211-
DepNode::TraitSelect(def_ids)
211+
212+
DepNode::ProjectionCache { def_ids: def_ids }
212213
}
213214
}
214215

0 commit comments

Comments
 (0)