Introduce HirId, a replacement for NodeId after lowering to HIR.
HirId has a more stable representation than NodeId, meaning that modifications to one item don't influence (part of) the IDs within other items. The other part is a DefIndex for which there already is a way of stable hashing and persistence. This commit introduces the HirId type and generates a HirId for every NodeId during HIR lowering, but the resulting values are not yet used anywhere, except in consistency checks.
This commit is contained in:
parent
559127b451
commit
bc259ee844
@ -43,12 +43,14 @@
|
||||
use hir;
|
||||
use hir::map::{Definitions, DefKey};
|
||||
use hir::map::definitions::DefPathData;
|
||||
use hir::def_id::{DefIndex, DefId};
|
||||
use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX};
|
||||
use hir::def::{Def, PathResolution};
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use session::Session;
|
||||
use util::nodemap::{DefIdMap, NodeMap};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Debug;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
|
||||
@ -63,6 +65,8 @@ use syntax::util::small_vector::SmallVector;
|
||||
use syntax::visit::{self, Visitor};
|
||||
use syntax_pos::Span;
|
||||
|
||||
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
|
||||
|
||||
pub struct LoweringContext<'a> {
|
||||
crate_root: Option<&'static str>,
|
||||
// Use to assign ids to hir nodes that do not directly correspond to an ast node
|
||||
@ -89,6 +93,10 @@ pub struct LoweringContext<'a> {
|
||||
is_in_loop_condition: bool,
|
||||
|
||||
type_def_lifetime_params: DefIdMap<usize>,
|
||||
|
||||
current_hir_id_owner: Vec<(DefIndex, u32)>,
|
||||
item_local_id_counters: NodeMap<u32>,
|
||||
node_id_to_hir_id: IndexVec<NodeId, hir::HirId>,
|
||||
}
|
||||
|
||||
pub trait Resolver {
|
||||
@ -128,6 +136,9 @@ pub fn lower_crate(sess: &Session,
|
||||
loop_scopes: Vec::new(),
|
||||
is_in_loop_condition: false,
|
||||
type_def_lifetime_params: DefIdMap(),
|
||||
current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)],
|
||||
item_local_id_counters: NodeMap(),
|
||||
node_id_to_hir_id: IndexVec::new(),
|
||||
}.lower_crate(krate)
|
||||
}
|
||||
|
||||
@ -152,6 +163,8 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
impl<'lcx, 'interner> Visitor<'lcx> for MiscCollector<'lcx, 'interner> {
|
||||
fn visit_item(&mut self, item: &'lcx Item) {
|
||||
self.lctx.allocate_hir_id_counter(item.id, item);
|
||||
|
||||
match item.node {
|
||||
ItemKind::Struct(_, ref generics) |
|
||||
ItemKind::Union(_, ref generics) |
|
||||
@ -166,6 +179,16 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
|
||||
self.lctx.allocate_hir_id_counter(item.id, item);
|
||||
visit::walk_trait_item(self, item);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, item: &'lcx ImplItem) {
|
||||
self.lctx.allocate_hir_id_counter(item.id, item);
|
||||
visit::walk_impl_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
struct ItemLowerer<'lcx, 'interner: 'lcx> {
|
||||
@ -174,27 +197,43 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> {
|
||||
fn visit_item(&mut self, item: &'lcx Item) {
|
||||
if let Some(hir_item) = self.lctx.lower_item(item) {
|
||||
self.lctx.items.insert(item.id, hir_item);
|
||||
let mut item_lowered = true;
|
||||
self.lctx.with_hir_id_owner(item.id, |lctx| {
|
||||
if let Some(hir_item) = lctx.lower_item(item) {
|
||||
lctx.items.insert(item.id, hir_item);
|
||||
} else {
|
||||
item_lowered = false;
|
||||
}
|
||||
});
|
||||
|
||||
if item_lowered {
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
|
||||
self.lctx.with_hir_id_owner(item.id, |lctx| {
|
||||
let id = hir::TraitItemId { node_id: item.id };
|
||||
let hir_item = self.lctx.lower_trait_item(item);
|
||||
self.lctx.trait_items.insert(id, hir_item);
|
||||
let hir_item = lctx.lower_trait_item(item);
|
||||
lctx.trait_items.insert(id, hir_item);
|
||||
});
|
||||
|
||||
visit::walk_trait_item(self, item);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, item: &'lcx ImplItem) {
|
||||
self.lctx.with_hir_id_owner(item.id, |lctx| {
|
||||
let id = hir::ImplItemId { node_id: item.id };
|
||||
let hir_item = self.lctx.lower_impl_item(item);
|
||||
self.lctx.impl_items.insert(id, hir_item);
|
||||
let hir_item = lctx.lower_impl_item(item);
|
||||
lctx.impl_items.insert(id, hir_item);
|
||||
});
|
||||
visit::walk_impl_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
self.lower_node_id(CRATE_NODE_ID);
|
||||
debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == hir::CRATE_HIR_ID);
|
||||
|
||||
visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
|
||||
visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c);
|
||||
|
||||
@ -202,6 +241,10 @@ impl<'a> LoweringContext<'a> {
|
||||
let attrs = self.lower_attrs(&c.attrs);
|
||||
let body_ids = body_ids(&self.bodies);
|
||||
|
||||
self.resolver
|
||||
.definitions()
|
||||
.init_node_id_to_hir_id_mapping(self.node_id_to_hir_id);
|
||||
|
||||
hir::Crate {
|
||||
module: module,
|
||||
attrs: attrs,
|
||||
@ -217,6 +260,103 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn allocate_hir_id_counter<T: Debug>(&mut self,
|
||||
owner: NodeId,
|
||||
debug: &T) {
|
||||
if self.item_local_id_counters.insert(owner, 0).is_some() {
|
||||
bug!("Tried to allocate item_local_id_counter for {:?} twice", debug);
|
||||
}
|
||||
// Always allocate the first HirId for the owner itself
|
||||
self.lower_node_id_with_owner(owner, owner);
|
||||
}
|
||||
|
||||
fn lower_node_id_generic<F>(&mut self,
|
||||
ast_node_id: NodeId,
|
||||
alloc_hir_id: F)
|
||||
-> NodeId
|
||||
where F: FnOnce(&mut Self) -> hir::HirId
|
||||
{
|
||||
if ast_node_id == DUMMY_NODE_ID {
|
||||
return ast_node_id;
|
||||
}
|
||||
|
||||
let min_size = ast_node_id.as_usize() + 1;
|
||||
|
||||
if min_size > self.node_id_to_hir_id.len() {
|
||||
self.node_id_to_hir_id.resize(min_size, hir::DUMMY_HIR_ID);
|
||||
}
|
||||
|
||||
if self.node_id_to_hir_id[ast_node_id] == hir::DUMMY_HIR_ID {
|
||||
// Generate a new HirId
|
||||
self.node_id_to_hir_id[ast_node_id] = alloc_hir_id(self);
|
||||
}
|
||||
|
||||
ast_node_id
|
||||
}
|
||||
|
||||
fn with_hir_id_owner<F>(&mut self, owner: NodeId, f: F)
|
||||
where F: FnOnce(&mut Self)
|
||||
{
|
||||
let counter = self.item_local_id_counters
|
||||
.insert(owner, HIR_ID_COUNTER_LOCKED)
|
||||
.unwrap();
|
||||
let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
|
||||
self.current_hir_id_owner.push((def_index, counter));
|
||||
f(self);
|
||||
let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap();
|
||||
|
||||
debug_assert!(def_index == new_def_index);
|
||||
debug_assert!(new_counter >= counter);
|
||||
|
||||
let prev = self.item_local_id_counters.insert(owner, new_counter).unwrap();
|
||||
debug_assert!(prev == HIR_ID_COUNTER_LOCKED);
|
||||
}
|
||||
|
||||
/// This method allocates a new HirId for the given NodeId and stores it in
|
||||
/// the LoweringContext's NodeId => HirId map.
|
||||
/// Take care not to call this method if the resulting HirId is then not
|
||||
/// actually used in the HIR, as that would trigger an assertion in the
|
||||
/// HirIdValidator later on, which makes sure that all NodeIds got mapped
|
||||
/// properly. Calling the method twice with the same NodeId is fine though.
|
||||
fn lower_node_id(&mut self, ast_node_id: NodeId) -> NodeId {
|
||||
self.lower_node_id_generic(ast_node_id, |this| {
|
||||
let &mut (def_index, ref mut local_id_counter) = this.current_hir_id_owner
|
||||
.last_mut()
|
||||
.unwrap();
|
||||
let local_id = *local_id_counter;
|
||||
*local_id_counter += 1;
|
||||
hir::HirId {
|
||||
owner: def_index,
|
||||
local_id: hir::ItemLocalId(local_id),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_node_id_with_owner(&mut self,
|
||||
ast_node_id: NodeId,
|
||||
owner: NodeId)
|
||||
-> NodeId {
|
||||
self.lower_node_id_generic(ast_node_id, |this| {
|
||||
let local_id_counter = this.item_local_id_counters
|
||||
.get_mut(&owner)
|
||||
.unwrap();
|
||||
let local_id = *local_id_counter;
|
||||
|
||||
// We want to be sure not to modify the counter in the map while it
|
||||
// is also on the stack. Otherwise we'll get lost updates when writing
|
||||
// back from the stack to the map.
|
||||
debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
|
||||
|
||||
*local_id_counter += 1;
|
||||
let def_index = this.resolver.definitions().opt_def_index(owner).unwrap();
|
||||
|
||||
hir::HirId {
|
||||
owner: def_index,
|
||||
local_id: hir::ItemLocalId(local_id),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>)
|
||||
-> hir::BodyId {
|
||||
let body = hir::Body {
|
||||
@ -230,8 +370,8 @@ impl<'a> LoweringContext<'a> {
|
||||
id
|
||||
}
|
||||
|
||||
fn next_id(&self) -> NodeId {
|
||||
self.sess.next_node_id()
|
||||
fn next_id(&mut self) -> NodeId {
|
||||
self.lower_node_id(self.sess.next_node_id())
|
||||
}
|
||||
|
||||
fn expect_full_def(&mut self, id: NodeId) -> Def {
|
||||
@ -362,7 +502,7 @@ impl<'a> LoweringContext<'a> {
|
||||
match destination {
|
||||
Some((id, label_ident)) => {
|
||||
let target = if let Def::Label(loop_id) = self.expect_full_def(id) {
|
||||
hir::LoopIdResult::Ok(loop_id)
|
||||
hir::LoopIdResult::Ok(self.lower_node_id(loop_id))
|
||||
} else {
|
||||
hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
|
||||
};
|
||||
@ -371,11 +511,18 @@ impl<'a> LoweringContext<'a> {
|
||||
target_id: hir::ScopeTarget::Loop(target),
|
||||
}
|
||||
},
|
||||
None => hir::Destination {
|
||||
None => {
|
||||
let loop_id = self.loop_scopes
|
||||
.last()
|
||||
.map(|innermost_loop_id| *innermost_loop_id);
|
||||
|
||||
hir::Destination {
|
||||
ident: None,
|
||||
target_id: hir::ScopeTarget::Loop(
|
||||
self.loop_scopes.last().map(|innermost_loop_id| Ok(*innermost_loop_id))
|
||||
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)).into())
|
||||
loop_id.map(|id| Ok(self.lower_node_id(id)))
|
||||
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
|
||||
.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -395,7 +542,7 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
fn lower_ty_binding(&mut self, b: &TypeBinding) -> hir::TypeBinding {
|
||||
hir::TypeBinding {
|
||||
id: b.id,
|
||||
id: self.lower_node_id(b.id),
|
||||
name: b.ident.name,
|
||||
ty: self.lower_ty(&b.ty),
|
||||
span: b.span,
|
||||
@ -403,9 +550,7 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
|
||||
fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
|
||||
P(hir::Ty {
|
||||
id: t.id,
|
||||
node: match t.node {
|
||||
let kind = match t.node {
|
||||
TyKind::Infer => hir::TyInfer,
|
||||
TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
|
||||
TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
|
||||
@ -433,8 +578,9 @@ impl<'a> LoweringContext<'a> {
|
||||
return self.lower_ty(ty);
|
||||
}
|
||||
TyKind::Path(ref qself, ref path) => {
|
||||
let id = self.lower_node_id(t.id);
|
||||
let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit);
|
||||
return self.ty_path(t.id, t.span, qpath);
|
||||
return self.ty_path(id, t.span, qpath);
|
||||
}
|
||||
TyKind::ImplicitSelf => {
|
||||
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
|
||||
@ -464,7 +610,9 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
|
||||
RegionTyParamBound(ref lifetime) => {
|
||||
if lifetime_bound.is_none() {
|
||||
lifetime_bound = Some(self.lower_lifetime(lifetime));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -478,7 +626,11 @@ impl<'a> LoweringContext<'a> {
|
||||
hir::TyImplTrait(self.lower_bounds(bounds))
|
||||
}
|
||||
TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
|
||||
},
|
||||
};
|
||||
|
||||
P(hir::Ty {
|
||||
id: self.lower_node_id(t.id),
|
||||
node: kind,
|
||||
span: t.span,
|
||||
})
|
||||
}
|
||||
@ -712,7 +864,7 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
fn lower_local(&mut self, l: &Local) -> P<hir::Local> {
|
||||
P(hir::Local {
|
||||
id: l.id,
|
||||
id: self.lower_node_id(l.id),
|
||||
ty: l.ty.as_ref().map(|t| self.lower_ty(t)),
|
||||
pat: self.lower_pat(&l.pat),
|
||||
init: l.init.as_ref().map(|e| P(self.lower_expr(e))),
|
||||
@ -730,7 +882,7 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
fn lower_arg(&mut self, arg: &Arg) -> hir::Arg {
|
||||
hir::Arg {
|
||||
id: arg.id,
|
||||
id: self.lower_node_id(arg.id),
|
||||
pat: self.lower_pat(&arg.pat),
|
||||
}
|
||||
}
|
||||
@ -786,7 +938,7 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
|
||||
hir::TyParam {
|
||||
id: tp.id,
|
||||
id: self.lower_node_id(tp.id),
|
||||
name: name,
|
||||
bounds: bounds,
|
||||
default: tp.default.as_ref().map(|x| self.lower_ty(x)),
|
||||
@ -804,7 +956,7 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
|
||||
hir::Lifetime {
|
||||
id: l.id,
|
||||
id: self.lower_node_id(l.id),
|
||||
name: l.name,
|
||||
span: l.span,
|
||||
}
|
||||
@ -876,7 +1028,7 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause {
|
||||
hir::WhereClause {
|
||||
id: wc.id,
|
||||
id: self.lower_node_id(wc.id),
|
||||
predicates: wc.predicates
|
||||
.iter()
|
||||
.map(|predicate| self.lower_where_predicate(predicate))
|
||||
@ -915,7 +1067,7 @@ impl<'a> LoweringContext<'a> {
|
||||
ref rhs_ty,
|
||||
span}) => {
|
||||
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
||||
id: id,
|
||||
id: self.lower_node_id(id),
|
||||
lhs_ty: self.lower_ty(lhs_ty),
|
||||
rhs_ty: self.lower_ty(rhs_ty),
|
||||
span: span,
|
||||
@ -931,16 +1083,16 @@ impl<'a> LoweringContext<'a> {
|
||||
.enumerate()
|
||||
.map(|f| self.lower_struct_field(f))
|
||||
.collect(),
|
||||
id)
|
||||
self.lower_node_id(id))
|
||||
}
|
||||
VariantData::Tuple(ref fields, id) => {
|
||||
hir::VariantData::Tuple(fields.iter()
|
||||
.enumerate()
|
||||
.map(|f| self.lower_struct_field(f))
|
||||
.collect(),
|
||||
id)
|
||||
self.lower_node_id(id))
|
||||
}
|
||||
VariantData::Unit(id) => hir::VariantData::Unit(id),
|
||||
VariantData::Unit(id) => hir::VariantData::Unit(self.lower_node_id(id)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -951,7 +1103,7 @@ impl<'a> LoweringContext<'a> {
|
||||
};
|
||||
hir::TraitRef {
|
||||
path: path,
|
||||
ref_id: p.ref_id,
|
||||
ref_id: self.lower_node_id(p.ref_id),
|
||||
}
|
||||
}
|
||||
|
||||
@ -966,9 +1118,9 @@ impl<'a> LoweringContext<'a> {
|
||||
fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField {
|
||||
hir::StructField {
|
||||
span: f.span,
|
||||
id: f.id,
|
||||
id: self.lower_node_id(f.id),
|
||||
name: f.ident.map(|ident| ident.name).unwrap_or(Symbol::intern(&index.to_string())),
|
||||
vis: self.lower_visibility(&f.vis),
|
||||
vis: self.lower_visibility(&f.vis, None),
|
||||
ty: self.lower_ty(&f.ty),
|
||||
attrs: self.lower_attrs(&f.attrs),
|
||||
}
|
||||
@ -997,17 +1149,22 @@ impl<'a> LoweringContext<'a> {
|
||||
fn lower_block(&mut self, b: &Block, break_to: Option<NodeId>) -> P<hir::Block> {
|
||||
let mut expr = None;
|
||||
|
||||
let mut stmts = b.stmts.iter().flat_map(|s| self.lower_stmt(s)).collect::<Vec<_>>();
|
||||
if let Some(last) = stmts.pop() {
|
||||
if let hir::StmtExpr(e, _) = last.node {
|
||||
expr = Some(e);
|
||||
let mut stmts = vec![];
|
||||
|
||||
for (index, stmt) in b.stmts.iter().enumerate() {
|
||||
if index == b.stmts.len() - 1 {
|
||||
if let StmtKind::Expr(ref e) = stmt.node {
|
||||
expr = Some(P(self.lower_expr(e)));
|
||||
} else {
|
||||
stmts.push(last);
|
||||
stmts.extend(self.lower_stmt(stmt));
|
||||
}
|
||||
} else {
|
||||
stmts.extend(self.lower_stmt(stmt));
|
||||
}
|
||||
}
|
||||
|
||||
P(hir::Block {
|
||||
id: b.id,
|
||||
id: self.lower_node_id(b.id),
|
||||
stmts: stmts.into(),
|
||||
expr: expr,
|
||||
rules: self.lower_block_check_mode(&b.rules),
|
||||
@ -1046,14 +1203,31 @@ impl<'a> LoweringContext<'a> {
|
||||
let mut path = self.lower_path_extra(import.id, path, suffix,
|
||||
ParamMode::Explicit, true);
|
||||
path.span = span;
|
||||
self.items.insert(import.id, hir::Item {
|
||||
|
||||
self.allocate_hir_id_counter(import.id, import);
|
||||
self.with_hir_id_owner(import.id, |this| {
|
||||
let vis = match *vis {
|
||||
hir::Visibility::Public => hir::Visibility::Public,
|
||||
hir::Visibility::Crate => hir::Visibility::Crate,
|
||||
hir::Visibility::Inherited => hir::Visibility::Inherited,
|
||||
hir::Visibility::Restricted { ref path, id: _ } => {
|
||||
hir::Visibility::Restricted {
|
||||
path: path.clone(),
|
||||
// We are allocating a new NodeId here
|
||||
id: this.next_id(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.items.insert(import.id, hir::Item {
|
||||
id: import.id,
|
||||
name: import.rename.unwrap_or(ident).name,
|
||||
attrs: attrs.clone(),
|
||||
node: hir::ItemUse(P(path), hir::UseKind::Single),
|
||||
vis: vis.clone(),
|
||||
vis: vis,
|
||||
span: span,
|
||||
});
|
||||
});
|
||||
}
|
||||
path
|
||||
}
|
||||
@ -1167,7 +1341,7 @@ impl<'a> LoweringContext<'a> {
|
||||
fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
|
||||
self.with_parent_def(i.id, |this| {
|
||||
hir::TraitItem {
|
||||
id: i.id,
|
||||
id: this.lower_node_id(i.id),
|
||||
name: i.ident.name,
|
||||
attrs: this.lower_attrs(&i.attrs),
|
||||
node: match i.node {
|
||||
@ -1228,10 +1402,10 @@ impl<'a> LoweringContext<'a> {
|
||||
fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
|
||||
self.with_parent_def(i.id, |this| {
|
||||
hir::ImplItem {
|
||||
id: i.id,
|
||||
id: this.lower_node_id(i.id),
|
||||
name: i.ident.name,
|
||||
attrs: this.lower_attrs(&i.attrs),
|
||||
vis: this.lower_visibility(&i.vis),
|
||||
vis: this.lower_visibility(&i.vis, None),
|
||||
defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
|
||||
node: match i.node {
|
||||
ImplItemKind::Const(ref ty, ref expr) => {
|
||||
@ -1260,7 +1434,7 @@ impl<'a> LoweringContext<'a> {
|
||||
id: hir::ImplItemId { node_id: i.id },
|
||||
name: i.ident.name,
|
||||
span: i.span,
|
||||
vis: self.lower_visibility(&i.vis),
|
||||
vis: self.lower_visibility(&i.vis, Some(i.id)),
|
||||
defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
|
||||
kind: match i.node {
|
||||
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
|
||||
@ -1299,7 +1473,6 @@ impl<'a> LoweringContext<'a> {
|
||||
pub fn lower_item(&mut self, i: &Item) -> Option<hir::Item> {
|
||||
let mut name = i.ident.name;
|
||||
let attrs = self.lower_attrs(&i.attrs);
|
||||
let mut vis = self.lower_visibility(&i.vis);
|
||||
if let ItemKind::MacroDef(ref tts) = i.node {
|
||||
if i.attrs.iter().any(|attr| attr.path == "macro_export") {
|
||||
self.exported_macros.push(hir::MacroDef {
|
||||
@ -1309,12 +1482,13 @@ impl<'a> LoweringContext<'a> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut vis = self.lower_visibility(&i.vis, None);
|
||||
let node = self.with_parent_def(i.id, |this| {
|
||||
this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node)
|
||||
});
|
||||
|
||||
Some(hir::Item {
|
||||
id: i.id,
|
||||
id: self.lower_node_id(i.id),
|
||||
name: name,
|
||||
attrs: attrs,
|
||||
node: node,
|
||||
@ -1326,7 +1500,7 @@ impl<'a> LoweringContext<'a> {
|
||||
fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem {
|
||||
self.with_parent_def(i.id, |this| {
|
||||
hir::ForeignItem {
|
||||
id: i.id,
|
||||
id: this.lower_node_id(i.id),
|
||||
name: i.ident.name,
|
||||
attrs: this.lower_attrs(&i.attrs),
|
||||
node: match i.node {
|
||||
@ -1339,7 +1513,7 @@ impl<'a> LoweringContext<'a> {
|
||||
hir::ForeignItemStatic(this.lower_ty(t), m)
|
||||
}
|
||||
},
|
||||
vis: this.lower_visibility(&i.vis),
|
||||
vis: this.lower_visibility(&i.vis, None),
|
||||
span: i.span,
|
||||
}
|
||||
})
|
||||
@ -1405,7 +1579,7 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
|
||||
P(hir::Pat {
|
||||
id: p.id,
|
||||
id: self.lower_node_id(p.id),
|
||||
node: match p.node {
|
||||
PatKind::Wild => hir::PatKind::Wild,
|
||||
PatKind::Ident(ref binding_mode, pth1, ref sub) => {
|
||||
@ -1491,9 +1665,7 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
|
||||
fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
|
||||
hir::Expr {
|
||||
id: e.id,
|
||||
node: match e.node {
|
||||
let kind = match e.node {
|
||||
// Issue #22181:
|
||||
// Eventually a desugaring for `box EXPR`
|
||||
// (similar to the desugaring above for `in PLACE BLOCK`)
|
||||
@ -1510,8 +1682,8 @@ impl<'a> LoweringContext<'a> {
|
||||
// }
|
||||
//
|
||||
// But for now there are type-inference issues doing that.
|
||||
ExprKind::Box(ref e) => {
|
||||
hir::ExprBox(P(self.lower_expr(e)))
|
||||
ExprKind::Box(ref inner) => {
|
||||
hir::ExprBox(P(self.lower_expr(inner)))
|
||||
}
|
||||
|
||||
// Desugar ExprBox: `in (PLACE) EXPR`
|
||||
@ -1602,8 +1774,7 @@ impl<'a> LoweringContext<'a> {
|
||||
};
|
||||
|
||||
let block = self.block_all(e.span, hir_vec![s1, s2, s3], Some(expr));
|
||||
// add the attributes to the outer returned expr node
|
||||
return self.expr_block(P(block), e.attrs.clone());
|
||||
hir::ExprBlock(P(block))
|
||||
}
|
||||
|
||||
ExprKind::Array(ref exprs) => {
|
||||
@ -1864,78 +2035,115 @@ impl<'a> LoweringContext<'a> {
|
||||
// _ => [<else_opt> | ()]
|
||||
// }
|
||||
|
||||
let mut arms = vec![];
|
||||
|
||||
// `<pat> => <body>`
|
||||
let pat_arm = {
|
||||
{
|
||||
let body = self.lower_block(body, None);
|
||||
let body_expr = P(self.expr_block(body, ThinVec::new()));
|
||||
let pat = self.lower_pat(pat);
|
||||
self.arm(hir_vec![pat], body_expr)
|
||||
};
|
||||
arms.push(self.arm(hir_vec![pat], body_expr));
|
||||
}
|
||||
|
||||
// `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
|
||||
let mut else_opt = else_opt.as_ref().map(|e| P(self.lower_expr(e)));
|
||||
let else_if_arms = {
|
||||
let mut arms = vec![];
|
||||
// `_ => [<else_opt> | ()]`
|
||||
{
|
||||
let mut current: Option<&Expr> = else_opt.as_ref().map(|p| &**p);
|
||||
let mut else_exprs: Vec<Option<&Expr>> = vec![current];
|
||||
|
||||
// First, we traverse the AST and recursively collect all
|
||||
// `else` branches into else_exprs, e.g.:
|
||||
//
|
||||
// if let Some(_) = x {
|
||||
// ...
|
||||
// } else if ... { // Expr1
|
||||
// ...
|
||||
// } else if ... { // Expr2
|
||||
// ...
|
||||
// } else { // Expr3
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// ... results in else_exprs = [Some(&Expr1),
|
||||
// Some(&Expr2),
|
||||
// Some(&Expr3)]
|
||||
//
|
||||
// Because there also the case there is no `else`, these
|
||||
// entries can also be `None`, as in:
|
||||
//
|
||||
// if let Some(_) = x {
|
||||
// ...
|
||||
// } else if ... { // Expr1
|
||||
// ...
|
||||
// } else if ... { // Expr2
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// ... results in else_exprs = [Some(&Expr1),
|
||||
// Some(&Expr2),
|
||||
// None]
|
||||
//
|
||||
// The last entry in this list is always translated into
|
||||
// the final "unguard" wildcard arm of the `match`. In the
|
||||
// case of a `None`, it becomes `_ => ()`.
|
||||
loop {
|
||||
let else_opt_continue = else_opt.and_then(|els| {
|
||||
els.and_then(|els| {
|
||||
match els.node {
|
||||
// else if
|
||||
hir::ExprIf(cond, then, else_opt) => {
|
||||
let pat_under = self.pat_wild(e.span);
|
||||
if let Some(e) = current {
|
||||
// There is an else branch at this level
|
||||
if let ExprKind::If(_, _, ref else_opt) = e.node {
|
||||
// The else branch is again an if-expr
|
||||
current = else_opt.as_ref().map(|p| &**p);
|
||||
else_exprs.push(current);
|
||||
} else {
|
||||
// The last item in the list is not an if-expr,
|
||||
// stop here
|
||||
break
|
||||
}
|
||||
} else {
|
||||
// We have no more else branch
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Now translate the list of nested else-branches into the
|
||||
// arms of the match statement.
|
||||
for else_expr in else_exprs {
|
||||
if let Some(else_expr) = else_expr {
|
||||
let (guard, body) = if let ExprKind::If(ref cond,
|
||||
ref then,
|
||||
_) = else_expr.node {
|
||||
let then = self.lower_block(then, None);
|
||||
(Some(cond),
|
||||
self.expr_block(then, ThinVec::new()))
|
||||
} else {
|
||||
(None,
|
||||
self.lower_expr(else_expr))
|
||||
};
|
||||
|
||||
arms.push(hir::Arm {
|
||||
attrs: hir_vec![],
|
||||
pats: hir_vec![pat_under],
|
||||
guard: Some(cond),
|
||||
body: P(self.expr_block(then, ThinVec::new())),
|
||||
pats: hir_vec![self.pat_wild(e.span)],
|
||||
guard: guard.map(|e| P(self.lower_expr(e))),
|
||||
body: P(body),
|
||||
});
|
||||
else_opt.map(|else_opt| (else_opt, true))
|
||||
}
|
||||
_ => Some((P(els), false)),
|
||||
}
|
||||
})
|
||||
});
|
||||
match else_opt_continue {
|
||||
Some((e, true)) => {
|
||||
else_opt = Some(e);
|
||||
}
|
||||
Some((e, false)) => {
|
||||
else_opt = Some(e);
|
||||
break;
|
||||
}
|
||||
None => {
|
||||
else_opt = None;
|
||||
break;
|
||||
} else {
|
||||
// There was no else-branch, push a noop
|
||||
let pat_under = self.pat_wild(e.span);
|
||||
let unit = self.expr_tuple(e.span, hir_vec![]);
|
||||
arms.push(self.arm(hir_vec![pat_under], unit));
|
||||
}
|
||||
}
|
||||
}
|
||||
arms
|
||||
};
|
||||
|
||||
let contains_else_clause = else_opt.is_some();
|
||||
|
||||
// `_ => [<else_opt> | ()]`
|
||||
let else_arm = {
|
||||
let pat_under = self.pat_wild(e.span);
|
||||
let else_expr =
|
||||
else_opt.unwrap_or_else(|| self.expr_tuple(e.span, hir_vec![]));
|
||||
self.arm(hir_vec![pat_under], else_expr)
|
||||
};
|
||||
|
||||
let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
|
||||
arms.push(pat_arm);
|
||||
arms.extend(else_if_arms);
|
||||
arms.push(else_arm);
|
||||
|
||||
let sub_expr = P(self.lower_expr(sub_expr));
|
||||
// add attributes to the outer returned expr node
|
||||
return self.expr(e.span,
|
||||
hir::ExprMatch(sub_expr,
|
||||
|
||||
hir::ExprMatch(
|
||||
sub_expr,
|
||||
arms.into(),
|
||||
hir::MatchSource::IfLetDesugar {
|
||||
contains_else_clause: contains_else_clause,
|
||||
}),
|
||||
e.attrs.clone());
|
||||
})
|
||||
}
|
||||
|
||||
// Desugar ExprWhileLet
|
||||
@ -1984,8 +2192,7 @@ impl<'a> LoweringContext<'a> {
|
||||
let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
|
||||
hir::LoopSource::WhileLet);
|
||||
// add attributes to the outer returned expr node
|
||||
let attrs = e.attrs.clone();
|
||||
return hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs };
|
||||
loop_expr
|
||||
}
|
||||
|
||||
// Desugar ExprForLoop
|
||||
@ -2056,7 +2263,7 @@ impl<'a> LoweringContext<'a> {
|
||||
let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
|
||||
hir::LoopSource::ForLoop);
|
||||
let loop_expr = P(hir::Expr {
|
||||
id: e.id,
|
||||
id: self.lower_node_id(e.id),
|
||||
node: loop_expr,
|
||||
span: e.span,
|
||||
attrs: ThinVec::new(),
|
||||
@ -2182,16 +2389,22 @@ impl<'a> LoweringContext<'a> {
|
||||
thin_attrs))
|
||||
};
|
||||
|
||||
|
||||
let err_pat = self.pat_err(e.span, err_local);
|
||||
self.arm(hir_vec![err_pat], ret_expr)
|
||||
};
|
||||
|
||||
return self.expr_match(e.span, discr, hir_vec![err_arm, ok_arm],
|
||||
hir::MatchSource::TryDesugar);
|
||||
hir::ExprMatch(discr,
|
||||
hir_vec![err_arm, ok_arm],
|
||||
hir::MatchSource::TryDesugar)
|
||||
}
|
||||
|
||||
ExprKind::Mac(_) => panic!("Shouldn't exist here"),
|
||||
},
|
||||
};
|
||||
|
||||
hir::Expr {
|
||||
id: self.lower_node_id(e.id),
|
||||
node: kind,
|
||||
span: e.span,
|
||||
attrs: e.attrs.clone(),
|
||||
}
|
||||
@ -2203,7 +2416,7 @@ impl<'a> LoweringContext<'a> {
|
||||
node: hir::StmtDecl(P(Spanned {
|
||||
node: hir::DeclLocal(self.lower_local(l)),
|
||||
span: s.span,
|
||||
}), s.id),
|
||||
}), self.lower_node_id(s.id)),
|
||||
span: s.span,
|
||||
},
|
||||
StmtKind::Item(ref it) => {
|
||||
@ -2213,19 +2426,23 @@ impl<'a> LoweringContext<'a> {
|
||||
node: hir::StmtDecl(P(Spanned {
|
||||
node: hir::DeclItem(item_id),
|
||||
span: s.span,
|
||||
}), id.take().unwrap_or_else(|| self.next_id())),
|
||||
}), id.take()
|
||||
.map(|id| self.lower_node_id(id))
|
||||
.unwrap_or_else(|| self.next_id())),
|
||||
span: s.span,
|
||||
}).collect();
|
||||
}
|
||||
StmtKind::Expr(ref e) => {
|
||||
Spanned {
|
||||
node: hir::StmtExpr(P(self.lower_expr(e)), s.id),
|
||||
node: hir::StmtExpr(P(self.lower_expr(e)),
|
||||
self.lower_node_id(s.id)),
|
||||
span: s.span,
|
||||
}
|
||||
}
|
||||
StmtKind::Semi(ref e) => {
|
||||
Spanned {
|
||||
node: hir::StmtSemi(P(self.lower_expr(e)), s.id),
|
||||
node: hir::StmtSemi(P(self.lower_expr(e)),
|
||||
self.lower_node_id(s.id)),
|
||||
span: s.span,
|
||||
}
|
||||
}
|
||||
@ -2240,14 +2457,26 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_visibility(&mut self, v: &Visibility) -> hir::Visibility {
|
||||
/// If an `explicit_owner` is given, this method allocates the `HirId` in
|
||||
/// the address space of that item instead of the item currently being
|
||||
/// lowered. This can happen during `lower_impl_item_ref()` where we need to
|
||||
/// lower a `Visibility` value although we haven't lowered the owning
|
||||
/// `ImplItem` in question yet.
|
||||
fn lower_visibility(&mut self,
|
||||
v: &Visibility,
|
||||
explicit_owner: Option<NodeId>)
|
||||
-> hir::Visibility {
|
||||
match *v {
|
||||
Visibility::Public => hir::Public,
|
||||
Visibility::Crate(_) => hir::Visibility::Crate,
|
||||
Visibility::Restricted { ref path, id } => {
|
||||
hir::Visibility::Restricted {
|
||||
path: P(self.lower_path(id, path, ParamMode::Explicit, true)),
|
||||
id: id
|
||||
id: if let Some(owner) = explicit_owner {
|
||||
self.lower_node_id_with_owner(id, owner)
|
||||
} else {
|
||||
self.lower_node_id(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
Visibility::Inherited => hir::Inherited,
|
||||
|
@ -14,8 +14,10 @@
|
||||
//! There are also some rather random cases (like const initializer
|
||||
//! expressions) that are mostly just leftovers.
|
||||
|
||||
use hir;
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
|
||||
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;
|
||||
@ -121,6 +123,7 @@ pub struct Definitions {
|
||||
table: DefPathTable,
|
||||
node_to_def_index: NodeMap<DefIndex>,
|
||||
def_index_to_node: Vec<ast::NodeId>,
|
||||
pub(super) node_to_hir_id: IndexVec<ast::NodeId, hir::HirId>,
|
||||
}
|
||||
|
||||
/// A unique identifier that we can use to lookup a definition
|
||||
@ -206,6 +209,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();
|
||||
@ -275,6 +295,7 @@ impl Definitions {
|
||||
},
|
||||
node_to_def_index: NodeMap(),
|
||||
def_index_to_node: vec![],
|
||||
node_to_hir_id: IndexVec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,6 +388,15 @@ impl Definitions {
|
||||
|
||||
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
src/librustc/hir/map/hir_id_validator.rs
Normal file
184
src/librustc/hir/map/hir_id_validator.rs
Normal file
@ -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.
|
||||
}
|
||||
}
|
@ -36,6 +36,7 @@ pub mod blocks;
|
||||
mod collector;
|
||||
mod def_collector;
|
||||
pub mod definitions;
|
||||
mod hir_id_validator;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Node<'hir> {
|
||||
@ -964,13 +965,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`,
|
||||
|
@ -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,
|
||||
|
@ -178,19 +178,11 @@ 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 => {
|
||||
if self.monotonic {
|
||||
assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
|
||||
stmt.id = self.cx.resolver.next_node_id();
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Some(stmt)
|
||||
});
|
||||
|
||||
|
@ -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
|
||||
// All of these are ok, because we can derive exactly one bound:
|
||||
a: Box<IsStatic>,
|
||||
b: Box<Is<'static>>,
|
||||
|
Loading…
x
Reference in New Issue
Block a user