1
Fork 0

rustc: store ty::Tables separately for each body (except closures').

This commit is contained in:
Eduard-Mihai Burtescu 2017-01-04 04:01:58 +02:00
parent 85a4a192c7
commit cde0a7e7e0
17 changed files with 223 additions and 477 deletions

View file

@ -113,6 +113,7 @@ pub enum DepNode<D: Clone + Debug> {
SizedConstraint(D), SizedConstraint(D),
AssociatedItemDefIds(D), AssociatedItemDefIds(D),
InherentImpls(D), InherentImpls(D),
Tables(D),
// The set of impls for a given trait. Ultimately, it would be // The set of impls for a given trait. Ultimately, it would be
// nice to get more fine-grained here (e.g., to include a // nice to get more fine-grained here (e.g., to include a
@ -162,6 +163,7 @@ impl<D: Clone + Debug> DepNode<D> {
ItemSignature, ItemSignature,
AssociatedItemDefIds, AssociatedItemDefIds,
InherentImpls, InherentImpls,
Tables,
TraitImpls, TraitImpls,
ReprHints, ReprHints,
} }
@ -230,6 +232,7 @@ impl<D: Clone + Debug> DepNode<D> {
SizedConstraint(ref d) => op(d).map(SizedConstraint), SizedConstraint(ref d) => op(d).map(SizedConstraint),
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds), AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
InherentImpls(ref d) => op(d).map(InherentImpls), InherentImpls(ref d) => op(d).map(InherentImpls),
Tables(ref d) => op(d).map(Tables),
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),

View file

