1
Fork 0

Auto merge of #33998 - nikomatsakis:incr-comp-dep-node-trait, r=mw

Incr. comp. dep-node for traits, tests

Introduce new tests and also make dep-node for trait selection a bit more selective.

Fixes #33850

r? @michaelwoerister
This commit is contained in:
bors 2016-06-04 06:14:57 -07:00
commit 382ab92cee
19 changed files with 447 additions and 82 deletions

View file

@ -10,7 +10,16 @@
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] macro_rules! try_opt {
($e:expr) => (
match $e {
Some(r) => r,
None => return None,
}
)
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum DepNode<D: Clone + Debug> { pub enum DepNode<D: Clone + Debug> {
// The `D` type is "how definitions are identified". // The `D` type is "how definitions are identified".
// During compilation, it is always `DefId`, but when serializing // During compilation, it is always `DefId`, but when serializing
@ -116,7 +125,7 @@ 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(D), TraitSelect(D, Vec<D>),
} }
impl<D: Clone + Debug> DepNode<D> { impl<D: Clone + Debug> DepNode<D> {
@ -212,7 +221,11 @@ impl<D: Clone + Debug> DepNode<D> {
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 d) => op(d).map(TraitSelect), TraitSelect(ref d, ref type_ds) => {
let d = try_opt!(op(d));
let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect());
Some(TraitSelect(d, type_ds))
}
} }
} }
} }

View file

