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
This commit is contained in:
commit
aff6161a9e
@ -131,7 +131,37 @@ pub enum DepNode<D: Clone + Debug> {
|
|||||||
// which would yield an overly conservative dep-graph.
|
// which would yield an overly conservative dep-graph.
|
||||||
TraitItems(D),
|
TraitItems(D),
|
||||||
ReprHints(D),
|
ReprHints(D),
|
||||||
TraitSelect(Vec<D>),
|
|
||||||
|
// Trait selection cache is a little funny. Given a trait
|
||||||
|
// reference like `Foo: SomeTrait<Bar>`, there could be
|
||||||
|
// arbitrarily many def-ids to map on in there (e.g., `Foo`,
|
||||||
|
// `SomeTrait`, `Bar`). We could have a vector of them, but it
|
||||||
|
// requires heap-allocation, and trait sel in general can be a
|
||||||
|
// surprisingly hot path. So instead we pick two def-ids: the
|
||||||
|
// trait def-id, and the first def-id in the input types. If there
|
||||||
|
// is no def-id in the input types, then we use the trait def-id
|
||||||
|
// again. So for example:
|
||||||
|
//
|
||||||
|
// - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
|
||||||
|
// - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
|
||||||
|
// - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
|
||||||
|
// - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }`
|
||||||
|
// - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }`
|
||||||
|
// - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
|
||||||
|
// - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
|
||||||
|
// - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
|
||||||
|
// - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
|
||||||
|
//
|
||||||
|
// You can see that we map many trait refs to the same
|
||||||
|
// trait-select node. This is not a problem, it just means
|
||||||
|
// imprecision in our dep-graph tracking. The important thing is
|
||||||
|
// that for any given trait-ref, we always map to the **same**
|
||||||
|
// trait-select node.
|
||||||
|
TraitSelect { trait_def_id: D, input_def_id: D },
|
||||||
|
|
||||||
|
// For proj. cache, we just keep a list of all def-ids, since it is
|
||||||
|
// not a hotspot.
|
||||||
|
ProjectionCache { def_ids: Vec<D> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Clone + Debug> DepNode<D> {
|
impl<D: Clone + Debug> DepNode<D> {
|
||||||
@ -236,9 +266,17 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
|
|||||||
TraitImpls(ref d) => op(d).map(TraitImpls),
|
TraitImpls(ref d) => op(d).map(TraitImpls),
|
||||||
TraitItems(ref d) => op(d).map(TraitItems),
|
TraitItems(ref d) => op(d).map(TraitItems),
|
||||||
ReprHints(ref d) => op(d).map(ReprHints),
|
ReprHints(ref d) => op(d).map(ReprHints),
|
||||||
TraitSelect(ref type_ds) => {
|
TraitSelect { ref trait_def_id, ref input_def_id } => {
|
||||||
let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect());
|
op(trait_def_id).and_then(|trait_def_id| {
|
||||||
Some(TraitSelect(type_ds))
|
op(input_def_id).and_then(|input_def_id| {
|
||||||
|
Some(TraitSelect { trait_def_id: trait_def_id,
|
||||||
|
input_def_id: input_def_id })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ProjectionCache { ref def_ids } => {
|
||||||
|
let def_ids: Option<Vec<E>> = def_ids.iter().map(op).collect();
|
||||||
|
def_ids.map(|d| ProjectionCache { def_ids: d })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::{Cell, RefCell, Ref};
|
use std::cell::{Cell, RefCell, Ref};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::iter;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
@ -843,27 +842,22 @@ pub fn def_id(&self) -> DefId {
|
|||||||
|
|
||||||
/// Creates the dep-node for selecting/evaluating this trait reference.
|
/// Creates the dep-node for selecting/evaluating this trait reference.
|
||||||
fn dep_node(&self) -> DepNode<DefId> {
|
fn dep_node(&self) -> DepNode<DefId> {
|
||||||
// Ideally, the dep-node would just have all the input types
|
// Extact the trait-def and first def-id from inputs. See the
|
||||||
// in it. But they are limited to including def-ids. So as an
|
// docs for `DepNode::TraitSelect` for more information.
|
||||||
// approximation we include the def-ids for all nominal types
|
let trait_def_id = self.def_id();
|
||||||
// found somewhere. This means that we will e.g. conflate the
|
let input_def_id =
|
||||||
// dep-nodes for `u32: SomeTrait` and `u64: SomeTrait`, but we
|
|
||||||
// would have distinct dep-nodes for `Vec<u32>: SomeTrait`,
|
|
||||||
// `Rc<u32>: SomeTrait`, and `(Vec<u32>, Rc<u32>): SomeTrait`.
|
|
||||||
// Note that it's always sound to conflate dep-nodes, it just
|
|
||||||
// leads to more recompilation.
|
|
||||||
let def_ids: Vec<_> =
|
|
||||||
self.input_types()
|
self.input_types()
|
||||||
.flat_map(|t| t.walk())
|
.flat_map(|t| t.walk())
|
||||||
.filter_map(|t| match t.sty {
|
.filter_map(|t| match t.sty {
|
||||||
ty::TyAdt(adt_def, _) =>
|
ty::TyAdt(adt_def, _) => Some(adt_def.did),
|
||||||
Some(adt_def.did),
|
_ => None
|
||||||
_ =>
|
|
||||||
None
|
|
||||||
})
|
})
|
||||||
.chain(iter::once(self.def_id()))
|
.next()
|
||||||
.collect();
|
.unwrap_or(trait_def_id);
|
||||||
DepNode::TraitSelect(def_ids)
|
DepNode::TraitSelect {
|
||||||
|
trait_def_id: trait_def_id,
|
||||||
|
input_def_id: input_def_id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
|
pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
|
||||||
|
@ -208,7 +208,8 @@ fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
|
|||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
DepNode::TraitSelect(def_ids)
|
|
||||||
|
DepNode::ProjectionCache { def_ids: def_ids }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user