@ -23,10 +23,6 @@ pub struct NodeCollector<'ast> {
pub(super) map: Vec<MapEntry<'ast>>, pub(super) map: Vec<MapEntry<'ast>>,
/// The parent of this node /// The parent of this node
pub parent_node: NodeId, pub parent_node: NodeId,
/// If true, completely ignore nested items. We set this when loading
/// HIR from metadata, since in that case we only want the HIR for
/// one specific item (and not the ones nested inside of it).
pub ignore_nested_items: bool
} }
impl<'ast> NodeCollector<'ast> { impl<'ast> NodeCollector<'ast> {
@ -35,30 +31,12 @@ impl<'ast> NodeCollector<'ast> {
krate: krate, krate: krate,
map: vec![], map: vec![],
parent_node: CRATE_NODE_ID, parent_node: CRATE_NODE_ID,
ignore_nested_items: false
}; };
collector.insert_entry(CRATE_NODE_ID, RootCrate); collector.insert_entry(CRATE_NODE_ID, RootCrate);
collector collector
} }
pub(super) fn extend(krate: &'ast Crate,
parent: &'ast InlinedItem,
parent_node: NodeId,
map: Vec<MapEntry<'ast>>)
-> NodeCollector<'ast> {
let mut collector = NodeCollector {
krate: krate,
map: map,
parent_node: parent_node,
ignore_nested_items: true
};
collector.insert_entry(parent_node, RootInlinedParent(parent));
collector
}
fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) { fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
debug!("ast_map: {:?} => {:?}", id, entry); debug!("ast_map: {:?} => {:?}", id, entry);
let len = self.map.len(); let len = self.map.len();
@ -92,27 +70,19 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
fn visit_nested_item(&mut self, item: ItemId) { fn visit_nested_item(&mut self, item: ItemId) {
debug!("visit_nested_item: {:?}", item); debug!("visit_nested_item: {:?}", item);
if !self.ignore_nested_items { self.visit_item(self.krate.item(item.id));
self.visit_item(self.krate.item(item.id))
}
} }
fn visit_nested_trait_item(&mut self, item_id: TraitItemId) { fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
if !self.ignore_nested_items { self.visit_trait_item(self.krate.trait_item(item_id));
self.visit_trait_item(self.krate.trait_item(item_id))
}
} }
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
if !self.ignore_nested_items { self.visit_impl_item(self.krate.impl_item(item_id));
self.visit_impl_item(self.krate.impl_item(item_id))
}
} }
fn visit_nested_body(&mut self, id: BodyId) { fn visit_nested_body(&mut self, id: BodyId) {
if !self.ignore_nested_items { self.visit_body(self.krate.body(id));
self.visit_body(self.krate.body(id))
}
} }
fn visit_item(&mut self, i: &'ast Item) { fn visit_item(&mut self, i: &'ast Item) {

View file

@ -25,28 +25,18 @@ use syntax::codemap::Spanned;
use syntax_pos::Span; use syntax_pos::Span;
use hir::*; use hir::*;
use hir::intravisit::Visitor;
use hir::print::Nested; use hir::print::Nested;
use util::nodemap::DefIdMap;
use arena::TypedArena; use arena::TypedArena;
use std::cell::RefCell; use std::cell::RefCell;
use std::io; use std::io;
use std::mem;
pub mod blocks; pub mod blocks;
mod collector; mod collector;
mod def_collector; mod def_collector;
pub mod definitions; pub mod definitions;
/// The data we save and restore about an inlined item or method. This is not
/// part of the AST that we parse from a file, but it becomes part of the tree
/// that we trans.
#[derive(Debug)]
struct InlinedItem {
def_id: DefId,
body: Body,
}
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum Node<'ast> { pub enum Node<'ast> {
NodeItem(&'ast Item), NodeItem(&'ast Item),
@ -99,7 +89,6 @@ enum MapEntry<'ast> {
/// Roots for node trees. /// Roots for node trees.
RootCrate, RootCrate,
RootInlinedParent(&'ast InlinedItem)
} }
impl<'ast> Clone for MapEntry<'ast> { impl<'ast> Clone for MapEntry<'ast> {
@ -152,8 +141,7 @@ impl<'ast> MapEntry<'ast> {
EntryVisibility(id, _) => id, EntryVisibility(id, _) => id,
NotPresent | NotPresent |
RootCrate | RootCrate => return None,
RootInlinedParent(_) => return None,
}) })
} }
@ -225,7 +213,7 @@ impl<'ast> MapEntry<'ast> {
pub struct Forest { pub struct Forest {
krate: Crate, krate: Crate,
pub dep_graph: DepGraph, pub dep_graph: DepGraph,
inlined_items: TypedArena<InlinedItem> inlined_bodies: TypedArena<Body>
} }
impl Forest { impl Forest {
@ -233,7 +221,7 @@ impl Forest {
Forest { Forest {
krate: krate, krate: krate,
dep_graph: dep_graph.clone(), dep_graph: dep_graph.clone(),
inlined_items: TypedArena::new() inlined_bodies: TypedArena::new()
} }
} }
@ -263,20 +251,15 @@ pub struct Map<'ast> {
/// ///
/// Also, indexing is pretty quick when you've got a vector and /// Also, indexing is pretty quick when you've got a vector and
/// plain old integers. /// plain old integers.
map: RefCell<Vec<MapEntry<'ast>>>, map: Vec<MapEntry<'ast>>,
definitions: Definitions, definitions: Definitions,
/// All NodeIds that are numerically greater or equal to this value come /// Bodies inlined from other crates are cached here.
/// from inlined items. inlined_bodies: RefCell<DefIdMap<&'ast Body>>,
local_node_id_watermark: NodeId,
} }
impl<'ast> Map<'ast> { impl<'ast> Map<'ast> {
pub fn is_inlined_node_id(&self, id: NodeId) -> bool {
id >= self.local_node_id_watermark
}
/// Registers a read in the dependency graph of the AST node with /// Registers a read in the dependency graph of the AST node with
/// the given `id`. This needs to be called each time a public /// the given `id`. This needs to be called each time a public
/// function returns the HIR for a node -- in other words, when it /// function returns the HIR for a node -- in other words, when it
@ -289,12 +272,10 @@ impl<'ast> Map<'ast> {
} }
fn dep_node(&self, id0: NodeId) -> DepNode<DefId> { fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
let map = self.map.borrow();
let mut id = id0; let mut id = id0;
if !self.is_inlined_node_id(id) {
let mut last_expr = None; let mut last_expr = None;
loop { loop {
let entry = map[id.as_usize()]; let entry = self.map[id.as_usize()];
match entry { match entry {
EntryItem(..) | EntryItem(..) |
EntryTraitItem(..) | EntryTraitItem(..) |
@ -344,9 +325,6 @@ impl<'ast> Map<'ast> {
return DepNode::Hir(DefId::local(CRATE_DEF_INDEX)); return DepNode::Hir(DefId::local(CRATE_DEF_INDEX));
} }
RootInlinedParent(_) =>
bug!("node {} has inlined ancestor but is not inlined", id0),
NotPresent => NotPresent =>
// Some nodes, notably macro definitions, are not // Some nodes, notably macro definitions, are not
// present in the map for whatever reason, but // present in the map for whatever reason, but
@ -361,41 +339,6 @@ impl<'ast> Map<'ast> {
}), }),
} }
} }
} else {
// reading from an inlined def-id is really a read out of
// the metadata from which we loaded the item.
loop {
match map[id.as_usize()] {
EntryItem(p, _) |
EntryForeignItem(p, _) |
EntryTraitItem(p, _) |
EntryImplItem(p, _) |
EntryVariant(p, _) |
EntryField(p, _) |
EntryExpr(p, _) |
EntryStmt(p, _) |
EntryTy(p, _) |
EntryTraitRef(p, _) |
EntryLocal(p, _) |
EntryPat(p, _) |
EntryBlock(p, _) |
EntryStructCtor(p, _) |
EntryLifetime(p, _) |
EntryTyParam(p, _) |
EntryVisibility(p, _) =>
id = p,
RootInlinedParent(parent) =>
return DepNode::MetaData(parent.def_id),
RootCrate =>
bug!("node {} has crate ancestor but is inlined", id0),
NotPresent =>
bug!("node {} is inlined but not present in map", id0),
}
}
}
} }
pub fn num_local_def_ids(&self) -> usize { pub fn num_local_def_ids(&self) -> usize {
@ -442,11 +385,11 @@ impl<'ast> Map<'ast> {
} }
fn entry_count(&self) -> usize { fn entry_count(&self) -> usize {
self.map.borrow().len() self.map.len()
} }
fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> { fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> {
self.map.borrow().get(id.as_usize()).cloned() self.map.get(id.as_usize()).cloned()
} }
pub fn krate(&self) -> &'ast Crate { pub fn krate(&self) -> &'ast Crate {
@ -483,7 +426,7 @@ impl<'ast> Map<'ast> {
/// for embedded constant expressions (e.g. `N` in `[T; N]`). /// for embedded constant expressions (e.g. `N` in `[T; N]`).
pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId { pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId {
let parent = self.get_parent_node(node_id); let parent = self.get_parent_node(node_id);
if self.map.borrow()[parent.as_usize()].is_body_owner(node_id) { if self.map[parent.as_usize()].is_body_owner(node_id) {
parent parent
} else { } else {
node_id node_id
@ -644,11 +587,7 @@ impl<'ast> Map<'ast> {
} }
pub fn get_parent_did(&self, id: NodeId) -> DefId { pub fn get_parent_did(&self, id: NodeId) -> DefId {
let parent = self.get_parent(id); self.local_def_id(self.get_parent(id))
match self.find_entry(parent) {
Some(RootInlinedParent(ii)) => ii.def_id,
_ => self.local_def_id(parent)
}
} }
pub fn get_foreign_abi(&self, id: NodeId) -> Abi { pub fn get_foreign_abi(&self, id: NodeId) -> Abi {
@ -660,8 +599,6 @@ impl<'ast> Map<'ast> {
_ => None _ => None
} }
} }
/// Wrong but OK, because the only inlined foreign items are intrinsics.
Some(RootInlinedParent(_)) => Some(Abi::RustIntrinsic),
_ => None _ => None
}; };
match abi { match abi {
@ -737,11 +674,17 @@ impl<'ast> Map<'ast> {
} }
} }
pub fn expect_inlined_body(&self, id: NodeId) -> &'ast Body { pub fn get_inlined_body(&self, def_id: DefId) -> Option<&'ast Body> {
match self.find_entry(id) { self.inlined_bodies.borrow().get(&def_id).map(|&body| {
Some(RootInlinedParent(inlined_item)) => &inlined_item.body, self.dep_graph.read(DepNode::MetaData(def_id));
_ => bug!("expected inlined item, found {}", self.node_to_string(id)), body
})
} }
pub fn intern_inlined_body(&self, def_id: DefId, body: Body) -> &'ast Body {
let body = self.forest.inlined_bodies.alloc(body);
self.inlined_bodies.borrow_mut().insert(def_id, body);
body
} }
/// Returns the name associated with the given NodeId's AST. /// Returns the name associated with the given NodeId's AST.
@ -824,7 +767,6 @@ impl<'ast> Map<'ast> {
Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v), Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v),
Some(RootCrate) => self.forest.krate.span, Some(RootCrate) => self.forest.krate.span,
Some(RootInlinedParent(parent)) => parent.body.value.span,
Some(NotPresent) | None => { Some(NotPresent) | None => {
bug!("hir::map::Map::span: id not in map: {:?}", id) bug!("hir::map::Map::span: id not in map: {:?}", id)
} }
@ -973,41 +915,15 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
entries, vector_length, (entries as f64 / vector_length as f64) * 100.); entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
} }
let local_node_id_watermark = NodeId::new(map.len());
Map { Map {
forest: forest, forest: forest,
dep_graph: forest.dep_graph.clone(), dep_graph: forest.dep_graph.clone(),
map: RefCell::new(map), map: map,
definitions: definitions, definitions: definitions,
local_node_id_watermark: local_node_id_watermark, inlined_bodies: RefCell::new(DefIdMap()),
} }
} }
/// Used for bodies loaded from external crate that are being inlined into this
/// crate.
pub fn map_decoded_body<'ast>(map: &Map<'ast>,
def_id: DefId,
body: Body,
parent_id: NodeId)
-> &'ast Body {
let _ignore = map.forest.dep_graph.in_ignore();
let ii = map.forest.inlined_items.alloc(InlinedItem {
def_id: def_id,
body: body
});
let mut collector = NodeCollector::extend(map.krate(),
ii,
parent_id,
mem::replace(&mut *map.map.borrow_mut(), vec![]));
collector.visit_body(&ii.body);
*map.map.borrow_mut() = collector.map;
&ii.body
}
/// Identical to the `PpAnn` implementation for `hir::Crate`, /// Identical to the `PpAnn` implementation for `hir::Crate`,
/// except it avoids creating a dependency on the whole crate. /// except it avoids creating a dependency on the whole crate.
impl<'ast> print::PpAnn for Map<'ast> { impl<'ast> print::PpAnn for Map<'ast> {

View file

@ -65,6 +65,7 @@ pub struct GlobalArenas<'tcx> {
trait_def: TypedArena<ty::TraitDef>, trait_def: TypedArena<ty::TraitDef>,
adt_def: TypedArena<ty::AdtDef>, adt_def: TypedArena<ty::AdtDef>,
mir: TypedArena<RefCell<Mir<'tcx>>>, mir: TypedArena<RefCell<Mir<'tcx>>>,
tables: TypedArena<ty::Tables<'tcx>>,
} }
impl<'tcx> GlobalArenas<'tcx> { impl<'tcx> GlobalArenas<'tcx> {
@ -75,6 +76,7 @@ impl<'tcx> GlobalArenas<'tcx> {
trait_def: TypedArena::new(), trait_def: TypedArena::new(),
adt_def: TypedArena::new(), adt_def: TypedArena::new(),
mir: TypedArena::new(), mir: TypedArena::new(),
tables: TypedArena::new(),
} }
} }
} }
@ -189,6 +191,7 @@ pub struct CommonTypes<'tcx> {
pub err: Ty<'tcx>, pub err: Ty<'tcx>,
} }
#[derive(RustcEncodable, RustcDecodable)]
pub struct Tables<'tcx> { pub struct Tables<'tcx> {
/// Resolved definitions for `<T>::X` associated paths. /// Resolved definitions for `<T>::X` associated paths.
pub type_relative_path_defs: NodeMap<Def>, pub type_relative_path_defs: NodeMap<Def>,
@ -399,7 +402,7 @@ pub struct GlobalCtxt<'tcx> {
free_region_maps: RefCell<NodeMap<FreeRegionMap>>, free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
// FIXME: jroesch make this a refcell // FIXME: jroesch make this a refcell
pub tables: RefCell<Tables<'tcx>>, pub tables: RefCell<DepTrackingMap<maps::Tables<'tcx>>>,
/// Maps from a trait item to the trait item "descriptor" /// Maps from a trait item to the trait item "descriptor"
pub associated_items: RefCell<DepTrackingMap<maps::AssociatedItems<'tcx>>>, pub associated_items: RefCell<DepTrackingMap<maps::AssociatedItems<'tcx>>>,
@ -651,6 +654,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.global_arenas.mir.alloc(RefCell::new(mir)) self.global_arenas.mir.alloc(RefCell::new(mir))
} }
pub fn alloc_tables(self, tables: ty::Tables<'gcx>) -> &'gcx ty::Tables<'gcx> {
self.global_arenas.tables.alloc(tables)
}
pub fn alloc_trait_def(self, def: ty::TraitDef) -> &'gcx ty::TraitDef { pub fn alloc_trait_def(self, def: ty::TraitDef) -> &'gcx ty::TraitDef {
self.global_arenas.trait_def.alloc(def) self.global_arenas.trait_def.alloc(def)
} }
@ -749,7 +756,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
variance_computed: Cell::new(false), variance_computed: Cell::new(false),
sess: s, sess: s,
trait_map: resolutions.trait_map, trait_map: resolutions.trait_map,
tables: RefCell::new(Tables::empty()), tables: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
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())),
adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())), adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),

