diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 9c00e95c17e05..e365cea6d0e5e 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -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; diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index d085c24036cef..600732fc6f70b 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -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, 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, 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, V: Visitor<'tcx> + impl<'visit, 'tcx, F, V> ItemLikeVisitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V> + where F: FnMut(DefId) -> DepNode, 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) } diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 044e36e5c9cd4..feefc43f4013e 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -106,7 +106,7 @@ pub type DefMap = NodeMap; // within. pub type ExportMap = NodeMap>; -#[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. diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 9932e5fe68623..4cfa889ec5616 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -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). + /// 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 + } + + /// 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); + } } - /// Visit the top-level item and (optionally) nested items. See + /// 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) { @@ -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, diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs new file mode 100644 index 0000000000000..1e373441e9e85 --- /dev/null +++ b/src/librustc/hir/itemlikevisit.rs @@ -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 or the MIT license +// , 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); + } +} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b985298e47cc2..05c4ae521803a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -105,6 +105,7 @@ impl<'a> LoweringContext<'a> { fn lower_crate(&mut self, c: &Crate) -> hir::Crate { struct ItemLowerer<'lcx, 'interner: 'lcx> { items: BTreeMap, + impl_items: BTreeMap, 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 + } } } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 04fcf7e84508e..51a378a08336e 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -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); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 39114ec4238e7..06cfc8aee8c9d 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -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. diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6b5b8101a146c..9f5ff6914b0cc 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -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, + + pub impl_items: BTreeMap, } 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>), } +// 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, // (optional) trait this impl implements P, // self - HirVec), + HirVec), } 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, diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 2c4ffb853c1f3..807bbec3b5888 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -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 { diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 50c581057407a..a490b58964a71 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -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); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 94667b398b080..991398813752f 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -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 +struct LifeSeeder<'k> { + worklist: Vec, + 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)) => { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 5634e2012c971..25fe407271bc0 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -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()); } diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index 11bde922f47f2..9dd54457a3499 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -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); } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 0f9748a16f46c..cf08b59312d50 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -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> { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 3e7de79246b66..9b4b1396669a3 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -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) { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index f472205b732d4..d381188d56b54 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -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(); } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 7868e700f2701..ac614494355a2 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -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, } -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. diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 34a6a547d9440..5f9a6b283c6a0 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -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; } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 292d9592ceb0c..f682dfbf1be95 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -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(&mut self, f: F) where + F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), + { + f(self) + } + fn with(&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(&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)` }); }); } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index d79833998d6c8..7e4efc7ddca06 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -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(&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 { diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 2c08e17f8f1a5..12d32bf31b13d 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -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); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index f1b69feb545ef..ca7d2ac3c69ab 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -943,7 +943,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() }; @@ -1007,8 +1007,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); } @@ -1303,7 +1304,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 diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1de54f49a5522..f5c23401a4e67 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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 { 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> { 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(self, - dep_node_fn: F, - visitor: &mut V) - where F: FnMut(DefId) -> DepNode, V: Visitor<'gcx> + pub fn visit_all_item_likes_in_krate(self, + dep_node_fn: F, + visitor: &mut V) + where F: FnMut(DefId) -> DepNode, 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` diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 2376560879222..5e54e333bb90c 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -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 ---"); diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e0e8a21591921..f63a27e0d7563 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -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(); } diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs index ea7621e16e7b7..4db620b2bec3b 100644 --- a/src/librustc_driver/derive_registrar.rs +++ b/src/librustc_driver/derive_registrar.rs @@ -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 { 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, } -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) { + } } + diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 37477da755c9f..998cbae2cce15 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -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>, diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 58a2152997410..c08519090d273 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -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); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 0b0dd596784e9..fa2eff817eaa8 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -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); diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 69b9be12de46c..0cd1c88fb877b 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -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, } -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> { diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 223200957cb7c..2572a9c1d78f6 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -201,6 +201,19 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { 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 { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f6b6c89b7cc21..51ffb1ebc8e99 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -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); } } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ba85544326f8f..6dbcfc8523dc7 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -834,7 +834,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 @@ -848,7 +847,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 @@ -861,7 +859,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 diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 778a9d185e145..d1508d7e9b398 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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); } @@ -1164,7 +1170,7 @@ struct ImplVisitor<'a, 'tcx: 'a> { impls: FxHashMap>, } -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); @@ -1176,6 +1182,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> { @@ -1185,7 +1195,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() diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index d7a5f7ad71544..7553b2e05a73e 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -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, } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 4a50585efe3bd..992c0e9b5fc85 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -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 diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b33a7060e3753..4ff2beb3fdb77 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -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 + }); } } }); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 02a0b3ab28d62..5df8accd8cef1 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -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(); } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 417987d9664e0..3bdaf276b40ce 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -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) diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index e58cd89381933..724100e02237f 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -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, _) => { diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index d55ce4c356384..7386be2528c9b 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -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, diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index 0e0f8a8456731..5f76f865c4aca 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -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()); }) } diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs index ff3038c3d1175..75046f6aeb874 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -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, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index dc7399e228908..b116408269e4d 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -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 { ... }. 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 diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4fb11509a1c13..778f018414165 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -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 diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index faf65f3f98b09..df56e27128c7e 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -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) { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 0fc6436e63cd8..5902b0b1ce075 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -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>, - 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; diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 25c30151ad45d..aa23a18172276 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -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> { diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 720423371a83a..f08d26373e50e 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -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" } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 0cb8cf2a58886..6093e45e5a21e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -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, }); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a95b3f4a973bb..d2939316219e6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 066b3d4be0881..2c55e8fbfd228 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -204,7 +204,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()); diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 7e41a672bf325..b4a10c52270e2 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -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); } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 5863305826462..31bd7b0f19b3c 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -34,7 +34,7 @@ use rustc::infer::{self, InferCtxt, TypeOrigin}; 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 diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 371c182030e24..a507077bef77e 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -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) { + } } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index b5aba512a66bd..c66a76ebba022 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -18,7 +18,7 @@ use rustc::ty::{self, TyCtxt}; 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(..) | @@ -199,4 +199,7 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { _ => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index cca6c88430672..6d5de8f250655 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -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) { + } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 816243b3eab47..535b6bcdcba17 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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); - 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); - } - } + // Subtle: before we store the predicates into the tcx, we + // sort them so that predicates like `T: Foo` 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)); - enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_items); + tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone()); }, 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", ¶m_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(¶m) && // (*) - !input_parameters.contains(¶m) - { - 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 { - // .... - // } - // } - // } - // ``` - // - // 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(); -} diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 7918537a6c08f..22be4491273ef 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -23,6 +23,18 @@ impl From 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>) + -> FxHashSet +{ + 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 diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs new file mode 100644 index 0000000000000..9f5b73d9b3075 --- /dev/null +++ b/src/librustc_typeck/impl_wf_check.rs @@ -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 or the MIT license +// , 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 `>`, 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 Trait for Bar { ... } +/// ^ T does not appear in `Foo` or `Bar`, error! +/// +/// impl Trait> for Bar { ... } +/// ^ T appears in `Foo`, ok. +/// +/// impl Trait for Bar where Bar: Iterator { ... } +/// ^ T is bound to `::Item`, ok. +/// +/// impl<'a> Trait for Bar { } +/// ^ 'a is unused, but for back-compat we allow it +/// +/// impl<'a> Trait 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", ¶m_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(¶m) && // (*) + !input_parameters.contains(¶m) + { + 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 { + // .... + // } + // } + // } + // ``` + // + // 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); + } + } + } +} diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 2c12959dbdde2..f2e8bb2e96145 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -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)); diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 10fca644ec16e..8a0c1c68322d0 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -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`? diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index f6732f36e355a..0a3238480d908 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -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) { + } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e8367bca2ef21..185f897c1baa1 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -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) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4d70c64634fb0..a141d0e4788dd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1373,9 +1373,10 @@ impl<'tcx> Clean 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 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 diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d9155e10e17b6..939fd6ccfc88e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -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, diff --git a/src/test/compile-fail/dep-graph-type-alias.rs b/src/test/compile-fail/dep-graph-type-alias.rs index 80cc9e71c7ab4..2e33f11c04b45 100644 --- a/src/test/compile-fail/dep-graph-type-alias.rs +++ b/src/test/compile-fail/dep-graph-type-alias.rs @@ -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) {} } diff --git a/src/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs index d3b932fbc53ef..010cfb54c1ae9 100644 --- a/src/test/compile-fail/issue-3214.rs +++ b/src/test/compile-fail/issue-3214.rs @@ -15,7 +15,6 @@ fn foo() { impl Drop for foo { //~^ ERROR wrong number of type arguments - //~^^ ERROR the type parameter `T` is not constrained fn drop(&mut self) {} } } diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs index 8fa34bde17053..46e5a88eef940 100644 --- a/src/test/incremental/change_private_impl_method/struct_point.rs +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -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); diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs index d8e5fbadad8bf..bb7f7025c5905 100644 --- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs +++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs @@ -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; } diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs new file mode 100644 index 0000000000000..f7a390e874509 --- /dev/null +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -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 or the MIT license +// , 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) { } +} + diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs new file mode 100644 index 0000000000000..500aaf52324b0 --- /dev/null +++ b/src/test/incremental/hashes/trait_impls.rs @@ -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 or the MIT license +// , 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) { } +} +