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`

View File

@ -110,7 +110,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
}
};
tcx.visit_all_items_in_krate(DepNode::BorrowCheck, &mut bccx);
tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor());
if tcx.sess.borrowck_stats() {
println!("--- borrowck stats ---");

View File

@ -78,7 +78,8 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
}
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut OuterVisitor { tcx: tcx });
tcx.visit_all_item_likes_in_krate(DepNode::MatchCheck,
&mut OuterVisitor { tcx: tcx }.as_deep_visitor());
tcx.sess.abort_if_errors();
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
use rustc::dep_graph::DepNode;
use rustc::hir::intravisit::Visitor;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::map::Map;
use rustc::hir;
use syntax::ast;
@ -20,7 +20,7 @@ pub fn find(hir_map: &Map) -> Option<ast::NodeId> {
let krate = hir_map.krate();
let mut finder = Finder { registrar: None };
krate.visit_all_items(&mut finder);
krate.visit_all_item_likes(&mut finder);
finder.registrar
}
@ -28,10 +28,14 @@ struct Finder {
registrar: Option<ast::NodeId>,
}
impl<'v> Visitor<'v> for Finder {
impl<'v> ItemLikeVisitor<'v> for Finder {
fn visit_item(&mut self, item: &hir::Item) {
if attr::contains_name(&item.attrs, "rustc_derive_registrar") {
self.registrar = Some(item.id);
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View File

@ -51,7 +51,7 @@ use rustc::ty::TyCtxt;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex};
use rustc::hir;
use rustc::hir::intravisit::Visitor;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use graphviz::IntoCow;
use std::env;
use std::fs::File;
@ -81,7 +81,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
if_this_changed: vec![],
then_this_would_need: vec![] };
visitor.process_attrs(ast::CRATE_NODE_ID, &tcx.map.krate().attrs);
tcx.map.krate().visit_all_items(&mut visitor);
tcx.map.krate().visit_all_item_likes(&mut visitor);
(visitor.if_this_changed, visitor.then_this_would_need)
};
@ -167,10 +167,14 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
}
}
impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> {
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
self.process_attrs(item.id, &item.attrs);
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.process_attrs(impl_item.id, &impl_item.attrs);
}
}
fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,

View File

@ -34,6 +34,7 @@ use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::hir::intravisit as visit;
use rustc::hir::intravisit::Visitor;
use rustc::ty::TyCtxt;
use rustc_data_structures::fx::FxHashMap;
use rustc::util::common::record_time;
@ -107,7 +108,8 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX),
|v| visit::walk_crate(v, krate));
krate.visit_all_items(&mut visitor);
// FIXME(#37713) if foreign items were item likes, could use ItemLikeVisitor
krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
});
tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
@ -199,12 +201,17 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
}
impl<'a, 'tcx> visit::Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
self.calculate_node_id(item.id, |v| v.visit_item(item));
visit::walk_item(self, item);
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
visit::walk_impl_item(self, impl_item);
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
self.calculate_node_id(item.id, |v| v.visit_foreign_item(item));
visit::walk_foreign_item(self, item);

View File

@ -199,6 +199,8 @@ enum SawAbiComponent<'a> {
SawExpr(SawExprComponent<'a>),
SawStmt,
SawVis,
SawAssociatedItemKind(hir::AssociatedItemKind),
SawDefaultness(hir::Defaultness),
SawWherePredicate,
SawTyParamBound,
SawPolyTraitRef,
@ -499,10 +501,6 @@ macro_rules! hash_span {
}
impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
fn visit_nested_item(&mut self, _: ItemId) {
// Each item is hashed independently; ignore nested items.
}
fn visit_variant_data(&mut self,
s: &'tcx VariantData,
name: Name,
@ -697,6 +695,18 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
visit::walk_vis(self, v)
}
fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) {
debug!("visit_associated_item_kind: st={:?}", self.st);
SawAssociatedItemKind(*kind).hash(self.st);
visit::walk_associated_item_kind(self, kind);
}
fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) {
debug!("visit_associated_item_kind: st={:?}", self.st);
SawDefaultness(*defaultness).hash(self.st);
visit::walk_defaultness(self, defaultness);
}
fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) {
debug!("visit_where_predicate: st={:?}", self.st);
SawWherePredicate.hash(self.st);

View File

@ -45,7 +45,7 @@ use super::load::DirtyNodes;
use rustc::dep_graph::{DepGraphQuery, DepNode};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::Visitor;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use syntax::ast::{self, Attribute, NestedMetaItem};
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use syntax::parse::token::InternedString;
@ -74,7 +74,7 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let query = tcx.dep_graph.query();
debug!("query-nodes: {:?}", query.nodes());
let krate = tcx.map.krate();
krate.visit_all_items(&mut DirtyCleanVisitor {
krate.visit_all_item_likes(&mut DirtyCleanVisitor {
tcx: tcx,
query: &query,
dirty_inputs: dirty_inputs,
@ -169,7 +169,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
let def_id = self.tcx.map.local_def_id(item.id);
for attr in self.tcx.get_attrs(def_id).iter() {
@ -184,6 +184,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -195,7 +198,7 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx.dep_graph.with_ignore(||{
let krate = tcx.map.krate();
krate.visit_all_items(&mut DirtyCleanMetadataVisitor {
krate.visit_all_item_likes(&mut DirtyCleanMetadataVisitor {
tcx: tcx,
prev_metadata_hashes: prev_metadata_hashes,
current_metadata_hashes: current_metadata_hashes,
@ -209,7 +212,7 @@ pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> {
current_metadata_hashes: &'m FxHashMap<DefId, Fingerprint>,
}
impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
let def_id = self.tcx.map.local_def_id(item.id);
@ -225,6 +228,9 @@ impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {

View File

@ -201,6 +201,19 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
debug!("crate-dir: {}", crate_dir.display());
try!(create_dir(tcx.sess, &crate_dir, "crate"));
// Hack: canonicalize the path *after creating the directory*
// because, on windows, long paths can cause problems;
// canonicalization inserts this weird prefix that makes windows
// tolerate long paths.
let crate_dir = match crate_dir.canonicalize() {
Ok(v) => v,
Err(err) => {
tcx.sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}",
crate_dir.display(), err));
return Err(());
}
};
let mut source_directories_already_tried = FxHashSet();
loop {

View File

@ -387,7 +387,7 @@ impl LateLintPass for MissingDoc {
"a trait"
}
hir::ItemTy(..) => "a type alias",
hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => {
hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) => {
// If the trait is private, add the impl items to private_traits so they don't get
// reported for missing docs.
let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id();
@ -395,8 +395,8 @@ impl LateLintPass for MissingDoc {
match cx.tcx.map.find(node_id) {
Some(hir_map::NodeItem(item)) => {
if item.vis == hir::Visibility::Inherited {
for itm in impl_items {
self.private_traits.insert(itm.id);
for impl_item_ref in impl_item_refs {
self.private_traits.insert(impl_item_ref.id.node_id);
}
}
}

View File

@ -850,7 +850,6 @@ impl<'a, 'tcx> CrateMetadata {
kind: ty::AssociatedKind::Const,
vis: item.visibility,
defaultness: container.defaultness(),
has_value: container.has_value(),
def_id: self.local_def_id(id),
container: container.with_def_id(parent),
method_has_self_argument: false
@ -864,7 +863,6 @@ impl<'a, 'tcx> CrateMetadata {
kind: ty::AssociatedKind::Method,
vis: item.visibility,
defaultness: data.container.defaultness(),
has_value: data.container.has_value(),
def_id: self.local_def_id(id),
container: data.container.with_def_id(parent),
method_has_self_argument: data.has_self
@ -877,7 +875,6 @@ impl<'a, 'tcx> CrateMetadata {
kind: ty::AssociatedKind::Type,
vis: item.visibility,
defaultness: container.defaultness(),
has_value: container.has_value(),
def_id: self.local_def_id(id),
container: container.with_def_id(parent),
method_has_self_argument: false

View File

@ -38,6 +38,7 @@ use syntax;
use syntax_pos;
use rustc::hir::{self, PatKind};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::intravisit::Visitor;
use rustc::hir::intravisit;
@ -459,10 +460,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let ast_item = tcx.map.expect_trait_item(node_id);
let trait_item = tcx.associated_item(def_id);
let container = if trait_item.has_value {
AssociatedContainer::TraitWithDefault
} else {
AssociatedContainer::TraitRequired
let container = match trait_item.defaultness {
hir::Defaultness::Default { has_value: true } =>
AssociatedContainer::TraitWithDefault,
hir::Defaultness::Default { has_value: false } =>
AssociatedContainer::TraitRequired,
hir::Defaultness::Final =>
span_bug!(ast_item.span, "traits cannot have final items"),
};
let kind = match trait_item.kind {
@ -500,7 +504,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
Some(self.encode_item_type(def_id))
}
ty::AssociatedKind::Type => {
if trait_item.has_value {
if trait_item.defaultness.has_value() {
Some(self.encode_item_type(def_id))
} else {
None
@ -529,8 +533,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let impl_def_id = impl_item.container.id();
let container = match impl_item.defaultness {
hir::Defaultness::Default => AssociatedContainer::ImplDefault,
hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault,
hir::Defaultness::Final => AssociatedContainer::ImplFinal,
hir::Defaultness::Default { has_value: false } =>
span_bug!(ast_item.span, "impl items always have values (currently)"),
};
let kind = match impl_item.kind {
@ -1074,7 +1080,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
EncodeContext::encode_info_for_mod,
FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public)));
let mut visitor = EncodeVisitor { index: index };
krate.visit_all_items(&mut visitor);
krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
for macro_def in &krate.exported_macros {
visitor.visit_macro_def(macro_def);
}
@ -1159,7 +1165,7 @@ struct ImplVisitor<'a, 'tcx: 'a> {
impls: FxHashMap<DefId, Vec<DefIndex>>,
}
impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
if let hir::ItemImpl(..) = item.node {
let impl_id = self.tcx.map.local_def_id(item.id);
@ -1171,6 +1177,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
}
}
}
fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) {
// handled in `visit_item` above
}
}
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
@ -1180,7 +1190,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
tcx: self.tcx,
impls: FxHashMap(),
};
self.tcx.map.krate().visit_all_items(&mut visitor);
self.tcx.map.krate().visit_all_item_likes(&mut visitor);
let all_impls: Vec<_> = visitor.impls
.into_iter()

View File

@ -310,21 +310,16 @@ impl AssociatedContainer {
}
}
pub fn has_value(&self) -> bool {
match *self {
AssociatedContainer::TraitRequired => false,
AssociatedContainer::TraitWithDefault |
AssociatedContainer::ImplDefault |
AssociatedContainer::ImplFinal => true,
}
}
pub fn defaultness(&self) -> hir::Defaultness {
match *self {
AssociatedContainer::TraitRequired |
AssociatedContainer::TraitRequired => hir::Defaultness::Default {
has_value: false,
},
AssociatedContainer::TraitWithDefault |
AssociatedContainer::ImplDefault => hir::Defaultness::Default,
AssociatedContainer::ImplDefault => hir::Defaultness::Default {
has_value: true,
},
AssociatedContainer::ImplFinal => hir::Defaultness::Final,
}

View File

@ -38,9 +38,9 @@ use syntax_pos::Span;
use std::mem;
pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.visit_all_items_in_krate(DepNode::Mir, &mut BuildMir {
tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut BuildMir {
tcx: tcx
});
}.as_deep_visitor());
}
/// A pass to lift all the types and substitutions in a Mir

View File

@ -277,8 +277,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
.and_then(|impl_node_id| self.tcx.map.find(impl_node_id))
.map(|node| {
if let hir_map::NodeItem(item) = node {
if let hir::ItemImpl(_, _, _, _, _, ref methods) = item.node {
span = methods.first().map(|method| method.span);
if let hir::ItemImpl(.., ref impl_item_refs) = item.node {
span = impl_item_refs.first()
.map(|iiref| {
self.tcx.map.impl_item(iiref.id)
.span
});
}
}
});

View File

@ -644,13 +644,13 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
}
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.visit_all_items_in_krate(DepNode::CheckConst,
&mut CheckCrateVisitor {
tcx: tcx,
mode: Mode::Var,
qualif: ConstQualif::NOT_CONST,
rvalue_borrows: NodeMap(),
});
tcx.visit_all_item_likes_in_krate(DepNode::CheckConst,
&mut CheckCrateVisitor {
tcx: tcx,
mode: Mode::Var,
qualif: ConstQualif::NOT_CONST,
rvalue_borrows: NodeMap(),
}.as_deep_visitor());
tcx.sess.abort_if_errors();
}

View File

@ -106,12 +106,20 @@ impl<'k> StatCollector<'k> {
}
impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> {
panic!("visit_nested_xxx must be manually implemented in this visitor")
}
fn visit_nested_item(&mut self, id: hir::ItemId) {
let nested_item = self.krate.unwrap().item(id.id);
self.visit_item(nested_item)
}
fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id);
self.visit_impl_item(nested_impl_item)
}
fn visit_item(&mut self, i: &'v hir::Item) {
self.record("Item", Id::Node(i.id), i);
hir_visit::walk_item(self, i)

View File

@ -33,10 +33,10 @@ struct CheckLoopVisitor<'a> {
pub fn check_crate(sess: &Session, map: &Map) {
let _task = map.dep_graph.in_task(DepNode::CheckLoops);
let krate = map.krate();
krate.visit_all_items(&mut CheckLoopVisitor {
krate.visit_all_item_likes(&mut CheckLoopVisitor {
sess: sess,
cx: Normal,
});
}.as_deep_visitor());
}
impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
@ -44,6 +44,10 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
self.with_context(Normal, |v| intravisit::walk_item(v, i));
}
fn visit_impl_item(&mut self, i: &hir::ImplItem) {
self.with_context(Normal, |v| intravisit::walk_impl_item(v, i));
}
fn visit_expr(&mut self, e: &hir::Expr) {
match e.node {
hir::ExprWhile(ref e, ref b, _) => {

View File

@ -18,20 +18,20 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment};
use rustc::traits::Reveal;
use rustc::hir;
use rustc::hir::intravisit;
use rustc::hir::intravisit::{self, Visitor};
use syntax::ast;
use syntax_pos::Span;
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut rvcx = RvalueContext { tcx: tcx };
tcx.visit_all_items_in_krate(DepNode::RvalueCheck, &mut rvcx);
tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor());
}
struct RvalueContext<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
impl<'a, 'tcx, 'v> Visitor<'v> for RvalueContext<'a, 'tcx> {
fn visit_fn(&mut self,
fk: intravisit::FnKind<'v>,
fd: &'v hir::FnDecl,

View File

@ -100,7 +100,8 @@ pub fn check_crate<'ast>(sess: &Session,
discriminant_map: RefCell::new(NodeMap()),
};
sess.track_errors(|| {
ast_map.krate().visit_all_items(&mut visitor);
// FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
ast_map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
})
}

View File

@ -16,14 +16,14 @@ use errors;
use syntax_pos::Span;
use rustc::dep_graph::DepNode;
use rustc::hir::map::Map;
use rustc::hir::intravisit::Visitor;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir;
struct RegistrarFinder {
registrars: Vec<(ast::NodeId, Span)> ,
}
impl<'v> Visitor<'v> for RegistrarFinder {
impl<'v> ItemLikeVisitor<'v> for RegistrarFinder {
fn visit_item(&mut self, item: &hir::Item) {
if let hir::ItemFn(..) = item.node {
if attr::contains_name(&item.attrs,
@ -32,6 +32,9 @@ impl<'v> Visitor<'v> for RegistrarFinder {
}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
/// Find the function marked with `#[plugin_registrar]`, if any.
@ -42,7 +45,7 @@ pub fn find_plugin_registrar(diagnostic: &errors::Handler,
let krate = hir_map.krate();
let mut finder = RegistrarFinder { registrars: Vec::new() };
krate.visit_all_items(&mut finder);
krate.visit_all_item_likes(&mut finder);
match finder.registrars.len() {
0 => None,

View File

@ -31,6 +31,7 @@ use rustc::hir::{self, PatKind};
use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::{self, Visitor};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
use rustc::lint;
use rustc::middle::privacy::{AccessLevel, AccessLevels};
@ -115,15 +116,14 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
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) {
let inherited_item_level = match item.node {
// Impls inherit level from their types and traits
hir::ItemImpl(.., None, ref ty, _) => {
@ -158,15 +158,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
}
}
}
hir::ItemImpl(.., None, _, ref impl_items) => {
for impl_item in impl_items {
hir::ItemImpl(.., None, _, ref impl_item_refs) => {
for impl_item_ref in impl_item_refs {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
if impl_item.vis == hir::Public {
self.update(impl_item.id, item_level);
}
}
}
hir::ItemImpl(.., Some(_), _, ref impl_items) => {
for impl_item in impl_items {
hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => {
for impl_item_ref in impl_item_refs {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
self.update(impl_item.id, item_level);
}
}
@ -249,11 +251,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
// The interface is empty
hir::ItemDefaultImpl(..) => {}
// Visit everything except for private impl items
hir::ItemImpl(.., ref generics, None, _, ref impl_items) => {
hir::ItemImpl(.., ref generics, None, _, ref impl_item_refs) => {
if item_level.is_some() {
self.reach().visit_generics(generics);
for impl_item in impl_items {
if self.get(impl_item.id).is_some() {
for impl_item_ref in impl_item_refs {
if self.get(impl_item_ref.id.node_id).is_some() {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
self.reach().visit_impl_item(impl_item);
}
}
@ -269,7 +272,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
self.prev_level = orig_level;
}
fn visit_block(&mut self, b: &'v hir::Block) {
fn visit_block(&mut self, b: &'tcx hir::Block) {
let orig_level = replace(&mut self.prev_level, None);
// Blocks can have public items, for example impls, but they always
@ -280,7 +283,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
self.prev_level = orig_level;
}
fn visit_mod(&mut self, m: &hir::Mod, _sp: Span, id: ast::NodeId) {
fn visit_mod(&mut self, m: &'tcx hir::Mod, _sp: Span, id: ast::NodeId) {
// This code is here instead of in visit_item so that the
// crate module gets processed as well.
if self.prev_level.is_some() {
@ -296,14 +299,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
intravisit::walk_mod(self, m, id);
}
fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
self.update(md.id, Some(AccessLevel::Public));
}
}
impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
// Make the type hidden under a type alias reachable
fn reach_aliased_type(&mut self, item: &hir::Item, path: &hir::Path) {
fn reach_aliased_type(&mut self, item: &'tcx hir::Item, path: &'tcx hir::Path) {
if let hir::ItemTy(ref ty, ref generics) = item.node {
// See `fn is_public_type_alias` for details
self.visit_ty(ty);
@ -317,8 +320,14 @@ impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
}
}
impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
fn visit_ty(&mut self, ty: &hir::Ty) {
impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
// when we visit an impl, its methods and items are part of its "interface"
let impl_item = self.ev.tcx.map.impl_item(item_id);
self.visit_impl_item(impl_item)
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
if let hir::TyPath(_, ref path) = ty.node {
let def = self.ev.tcx.expect_def(ty.id);
match def {
@ -350,7 +359,7 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<
intravisit::walk_ty(self, ty);
}
fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
let def_id = self.ev.tcx.expect_def(trait_ref.ref_id).def_id();
if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
let item = self.ev.tcx.map.expect_item(node_id);
@ -412,21 +421,20 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
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) {
let orig_curitem = replace(&mut self.curitem, item.id);
intravisit::walk_item(self, item);
self.curitem = orig_curitem;
}
fn visit_expr(&mut self, expr: &hir::Expr) {
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
match expr.node {
hir::ExprMethodCall(..) => {
let method_call = ty::MethodCall::expr(expr.id);
@ -486,7 +494,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
intravisit::walk_expr(self, expr);
}
fn visit_pat(&mut self, pattern: &hir::Pat) {
fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
// Foreign functions do not have their patterns mapped in the def_map,
// and there's nothing really relevant there anyway, so don't bother
// checking privacy. If you can name the type then you can pass it to an
@ -522,7 +530,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
intravisit::walk_pat(self, pattern);
}
fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
self.in_foreign = true;
intravisit::walk_foreign_item(self, fi);
self.in_foreign = false;
@ -616,15 +624,14 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a
fn visit_expr(&mut self, _: &hir::Expr) {}
}
impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
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) {
match item.node {
// contents of a private mod can be reexported, so we need
// to check internals.
@ -649,7 +656,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
// (i.e. we could just return here to not check them at
// all, or some worse estimation of whether an impl is
// publicly visible).
hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_items) => {
hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_item_refs) => {
// `impl [... for] Private` is never visible.
let self_contains_private;
// impl [... for] Public<...>, but not `impl [... for]
@ -694,16 +701,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
// are private (because `T` won't be visible externally).
let trait_or_some_public_method =
trait_ref.is_some() ||
impl_items.iter()
.any(|impl_item| {
match impl_item.node {
hir::ImplItemKind::Const(..) |
hir::ImplItemKind::Method(..) => {
self.access_levels.is_reachable(impl_item.id)
}
hir::ImplItemKind::Type(_) => false,
}
});
impl_item_refs.iter()
.any(|impl_item_ref| {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
match impl_item.node {
hir::ImplItemKind::Const(..) |
hir::ImplItemKind::Method(..) => {
self.access_levels.is_reachable(impl_item.id)
}
hir::ImplItemKind::Type(_) => false,
}
});
if !self_contains_private &&
not_private_trait &&
@ -713,12 +721,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
match *trait_ref {
None => {
for impl_item in impl_items {
for impl_item_ref in impl_item_refs {
// This is where we choose whether to walk down
// further into the impl to check its items. We
// should only walk into public items so that we
// don't erroneously report errors for private
// types in private items.
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
match impl_item.node {
hir::ImplItemKind::Const(..) |
hir::ImplItemKind::Method(..)
@ -750,7 +759,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
intravisit::walk_path(self, &tr.path);
// Those in 3. are warned with this call.
for impl_item in impl_items {
for impl_item_ref in impl_item_refs {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
if let hir::ImplItemKind::Type(ref ty) = impl_item.node {
self.visit_ty(ty);
}
@ -761,7 +771,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
// impl Public<Private> { ... }. Any public static
// methods will be visible as `Public::foo`.
let mut found_pub_static = false;
for impl_item in impl_items {
for impl_item_ref in impl_item_refs {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
match impl_item.node {
hir::ImplItemKind::Const(..) => {
if self.item_is_public(&impl_item.id, &impl_item.vis) {
@ -805,7 +816,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
intravisit::walk_item(self, item);
}
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() {
for bound in ty_param.bounds.iter() {
self.check_ty_param_bound(bound)
@ -826,13 +837,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
}
}
fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
if self.access_levels.is_reachable(item.id) {
intravisit::walk_foreign_item(self, item)
}
}
fn visit_ty(&mut self, t: &hir::Ty) {
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
if let hir::TyPath(..) = t.node {
if self.path_is_private_type(t.id) {
self.old_error_set.insert(t.id);
@ -841,7 +852,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
intravisit::walk_ty(self, t)
}
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) {
if self.access_levels.is_reachable(v.node.data.id()) {
self.in_variant = true;
intravisit::walk_variant(self, v, g, item_id);
@ -849,7 +863,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
}
}
fn visit_struct_field(&mut self, s: &hir::StructField) {
fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
if s.vis == hir::Public || self.in_variant {
intravisit::walk_struct_field(self, s);
}
@ -859,8 +873,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
// expression/block context can't possibly contain exported things.
// (Making them no-ops stops us from traversing the whole AST without
// having to be super careful about our `walk_...` calls above.)
fn visit_block(&mut self, _: &hir::Block) {}
fn visit_expr(&mut self, _: &hir::Expr) {}
fn visit_block(&mut self, _: &'tcx hir::Block) {}
fn visit_expr(&mut self, _: &'tcx hir::Expr) {}
}
///////////////////////////////////////////////////////////////////////////////
@ -1039,7 +1053,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
let min = |vis1: ty::Visibility, vis2| {
if vis1.is_at_least(vis2, &self.tcx.map) { vis2 } else { vis1 }
@ -1085,12 +1099,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
hir::ItemDefaultImpl(..) => {}
// An inherent impl is public when its type is public
// Subitems of inherent impls have their own publicity
hir::ItemImpl(.., ref generics, None, ref ty, ref impl_items) => {
hir::ItemImpl(.., ref generics, None, ref ty, ref impl_item_refs) => {
let ty_vis = self.ty_visibility(ty);
check.required_visibility = ty_vis;
check.visit_generics(generics);
for impl_item in impl_items {
for impl_item_ref in impl_item_refs {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
let impl_item_vis =
ty::Visibility::from_hir(&impl_item.vis, item.id, self.tcx);
check.required_visibility = min(impl_item_vis, ty_vis);
@ -1099,16 +1114,21 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
}
// A trait impl is public when both its type and its trait are public
// Subitems of trait impls have inherited publicity
hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_items) => {
hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_item_refs) => {
let vis = min(self.ty_visibility(ty), self.trait_ref_visibility(trait_ref));
check.required_visibility = vis;
check.visit_generics(generics);
for impl_item in impl_items {
for impl_item_ref in impl_item_refs {
let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
check.visit_impl_item(impl_item);
}
}
}
}
fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) {
// handled in `visit_item` above
}
}
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -1161,7 +1181,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx: tcx,
old_error_set: &visitor.old_error_set,
};
krate.visit_all_items(&mut visitor);
krate.visit_all_item_likes(&mut visitor);
}
visitor.access_levels

View File

@ -536,7 +536,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
let def_id = if decl_id.is_local() {
let ti = self.tcx.associated_item(decl_id);
self.tcx.associated_items(ti.container.id())
.find(|item| item.name == ti.name && item.has_value)
.find(|item| item.name == ti.name && item.defaultness.has_value())
.map(|item| item.def_id)
} else {
None

View File

@ -600,13 +600,8 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// reference. It also occurs when testing libcore and in some
// other weird situations. Annoying.
let fn_ptr_ty = match fn_ty.sty {
ty::TyFnDef(.., fty) => {
// Create a fn pointer with the substituted signature.
tcx.mk_fn_ptr(fty)
}
_ => bug!("expected fn item type, found {}", fn_ty)
};
// Create a fn pointer with the substituted signature.
let fn_ptr_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(common::ty_fn_ty(ccx, fn_ty).into_owned()));
let llptrty = type_of::type_of(ccx, fn_ptr_ty);
let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {

View File

@ -189,7 +189,7 @@
//! regardless of whether it is actually needed or not.
use rustc::hir;
use rustc::hir::intravisit as hir_visit;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
@ -306,10 +306,9 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
scx: scx,
mode: mode,
output: &mut roots,
enclosing_item: None,
};
scx.tcx().map.krate().visit_all_items(&mut visitor);
scx.tcx().map.krate().visit_all_item_likes(&mut visitor);
}
roots
@ -1030,14 +1029,10 @@ struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> {
scx: &'b SharedCrateContext<'a, 'tcx>,
mode: TransItemCollectionMode,
output: &'b mut Vec<TransItem<'tcx>>,
enclosing_item: Option<&'tcx hir::Item>,
}
impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
fn visit_item(&mut self, item: &'v hir::Item) {
let old_enclosing_item = self.enclosing_item;
self.enclosing_item = Some(item);
match item.node {
hir::ItemExternCrate(..) |
hir::ItemUse(..) |
@ -1094,9 +1089,6 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
}
}
}
hir_visit::walk_item(self, item);
self.enclosing_item = old_enclosing_item;
}
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
@ -1131,8 +1123,6 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
}
_ => { /* Nothing to do here */ }
}
hir_visit::walk_impl_item(self, ii)
}
}
@ -1145,7 +1135,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
_,
ref generics,
..,
ref items) => {
ref impl_item_refs) => {
if generics.is_type_parameterized() {
return
}
@ -1157,9 +1147,10 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
let callee_substs = tcx.erase_regions(&trait_ref.substs);
let overridden_methods: FxHashSet<_> = items.iter()
.map(|item| item.name)
.collect();
let overridden_methods: FxHashSet<_> =
impl_item_refs.iter()
.map(|iiref| iiref.name)
.collect();
for method in tcx.provided_trait_methods(trait_ref.def_id) {
if overridden_methods.contains(&method.name) {
continue;

View File

@ -35,7 +35,8 @@ pub fn report_symbol_names(scx: &SharedCrateContext) {
let _ignore = tcx.dep_graph.in_ignore();
let mut visitor = SymbolNamesTest { scx: scx };
tcx.map.krate().visit_all_items(&mut visitor);
// FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
tcx.map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
}
struct SymbolNamesTest<'a, 'tcx:'a> {

View File

@ -18,6 +18,7 @@ rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
syntax_pos = { path = "../libsyntax_pos" }
rustc_errors = { path = "../librustc_errors" }

View File

@ -439,7 +439,7 @@ impl Ord for TraitInfo {
/// Retrieve all traits in this crate and any dependent crates.
pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
if ccx.all_traits.borrow().is_none() {
use rustc::hir::intravisit;
use rustc::hir::itemlikevisit;
let mut traits = vec![];
@ -450,7 +450,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
map: &'a hir_map::Map<'tcx>,
traits: &'a mut AllTraitsVec,
}
impl<'v, 'a, 'tcx> intravisit::Visitor<'v> for Visitor<'a, 'tcx> {
impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
fn visit_item(&mut self, i: &'v hir::Item) {
match i.node {
hir::ItemTrait(..) => {
@ -460,8 +460,11 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
_ => {}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
ccx.tcx.map.krate().visit_all_items(&mut Visitor {
ccx.tcx.map.krate().visit_all_item_likes(&mut Visitor {
map: &ccx.tcx.map,
traits: &mut traits,
});

View File

@ -121,6 +121,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::{self, BytePos, Span};
use rustc::hir::intravisit::{self, Visitor};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::{self, PatKind};
use rustc::hir::print as pprust;
use rustc_back::slice;
@ -525,30 +526,35 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
fn visit_item(&mut self, i: &'tcx hir::Item) {
check_item_body(self.ccx, i);
}
fn visit_impl_item(&mut self, _item: &'tcx hir::ImplItem) {
// done as part of `visit_item` above
}
}
pub fn check_wf_new(ccx: &CrateCtxt) -> CompileResult {
ccx.tcx.sess.track_errors(|| {
let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx);
ccx.tcx.visit_all_items_in_krate(DepNode::WfCheck, &mut visit);
ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor());
})
}
pub fn check_item_types(ccx: &CrateCtxt) -> CompileResult {
ccx.tcx.sess.track_errors(|| {
let mut visit = CheckItemTypesVisitor { ccx: ccx };
ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemType, &mut visit);
ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
&mut visit.as_deep_visitor());
})
}
pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult {
ccx.tcx.sess.track_errors(|| {
let mut visit = CheckItemBodiesVisitor { ccx: ccx };
ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemBody, &mut visit);
ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemBody, &mut visit);
// Process deferred obligations, now that all functions
// bodies have been fully inferred.
@ -809,7 +815,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
it.id);
}
hir::ItemFn(..) => {} // entirely within check_item_body
hir::ItemImpl(.., ref impl_items) => {
hir::ItemImpl(.., ref impl_item_refs) => {
debug!("ItemImpl {} with id {}", it.name, it.id);
let impl_def_id = ccx.tcx.map.local_def_id(it.id);
if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) {
@ -817,7 +823,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
it.span,
impl_def_id,
impl_trait_ref,
impl_items);
impl_item_refs);
let trait_def_id = impl_trait_ref.def_id;
check_on_unimplemented(ccx, trait_def_id, it);
}
@ -879,10 +885,11 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
hir::ItemFn(ref decl, .., ref body) => {
check_bare_fn(ccx, &decl, &body, it.id, it.span);
}
hir::ItemImpl(.., ref impl_items) => {
hir::ItemImpl(.., ref impl_item_refs) => {
debug!("ItemImpl {} with id {}", it.name, it.id);
for impl_item in impl_items {
for impl_item_ref in impl_item_refs {
let impl_item = ccx.tcx.map.impl_item(impl_item_ref.id);
match impl_item.node {
hir::ImplItemKind::Const(_, ref expr) => {
check_const(ccx, &expr, impl_item.id)
@ -1019,7 +1026,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
impl_span: Span,
impl_id: DefId,
impl_trait_ref: ty::TraitRef<'tcx>,
impl_items: &[hir::ImplItem]) {
impl_item_refs: &[hir::ImplItemRef]) {
// If the trait reference itself is erroneous (so the compilation is going
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
// isn't populated for such impls.
@ -1030,9 +1037,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id);
let mut overridden_associated_type = None;
let impl_items = || impl_item_refs.iter().map(|iiref| ccx.tcx.map.impl_item(iiref.id));
// Check existing impl methods to see if they are both present in trait
// and compatible with trait signature
for impl_item in impl_items {
for impl_item in impl_items() {
let ty_impl_item = tcx.associated_item(tcx.map.local_def_id(impl_item.id));
let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id)
.find(|ac| ac.name == ty_impl_item.name);
@ -1101,7 +1110,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
}
hir::ImplItemKind::Type(_) => {
if ty_trait_item.kind == ty::AssociatedKind::Type {
if ty_trait_item.has_value {
if ty_trait_item.defaultness.has_value() {
overridden_associated_type = Some(impl_item);
}
} else {
@ -1135,7 +1144,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
.unwrap_or(false);
if !is_implemented {
if !trait_item.has_value {
if !trait_item.defaultness.has_value() {
missing_items.push(trait_item);
} else if associated_type_overridden {
invalidated_items.push(trait_item.name);

View File

@ -203,7 +203,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
free_id_outlive, self_ty);
}
ty::AssociatedKind::Type => {
if item.has_value {
if item.defaultness.has_value() {
let ty = fcx.tcx.item_type(item.def_id);
let ty = fcx.instantiate_type_scheme(span, free_substs, &ty);
fcx.register_wf_obligation(ty, span, code.clone());

View File

@ -16,7 +16,7 @@ use syntax::ast;
use syntax_pos::{Span, DUMMY_SP};
use rustc::hir;
use rustc::hir::intravisit::Visitor;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
struct UnusedTraitImportVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -40,7 +40,7 @@ impl<'a, 'tcx> UnusedTraitImportVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
if item.vis == hir::Public || item.span == DUMMY_SP {
return;
@ -58,10 +58,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let _task = tcx.dep_graph.in_task(DepNode::UnusedTraitCheck);
let mut visitor = UnusedTraitImportVisitor { tcx: tcx };
tcx.map.krate().visit_all_items(&mut visitor);
tcx.map.krate().visit_all_item_likes(&mut visitor);
}

View File

@ -34,7 +34,7 @@ use rustc::infer::{self, InferCtxt};
use syntax_pos::Span;
use rustc::dep_graph::DepNode;
use rustc::hir::map as hir_map;
use rustc::hir::intravisit;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::{Item, ItemImpl};
use rustc::hir;
@ -51,12 +51,15 @@ struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>,
}
impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
fn visit_item(&mut self, item: &Item) {
if let ItemImpl(..) = item.node {
self.cc.check_implementation(item)
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
@ -87,8 +90,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
// Check implementations and traits. This populates the tables
// containing the inherent methods and extension methods. It also
// builds up the trait inheritance table.
self.crate_context.tcx.visit_all_items_in_krate(DepNode::CoherenceCheckImpl,
&mut CoherenceCheckVisitor { cc: self });
self.crate_context.tcx.visit_all_item_likes_in_krate(
DepNode::CoherenceCheckImpl,
&mut CoherenceCheckVisitor { cc: self });
// Populate the table of destructors. It might seem a bit strange to
// do this here, but it's actually the most convenient place, since

View File

@ -17,12 +17,12 @@ use rustc::ty::{self, TyCtxt};
use syntax::ast;
use syntax_pos::Span;
use rustc::dep_graph::DepNode;
use rustc::hir::intravisit;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir;
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut orphan = OrphanChecker { tcx: tcx };
tcx.visit_all_items_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan);
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan);
}
struct OrphanChecker<'cx, 'tcx: 'cx> {
@ -380,8 +380,12 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
}
}
impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
self.check_item(item);
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View File

@ -18,7 +18,7 @@ use rustc::ty::{self, TyCtxt, TypeFoldable};
use syntax::ast;
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::intravisit;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use util::nodemap::DefIdMap;
use lint;
@ -30,7 +30,7 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
// this secondary walk specifically checks for some other cases,
// like defaulted traits, for which additional overlap rules exist
tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
}
struct OverlapChecker<'cx, 'tcx: 'cx> {
@ -97,7 +97,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
}
}
impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v hir::Item) {
match item.node {
hir::ItemEnum(..) |
@ -205,4 +205,7 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
_ => {}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View File

@ -12,12 +12,12 @@
//! crate or pertains to a type defined in this crate.
use rustc::ty::TyCtxt;
use rustc::hir::intravisit;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::{self, Unsafety};
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut orphan = UnsafetyChecker { tcx: tcx };
tcx.map.krate().visit_all_items(&mut orphan);
let mut unsafety = UnsafetyChecker { tcx: tcx };
tcx.map.krate().visit_all_item_likes(&mut unsafety);
}
struct UnsafetyChecker<'cx, 'tcx: 'cx> {
@ -94,7 +94,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
}
}
impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v hir::Item) {
match item.node {
hir::ItemDefaultImpl(unsafety, _) => {
@ -106,4 +106,7 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
_ => {}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View File

@ -77,13 +77,13 @@ use CrateCtxt;
use rustc_const_math::ConstInt;
use std::cell::RefCell;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax::{abi, ast, attr};
use syntax::parse::token::{self, keywords};
use syntax_pos::Span;
use rustc::hir::{self, intravisit, map as hir_map, print as pprust};
use rustc::hir::{self, map as hir_map, print as pprust};
use rustc::hir::intravisit::{self, Visitor};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
@ -92,7 +92,7 @@ use rustc::hir::def_id::DefId;
pub fn collect_item_types(ccx: &CrateCtxt) {
let mut visitor = CollectItemTypesVisitor { ccx: ccx };
ccx.tcx.visit_all_items_in_krate(DepNode::CollectItem, &mut visitor);
ccx.tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor());
}
///////////////////////////////////////////////////////////////////////////
@ -128,7 +128,7 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
ccx: &'a CrateCtxt<'a, 'tcx>
}
impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
convert_item(self.ccx, item);
intravisit::walk_item(self, item);
@ -148,6 +148,11 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx>
}
intravisit::walk_ty(self, ty);
}
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
convert_impl_item(self.ccx, impl_item);
intravisit::walk_impl_item(self, impl_item);
}
}
///////////////////////////////////////////////////////////////////////////
@ -726,7 +731,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
ref generics,
ref opt_trait_ref,
ref selfty,
ref impl_items) => {
_) => {
// Create generics from the generics specified in the impl head.
debug!("convert: ast_generics={:?}", generics);
let def_id = ccx.tcx.map.local_def_id(it.id);
@ -747,73 +752,16 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
});
tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref);
enforce_impl_params_are_constrained(ccx, generics, &mut ty_predicates, def_id);
// Subtle: before we store the predicates into the tcx, we
// sort them so that predicates like `T: Foo<Item=U>` come
// before uses of `U`. This avoids false ambiguity errors
// in trait checking. See `setup_constraining_predicates`
// for details.
ctp::setup_constraining_predicates(&mut ty_predicates.predicates,
trait_ref,
&mut ctp::parameters_for_impl(selfty, trait_ref));
tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
// Convert all the associated consts.
// Also, check if there are any duplicate associated items
let mut seen_type_items = FxHashMap();
let mut seen_value_items = FxHashMap();
for impl_item in impl_items {
let seen_items = match impl_item.node {
hir::ImplItemKind::Type(_) => &mut seen_type_items,
_ => &mut seen_value_items,
};
match seen_items.entry(impl_item.name) {
Occupied(entry) => {
let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201,
"duplicate definitions with name `{}`:",
impl_item.name);
err.span_label(*entry.get(),
&format!("previous definition of `{}` here",
impl_item.name));
err.span_label(impl_item.span, &format!("duplicate definition"));
err.emit();
}
Vacant(entry) => {
entry.insert(impl_item.span);
}
}
if let hir::ImplItemKind::Const(ref ty, _) = impl_item.node {
let const_def_id = ccx.tcx.map.local_def_id(impl_item.id);
generics_of_def_id(ccx, const_def_id);
let ty = ccx.icx(&ty_predicates)
.to_ty(&ExplicitRscope, &ty);
tcx.item_types.borrow_mut().insert(const_def_id, ty);
convert_associated_const(ccx, ImplContainer(def_id),
impl_item.id, ty);
}
}
// Convert all the associated types.
for impl_item in impl_items {
if let hir::ImplItemKind::Type(ref ty) = impl_item.node {
let type_def_id = ccx.tcx.map.local_def_id(impl_item.id);
generics_of_def_id(ccx, type_def_id);
if opt_trait_ref.is_none() {
span_err!(tcx.sess, impl_item.span, E0202,
"associated types are not allowed in inherent impls");
}
let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
convert_associated_type(ccx, ImplContainer(def_id), impl_item.id, Some(typ));
}
}
for impl_item in impl_items {
if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
convert_method(ccx, ImplContainer(def_id),
impl_item.id, sig, selfty,
&ty_predicates);
}
}
enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_items);
},
hir::ItemTrait(.., ref trait_items) => {
let trait_def = trait_def_of_item(ccx, it);
@ -899,6 +847,49 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
}
}
fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
let tcx = ccx.tcx;
// we can lookup details about the impl because items are visited
// before impl-items
let impl_def_id = tcx.map.get_parent_did(impl_item.id);
let impl_predicates = tcx.item_predicates(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let impl_self_ty = tcx.item_type(impl_def_id);
match impl_item.node {
hir::ImplItemKind::Const(ref ty, _) => {
let const_def_id = ccx.tcx.map.local_def_id(impl_item.id);
generics_of_def_id(ccx, const_def_id);
let ty = ccx.icx(&impl_predicates)
.to_ty(&ExplicitRscope, &ty);
tcx.item_types.borrow_mut().insert(const_def_id, ty);
convert_associated_const(ccx, ImplContainer(impl_def_id),
impl_item.id, ty);
}
hir::ImplItemKind::Type(ref ty) => {
let type_def_id = ccx.tcx.map.local_def_id(impl_item.id);
generics_of_def_id(ccx, type_def_id);
if impl_trait_ref.is_none() {
span_err!(tcx.sess, impl_item.span, E0202,
"associated types are not allowed in inherent impls");
}
let typ = ccx.icx(&impl_predicates).to_ty(&ExplicitRscope, ty);
convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
}
hir::ImplItemKind::Method(ref sig, _) => {
convert_method(ccx, ImplContainer(impl_def_id),
impl_item.id, sig, impl_self_ty,
&impl_predicates);
}
}
}
fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
ctor_id: ast::NodeId,
variant: ty::VariantDef<'tcx>,
@ -2067,110 +2058,3 @@ pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
|def, _| tcx.mk_region(def.to_early_bound_region()),
|def, _| tcx.mk_param_from_def(def))
}
/// Checks that all the type parameters on an impl
fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
generics: &hir::Generics,
impl_predicates: &mut ty::GenericPredicates<'tcx>,
impl_def_id: DefId)
{
let impl_ty = ccx.tcx.item_type(impl_def_id);
let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
// The trait reference is an input, so find all type parameters
// reachable from there, to start (if this is an inherent impl,
// then just examine the self type).
let mut input_parameters: FxHashSet<_> =
ctp::parameters_for(&impl_ty, false).into_iter().collect();
if let Some(ref trait_ref) = impl_trait_ref {
input_parameters.extend(ctp::parameters_for(trait_ref, false));
}
ctp::setup_constraining_predicates(&mut impl_predicates.predicates,
impl_trait_ref,
&mut input_parameters);
let ty_generics = generics_of_def_id(ccx, impl_def_id);
for (ty_param, param) in ty_generics.types.iter().zip(&generics.ty_params) {
let param_ty = ty::ParamTy::for_def(ty_param);
if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
report_unused_parameter(ccx, param.span, "type", &param_ty.to_string());
}
}
}
fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
ast_generics: &hir::Generics,
impl_def_id: DefId,
impl_items: &[hir::ImplItem])
{
// Every lifetime used in an associated type must be constrained.
let impl_ty = ccx.tcx.item_type(impl_def_id);
let impl_predicates = ccx.tcx.item_predicates(impl_def_id);
let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
let mut input_parameters: FxHashSet<_> =
ctp::parameters_for(&impl_ty, false).into_iter().collect();
if let Some(ref trait_ref) = impl_trait_ref {
input_parameters.extend(ctp::parameters_for(trait_ref, false));
}
ctp::identify_constrained_type_params(
&impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
let lifetimes_in_associated_types: FxHashSet<_> = impl_items.iter()
.map(|item| ccx.tcx.map.local_def_id(item.id))
.filter(|&def_id| {
let item = ccx.tcx.associated_item(def_id);
item.kind == ty::AssociatedKind::Type && item.has_value
})
.flat_map(|def_id| {
ctp::parameters_for(&ccx.tcx.item_type(def_id), true)
}).collect();
for (ty_lifetime, lifetime) in ccx.tcx.item_generics(impl_def_id).regions.iter()
.zip(&ast_generics.lifetimes)
{
let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data());
if
lifetimes_in_associated_types.contains(&param) && // (*)
!input_parameters.contains(&param)
{
report_unused_parameter(ccx, lifetime.lifetime.span,
"lifetime", &lifetime.lifetime.name.to_string());
}
}
// (*) This is a horrible concession to reality. I think it'd be
// better to just ban unconstrianed lifetimes outright, but in
// practice people do non-hygenic macros like:
//
// ```
// macro_rules! __impl_slice_eq1 {
// ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
// impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
// ....
// }
// }
// }
// ```
//
// In a concession to backwards compatbility, we continue to
// permit those, so long as the lifetimes aren't used in
// associated types. I believe this is sound, because lifetimes
// used elsewhere are not projected back out.
}
fn report_unused_parameter(ccx: &CrateCtxt,
span: Span,
kind: &str,
name: &str)
{
struct_span_err!(
ccx.tcx.sess, span, E0207,
"the {} parameter `{}` is not constrained by the \
impl trait, self type, or predicates",
kind, name)
.span_label(span, &format!("unconstrained {} parameter", kind))
.emit();
}

View File

@ -23,6 +23,18 @@ impl From<ty::EarlyBoundRegion> for Parameter {
fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) }
}
/// Return the set of parameters constrained by the impl header.
pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>,
impl_trait_ref: Option<ty::TraitRef<'tcx>>)
-> FxHashSet<Parameter>
{
let vec = match impl_trait_ref {
Some(tr) => parameters_for(&tr, false),
None => parameters_for(&impl_self_ty, false),
};
vec.into_iter().collect()
}
/// If `include_projections` is false, returns the list of parameters that are
/// constrained by `t` - i.e. the value of each parameter in the list is
/// uniquely determined by `t` (see RFC 447). If it is true, return the list

View File

@ -0,0 +1,203 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! This pass enforces various "well-formedness constraints" on impls.
//! Logically, it is part of wfcheck -- but we do it early so that we
//! can stop compilation afterwards, since part of the trait matching
//! infrastructure gets very grumpy if these conditions don't hold. In
//! particular, if there are type parameters that are not part of the
//! impl, then coherence will report strange inference ambiguity
//! errors; if impls have duplicate items, we get misleading
//! specialization errors. These things can (and probably should) be
//! fixed, but for the moment it's easier to do these checks early.
use constrained_type_params as ctp;
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax_pos::Span;
use CrateCtxt;
/// Checks that all the type/lifetime parameters on an impl also
/// appear in the trait ref or self-type (or are constrained by a
/// where-clause). These rules are needed to ensure that, given a
/// trait ref like `<T as Trait<U>>`, we can derive the values of all
/// parameters on the impl (which is needed to make specialization
/// possible).
///
/// However, in the case of lifetimes, we only enforce these rules if
/// the lifetime parameter is used in an associated type. This is a
/// concession to backwards compatibility; see comment at the end of
/// the fn for details.
///
/// Example:
///
/// ```
/// impl<T> Trait<Foo> for Bar { ... }
/// ^ T does not appear in `Foo` or `Bar`, error!
///
/// impl<T> Trait<Foo<T>> for Bar { ... }
/// ^ T appears in `Foo<T>`, ok.
///
/// impl<T> Trait<Foo> for Bar where Bar: Iterator<Item=T> { ... }
/// ^ T is bound to `<Bar as Iterator>::Item`, ok.
///
/// impl<'a> Trait<Foo> for Bar { }
/// ^ 'a is unused, but for back-compat we allow it
///
/// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
/// ^ 'a is unused and appears in assoc type, error
/// ```
pub fn impl_wf_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>) {
// We will tag this as part of the WF check -- logically, it is,
// but it's one that we must perform earlier than the rest of
// WfCheck.
ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { ccx: ccx });
}
struct ImplWfCheck<'a, 'tcx: 'a> {
ccx: &'a CrateCtxt<'a, 'tcx>,
}
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node {
hir::ItemImpl(.., ref generics, _, _, ref impl_item_refs) => {
let impl_def_id = self.ccx.tcx.map.local_def_id(item.id);
enforce_impl_params_are_constrained(self.ccx,
generics,
impl_def_id,
impl_item_refs);
enforce_impl_items_are_distinct(self.ccx, impl_item_refs);
}
_ => { }
}
}
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
}
fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
impl_hir_generics: &hir::Generics,
impl_def_id: DefId,
impl_item_refs: &[hir::ImplItemRef])
{
// Every lifetime used in an associated type must be constrained.
let impl_self_ty = ccx.tcx.item_type(impl_def_id);
let impl_generics = ccx.tcx.item_generics(impl_def_id);
let impl_predicates = ccx.tcx.item_predicates(impl_def_id);
let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref);
ctp::identify_constrained_type_params(
&impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
// Disallow ANY unconstrained type parameters.
for (ty_param, param) in impl_generics.types.iter().zip(&impl_hir_generics.ty_params) {
let param_ty = ty::ParamTy::for_def(ty_param);
if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
report_unused_parameter(ccx, param.span, "type", &param_ty.to_string());
}
}
// Disallow unconstrained lifetimes, but only if they appear in assoc types.
let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter()
.map(|item_ref| ccx.tcx.map.local_def_id(item_ref.id.node_id))
.filter(|&def_id| {
let item = ccx.tcx.associated_item(def_id);
item.kind == ty::AssociatedKind::Type && item.defaultness.has_value()
})
.flat_map(|def_id| {
ctp::parameters_for(&ccx.tcx.item_type(def_id), true)
}).collect();
for (ty_lifetime, lifetime) in impl_generics.regions.iter()
.zip(&impl_hir_generics.lifetimes)
{
let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data());
if
lifetimes_in_associated_types.contains(&param) && // (*)
!input_parameters.contains(&param)
{
report_unused_parameter(ccx, lifetime.lifetime.span,
"lifetime", &lifetime.lifetime.name.to_string());
}
}
// (*) This is a horrible concession to reality. I think it'd be
// better to just ban unconstrianed lifetimes outright, but in
// practice people do non-hygenic macros like:
//
// ```
// macro_rules! __impl_slice_eq1 {
// ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
// impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
// ....
// }
// }
// }
// ```
//
// In a concession to backwards compatbility, we continue to
// permit those, so long as the lifetimes aren't used in
// associated types. I believe this is sound, because lifetimes
// used elsewhere are not projected back out.
}
fn report_unused_parameter(ccx: &CrateCtxt,
span: Span,
kind: &str,
name: &str)
{
struct_span_err!(
ccx.tcx.sess, span, E0207,
"the {} parameter `{}` is not constrained by the \
impl trait, self type, or predicates",
kind, name)
.span_label(span, &format!("unconstrained {} parameter", kind))
.emit();
}
/// Enforce that we do not have two items in an impl with the same name.
fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
impl_item_refs: &[hir::ImplItemRef])
{
let tcx = ccx.tcx;
let mut seen_type_items = FxHashMap();
let mut seen_value_items = FxHashMap();
for impl_item_ref in impl_item_refs {
let impl_item = tcx.map.impl_item(impl_item_ref.id);
let seen_items = match impl_item.node {
hir::ImplItemKind::Type(_) => &mut seen_type_items,
_ => &mut seen_value_items,
};
match seen_items.entry(impl_item.name) {
Occupied(entry) => {
let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201,
"duplicate definitions with name `{}`:",
impl_item.name);
err.span_label(*entry.get(),
&format!("previous definition of `{}` here",
impl_item.name));
err.span_label(impl_item.span, &format!("duplicate definition"));
err.emit();
}
Vacant(entry) => {
entry.insert(impl_item.span);
}
}
}
}