View file

@ -48,3 +48,4 @@ dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>> }
dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>> } dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>> }
dep_map_ty! { ClosureKinds: ItemSignature(DefId) -> ty::ClosureKind } dep_map_ty! { ClosureKinds: ItemSignature(DefId) -> ty::ClosureKind }
dep_map_ty! { ClosureTypes: ItemSignature(DefId) -> ty::ClosureTy<'tcx> } dep_map_ty! { ClosureTypes: ItemSignature(DefId) -> ty::ClosureTy<'tcx> }
dep_map_ty! { Tables: Tables(DefId) -> &'tcx ty::Tables<'tcx> }

View file

@ -321,7 +321,7 @@ pub struct MethodCallee<'tcx> {
/// needed to add to the side tables. Thus to disambiguate /// needed to add to the side tables. Thus to disambiguate
/// we also keep track of whether there's an adjustment in /// we also keep track of whether there's an adjustment in
/// our key. /// our key.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct MethodCall { pub struct MethodCall {
pub expr_id: NodeId, pub expr_id: NodeId,
pub autoderef: u32 pub autoderef: u32
@ -501,7 +501,7 @@ impl<T> Slice<T> {
/// Upvars do not get their own node-id. Instead, we use the pair of /// Upvars do not get their own node-id. Instead, we use the pair of
/// the original var id (that is, the root variable that is referenced /// the original var id (that is, the root variable that is referenced
/// by the upvar) and the id of the closure expression. /// by the upvar) and the id of the closure expression.
#[derive(Clone, Copy, PartialEq, Eq, Hash)] #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct UpvarId { pub struct UpvarId {
pub var_id: NodeId, pub var_id: NodeId,
pub closure_expr_id: NodeId, pub closure_expr_id: NodeId,
@ -1917,19 +1917,30 @@ impl BorrowKind {
} }
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn tables(self) -> Ref<'a, Tables<'gcx>> { pub fn body_tables(self, body: hir::BodyId) -> &'gcx Tables<'gcx> {
self.tables.borrow()
}
pub fn body_tables(self, body: hir::BodyId) -> &'a Tables<'gcx> {
self.item_tables(self.map.body_owner_def_id(body)) self.item_tables(self.map.body_owner_def_id(body))
} }
pub fn item_tables(self, _def_id: DefId) -> &'a Tables<'gcx> { pub fn item_tables(self, def_id: DefId) -> &'gcx Tables<'gcx> {
// HACK(eddyb) temporarily work around RefCell until proper per-body tables self.tables.memoize(def_id, || {
unsafe { if def_id.is_local() {
mem::transmute::<&Tables, &Tables>(&self.tables()) // Closures' tables come from their outermost function,
// as they are part of the same "inference environment".
let outer_def_id = self.closure_base_def_id(def_id);
if outer_def_id != def_id {
return self.item_tables(outer_def_id);
} }
bug!("No def'n found for {:?} in tcx.tables", def_id);
}
// Cross-crate side-tables only exist alongside serialized HIR.
self.sess.cstore.maybe_get_item_body(self.global_tcx(), def_id).map(|_| {
self.tables.borrow()[&def_id]
}).unwrap_or_else(|| {
bug!("tcx.item_tables({:?}): missing from metadata", def_id)
})
})
} }
pub fn expr_span(self, id: NodeId) -> Span { pub fn expr_span(self, id: NodeId) -> Span {

View file

@ -52,22 +52,21 @@ macro_rules! math {
fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
variant_def: DefId) variant_def: DefId)
-> Option<(&'tcx Expr, &'a ty::Tables<'tcx>)> { -> Option<(&'tcx Expr, Option<&'a ty::Tables<'tcx>>)> {
if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) { if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
let enum_node_id = tcx.map.get_parent(variant_node_id); let enum_node_id = tcx.map.get_parent(variant_node_id);
if let Some(ast_map::NodeItem(it)) = tcx.map.find(enum_node_id) { if let Some(ast_map::NodeItem(it)) = tcx.map.find(enum_node_id) {
match it.node { if let hir::ItemEnum(ref edef, _) = it.node {
hir::ItemEnum(hir::EnumDef { ref variants }, _) => { for variant in &edef.variants {
for variant in variants {
if variant.node.data.id() == variant_node_id { if variant.node.data.id() == variant_node_id {
return variant.node.disr_expr.map(|e| { return variant.node.disr_expr.map(|e| {
(&tcx.map.body(e).value, tcx.body_tables(e)) let def_id = tcx.map.body_owner_def_id(e);
(&tcx.map.body(e).value,
tcx.tables.borrow().get(&def_id).cloned())
}); });
} }
} }
} }
_ => {}
}
} }
} }
None None
@ -81,7 +80,8 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId, def_id: DefId,
substs: Option<&'tcx Substs<'tcx>>) substs: Option<&'tcx Substs<'tcx>>)
-> Option<(&'tcx Expr, &'a ty::Tables<'tcx>, -> Option<(&'tcx Expr,
Option<&'a ty::Tables<'tcx>>,
Option<ty::Ty<'tcx>>)> { Option<ty::Ty<'tcx>>)> {
if let Some(node_id) = tcx.map.as_local_node_id(def_id) { if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
match tcx.map.find(node_id) { match tcx.map.find(node_id) {
@ -92,7 +92,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Some(ast_map::NodeImplItem(&hir::ImplItem { Some(ast_map::NodeImplItem(&hir::ImplItem {
node: hir::ImplItemKind::Const(ref ty, body), .. node: hir::ImplItemKind::Const(ref ty, body), ..
})) => { })) => {
Some((&tcx.map.body(body).value, tcx.item_tables(def_id), Some((&tcx.map.body(body).value,
tcx.tables.borrow().get(&def_id).cloned(),
tcx.ast_ty_to_prim_ty(ty))) tcx.ast_ty_to_prim_ty(ty)))
} }
Some(ast_map::NodeTraitItem(ti)) => match ti.node { Some(ast_map::NodeTraitItem(ti)) => match ti.node {
@ -104,7 +105,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let trait_id = tcx.map.get_parent(node_id); let trait_id = tcx.map.get_parent(node_id);
let trait_id = tcx.map.local_def_id(trait_id); let trait_id = tcx.map.local_def_id(trait_id);
let default_value = default.map(|body| { let default_value = default.map(|body| {
(&tcx.map.body(body).value, tcx.item_tables(def_id), (&tcx.map.body(body).value,
tcx.tables.borrow().get(&def_id).cloned(),
tcx.ast_ty_to_prim_ty(ty)) tcx.ast_ty_to_prim_ty(ty))
}); });
resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs) resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
@ -124,7 +126,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
} else { } else {
let expr_tables_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { let expr_tables_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
(&body.value, tcx.item_tables(def_id), (&body.value, Some(tcx.item_tables(def_id)),
Some(tcx.sess.cstore.item_type(tcx, def_id))) Some(tcx.sess.cstore.item_type(tcx, def_id)))
}); });
match tcx.sess.cstore.describe_def(def_id) { match tcx.sess.cstore.describe_def(def_id) {
@ -152,12 +154,13 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> Option<(&'tcx hir::Body, &'a ty::Tables<'tcx>)> -> Option<(&'tcx hir::Body, Option<&'a ty::Tables<'tcx>>)>
{ {
if let Some(node_id) = tcx.map.as_local_node_id(def_id) { if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
FnLikeNode::from_node(tcx.map.get(node_id)).and_then(|fn_like| { FnLikeNode::from_node(tcx.map.get(node_id)).and_then(|fn_like| {
if fn_like.constness() == hir::Constness::Const { if fn_like.constness() == hir::Constness::Const {
Some((tcx.map.body(fn_like.body()), tcx.body_tables(fn_like.body()))) Some((tcx.map.body(fn_like.body()),
tcx.tables.borrow().get(&def_id).cloned()))
} else { } else {
None None
} }
@ -165,7 +168,7 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
} else { } else {
if tcx.sess.cstore.is_const_fn(def_id) { if tcx.sess.cstore.is_const_fn(def_id) {
tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
(body, tcx.item_tables(def_id)) (body, Some(tcx.item_tables(def_id)))
}) })
} else { } else {
None None
@ -223,19 +226,24 @@ pub fn note_const_eval_err<'a, 'tcx>(
pub struct ConstContext<'a, 'tcx: 'a> { pub struct ConstContext<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::Tables<'tcx>, tables: Option<&'a ty::Tables<'tcx>>,
fn_args: Option<DefIdMap<ConstVal>> fn_args: Option<DefIdMap<ConstVal>>
} }
impl<'a, 'tcx> ConstContext<'a, 'tcx> { impl<'a, 'tcx> ConstContext<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self {
ConstContext::with_tables(tcx, tcx.body_tables(body)) let def_id = tcx.map.body_owner_def_id(body);
ConstContext {
tcx: tcx,
tables: tcx.tables.borrow().get(&def_id).cloned(),
fn_args: None
}
} }
pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::Tables<'tcx>) -> Self { pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::Tables<'tcx>) -> Self {
ConstContext { ConstContext {
tcx: tcx, tcx: tcx,
tables: tables, tables: Some(tables),
fn_args: None fn_args: None
} }
} }
@ -436,7 +444,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
let ety = match ty_hint { let ety = match ty_hint {
ExprTypeChecked => { ExprTypeChecked => {
// After type-checking, expr_ty is guaranteed to succeed. // After type-checking, expr_ty is guaranteed to succeed.
Some(cx.tables.expr_ty(e)) cx.tables.map(|tables| tables.expr_ty(e))
} }
UncheckedExprHint(ty) => { UncheckedExprHint(ty) => {
// Use the type hint; it's not guaranteed to be right, but it's // Use the type hint; it's not guaranteed to be right, but it's
@ -447,7 +455,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
// This expression might not be type-checked, and we have no hint. // This expression might not be type-checked, and we have no hint.
// Try to query the context for a type anyway; we might get lucky // Try to query the context for a type anyway; we might get lucky
// (for example, if the expression was imported from another crate). // (for example, if the expression was imported from another crate).
cx.tables.expr_ty_opt(e) cx.tables.and_then(|tables| tables.expr_ty_opt(e))
} }
}; };
let result = match e.node { let result = match e.node {
@ -594,7 +602,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
let base_hint = if let ExprTypeChecked = ty_hint { let base_hint = if let ExprTypeChecked = ty_hint {
ExprTypeChecked ExprTypeChecked
} else { } else {
match cx.tables.expr_ty_opt(&base) { match cx.tables.and_then(|tables| tables.expr_ty_opt(&base)) {
Some(t) => UncheckedExprHint(t), Some(t) => UncheckedExprHint(t),
None => ty_hint None => ty_hint
} }
@ -623,12 +631,18 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
} }
} }
hir::ExprPath(ref qpath) => { hir::ExprPath(ref qpath) => {
let def = cx.tables.qpath_def(qpath, e.id); let def = cx.tables.map(|tables| tables.qpath_def(qpath, e.id)).unwrap_or_else(|| {
// There are no tables so we can only handle already-resolved HIR.
match *qpath {
hir::QPath::Resolved(_, ref path) => path.def,
hir::QPath::TypeRelative(..) => Def::Err
}
});
match def { match def {
Def::Const(def_id) | Def::Const(def_id) |
Def::AssociatedConst(def_id) => { Def::AssociatedConst(def_id) => {
let substs = if let ExprTypeChecked = ty_hint { let substs = if let ExprTypeChecked = ty_hint {
Some(cx.tables.node_id_item_substs(e.id) Some(cx.tables.and_then(|tables| tables.node_id_item_substs(e.id))
.unwrap_or_else(|| tcx.intern_substs(&[]))) .unwrap_or_else(|| tcx.intern_substs(&[])))
} else { } else {
None None
@ -638,7 +652,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
Some(ty) => ty_hint.checked_or(ty), Some(ty) => ty_hint.checked_or(ty),
None => ty_hint, None => ty_hint,
}; };
let cx = ConstContext::with_tables(tcx, tables); let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
match cx.eval(expr, item_hint) { match cx.eval(expr, item_hint) {
Ok(val) => val, Ok(val) => val,
Err(err) => { Err(err) => {
@ -652,7 +666,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
}, },
Def::VariantCtor(variant_def, ..) => { Def::VariantCtor(variant_def, ..) => {
if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) { if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
let cx = ConstContext::with_tables(tcx, tables); let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
match cx.eval(expr, ty_hint) { match cx.eval(expr, ty_hint) {
Ok(val) => val, Ok(val) => val,
Err(err) => { Err(err) => {
@ -903,10 +917,10 @@ fn infer<'a, 'tcx>(i: ConstInt,
fn resolve_trait_associated_const<'a, 'tcx: 'a>( fn resolve_trait_associated_const<'a, 'tcx: 'a>(
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_item_id: DefId, trait_item_id: DefId,
default_value: Option<(&'tcx Expr, &'a ty::Tables<'tcx>, Option<ty::Ty<'tcx>>)>, default_value: Option<(&'tcx Expr, Option<&'a ty::Tables<'tcx>>, Option<ty::Ty<'tcx>>)>,
trait_id: DefId, trait_id: DefId,
rcvr_substs: &'tcx Substs<'tcx> rcvr_substs: &'tcx Substs<'tcx>
) -> Option<(&'tcx Expr, &'a ty::Tables<'tcx>, Option<ty::Ty<'tcx>>)> ) -> Option<(&'tcx Expr, Option<&'a ty::Tables<'tcx>>, Option<ty::Ty<'tcx>>)>
{ {
let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs)); let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
debug!("resolve_trait_associated_const: trait_ref={:?}", debug!("resolve_trait_associated_const: trait_ref={:?}",

View file

@ -582,7 +582,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
Some((const_expr, const_tables, _const_ty)) => { Some((const_expr, const_tables, _const_ty)) => {
// Enter the inlined constant's tables temporarily. // Enter the inlined constant's tables temporarily.
let old_tables = self.tables; let old_tables = self.tables;
self.tables = const_tables; self.tables = const_tables.expect("missing tables after typeck");
let pat = self.lower_const_expr(const_expr, pat_id, span); let pat = self.lower_const_expr(const_expr, pat_id, span);
self.tables = old_tables; self.tables = old_tables;
return pat; return pat;

View file

@ -8,60 +8,31 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use rustc::hir::map as ast_map; use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange, NestedVisitorMap};
use cstore::CrateMetadata;
use encoder::EncodeContext; use encoder::EncodeContext;
use schema::*; use schema::*;
use rustc::hir; use rustc::hir;
use rustc::hir::def::Def; use rustc::ty;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TyCtxt, Ty};
use syntax::ast;
use rustc_serialize::Encodable; use rustc_serialize::Encodable;
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
pub struct Ast<'tcx> { pub struct Ast<'tcx> {
id_range: IdRange, pub body: Lazy<hir::Body>,
body: Lazy<hir::Body>, pub tables: Lazy<ty::Tables<'tcx>>,
side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)>,
pub nested_bodies: LazySeq<hir::Body>, pub nested_bodies: LazySeq<hir::Body>,
pub rvalue_promotable_to_static: bool, pub rvalue_promotable_to_static: bool,
} }
#[derive(RustcEncodable, RustcDecodable)]
enum TableEntry<'tcx> {
TypeRelativeDef(Def),
NodeType(Ty<'tcx>),
ItemSubsts(ty::ItemSubsts<'tcx>),
Adjustment(ty::adjustment::Adjustment<'tcx>),
}
impl<'a, 'tcx> EncodeContext<'a, 'tcx> { impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
pub fn encode_body(&mut self, body: hir::BodyId) -> Lazy<Ast<'tcx>> { pub fn encode_body(&mut self, body_id: hir::BodyId) -> Lazy<Ast<'tcx>> {
let body = self.tcx.map.body(body); let body = self.tcx.map.body(body_id);
let lazy_body = self.lazy(body);
let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map); let tables = self.tcx.body_tables(body_id);
id_visitor.visit_body(body); let lazy_tables = self.lazy(tables);
let body_pos = self.position();
body.encode(self).unwrap();
let tables_pos = self.position();
let tables_count = {
let mut visitor = SideTableEncodingIdVisitor {
tables: self.tcx.body_tables(body.id()),
ecx: self,
count: 0,
};
visitor.visit_body(body);
visitor.count
};
let nested_pos = self.position(); let nested_pos = self.position();
let nested_count = { let nested_count = {
@ -77,45 +48,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id]; self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id];
self.lazy(&Ast { self.lazy(&Ast {
id_range: id_visitor.result(), body: lazy_body,
body: Lazy::with_position(body_pos), tables: lazy_tables,
side_tables: LazySeq::with_position_and_length(tables_pos, tables_count),
nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count), nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count),
rvalue_promotable_to_static: rvalue_promotable_to_static rvalue_promotable_to_static: rvalue_promotable_to_static
}) })
} }
} }
struct SideTableEncodingIdVisitor<'a, 'b: 'a, 'tcx: 'b> {
ecx: &'a mut EncodeContext<'b, 'tcx>,
tables: &'a ty::Tables<'tcx>,
count: usize,
}
impl<'a, 'b, 'tcx> Visitor<'tcx> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::OnlyBodies(&self.ecx.tcx.map)
}
fn visit_id(&mut self, id: ast::NodeId) {
debug!("Encoding side tables for id {}", id);
let tables = self.tables;
let mut encode = |entry: Option<TableEntry>| {
if let Some(entry) = entry {
(id, entry).encode(self.ecx).unwrap();
self.count += 1;
}
};
encode(tables.type_relative_path_defs.get(&id).cloned()
.map(TableEntry::TypeRelativeDef));
encode(tables.node_types.get(&id).cloned().map(TableEntry::NodeType));
encode(tables.item_substs.get(&id).cloned().map(TableEntry::ItemSubsts));
encode(tables.adjustments.get(&id).cloned().map(TableEntry::Adjustment));
}
}
struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> { struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> {
ecx: &'a mut EncodeContext<'b, 'tcx>, ecx: &'a mut EncodeContext<'b, 'tcx>,
count: usize, count: usize,
@ -134,41 +74,3 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedBodyEncodingVisitor<'a, 'b, 'tcx> {
self.visit_body(body); self.visit_body(body);
} }
} }
/// Decodes an item's body from its AST in the cdata's metadata and adds it to the
/// ast-map.
pub fn decode_body<'a, 'tcx>(cdata: &CrateMetadata,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
ast: Ast<'tcx>)
-> &'tcx hir::Body {
debug!("> Decoding inlined fn: {}", tcx.item_path_str(def_id));
let cnt = ast.id_range.max.as_usize() - ast.id_range.min.as_usize();
let start = tcx.sess.reserve_node_ids(cnt);
let id_ranges = [ast.id_range,
IdRange {
min: start,
max: ast::NodeId::new(start.as_usize() + cnt),
}];
for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) {
match entry {
TableEntry::TypeRelativeDef(def) => {
tcx.tables.borrow_mut().type_relative_path_defs.insert(id, def);
}
TableEntry::NodeType(ty) => {
tcx.tables.borrow_mut().node_types.insert(id, ty);
}
TableEntry::ItemSubsts(item_substs) => {
tcx.tables.borrow_mut().item_substs.insert(id, item_substs);
}
TableEntry::Adjustment(adj) => {
tcx.tables.borrow_mut().adjustments.insert(id, adj);
}
}
}
let body = ast.body.decode((cdata, tcx, id_ranges));
ast_map::map_decoded_body(&tcx.map, def_id, body, tcx.sess.next_node_id())
}

View file

@ -97,7 +97,6 @@ pub struct CStore {
used_link_args: RefCell<Vec<String>>, used_link_args: RefCell<Vec<String>>,
statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>, statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>, pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub inlined_item_cache: RefCell<DefIdMap<Option<ast::NodeId>>>,
pub visible_parent_map: RefCell<DefIdMap<DefId>>, pub visible_parent_map: RefCell<DefIdMap<DefId>>,
} }
@ -112,7 +111,6 @@ impl CStore {
statically_included_foreign_items: RefCell::new(FxHashSet()), statically_included_foreign_items: RefCell::new(FxHashSet()),
dllimport_foreign_items: RefCell::new(FxHashSet()), dllimport_foreign_items: RefCell::new(FxHashSet()),
visible_parent_map: RefCell::new(FxHashMap()), visible_parent_map: RefCell::new(FxHashMap()),
inlined_item_cache: RefCell::new(FxHashMap()),
} }
} }

View file

@ -434,27 +434,14 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
def_id: DefId) def_id: DefId)
-> Option<&'tcx hir::Body> -> Option<&'tcx hir::Body>
{ {
self.dep_graph.read(DepNode::MetaData(def_id)); if let Some(cached) = tcx.map.get_inlined_body(def_id) {
return Some(cached);
if let Some(&cached) = self.inlined_item_cache.borrow().get(&def_id) {
return cached.map(|root_id| {
// Already inline
debug!("maybe_get_item_body({}): already inline", tcx.item_path_str(def_id));
tcx.map.expect_inlined_body(root_id)
});
} }
self.dep_graph.read(DepNode::MetaData(def_id));
debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id)); debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id));
let inlined = self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index); self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index)
self.inlined_item_cache.borrow_mut().insert(def_id, inlined.map(|body| {
let root_id = tcx.map.get_parent_node(body.value.id);
assert_eq!(tcx.map.get_parent_node(root_id), root_id);
root_id
}));
inlined
} }
fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> { fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {

View file

@ -10,13 +10,11 @@
// Decoding metadata from a single crate's metadata // Decoding metadata from a single crate's metadata
use astencode::decode_body;
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary}; use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
use schema::*; use schema::*;
use rustc::hir::map::{DefKey, DefPath, DefPathData}; use rustc::hir::map::{DefKey, DefPath, DefPathData};
use rustc::hir; use rustc::hir;
use rustc::hir::intravisit::IdRange;
use rustc::middle::cstore::LinkagePreference; use rustc::middle::cstore::LinkagePreference;
use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def::{self, Def, CtorKind};
@ -40,7 +38,7 @@ use std::u32;
use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
use syntax::attr; use syntax::attr;
use syntax::ast::{self, NodeId}; use syntax::ast;
use syntax::codemap; use syntax::codemap;
use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP}; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP};
use rustc_i128::{u128, i128}; use rustc_i128::{u128, i128};
@ -50,8 +48,6 @@ pub struct DecodeContext<'a, 'tcx: 'a> {
cdata: Option<&'a CrateMetadata>, cdata: Option<&'a CrateMetadata>,
sess: Option<&'a Session>, sess: Option<&'a Session>,
tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>, tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
from_id_range: IdRange,
to_id_range: IdRange,
// Cache the last used filemap for translating spans as an optimization. // Cache the last used filemap for translating spans as an optimization.
last_filemap_index: usize, last_filemap_index: usize,
@ -67,18 +63,12 @@ pub trait Metadata<'a, 'tcx>: Copy {
fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> { None } fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> { None }
fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
let id_range = IdRange {
min: NodeId::from_u32(u32::MIN),
max: NodeId::from_u32(u32::MAX),
};
let tcx = self.tcx(); let tcx = self.tcx();
DecodeContext { DecodeContext {
opaque: opaque::Decoder::new(self.raw_bytes(), pos), opaque: opaque::Decoder::new(self.raw_bytes(), pos),
cdata: self.cdata(), cdata: self.cdata(),
sess: self.sess().or(tcx.map(|tcx| tcx.sess)), sess: self.sess().or(tcx.map(|tcx| tcx.sess)),
tcx: tcx, tcx: tcx,
from_id_range: id_range,
to_id_range: id_range,
last_filemap_index: 0, last_filemap_index: 0,
lazy_state: LazyState::NoNode, lazy_state: LazyState::NoNode,
} }
@ -128,26 +118,6 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>
} }
} }
// HACK(eddyb) Only used by astencode to customize the from/to IdRange's.
impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>, [IdRange; 2]) {
fn raw_bytes(self) -> &'a [u8] {
self.0.raw_bytes()
}
fn cdata(self) -> Option<&'a CrateMetadata> {
Some(self.0)
}
fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> {
Some(self.1)
}
fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
let mut dcx = (self.0, self.1).decoder(pos);
dcx.from_id_range = self.2[0];
dcx.to_id_range = self.2[1];
dcx
}
}
impl<'a, 'tcx: 'a, T: Decodable> Lazy<T> { impl<'a, 'tcx: 'a, T: Decodable> Lazy<T> {
pub fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> T { pub fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> T {
let mut dcx = meta.decoder(self.position); let mut dcx = meta.decoder(self.position);
@ -256,28 +226,6 @@ impl<'a, 'tcx, T> SpecializedDecoder<LazySeq<T>> for DecodeContext<'a, 'tcx> {
} }
} }
impl<'a, 'tcx> SpecializedDecoder<NodeId> for DecodeContext<'a, 'tcx> {
fn specialized_decode(&mut self) -> Result<NodeId, Self::Error> {
let id = u32::decode(self)?;
// from_id_range should be non-empty
assert!(!self.from_id_range.empty());
// Make sure that translating the NodeId will actually yield a
// meaningful result
if !self.from_id_range.contains(NodeId::from_u32(id)) {
bug!("NodeId::decode: {} out of DecodeContext range ({:?} -> {:?})",
id,
self.from_id_range,
self.to_id_range);
}
// Use wrapping arithmetic because otherwise it introduces control flow.
// Maybe we should just have the control flow? -- aatch
Ok(NodeId::from_u32(id.wrapping_sub(self.from_id_range.min.as_u32())
.wrapping_add(self.to_id_range.min.as_u32())))
}
}
impl<'a, 'tcx> SpecializedDecoder<CrateNum> for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder<CrateNum> for DecodeContext<'a, 'tcx> {
fn specialized_decode(&mut self) -> Result<CrateNum, Self::Error> { fn specialized_decode(&mut self) -> Result<CrateNum, Self::Error> {
let cnum = CrateNum::from_u32(u32::decode(self)?); let cnum = CrateNum::from_u32(u32::decode(self)?);
@ -829,7 +777,14 @@ impl<'a, 'tcx> CrateMetadata {
-> Option<&'tcx hir::Body> { -> Option<&'tcx hir::Body> {
if self.is_proc_macro(id) { return None; } if self.is_proc_macro(id) { return None; }
self.entry(id).ast.map(|ast| { self.entry(id).ast.map(|ast| {
decode_body(self, tcx, self.local_def_id(id), ast.decode(self)) let def_id = self.local_def_id(id);
let ast = ast.decode(self);
let tables = ast.tables.decode((self, tcx));
tcx.tables.borrow_mut().insert(def_id, tcx.alloc_tables(tables));
let body = ast.body.decode((self, tcx));
tcx.map.intern_inlined_body(def_id, body)
}) })
} }

View file

@ -20,7 +20,6 @@ use rustc::mir::transform::MirSource;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err}; use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::blocks::FnLikeNode;
use rustc::infer::InferCtxt; use rustc::infer::InferCtxt;
@ -52,17 +51,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
MirSource::Promoted(..) => bug!(), MirSource::Promoted(..) => bug!(),
}; };
let src_node_id = src.item_id(); let attrs = infcx.tcx.map.attrs(src.item_id());
// We are going to be accessing various tables
// generated by TypeckItemBody; we also assume
// that the body passes type check. These tables
// are not individually tracked, so just register
// a read here.
let src_def_id = infcx.tcx.map.local_def_id(src_node_id);
infcx.tcx.dep_graph.read(DepNode::TypeckItemBody(src_def_id));
let attrs = infcx.tcx.map.attrs(src_node_id);
// Some functions always have overflow checks enabled, // Some functions always have overflow checks enabled,
// however, they may not get codegen'd, depending on // however, they may not get codegen'd, depending on

