Skip to content

Introduce HirId, a replacement for ast::NodeId after lowering to HIR #40518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 23, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions src/librustc/hir/def_id.rs
Original file line number Diff line number Diff line change
@@ -78,33 +78,86 @@ impl serialize::UseSpecializedDecodable for CrateNum {
/// A DefIndex is an index into the hir-map for a crate, identifying a
/// particular definition. It should really be considered an interned
/// shorthand for a particular DefPath.
///
/// At the moment we are allocating the numerical values of DefIndexes into two
/// ranges: the "low" range (starting at zero) and the "high" range (starting at
/// DEF_INDEX_HI_START). This allows us to allocate the DefIndexes of all
/// item-likes (Items, TraitItems, and ImplItems) into one of these ranges and
/// consequently use a simple array for lookup tables keyed by DefIndex and
/// known to be densely populated. This is especially important for the HIR map.
///
/// Since the DefIndex is mostly treated as an opaque ID, you probably
/// don't have to care about these ranges.
#[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
RustcDecodable, Hash, Copy)]
pub struct DefIndex(u32);

impl DefIndex {
#[inline]
pub fn new(x: usize) -> DefIndex {
assert!(x < (u32::MAX as usize));
DefIndex(x as u32)
}

#[inline]
pub fn from_u32(x: u32) -> DefIndex {
DefIndex(x)
}

#[inline]
pub fn as_usize(&self) -> usize {
self.0 as usize
}

#[inline]
pub fn as_u32(&self) -> u32 {
self.0
}

#[inline]
pub fn address_space(&self) -> DefIndexAddressSpace {
if self.0 < DEF_INDEX_HI_START.0 {
DefIndexAddressSpace::Low
} else {
DefIndexAddressSpace::High
}
}

/// Converts this DefIndex into a zero-based array index.
/// This index is the offset within the given "range" of the DefIndex,
/// that is, if the DefIndex is part of the "high" range, the resulting
/// index will be (DefIndex - DEF_INDEX_HI_START).
#[inline]
pub fn as_array_index(&self) -> usize {
(self.0 & !DEF_INDEX_HI_START.0) as usize
}
}

/// The start of the "high" range of DefIndexes.
const DEF_INDEX_HI_START: DefIndex = DefIndex(1 << 31);

/// The crate root is always assigned index 0 by the AST Map code,
/// thanks to `NodeCollector::new`.
pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);

#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub enum DefIndexAddressSpace {
Low = 0,
High = 1,
}

impl DefIndexAddressSpace {
#[inline]
pub fn index(&self) -> usize {
*self as usize
}

#[inline]
pub fn start(&self) -> usize {
self.index() * DEF_INDEX_HI_START.as_usize()
}
}

/// A DefId identifies a particular *definition*, by combining a crate
/// index and a def index.
#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, RustcDecodable, Hash, Copy)]
1,780 changes: 1,006 additions & 774 deletions src/librustc/hir/lowering.rs

Large diffs are not rendered by default.

67 changes: 46 additions & 21 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
@@ -9,13 +9,15 @@
// except according to those terms.

use hir::map::definitions::*;
use hir::def_id::{CRATE_DEF_INDEX, DefIndex};
use hir::def_id::{CRATE_DEF_INDEX, DefIndex, DefIndexAddressSpace};

use syntax::ast::*;
use syntax::ext::hygiene::Mark;
use syntax::visit;
use syntax::symbol::{Symbol, keywords};

use hir::map::{ITEM_LIKE_SPACE, REGULAR_SPACE};

/// Creates def ids for nodes in the AST.
pub struct DefCollector<'a> {
definitions: &'a mut Definitions,
@@ -39,23 +41,31 @@ impl<'a> DefCollector<'a> {
}

pub fn collect_root(&mut self) {
let root = self.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot);
let root = self.create_def_with_parent(None,
CRATE_NODE_ID,
DefPathData::CrateRoot,
ITEM_LIKE_SPACE);
assert_eq!(root, CRATE_DEF_INDEX);
self.parent_def = Some(root);
}

fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex {
fn create_def(&mut self,
node_id: NodeId,
data: DefPathData,
address_space: DefIndexAddressSpace)
-> DefIndex {
let parent_def = self.parent_def;
debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
self.definitions.create_def_with_parent(parent_def, node_id, data)
self.definitions.create_def_with_parent(parent_def, node_id, data, address_space)
}

fn create_def_with_parent(&mut self,
parent: Option<DefIndex>,
node_id: NodeId,
data: DefPathData)
data: DefPathData,
address_space: DefIndexAddressSpace)
-> DefIndex {
self.definitions.create_def_with_parent(parent, node_id, data)
self.definitions.create_def_with_parent(parent, node_id, data, address_space)
}

pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
@@ -76,7 +86,7 @@ impl<'a> DefCollector<'a> {
_ => {}
}

self.create_def(expr.id, DefPathData::Initializer);
self.create_def(expr.id, DefPathData::Initializer, REGULAR_SPACE);
}

fn visit_macro_invoc(&mut self, id: NodeId, const_expr: bool) {
@@ -118,27 +128,32 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
ViewPathSimple(..) => {}
ViewPathList(_, ref imports) => {
for import in imports {
self.create_def(import.node.id, DefPathData::Misc);
self.create_def(import.node.id,
DefPathData::Misc,
ITEM_LIKE_SPACE);
}
}
}
DefPathData::Misc
}
};
let def = self.create_def(i.id, def_data);
let def = self.create_def(i.id, def_data, ITEM_LIKE_SPACE);

