about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2016-07-27 17:26:55 -0400
committerNiko Matsakis <niko@alum.mit.edu>2016-08-09 20:28:46 -0400
commitc7f15aa178c179cc664dafa062121d854df5a3f6 (patch)
treef90971f8452bcba05fae916ff1bb18769def828a
parent953d711cc74457981bc01e0090ba67b9a5779e5b (diff)
incorporate resolve results into hashing
We now incorporate the `def_map` and `trait_map`
results into the SVH.
-rw-r--r--src/librustc/ty/context.rs11
-rw-r--r--src/librustc_driver/driver.rs4
-rw-r--r--src/librustc_driver/test.rs1
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs97
-rw-r--r--src/librustc_incremental/persist/load.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs2
-rw-r--r--src/librustc_typeck/lib.rs7
-rw-r--r--src/test/incremental/ich_method_call_trait_scope.rs60
-rw-r--r--src/test/incremental/ich_resolve_results.rs74
-rw-r--r--src/test/incremental/string_constant.rs6
10 files changed, 250 insertions, 14 deletions
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 77cc62060aa..a816d26edad 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -14,6 +14,7 @@ use dep_graph::{DepGraph, DepTrackingMap};
 use session::Session;
 use middle;
 use middle::cstore::LOCAL_CRATE;
+use hir::TraitMap;
 use hir::def::DefMap;
 use hir::def_id::{DefId, DefIndex};
 use hir::map as ast_map;
@@ -299,8 +300,16 @@ pub struct GlobalCtxt<'tcx> {
     pub types: CommonTypes<'tcx>,
 
     pub sess: &'tcx Session,
+
+    /// Map from path id to the results from resolve; generated
+    /// initially by resolve and updated during typeck in some cases
+    /// (e.g., UFCS paths)
     pub def_map: RefCell<DefMap>,
 
+    /// Map indicating what traits are in scope for places where this
+    /// is relevant; generated by resolve.
+    pub trait_map: TraitMap,
+
     pub named_region_map: resolve_lifetime::NamedRegionMap,
 
     pub region_maps: RegionMaps,