View file

@ -95,8 +95,6 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
let sym = ccx.symbol_map() let sym = ccx.symbol_map()
.get(TransItem::Static(id)) .get(TransItem::Static(id))
.expect("Local statics should always be in the SymbolMap"); .expect("Local statics should always be in the SymbolMap");
// Make sure that this is never executed for something inlined.
assert!(!ccx.tcx().map.is_inlined_node_id(id));
let defined_in_current_codegen_unit = ccx.codegen_unit() let defined_in_current_codegen_unit = ccx.codegen_unit()
.items() .items()

View file

@ -1738,14 +1738,6 @@ pub fn create_global_var_metadata(cx: &CrateContext,
let tcx = cx.tcx(); let tcx = cx.tcx();
// Don't create debuginfo for globals inlined from other crates. The other
// crate should already contain debuginfo for it. More importantly, the
// global might not even exist in un-inlined form anywhere which would lead
// to a linker errors.
if tcx.map.is_inlined_node_id(node_id) {
return;
}
let node_def_id = tcx.map.local_def_id(node_id); let node_def_id = tcx.map.local_def_id(node_id);
let (var_scope, span) = get_namespace_and_span_for_item(cx, node_def_id); let (var_scope, span) = get_namespace_and_span_for_item(cx, node_def_id);

View file

@ -679,7 +679,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations. fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
fcx.regionck_fn(fn_id, body); fcx.regionck_fn(fn_id, body);
fcx.resolve_type_vars_in_body(body, fn_id); fcx.resolve_type_vars_in_body(body);
}); });
} }
@ -1246,7 +1246,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
fcx.select_all_obligations_or_error(); fcx.select_all_obligations_or_error();
fcx.regionck_expr(body); fcx.regionck_expr(body);
fcx.resolve_type_vars_in_body(body, id); fcx.resolve_type_vars_in_body(body);
}); });
} }

