From 36fbf8c53cd37498e5eaadf02740e2aac87f6118 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 2 Nov 2016 18:22:59 -0400 Subject: [PATCH 01/18] refactor Visitor into ItemLikeVisitor and intravisit::Visitor There are now three patterns (shallow, deep, and nested visit). These are described in detail on the docs in `itemlikevisit::ItemLikeVisitor`. --- src/librustc/dep_graph/mod.rs | 2 +- src/librustc/dep_graph/visit.rs | 17 ++-- src/librustc/hir/intravisit.rs | 28 +++++-- src/librustc/hir/itemlikevisit.rs | 79 +++++++++++++++++++ src/librustc/hir/mod.rs | 5 +- src/librustc/middle/dead.rs | 5 +- src/librustc/middle/effect.rs | 2 +- src/librustc/middle/entry.rs | 6 +- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/middle/lang_items.rs | 6 +- src/librustc/middle/liveness.rs | 2 +- src/librustc/middle/reachable.rs | 5 +- src/librustc/middle/region.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 17 +++- src/librustc/middle/weak_lang_items.rs | 2 +- src/librustc/ty/mod.rs | 12 +-- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_const_eval/check_match.rs | 3 +- src/librustc_driver/derive_registrar.rs | 6 +- src/librustc_incremental/assert_dep_graph.rs | 6 +- src/librustc_incremental/calculate_svh/mod.rs | 6 +- .../persist/dirty_clean.rs | 10 +-- src/librustc_metadata/encoder.rs | 7 +- src/librustc_mir/mir_map.rs | 4 +- src/librustc_passes/consts.rs | 14 ++-- src/librustc_passes/loops.rs | 4 +- src/librustc_passes/rvalues.rs | 6 +- src/librustc_passes/static_recursion.rs | 3 +- src/librustc_plugin/build.rs | 6 +- src/librustc_privacy/lib.rs | 5 +- src/librustc_trans/collector.rs | 16 ++-- src/librustc_trans/symbol_names_test.rs | 3 +- src/librustc_typeck/check/method/suggest.rs | 6 +- src/librustc_typeck/check/mod.rs | 10 ++- src/librustc_typeck/check_unused.rs | 6 +- src/librustc_typeck/coherence/mod.rs | 9 ++- src/librustc_typeck/coherence/orphan.rs | 6 +- src/librustc_typeck/coherence/overlap.rs | 6 +- src/librustc_typeck/coherence/unsafety.rs | 8 +- src/librustc_typeck/collect.rs | 7 +- src/librustc_typeck/variance/constraints.rs | 8 +- src/librustc_typeck/variance/terms.rs | 6 +- 42 files changed, 239 insertions(+), 126 deletions(-) create mode 100644 src/librustc/hir/itemlikevisit.rs diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 9c00e95c17e..e365cea6d0e 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 d085c24036c..30de5e5288a 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); @@ -54,5 +53,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/intravisit.rs b/src/librustc/hir/intravisit.rs index 9932e5fe686..2fc27e0cea0 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,7 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax::codemap::Spanned; use syntax_pos::Span; use hir::*; +use super::itemlikevisit::DeepVisitor; use std::cmp; use std::u32; @@ -78,10 +87,9 @@ pub trait Visitor<'v> : Sized { /// 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). + /// fetch the item contents. But most of the time, it is easier to + /// use either the "shallow" or "deep" visit patterns described on + /// `itemlikevisit::ItemLikeVisitor`. #[allow(unused_variables)] fn visit_nested_item(&mut self, id: ItemId) { } @@ -92,6 +100,16 @@ pub trait Visitor<'v> : Sized { 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) { diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs new file mode 100644 index 00000000000..6da47015d7d --- /dev/null +++ b/src/librustc/hir/itemlikevisit.rs @@ -0,0 +1,79 @@ +// 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; +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); +} + +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); + } +} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6b5b8101a14..4716a09ad35 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; @@ -438,8 +439,8 @@ 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); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 94667b398b0..2667943bea9 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}; @@ -333,7 +334,7 @@ struct LifeSeeder { worklist: Vec } -impl<'v> Visitor<'v> for LifeSeeder { +impl<'v> ItemLikeVisitor<'v> for LifeSeeder { 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 { @@ -388,7 +389,7 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut life_seeder = LifeSeeder { worklist: worklist }; - krate.visit_all_items(&mut life_seeder); + krate.visit_all_item_likes(&mut life_seeder); return life_seeder.worklist; } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 5634e2012c9..25fe407271b 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 11bde922f47..e5112749c0e 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -18,7 +18,7 @@ use syntax::attr; use syntax::entry::EntryPointType; use syntax_pos::Span; use hir::{Item, ItemFn}; -use hir::intravisit::Visitor; +use hir::itemlikevisit::ItemLikeVisitor; struct EntryContext<'a, 'tcx: 'a> { session: &'a Session, @@ -39,7 +39,7 @@ 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); @@ -74,7 +74,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 0f9748a16f4..cf08b59312d 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 3e7de79246b..6fe8442474a 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(); @@ -219,7 +219,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 f472205b732..d381188d56b 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 7868e700f27..848f4218d88 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,7 +325,7 @@ 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 { @@ -364,7 +365,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 34a6a547d94..5f9a6b283c6 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 292d9592ceb..c342342d73b 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,23 @@ 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> { + // Override the nested functions -- lifetimes follow lexical scope, + // so it's convenient to walk the tree in lexical order. + + fn visit_nested_item(&mut self, id: hir::ItemId) { + let item = self.hir_map.expect_item(id.id); + self.visit_item(item) + } + fn visit_item(&mut self, item: &hir::Item) { - assert!(self.labels_in_fn.is_empty()); + // 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,7 +184,7 @@ 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) { diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 2c08e17f8f1..12d32bf31b1 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/ty/mod.rs b/src/librustc/ty/mod.rs index 1de54f49a55..c6fff94438f 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}; @@ -2695,12 +2695,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 23765608792..5e54e333bb9 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 e0e8a215919..f63a27e0d75 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 ea7621e16e7..605193a0434 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,7 +28,7 @@ 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); diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 37477da755c..84489c2e8c6 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,7 +167,7 @@ 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); } diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 58a21529974..5697441b667 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,7 +201,7 @@ 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); diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 69b9be12de4..f6b7abd2ef1 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() { @@ -195,7 +195,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 +209,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); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 778a9d185e1..bbffe88316b 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; @@ -1074,7 +1075,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 +1165,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); @@ -1185,7 +1186,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_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 4a50585efe3..992c0e9b5fc 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_passes/consts.rs b/src/librustc_passes/consts.rs index 02a0b3ab28d..5df8accd8ce 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/loops.rs b/src/librustc_passes/loops.rs index e58cd893819..adcb7842ee1 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> { diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index d55ce4c3563..7386be2528c 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 0e0f8a84567..5f76f865c4a 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 ff3038c3d11..0464a93ef71 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, @@ -42,7 +42,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 dc7399e2289..d9c1cfd9fdb 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}; @@ -1039,7 +1040,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 } @@ -1161,7 +1162,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_trans/collector.rs b/src/librustc_trans/collector.rs index 0fc6436e63c..d744d2a6db3 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::intravisit::{self, Visitor}; 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.as_deep_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> Visitor<'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(..) | @@ -1095,8 +1090,7 @@ 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; + intravisit::walk_item(self, item) } fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { @@ -1132,7 +1126,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { _ => { /* Nothing to do here */ } } - hir_visit::walk_impl_item(self, ii) + intravisit::walk_impl_item(self, ii) } } diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 25c30151ad4..aa23a181722 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/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 0cb8cf2a588..35f419bbf73 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(..) => { @@ -461,7 +461,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { } } } - 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 a95b3f4a973..7cf773688e6 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,7 +526,7 @@ 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); } @@ -534,21 +535,22 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { 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. diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 7e41a672bf3..d9411070e2e 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; @@ -63,5 +63,5 @@ impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { 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 58633058264..e8b0044ed20 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,7 +51,7 @@ 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) @@ -87,8 +87,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 371c182030e..d5a7726aa14 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,7 +380,7 @@ 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); } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index b5aba512a66..fb17255ccbc 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(..) | diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index cca6c884306..dd9d3e0d5b7 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, _) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 816243b3eab..52669ccc842 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -83,7 +83,8 @@ 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 +93,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 +129,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); diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 10fca644ec1..2c045bc88a2 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); diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index f6732f36e35..c40adb5f428 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)); From b889259e2b42479584343eb3674b7a3de1870e5b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 2 Nov 2016 18:25:31 -0400 Subject: [PATCH 02/18] separate impl-items from the impl in the HIR This commit does not change how the incremental accounting is done, so changes (or accessses) to an impl-item are still tagged to the enclosing impl. This commits adds the "main guts" of this change. It does not build on its own. --- src/librustc/dep_graph/visit.rs | 12 ++++++++++++ src/librustc/hir/intravisit.rs | 18 +++++++++++++++--- src/librustc/hir/itemlikevisit.rs | 2 +- src/librustc/hir/lowering.rs | 22 ++++++++++++++++++---- src/librustc/hir/map/mod.rs | 9 +++++++++ src/librustc/hir/mod.rs | 20 +++++++++++++++++++- src/librustc/hir/print.rs | 14 ++++++++++++-- 7 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index 30de5e5288a..6d89bbba54e 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -45,6 +45,18 @@ pub fn visit_all_item_likes_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) { + // TODO -- use the def-id of the impl for now + let impl_def_id = self.tcx.map.get_parent_did(i.id); + let task_id = (self.dep_node_fn)(impl_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_def_id)); + self.tcx.dep_graph.read(DepNode::Hir(impl_def_id)); + self.visitor.visit_impl_item(i); + debug!("Ended task {:?}", task_id); + } } let krate = tcx.dep_graph.with_ignore(|| tcx.map.krate()); diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2fc27e0cea0..5a193a0ac94 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -94,7 +94,17 @@ pub trait Visitor<'v> : Sized { fn visit_nested_item(&mut self, id: ItemId) { } - /// Visit the top-level item and (optionally) nested items. See + /// Invoked when a nested impl 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_item_likes`, which visits + /// all items in the crate in some order (but doesn't respect + /// nesting). + #[allow(unused_variables)] + fn visit_nested_impl_item(&mut self, id: ImplItemId) { + } + + /// 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) @@ -359,12 +369,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_ids) => { 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_id in impl_item_ids { + visitor.visit_nested_impl_item(impl_item_id); + } } ItemStruct(ref struct_definition, ref generics) | ItemUnion(ref struct_definition, ref generics) => { diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs index 6da47015d7d..22b56604428 100644 --- a/src/librustc/hir/itemlikevisit.rs +++ b/src/librustc/hir/itemlikevisit.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::Item; +use super::{Item, ImplItem}; use super::intravisit::Visitor; /// The "item-like visitor" visitor defines only the top-level methods diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b985298e47c..0731c35ff16 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_id(item); + 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_id(item)) .collect(); let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref)); hir::ItemImpl(self.lower_unsafety(unsafety), @@ -707,6 +717,10 @@ impl<'a> LoweringContext<'a> { }) } + fn lower_impl_item_id(&mut self, i: &ImplItem) -> hir::ImplItemId { + hir::ImplItemId { id: i.id } + } + fn lower_mod(&mut self, m: &Mod) -> hir::Mod { hir::Mod { inner: m.inner, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 39114ec4238..c629ec66ca4 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -378,6 +378,15 @@ impl<'ast> Map<'ast> { self.forest.krate() } + pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem { + // TODO right now this triggers a read of the whole impl + self.read(id.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 4716a09ad35..c9892135b1d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -424,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 { @@ -431,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. @@ -445,6 +451,10 @@ impl Crate { for (_, item) in &self.items { visitor.visit_item(item); } + + for (_, impl_item) in &self.impl_items { + visitor.visit_impl_item(impl_item); + } } } @@ -1042,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 id: NodeId, +} + /// Represents anything within an `impl` block #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ImplItem { @@ -1528,7 +1546,7 @@ pub enum Item_ { Generics, Option, // (optional) trait this impl implements P, // self - HirVec), + HirVec), } impl Item_ { diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 2c4ffb853c1..ed274b5a23e 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -808,8 +808,8 @@ impl<'a> State<'a> { space(&mut self.s)?; self.bopen()?; self.print_inner_attributes(&item.attrs)?; - for impl_item in impl_items { - self.print_impl_item(impl_item)?; + for &impl_item in impl_items { + self.print_impl_item_id(impl_item)?; } self.bclose(item.span)?; } @@ -1020,6 +1020,16 @@ impl<'a> State<'a> { self.ann.post(self, NodeSubItem(ti.id)) } + pub fn print_impl_item_id(&mut self, item_id: hir::ImplItemId) -> io::Result<()> { + if let Some(krate) = self.krate { + // skip nested items if krate context was not provided + let item = &krate.impl_item(item_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()?; From 3fd67eba87fc4bd634af34d170d7683397aeca3a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 4 Nov 2016 18:20:15 -0400 Subject: [PATCH 03/18] fallout from separating impl-items from impls Basically adding `visit_impl_item` in various places and so forth. --- src/librustc/hir/itemlikevisit.rs | 5 ++ src/librustc/hir/map/collector.rs | 4 + src/librustc/lint/context.rs | 9 +- src/librustc/middle/dead.rs | 30 +++++-- src/librustc/middle/entry.rs | 6 +- src/librustc/middle/lang_items.rs | 4 + src/librustc/middle/reachable.rs | 4 + src/librustc/middle/resolve_lifetime.rs | 5 ++ src/librustc/middle/stability.rs | 23 +++-- src/librustc_driver/derive_registrar.rs | 4 + src/librustc_incremental/assert_dep_graph.rs | 4 + .../calculate_svh/svh_visitor.rs | 6 ++ .../persist/dirty_clean.rs | 6 ++ src/librustc_metadata/encoder.rs | 4 + src/librustc_mir/transform/qualify_consts.rs | 8 +- src/librustc_passes/loops.rs | 4 + src/librustc_plugin/build.rs | 3 + src/librustc_privacy/lib.rs | 84 +++++++++++++------ src/librustc_trans/collector.rs | 18 ++-- src/librustc_typeck/check/method/suggest.rs | 3 + src/librustc_typeck/check/mod.rs | 19 +++-- src/librustc_typeck/check_unused.rs | 3 + src/librustc_typeck/coherence/mod.rs | 3 + src/librustc_typeck/coherence/orphan.rs | 4 + src/librustc_typeck/coherence/overlap.rs | 3 + src/librustc_typeck/coherence/unsafety.rs | 3 + src/librustc_typeck/collect.rs | 23 +++-- src/librustc_typeck/variance/constraints.rs | 3 + src/librustc_typeck/variance/terms.rs | 3 + src/librustdoc/visit_ast.rs | 5 +- 30 files changed, 233 insertions(+), 70 deletions(-) diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs index 22b56604428..1e373441e9e 100644 --- a/src/librustc/hir/itemlikevisit.rs +++ b/src/librustc/hir/itemlikevisit.rs @@ -56,6 +56,7 @@ use super::intravisit::Visitor; /// 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> { @@ -76,4 +77,8 @@ impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V> 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/map/collector.rs b/src/librustc/hir/map/collector.rs index 04fcf7e8450..eafb7949da3 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -99,6 +99,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/lint/context.rs b/src/librustc/lint/context.rs index 50c58105740..78049663afe 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -797,8 +797,13 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { /// 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)) + let item = self.tcx.map.expect_item(item.id); + self.visit_item(item) + } + + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) } fn visit_item(&mut self, it: &hir::Item) { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2667943bea9..57abf0bdc42 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -330,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> ItemLikeVisitor<'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 { @@ -358,17 +359,22 @@ impl<'v> ItemLikeVisitor<'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_ids) => { + for &impl_item_id in impl_item_ids { + let impl_item = self.krate.impl_item(impl_item_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_id.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>, @@ -387,7 +393,8 @@ 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_item_likes(&mut life_seeder); @@ -510,8 +517,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { /// 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)) + let item = self.tcx.map.expect_item(item.id); + self.visit_item(item) + } + + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) } fn visit_item(&mut self, item: &hir::Item) { diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index e5112749c0e..9dd54457a34 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -17,7 +17,7 @@ use syntax::ast::NodeId; use syntax::attr; use syntax::entry::EntryPointType; use syntax_pos::Span; -use hir::{Item, ItemFn}; +use hir::{Item, ItemFn, ImplItem}; use hir::itemlikevisit::ItemLikeVisitor; struct EntryContext<'a, 'tcx: 'a> { @@ -46,6 +46,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { 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) { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 6fe8442474a..9b4b1396669 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -164,6 +164,10 @@ impl<'a, 'v, 'tcx> ItemLikeVisitor<'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> { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 848f4218d88..0a45f895d7d 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -336,6 +336,10 @@ impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> { } } } + + 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>, diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index c342342d73b..68d2cceda84 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -141,6 +141,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { self.visit_item(item) } + fn visit_nested_impl_item(&mut self, id: hir::ImplItemId) { + let impl_item = self.hir_map.impl_item(id); + self.visit_impl_item(impl_item) + } + fn visit_item(&mut self, item: &hir::Item) { // Save labels for nested items. let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]); diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index d79833998d6..f8d58c5f2d9 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -239,8 +239,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { /// 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)) + let item = self.tcx.map.expect_item(item.id); + self.visit_item(item) + } + + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) } fn visit_item(&mut self, i: &Item) { @@ -449,8 +454,13 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { /// 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)) + let item = self.tcx.map.expect_item(item.id); + self.visit_item(item) + } + + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) } fn visit_item(&mut self, item: &hir::Item) { @@ -527,9 +537,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_ids) => { let trait_did = tcx.expect_def(t.ref_id).def_id(); - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = tcx.map.impl_item(impl_item_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_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs index 605193a0434..4db620b2bec 100644 --- a/src/librustc_driver/derive_registrar.rs +++ b/src/librustc_driver/derive_registrar.rs @@ -34,4 +34,8 @@ impl<'v> ItemLikeVisitor<'v> for Finder { 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 84489c2e8c6..d66e0f6aba3 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -171,6 +171,10 @@ 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) { + // handled in `visit_item` above + } } fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 0b0dd596784..3060e237fc1 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -503,6 +503,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has // Each item is hashed independently; ignore nested items. } + fn visit_nested_impl_item(&mut self, impl_item_id: ImplItemId) { + // For now, we hash impl items as part of the containing impl. + let impl_item = self.tcx.map.impl_item(impl_item_id); + self.visit_impl_item(impl_item); + } + fn visit_variant_data(&mut self, s: &'tcx VariantData, name: Name, diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index f6b7abd2ef1..0cd1c88fb87 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -184,6 +184,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'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>, @@ -225,6 +228,9 @@ impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index bbffe88316b..2d96eeb8f20 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1177,6 +1177,10 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'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> { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b33a7060e37..21bebb2562a 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_ids) = item.node { + span = impl_item_ids.first() + .map(|&impl_item_id| { + self.tcx.map.impl_item(impl_item_id) + .span + }); } } }); diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index adcb7842ee1..724100e0223 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -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_plugin/build.rs b/src/librustc_plugin/build.rs index 0464a93ef71..75046f6aeb8 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -32,6 +32,9 @@ impl<'v> ItemLikeVisitor<'v> for RegistrarFinder { } } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } /// Find the function marked with `#[plugin_registrar]`, if any. diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index d9c1cfd9fdb..3fd1ed93516 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -124,6 +124,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.visit_item(tcx.map.expect_item(item.id)) } + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) + } + fn visit_item(&mut self, item: &hir::Item) { let inherited_item_level = match item.node { // Impls inherit level from their types and traits @@ -159,15 +164,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_ids) => { + for &impl_item_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_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_ids) => { + for &impl_item_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_id); self.update(impl_item.id, item_level); } } @@ -250,11 +257,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_ids) => { 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_id in impl_item_ids { + if self.get(impl_item_id.id).is_some() { + let impl_item = self.tcx.map.impl_item(impl_item_id); self.reach().visit_impl_item(impl_item); } } @@ -319,6 +327,12 @@ impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { } impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> 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: &hir::Ty) { if let hir::TyPath(_, ref path) = ty.node { let def = self.ev.tcx.expect_def(ty.id); @@ -421,6 +435,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { self.visit_item(tcx.map.expect_item(item.id)) } + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) + } + fn visit_item(&mut self, item: &hir::Item) { let orig_curitem = replace(&mut self.curitem, item.id); intravisit::walk_item(self, item); @@ -625,6 +644,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> self.visit_item(tcx.map.expect_item(item.id)) } + fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { + let impl_item = self.tcx.map.impl_item(item_id); + self.visit_impl_item(impl_item) + } + fn visit_item(&mut self, item: &hir::Item) { match item.node { // contents of a private mod can be reexported, so we need @@ -650,7 +674,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_ids) => { // `impl [... for] Private` is never visible. let self_contains_private; // impl [... for] Public<...>, but not `impl [... for] @@ -695,16 +719,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_ids.iter() + .any(|&impl_item_id| { + let impl_item = self.tcx.map.impl_item(impl_item_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 && @@ -714,12 +739,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> match *trait_ref { None => { - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { // 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_id); match impl_item.node { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) @@ -751,7 +777,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_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_id); if let hir::ImplItemKind::Type(ref ty) = impl_item.node { self.visit_ty(ty); } @@ -762,7 +789,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_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_id); match impl_item.node { hir::ImplItemKind::Const(..) => { if self.item_is_public(&impl_item.id, &impl_item.vis) { @@ -1086,12 +1114,13 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor 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_ids) => { 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_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_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); @@ -1100,16 +1129,21 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor } // 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_ids) => { 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_id in impl_item_ids { + let impl_item = self.tcx.map.impl_item(impl_item_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>, diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index d744d2a6db3..8245b0cf7f5 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::{self, Visitor}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; @@ -308,7 +308,7 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, output: &mut roots, }; - scx.tcx().map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); + scx.tcx().map.krate().visit_all_item_likes(&mut visitor); } roots @@ -1031,7 +1031,7 @@ struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { output: &'b mut Vec>, } -impl<'b, 'a, 'v> 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) { match item.node { hir::ItemExternCrate(..) | @@ -1089,8 +1089,6 @@ impl<'b, 'a, 'v> Visitor<'v> for RootCollector<'b, 'a, 'v> { } } } - - intravisit::walk_item(self, item) } fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { @@ -1125,8 +1123,6 @@ impl<'b, 'a, 'v> Visitor<'v> for RootCollector<'b, 'a, 'v> { } _ => { /* Nothing to do here */ } } - - intravisit::walk_impl_item(self, ii) } } @@ -1151,9 +1147,11 @@ 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<_> = + items.iter() + .map(|&id| tcx.map.impl_item(id)) + .map(|item| item.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_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 35f419bbf73..6093e45e5a2 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -460,6 +460,9 @@ 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_item_likes(&mut Visitor { map: &ccx.tcx.map, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7cf773688e6..e8ebc2eee63 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -530,6 +530,10 @@ 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 { @@ -811,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_ids) => { 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) { @@ -819,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_ids); let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); } @@ -881,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_ids) => { debug!("ItemImpl {} with id {}", it.name, it.id); - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = ccx.tcx.map.impl_item(impl_item_id); match impl_item.node { hir::ImplItemKind::Const(_, ref expr) => { check_const(ccx, &expr, impl_item.id) @@ -1021,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_ids: &[hir::ImplItemId]) { // 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. @@ -1032,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_ids.iter().map(|&id| ccx.tcx.map.impl_item(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); diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index d9411070e2e..b4a10c52270 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -58,6 +58,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'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>) { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index e8b0044ed20..31bd7b0f19b 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -57,6 +57,9 @@ impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx, self.cc.check_implementation(item) } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index d5a7726aa14..a507077bef7 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -384,4 +384,8 @@ 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 fb17255ccbc..c66a76ebba0 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -199,4 +199,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'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 dd9d3e0d5b7..6d5de8f2506 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -106,4 +106,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'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 52669ccc842..658a655c2de 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -149,6 +149,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { } intravisit::walk_ty(self, ty); } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + // handled in `visit_item` above; we may want to break this out later + } } /////////////////////////////////////////////////////////////////////////// @@ -727,7 +731,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { ref generics, ref opt_trait_ref, ref selfty, - ref impl_items) => { + ref impl_item_ids) => { // 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); @@ -757,7 +761,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let mut seen_type_items = FxHashMap(); let mut seen_value_items = FxHashMap(); - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = tcx.map.impl_item(impl_item_id); let seen_items = match impl_item.node { hir::ImplItemKind::Type(_) => &mut seen_type_items, _ => &mut seen_value_items, @@ -790,7 +795,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } // Convert all the associated types. - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = tcx.map.impl_item(impl_item_id); 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); @@ -806,7 +812,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } - for impl_item in impl_items { + for &impl_item_id in impl_item_ids { + let impl_item = tcx.map.impl_item(impl_item_id); if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { convert_method(ccx, ImplContainer(def_id), impl_item.id, sig, selfty, @@ -814,7 +821,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } - enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_items); + enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_item_ids); }, hir::ItemTrait(.., ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); @@ -2103,7 +2110,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast_generics: &hir::Generics, impl_def_id: DefId, - impl_items: &[hir::ImplItem]) + impl_item_ids: &[hir::ImplItemId]) { // Every lifetime used in an associated type must be constrained. let impl_ty = ccx.tcx.item_type(impl_def_id); @@ -2118,8 +2125,8 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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)) + let lifetimes_in_associated_types: FxHashSet<_> = impl_item_ids.iter() + .map(|item_id| ccx.tcx.map.local_def_id(item_id.id)) .filter(|&def_id| { let item = ccx.tcx.associated_item(def_id); item.kind == ty::AssociatedKind::Type && item.has_value diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 2c045bc88a2..8a0c1c68322 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -115,6 +115,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'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 c40adb5f428..0a3238480d9 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -257,4 +257,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { hir::ItemTy(..) => {} } } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d9155e10e17..6587392e18f 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -502,10 +502,13 @@ 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(|&id| self.cx.map.impl_item(id).clone()) + .collect(); let i = Impl { unsafety: unsafety, polarity: polarity, From eeb45c7591ae7c7e843a132fe937b97a7d670581 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 11:16:39 -0500 Subject: [PATCH 04/18] make distinct Hir() nodes in the graph for impl items --- src/librustc/dep_graph/visit.rs | 9 ++++----- src/librustc/hir/map/mod.rs | 8 ++++++-- src/librustc_incremental/calculate_svh/mod.rs | 5 +++++ src/librustc_incremental/calculate_svh/svh_visitor.rs | 6 ++---- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index 6d89bbba54e..600732fc6f7 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -47,13 +47,12 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> } fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) { - // TODO -- use the def-id of the impl for now - let impl_def_id = self.tcx.map.get_parent_did(i.id); - let task_id = (self.dep_node_fn)(impl_def_id); + 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_def_id)); - self.tcx.dep_graph.read(DepNode::Hir(impl_def_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); } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index c629ec66ca4..e684040a173 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, _) | @@ -379,7 +384,6 @@ impl<'ast> Map<'ast> { } pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem { - // TODO right now this triggers a read of the whole impl self.read(id.id); // NB: intentionally bypass `self.forest.krate()` so that we diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 5697441b667..c08519090d2 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -207,6 +207,11 @@ impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { 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 3060e237fc1..3af6ee35f9e 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -503,10 +503,8 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has // Each item is hashed independently; ignore nested items. } - fn visit_nested_impl_item(&mut self, impl_item_id: ImplItemId) { - // For now, we hash impl items as part of the containing impl. - let impl_item = self.tcx.map.impl_item(impl_item_id); - self.visit_impl_item(impl_item); + fn visit_nested_impl_item(&mut self, _: ImplItemId) { + // Impl items are hashed independently; ignore nested impl items. } fn visit_variant_data(&mut self, From 7918299bf0aa96951f304ce84aa1b3c4b3a75cb9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 11 Nov 2016 10:02:10 -0500 Subject: [PATCH 05/18] fix dep-graph checking to account for implitems --- src/librustc_incremental/assert_dep_graph.rs | 4 ++-- src/test/compile-fail/dep-graph-type-alias.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index d66e0f6aba3..998cbae2cce 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -172,8 +172,8 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> { self.process_attrs(item.id, &item.attrs); } - fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { - // handled in `visit_item` above + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + self.process_attrs(impl_item.id, &impl_item.attrs); } } diff --git a/src/test/compile-fail/dep-graph-type-alias.rs b/src/test/compile-fail/dep-graph-type-alias.rs index 80cc9e71c7a..2e33f11c04b 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) {} } From ae8cb22fb9f2fa753963504b9c6a4d9e333840ba Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 13:23:59 -0500 Subject: [PATCH 06/18] factor out collection of impl-items into a distinct fn --- src/librustc_trans/callee.rs | 2 +- src/librustc_typeck/collect.rs | 79 +++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index faf65f3f98b..a7553ce4995 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -605,7 +605,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Create a fn pointer with the substituted signature. tcx.mk_fn_ptr(fty) } - _ => bug!("expected fn item type, found {}", fn_ty) + _ => bug!("expected fn item type for {:?}, found {}", def_id, fn_ty) }; let llptrty = type_of::type_of(ccx, fn_ptr_ty); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 658a655c2de..eb4775a29bf 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -150,8 +150,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { intravisit::walk_ty(self, ty); } - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { // handled in `visit_item` above; we may want to break this out later + intravisit::walk_impl_item(self, impl_item); } } @@ -782,43 +783,10 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { 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_id in impl_item_ids { - let impl_item = tcx.map.impl_item(impl_item_id); - 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_id in impl_item_ids { - let impl_item = tcx.map.impl_item(impl_item_id); - if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - convert_method(ccx, ImplContainer(def_id), - impl_item.id, sig, selfty, - &ty_predicates); - } + convert_impl_item(ccx, impl_item_id); } enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_item_ids); @@ -907,6 +875,47 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } +fn convert_impl_item(ccx: &CrateCtxt, impl_item_id: hir::ImplItemId) { + let tcx = ccx.tcx; + let impl_item = tcx.map.impl_item(impl_item_id); + let impl_def_id = tcx.map.get_parent_did(impl_item_id.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>, From 4a4c61b2d2b99e2ae20ab5fcf7c1c59a9ac7d226 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 19:23:09 -0500 Subject: [PATCH 07/18] move the impl-params-constrained check out of collect This helps with incr. comp. because otherwise the Collect(Impl) check winds up touching all of the impl items; since Collect(Impl) also produces the types for the impl header, this creates a polluted graph where the impl types depend on the impl items. --- src/librustc_typeck/Cargo.toml | 1 + .../check/impl_parameters_used.rs | 129 ++++++++++++++++++ src/librustc_typeck/check/mod.rs | 9 +- src/librustc_typeck/collect.rs | 119 ++-------------- .../constrained_type_params.rs | 12 ++ src/librustc_typeck/lib.rs | 1 + 6 files changed, 160 insertions(+), 111 deletions(-) create mode 100644 src/librustc_typeck/check/impl_parameters_used.rs diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 720423371a8..f08d26373e5 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/impl_parameters_used.rs b/src/librustc_typeck/check/impl_parameters_used.rs new file mode 100644 index 00000000000..defdcc7906c --- /dev/null +++ b/src/librustc_typeck/check/impl_parameters_used.rs @@ -0,0 +1,129 @@ +// 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. + +use constrained_type_params as ctp; +use rustc::hir; +use rustc::hir::def_id::DefId; +use rustc::ty; +use rustc::util::nodemap::FxHashSet; + +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 enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_hir_generics: &hir::Generics, + impl_def_id: DefId, + impl_item_ids: &[hir::ImplItemId]) +{ + // Every lifetime used in an associated type must be constrained. + let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); + let impl_predicates = ccx.tcx.lookup_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_scheme.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_scheme.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_ids.iter() + .map(|item_id| ccx.tcx.map.local_def_id(item_id.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.lookup_item_type(def_id).ty, true) + }).collect(); + for (ty_lifetime, lifetime) in impl_scheme.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(); +} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e8ebc2eee63..12a1cc8279f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -143,6 +143,7 @@ mod closure; mod callee; mod compare_method; mod intrinsic; +mod impl_parameters_used; mod op; /// closures defined within the function. For example: @@ -815,7 +816,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_item_ids) => { + hir::ItemImpl(_, _, ref hir_generics, _, _, ref impl_item_ids) => { 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) { @@ -827,6 +828,12 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); } + + impl_parameters_used::enforce_impl_params_are_constrained(ccx, + hir_generics, + impl_def_id, + impl_item_ids); + } hir::ItemTrait(..) => { let def_id = ccx.tcx.map.local_def_id(it.id); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index eb4775a29bf..e7873d2f818 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -753,7 +753,15 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { }); tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref); - enforce_impl_params_are_constrained(ccx, generics, &mut ty_predicates, def_id); + // Subtle: before we store the predicates into the tcx, we + // sort them so that predicates like `T: Foo` come + // before uses of `U`. This avoids false ambiguity errors + // in trait checking. See `setup_constraining_predicates` + // for details. + ctp::setup_constraining_predicates(&mut ty_predicates.predicates, + trait_ref, + &mut ctp::parameters_for_impl(selfty, trait_ref)); + tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone()); @@ -788,8 +796,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { for &impl_item_id in impl_item_ids { convert_impl_item(ccx, impl_item_id); } - - enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_item_ids); }, hir::ItemTrait(.., ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); @@ -2084,110 +2090,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_item_ids: &[hir::ImplItemId]) -{ - // 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_item_ids.iter() - .map(|item_id| ccx.tcx.map.local_def_id(item_id.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 7918537a6c0..22be4491273 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/lib.rs b/src/librustc_typeck/lib.rs index 2c12959dbdd..222e60bb054 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; From 29a39ab8346721cf60cfb15f7e025eb24efc818f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 20:26:59 -0500 Subject: [PATCH 08/18] move `convert_impl_item` into the main loop This is better because the edges will be accounted to the impl item itself --- src/librustc_typeck/collect.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e7873d2f818..fc197742455 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -151,7 +151,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { - // handled in `visit_item` above; we may want to break this out later + convert_impl_item(self.ccx, impl_item); intravisit::walk_impl_item(self, impl_item); } } @@ -792,10 +792,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } } - - for &impl_item_id in impl_item_ids { - convert_impl_item(ccx, impl_item_id); - } }, hir::ItemTrait(.., ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); @@ -881,10 +877,12 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } -fn convert_impl_item(ccx: &CrateCtxt, impl_item_id: hir::ImplItemId) { +fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { let tcx = ccx.tcx; - let impl_item = tcx.map.impl_item(impl_item_id); - let impl_def_id = tcx.map.get_parent_did(impl_item_id.id); + + // 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); From 4df5288971b9908b77c0c785885a59d91e546a4d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 8 Nov 2016 20:27:28 -0500 Subject: [PATCH 09/18] move duplicate checking into TypeCheck This completes the effort to not touch the impl-items during `Collect(Impl)`. --- .../check/impl_item_duplicate.rs | 46 +++++++++++++++++++ src/librustc_typeck/check/mod.rs | 3 ++ src/librustc_typeck/collect.rs | 36 ++------------- 3 files changed, 54 insertions(+), 31 deletions(-) create mode 100644 src/librustc_typeck/check/impl_item_duplicate.rs diff --git a/src/librustc_typeck/check/impl_item_duplicate.rs b/src/librustc_typeck/check/impl_item_duplicate.rs new file mode 100644 index 00000000000..4111fa9a2c0 --- /dev/null +++ b/src/librustc_typeck/check/impl_item_duplicate.rs @@ -0,0 +1,46 @@ +// 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. + +use rustc::hir; +use rustc_data_structures::fx::FxHashMap; +use std::collections::hash_map::Entry::{Occupied, Vacant}; + +use CrateCtxt; + +/// Enforce that we do not have two items in an impl with the same name. +pub fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_item_ids: &[hir::ImplItemId]) +{ + let tcx = ccx.tcx; + let mut seen_type_items = FxHashMap(); + let mut seen_value_items = FxHashMap(); + for &impl_item_id in impl_item_ids { + let impl_item = tcx.map.impl_item(impl_item_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/check/mod.rs b/src/librustc_typeck/check/mod.rs index 12a1cc8279f..7c21ddbe401 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -143,6 +143,7 @@ mod closure; mod callee; mod compare_method; mod intrinsic; +mod impl_item_duplicate; mod impl_parameters_used; mod op; @@ -834,6 +835,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { impl_def_id, impl_item_ids); + impl_item_duplicate::enforce_impl_items_are_distinct(ccx, + impl_item_ids); } hir::ItemTrait(..) => { let def_id = ccx.tcx.map.local_def_id(it.id); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fc197742455..c20e1d1d4d7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -77,7 +77,6 @@ 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}; @@ -732,7 +731,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { ref generics, ref opt_trait_ref, ref selfty, - ref impl_item_ids) => { + ref _impl_item_ids /* [1] */) => { + // [1]: We really don't want to be inspecting the details + // of impl-items here; it creates bad edges in the + // incr. comp. graph. + // 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); @@ -763,35 +766,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { &mut ctp::parameters_for_impl(selfty, trait_ref)); tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone()); - - - // Convert all the associated consts. - // Also, check if there are any duplicate associated items - let mut seen_type_items = FxHashMap(); - let mut seen_value_items = FxHashMap(); - - for &impl_item_id in impl_item_ids { - let impl_item = tcx.map.impl_item(impl_item_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); - } - } - } }, hir::ItemTrait(.., ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); From 26d1500e133d50727dfea10043d194a5b9f3761f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 9 Nov 2016 16:45:26 -0500 Subject: [PATCH 10/18] add a `nested_visit_map` method This allows you to enable *all* nested visits in a future-compatible sort of way. Moreover, if you choose to override the `visit_nested` methods yourself, you can "future-proof" against omissions by overriding `nested_visit_map` to panic. --- src/librustc/hir/intravisit.rs | 56 ++++++++++--- src/librustc/hir/map/collector.rs | 5 ++ src/librustc/lint/context.rs | 66 ++++++++-------- src/librustc/middle/dead.rs | 27 +++---- src/librustc/middle/resolve_lifetime.rs | 66 ++++++++-------- src/librustc/middle/stability.rs | 52 +++++------- .../calculate_svh/svh_visitor.rs | 8 -- src/librustc_passes/hir_stats.rs | 8 ++ src/librustc_privacy/lib.rs | 79 ++++++++----------- 9 files changed, 183 insertions(+), 184 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 5a193a0ac94..0b83a8bc922 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -38,6 +38,7 @@ 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; @@ -85,23 +86,52 @@ 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 to - /// use either the "shallow" or "deep" visit patterns described on - /// `itemlikevisit::ItemLikeVisitor`. - #[allow(unused_variables)] - fn visit_nested_item(&mut self, id: ItemId) { + /// The default versions of the `visit_nested_XXX` routines invoke + /// this method to get a map to use; if they get back `None`, they + /// just skip nested things. Otherwise, they will lookup the + /// nested item-like things in the map and visit it. So the best + /// way to implement a nested visitor is to override this method + /// to return a `Map`; one advantage of this is that if we add + /// more types of nested things in the future, they will + /// automatically work. + /// + /// **If for some reason you want the nested behavior, but don't + /// have a `Map` are your disposal:** then you should override the + /// `visit_nested_XXX` methods, and override this method to + /// `panic!()`. This way, if a new `visit_nested_XXX` variant is + /// added in the future, we will see the panic in your code and + /// fix it appropriately. + fn nested_visit_map(&mut self) -> Option<&Map<'v>> { + None } - /// Invoked when a nested impl 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_item_likes`, which visits - /// all items in the crate in some order (but doesn't respect - /// nesting). + /// Invoked when a nested item is encountered. By default does + /// nothing unless you override `nested_visit_map` to return + /// `Some(_)`, in which case it will walk the item. **You probably + /// don't want to override this method** -- instead, override + /// `nested_visit_map` or use the "shallow" or "deep" visit + /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only + /// reason to override this method is if you want a nested pattern + /// but cannot supply a `Map`; see `nested_visit_map` for advice. + #[allow(unused_variables)] + fn visit_nested_item(&mut self, id: ItemId) { + let opt_item = self.nested_visit_map() + .map(|map| map.expect_item(id.id)); + if let Some(item) = opt_item { + self.visit_item(item); + } + } + + /// Like `visit_nested_item()`, but for impl items. See + /// `visit_nested_item()` for advice on when to override this + /// method. #[allow(unused_variables)] fn visit_nested_impl_item(&mut self, id: ImplItemId) { + let opt_item = self.nested_visit_map() + .map(|map| map.impl_item(id)); + if let Some(item) = opt_item { + self.visit_impl_item(item); + } } /// Visit the top-level item and (optionally) nested items / impl items. See diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index eafb7949da3..5fd0839affe 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<&hir::map::Map<'v>> { + 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 { diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 78049663afe..a490b58964a 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -792,21 +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 item = self.tcx.map.expect_item(item.id); - self.visit_item(item) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - 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)); @@ -815,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); @@ -823,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 @@ -845,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); @@ -863,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); @@ -878,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); } @@ -887,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)); @@ -934,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)); @@ -943,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); } @@ -1121,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 57abf0bdc42..e6722661223 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -511,22 +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 item = self.tcx.map.expect_item(item.id); - self.visit_item(item) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - 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, @@ -540,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"); @@ -549,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"); @@ -565,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) { @@ -586,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/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 68d2cceda84..f682dfbf1be 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -132,21 +132,14 @@ pub fn krate(sess: &Session, Ok(map) } -impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { +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 visit_nested_item(&mut self, id: hir::ItemId) { - let item = self.hir_map.expect_item(id.id); - self.visit_item(item) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.hir_map) } - fn visit_nested_impl_item(&mut self, id: hir::ImplItemId) { - let impl_item = self.hir_map.impl_item(id); - self.visit_impl_item(impl_item) - } - - fn visit_item(&mut self, item: &hir::Item) { + 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![]); @@ -192,7 +185,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { 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![]); @@ -215,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| { @@ -241,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| { @@ -271,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![]); @@ -288,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; @@ -296,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 { @@ -345,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() { @@ -504,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); @@ -533,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 { @@ -571,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, @@ -604,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 f8d58c5f2d9..239aaa6bb75 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,21 +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 item = self.tcx.map.expect_item(item.id); - self.visit_item(item) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - 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 { @@ -277,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 { @@ -294,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, |_| {}); } @@ -449,21 +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 item = self.tcx.map.expect_item(item.id); - self.visit_item(item) + fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { + Some(&self.tcx.map) } - fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - 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` @@ -474,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 => { diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 3af6ee35f9e..318cc83d9ad 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -499,14 +499,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_nested_impl_item(&mut self, _: ImplItemId) { - // Impl items are hashed independently; ignore nested impl items. - } - fn visit_variant_data(&mut self, s: &'tcx VariantData, name: Name, diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 417987d9664..3bdaf276b40 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_privacy/lib.rs b/src/librustc_privacy/lib.rs index 3fd1ed93516..9cbf4c8a615 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -116,20 +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_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - 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, _) => { @@ -278,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 @@ -289,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() { @@ -305,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); @@ -326,14 +320,14 @@ impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { } } -impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { +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: &hir::Ty) { + 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 { @@ -365,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); @@ -427,26 +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_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - 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); @@ -506,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 @@ -542,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; @@ -636,20 +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_nested_impl_item(&mut self, item_id: hir::ImplItemId) { - let impl_item = self.tcx.map.impl_item(item_id); - self.visit_impl_item(impl_item) - } - - 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. @@ -834,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) @@ -855,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); @@ -870,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); @@ -878,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); } @@ -888,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) {} } /////////////////////////////////////////////////////////////////////////////// From 629f5ffb23aeb96621bb4da7f7ea6d605670056b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 10 Nov 2016 09:47:00 -0500 Subject: [PATCH 11/18] include a Name and Span for each item in the HIR of the impl --- src/librustc/hir/intravisit.rs | 15 ++++-- src/librustc/hir/lowering.rs | 24 +++++++-- src/librustc/hir/map/collector.rs | 2 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/hir/mod.rs | 28 +++++++++- src/librustc/hir/print.rs | 8 +-- src/librustc/middle/dead.rs | 8 +-- src/librustc/middle/reachable.rs | 6 +-- src/librustc/middle/stability.rs | 6 +-- src/librustc/ty/mod.rs | 6 +-- src/librustc_lint/builtin.rs | 6 +-- src/librustc_mir/transform/qualify_consts.rs | 12 ++--- src/librustc_privacy/lib.rs | 52 +++++++++---------- src/librustc_trans/collector.rs | 9 ++-- .../check/impl_item_duplicate.rs | 6 +-- .../check/impl_parameters_used.rs | 6 +-- src/librustc_typeck/check/mod.rs | 18 +++---- 17 files changed, 131 insertions(+), 83 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 0b83a8bc922..887b1febf65 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -205,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) } @@ -399,13 +402,13 @@ 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_item_ids) => { + 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); - for &impl_item_id in impl_item_ids { - visitor.visit_nested_impl_item(impl_item_id); + for impl_item_ref in impl_item_refs { + visitor.visit_impl_item_ref(impl_item_ref); } } ItemStruct(ref struct_definition, ref generics) | @@ -763,6 +766,12 @@ 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) { + visitor.visit_nested_impl_item(impl_item_ref.id); + visitor.visit_name(impl_item_ref.span, impl_item_ref.name); +} + + 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()); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 0731c35ff16..d1b57586ffd 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -116,7 +116,7 @@ impl<'a> LoweringContext<'a> { } fn visit_impl_item(&mut self, item: &ImplItem) { - let id = self.lctx.lower_impl_item_id(item); + 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); } @@ -641,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_id(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), @@ -717,8 +717,24 @@ impl<'a> LoweringContext<'a> { }) } - fn lower_impl_item_id(&mut self, i: &ImplItem) -> hir::ImplItemId { - hir::ImplItemId { id: i.id } + 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), + 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!(), + }, + // since `default impl` is not yet implemented, this is always true in impls + has_value: true, + } } fn lower_mod(&mut self, m: &Mod) -> hir::Mod { diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 5fd0839affe..51a378a0833 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -93,7 +93,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { /// deep walking so that we walk nested items in the context of /// their outer items. - fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> { + fn nested_visit_map(&mut self) -> Option<&map::Map<'ast>> { panic!("visit_nested_xxx must be manually implemented in this visitor") } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index e684040a173..06cfc8aee8c 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -384,7 +384,7 @@ impl<'ast> Map<'ast> { } pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem { - self.read(id.id); + self.read(id.node_id); // NB: intentionally bypass `self.forest.krate()` so that we // do not trigger a read of the whole krate here diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c9892135b1d..9dac6fac100 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1057,7 +1057,7 @@ pub enum TraitItem_ { // so it can fetched later. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ImplItemId { - pub id: NodeId, + pub node_id: NodeId, } /// Represents anything within an `impl` block @@ -1546,7 +1546,7 @@ pub enum Item_ { Generics, Option, // (optional) trait this impl implements P, // self - HirVec), + HirVec), } impl Item_ { @@ -1570,6 +1570,30 @@ 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, + pub has_value: bool, +} + +#[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 ed274b5a23e..5a381a189fc 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -808,8 +808,8 @@ impl<'a> State<'a> { space(&mut self.s)?; self.bopen()?; self.print_inner_attributes(&item.attrs)?; - for &impl_item in impl_items { - self.print_impl_item_id(impl_item)?; + for impl_item in impl_items { + self.print_impl_item_ref(impl_item)?; } self.bclose(item.span)?; } @@ -1020,10 +1020,10 @@ impl<'a> State<'a> { self.ann.post(self, NodeSubItem(ti.id)) } - pub fn print_impl_item_id(&mut self, item_id: hir::ImplItemId) -> io::Result<()> { + 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_id); + let item = &krate.impl_item(item_ref.id); self.print_impl_item(item) } else { Ok(()) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index e6722661223..99139881375 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -359,12 +359,12 @@ impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> { } } } - hir::ItemImpl(.., ref opt_trait, _, ref impl_item_ids) => { - for &impl_item_id in impl_item_ids { - let impl_item = self.krate.impl_item(impl_item_id); + 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.id); + self.worklist.push(impl_item_ref.id.node_id); } } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 0a45f895d7d..ac614494355 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -328,10 +328,10 @@ struct 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); } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 239aaa6bb75..7e4efc7ddca 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -525,10 +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_item_ids) => { + hir::ItemImpl(.., Some(ref t), _, ref impl_item_refs) => { let trait_did = tcx.expect_def(t.ref_id).def_id(); - for &impl_item_id in impl_item_ids { - let impl_item = tcx.map.impl_item(impl_item_id); + 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/ty/mod.rs b/src/librustc/ty/mod.rs index c6fff94438f..4db788a92d6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2190,9 +2190,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.map.local_def_id(trait_item.id) }).collect()) } - hir::ItemImpl(.., ref impl_items) => { - Rc::new(impl_items.iter().map(|impl_item| { - self.map.local_def_id(impl_item.id) + hir::ItemImpl(.., ref impl_item_refs) => { + Rc::new(impl_item_refs.iter().map(|impl_item_ref| { + self.map.local_def_id(impl_item_ref.id.node_id) }).collect()) } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f6b6c89b7cc..51ffb1ebc8e 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_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 21bebb2562a..4ff2beb3fdb 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -277,12 +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 impl_item_ids) = item.node { - span = impl_item_ids.first() - .map(|&impl_item_id| { - self.tcx.map.impl_item(impl_item_id) - .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_privacy/lib.rs b/src/librustc_privacy/lib.rs index 9cbf4c8a615..b116408269e 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -158,17 +158,17 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } } } - hir::ItemImpl(.., None, _, ref impl_item_ids) => { - for &impl_item_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + 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_item_ids) => { - for &impl_item_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + 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); } } @@ -251,12 +251,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { // The interface is empty hir::ItemDefaultImpl(..) => {} // Visit everything except for private impl items - hir::ItemImpl(.., ref generics, None, _, ref impl_item_ids) => { + hir::ItemImpl(.., ref generics, None, _, ref impl_item_refs) => { if item_level.is_some() { self.reach().visit_generics(generics); - for &impl_item_id in impl_item_ids { - if self.get(impl_item_id.id).is_some() { - let impl_item = self.tcx.map.impl_item(impl_item_id); + 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); } } @@ -656,7 +656,7 @@ impl<'a, 'tcx> Visitor<'tcx> 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_item_ids) => { + 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] @@ -701,9 +701,9 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // are private (because `T` won't be visible externally). let trait_or_some_public_method = trait_ref.is_some() || - impl_item_ids.iter() - .any(|&impl_item_id| { - let impl_item = self.tcx.map.impl_item(impl_item_id); + 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(..) => { @@ -721,13 +721,13 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { match *trait_ref { None => { - for &impl_item_id in impl_item_ids { + 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_id); + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); match impl_item.node { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) @@ -759,8 +759,8 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { intravisit::walk_path(self, &tr.path); // Those in 3. are warned with this call. - for &impl_item_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + 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); } @@ -771,8 +771,8 @@ impl<'a, 'tcx> Visitor<'tcx> 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_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + 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) { @@ -1099,13 +1099,13 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor 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_item_ids) => { + 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_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + 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); @@ -1114,12 +1114,12 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor } // 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_item_ids) => { + 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_id in impl_item_ids { - let impl_item = self.tcx.map.impl_item(impl_item_id); + 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); } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 8245b0cf7f5..5902b0b1ce0 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -1135,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 } @@ -1148,10 +1148,9 @@ 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(|&id| tcx.map.impl_item(id)) - .map(|item| item.name) - .collect(); + 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_typeck/check/impl_item_duplicate.rs b/src/librustc_typeck/check/impl_item_duplicate.rs index 4111fa9a2c0..7b33aa694a2 100644 --- a/src/librustc_typeck/check/impl_item_duplicate.rs +++ b/src/librustc_typeck/check/impl_item_duplicate.rs @@ -16,13 +16,13 @@ use CrateCtxt; /// Enforce that we do not have two items in an impl with the same name. pub fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_item_ids: &[hir::ImplItemId]) + impl_item_refs: &[hir::ImplItemRef]) { let tcx = ccx.tcx; let mut seen_type_items = FxHashMap(); let mut seen_value_items = FxHashMap(); - for &impl_item_id in impl_item_ids { - let impl_item = tcx.map.impl_item(impl_item_id); + 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, diff --git a/src/librustc_typeck/check/impl_parameters_used.rs b/src/librustc_typeck/check/impl_parameters_used.rs index defdcc7906c..650e959ba01 100644 --- a/src/librustc_typeck/check/impl_parameters_used.rs +++ b/src/librustc_typeck/check/impl_parameters_used.rs @@ -51,7 +51,7 @@ use CrateCtxt; pub fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_hir_generics: &hir::Generics, impl_def_id: DefId, - impl_item_ids: &[hir::ImplItemId]) + impl_item_refs: &[hir::ImplItemRef]) { // Every lifetime used in an associated type must be constrained. let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); @@ -71,8 +71,8 @@ pub fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } // Disallow unconstrained lifetimes, but only if they appear in assoc types. - let lifetimes_in_associated_types: FxHashSet<_> = impl_item_ids.iter() - .map(|item_id| ccx.tcx.map.local_def_id(item_id.id)) + 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.has_value diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7c21ddbe401..a8e38a362b5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -817,7 +817,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 hir_generics, _, _, ref impl_item_ids) => { + hir::ItemImpl(_, _, ref hir_generics, _, _, 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) { @@ -825,7 +825,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_item_ids); + impl_item_refs); let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); } @@ -833,10 +833,10 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { impl_parameters_used::enforce_impl_params_are_constrained(ccx, hir_generics, impl_def_id, - impl_item_ids); + impl_item_refs); impl_item_duplicate::enforce_impl_items_are_distinct(ccx, - impl_item_ids); + impl_item_refs); } hir::ItemTrait(..) => { let def_id = ccx.tcx.map.local_def_id(it.id); @@ -895,11 +895,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_item_ids) => { + hir::ItemImpl(.., ref impl_item_refs) => { debug!("ItemImpl {} with id {}", it.name, it.id); - for &impl_item_id in impl_item_ids { - let impl_item = ccx.tcx.map.impl_item(impl_item_id); + 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) @@ -1036,7 +1036,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_item_ids: &[hir::ImplItemId]) { + 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. @@ -1047,7 +1047,7 @@ 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_ids.iter().map(|&id| ccx.tcx.map.impl_item(id)); + 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 From 34c361cfb2e7aa3efffe8783d2c31afc9e43f040 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 11 Nov 2016 18:22:41 -0500 Subject: [PATCH 12/18] when creating an AssociatedItem, read data from impl, not impl item Before, when we created an AssociatedItem for impl item X, we would read the impl item itself. Now we instead load up the impl I that contains X and read the data from the `ImplItemRef` for X; actually, we do it for all impl items in I pre-emptively. This kills the last source of edges between a method X and a call to a method Y defined in the same impl. Fixes #37121 --- src/librustc/hir/def.rs | 2 +- src/librustc/traits/project.rs | 5 +- src/librustc/ty/mod.rs | 163 +++++++++++------- src/librustc_typeck/collect.rs | 6 +- src/librustdoc/visit_ast.rs | 4 +- .../struct_point.rs | 11 +- .../struct_point.rs | 26 +-- 7 files changed, 128 insertions(+), 89 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 044e36e5c9c..feefc43f401 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/traits/project.rs b/src/librustc/traits/project.rs index f1b69feb545..ac2f3ad9b89 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -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); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4db788a92d6..9984dd42f56 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2113,69 +2113,111 @@ 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, + has_value: true, + 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 +2226,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_item_refs) => { - Rc::new(impl_item_refs.iter().map(|impl_item_ref| { - self.map.local_def_id(impl_item_ref.id.node_id) - }).collect()) + 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) }) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c20e1d1d4d7..535b6bcdcba 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -731,11 +731,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { ref generics, ref opt_trait_ref, ref selfty, - ref _impl_item_ids /* [1] */) => { - // [1]: We really don't want to be inspecting the details - // of impl-items here; it creates bad edges in the - // incr. comp. graph. - + _) => { // 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); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6587392e18f..939fd6ccfc8 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -507,7 +507,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // regardless of where they're located. if !self.inlining { let items = item_ids.iter() - .map(|&id| self.cx.map.impl_item(id).clone()) + .map(|ii| self.cx.map.impl_item(ii.id).clone()) .collect(); let i = Impl { unsafety: unsafety, @@ -515,7 +515,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { 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/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs index 8fa34bde170..46e5a88eef9 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 d8e5fbadad8..a8779e3f92d 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,15 @@ #![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")] + +// FIXME(#37333) the struct fields get entangled with inherent methods +#![rustc_partition_translated(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 +35,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 +47,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 +59,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 +69,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 +79,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; } From c17be9ea110a1158e6a1ad131941ec6965ce6ac9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 11 Nov 2016 09:52:46 -0500 Subject: [PATCH 13/18] move impl wf check so they occur earlier Needed to keep coherence from freaking out. --- .../check/impl_item_duplicate.rs | 46 --------- src/librustc_typeck/check/mod.rs | 12 +-- ...pl_parameters_used.rs => impl_wf_check.rs} | 96 ++++++++++++++++--- src/librustc_typeck/lib.rs | 6 ++ src/test/compile-fail/issue-3214.rs | 1 - 5 files changed, 92 insertions(+), 69 deletions(-) delete mode 100644 src/librustc_typeck/check/impl_item_duplicate.rs rename src/librustc_typeck/{check/impl_parameters_used.rs => impl_wf_check.rs} (51%) diff --git a/src/librustc_typeck/check/impl_item_duplicate.rs b/src/librustc_typeck/check/impl_item_duplicate.rs deleted file mode 100644 index 7b33aa694a2..00000000000 --- a/src/librustc_typeck/check/impl_item_duplicate.rs +++ /dev/null @@ -1,46 +0,0 @@ -// 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. - -use rustc::hir; -use rustc_data_structures::fx::FxHashMap; -use std::collections::hash_map::Entry::{Occupied, Vacant}; - -use CrateCtxt; - -/// Enforce that we do not have two items in an impl with the same name. -pub 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/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8e38a362b5..2197ecc10a1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -143,8 +143,6 @@ mod closure; mod callee; mod compare_method; mod intrinsic; -mod impl_item_duplicate; -mod impl_parameters_used; mod op; /// closures defined within the function. For example: @@ -817,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 hir_generics, _, _, ref impl_item_refs) => { + 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) { @@ -829,14 +827,6 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); } - - impl_parameters_used::enforce_impl_params_are_constrained(ccx, - hir_generics, - impl_def_id, - impl_item_refs); - - impl_item_duplicate::enforce_impl_items_are_distinct(ccx, - impl_item_refs); } hir::ItemTrait(..) => { let def_id = ccx.tcx.map.local_def_id(it.id); diff --git a/src/librustc_typeck/check/impl_parameters_used.rs b/src/librustc_typeck/impl_wf_check.rs similarity index 51% rename from src/librustc_typeck/check/impl_parameters_used.rs rename to src/librustc_typeck/impl_wf_check.rs index 650e959ba01..1572d04f68c 100644 --- a/src/librustc_typeck/check/impl_parameters_used.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -8,11 +8,24 @@ // 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::FxHashSet; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax_pos::Span; @@ -48,22 +61,52 @@ use CrateCtxt; /// impl<'a> Trait for Bar { type X = &'a i32; } /// ^ 'a is unused and appears in assoc type, error /// ``` -pub 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]) +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_scheme = ccx.tcx.lookup_item_type(impl_def_id); - let impl_predicates = ccx.tcx.lookup_predicates(impl_def_id); + 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_scheme.ty, impl_trait_ref); + 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_scheme.generics.types.iter().zip(&impl_hir_generics.ty_params) { + 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()); @@ -78,9 +121,9 @@ pub fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, item.kind == ty::AssociatedKind::Type && item.has_value }) .flat_map(|def_id| { - ctp::parameters_for(&ccx.tcx.lookup_item_type(def_id).ty, true) + ctp::parameters_for(&ccx.tcx.item_type(def_id), true) }).collect(); - for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter() + 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()); @@ -127,3 +170,34 @@ fn report_unused_parameter(ccx: &CrateCtxt, .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 222e60bb054..f2e8bb2e961 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -131,6 +131,7 @@ mod rscope; mod astconv; pub mod collect; mod constrained_type_params; +mod impl_wf_check; pub mod coherence; pub mod variance; @@ -334,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/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs index d3b932fbc53..010cfb54c1a 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) {} } } From b10b98169ff7350236e96f99ddb2f5d4cbef732b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 14 Nov 2016 11:00:02 -0500 Subject: [PATCH 14/18] hash the contents of impl-item-ref by adding them to visitor Also simplify some of the `ty::AssociatedItem` representation, in particular by folding `has_value` into `hir::Defaultness` --- src/librustc/hir/intravisit.rs | 39 +++++- src/librustc/hir/lowering.rs | 19 ++- src/librustc/hir/mod.rs | 15 +- src/librustc/hir/print.rs | 5 +- src/librustc/traits/project.rs | 4 +- src/librustc/ty/mod.rs | 7 +- .../calculate_svh/svh_visitor.rs | 14 ++ src/librustc_metadata/decoder.rs | 3 - src/librustc_metadata/encoder.rs | 17 ++- src/librustc_metadata/schema.rs | 19 +-- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/impl_wf_check.rs | 2 +- src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/mod.rs | 5 +- src/test/incremental/hashes/inherent_impls.rs | 128 ++++++++++++++++++ 17 files changed, 234 insertions(+), 55 deletions(-) create mode 100644 src/test/incremental/hashes/inherent_impls.rs diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 887b1febf65..4cfa889ec56 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -267,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) { @@ -740,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); @@ -767,8 +777,13 @@ 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) { - visitor.visit_nested_impl_item(impl_item_ref.id); - visitor.visit_name(impl_item_ref.span, impl_item_ref.name); + // 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); } @@ -941,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/lowering.rs b/src/librustc/hir/lowering.rs index d1b57586ffd..05c4ae52180 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -699,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)) @@ -715,6 +715,8 @@ 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 { @@ -723,7 +725,7 @@ impl<'a> LoweringContext<'a> { name: i.ident.name, span: i.span, vis: self.lower_visibility(&i.vis), - defaultness: self.lower_defaultness(i.defaultness), + defaultness: self.lower_defaultness(i.defaultness, true /* [1] */), kind: match i.node { ImplItemKind::Const(..) => hir::AssociatedItemKind::Const, ImplItemKind::Type(..) => hir::AssociatedItemKind::Type, @@ -732,9 +734,9 @@ impl<'a> LoweringContext<'a> { }, ImplItemKind::Macro(..) => unimplemented!(), }, - // since `default impl` is not yet implemented, this is always true in impls - has_value: true, } + + // [1] since `default impl` is not yet implemented, this is always true in impls } fn lower_mod(&mut self, m: &Mod) -> hir::Mod { @@ -1650,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/mod.rs b/src/librustc/hir/mod.rs index 9dac6fac100..9f5ff6914b0 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1259,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, + } } } @@ -1584,7 +1594,6 @@ pub struct ImplItemRef { pub span: Span, pub vis: Visibility, pub defaultness: Defaultness, - pub has_value: bool, } #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 5a381a189fc..807bbec3b58 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1036,8 +1036,9 @@ impl<'a> State<'a> { 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/traits/project.rs b/src/librustc/traits/project.rs index ac2f3ad9b89..ca7d2ac3c69 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() }; @@ -1304,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 9984dd42f56..f5c23401a4e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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() } @@ -2180,8 +2179,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { name: trait_item.name, kind: kind, vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self), - defaultness: hir::Defaultness::Default, - has_value: has_value, + defaultness: hir::Defaultness::Default { has_value: has_value }, def_id: def_id, container: TraitContainer(parent_def_id), method_has_self_argument: has_self @@ -2211,7 +2209,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { kind: kind, vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self), defaultness: impl_item_ref.defaultness, - has_value: true, def_id: def_id, container: ImplContainer(parent_def_id), method_has_self_argument: has_self diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 318cc83d9ad..fa2eff817ea 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, @@ -693,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_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ba85544326f..6dbcfc8523d 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 2d96eeb8f20..d1508d7e9b3 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -460,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 { @@ -501,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 @@ -530,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 { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index d7a5f7ad715..7553b2e05a7 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_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4fb11509a1c..778f0184141 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_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2197ecc10a1..d2939316219 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1110,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 { @@ -1144,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 066b3d4be08..2c55e8fbfd2 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/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index 1572d04f68c..9f5b73d9b30 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -118,7 +118,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .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.has_value + item.kind == ty::AssociatedKind::Type && item.defaultness.has_value() }) .flat_map(|def_id| { ctp::parameters_for(&ccx.tcx.item_type(def_id), true) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e8367bca2ef..185f897c1ba 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 4d70c64634f..a141d0e4788 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/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs new file mode 100644 index 00000000000..f7a390e8745 --- /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) { } +} + From b8116dabdaf5952ce676239b1e2d0a7684ce0c34 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 14 Nov 2016 18:23:07 -0500 Subject: [PATCH 15/18] fix oversight in closure translation (Unrelated to this PR series) --- src/librustc_trans/callee.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index a7553ce4995..df56e27128c 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 for {:?}, found {}", def_id, 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) { From 4e844ad1e5d0f62cfac00ad0c0f50474d99331f7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 14 Nov 2016 21:02:29 -0500 Subject: [PATCH 16/18] fix change_private_impl_method_cc test --- .../incremental/change_private_impl_method_cc/struct_point.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 a8779e3f92d..bb7f7025c59 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 @@ -21,9 +21,7 @@ #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] #![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] - -// FIXME(#37333) the struct fields get entangled with inherent methods -#![rustc_partition_translated(module="struct_point-fn_make_struct", 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")] From ab79438d68dbc79da41fd97b2ffc3238d039b02d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 17 Nov 2016 12:44:46 -0500 Subject: [PATCH 17/18] canonicalize base incremental path on windows This sidesteps problems with long paths because the canonical path includes the "magic long path prefix" on Windows. --- src/librustc_incremental/persist/fs.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 223200957cb..2572a9c1d78 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 { From c938007f90711d6acc8b55e15a5e3cf7cc147e91 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 17 Nov 2016 15:12:43 -0500 Subject: [PATCH 18/18] add test for hashing trait impls --- src/test/incremental/hashes/trait_impls.rs | 404 +++++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 src/test/incremental/hashes/trait_impls.rs diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs new file mode 100644 index 00000000000..500aaf52324 --- /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) { } +} +