@@ -666,6 +675,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn create_and_enter<F, R>(s: &'tcx Session,
                                   arenas: &'tcx CtxtArenas<'tcx>,
                                   def_map: DefMap,
+                                  trait_map: TraitMap,
                                   named_region_map: resolve_lifetime::NamedRegionMap,
                                   map: ast_map::Map<'tcx>,
                                   freevars: FreevarMap,
@@ -694,6 +704,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             variance_computed: Cell::new(false),
             sess: s,
             def_map: RefCell::new(def_map),
+            trait_map: trait_map,
             tables: RefCell::new(Tables::empty()),
             impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index f1f5e194da4..7f50522b203 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -846,10 +846,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
     let index = stability::Index::new(&hir_map);
 
-    let trait_map = resolutions.trait_map;
     TyCtxt::create_and_enter(sess,
                              arenas,
                              resolutions.def_map,
+                             resolutions.trait_map,
                              named_region_map,
                              hir_map,
                              resolutions.freevars,
@@ -864,7 +864,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
              || rustc_incremental::load_dep_graph(tcx));
 
         // passes are timed inside typeck
-        try_with_f!(typeck::check_crate(tcx, trait_map), (tcx, None, analysis));
+        try_with_f!(typeck::check_crate(tcx), (tcx, None, analysis));
 
         time(time_passes,
              "const checking",
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 39763bfa0eb..2b0bd14d83f 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -131,6 +131,7 @@ fn test_env<F>(source_string: &str,
     TyCtxt::create_and_enter(&sess,
                              &arenas,
                              resolutions.def_map,
+                             resolutions.trait_map,
                              named_region_map.unwrap(),
                              ast_map,
                              resolutions.freevars,
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index d15734dce70..42e7abeeaca 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -19,12 +19,14 @@ use self::SawAbiComponent::*;
 use syntax::ast::{self, Name, NodeId};
 use syntax::parse::token;
 use syntax_pos::Span;
-use rustc::ty::TyCtxt;
 use rustc::hir;
 use rustc::hir::*;
-use rustc::hir::map::DefPath;
+use rustc::hir::def::{Def, PathResolution};
+use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit as visit;
 use rustc::hir::intravisit::{Visitor, FnKind};
+use rustc::hir::map::DefPath;
+use rustc::ty::TyCtxt;
 
 use std::hash::{Hash, SipHasher};
 
@@ -343,4 +345,95 @@ impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> {
         debug!("visit_arm: st={:?}", self.st);
         SawArm.hash(self.st); visit::walk_arm(self, a)
     }
+
+    fn visit_id(&mut self, id: NodeId) {
+        debug!("visit_id: id={} st={:?}", id, self.st);
+        self.hash_resolve(id);
+    }
+}
+
+#[derive(Hash)]
+pub enum DefHash {
+    SawDefId,
+    SawLabel,
+    SawPrimTy,
+    SawSelfTy,
+    SawErr,
+}
+
+impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> {
+    fn hash_resolve(&mut self, id: ast::NodeId) {
+        // Because whether or not a given id has an entry is dependent
+        // solely on expr variant etc, we don't need to hash whether
+        // or not an entry was present (we are already hashing what
+        // variant it is above when we visit the HIR).
+
+        if let Some(def) = self.tcx.def_map.borrow().get(&id) {
+            self.hash_partial_def(def);
+        }
+
+        if let Some(traits) = self.tcx.trait_map.get(&id) {
+            traits.len().hash(self.st);
+            for candidate in traits {
+                self.hash_def_id(candidate.def_id);
+            }
+        }
+    }
+
+    fn hash_def_id(&mut self, def_id: DefId) {
+        let def_path = self.tcx.def_path(def_id);
+        self.hash_def_path(&def_path);
+    }
+
+    fn hash_partial_def(&mut self, def: &PathResolution) {
+        self.hash_def(def.base_def);
+        def.depth.hash(self.st);
+    }
+
+    fn hash_def(&mut self, def: Def) {
+        match def {
+            // Crucial point: for all of these variants, the variant +
+            // add'l data that is added is always the same if the
+            // def-id is the same, so it suffices to hash the def-id
+            Def::Fn(..) |
+            Def::Mod(..) |
+            Def::ForeignMod(..) |
+            Def::Static(..) |
+            Def::Variant(..) |
+            Def::Enum(..) |
+            Def::TyAlias(..) |
+            Def::AssociatedTy(..) |
+            Def::TyParam(..) |
+            Def::Struct(..) |
+            Def::Trait(..) |
+            Def::Method(..) |
+            Def::Const(..) |
+            Def::AssociatedConst(..) |
+            Def::Local(..) |
+            Def::Upvar(..) => {
+                DefHash::SawDefId.hash(self.st);
+                self.hash_def_id(def.def_id());
+            }
+
+            Def::Label(..) => {
+                DefHash::SawLabel.hash(self.st);
+                // we don't encode the `id` because it always refers to something
+                // within this item, so if it changed, there would have to be other
+                // changes too
+            }
+            Def::PrimTy(ref prim_ty) => {
+                DefHash::SawPrimTy.hash(self.st);
+                prim_ty.hash(self.st);
+            }
+            Def::SelfTy(..) => {
+                DefHash::SawSelfTy.hash(self.st);
+                // the meaning of Self is always the same within a
+                // given context, so we don't need to hash the other
+                // fields
+            }
+            Def::Err => {
+                DefHash::SawErr.hash(self.st);
+            }
+        }
+    }
 }
diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs
index 48ddcd2c416..79b90b63dc6 100644
--- a/src/librustc_incremental/persist/load.rs
+++ b/src/librustc_incremental/persist/load.rs
@@ -61,7 +61,7 @@ fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     };
 
     match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) {
-        Ok(()) => return,
+        Ok(dirty_nodes) => dirty_nodes,
         Err(err) => {
             tcx.sess.warn(
                 &format!("decoding error in dep-graph from `{}` and `{}`: {}",
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 6a1baf13b27..648d1f42fb5 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -580,7 +580,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                                                          -> Result<(), MethodError<'tcx>>
     {
         let mut duplicates = HashSet::new();
-        let opt_applicable_traits = self.ccx.trait_map.get(&expr_id);
+        let opt_applicable_traits = self.tcx.trait_map.get(&expr_id);
         if let Some(applicable_traits) = opt_applicable_traits {
             for trait_candidate in applicable_traits {
                 let trait_did = trait_candidate.def_id;
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 65e00705121..eac26487ea3 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -139,9 +139,6 @@ pub struct TypeAndSubsts<'tcx> {
 pub struct CrateCtxt<'a, 'tcx: 'a> {
     ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
 
-    /// A mapping from method call sites to traits that have that method.
-    pub trait_map: hir::TraitMap,
-
     /// A vector of every trait accessible in the whole crate
     /// (i.e. including those from subcrates). This is used only for
     /// error reporting, and so is lazily initialised and generally
@@ -321,13 +318,11 @@ fn check_for_entry_fn(ccx: &CrateCtxt) {
     }
 }
 
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             trait_map: hir::TraitMap)
+pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
                              -> CompileResult {
     let time_passes = tcx.sess.time_passes();
     let ccx = CrateCtxt {
         ast_ty_to_ty_cache: RefCell::new(NodeMap()),
-        trait_map: trait_map,
         all_traits: RefCell::new(None),
         stack: RefCell::new(Vec::new()),
         tcx: tcx
diff --git a/src/test/incremental/ich_method_call_trait_scope.rs b/src/test/incremental/ich_method_call_trait_scope.rs
new file mode 100644
index 00000000000..f28ecf74dd4
--- /dev/null
+++ b/src/test/incremental/ich_method_call_trait_scope.rs
@@ -0,0 +1,60 @@
+// 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.
+
+// Check that the hash for a method call is sensitive to the traits in
+// scope.
+
+// revisions: rpass1 rpass2
+
+#![feature(rustc_attrs)]
+
+fn test<T>() { }
+
+trait Trait1 {
+    fn method(&self) { }
+}
+
+impl Trait1 for () { }
+
+trait Trait2 {
+    fn method(&self) { }
+}
+
+impl Trait2 for () { }
+
+#[cfg(rpass1)]
+mod mod3 {
+    use Trait1;
+
+    fn bar() {
+        ().method();
+    }
+
+    fn baz() {
+        22; // no method call, traits in scope don't matter
+    }
+}
+
+#[cfg(rpass2)]
+mod mod3 {
+    use Trait2;
+
+    #[rustc_dirty(label="Hir", cfg="rpass2")]
+    fn bar() {
+        ().method();
+    }
+
+    #[rustc_clean(label="Hir", cfg="rpass2")]
+    fn baz() {
+        22; // no method call, traits in scope don't matter
+    }
+}
+
+fn main() { }
diff --git a/src/test/incremental/ich_resolve_results.rs b/src/test/incremental/ich_resolve_results.rs
new file mode 100644
index 00000000000..680a91da09f
--- /dev/null
+++ b/src/test/incremental/ich_resolve_results.rs
@@ -0,0 +1,74 @@
+// 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.
+
+// Check that the hash for `mod3::bar` changes when we change the
+// `use` to something different.
+
+// revisions: rpass1 rpass2 rpass3
+
+#![feature(rustc_attrs)]
+
+fn test<T>() { }
+
+mod mod1 {
+    pub struct Foo(pub u32);
+}
+
+mod mod2 {
+    pub struct Foo(pub i64);
+}
+
+#[cfg(rpass1)]
+mod mod3 {
+    use test;
+    use mod1::Foo;
+
+    fn in_expr() {
+        Foo(0);
+    }
+
+    fn in_type() {
+        test::<Foo>();
+    }
+}
+
+#[cfg(rpass2)]
+mod mod3 {
+    use mod1::Foo; // <-- Nothing changed, but reordered!
+    use test;
+
+    #[rustc_clean(label="Hir", cfg="rpass2")]
+    fn in_expr() {
+        Foo(0);
+    }
+
+    #[rustc_clean(label="Hir", cfg="rpass2")]
+    fn in_type() {
+        test::<Foo>();
+    }
+}
+
+#[cfg(rpass3)]
+mod mod3 {
+    use test;
+    use mod2::Foo; // <-- This changed!
+
+    #[rustc_dirty(label="Hir", cfg="rpass3")]
+    fn in_expr() {
+        Foo(0);
+    }
+
+    #[rustc_dirty(label="Hir", cfg="rpass3")]
+    fn in_type() {
+        test::<Foo>();
+    }
+}
+
+fn main() { }
diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs
index f4062169256..72072248ec0 100644
--- a/src/test/incremental/string_constant.rs
+++ b/src/test/incremental/string_constant.rs
@@ -41,8 +41,10 @@ mod x {
 mod y {
     use x;
 
-    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
-    #[rustc_clean(label="TransCrateItem", cfg="rpass2")]
+    // FIXME(#35078) -- when body of `x` changes, we treat it as
+    // though signature changed.
+    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_dirty(label="TransCrateItem", cfg="rpass2")]
     pub fn y() {
         x::x();
     }