View file

@ -33,10 +33,12 @@ use rustc::hir;
// Entry point // Entry point
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn resolve_type_vars_in_body(&self, pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) {
body: &'gcx hir::Body,
item_id: ast::NodeId) {
assert_eq!(self.writeback_errors.get(), false); assert_eq!(self.writeback_errors.get(), false);
let item_id = self.tcx.map.body_owner(body.id());
let item_def_id = self.tcx.map.local_def_id(item_id);
let mut wbcx = WritebackCx::new(self); let mut wbcx = WritebackCx::new(self);
for arg in &body.arguments { for arg in &body.arguments {
wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id); wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
@ -49,6 +51,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
wbcx.visit_anon_types(); wbcx.visit_anon_types();
wbcx.visit_deferred_obligations(item_id); wbcx.visit_deferred_obligations(item_id);
wbcx.visit_type_nodes(); wbcx.visit_type_nodes();
let tables = self.tcx.alloc_tables(wbcx.tables);
self.tcx.tables.borrow_mut().insert(item_def_id, tables);
} }
} }
@ -63,6 +68,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>,
tables: ty::Tables<'gcx>,
// Mapping from free regions of the function to the // Mapping from free regions of the function to the
// early-bound versions of them, visible from the // early-bound versions of them, visible from the
// outside of the function. This is needed by, and // outside of the function. This is needed by, and
@ -74,6 +81,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>) -> WritebackCx<'cx, 'gcx, 'tcx> { fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>) -> WritebackCx<'cx, 'gcx, 'tcx> {
let mut wbcx = WritebackCx { let mut wbcx = WritebackCx {
fcx: fcx, fcx: fcx,
tables: ty::Tables::empty(),
free_to_bound_regions: DefIdMap() free_to_bound_regions: DefIdMap()
}; };
@ -113,10 +121,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
self.fcx.tcx self.fcx.tcx
} }
fn write_ty_to_tcx(&self, node_id: ast::NodeId, ty: Ty<'gcx>) { fn write_ty_to_tables(&mut self, node_id: ast::NodeId, ty: Ty<'gcx>) {
debug!("write_ty_to_tcx({}, {:?})", node_id, ty); debug!("write_ty_to_tables({}, {:?})", node_id, ty);
assert!(!ty.needs_infer()); assert!(!ty.needs_infer());
self.tcx().tables.borrow_mut().node_types.insert(node_id, ty); self.tables.node_types.insert(node_id, ty);
} }
// Hacky hack: During type-checking, we treat *all* operators // Hacky hack: During type-checking, we treat *all* operators
@ -238,13 +246,13 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
let var_ty = self.fcx.local_ty(l.span, l.id); let var_ty = self.fcx.local_ty(l.span, l.id);
let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span)); let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
self.write_ty_to_tcx(l.id, var_ty); self.write_ty_to_tables(l.id, var_ty);
intravisit::walk_local(self, l); intravisit::walk_local(self, l);
} }
} }
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn visit_upvar_borrow_map(&self) { fn visit_upvar_borrow_map(&mut self) {
if self.fcx.writeback_errors.get() { if self.fcx.writeback_errors.get() {
return; return;
} }
@ -262,11 +270,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
debug!("Upvar capture for {:?} resolved to {:?}", debug!("Upvar capture for {:?} resolved to {:?}",
upvar_id, upvar_id,
new_upvar_capture); new_upvar_capture);
self.tcx() self.tables.upvar_capture_map.insert(*upvar_id, new_upvar_capture);
.tables
.borrow_mut()
.upvar_capture_map
.insert(*upvar_id, new_upvar_capture);
} }
} }
@ -336,10 +340,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
} }
} }
fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) { fn visit_node_id(&mut self, reason: ResolveReason, id: ast::NodeId) {
// Export associated path extensions. // Export associated path extensions.
if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&id) { if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&id) {
self.tcx().tables.borrow_mut().type_relative_path_defs.insert(id, def); self.tables.type_relative_path_defs.insert(id, def);
} }
// Resolve any borrowings for the node with id `id` // Resolve any borrowings for the node with id `id`
@ -348,7 +352,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
// Resolve the type of the node with id `id` // Resolve the type of the node with id `id`
let n_ty = self.fcx.node_ty(id); let n_ty = self.fcx.node_ty(id);
let n_ty = self.resolve(&n_ty, reason); let n_ty = self.resolve(&n_ty, reason);
self.write_ty_to_tcx(id, n_ty); self.write_ty_to_tables(id, n_ty);
debug!("Node {} has type {:?}", id, n_ty); debug!("Node {} has type {:?}", id, n_ty);
// Resolve any substitutions // Resolve any substitutions
@ -357,12 +361,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
if !item_substs.is_noop() { if !item_substs.is_noop() {
debug!("write_substs_to_tcx({}, {:?})", id, item_substs); debug!("write_substs_to_tcx({}, {:?})", id, item_substs);
assert!(!item_substs.substs.needs_infer()); assert!(!item_substs.substs.needs_infer());
self.tcx().tables.borrow_mut().item_substs.insert(id, item_substs); self.tables.item_substs.insert(id, item_substs);
} }
}); });
} }
fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) { fn visit_adjustments(&mut self, reason: ResolveReason, id: ast::NodeId) {
let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&id); let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&id);
match adjustments { match adjustments {
None => { None => {
@ -405,13 +409,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
target: self.resolve(&adjustment.target, reason) target: self.resolve(&adjustment.target, reason)
}; };
debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
self.tcx().tables.borrow_mut().adjustments.insert( self.tables.adjustments.insert(id, resolved_adjustment);
id, resolved_adjustment);
} }
} }
} }
fn visit_method_map_entry(&self, fn visit_method_map_entry(&mut self,
reason: ResolveReason, reason: ResolveReason,
method_call: MethodCall) { method_call: MethodCall) {
// Resolve any method map entry // Resolve any method map entry
@ -433,25 +436,25 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
//NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE //NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE
if let Some(method) = new_method { if let Some(method) = new_method {
self.tcx().tables.borrow_mut().method_map.insert(method_call, method); self.tables.method_map.insert(method_call, method);
} }
} }
fn visit_liberated_fn_sigs(&self) { fn visit_liberated_fn_sigs(&mut self) {
for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() { for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() {
let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id)); let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id));
self.tcx().tables.borrow_mut().liberated_fn_sigs.insert(node_id, fn_sig.clone()); self.tables.liberated_fn_sigs.insert(node_id, fn_sig.clone());
} }
} }
fn visit_fru_field_types(&self) { fn visit_fru_field_types(&mut self) {
for (&node_id, ftys) in self.fcx.tables.borrow().fru_field_types.iter() { for (&node_id, ftys) in self.fcx.tables.borrow().fru_field_types.iter() {
let ftys = self.resolve(ftys, ResolvingFieldTypes(node_id)); let ftys = self.resolve(ftys, ResolvingFieldTypes(node_id));
self.tcx().tables.borrow_mut().fru_field_types.insert(node_id, ftys); self.tables.fru_field_types.insert(node_id, ftys);
} }
} }
fn visit_deferred_obligations(&self, item_id: ast::NodeId) { fn visit_deferred_obligations(&mut self, item_id: ast::NodeId) {
let deferred_obligations = self.fcx.deferred_obligations.borrow(); let deferred_obligations = self.fcx.deferred_obligations.borrow();
let obligations: Vec<_> = deferred_obligations.iter().map(|obligation| { let obligations: Vec<_> = deferred_obligations.iter().map(|obligation| {
let reason = ResolvingDeferredObligation(obligation.cause.span); let reason = ResolvingDeferredObligation(obligation.cause.span);