Auto merge of #37660 - nikomatsakis:incremental-36349, r=eddyb

Separate impl items from the parent impl

This change separates impl item bodies out of the impl itself. This gives incremental more resolution. In so doing, it refactors how the visitors work, and cleans up a bit of the collect/check logic (mostly by moving things out of collect that didn't really belong there, because they were just checking conditions).

However, this is not as effective as I expected, for a kind of frustrating reason. In particular, when invoking `foo.bar()` you still wind up with dependencies on private items. The problem is that the method resolution code scans that list for methods with the name `bar` -- and this winds up touching *all* the methods, even private ones.

I can imagine two obvious ways to fix this:

- separating fn bodies from fn sigs (#35078, currently being pursued by @flodiebold)
- a more aggressive model of incremental that @michaelwoerister has been advocating, in which we hash the intermediate results (e.g., the outputs of collect) so that we can see that the intermediate result hasn't changed, even if a particular impl item has changed.

So all in all I'm not quite sure whether to land this or not. =) It still seems like it has to be a win in some cases, but not with the test cases we have just now. I can try to gin up some test cases, but I'm not sure if they will be totally realistic. On the other hand, some of the early refactorings to the visitor trait seem worthwhile to me regardless.

cc #36349 -- well, this is basically a fix for that issue, I guess

r? @michaelwoerister

NB: Based atop of @eddyb's PR https://github.com/rust-lang/rust/pull/37402; don't land until that lands.
This commit is contained in:
bors 2016-11-17 17:31:01 -08:00 committed by GitHub
commit 35e8924dc5
73 changed files with 1766 additions and 631 deletions

View file

@ -25,5 +25,5 @@ pub use self::dep_node::WorkProductId;
pub use self::graph::DepGraph;
pub use self::graph::WorkProduct;
pub use self::query::DepGraphQuery;
pub use self::visit::visit_all_items_in_krate;
pub use self::visit::visit_all_item_likes_in_krate;
pub use self::raii::DepTask;

View file

@ -10,22 +10,21 @@
use hir;
use hir::def_id::DefId;
use hir::intravisit::Visitor;
use hir::itemlikevisit::ItemLikeVisitor;
use ty::TyCtxt;
use super::dep_node::DepNode;
/// Visit all the items in the krate in some order. When visiting a
/// particular item, first create a dep-node by calling `dep_node_fn`
/// and push that onto the dep-graph stack of tasks, and also create a
/// read edge from the corresponding AST node. This is used in
/// compiler passes to automatically record the item that they are
/// working on.
pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mut dep_node_fn: F,
visitor: &mut V)
where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mut dep_node_fn: F,
visitor: &mut V)
where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'tcx>
{
struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> {
tcx: TyCtxt<'visit, 'tcx, 'tcx>,
@ -33,8 +32,8 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
visitor: &'visit mut V
}
impl<'visit, 'tcx, F, V> Visitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
impl<'visit, 'tcx, F, V> ItemLikeVisitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'tcx>
{
fn visit_item(&mut self, i: &'tcx hir::Item) {
let item_def_id = self.tcx.map.local_def_id(i.id);
@ -46,6 +45,17 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
self.visitor.visit_item(i);
debug!("Ended task {:?}", task_id);
}
fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
let impl_item_def_id = self.tcx.map.local_def_id(i.id);
let task_id = (self.dep_node_fn)(impl_item_def_id);
let _task = self.tcx.dep_graph.in_task(task_id.clone());
debug!("Started task {:?}", task_id);
assert!(!self.tcx.map.is_inlined_def_id(impl_item_def_id));
self.tcx.dep_graph.read(DepNode::Hir(impl_item_def_id));
self.visitor.visit_impl_item(i);
debug!("Ended task {:?}", task_id);
}
}
let krate = tcx.dep_graph.with_ignore(|| tcx.map.krate());
@ -54,5 +64,5 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
dep_node_fn: &mut dep_node_fn,
visitor: visitor
};
krate.visit_all_items(&mut tracking_visitor)
krate.visit_all_item_likes(&mut tracking_visitor)
}

View file