self.with_parent(def, |this| {
match i.node {
ItemKind::Enum(ref enum_definition, _) => {
for v in &enum_definition.variants {
let variant_def_index =
this.create_def(v.node.data.id(),
DefPathData::EnumVariant(v.node.name.name.as_str()));
DefPathData::EnumVariant(v.node.name.name.as_str()),
REGULAR_SPACE);
this.with_parent(variant_def_index, |this| {
for (index, field) in v.node.data.fields().iter().enumerate() {
let name = field.ident.map(|ident| ident.name)
.unwrap_or_else(|| Symbol::intern(&index.to_string()));
this.create_def(field.id, DefPathData::Field(name.as_str()));
this.create_def(field.id,
DefPathData::Field(name.as_str()),
REGULAR_SPACE);
}

if let Some(ref expr) = v.node.disr_expr {
@@ -151,13 +166,14 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
// If this is a tuple-like struct, register the constructor.
if !struct_def.is_struct() {
this.create_def(struct_def.id(),
DefPathData::StructCtor);
DefPathData::StructCtor,
REGULAR_SPACE);
}

for (index, field) in struct_def.fields().iter().enumerate() {
let name = field.ident.map(|ident| ident.name.as_str())
.unwrap_or(Symbol::intern(&index.to_string()).as_str());
this.create_def(field.id, DefPathData::Field(name));
this.create_def(field.id, DefPathData::Field(name), REGULAR_SPACE);
}
}
_ => {}
@@ -168,7 +184,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {

fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
let def = self.create_def(foreign_item.id,
DefPathData::ValueNs(foreign_item.ident.name.as_str()));
DefPathData::ValueNs(foreign_item.ident.name.as_str()),
REGULAR_SPACE);

self.with_parent(def, |this| {
visit::walk_foreign_item(this, foreign_item);
@@ -177,7 +194,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {

fn visit_generics(&mut self, generics: &'a Generics) {
for ty_param in generics.ty_params.iter() {
self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.ident.name.as_str()));
self.create_def(ty_param.id,
DefPathData::TypeParam(ty_param.ident.name.as_str()),
REGULAR_SPACE);
}

visit::walk_generics(self, generics);
@@ -191,7 +210,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
};

let def = self.create_def(ti.id, def_data);
let def = self.create_def(ti.id, def_data, ITEM_LIKE_SPACE);
self.with_parent(def, |this| {
if let TraitItemKind::Const(_, Some(ref expr)) = ti.node {
this.visit_const_expr(expr);
@@ -209,7 +228,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
};

let def = self.create_def(ii.id, def_data);
let def = self.create_def(ii.id, def_data, ITEM_LIKE_SPACE);
self.with_parent(def, |this| {
if let ImplItemKind::Const(_, ref expr) = ii.node {
this.visit_const_expr(expr);
@@ -225,7 +244,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
match pat.node {
PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false),
PatKind::Ident(_, id, _) => {
let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
let def = self.create_def(pat.id,
DefPathData::Binding(id.node.name.as_str()),
REGULAR_SPACE);
self.parent_def = Some(def);
}
_ => {}
@@ -242,7 +263,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, false),
ExprKind::Repeat(_, ref count) => self.visit_const_expr(count),
ExprKind::Closure(..) => {
let def = self.create_def(expr.id, DefPathData::ClosureExpr);
let def = self.create_def(expr.id,
DefPathData::ClosureExpr,
REGULAR_SPACE);
self.parent_def = Some(def);
}
_ => {}
@@ -257,7 +280,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false),
TyKind::Array(_, ref length) => self.visit_const_expr(length),
TyKind::ImplTrait(..) => {
self.create_def(ty.id, DefPathData::ImplTrait);
self.create_def(ty.id, DefPathData::ImplTrait, REGULAR_SPACE);
}
TyKind::Typeof(ref expr) => self.visit_const_expr(expr),
_ => {}
@@ -266,7 +289,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
}

fn visit_lifetime_def(&mut self, def: &'a LifetimeDef) {
self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
self.create_def(def.lifetime.id,
DefPathData::LifetimeDef(def.lifetime.name.as_str()),
REGULAR_SPACE);
}

fn visit_stmt(&mut self, stmt: &'a Stmt) {
134 changes: 108 additions & 26 deletions src/librustc/hir/map/definitions.rs
Original file line number Diff line number Diff line change
@@ -14,8 +14,10 @@
//! There are also some rather random cases (like const initializer
//! expressions) that are mostly just leftovers.
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
use hir;
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, DefIndexAddressSpace};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::stable_hasher::StableHasher;
use serialize::{Encodable, Decodable, Encoder, Decoder};
use std::fmt::Write;
@@ -29,24 +31,44 @@ use util::nodemap::NodeMap;
/// Internally the DefPathTable holds a tree of DefKeys, where each DefKey
/// stores the DefIndex of its parent.
/// There is one DefPathTable for each crate.
#[derive(Clone)]
pub struct DefPathTable {
index_to_key: Vec<DefKey>,
index_to_key: [Vec<DefKey>; 2],
key_to_index: FxHashMap<DefKey, DefIndex>,
}

// Unfortunately we have to provide a manual impl of Clone because of the
// fixed-sized array field.
impl Clone for DefPathTable {
fn clone(&self) -> Self {
DefPathTable {
index_to_key: [self.index_to_key[0].clone(),
self.index_to_key[1].clone()],
key_to_index: self.key_to_index.clone(),
}
}
}

impl DefPathTable {
fn insert(&mut self, key: DefKey) -> DefIndex {
let index = DefIndex::new(self.index_to_key.len());
debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
self.index_to_key.push(key.clone());

fn allocate(&mut self,
key: DefKey,
address_space: DefIndexAddressSpace)
-> DefIndex {
let index = {
let index_to_key = &mut self.index_to_key[address_space.index()];
let index = DefIndex::new(index_to_key.len() + address_space.start());
debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
index_to_key.push(key.clone());
index
};
self.key_to_index.insert(key, index);
index
}

#[inline(always)]
pub fn def_key(&self, index: DefIndex) -> DefKey {
self.index_to_key[index.as_usize()].clone()
self.index_to_key[index.address_space().index()]
[index.as_array_index()].clone()
}

#[inline(always)]
@@ -94,17 +116,28 @@ impl DefPathTable {

impl Encodable for DefPathTable {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
self.index_to_key.encode(s)
self.index_to_key[DefIndexAddressSpace::Low.index()].encode(s)?;
self.index_to_key[DefIndexAddressSpace::High.index()].encode(s)
}
}

impl Decodable for DefPathTable {
fn decode<D: Decoder>(d: &mut D) -> Result<DefPathTable, D::Error> {
let index_to_key: Vec<DefKey> = Decodable::decode(d)?;
let key_to_index = index_to_key.iter()
.enumerate()
.map(|(index, key)| (key.clone(), DefIndex::new(index)))
.collect();
let index_to_key_lo: Vec<DefKey> = Decodable::decode(d)?;
let index_to_key_high: Vec<DefKey> = Decodable::decode(d)?;

let index_to_key = [index_to_key_lo, index_to_key_high];

let mut key_to_index = FxHashMap();

for space in &[DefIndexAddressSpace::Low, DefIndexAddressSpace::High] {
key_to_index.extend(index_to_key[space.index()]
.iter()
.enumerate()
.map(|(index, key)| (key.clone(),
DefIndex::new(index + space.start()))))
}

Ok(DefPathTable {
index_to_key: index_to_key,
key_to_index: key_to_index,
@@ -116,11 +149,27 @@ impl Decodable for DefPathTable {
/// The definition table containing node definitions.
/// It holds the DefPathTable for local DefIds/DefPaths and it also stores a
/// mapping from NodeIds to local DefIds.
#[derive(Clone)]
pub struct Definitions {
table: DefPathTable,
node_to_def_index: NodeMap<DefIndex>,
def_index_to_node: Vec<ast::NodeId>,
def_index_to_node: [Vec<ast::NodeId>; 2],
pub(super) node_to_hir_id: IndexVec<ast::NodeId, hir::HirId>,
}

// Unfortunately we have to provide a manual impl of Clone because of the
// fixed-sized array field.
impl Clone for Definitions {
fn clone(&self) -> Self {
Definitions {
table: self.table.clone(),
node_to_def_index: self.node_to_def_index.clone(),
def_index_to_node: [
self.def_index_to_node[0].clone(),
self.def_index_to_node[1].clone(),
],
node_to_hir_id: self.node_to_hir_id.clone(),
}
}
}

/// A unique identifier that we can use to lookup a definition
@@ -206,6 +255,23 @@ impl DefPath {
s
}

/// Returns a string representation of the DefPath without
/// the crate-prefix. This method is useful if you don't have
/// a TyCtxt available.
pub fn to_string_no_crate(&self) -> String {
let mut s = String::with_capacity(self.data.len() * 16);

for component in &self.data {
write!(s,
"::{}[{}]",
component.data.as_interned_str(),
component.disambiguator)
.unwrap();
}

s
}

pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 {
debug!("deterministic_hash({:?})", self);
let mut state = StableHasher::new();
@@ -270,11 +336,12 @@ impl Definitions {
pub fn new() -> Definitions {
Definitions {
table: DefPathTable {
index_to_key: vec![],
index_to_key: [vec![], vec![]],
key_to_index: FxHashMap(),
},
node_to_def_index: NodeMap(),
def_index_to_node: vec![],
def_index_to_node: [vec![], vec![]],
node_to_hir_id: IndexVec::new(),
}
}

@@ -283,8 +350,9 @@ impl Definitions {
}

/// Get the number of definitions.
pub fn len(&self) -> usize {
self.def_index_to_node.len()
pub fn def_index_counts_lo_hi(&self) -> (usize, usize) {
(self.def_index_to_node[DefIndexAddressSpace::Low.index()].len(),
self.def_index_to_node[DefIndexAddressSpace::High.index()].len())
}

pub fn def_key(&self, index: DefIndex) -> DefKey {
@@ -318,8 +386,9 @@ impl Definitions {

pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
if def_id.krate == LOCAL_CRATE {
assert!(def_id.index.as_usize() < self.def_index_to_node.len());
Some(self.def_index_to_node[def_id.index.as_usize()])
let space_index = def_id.index.address_space().index();
let array_index = def_id.index.as_array_index();
Some(self.def_index_to_node[space_index][array_index])
} else {
None
}
@@ -329,7 +398,9 @@ impl Definitions {
pub fn create_def_with_parent(&mut self,
parent: Option<DefIndex>,
node_id: ast::NodeId,
data: DefPathData)
data: DefPathData,
// is_owner: bool)
address_space: DefIndexAddressSpace)
-> DefIndex {
debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
parent, node_id, data);
@@ -359,14 +430,25 @@ impl Definitions {
debug!("create_def_with_parent: after disambiguation, key = {:?}", key);

// Create the definition.
let index = self.table.insert(key);
let index = self.table.allocate(key, address_space);
assert_eq!(index.as_array_index(),
self.def_index_to_node[address_space.index()].len());
self.def_index_to_node[address_space.index()].push(node_id);

debug!("create_def_with_parent: def_index_to_node[{:?} <-> {:?}", index, node_id);
self.node_to_def_index.insert(node_id, index);
assert_eq!(index.as_usize(), self.def_index_to_node.len());
self.def_index_to_node.push(node_id);

index
}

/// Initialize the ast::NodeId to HirId mapping once it has been generated during
/// AST to HIR lowering.
pub fn init_node_id_to_hir_id_mapping(&mut self,
mapping: IndexVec<ast::NodeId, hir::HirId>) {
assert!(self.node_to_hir_id.is_empty(),
"Trying initialize NodeId -> HirId mapping twice");
self.node_to_hir_id = mapping;
}
}

impl DefPathData {
184 changes: 184 additions & 0 deletions src/librustc/hir/map/hir_id_validator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// Copyright 2017 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.

use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
use hir::{self, intravisit, HirId, ItemLocalId};
use syntax::ast::NodeId;
use hir::itemlikevisit::ItemLikeVisitor;
use rustc_data_structures::fx::FxHashMap;

pub fn check_crate<'hir>(hir_map: &hir::map::Map<'hir>) {
let mut outer_visitor = OuterVisitor {
hir_map: hir_map,
errors: vec![],
};

hir_map.dep_graph.with_ignore(|| {
hir_map.krate().visit_all_item_likes(&mut outer_visitor);
if !outer_visitor.errors.is_empty() {
let message = outer_visitor
.errors
.iter()
.fold(String::new(), |s1, s2| s1 + "\n" + s2);
bug!("{}", message);
}
});
}

struct HirIdValidator<'a, 'hir: 'a> {
hir_map: &'a hir::map::Map<'hir>,
owner_def_index: Option<DefIndex>,
hir_ids_seen: FxHashMap<ItemLocalId, NodeId>,
errors: Vec<String>,
}

struct OuterVisitor<'a, 'hir: 'a> {
hir_map: &'a hir::map::Map<'hir>,
errors: Vec<String>,
}

impl<'a, 'hir: 'a> OuterVisitor<'a, 'hir> {
fn new_inner_visitor(&self,
hir_map: &'a hir::map::Map<'hir>)
-> HirIdValidator<'a, 'hir> {
HirIdValidator {
hir_map: hir_map,
owner_def_index: None,
hir_ids_seen: FxHashMap(),
errors: Vec::new(),
}
}
}

impl<'a, 'hir: 'a> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
fn visit_item(&mut self, i: &'hir hir::Item) {
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
inner_visitor.check(i.id, |this| intravisit::walk_item(this, i));
self.errors.extend(inner_visitor.errors.drain(..));
}

fn visit_trait_item(&mut self, i: &'hir hir::TraitItem) {
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
inner_visitor.check(i.id, |this| intravisit::walk_trait_item(this, i));
self.errors.extend(inner_visitor.errors.drain(..));
}

fn visit_impl_item(&mut self, i: &'hir hir::ImplItem) {
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
inner_visitor.check(i.id, |this| intravisit::walk_impl_item(this, i));
self.errors.extend(inner_visitor.errors.drain(..));
}
}

impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {

fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self,
node_id: NodeId,
walk: F) {
assert!(self.owner_def_index.is_none());
let owner_def_index = self.hir_map.local_def_id(node_id).index;
self.owner_def_index = Some(owner_def_index);
walk(self);

if owner_def_index == CRATE_DEF_INDEX {
return
}

// There's always at least one entry for the owning item itself
let max = self.hir_ids_seen
.keys()
.map(|local_id| local_id.as_usize())
.max()
.unwrap();

if max != self.hir_ids_seen.len() - 1 {
// Collect the missing ItemLocalIds
let missing: Vec<_> = (0 .. max + 1)
.filter(|&i| !self.hir_ids_seen.contains_key(&ItemLocalId(i as u32)))
.collect();

// Try to map those to something more useful
let mut missing_items = vec![];

for local_id in missing {
let hir_id = HirId {
owner: owner_def_index,
local_id: ItemLocalId(local_id as u32),
};

// We are already in ICE mode here, so doing a linear search
// should be fine.
let (node_id, _) = self.hir_map
.definitions()
.node_to_hir_id
.iter()
.enumerate()
.find(|&(_, &entry)| hir_id == entry)
.unwrap();
let node_id = NodeId::new(node_id);
missing_items.push(format!("[local_id: {}, node:{}]",
local_id,
self.hir_map.node_to_string(node_id)));
}

self.errors.push(format!(
"ItemLocalIds not assigned densely in {}. \
Max ItemLocalId = {}, missing IDs = {:?}",
self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(),
max,
missing_items));
}
}
}

impl<'a, 'hir: 'a> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {

fn nested_visit_map<'this>(&'this mut self)
-> intravisit::NestedVisitorMap<'this, 'hir> {
intravisit::NestedVisitorMap::OnlyBodies(self.hir_map)
}

fn visit_id(&mut self, node_id: NodeId) {
let owner = self.owner_def_index.unwrap();
let stable_id = self.hir_map.definitions().node_to_hir_id[node_id];

if stable_id == hir::DUMMY_HIR_ID {
self.errors.push(format!("HirIdValidator: No HirId assigned for NodeId {}: {:?}",
node_id,
self.hir_map.node_to_string(node_id)));
}

if owner != stable_id.owner {
self.errors.push(format!(
"HirIdValidator: The recorded owner of {} is {} instead of {}",
self.hir_map.node_to_string(node_id),
self.hir_map.def_path(DefId::local(stable_id.owner)).to_string_no_crate(),
self.hir_map.def_path(DefId::local(owner)).to_string_no_crate()));
}

if let Some(prev) = self.hir_ids_seen.insert(stable_id.local_id, node_id) {
if prev != node_id {
self.errors.push(format!(
"HirIdValidator: Same HirId {}/{} assigned for nodes {} and {}",
self.hir_map.def_path(DefId::local(stable_id.owner)).to_string_no_crate(),
stable_id.local_id.as_usize(),
self.hir_map.node_to_string(prev),
self.hir_map.node_to_string(node_id)));
}
}
}

fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) {
// Explicitly do nothing here. ImplItemRefs contain hir::Visibility
// values that actually belong to an ImplItem instead of the ItemImpl
// we are currently in. So for those it's correct that they have a
// different owner.
}
}
18 changes: 11 additions & 7 deletions src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,

use dep_graph::{DepGraph, DepNode};

use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex, DefIndexAddressSpace};

use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID};
@@ -36,6 +36,10 @@ pub mod blocks;
mod collector;
mod def_collector;
pub mod definitions;
mod hir_id_validator;

pub const ITEM_LIKE_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::Low;
pub const REGULAR_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::High;

#[derive(Copy, Clone, Debug)]
pub enum Node<'hir> {
@@ -346,10 +350,6 @@ impl<'hir> Map<'hir> {
}
}

pub fn num_local_def_ids(&self) -> usize {
self.definitions.len()
}

pub fn definitions(&self) -> &Definitions {
&self.definitions
}
@@ -964,13 +964,17 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest,
entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
}

Map {
let map = Map {
forest: forest,
dep_graph: forest.dep_graph.clone(),
map: map,
definitions: definitions,
inlined_bodies: RefCell::new(DefIdMap()),
}
};

hir_id_validator::check_crate(&map);

map
}

/// Identical to the `PpAnn` implementation for `hir::Crate`,
61 changes: 60 additions & 1 deletion src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ pub use self::Visibility::{Public, Inherited};
pub use self::PathParameters::*;

use hir::def::Def;
use hir::def_id::DefId;
use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
use util::nodemap::{NodeMap, FxHashSet};

use syntax_pos::{Span, ExpnId, DUMMY_SP};
@@ -43,6 +43,8 @@ use syntax::symbol::{Symbol, keywords};
use syntax::tokenstream::TokenStream;
use syntax::util::ThinVec;

use rustc_data_structures::indexed_vec;

use std::collections::BTreeMap;
use std::fmt;

@@ -73,6 +75,63 @@ pub mod pat_util;
pub mod print;
pub mod svh;

/// A HirId uniquely identifies a node in the HIR of then current crate. It is
/// composed of the `owner`, which is the DefIndex of the directly enclosing
/// hir::Item, hir::TraitItem, or hir::ImplItem (i.e. the closest "item-like"),
/// and the `local_id` which is unique within the given owner.
///
/// This two-level structure makes for more stable values: One can move an item
/// around within the source code, or add or remove stuff before it, without
/// the local_id part of the HirId changing, which is a very useful property
/// incremental compilation where we have to persist things through changes to
/// the code base.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug,
RustcEncodable, RustcDecodable)]
pub struct HirId {
pub owner: DefIndex,
pub local_id: ItemLocalId,
}

/// An `ItemLocalId` uniquely identifies something within a given "item-like",
/// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
/// guarantee that the numerical value of a given `ItemLocalId` corresponds to
/// the node's position within the owning item in any way, but there is a
/// guarantee that the `LocalItemId`s within an owner occupy a dense range of
/// integers starting at zero, so a mapping that maps all or most nodes within
/// an "item-like" to something else can be implement by a `Vec` instead of a
/// tree or hash map.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug,
RustcEncodable, RustcDecodable)]
pub struct ItemLocalId(pub u32);

impl ItemLocalId {
pub fn as_usize(&self) -> usize {
self.0 as usize
}
}

impl indexed_vec::Idx for ItemLocalId {
fn new(idx: usize) -> Self {
debug_assert!((idx as u32) as usize == idx);
ItemLocalId(idx as u32)
}

fn index(self) -> usize {
self.0 as usize
}
}

/// The `HirId` corresponding to CRATE_NODE_ID and CRATE_DEF_INDEX
pub const CRATE_HIR_ID: HirId = HirId {
owner: CRATE_DEF_INDEX,
local_id: ItemLocalId(0)
};

pub const DUMMY_HIR_ID: HirId = HirId {
owner: CRATE_DEF_INDEX,
local_id: ItemLocalId(!0)
};

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub struct Lifetime {
pub id: NodeId,
7 changes: 7 additions & 0 deletions src/librustc_data_structures/indexed_vec.rs
Original file line number Diff line number Diff line change
@@ -189,6 +189,13 @@ impl<I: Idx, T> IndexVec<I, T> {
}
}

impl<I: Idx, T: Clone> IndexVec<I, T> {
#[inline]
pub fn resize(&mut self, new_len: usize, value: T) {
self.raw.resize(new_len, value)
}
}

impl<I: Idx, T> Index<I> for IndexVec<I, T> {
type Output = T;

67 changes: 50 additions & 17 deletions src/librustc_metadata/index.rs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@

use schema::*;

use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace};
use std::io::{Cursor, Write};
use std::slice;
use std::u32;
@@ -23,12 +23,15 @@ use std::u32;
/// appropriate spot by calling `record_position`. We should never
/// visit the same index twice.
pub struct Index {
positions: Vec<u32>,
positions: [Vec<u32>; 2]
}

impl Index {
pub fn new(max_index: usize) -> Index {
Index { positions: vec![u32::MAX; max_index] }
pub fn new((max_index_lo, max_index_hi): (usize, usize)) -> Index {
Index {
positions: [vec![u32::MAX; max_index_lo],
vec![u32::MAX; max_index_hi]],
}
}

pub fn record(&mut self, def_id: DefId, entry: Lazy<Entry>) {
@@ -37,24 +40,31 @@ impl Index {
}

pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry>) {
let item = item.as_usize();

assert!(entry.position < (u32::MAX as usize));
let position = entry.position as u32;
let space_index = item.address_space().index();
let array_index = item.as_array_index();

assert!(self.positions[item] == u32::MAX,
assert!(self.positions[space_index][array_index] == u32::MAX,
"recorded position for item {:?} twice, first at {:?} and now at {:?}",
item,
self.positions[item],
self.positions[space_index][array_index],
position);

self.positions[item] = position.to_le();
self.positions[space_index][array_index] = position.to_le();
}

pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) -> LazySeq<Index> {
let pos = buf.position();
buf.write_all(words_to_bytes(&self.positions)).unwrap();
LazySeq::with_position_and_length(pos as usize, self.positions.len())

// First we write the length of the lower range ...
buf.write_all(words_to_bytes(&[self.positions[0].len() as u32])).unwrap();
// ... then the values in the lower range ...
buf.write_all(words_to_bytes(&self.positions[0][..])).unwrap();
// ... then the values in the higher range.
buf.write_all(words_to_bytes(&self.positions[1][..])).unwrap();
LazySeq::with_position_and_length(pos as usize,
self.positions[0].len() + self.positions[1].len() + 1)
}
}

@@ -70,7 +80,18 @@ impl<'tcx> LazySeq<Index> {
index,
words.len());

let position = u32::from_le(words[index].get());
let positions = match def_index.address_space() {
DefIndexAddressSpace::Low => &words[1..],
DefIndexAddressSpace::High => {
// This is a DefIndex in the higher range, so find out where
// that starts:
let lo_count = u32::from_le(words[0].get()) as usize;
&words[lo_count + 1 .. ]
}
};

let array_index = def_index.as_array_index();
let position = u32::from_le(positions[array_index].get());
if position == u32::MAX {
debug!("Index::lookup: position=u32::MAX");
None
@@ -84,14 +105,26 @@ impl<'tcx> LazySeq<Index> {
bytes: &'a [u8])
-> impl Iterator<Item = (DefIndex, Lazy<Entry<'tcx>>)> + 'a {
let words = &bytes_to_words(&bytes[self.position..])[..self.len];
words.iter().map(|word| word.get()).enumerate().filter_map(|(index, position)| {
if position == u32::MAX {
let lo_count = u32::from_le(words[0].get()) as usize;
let lo = &words[1 .. lo_count + 1];
let hi = &words[1 + lo_count ..];

lo.iter().map(|word| word.get()).enumerate().filter_map(|(index, pos)| {
if pos == u32::MAX {
None
} else {
let pos = u32::from_le(pos) as usize;
Some((DefIndex::new(index), Lazy::with_position(pos)))
}
}).chain(hi.iter().map(|word| word.get()).enumerate().filter_map(|(index, pos)| {
if pos == u32::MAX {
None
} else {
let position = u32::from_le(position) as usize;
Some((DefIndex::new(index), Lazy::with_position(position)))
let pos = u32::from_le(pos) as usize;
Some((DefIndex::new(index + DefIndexAddressSpace::High.start()),
Lazy::with_position(pos)))
}
})
}))
}
}

2 changes: 1 addition & 1 deletion src/librustc_metadata/index_builder.rs
Original file line number Diff line number Diff line change
@@ -90,7 +90,7 @@ impl<'a, 'b, 'tcx> DerefMut for IndexBuilder<'a, 'b, 'tcx> {
impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self {
IndexBuilder {
items: Index::new(ecx.tcx.hir.num_local_def_ids()),
items: Index::new(ecx.tcx.hir.definitions().def_index_counts_lo_hi()),
ecx: ecx,
}
}
11 changes: 11 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ use abi::Abi;
use ext::hygiene::SyntaxContext;
use print::pprust;
use ptr::P;
use rustc_data_structures::indexed_vec;
use symbol::{Symbol, keywords};
use tokenstream::{ThinTokenStream, TokenStream};

@@ -275,6 +276,16 @@ impl serialize::UseSpecializedDecodable for NodeId {
}
}

impl indexed_vec::Idx for NodeId {
fn new(idx: usize) -> Self {
NodeId::new(idx)
}

fn index(self) -> usize {
self.as_usize()
}
}

/// Node id used to represent the root of the crate.
pub const CRATE_NODE_ID: NodeId = NodeId(0);

14 changes: 3 additions & 11 deletions src/libsyntax/ext/placeholders.rs
Original file line number Diff line number Diff line change
@@ -178,17 +178,9 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
block.stmts = block.stmts.move_flat_map(|mut stmt| {
remaining_stmts -= 1;

match stmt.node {
// Avoid wasting a node id on a trailing expression statement,
// which shares a HIR node with the expression itself.
ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id,

_ if self.monotonic => {
assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
stmt.id = self.cx.resolver.next_node_id();
}

_ => {}
if self.monotonic {
assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
stmt.id = self.cx.resolver.next_node_id();
}

Some(stmt)
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ trait SomeTrait { }

// Bounds on object types:

struct Foo<'a,'b,'c> { //~ ERROR parameter `'b` is never used
struct Foo<'a,'b,'c> { //~ ERROR parameter `'c` is never used
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hahahaha I think I remember when this changed due to syntactical elision.

// All of these are ok, because we can derive exactly one bound:
a: Box<IsStatic>,
b: Box<Is<'static>>,