View File

@ -95,6 +95,7 @@ extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_back;
extern crate rustc_const_math;
extern crate rustc_const_eval;
extern crate rustc_data_structures;
extern crate rustc_errors as errors;
pub use rustc::dep_graph;
@ -130,6 +131,7 @@ mod rscope;
mod astconv;
pub mod collect;
mod constrained_type_params;
mod impl_wf_check;
pub mod coherence;
pub mod variance;
@ -333,6 +335,11 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
time(time_passes, "variance inference", ||
variance::infer_variance(tcx));
tcx.sess.track_errors(|| {
time(time_passes, "impl wf inference", ||
impl_wf_check::impl_wf_check(&ccx));
})?;
tcx.sess.track_errors(|| {
time(time_passes, "coherence checking", ||
coherence::check_coherence(&ccx));

View File

@ -22,7 +22,7 @@ use rustc::ty::maps::ItemVariances;
use rustc::hir::map as hir_map;
use syntax::ast;
use rustc::hir;
use rustc::hir::intravisit::Visitor;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use super::terms::*;
use super::terms::VarianceTerm::*;
@ -65,13 +65,13 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
};
// See README.md for a discussion on dep-graph management.
tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
&mut constraint_cx);
tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
&mut constraint_cx);
constraint_cx
}
impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
let tcx = self.terms_cx.tcx;
let did = tcx.map.local_def_id(item.id);
@ -115,6 +115,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
hir::ItemDefaultImpl(..) => {}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
/// Is `param_id` a lifetime according to `map`?