@ -47,26 +47,26 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
self.indices.contains_key(&node) self.indices.contains_key(&node)
} }
pub fn nodes(&self) -> Vec<DepNode<D>> { pub fn nodes(&self) -> Vec<&DepNode<D>> {
self.graph.all_nodes() self.graph.all_nodes()
.iter() .iter()
.map(|n| n.data.clone()) .map(|n| &n.data)
.collect() .collect()
} }
pub fn edges(&self) -> Vec<(DepNode<D>,DepNode<D>)> { pub fn edges(&self) -> Vec<(&DepNode<D>,&DepNode<D>)> {
self.graph.all_edges() self.graph.all_edges()
.iter() .iter()
.map(|edge| (edge.source(), edge.target())) .map(|edge| (edge.source(), edge.target()))
.map(|(s, t)| (self.graph.node_data(s).clone(), .map(|(s, t)| (self.graph.node_data(s),
self.graph.node_data(t).clone())) self.graph.node_data(t)))
.collect() .collect()
} }
fn reachable_nodes(&self, node: DepNode<D>, direction: Direction) -> Vec<DepNode<D>> { fn reachable_nodes(&self, node: &DepNode<D>, direction: Direction) -> Vec<&DepNode<D>> {
if let Some(&index) = self.indices.get(&node) { if let Some(&index) = self.indices.get(node) {
self.graph.depth_traverse(index, direction) self.graph.depth_traverse(index, direction)
.map(|s| self.graph.node_data(s).clone()) .map(|s| self.graph.node_data(s))
.collect() .collect()
} else { } else {
vec![] vec![]
@ -75,20 +75,20 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
/// All nodes reachable from `node`. In other words, things that /// All nodes reachable from `node`. In other words, things that
/// will have to be recomputed if `node` changes. /// will have to be recomputed if `node` changes.
pub fn transitive_successors(&self, node: DepNode<D>) -> Vec<DepNode<D>> { pub fn transitive_successors(&self, node: &DepNode<D>) -> Vec<&DepNode<D>> {
self.reachable_nodes(node, OUTGOING) self.reachable_nodes(node, OUTGOING)
} }
/// All nodes that can reach `node`. /// All nodes that can reach `node`.
pub fn transitive_predecessors(&self, node: DepNode<D>) -> Vec<DepNode<D>> { pub fn transitive_predecessors(&self, node: &DepNode<D>) -> Vec<&DepNode<D>> {
self.reachable_nodes(node, INCOMING) self.reachable_nodes(node, INCOMING)
} }
/// Just the outgoing edges from `node`. /// Just the outgoing edges from `node`.
pub fn immediate_successors(&self, node: DepNode<D>) -> Vec<DepNode<D>> { pub fn immediate_successors(&self, node: &DepNode<D>) -> Vec<&DepNode<D>> {
if let Some(&index) = self.indices.get(&node) { if let Some(&index) = self.indices.get(&node) {
self.graph.successor_nodes(index) self.graph.successor_nodes(index)
.map(|s| self.graph.node_data(s).clone()) .map(|s| self.graph.node_data(s))
.collect() .collect()
} else { } else {
vec![] vec![]

View file

@ -14,20 +14,20 @@ use super::thread::{DepGraphThreadData, DepMessage};
pub struct DepTask<'graph> { pub struct DepTask<'graph> {
data: &'graph DepGraphThreadData, data: &'graph DepGraphThreadData,
key: DepNode<DefId>, key: Option<DepNode<DefId>>,
} }
impl<'graph> DepTask<'graph> { impl<'graph> DepTask<'graph> {
pub fn new(data: &'graph DepGraphThreadData, key: DepNode<DefId>) pub fn new(data: &'graph DepGraphThreadData, key: DepNode<DefId>)
-> DepTask<'graph> { -> DepTask<'graph> {
data.enqueue(DepMessage::PushTask(key)); data.enqueue(DepMessage::PushTask(key.clone()));
DepTask { data: data, key: key } DepTask { data: data, key: Some(key) }
} }
} }
impl<'graph> Drop for DepTask<'graph> { impl<'graph> Drop for DepTask<'graph> {
fn drop(&mut self) { fn drop(&mut self) {
self.data.enqueue(DepMessage::PopTask(self.key)); self.data.enqueue(DepMessage::PopTask(self.key.take().unwrap()));
} }
} }

View file

@ -39,7 +39,7 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn visit_item(&mut self, i: &'tcx hir::Item) { fn visit_item(&mut self, i: &'tcx hir::Item) {
let item_def_id = self.tcx.map.local_def_id(i.id); let item_def_id = self.tcx.map.local_def_id(i.id);
let task_id = (self.dep_node_fn)(item_def_id); let task_id = (self.dep_node_fn)(item_def_id);
let _task = self.tcx.dep_graph.in_task(task_id); let _task = self.tcx.dep_graph.in_task(task_id.clone());
debug!("Started task {:?}", task_id); debug!("Started task {:?}", task_id);
self.tcx.dep_graph.read(DepNode::Hir(item_def_id)); self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
self.visitor.visit_item(i); self.visitor.visit_item(i);

View file

@ -946,7 +946,28 @@ impl<'tcx> TraitPredicate<'tcx> {
/// 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> {
DepNode::TraitSelect(self.def_id()) // Ideally, the dep-node would just have all the input types
// in it. But they are limited to including def-ids. So as an
// approximation we include the def-ids for all nominal types
// found somewhere. This means that we will e.g. conflate the
// 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()
.iter()
.flat_map(|t| t.walk())
.filter_map(|t| match t.sty {
ty::TyStruct(adt_def, _) |
ty::TyEnum(adt_def, _) =>
Some(adt_def.did),
_ =>
None
})
.collect();
DepNode::TraitSelect(self.def_id(), def_ids)
} }
pub fn input_types(&self) -> &[Ty<'tcx>] { pub fn input_types(&self) -> &[Ty<'tcx>] {
@ -1768,9 +1789,8 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
stack: &mut Vec<AdtDefMaster<'tcx>>) stack: &mut Vec<AdtDefMaster<'tcx>>)
{ {
let dep_node = DepNode::SizedConstraint(self.did); let dep_node = || DepNode::SizedConstraint(self.did);
if self.sized_constraint.get(dep_node()).is_some() {
if self.sized_constraint.get(dep_node).is_some() {
return; return;
} }
@ -1780,7 +1800,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
// //
// Consider the type as Sized in the meanwhile to avoid // Consider the type as Sized in the meanwhile to avoid
// further errors. // further errors.
self.sized_constraint.fulfill(dep_node, tcx.types.err); self.sized_constraint.fulfill(dep_node(), tcx.types.err);
return; return;
} }
@ -1803,14 +1823,14 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
_ => tcx.mk_tup(tys) _ => tcx.mk_tup(tys)
}; };
match self.sized_constraint.get(dep_node) { match self.sized_constraint.get(dep_node()) {
Some(old_ty) => { Some(old_ty) => {
debug!("calculate_sized_constraint: {:?} recurred", self); debug!("calculate_sized_constraint: {:?} recurred", self);
assert_eq!(old_ty, tcx.types.err) assert_eq!(old_ty, tcx.types.err)
} }
None => { None => {
debug!("calculate_sized_constraint: {:?} => {:?}", self, ty); debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
self.sized_constraint.fulfill(dep_node, ty) self.sized_constraint.fulfill(dep_node(), ty)
} }
} }
} }

View file

@ -195,7 +195,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
}; };
for &(_, source_def_id, source_dep_node) in sources { for &(_, source_def_id, ref source_dep_node) in sources {
let dependents = query.transitive_successors(source_dep_node); let dependents = query.transitive_successors(source_dep_node);
for &(target_span, ref target_pass, _, ref target_dep_node) in targets { for &(target_span, ref target_pass, _, ref target_dep_node) in targets {
if !dependents.contains(&target_dep_node) { if !dependents.contains(&target_dep_node) {
@ -239,7 +239,7 @@ fn dump_graph(tcx: TyCtxt) {
{ // dump a .txt file with just the edges: { // dump a .txt file with just the edges:
let txt_path = format!("{}.txt", path); let txt_path = format!("{}.txt", path);
let mut file = File::create(&txt_path).unwrap(); let mut file = File::create(&txt_path).unwrap();
for &(source, target) in &edges { for &(ref source, ref target) in &edges {
write!(file, "{:?} -> {:?}\n", source, target).unwrap(); write!(file, "{:?} -> {:?}\n", source, target).unwrap();
} }
} }
@ -252,34 +252,34 @@ fn dump_graph(tcx: TyCtxt) {
} }
} }
pub struct GraphvizDepGraph(FnvHashSet<DepNode<DefId>>, pub struct GraphvizDepGraph<'q>(FnvHashSet<&'q DepNode<DefId>>,
Vec<(DepNode<DefId>, DepNode<DefId>)>); Vec<(&'q DepNode<DefId>, &'q DepNode<DefId>)>);
impl<'a, 'tcx> dot::GraphWalk<'a> for GraphvizDepGraph { impl<'a, 'tcx, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> {
type Node = DepNode<DefId>; type Node = &'q DepNode<DefId>;
type Edge = (DepNode<DefId>, DepNode<DefId>); type Edge = (&'q DepNode<DefId>, &'q DepNode<DefId>);
fn nodes(&self) -> dot::Nodes<DepNode<DefId>> { fn nodes(&self) -> dot::Nodes<&'q DepNode<DefId>> {
let nodes: Vec<_> = self.0.iter().cloned().collect(); let nodes: Vec<_> = self.0.iter().cloned().collect();
nodes.into_cow() nodes.into_cow()
} }
fn edges(&self) -> dot::Edges<(DepNode<DefId>, DepNode<DefId>)> { fn edges(&self) -> dot::Edges<(&'q DepNode<DefId>, &'q DepNode<DefId>)> {
self.1[..].into_cow() self.1[..].into_cow()
} }
fn source(&self, edge: &(DepNode<DefId>, DepNode<DefId>)) -> DepNode<DefId> { fn source(&self, edge: &(&'q DepNode<DefId>, &'q DepNode<DefId>)) -> &'q DepNode<DefId> {
edge.0 edge.0
} }
fn target(&self, edge: &(DepNode<DefId>, DepNode<DefId>)) -> DepNode<DefId> { fn target(&self, edge: &(&'q DepNode<DefId>, &'q DepNode<DefId>)) -> &'q DepNode<DefId> {
edge.1 edge.1
} }
} }
impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph { impl<'a, 'tcx, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> {
type Node = DepNode<DefId>; type Node = &'q DepNode<DefId>;
type Edge = (DepNode<DefId>, DepNode<DefId>); type Edge = (&'q DepNode<DefId>, &'q DepNode<DefId>);
fn graph_id(&self) -> dot::Id { fn graph_id(&self) -> dot::Id {
dot::Id::new("DependencyGraph").unwrap() dot::Id::new("DependencyGraph").unwrap()
} }
fn node_id(&self, n: &DepNode<DefId>) -> dot::Id { fn node_id(&self, n: &&'q DepNode<DefId>) -> dot::Id {
let s: String = let s: String =
format!("{:?}", n).chars() format!("{:?}", n).chars()
.map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' }) .map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' })
@ -287,7 +287,7 @@ impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph {
debug!("n={:?} s={:?}", n, s); debug!("n={:?} s={:?}", n, s);
dot::Id::new(s).unwrap() dot::Id::new(s).unwrap()
} }
fn node_label(&self, n: &DepNode<DefId>) -> dot::LabelText { fn node_label(&self, n: &&'q DepNode<DefId>) -> dot::LabelText {
dot::LabelText::label(format!("{:?}", n)) dot::LabelText::label(format!("{:?}", n))
} }
} }
@ -295,8 +295,8 @@ impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph {
// Given an optional filter like `"x,y,z"`, returns either `None` (no // Given an optional filter like `"x,y,z"`, returns either `None` (no
// filter) or the set of nodes whose labels contain all of those // filter) or the set of nodes whose labels contain all of those
// substrings. // substrings.
fn node_set(query: &DepGraphQuery<DefId>, filter: &DepNodeFilter) fn node_set<'q>(query: &'q DepGraphQuery<DefId>, filter: &DepNodeFilter)
-> Option<FnvHashSet<DepNode<DefId>>> -> Option<FnvHashSet<&'q DepNode<DefId>>>
{ {
debug!("node_set(filter={:?})", filter); debug!("node_set(filter={:?})", filter);
@ -307,10 +307,10 @@ fn node_set(query: &DepGraphQuery<DefId>, filter: &DepNodeFilter)
Some(query.nodes().into_iter().filter(|n| filter.test(n)).collect()) Some(query.nodes().into_iter().filter(|n| filter.test(n)).collect())
} }
fn filter_nodes(query: &DepGraphQuery<DefId>, fn filter_nodes<'q>(query: &'q DepGraphQuery<DefId>,
sources: &Option<FnvHashSet<DepNode<DefId>>>, sources: &Option<FnvHashSet<&'q DepNode<DefId>>>,
targets: &Option<FnvHashSet<DepNode<DefId>>>) targets: &Option<FnvHashSet<&'q DepNode<DefId>>>)
-> FnvHashSet<DepNode<DefId>> -> FnvHashSet<&'q DepNode<DefId>>
{ {
if let &Some(ref sources) = sources { if let &Some(ref sources) = sources {
if let &Some(ref targets) = targets { if let &Some(ref targets) = targets {
@ -325,21 +325,21 @@ fn filter_nodes(query: &DepGraphQuery<DefId>,
} }
} }
fn walk_nodes(query: &DepGraphQuery<DefId>, fn walk_nodes<'q>(query: &'q DepGraphQuery<DefId>,
starts: &FnvHashSet<DepNode<DefId>>, starts: &FnvHashSet<&'q DepNode<DefId>>,
direction: Direction) direction: Direction)
-> FnvHashSet<DepNode<DefId>> -> FnvHashSet<&'q DepNode<DefId>>
{ {
let mut set = FnvHashSet(); let mut set = FnvHashSet();
for start in starts { for &start in starts {
debug!("walk_nodes: start={:?} outgoing?={:?}", start, direction == OUTGOING); debug!("walk_nodes: start={:?} outgoing?={:?}", start, direction == OUTGOING);
if set.insert(*start) { if set.insert(start) {
let mut stack = vec![query.indices[start]]; let mut stack = vec![query.indices[start]];
while let Some(index) = stack.pop() { while let Some(index) = stack.pop() {
for (_, edge) in query.graph.adjacent_edges(index, direction) { for (_, edge) in query.graph.adjacent_edges(index, direction) {
let neighbor_index = edge.source_or_target(direction); let neighbor_index = edge.source_or_target(direction);
let neighbor = query.graph.node_data(neighbor_index); let neighbor = query.graph.node_data(neighbor_index);
if set.insert(*neighbor) { if set.insert(neighbor) {
stack.push(neighbor_index); stack.push(neighbor_index);
} }
} }
@ -349,10 +349,10 @@ fn walk_nodes(query: &DepGraphQuery<DefId>,
set set
} }
fn walk_between(query: &DepGraphQuery<DefId>, fn walk_between<'q>(query: &'q DepGraphQuery<DefId>,
sources: &FnvHashSet<DepNode<DefId>>, sources: &FnvHashSet<&'q DepNode<DefId>>,
targets: &FnvHashSet<DepNode<DefId>>) targets: &FnvHashSet<&'q DepNode<DefId>>)
-> FnvHashSet<DepNode<DefId>> -> FnvHashSet<&'q DepNode<DefId>>
{ {
// This is a bit tricky. We want to include a node only if it is: // This is a bit tricky. We want to include a node only if it is:
// (a) reachable from a source and (b) will reach a target. And we // (a) reachable from a source and (b) will reach a target. And we
@ -365,16 +365,16 @@ fn walk_between(query: &DepGraphQuery<DefId>,
let mut node_states = vec![State::Undecided; query.graph.len_nodes()]; let mut node_states = vec![State::Undecided; query.graph.len_nodes()];
for &target in targets { for &target in targets {
node_states[query.indices[&target].0] = State::Included; node_states[query.indices[target].0] = State::Included;
} }
for source in sources.iter().map(|n| query.indices[n]) { for source in sources.iter().map(|&n| query.indices[n]) {
recurse(query, &mut node_states, source); recurse(query, &mut node_states, source);
} }
return query.nodes() return query.nodes()
.into_iter() .into_iter()
.filter(|n| { .filter(|&n| {
let index = query.indices[n]; let index = query.indices[n];
node_states[index.0] == State::Included node_states[index.0] == State::Included
}) })
@ -417,12 +417,12 @@ fn walk_between(query: &DepGraphQuery<DefId>,
} }
} }
fn filter_edges(query: &DepGraphQuery<DefId>, fn filter_edges<'q>(query: &'q DepGraphQuery<DefId>,
nodes: &FnvHashSet<DepNode<DefId>>) nodes: &FnvHashSet<&'q DepNode<DefId>>)
-> Vec<(DepNode<DefId>, DepNode<DefId>)> -> Vec<(&'q DepNode<DefId>, &'q DepNode<DefId>)>
{ {
query.edges() query.edges()
.into_iter() .into_iter()
.filter(|&(source, target)| nodes.contains(&source) && nodes.contains(&target)) .filter(|&(source, target)| nodes.contains(source) && nodes.contains(target))
.collect() .collect()
} }

View file

@ -57,7 +57,7 @@ impl RetracedDefIdDirectory {
self.ids[index.index as usize] self.ids[index.index as usize]
} }
pub fn map(&self, node: DepNode<DefPathIndex>) -> Option<DepNode<DefId>> { pub fn map(&self, node: &DepNode<DefPathIndex>) -> Option<DepNode<DefId>> {
node.map_def(|&index| self.def_id(index)) node.map_def(|&index| self.def_id(index))
} }
} }
@ -91,7 +91,7 @@ impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> {
.clone() .clone()
} }
pub fn map(&mut self, node: DepNode<DefId>) -> DepNode<DefPathIndex> { pub fn map(&mut self, node: &DepNode<DefId>) -> DepNode<DefPathIndex> {
node.map_def(|&def_id| Some(self.add(def_id))).unwrap() node.map_def(|&def_id| Some(self.add(def_id))).unwrap()
} }

View file

@ -39,8 +39,8 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
} }
} }
pub fn hash(&mut self, dep_node: DepNode<DefId>) -> Option<u64> { pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<u64> {
match dep_node { match *dep_node {
// HIR nodes (which always come from our crate) are an input: // HIR nodes (which always come from our crate) are an input:
DepNode::Hir(def_id) => { DepNode::Hir(def_id) => {
assert!(def_id.is_local()); assert!(def_id.is_local());

View file

@ -114,15 +114,15 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let clean_nodes = let clean_nodes =
serialized_dep_graph.nodes serialized_dep_graph.nodes
.iter() .iter()
.filter_map(|&node| retraced.map(node)) .filter_map(|node| retraced.map(node))
.filter(|node| !dirty_nodes.contains(node)) .filter(|node| !dirty_nodes.contains(node))
.map(|node| (node, node)); .map(|node| (node.clone(), node));
// Add nodes and edges that are not dirty into our main graph. // Add nodes and edges that are not dirty into our main graph.
let dep_graph = tcx.dep_graph.clone(); let dep_graph = tcx.dep_graph.clone();
for (source, target) in clean_edges.into_iter().chain(clean_nodes) { for (source, target) in clean_edges.into_iter().chain(clean_nodes) {
let _task = dep_graph.in_task(target); let _task = dep_graph.in_task(target.clone());
dep_graph.read(source); dep_graph.read(source.clone());
debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source, target); debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source, target);
} }
@ -140,7 +140,7 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
for hash in hashes { for hash in hashes {
match hash.node.map_def(|&i| retraced.def_id(i)) { match hash.node.map_def(|&i| retraced.def_id(i)) {
Some(dep_node) => { Some(dep_node) => {
let current_hash = hcx.hash(dep_node).unwrap(); let current_hash = hcx.hash(&dep_node).unwrap();
debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}", debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}",
dep_node, current_hash, hash.hash); dep_node, current_hash, hash.hash);
if current_hash != hash.hash { if current_hash != hash.hash {
@ -171,7 +171,7 @@ fn compute_clean_edges(serialized_edges: &[(SerializedEdge)],
// target) if neither node has been removed. If the source has // target) if neither node has been removed. If the source has
// been removed, add target to the list of dirty nodes. // been removed, add target to the list of dirty nodes.
let mut clean_edges = Vec::with_capacity(serialized_edges.len()); let mut clean_edges = Vec::with_capacity(serialized_edges.len());
for &(serialized_source, serialized_target) in serialized_edges { for &(ref serialized_source, ref serialized_target) in serialized_edges {
if let Some(target) = retraced.map(serialized_target) { if let Some(target) = retraced.map(serialized_target) {
if let Some(source) = retraced.map(serialized_source) { if let Some(source) = retraced.map(serialized_source) {
clean_edges.push((source, target)) clean_edges.push((source, target))

View file

@ -99,7 +99,7 @@ pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
query.nodes() query.nodes()
.into_iter() .into_iter()
.filter_map(|dep_node| { .filter_map(|dep_node| {
hcx.hash(dep_node) hcx.hash(&dep_node)
.map(|hash| { .map(|hash| {
let node = builder.map(dep_node); let node = builder.map(dep_node);
SerializedHash { node: node, hash: hash } SerializedHash { node: node, hash: hash }
@ -147,7 +147,7 @@ pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
let meta_data_def_ids = let meta_data_def_ids =
query.nodes() query.nodes()
.into_iter() .into_iter()
.filter_map(|dep_node| match dep_node { .filter_map(|dep_node| match *dep_node {
DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id), DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id),
_ => None, _ => None,
}); });
@ -165,8 +165,8 @@ pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
let dep_node = DepNode::MetaData(def_id); let dep_node = DepNode::MetaData(def_id);
let mut state = SipHasher::new(); let mut state = SipHasher::new();
debug!("save: computing metadata hash for {:?}", dep_node); debug!("save: computing metadata hash for {:?}", dep_node);
for node in query.transitive_predecessors(dep_node) { for node in query.transitive_predecessors(&dep_node) {
if let Some(hash) = hcx.hash(node) { if let Some(hash) = hcx.hash(&node) {
debug!("save: predecessor {:?} has hash {}", node, hash); debug!("save: predecessor {:?} has hash {}", node, hash);
state.write_u64(hash.to_le()); state.write_u64(hash.to_le());
} else { } else {

View file

@ -0,0 +1,48 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test incremental compilation tracking where we change field names
// in between revisions (hashing should be stable).
// revisions:rpass1 rpass2
#![feature(rustc_attrs)]
pub struct X {
pub x: u32,
#[cfg(rpass2)]
pub x2: u32,
}
pub struct EmbedX {
x: X
}
pub struct Y {
pub y: char
}
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn use_X(x: X) -> u32 {
x.x as u32
}
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
}
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub fn main() { }

View file

@ -0,0 +1,55 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test incremental compilation tracking where we change field names
// in between revisions (hashing should be stable).
// revisions:rpass1 cfail2
#![feature(rustc_attrs)]
#[cfg(rpass1)]
pub struct X {
pub x: u32
}
#[cfg(cfail2)]
pub struct X {
pub y: u32
}
pub struct EmbedX {
x: X
}
pub struct Y {
pub y: char
}
#[rustc_dirty(label="TypeckItemBody", cfg="cfail2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
//[cfail2]~^ ERROR structure `X` has no field named `x`
x.x as u32
//[cfail2]~^ ERROR attempted access of field `x`
}
#[rustc_dirty(label="TypeckItemBody", cfg="cfail2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
//[cfail2]~^ ERROR attempted access of field `x`
}
#[rustc_clean(label="TypeckItemBody", cfg="cfail2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub fn main() { }

View file

@ -0,0 +1,53 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test incremental compilation tracking where we change nothing
// in between revisions (hashing should be stable).
// revisions:rpass1 rpass2
#![feature(rustc_attrs)]
#[cfg(rpass1)]
pub struct X {
pub x: u32
}
#[cfg(rpass2)]
pub struct X {
pub x: i32
}
pub struct EmbedX {
x: X
}
pub struct Y {
pub y: char
}
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn use_EmbedX(x: EmbedX) -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub fn main() { }

View file

@ -0,0 +1,29 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_type="rlib"]
#[cfg(rpass1)]
pub struct X {
pub x: u32
}
#[cfg(rpass2)]
pub struct X {
pub x: i32
}
pub struct EmbedX {
pub x: X
}
pub struct Y {
pub y: char
}

View file

@ -0,0 +1,36 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:a.rs
// revisions:rpass1 rpass2
#![feature(rustc_attrs)]
extern crate a;
use a::*;
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
}
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub fn main() { }

View file

@ -0,0 +1,53 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test incremental compilation tracking where we change nothing
// in between revisions (hashing should be stable).
// revisions:rpass1 rpass2
#![feature(rustc_attrs)]
#[cfg(rpass1)]
pub struct X {
pub x: u32
}
#[cfg(rpass2)]
pub struct X {
pub x: u32
}
pub struct EmbedX {
x: X
}
pub struct Y {
pub y: char
}
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn use_EmbedX(x: EmbedX) -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub fn main() { }

View file

@ -0,0 +1,52 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test incremental compilation tracking where we change field names
// in between revisions (hashing should be stable).
// revisions:rpass1 rpass2
#![feature(rustc_attrs)]
#[cfg(rpass1)]
pub struct X {
pub x: u32,
pub x2: u32,
}
#[cfg(rpass2)]
pub struct X {
pub x: u32,
}
pub struct EmbedX {
x: X
}
pub struct Y {
pub y: char
}
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn use_X(x: X) -> u32 {
x.x as u32
}
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
}
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub fn main() { }

View file

@ -16,4 +16,8 @@ pub type X = u32;
#[cfg(rpass2)] #[cfg(rpass2)]
pub type X = i32; pub type X = i32;
// this version doesn't actually change anything:
#[cfg(rpass3)]
pub type X = i32;
pub type Y = char; pub type Y = char;

View file

@ -9,19 +9,21 @@
// except according to those terms. // except according to those terms.
// aux-build:a.rs // aux-build:a.rs
// revisions:rpass1 rpass2 // revisions:rpass1 rpass2 rpass3
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
extern crate a; extern crate a;
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
#[rustc_clean(label="TypeckItemBody", cfg="rpass3")]
pub fn use_X() -> u32 { pub fn use_X() -> u32 {
let x: a::X = 22; let x: a::X = 22;
x as u32 x as u32
} }
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")] #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
#[rustc_clean(label="TypeckItemBody", cfg="rpass3")]
pub fn use_Y() { pub fn use_Y() {
let x: a::Y = 'c'; let x: a::Y = 'c';
} }