@ -106,7 +106,7 @@ pub type DefMap = NodeMap<PathResolution>;
// within.
pub type ExportMap = NodeMap<Vec<Export>>;
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Export {
pub name: ast::Name, // The name of the target.
pub def: Def, // The definition of the target.

View file

@ -8,7 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! HIR walker. Each overridden visit method has full control over what
//! HIR walker for walking the contents of nodes.
//!
//! **For an overview of the visitor strategy, see the docs on the
//! `super::itemlikevisit::ItemLikeVisitor` trait.**
//!
//! If you have decided to use this visitor, here are some general
//! notes on how to do it:
//!
//! Each overridden visit method has full control over what
//! happens with its node, it can do its own traversal of the node's children,
//! call `intravisit::walk_*` to apply the default traversal algorithm, or prevent
//! deeper traversal by doing nothing.
@ -30,6 +38,8 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
use syntax::codemap::Spanned;
use syntax_pos::Span;
use hir::*;
use hir::map::Map;
use super::itemlikevisit::DeepVisitor;
use std::cmp;
use std::u32;
@ -76,22 +86,70 @@ pub trait Visitor<'v> : Sized {
///////////////////////////////////////////////////////////////////////////
// Nested items.
/// Invoked when a nested item is encountered. By default, does
/// nothing. If you want a deep walk, you need to override to
/// fetch the item contents. But most of the time, it is easier
/// (and better) to invoke `Crate::visit_all_items`, which visits
/// all items in the crate in some order (but doesn't respect
/// nesting).
#[allow(unused_variables)]
fn visit_nested_item(&mut self, id: ItemId) {
/// The default versions of the `visit_nested_XXX` routines invoke
/// this method to get a map to use; if they get back `None`, they
/// just skip nested things. Otherwise, they will lookup the
/// nested item-like things in the map and visit it. So the best
/// way to implement a nested visitor is to override this method
/// to return a `Map`; one advantage of this is that if we add
/// more types of nested things in the future, they will
/// automatically work.
///
/// **If for some reason you want the nested behavior, but don't
/// have a `Map` are your disposal:** then you should override the
/// `visit_nested_XXX` methods, and override this method to
/// `panic!()`. This way, if a new `visit_nested_XXX` variant is
/// added in the future, we will see the panic in your code and
/// fix it appropriately.
fn nested_visit_map(&mut self) -> Option<&Map<'v>> {
None
}
/// Visit the top-level item and (optionally) nested items. See
/// Invoked when a nested item is encountered. By default does
/// nothing unless you override `nested_visit_map` to return
/// `Some(_)`, in which case it will walk the item. **You probably
/// don't want to override this method** -- instead, override
/// `nested_visit_map` or use the "shallow" or "deep" visit
/// patterns described on `itemlikevisit::ItemLikeVisitor`. The only
/// reason to override this method is if you want a nested pattern
/// but cannot supply a `Map`; see `nested_visit_map` for advice.
#[allow(unused_variables)]
fn visit_nested_item(&mut self, id: ItemId) {
let opt_item = self.nested_visit_map()
.map(|map| map.expect_item(id.id));
if let Some(item) = opt_item {
self.visit_item(item);
}
}
/// Like `visit_nested_item()`, but for impl items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
#[allow(unused_variables)]
fn visit_nested_impl_item(&mut self, id: ImplItemId) {
let opt_item = self.nested_visit_map()
.map(|map| map.impl_item(id));
if let Some(item) = opt_item {
self.visit_impl_item(item);
}
}
/// Visit the top-level item and (optionally) nested items / impl items. See
/// `visit_nested_item` for details.
fn visit_item(&mut self, i: &'v Item) {
walk_item(self, i)
}
/// When invoking `visit_all_item_likes()`, you need to supply an
/// item-like visitor. This method converts a "intra-visit"
/// visitor into an item-like visitor that walks the entire tree.
/// If you use this, you probably don't want to process the
/// contents of nested item-like things, since the outer loop will
/// visit them as well.
fn as_deep_visitor<'s>(&'s mut self) -> DeepVisitor<'s, Self> {
DeepVisitor::new(self)
}
///////////////////////////////////////////////////////////////////////////
fn visit_id(&mut self, _node_id: NodeId) {
@ -147,6 +205,9 @@ pub trait Visitor<'v> : Sized {
fn visit_impl_item(&mut self, ii: &'v ImplItem) {
walk_impl_item(self, ii)
}
fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef) {
walk_impl_item_ref(self, ii)
}
fn visit_trait_ref(&mut self, t: &'v TraitRef) {
walk_trait_ref(self, t)
}
@ -206,6 +267,12 @@ pub trait Visitor<'v> : Sized {
fn visit_vis(&mut self, vis: &'v Visibility) {
walk_vis(self, vis)
}
fn visit_associated_item_kind(&mut self, kind: &'v AssociatedItemKind) {
walk_associated_item_kind(self, kind);
}
fn visit_defaultness(&mut self, defaultness: &'v Defaultness) {
walk_defaultness(self, defaultness);
}
}
pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option<Name>) {
@ -341,12 +408,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_id(item.id);
visitor.visit_trait_ref(trait_ref)
}
ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => {
ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_item_refs) => {
visitor.visit_id(item.id);
visitor.visit_generics(type_parameters);
walk_list!(visitor, visit_trait_ref, opt_trait_reference);
visitor.visit_ty(typ);
walk_list!(visitor, visit_impl_item, impl_items);
for impl_item_ref in impl_item_refs {
visitor.visit_impl_item_ref(impl_item_ref);
}
}
ItemStruct(ref struct_definition, ref generics) |
ItemUnion(ref struct_definition, ref generics) => {
@ -677,10 +746,14 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
}
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) {
visitor.visit_vis(&impl_item.vis);
visitor.visit_name(impl_item.span, impl_item.name);
walk_list!(visitor, visit_attribute, &impl_item.attrs);
match impl_item.node {
// NB: Deliberately force a compilation error if/when new fields are added.
let ImplItem { id: _, name, ref vis, ref defaultness, ref attrs, ref node, span } = *impl_item;
visitor.visit_name(span, name);
visitor.visit_vis(vis);
visitor.visit_defaultness(defaultness);
walk_list!(visitor, visit_attribute, attrs);
match *node {
ImplItemKind::Const(ref ty, ref expr) => {
visitor.visit_id(impl_item.id);
visitor.visit_ty(ty);
@ -703,6 +776,17 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
}
}
pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) {
// NB: Deliberately force a compilation error if/when new fields are added.
let ImplItemRef { id, name, ref kind, span, ref vis, ref defaultness } = *impl_item_ref;
visitor.visit_nested_impl_item(id);
visitor.visit_name(span, name);
visitor.visit_associated_item_kind(kind);
visitor.visit_vis(vis);
visitor.visit_defaultness(defaultness);
}
pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
visitor.visit_id(struct_definition.id());
walk_list!(visitor, visit_struct_field, struct_definition.fields());
@ -872,6 +956,18 @@ pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) {
}
}
pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssociatedItemKind) {
// No visitable content here: this fn exists so you can call it if
// the right thing to do, should content be added in the future,
// would be to walk it.
}
pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) {
// No visitable content here: this fn exists so you can call it if
// the right thing to do, should content be added in the future,
// would be to walk it.
}
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)]
pub struct IdRange {
pub min: NodeId,

View file

@ -0,0 +1,84 @@
// Copyright 2012-2015 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 super::{Item, ImplItem};
use super::intravisit::Visitor;
/// The "item-like visitor" visitor defines only the top-level methods
/// that can be invoked by `Crate::visit_all_item_likes()`. Whether
/// this trait is the right one to implement will depend on the
/// overall pattern you need. Here are the three available patterns,
/// in roughly the order of desirability:
///
/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
/// - Example: find all items with a `#[foo]` attribute on them.
/// - How: Implement `ItemLikeVisitor` and call `tcx.visit_all_item_likes_in_krate()`.
/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
/// - Pro: Integrates well into dependency tracking.
/// - Con: Don't get information about nesting
/// - Con: Don't have methods for specific bits of HIR, like "on
/// every expr, do this".
/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
/// an item, but don't care about how item-like things are nested
/// within one another.
/// - Example: Examine each expression to look for its type and do some check or other.
/// - How: Implement `intravisit::Visitor` and use
/// `tcx.visit_all_item_likes_in_krate(visitor.as_deep_visitor())`. Within
/// your `intravisit::Visitor` impl, implement methods like
/// `visit_expr()`; don't forget to invoke
/// `intravisit::walk_visit_expr()` to keep walking the subparts.
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
/// - Pro: Integrates well into dependency tracking.
/// - Con: Don't get information about nesting between items
/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
/// item-like things.
/// - Example: Lifetime resolution, which wants to bring lifetimes declared on the
/// impl into scope while visiting the impl-items, and then back out again.
/// - How: Implement `intravisit::Visitor` and override the `visit_nested_foo()` foo methods
/// as needed. Walk your crate with `intravisit::walk_crate()` invoked on `tcx.map.krate()`.
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
/// - Pro: Preserves nesting information
/// - Con: Does not integrate well into dependency tracking.
///
/// Note: the methods of `ItemLikeVisitor` intentionally have no
/// defaults, so that as we expand the list of item-like things, we
/// revisit the various visitors to see if they need to change. This
/// is harder to do with `intravisit::Visitor`, so when you add a new
/// `visit_nested_foo()` method, it is recommended that you search for
/// existing `fn visit_nested` methods to see where changes are
/// needed.
pub trait ItemLikeVisitor<'hir> {
fn visit_item(&mut self, item: &'hir Item);
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem);
}
pub struct DeepVisitor<'v, V: 'v> {
visitor: &'v mut V,
}
impl<'v, 'hir, V> DeepVisitor<'v, V>
where V: Visitor<'hir> + 'v
{
pub fn new(base: &'v mut V) -> Self {
DeepVisitor { visitor: base }
}
}
impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V>
where V: Visitor<'hir>
{
fn visit_item(&mut self, item: &'hir Item) {
self.visitor.visit_item(item);
}
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem) {
self.visitor.visit_impl_item(impl_item);
}
}

View file

@ -105,6 +105,7 @@ impl<'a> LoweringContext<'a> {
fn lower_crate(&mut self, c: &Crate) -> hir::Crate {
struct ItemLowerer<'lcx, 'interner: 'lcx> {
items: BTreeMap<NodeId, hir::Item>,
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
lctx: &'lcx mut LoweringContext<'interner>,
}
@ -113,12 +114,20 @@ impl<'a> LoweringContext<'a> {
self.items.insert(item.id, self.lctx.lower_item(item));
visit::walk_item(self, item);
}
fn visit_impl_item(&mut self, item: &ImplItem) {
let id = self.lctx.lower_impl_item_ref(item).id;
self.impl_items.insert(id, self.lctx.lower_impl_item(item));
visit::walk_impl_item(self, item);
}
}
let items = {
let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), lctx: self };
let (items, impl_items) = {
let mut item_lowerer = ItemLowerer { items: BTreeMap::new(),
impl_items: BTreeMap::new(),
lctx: self };
visit::walk_crate(&mut item_lowerer, c);
item_lowerer.items
(item_lowerer.items, item_lowerer.impl_items)
};
hir::Crate {
@ -127,6 +136,7 @@ impl<'a> LoweringContext<'a> {
span: c.span,
exported_macros: c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(),
items: items,
impl_items: impl_items,
}
}
@ -631,7 +641,7 @@ impl<'a> LoweringContext<'a> {
}
ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
let new_impl_items = impl_items.iter()
.map(|item| self.lower_impl_item(item))
.map(|item| self.lower_impl_item_ref(item))
.collect();
let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref));
hir::ItemImpl(self.lower_unsafety(unsafety),
@ -689,7 +699,7 @@ impl<'a> LoweringContext<'a> {
name: i.ident.name,
attrs: this.lower_attrs(&i.attrs),
vis: this.lower_visibility(&i.vis),
defaultness: this.lower_defaultness(i.defaultness),
defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
node: match i.node {
ImplItemKind::Const(ref ty, ref expr) => {
hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr))
@ -705,6 +715,28 @@ impl<'a> LoweringContext<'a> {
span: i.span,
}
})
// [1] since `default impl` is not yet implemented, this is always true in impls
}
fn lower_impl_item_ref(&mut self, i: &ImplItem) -> hir::ImplItemRef {
hir::ImplItemRef {
id: hir::ImplItemId { node_id: i.id },
name: i.ident.name,
span: i.span,
vis: self.lower_visibility(&i.vis),
defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
kind: match i.node {
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
has_self: sig.decl.get_self().is_some(),
},
ImplItemKind::Macro(..) => unimplemented!(),
},
}
// [1] since `default impl` is not yet implemented, this is always true in impls
}
fn lower_mod(&mut self, m: &Mod) -> hir::Mod {
@ -1620,10 +1652,13 @@ impl<'a> LoweringContext<'a> {
}
}
fn lower_defaultness(&mut self, d: Defaultness) -> hir::Defaultness {
fn lower_defaultness(&mut self, d: Defaultness, has_value: bool) -> hir::Defaultness {
match d {
Defaultness::Default => hir::Defaultness::Default,
Defaultness::Final => hir::Defaultness::Final,
Defaultness::Default => hir::Defaultness::Default { has_value: has_value },
Defaultness::Final => {
assert!(has_value);
hir::Defaultness::Final
}
}
}

View file

@ -92,6 +92,11 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
/// Because we want to track parent items and so forth, enable
/// deep walking so that we walk nested items in the context of
/// their outer items.
fn nested_visit_map(&mut self) -> Option<&map::Map<'ast>> {
panic!("visit_nested_xxx must be manually implemented in this visitor")
}
fn visit_nested_item(&mut self, item: ItemId) {
debug!("visit_nested_item: {:?}", item);
if !self.ignore_nested_items {
@ -99,6 +104,10 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
}
}
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
self.visit_impl_item(self.krate.impl_item(item_id))
}
fn visit_item(&mut self, i: &'ast Item) {
debug!("visit_item: {:?}", i);

View file

@ -254,9 +254,14 @@ impl<'ast> Map<'ast> {
return DepNode::Hir(def_id);
}
EntryImplItem(..) => {
let def_id = self.local_def_id(id);
assert!(!self.is_inlined_def_id(def_id));
return DepNode::Hir(def_id);
}
EntryForeignItem(p, _) |
EntryTraitItem(p, _) |
EntryImplItem(p, _) |
EntryVariant(p, _) |
EntryExpr(p, _) |
EntryStmt(p, _) |
@ -378,6 +383,14 @@ impl<'ast> Map<'ast> {
self.forest.krate()
}
pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem {
self.read(id.node_id);
// NB: intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here
self.forest.krate.impl_item(id)
}
/// Get the attributes on the krate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.

View file

@ -68,6 +68,7 @@ pub mod check_attr;
pub mod def;
pub mod def_id;
pub mod intravisit;
pub mod itemlikevisit;
pub mod lowering;
pub mod map;
pub mod pat_util;
@ -423,6 +424,8 @@ pub struct Crate {
// detected, which in turn can make compile-fail tests yield
// slightly different results.
pub items: BTreeMap<NodeId, Item>,
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
}
impl Crate {
@ -430,6 +433,10 @@ impl Crate {
&self.items[&id]
}
pub fn impl_item(&self, id: ImplItemId) -> &ImplItem {
&self.impl_items[&id]
}
/// Visits all items in the crate in some determinstic (but
/// unspecified) order. If you just need to process every item,
/// but don't care about nesting, this method is the best choice.
@ -438,12 +445,16 @@ impl Crate {
/// follows lexical scoping rules -- then you want a different
/// approach. You should override `visit_nested_item` in your
/// visitor and then call `intravisit::walk_crate` instead.
pub fn visit_all_items<'hir, V>(&'hir self, visitor: &mut V)
where V: intravisit::Visitor<'hir>
pub fn visit_all_item_likes<'hir, V>(&'hir self, visitor: &mut V)
where V: itemlikevisit::ItemLikeVisitor<'hir>
{
for (_, item) in &self.items {
visitor.visit_item(item);
}
for (_, impl_item) in &self.impl_items {
visitor.visit_impl_item(impl_item);
}
}
}
@ -1041,6 +1052,14 @@ pub enum TraitItem_ {
TypeTraitItem(TyParamBounds, Option<P<Ty>>),
}
// The bodies for items are stored "out of line", in a separate
// hashmap in the `Crate`. Here we just record the node-id of the item
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct ImplItemId {
pub node_id: NodeId,
}
/// Represents anything within an `impl` block
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct ImplItem {
@ -1240,17 +1259,27 @@ pub enum Constness {
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Defaultness {
Default,
Default { has_value: bool },
Final,
}
impl Defaultness {
pub fn has_value(&self) -> bool {
match *self {
Defaultness::Default { has_value, .. } => has_value,
Defaultness::Final => true,
}
}
pub fn is_final(&self) -> bool {
*self == Defaultness::Final
}
pub fn is_default(&self) -> bool {
*self == Defaultness::Default
match *self {
Defaultness::Default { .. } => true,
_ => false,
}
}
}
@ -1527,7 +1556,7 @@ pub enum Item_ {
Generics,
Option<TraitRef>, // (optional) trait this impl implements
P<Ty>, // self
HirVec<ImplItem>),
HirVec<ImplItemRef>),
}
impl Item_ {
@ -1551,6 +1580,29 @@ impl Item_ {
}
}
/// A reference from an impl to one of its associated items. This
/// contains the item's id, naturally, but also the item's name and
/// some other high-level details (like whether it is an associated
/// type or method, and whether it is public). This allows other
/// passes to find the impl they want without loading the id (which
/// means fewer edges in the incremental compilation graph).
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct ImplItemRef {
pub id: ImplItemId,
pub name: Name,
pub kind: AssociatedItemKind,
pub span: Span,
pub vis: Visibility,
pub defaultness: Defaultness,
}
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum AssociatedItemKind {
Const,
Method { has_self: bool },
Type,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct ForeignItem {
pub name: Name,

View file

@ -809,7 +809,7 @@ impl<'a> State<'a> {
self.bopen()?;
self.print_inner_attributes(&item.attrs)?;
for impl_item in impl_items {
self.print_impl_item(impl_item)?;
self.print_impl_item_ref(impl_item)?;
}
self.bclose(item.span)?;
}
@ -1020,14 +1020,25 @@ impl<'a> State<'a> {
self.ann.post(self, NodeSubItem(ti.id))
}
pub fn print_impl_item_ref(&mut self, item_ref: &hir::ImplItemRef) -> io::Result<()> {
if let Some(krate) = self.krate {
// skip nested items if krate context was not provided
let item = &krate.impl_item(item_ref.id);
self.print_impl_item(item)
} else {
Ok(())
}
}
pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> {
self.ann.pre(self, NodeSubItem(ii.id))?;
self.hardbreak_if_not_bol()?;
self.maybe_print_comment(ii.span.lo)?;
self.print_outer_attributes(&ii.attrs)?;
if let hir::Defaultness::Default = ii.defaultness {
self.word_nbsp("default")?;
match ii.defaultness {
hir::Defaultness::Default { .. } => self.word_nbsp("default")?,
hir::Defaultness::Final => (),
}
match ii.node {

View file

@ -792,16 +792,15 @@ impl<'a> LintContext for EarlyContext<'a> {
}
}
impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
/// Because lints are scoped lexically, we want to walk nested
/// items in the context of the outer item, so enable
/// deep-walking.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let tcx = self.tcx;
self.visit_item(tcx.map.expect_item(item.id))
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_item(&mut self, it: &hir::Item) {
fn visit_item(&mut self, it: &'tcx hir::Item) {
self.with_lint_attrs(&it.attrs, |cx| {
run_lints!(cx, check_item, late_passes, it);
cx.visit_ids(|v| v.visit_item(it));
@ -810,7 +809,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
})
}
fn visit_foreign_item(&mut self, it: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
self.with_lint_attrs(&it.attrs, |cx| {
run_lints!(cx, check_foreign_item, late_passes, it);
hir_visit::walk_foreign_item(cx, it);
@ -818,19 +817,19 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
})
}
fn visit_pat(&mut self, p: &hir::Pat) {
fn visit_pat(&mut self, p: &'tcx hir::Pat) {
run_lints!(self, check_pat, late_passes, p);
hir_visit::walk_pat(self, p);
}
fn visit_expr(&mut self, e: &hir::Expr) {
fn visit_expr(&mut self, e: &'tcx hir::Expr) {
self.with_lint_attrs(&e.attrs, |cx| {
run_lints!(cx, check_expr, late_passes, e);
hir_visit::walk_expr(cx, e);
})
}
fn visit_stmt(&mut self, s: &hir::Stmt) {
fn visit_stmt(&mut self, s: &'tcx hir::Stmt) {
// statement attributes are actually just attributes on one of
// - item
// - local
@ -840,17 +839,17 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
hir_visit::walk_stmt(self, s);
}
fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
body: &'v hir::Expr, span: Span, id: ast::NodeId) {
fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
body: &'tcx hir::Expr, span: Span, id: ast::NodeId) {
run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
hir_visit::walk_fn(self, fk, decl, body, span, id);
run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
}
fn visit_variant_data(&mut self,
s: &hir::VariantData,
s: &'tcx hir::VariantData,
name: ast::Name,
g: &hir::Generics,
g: &'tcx hir::Generics,
item_id: ast::NodeId,
_: Span) {
run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
@ -858,14 +857,17 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
}
fn visit_struct_field(&mut self, s: &hir::StructField) {
fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
self.with_lint_attrs(&s.attrs, |cx| {
run_lints!(cx, check_struct_field, late_passes, s);
hir_visit::walk_struct_field(cx, s);
})
}
fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
fn visit_variant(&mut self,
v: &'tcx hir::Variant,
g: &'tcx hir::Generics,
item_id: ast::NodeId) {
self.with_lint_attrs(&v.node.attrs, |cx| {
run_lints!(cx, check_variant, late_passes, v, g);
hir_visit::walk_variant(cx, v, g, item_id);
@ -873,7 +875,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
})
}
fn visit_ty(&mut self, t: &hir::Ty) {
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
run_lints!(self, check_ty, late_passes, t);
hir_visit::walk_ty(self, t);
}
@ -882,45 +884,45 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
run_lints!(self, check_name, late_passes, sp, name);
}
fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) {
run_lints!(self, check_mod, late_passes, m, s, n);
hir_visit::walk_mod(self, m, n);
run_lints!(self, check_mod_post, late_passes, m, s, n);
}
fn visit_local(&mut self, l: &hir::Local) {
fn visit_local(&mut self, l: &'tcx hir::Local) {
self.with_lint_attrs(&l.attrs, |cx| {
run_lints!(cx, check_local, late_passes, l);
hir_visit::walk_local(cx, l);
})
}
fn visit_block(&mut self, b: &hir::Block) {
fn visit_block(&mut self, b: &'tcx hir::Block) {
run_lints!(self, check_block, late_passes, b);
hir_visit::walk_block(self, b);
run_lints!(self, check_block_post, late_passes, b);
}
fn visit_arm(&mut self, a: &hir::Arm) {
fn visit_arm(&mut self, a: &'tcx hir::Arm) {
run_lints!(self, check_arm, late_passes, a);
hir_visit::walk_arm(self, a);
}
fn visit_decl(&mut self, d: &hir::Decl) {
fn visit_decl(&mut self, d: &'tcx hir::Decl) {
run_lints!(self, check_decl, late_passes, d);
hir_visit::walk_decl(self, d);
}
fn visit_expr_post(&mut self, e: &hir::Expr) {
fn visit_expr_post(&mut self, e: &'tcx hir::Expr) {
run_lints!(self, check_expr_post, late_passes, e);
}
fn visit_generics(&mut self, g: &hir::Generics) {
fn visit_generics(&mut self, g: &'tcx hir::Generics) {
run_lints!(self, check_generics, late_passes, g);
hir_visit::walk_generics(self, g);
}
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
self.with_lint_attrs(&trait_item.attrs, |cx| {
run_lints!(cx, check_trait_item, late_passes, trait_item);
cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item));
@ -929,7 +931,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
});
}
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.with_lint_attrs(&impl_item.attrs, |cx| {
run_lints!(cx, check_impl_item, late_passes, impl_item);
cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item));
@ -938,20 +940,20 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
});
}
fn visit_lifetime(&mut self, lt: &hir::Lifetime) {
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
run_lints!(self, check_lifetime, late_passes, lt);
}
fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) {
fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) {
run_lints!(self, check_lifetime_def, late_passes, lt);
}
fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) {
fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) {
run_lints!(self, check_path, late_passes, p, id);
hir_visit::walk_path(self, p);
}
fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) {
run_lints!(self, check_path_list_item, late_passes, item);
hir_visit::walk_path_list_item(self, prefix, item);
}
@ -1116,7 +1118,6 @@ struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> {
// Output any lints that were previously added to the session.
impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> {
fn visit_id(&mut self, id: ast::NodeId) {
if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) {
debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);

View file

@ -16,6 +16,7 @@ use dep_graph::DepNode;
use hir::map as ast_map;
use hir::{self, pat_util, PatKind};
use hir::intravisit::{self, Visitor};
use hir::itemlikevisit::ItemLikeVisitor;
use middle::privacy;
use ty::{self, TyCtxt};
@ -329,11 +330,12 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool {
// or
// 2) We are not sure to be live or not
// * Implementation of a trait method
struct LifeSeeder {
worklist: Vec<ast::NodeId>
struct LifeSeeder<'k> {
worklist: Vec<ast::NodeId>,
krate: &'k hir::Crate,
}
impl<'v> Visitor<'v> for LifeSeeder {
impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> {
fn visit_item(&mut self, item: &hir::Item) {
let allow_dead_code = has_allow_dead_code_or_lang_attr(&item.attrs);
if allow_dead_code {
@ -357,17 +359,22 @@ impl<'v> Visitor<'v> for LifeSeeder {
}
}
}
hir::ItemImpl(.., ref opt_trait, _, ref impl_items) => {
for impl_item in impl_items {
hir::ItemImpl(.., ref opt_trait, _, ref impl_item_refs) => {
for impl_item_ref in impl_item_refs {
let impl_item = self.krate.impl_item(impl_item_ref.id);
if opt_trait.is_some() ||
has_allow_dead_code_or_lang_attr(&impl_item.attrs) {
self.worklist.push(impl_item.id);
self.worklist.push(impl_item_ref.id.node_id);
}
}
}
_ => ()
}
}
fn visit_impl_item(&mut self, _item: &hir::ImplItem) {
// ignore: we are handling this in `visit_item` above
}
}
fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -386,9 +393,10 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Seed implemented trait items
let mut life_seeder = LifeSeeder {
worklist: worklist
worklist: worklist,
krate: krate,
};
krate.visit_all_items(&mut life_seeder);
krate.visit_all_item_likes(&mut life_seeder);
return life_seeder.worklist;
}
@ -503,17 +511,16 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
/// Walk nested items in place so that we don't report dead-code
/// on inner functions when the outer function is already getting
/// an error. We could do this also by checking the parents, but
/// this is how the code is setup and it seems harmless enough.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let tcx = self.tcx;
self.visit_item(tcx.map.expect_item(item.id))
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_item(&mut self, item: &hir::Item) {
fn visit_item(&mut self, item: &'tcx hir::Item) {
if self.should_warn_about_item(item) {
self.warn_dead_code(
item.id,
@ -527,7 +534,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
}
}
fn visit_variant(&mut self, variant: &hir::Variant, g: &hir::Generics, id: ast::NodeId) {
fn visit_variant(&mut self,
variant: &'tcx hir::Variant,
g: &'tcx hir::Generics,
id: ast::NodeId) {
if self.should_warn_about_variant(&variant.node) {
self.warn_dead_code(variant.node.data.id(), variant.span,
variant.node.name, "variant");
@ -536,14 +546,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
}
}
fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
if !self.symbol_is_live(fi.id, None) {
self.warn_dead_code(fi.id, fi.span, fi.name, fi.node.descriptive_variant());
}
intravisit::walk_foreign_item(self, fi);
}
fn visit_struct_field(&mut self, field: &hir::StructField) {
fn visit_struct_field(&mut self, field: &'tcx hir::StructField) {
if self.should_warn_about_field(&field) {
self.warn_dead_code(field.id, field.span,
field.name, "field");
@ -552,7 +562,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
intravisit::walk_struct_field(self, field);
}
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
match impl_item.node {
hir::ImplItemKind::Const(_, ref expr) => {
if !self.symbol_is_live(impl_item.id, None) {
@ -573,7 +583,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
}
// Overwrite so that we don't warn the trait item itself.
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
match trait_item.node {
hir::ConstTraitItem(_, Some(ref body))|
hir::MethodTraitItem(_, Some(ref body)) => {

View file

@ -235,5 +235,5 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
unsafe_context: UnsafeContext::new(SafeContext),
};
tcx.map.krate().visit_all_items(&mut visitor);
tcx.map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
}

View file

@ -17,8 +17,8 @@ use syntax::ast::NodeId;
use syntax::attr;
use syntax::entry::EntryPointType;
use syntax_pos::Span;
use hir::{Item, ItemFn};
use hir::intravisit::Visitor;
use hir::{Item, ItemFn, ImplItem};
use hir::itemlikevisit::ItemLikeVisitor;
struct EntryContext<'a, 'tcx: 'a> {
session: &'a Session,
@ -39,13 +39,17 @@ struct EntryContext<'a, 'tcx: 'a> {
non_main_fns: Vec<(NodeId, Span)> ,
}
impl<'a, 'tcx> Visitor<'tcx> for EntryContext<'a, 'tcx> {
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx Item) {
let def_id = self.map.local_def_id(item.id);
let def_key = self.map.def_key(def_id);
let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
find_item(item, self, at_root);
}
fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) {
// entry fn is never an impl item
}
}
pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) {
@ -74,7 +78,7 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) {
non_main_fns: Vec::new(),
};
ast_map.krate().visit_all_items(&mut ctxt);
ast_map.krate().visit_all_item_likes(&mut ctxt);
configure_main(&mut ctxt);
}

View file

@ -26,7 +26,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut visitor = ItemVisitor {
tcx: tcx
};
tcx.visit_all_items_in_krate(DepNode::IntrinsicCheck, &mut visitor);
tcx.visit_all_item_likes_in_krate(DepNode::IntrinsicCheck, &mut visitor.as_deep_visitor());
}
struct ItemVisitor<'a, 'tcx: 'a> {

View file

@ -31,7 +31,7 @@ use util::nodemap::FxHashMap;
use syntax::ast;
use syntax::parse::token::InternedString;
use hir::intravisit::Visitor;
use hir::itemlikevisit::ItemLikeVisitor;
use hir;
// The actual lang items defined come at the end of this file in one handy table.
@ -149,7 +149,7 @@ struct LanguageItemCollector<'a, 'tcx: 'a> {
item_refs: FxHashMap<&'static str, usize>,
}
impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
if let Some(value) = extract(&item.attrs) {
let item_index = self.item_refs.get(&value[..]).cloned();
@ -164,6 +164,10 @@ impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
// at present, lang items are always items, not impl items
}
}
impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
@ -219,7 +223,7 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
}
pub fn collect_local_language_items(&mut self, krate: &hir::Crate) {
krate.visit_all_items(self);
krate.visit_all_item_likes(self);
}
pub fn collect_external_language_items(&mut self) {

View file

@ -196,7 +196,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> {
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let _task = tcx.dep_graph.in_task(DepNode::Liveness);
tcx.map.krate().visit_all_items(&mut IrMaps::new(tcx));
tcx.map.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor());
tcx.sess.abort_if_errors();
}

View file

@ -29,6 +29,7 @@ use syntax::ast;
use syntax::attr;
use hir;
use hir::intravisit::Visitor;
use hir::itemlikevisit::ItemLikeVisitor;
use hir::intravisit;
// Returns true if the given set of generics implies that the item it's
@ -324,17 +325,21 @@ struct CollectPrivateImplItemsVisitor<'a> {
worklist: &'a mut Vec<ast::NodeId>,
}
impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> {
impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> {
fn visit_item(&mut self, item: &hir::Item) {
// We need only trait impls here, not inherent impls, and only non-exported ones
if let hir::ItemImpl(.., Some(_), _, ref impl_items) = item.node {
if let hir::ItemImpl(.., Some(_), _, ref impl_item_refs) = item.node {
if !self.access_levels.is_reachable(item.id) {
for impl_item in impl_items {
self.worklist.push(impl_item.id);
for impl_item_ref in impl_item_refs {
self.worklist.push(impl_item_ref.id.node_id);
}
}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
// processed in visit_item above
}
}
pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -364,7 +369,7 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
access_levels: access_levels,
worklist: &mut reachable_context.worklist,
};
tcx.map.krate().visit_all_items(&mut collect_private_impl_items);
tcx.map.krate().visit_all_item_likes(&mut collect_private_impl_items);
}
// Step 2: Mark all symbols that the symbols on the worklist touch.

View file

@ -1235,7 +1235,7 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps {
},
terminating_scopes: NodeSet()
};
krate.visit_all_items(&mut visitor);
krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
}
return maps;
}

View file

@ -119,7 +119,7 @@ pub fn krate(sess: &Session,
late_bound: NodeMap(),
};
sess.track_errors(|| {
krate.visit_all_items(&mut LifetimeContext {
intravisit::walk_crate(&mut LifetimeContext {
sess: sess,
hir_map: hir_map,
map: &mut map,
@ -127,14 +127,21 @@ pub fn krate(sess: &Session,
def_map: def_map,
trait_ref_hack: false,
labels_in_fn: vec![],
});
}, krate);
})?;
Ok(map)
}
impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
assert!(self.labels_in_fn.is_empty());
impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// Override the nested functions -- lifetimes follow lexical scope,
// so it's convenient to walk the tree in lexical order.
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.hir_map)
}
fn visit_item(&mut self, item: &'tcx hir::Item) {
// Save labels for nested items.
let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
// Items always introduce a new root scope
self.with(RootScope, |_, this| {
@ -175,10 +182,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
});
// Done traversing the item; remove any labels it created
self.labels_in_fn.truncate(0);
self.labels_in_fn = saved_labels_in_fn;
}
fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
// Items save/restore the set of labels. This way inner items
// can freely reuse names, be they loop labels or lifetimes.
let saved = replace(&mut self.labels_in_fn, vec![]);
@ -201,8 +208,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
replace(&mut self.labels_in_fn, saved);
}
fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) {
fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
b: &'tcx hir::Expr, s: Span, fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, ..) => {
self.visit_early_late(fn_id,decl, generics, |this| {
@ -227,7 +234,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
}
}
fn visit_ty(&mut self, ty: &hir::Ty) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
match ty.node {
hir::TyBareFn(ref c) => {
self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
@ -257,7 +264,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
}
}
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
// We reset the labels on every trait item, so that different
// methods in an impl can reuse label names.
let saved = replace(&mut self.labels_in_fn, vec![]);
@ -274,7 +281,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
replace(&mut self.labels_in_fn, saved);
}
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
if lifetime_ref.name == keywords::StaticLifetime.name() {
self.insert_lifetime(lifetime_ref, DefStaticRegion);
return;
@ -282,7 +289,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
self.resolve_lifetime_ref(lifetime_ref);
}
fn visit_generics(&mut self, generics: &hir::Generics) {
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
for ty_param in generics.ty_params.iter() {
walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
if let Some(ref ty) = ty_param.default {
@ -331,8 +338,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
}
fn visit_poly_trait_ref(&mut self,
trait_ref: &hir::PolyTraitRef,
_modifier: &hir::TraitBoundModifier) {
trait_ref: &'tcx hir::PolyTraitRef,
_modifier: &'tcx hir::TraitBoundModifier) {
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() {
@ -490,13 +497,12 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) {
}
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
fn add_scope_and_walk_fn<'b>(&mut self,
fk: FnKind,
fd: &hir::FnDecl,
fb: &'b hir::Expr,
_span: Span,
fn_id: ast::NodeId) {
fn add_scope_and_walk_fn(&mut self,
fk: FnKind<'tcx>,
fd: &'tcx hir::FnDecl,
fb: &'tcx hir::Expr,
_span: Span,
fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, ..) => {
intravisit::walk_fn_decl(self, fd);
@ -519,8 +525,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|_old_scope, this| this.visit_expr(fb))
}
// FIXME(#37666) this works around a limitation in the region inferencer
fn hack<F>(&mut self, f: F) where
F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
{
f(self)
}
fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
F: FnOnce(Scope, &mut LifetimeContext),
F: for<'b> FnOnce(Scope, &mut LifetimeContext<'b, 'tcx>),
{
let LifetimeContext {sess, hir_map, ref mut map, ..} = *self;
let mut this = LifetimeContext {
@ -557,10 +570,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// ordering is not important there.
fn visit_early_late<F>(&mut self,
fn_id: ast::NodeId,
decl: &hir::FnDecl,
generics: &hir::Generics,
decl: &'tcx hir::FnDecl,
generics: &'tcx hir::Generics,
walk: F) where
F: FnOnce(&mut LifetimeContext),
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
{
let fn_def_id = self.hir_map.local_def_id(fn_id);
insert_late_bound_lifetimes(self.map,
@ -590,11 +603,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
}
let this = self;
this.with(EarlyScope(&early, start as u32, this.scope), move |old_scope, this| {
self.with(EarlyScope(&early, start as u32, self.scope), move |old_scope, this| {
this.with(LateScope(&late, this.scope), move |_, this| {
this.check_lifetime_defs(old_scope, &generics.lifetimes);
walk(this);
this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)`
});
});
}

View file

@ -120,7 +120,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
// stability. The stability is recorded in the index and used as the parent.
fn annotate<F>(&mut self, id: NodeId, attrs: &[Attribute],
item_sp: Span, kind: AnnotationKind, visit_children: F)
where F: FnOnce(&mut Annotator)
where F: FnOnce(&mut Self)
{
if self.index.staged_api[&LOCAL_CRATE] && self.tcx.sess.features.borrow().staged_api {
debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
@ -234,16 +234,15 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
/// Because stability levels are scoped lexically, we want to walk
/// nested items in the context of the outer item, so enable
/// deep-walking.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let tcx = self.tcx;
self.visit_item(tcx.map.expect_item(item.id))
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_item(&mut self, i: &Item) {
fn visit_item(&mut self, i: &'tcx Item) {
let orig_in_trait_impl = self.in_trait_impl;
let mut kind = AnnotationKind::Required;
match i.node {
@ -272,13 +271,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
self.in_trait_impl = orig_in_trait_impl;
}
fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
self.annotate(ti.id, &ti.attrs, ti.span, AnnotationKind::Required, |v| {
intravisit::walk_trait_item(v, ti);
});
}
fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
let kind = if self.in_trait_impl {
AnnotationKind::Prohibited
} else {
@ -289,25 +288,25 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
});
}
fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) {
fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) {
self.annotate(var.node.data.id(), &var.node.attrs, var.span, AnnotationKind::Required, |v| {
intravisit::walk_variant(v, var, g, item_id);
})
}
fn visit_struct_field(&mut self, s: &StructField) {
fn visit_struct_field(&mut self, s: &'tcx StructField) {
self.annotate(s.id, &s.attrs, s.span, AnnotationKind::Required, |v| {
intravisit::walk_struct_field(v, s);
});
}
fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) {
self.annotate(i.id, &i.attrs, i.span, AnnotationKind::Required, |v| {
intravisit::walk_foreign_item(v, i);
});
}
fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
if md.imported_from.is_none() {
self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {});
}
@ -444,16 +443,15 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
}
}
impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
/// Because stability levels are scoped lexically, we want to walk
/// nested items in the context of the outer item, so enable
/// deep-walking.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let tcx = self.tcx;
self.visit_item(tcx.map.expect_item(item.id))
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_item(&mut self, item: &hir::Item) {
fn visit_item(&mut self, item: &'tcx hir::Item) {
// When compiling with --test we don't enforce stability on the
// compiler-generated test module, demarcated with `DUMMY_SP` plus the
// name `__test`
@ -464,31 +462,31 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
intravisit::walk_item(self, item);
}
fn visit_expr(&mut self, ex: &hir::Expr) {
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
check_expr(self.tcx, ex,
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
intravisit::walk_expr(self, ex);
}
fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) {
check_path(self.tcx, path, id,
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
intravisit::walk_path(self, path)
}
fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) {
check_path_list_item(self.tcx, item,
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
intravisit::walk_path_list_item(self, prefix, item)
}
fn visit_pat(&mut self, pat: &hir::Pat) {
fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
check_pat(self.tcx, pat,
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
intravisit::walk_pat(self, pat)
}
fn visit_block(&mut self, b: &hir::Block) {
fn visit_block(&mut self, b: &'tcx hir::Block) {
let old_skip_count = self.in_skip_block;
match b.rules {
hir::BlockCheckMode::PushUnstableBlock => {
@ -527,9 +525,10 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// For implementations of traits, check the stability of each item
// individually as it's possible to have a stable trait with unstable
// items.
hir::ItemImpl(.., Some(ref t), _, ref impl_items) => {
hir::ItemImpl(.., Some(ref t), _, ref impl_item_refs) => {
let trait_did = tcx.expect_def(t.ref_id).def_id();
for impl_item in impl_items {
for impl_item_ref in impl_item_refs {
let impl_item = tcx.map.impl_item(impl_item_ref.id);
let item = tcx.associated_items(trait_did)
.find(|item| item.name == impl_item.name).unwrap();
if warn_about_defns {

View file

@ -50,7 +50,7 @@ pub fn check_crate(krate: &hir::Crate,
{
let mut cx = Context { sess: sess, items: items };
krate.visit_all_items(&mut cx);
krate.visit_all_item_likes(&mut cx.as_deep_visitor());
}
verify(sess, items);
}

View file

@ -940,7 +940,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
// an error when we confirm the candidate
// (which will ultimately lead to `normalize_to_error`
// being invoked).
node_item.item.has_value
node_item.item.defaultness.has_value()
} else {
node_item.item.defaultness.is_default()
};
@ -1004,8 +1004,9 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
// types, which appear not to unify -- so the
// overlap check succeeds, when it should
// fail.
bug!("Tried to project an inherited associated type during \
coherence checking, which is currently not supported.");
span_bug!(obligation.cause.span,
"Tried to project an inherited associated type during \
coherence checking, which is currently not supported.");
};
candidate_set.vec.extend(new_candidate);
}
@ -1295,7 +1296,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
match assoc_ty {
Some(node_item) => {
let ty = if !node_item.item.has_value {
let ty = if !node_item.item.defaultness.has_value() {
// This means that the impl is missing a definition for the
// associated type. This error will be reported by the type
// checker method `check_impl_items_against_trait`, so here we

View file

@ -50,7 +50,7 @@ use syntax_pos::{DUMMY_SP, Span};
use rustc_const_math::ConstInt;
use hir;
use hir::intravisit::Visitor;
use hir::itemlikevisit::ItemLikeVisitor;
pub use self::sty::{Binder, DebruijnIndex};
pub use self::sty::{BuiltinBound, BuiltinBounds};
@ -189,7 +189,6 @@ pub struct AssociatedItem {
pub kind: AssociatedKind,
pub vis: Visibility,
pub defaultness: hir::Defaultness,
pub has_value: bool,
pub container: AssociatedItemContainer,
/// Whether this is a method with an explicit self
@ -2072,7 +2071,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn provided_trait_methods(self, id: DefId) -> Vec<AssociatedItem> {
self.associated_items(id)
.filter(|item| item.kind == AssociatedKind::Method && item.has_value)
.filter(|item| item.kind == AssociatedKind::Method && item.defaultness.has_value())
.collect()
}
@ -2113,69 +2112,109 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
.expect("missing AssociatedItem in metadata");
}
// When the user asks for a given associated item, we
// always go ahead and convert all the associated items in
// the container. Note that we are also careful only to
// ever register a read on the *container* of the assoc
// item, not the assoc item itself. This prevents changes
// in the details of an item (for example, the type to
// which an associated type is bound) from contaminating
// those tasks that just need to scan the names of items
// and so forth.
let id = self.map.as_local_node_id(def_id).unwrap();
let parent_id = self.map.get_parent(id);
let parent_def_id = self.map.local_def_id(parent_id);
match self.map.get(id) {
ast_map::NodeTraitItem(trait_item) => {
let (kind, has_self, has_value) = match trait_item.node {
hir::MethodTraitItem(ref sig, ref body) => {
(AssociatedKind::Method, sig.decl.get_self().is_some(),
body.is_some())
}
hir::ConstTraitItem(_, ref value) => {
(AssociatedKind::Const, false, value.is_some())
}
hir::TypeTraitItem(_, ref ty) => {
(AssociatedKind::Type, false, ty.is_some())
}
};
AssociatedItem {
name: trait_item.name,
kind: kind,
vis: Visibility::from_hir(&hir::Inherited, id, self),
defaultness: hir::Defaultness::Default,
has_value: has_value,
def_id: def_id,
container: TraitContainer(parent_def_id),
method_has_self_argument: has_self
let parent_item = self.map.expect_item(parent_id);
match parent_item.node {
hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => {
for impl_item_ref in impl_item_refs {
let assoc_item =
self.associated_item_from_impl_item_ref(parent_def_id,
impl_trait_ref.is_some(),
impl_item_ref);
self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
}
}
ast_map::NodeImplItem(impl_item) => {
let (kind, has_self) = match impl_item.node {
hir::ImplItemKind::Method(ref sig, _) => {
(AssociatedKind::Method, sig.decl.get_self().is_some())
}
hir::ImplItemKind::Const(..) => (AssociatedKind::Const, false),
hir::ImplItemKind::Type(..) => (AssociatedKind::Type, false)
};
// Trait impl items are always public.
let public = hir::Public;
let parent_item = self.map.expect_item(parent_id);
let vis = if let hir::ItemImpl(.., Some(_), _, _) = parent_item.node {
&public
} else {
&impl_item.vis
};
AssociatedItem {
name: impl_item.name,
kind: kind,
vis: Visibility::from_hir(vis, id, self),
defaultness: impl_item.defaultness,
has_value: true,
def_id: def_id,
container: ImplContainer(parent_def_id),
method_has_self_argument: has_self
hir::ItemTrait(.., ref trait_items) => {
for trait_item in trait_items {
let assoc_item =
self.associated_item_from_trait_item_ref(parent_def_id, trait_item);
self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
}
}
item => bug!("associated_item: {:?} not an associated item", item)
ref r => {
panic!("unexpected container of associated items: {:?}", r)
}
}
// memoize wants us to return something, so return
// the one we generated for this def-id
*self.associated_items.borrow().get(&def_id).unwrap()
})
}
fn associated_item_from_trait_item_ref(self,
parent_def_id: DefId,
trait_item: &hir::TraitItem)
-> AssociatedItem {
let def_id = self.map.local_def_id(trait_item.id);
let (kind, has_self, has_value) = match trait_item.node {
hir::MethodTraitItem(ref sig, ref body) => {
(AssociatedKind::Method, sig.decl.get_self().is_some(),
body.is_some())
}
hir::ConstTraitItem(_, ref value) => {
(AssociatedKind::Const, false, value.is_some())
}
hir::TypeTraitItem(_, ref ty) => {
(AssociatedKind::Type, false, ty.is_some())
}
};
AssociatedItem {
name: trait_item.name,
kind: kind,
vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self),
defaultness: hir::Defaultness::Default { has_value: has_value },
def_id: def_id,
container: TraitContainer(parent_def_id),
method_has_self_argument: has_self
}
}
fn associated_item_from_impl_item_ref(self,
parent_def_id: DefId,
from_trait_impl: bool,
impl_item_ref: &hir::ImplItemRef)
-> AssociatedItem {
let def_id = self.map.local_def_id(impl_item_ref.id.node_id);
let (kind, has_self) = match impl_item_ref.kind {
hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false),
hir::AssociatedItemKind::Method { has_self } => {
(ty::AssociatedKind::Method, has_self)
}
hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
};
// Trait impl items are always public.
let public = hir::Public;
let vis = if from_trait_impl { &public } else { &impl_item_ref.vis };
ty::AssociatedItem {
name: impl_item_ref.name,
kind: kind,
vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self),
defaultness: impl_item_ref.defaultness,
def_id: def_id,
container: ImplContainer(parent_def_id),
method_has_self_argument: has_self
}
}
pub fn associated_item_def_ids(self, def_id: DefId) -> Rc<Vec<DefId>> {
self.associated_item_def_ids.memoize(def_id, || {
if !def_id.is_local() {
@ -2184,19 +2223,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let id = self.map.as_local_node_id(def_id).unwrap();
let item = self.map.expect_item(id);
match item.node {
let vec: Vec<_> = match item.node {
hir::ItemTrait(.., ref trait_items) => {
Rc::new(trait_items.iter().map(|trait_item| {
self.map.local_def_id(trait_item.id)
}).collect())
trait_items.iter()
.map(|trait_item| trait_item.id)
.map(|id| self.map.local_def_id(id))
.collect()
}
hir::ItemImpl(.., ref impl_items) => {
Rc::new(impl_items.iter().map(|impl_item| {
self.map.local_def_id(impl_item.id)
}).collect())
hir::ItemImpl(.., ref impl_item_refs) => {
impl_item_refs.iter()
.map(|impl_item_ref| impl_item_ref.id)
.map(|id| self.map.local_def_id(id.node_id))
.collect()
}
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait")
}
};
Rc::new(vec)
})
}
@ -2695,12 +2737,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.mk_region(ty::ReScope(self.region_maps.node_extent(id)))
}
pub fn visit_all_items_in_krate<V,F>(self,
dep_node_fn: F,
visitor: &mut V)
where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'gcx>
pub fn visit_all_item_likes_in_krate<V,F>(self,
dep_node_fn: F,
visitor: &mut V)
where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'gcx>
{
dep_graph::visit_all_items_in_krate(self.global_tcx(), dep_node_fn, visitor);
dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor);
}
/// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`