View File

@ -27,7 +27,7 @@ use std::fmt;
use std::rc::Rc;
use syntax::ast;
use rustc::hir;
use rustc::hir::intravisit::Visitor;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use util::nodemap::NodeMap;
use self::VarianceTerm::*;
@ -109,7 +109,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
};
// See README.md for a discussion on dep-graph management.
tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx);
tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx);
terms_cx
}
@ -227,7 +227,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
debug!("add_inferreds for item {}",
self.tcx.map.node_to_string(item.id));
@ -257,4 +257,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
hir::ItemTy(..) => {}
}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}

View File

@ -364,7 +364,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
let trait_items = tcx.associated_items(did).filter_map(|item| {
match item.kind {
ty::AssociatedKind::Const => {
let default = if item.has_value {
let default = if item.defaultness.has_value() {
Some(pprust::expr_to_string(
lookup_const_by_id(tcx, item.def_id, None).unwrap().0))
} else {
@ -407,7 +407,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
abi: abi
})
}
_ => panic!("not a tymethod"),
ref r => panic!("not a tymethod: {:?}", r),
};
Some(cleaned)
}

View File

@ -1373,9 +1373,10 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
}
}
}
let provided = match self.container {
ty::ImplContainer(_) => false,
ty::TraitContainer(_) => self.has_value
ty::TraitContainer(_) => self.defaultness.has_value()
};
if provided {
MethodItem(Method {
@ -1440,7 +1441,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
None => bounds.push(TyParamBound::maybe_sized(cx)),
}
let ty = if self.has_value {
let ty = if self.defaultness.has_value() {
Some(cx.tcx().item_type(self.def_id))
} else {
None

View File

@ -502,17 +502,20 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
om.traits.push(t);
},
hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref items) => {
hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref item_ids) => {
// Don't duplicate impls when inlining, we'll pick them up
// regardless of where they're located.
if !self.inlining {
let items = item_ids.iter()
.map(|ii| self.cx.map.impl_item(ii.id).clone())
.collect();
let i = Impl {
unsafety: unsafety,
polarity: polarity,
generics: gen.clone(),
trait_: tr.clone(),
for_: ty.clone(),
items: items.clone(),
items: items,
attrs: item.attrs.clone(),
id: item.id,
whence: item.span,

View File

@ -42,8 +42,9 @@ trait Trait {
struct SomeType;
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
impl SomeType {
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
fn method(&self, _: TypeAlias) {}
}

View File

@ -15,7 +15,6 @@ fn foo<T>() {
impl<T> Drop for foo<T> {
//~^ ERROR wrong number of type arguments
//~^^ ERROR the type parameter `T` is not constrained
fn drop(&mut self) {}
}
}

View File

@ -20,9 +20,8 @@
#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")]
// FIXME(#37121) -- the following two modules *should* be reused but are not
#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")]
#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")]
@ -60,8 +59,7 @@ mod point {
mod fn_calls_methods_in_same_impl {
use point::Point;
// FIXME(#37121) -- we should not need to typeck this again
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
@ -72,8 +70,7 @@ mod fn_calls_methods_in_same_impl {
mod fn_calls_methods_in_another_impl {
use point::Point;
// FIXME(#37121) -- we should not need to typeck this again
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn check() {
let mut x = Point { x: 2.0, y: 2.0 };
x.translate(3.0, 3.0);

View File

@ -19,12 +19,13 @@
#![feature(stmt_expr_attributes)]
#![allow(dead_code)]
// FIXME(#37333) -- the following modules *should* be reused but are not
#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")]
#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")]
#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
// FIXME(#37720) these two should be reused, but data gets entangled across crates
#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")]
#![rustc_partition_translated(module="struct_point-fn_read_field", cfg="rpass2")]
#![rustc_partition_translated(module="struct_point-fn_write_field", cfg="rpass2")]
extern crate point;
@ -32,7 +33,7 @@ extern crate point;
mod fn_calls_methods_in_same_impl {
use point::Point;
// FIXME(#37333) -- we should not need to typeck this again
// FIXME(#37720) data gets entangled across crates
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
@ -44,9 +45,9 @@ mod fn_calls_methods_in_same_impl {
mod fn_calls_methods_in_another_impl {
use point::Point;
// FIXME(#37333) -- we should not need to typeck this again
// FIXME(#37720) data gets entangled across crates
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
pub fn check() {
pub fn dirty() {
let mut x = Point { x: 2.0, y: 2.0 };
x.translate(3.0, 3.0);
}
@ -56,8 +57,7 @@ mod fn_calls_methods_in_another_impl {
mod fn_make_struct {
use point::Point;
// FIXME(#37333) -- we should not need to typeck this again
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
@ -67,8 +67,7 @@ mod fn_make_struct {
mod fn_read_field {
use point::Point;
// FIXME(#37333) -- we should not need to typeck this again
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
@ -78,8 +77,7 @@ mod fn_read_field {
mod fn_write_field {
use point::Point;
// FIXME(#37333) -- we should not need to typeck this again
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}

View File

@ -0,0 +1,128 @@
// Copyright 2016 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.
// This test case tests the incremental compilation hash (ICH) implementation
// for let expressions.
// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.
// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph
#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]
struct Foo;
// Change Method Name -----------------------------------------------------------
#[cfg(cfail1)]
impl Foo {
pub fn method_name() { }
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn method_name2() { }
}
// Change Method Body -----------------------------------------------------------
//
// This should affect the method itself, but not the impl.
#[cfg(cfail1)]
impl Foo {
pub fn method_body() { }
}
#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn method_body() {
println!("Hello, world!");
}
}
// Change Method Privacy -----------------------------------------------------------
#[cfg(cfail1)]
impl Foo {
pub fn method_privacy() { }
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn method_privacy() { }
}
// Change Method Selfness -----------------------------------------------------------
#[cfg(cfail1)]
impl Foo {
pub fn method_selfness() { }
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn method_selfness(&self) { }
}
// Change Method Selfmutness -----------------------------------------------------------
#[cfg(cfail1)]
impl Foo {
pub fn method_selfmutness(&self) { }
}
#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn method_selfmutness(&mut self) { }
}

View File

@ -0,0 +1,404 @@
// Copyright 2016 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.
// This test case tests the incremental compilation hash (ICH) implementation
// for let expressions.
// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.
// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph
#![allow(warnings)]
#![feature(rustc_attrs)]
#![feature(specialization)]
#![crate_type="rlib"]
struct Foo;
// Change Method Name -----------------------------------------------------------
#[cfg(cfail1)]
pub trait ChangeMethodNameTrait {
fn method_name();
}
#[cfg(cfail1)]
impl ChangeMethodNameTrait for Foo {
fn method_name() { }
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub trait ChangeMethodNameTrait {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn method_name2();
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl ChangeMethodNameTrait for Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn method_name2() { }
}
// Change Method Body -----------------------------------------------------------
//
// This should affect the method itself, but not the trait.
pub trait ChangeMethodBodyTrait {
fn method_name();
}
#[cfg(cfail1)]
impl ChangeMethodBodyTrait for Foo {
fn method_name() { }
}
#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl ChangeMethodBodyTrait for Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn method_name() {
()
}
}
// Change Method Selfness -----------------------------------------------------------
#[cfg(cfail1)]
pub trait ChangeMethodSelfnessTrait {
fn method_name();
}
#[cfg(cfail1)]
impl ChangeMethodSelfnessTrait for Foo {
fn method_name() { }
}
#[cfg(not(cfail1))]
pub trait ChangeMethodSelfnessTrait {
fn method_name(&self);
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl ChangeMethodSelfnessTrait for Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn method_name(&self) {
()
}
}
// Change Method Selfness -----------------------------------------------------------
#[cfg(cfail1)]
pub trait RemoveMethodSelfnessTrait {
fn method_name(&self);
}
#[cfg(cfail1)]
impl RemoveMethodSelfnessTrait for Foo {
fn method_name(&self) { }
}
#[cfg(not(cfail1))]
pub trait RemoveMethodSelfnessTrait {
fn method_name();
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl RemoveMethodSelfnessTrait for Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn method_name() {
()
}
}
// Change Method Selfmutness -----------------------------------------------------------
#[cfg(cfail1)]
pub trait ChangeMethodSelfmutnessTrait {
fn method_name(&self);
}
#[cfg(cfail1)]
impl ChangeMethodSelfmutnessTrait for Foo {
fn method_name(&self) { }
}
#[cfg(not(cfail1))]
pub trait ChangeMethodSelfmutnessTrait {
fn method_name(&mut self);
}
#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl ChangeMethodSelfmutnessTrait for Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn method_name(&mut self) {
()
}
}
// Change item kind -----------------------------------------------------------
#[cfg(cfail1)]
pub trait ChangeItemKindTrait {
fn name();
}
#[cfg(cfail1)]
impl ChangeItemKindTrait for Foo {
fn name() { }
}
#[cfg(not(cfail1))]
pub trait ChangeItemKindTrait {
type name;
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl ChangeItemKindTrait for Foo {
type name = ();
}
// Remove item -----------------------------------------------------------
#[cfg(cfail1)]
pub trait RemoveItemTrait {
type TypeName;
fn method_name();
}
#[cfg(cfail1)]
impl RemoveItemTrait for Foo {
type TypeName = ();
fn method_name() { }
}
#[cfg(not(cfail1))]
pub trait RemoveItemTrait {
type TypeName;
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl RemoveItemTrait for Foo {
type TypeName = ();
}
// Add item -----------------------------------------------------------
#[cfg(cfail1)]
pub trait AddItemTrait {
type TypeName;
}
#[cfg(cfail1)]
impl AddItemTrait for Foo {
type TypeName = ();
}
#[cfg(not(cfail1))]
pub trait AddItemTrait {
type TypeName;
fn method_name();
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl AddItemTrait for Foo {
type TypeName = ();
fn method_name() { }
}
// Change has-value -----------------------------------------------------------
#[cfg(cfail1)]
pub trait ChangeHasValueTrait {
fn method_name();
}
#[cfg(cfail1)]
impl ChangeHasValueTrait for Foo {
fn method_name() { }
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub trait ChangeHasValueTrait {
fn method_name() { }
}
#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl ChangeHasValueTrait for Foo {
fn method_name() { }
}
// Add default
pub trait AddDefaultTrait {
fn method_name();
}
#[cfg(cfail1)]
impl AddDefaultTrait for Foo {
fn method_name() { }
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl AddDefaultTrait for Foo {
default fn method_name() { }
}
// Remove default
pub trait RemoveDefaultTrait {
fn method_name();
}
#[cfg(cfail1)]
impl RemoveDefaultTrait for Foo {
default fn method_name() { }
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl RemoveDefaultTrait for Foo {
fn method_name() { }
}
// Add arguments
#[cfg(cfail1)]
pub trait AddArgumentTrait {
fn method_name(&self);
}
#[cfg(cfail1)]
impl AddArgumentTrait for Foo {
fn method_name(&self) { }
}
#[cfg(not(cfail1))]
pub trait AddArgumentTrait {
fn method_name(&self, x: u32);
}
#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl AddArgumentTrait for Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn method_name(&self, _x: u32) { }
}
// Change argument type
#[cfg(cfail1)]
pub trait ChangeArgumentTypeTrait {
fn method_name(&self, x: u32);
}
#[cfg(cfail1)]
impl ChangeArgumentTypeTrait for Foo {
fn method_name(&self, _x: u32) { }
}
#[cfg(not(cfail1))]
pub trait ChangeArgumentTypeTrait {
fn method_name(&self, x: char);
}
#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
impl ChangeArgumentTypeTrait for Foo {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn method_name(&self, _x: char) { }
}