incorporate resolve results into hashing

We now incorporate the `def_map` and `trait_map`
results into the SVH.
This commit is contained in:
Niko Matsakis 2016-07-27 17:26:55 -04:00
parent 953d711cc7
commit c7f15aa178
10 changed files with 250 additions and 14 deletions

View File

@ -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())),

View File

@ -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",

View File

@ -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,

View File

@ -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);
}
}
}
}

View File

@ -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 `{}`: {}",

View File

@ -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;

View File

@ -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

View File

@ -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() { }

View File

@ -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() { }

View File

@ -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();
}