incorporate resolve results into hashing
We now incorporate the `def_map` and `trait_map` results into the SVH.
This commit is contained in:
parent
953d711cc7
commit
c7f15aa178
10 changed files with 250 additions and 14 deletions
|
@ -14,6 +14,7 @@ use dep_graph::{DepGraph, DepTrackingMap};
|
||||||
use session::Session;
|
use session::Session;
|
||||||
use middle;
|
use middle;
|
||||||
use middle::cstore::LOCAL_CRATE;
|
use middle::cstore::LOCAL_CRATE;
|
||||||
|
use hir::TraitMap;
|
||||||
use hir::def::DefMap;
|
use hir::def::DefMap;
|
||||||
use hir::def_id::{DefId, DefIndex};
|
use hir::def_id::{DefId, DefIndex};
|
||||||
use hir::map as ast_map;
|
use hir::map as ast_map;
|
||||||
|
@ -299,8 +300,16 @@ pub struct GlobalCtxt<'tcx> {
|
||||||
pub types: CommonTypes<'tcx>,
|
pub types: CommonTypes<'tcx>,
|
||||||
|
|
||||||
pub sess: &'tcx Session,
|
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>,
|
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 named_region_map: resolve_lifetime::NamedRegionMap,
|
||||||
|
|
||||||
pub region_maps: RegionMaps,
|
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,
|
pub fn create_and_enter<F, R>(s: &'tcx Session,
|
||||||
arenas: &'tcx CtxtArenas<'tcx>,
|
arenas: &'tcx CtxtArenas<'tcx>,
|
||||||
def_map: DefMap,
|
def_map: DefMap,
|
||||||
|
trait_map: TraitMap,
|
||||||
named_region_map: resolve_lifetime::NamedRegionMap,
|
named_region_map: resolve_lifetime::NamedRegionMap,
|
||||||
map: ast_map::Map<'tcx>,
|
map: ast_map::Map<'tcx>,
|
||||||
freevars: FreevarMap,
|
freevars: FreevarMap,
|
||||||
|
@ -694,6 +704,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
variance_computed: Cell::new(false),
|
variance_computed: Cell::new(false),
|
||||||
sess: s,
|
sess: s,
|
||||||
def_map: RefCell::new(def_map),
|
def_map: RefCell::new(def_map),
|
||||||
|
trait_map: trait_map,
|
||||||
tables: RefCell::new(Tables::empty()),
|
tables: RefCell::new(Tables::empty()),
|
||||||
impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||||
trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||||
|
|
|
@ -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 index = stability::Index::new(&hir_map);
|
||||||
|
|
||||||
let trait_map = resolutions.trait_map;
|
|
||||||
TyCtxt::create_and_enter(sess,
|
TyCtxt::create_and_enter(sess,
|
||||||
arenas,
|
arenas,
|
||||||
resolutions.def_map,
|
resolutions.def_map,
|
||||||
|
resolutions.trait_map,
|
||||||
named_region_map,
|
named_region_map,
|
||||||
hir_map,
|
hir_map,
|
||||||
resolutions.freevars,
|
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));
|
|| rustc_incremental::load_dep_graph(tcx));
|
||||||
|
|
||||||
// passes are timed inside typeck
|
// 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,
|
time(time_passes,
|
||||||
"const checking",
|
"const checking",
|
||||||
|
|
|
@ -131,6 +131,7 @@ fn test_env<F>(source_string: &str,
|
||||||
TyCtxt::create_and_enter(&sess,
|
TyCtxt::create_and_enter(&sess,
|
||||||
&arenas,
|
&arenas,
|
||||||
resolutions.def_map,
|
resolutions.def_map,
|
||||||
|
resolutions.trait_map,
|
||||||
named_region_map.unwrap(),
|
named_region_map.unwrap(),
|
||||||
ast_map,
|
ast_map,
|
||||||
resolutions.freevars,
|
resolutions.freevars,
|
||||||
|
|
|
@ -19,12 +19,14 @@ use self::SawAbiComponent::*;
|
||||||
use syntax::ast::{self, Name, NodeId};
|
use syntax::ast::{self, Name, NodeId};
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use rustc::ty::TyCtxt;
|
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
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 as visit;
|
||||||
use rustc::hir::intravisit::{Visitor, FnKind};
|
use rustc::hir::intravisit::{Visitor, FnKind};
|
||||||
|
use rustc::hir::map::DefPath;
|
||||||
|
use rustc::ty::TyCtxt;
|
||||||
|
|
||||||
use std::hash::{Hash, SipHasher};
|
use std::hash::{Hash, SipHasher};
|
||||||
|
|
||||||
|
@ -343,4 +345,95 @@ impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> {
|
||||||
debug!("visit_arm: st={:?}", self.st);
|
debug!("visit_arm: st={:?}", self.st);
|
||||||
SawArm.hash(self.st); visit::walk_arm(self, a)
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) {
|
||||||
Ok(()) => return,
|
Ok(dirty_nodes) => dirty_nodes,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
tcx.sess.warn(
|
tcx.sess.warn(
|
||||||
&format!("decoding error in dep-graph from `{}` and `{}`: {}",
|
&format!("decoding error in dep-graph from `{}` and `{}`: {}",
|
||||||
|
|
|
@ -580,7 +580,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||||
-> Result<(), MethodError<'tcx>>
|
-> Result<(), MethodError<'tcx>>
|
||||||
{
|
{
|
||||||
let mut duplicates = HashSet::new();
|
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 {
|
if let Some(applicable_traits) = opt_applicable_traits {
|
||||||
for trait_candidate in applicable_traits {
|
for trait_candidate in applicable_traits {
|
||||||
let trait_did = trait_candidate.def_id;
|
let trait_did = trait_candidate.def_id;
|
||||||
|
|
|
@ -139,9 +139,6 @@ pub struct TypeAndSubsts<'tcx> {
|
||||||
pub struct CrateCtxt<'a, 'tcx: 'a> {
|
pub struct CrateCtxt<'a, 'tcx: 'a> {
|
||||||
ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
|
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
|
/// A vector of every trait accessible in the whole crate
|
||||||
/// (i.e. including those from subcrates). This is used only for
|
/// (i.e. including those from subcrates). This is used only for
|
||||||
/// error reporting, and so is lazily initialised and generally
|
/// 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>,
|
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
||||||
trait_map: hir::TraitMap)
|
|
||||||
-> CompileResult {
|
-> CompileResult {
|
||||||
let time_passes = tcx.sess.time_passes();
|
let time_passes = tcx.sess.time_passes();
|
||||||
let ccx = CrateCtxt {
|
let ccx = CrateCtxt {
|
||||||
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
|
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
|
||||||
trait_map: trait_map,
|
|
||||||
all_traits: RefCell::new(None),
|
all_traits: RefCell::new(None),
|
||||||
stack: RefCell::new(Vec::new()),
|
stack: RefCell::new(Vec::new()),
|
||||||
tcx: tcx
|
tcx: tcx
|
||||||
|
|
60
src/test/incremental/ich_method_call_trait_scope.rs
Normal file
60
src/test/incremental/ich_method_call_trait_scope.rs
Normal 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() { }
|
74
src/test/incremental/ich_resolve_results.rs
Normal file
74
src/test/incremental/ich_resolve_results.rs
Normal 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() { }
|
|
@ -41,8 +41,10 @@ mod x {
|
||||||
mod y {
|
mod y {
|
||||||
use x;
|
use x;
|
||||||
|
|
||||||
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
|
// FIXME(#35078) -- when body of `x` changes, we treat it as
|
||||||
#[rustc_clean(label="TransCrateItem", cfg="rpass2")]
|
// though signature changed.
|
||||||
|
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
|
||||||
|
#[rustc_dirty(label="TransCrateItem", cfg="rpass2")]
|
||||||
pub fn y() {
|
pub fn y() {
|
||||||
x::x();
|
x::x();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue