diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 33133f6834b9a..df6507c442fbd 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -80,6 +80,7 @@ pub enum DepNode { TransCrateItem(D), TransInlinedItem(D), TransWriteMetadata, + CrateVariances, // Nodes representing bits of computed IR in the tcx. Each shared // table in the tcx (or elsewhere) maps to one of these @@ -88,6 +89,7 @@ pub enum DepNode { // predicates for an item wind up in `ItemSignature`). AssociatedItems(D), ItemSignature(D), + ItemVariances(D), IsForeignItem(D), TypeParamPredicates((D, D)), SizedConstraint(D), @@ -195,6 +197,7 @@ impl DepNode { TypeckBodiesKrate => Some(TypeckBodiesKrate), RegionResolveCrate => Some(RegionResolveCrate), Coherence => Some(Coherence), + CrateVariances => Some(CrateVariances), Resolve => Some(Resolve), Variance => Some(Variance), PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)), @@ -224,6 +227,7 @@ impl DepNode { TransInlinedItem(ref d) => op(d).map(TransInlinedItem), AssociatedItems(ref d) => op(d).map(AssociatedItems), ItemSignature(ref d) => op(d).map(ItemSignature), + ItemVariances(ref d) => op(d).map(ItemVariances), IsForeignItem(ref d) => op(d).map(IsForeignItem), TypeParamPredicates((ref item, ref param)) => { Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param))))) diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index a9f0a44e4208c..809bed939f54c 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -18,7 +18,6 @@ mod raii; mod safe; mod shadow; mod thread; -mod visit; pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig}; pub use self::dep_node::DepNode; @@ -28,6 +27,4 @@ pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; pub use self::safe::AssertDepGraphSafe; pub use self::safe::DepGraphSafe; -pub use self::visit::visit_all_bodies_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 deleted file mode 100644 index 93f6e3a83a0c2..0000000000000 --- a/src/librustc/dep_graph/visit.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 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 hir; -use hir::def_id::DefId; -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_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>, - dep_node_fn: &'visit mut F, - visitor: &'visit mut V, - } - - 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.hir.local_def_id(i.id); - let task_id = (self.dep_node_fn)(item_def_id); - let _task = self.tcx.dep_graph.in_task(task_id.clone()); - debug!("Started task {:?}", task_id); - self.tcx.dep_graph.read(DepNode::Hir(item_def_id)); - self.visitor.visit_item(i); - debug!("Ended task {:?}", task_id); - } - - fn visit_trait_item(&mut self, i: &'tcx hir::TraitItem) { - let trait_item_def_id = self.tcx.hir.local_def_id(i.id); - let task_id = (self.dep_node_fn)(trait_item_def_id); - let _task = self.tcx.dep_graph.in_task(task_id.clone()); - debug!("Started task {:?}", task_id); - self.tcx.dep_graph.read(DepNode::Hir(trait_item_def_id)); - self.visitor.visit_trait_item(i); - debug!("Ended task {:?}", task_id); - } - - fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) { - let impl_item_def_id = self.tcx.hir.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); - self.tcx.dep_graph.read(DepNode::Hir(impl_item_def_id)); - self.visitor.visit_impl_item(i); - debug!("Ended task {:?}", task_id); - } - } - - let krate = tcx.dep_graph.with_ignore(|| tcx.hir.krate()); - let mut tracking_visitor = TrackingVisitor { - tcx: tcx, - dep_node_fn: &mut dep_node_fn, - visitor: visitor, - }; - krate.visit_all_item_likes(&mut tracking_visitor) -} - -pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C) - where C: Fn(/* body_owner */ - DefId, - /* body id */ - hir::BodyId) -{ - let krate = tcx.hir.krate(); - for &body_id in &krate.body_ids { - let body_owner_def_id = tcx.hir.body_owner_def_id(body_id); - callback(body_owner_def_id, body_id); - } -} diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2b0d53b2bc356..a6f1e0d0e055f 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -88,7 +88,7 @@ pub enum NestedVisitorMap<'this, 'tcx: 'this> { /// that are inside of an item-like. /// /// **This is the most common choice.** A very commmon pattern is - /// to use `tcx.visit_all_item_likes_in_krate()` as an outer loop, + /// to use `visit_all_item_likes()` as an outer loop, /// and to have the visitor that visits the contents of each item /// using this setting. OnlyBodies(&'this Map<'tcx>), diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs index 0d79017066b01..ce1a34faf5ee8 100644 --- a/src/librustc/hir/itemlikevisit.rs +++ b/src/librustc/hir/itemlikevisit.rs @@ -19,9 +19,8 @@ use super::intravisit::Visitor; /// /// 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()`. +/// - How: Implement `ItemLikeVisitor` and call `tcx.hir.krate().visit_all_item_likes()`. /// - 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". @@ -30,7 +29,7 @@ use super::intravisit::Visitor; /// 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 +/// `tcx.hir.krate().visit_all_item_likes(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. diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index b20ac8ddbfc8a..830fc63115cef 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -461,9 +461,6 @@ pub struct GlobalCtxt<'tcx> { pub lang_items: middle::lang_items::LanguageItems, - /// True if the variance has been computed yet; false otherwise. - pub variance_computed: Cell, - /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not /// present in this set can be warned about. pub used_unsafe: RefCell, @@ -715,7 +712,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { types: common_types, named_region_map: named_region_map, region_maps: region_maps, - variance_computed: Cell::new(false), trait_map: resolutions.trait_map, export_map: resolutions.export_map, fulfilled_predicates: RefCell::new(fulfilled_predicates), diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 4595a8c4f7784..c72f87c7e326c 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -209,6 +209,12 @@ impl<'tcx> QueryDescription for queries::crate_inherent_impls_overlap_check<'tcx } } +impl<'tcx> QueryDescription for queries::crate_variances<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("computing the variances for items in this crate") + } +} + impl<'tcx> QueryDescription for queries::mir_shims<'tcx> { fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String { format!("generating MIR shim for `{}`", @@ -409,9 +415,13 @@ define_maps! { <'tcx> /// True if this is a foreign item (i.e., linked via `extern { ... }`). pub is_foreign_item: IsForeignItem(DefId) -> bool, + /// Get a map with the variance of every item; use `item_variance` + /// instead. + pub crate_variances: crate_variances(CrateNum) -> Rc, + /// Maps from def-id of a type or region parameter to its /// (inferred) variance. - pub variances: ItemSignature(DefId) -> Rc>, + pub item_variances: ItemVariances(DefId) -> Rc>, /// Maps from an impl/trait def-id to a list of the def-ids of its items pub associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc>, @@ -507,3 +517,7 @@ fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode { fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode { DepNode::ConstEval(def_id) } + +fn crate_variances(_: CrateNum) -> DepNode { + DepNode::CrateVariances +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 352b6ab1d356f..7e4d7fda22aeb 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -15,7 +15,7 @@ pub use self::IntVarValue::*; pub use self::LvaluePreference::*; pub use self::fold::TypeFoldable; -use dep_graph::{self, DepNode}; +use dep_graph::DepNode; use hir::{map as hir_map, FreevarMap, TraitMap}; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -54,9 +54,9 @@ use rustc_const_math::ConstInt; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; +use rustc_data_structures::transitive_relation::TransitiveRelation; use hir; -use hir::itemlikevisit::ItemLikeVisitor; pub use self::sty::{Binder, DebruijnIndex}; pub use self::sty::{FnSig, PolyFnSig}; @@ -306,6 +306,27 @@ pub enum Variance { Bivariant, // T <: T -- e.g., unused type parameter } +/// The crate variances map is computed during typeck and contains the +/// variance of every item in the local crate. You should not use it +/// directly, because to do so will make your pass dependent on the +/// HIR of every item in the local crate. Instead, use +/// `tcx.item_variances()` to get the variance for a *particular* +/// item. +pub struct CrateVariancesMap { + /// This relation tracks the dependencies between the variance of + /// various items. In particular, if `a < b`, then the variance of + /// `a` depends on the sources of `b`. + pub dependencies: TransitiveRelation, + + /// For each item with generics, maps to a vector of the variance + /// of its generics. If an item has no generics, it will have no + /// entry. + pub variances: FxHashMap>>, + + /// An empty vector, useful for cloning. + pub empty_variance: Rc>, +} + #[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)] pub struct MethodCallee<'tcx> { /// Impl method ID, for inherent methods, or trait method ID, otherwise. @@ -2400,7 +2421,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn item_variances(self, item_id: DefId) -> Rc> { - queries::variances::get(self, DUMMY_SP, item_id) + queries::item_variances::get(self, DUMMY_SP, item_id) } pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool { @@ -2589,14 +2610,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_region(ty::ReScope(self.region_maps.node_extent(id))) } - 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_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor); - } - /// Invokes `callback` for each body in the krate. This will /// create a read edge from `DepNode::Krate` to the current task; /// it is meant to be run in the context of some global task like @@ -2605,7 +2618,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn visit_all_bodies_in_krate(self, callback: C) where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), { - dep_graph::visit_all_bodies_in_krate(self.global_tcx(), callback) + let krate = self.hir.krate(); + for &body_id in &krate.body_ids { + let body_owner_def_id = self.hir.body_owner_def_id(body_id); + callback(body_owner_def_id, body_id); + } } /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index cef24d44d6875..7f2943fcb3c69 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -124,14 +124,8 @@ fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, a_subst, b_subst); - let variances; - let opt_variances = if relation.tcx().variance_computed.get() { - variances = relation.tcx().item_variances(item_def_id); - Some(&*variances) - } else { - None - }; - relate_substs(relation, opt_variances, a_subst, b_subst) + let opt_variances = relation.tcx().item_variances(item_def_id); + relate_substs(relation, Some(&opt_variances), a_subst, b_subst) } pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 2631108aeb5fa..3acbcd4eaa274 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -9,21 +9,23 @@ // except according to those terms. use bitvec::BitMatrix; -use stable_hasher::{HashStable, StableHasher, StableHasherResult}; +use fx::FxHashMap; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; +use stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::cell::RefCell; use std::fmt::Debug; +use std::hash::Hash; use std::mem; - #[derive(Clone)] -pub struct TransitiveRelation { - // List of elements. This is used to map from a T to a usize. We - // expect domain to be small so just use a linear list versus a - // hashmap or something. +pub struct TransitiveRelation { + // List of elements. This is used to map from a T to a usize. elements: Vec, + // Maps each element to an index. + map: FxHashMap, + // List of base edges in the graph. Require to compute transitive // closure. edges: Vec, @@ -40,19 +42,20 @@ pub struct TransitiveRelation { closure: RefCell>, } -#[derive(Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] struct Index(usize); -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] struct Edge { source: Index, target: Index, } -impl TransitiveRelation { +impl TransitiveRelation { pub fn new() -> TransitiveRelation { TransitiveRelation { elements: vec![], + map: FxHashMap(), edges: vec![], closure: RefCell::new(None), } @@ -63,21 +66,27 @@ impl TransitiveRelation { } fn index(&self, a: &T) -> Option { - self.elements.iter().position(|e| *e == *a).map(Index) + self.map.get(a).cloned() } fn add_index(&mut self, a: T) -> Index { - match self.index(&a) { - Some(i) => i, - None => { - self.elements.push(a); - - // if we changed the dimensions, clear the cache - *self.closure.borrow_mut() = None; - - Index(self.elements.len() - 1) - } - } + let &mut TransitiveRelation { + ref mut elements, + ref closure, + ref mut map, + .. + } = self; + + map.entry(a.clone()) + .or_insert_with(|| { + elements.push(a); + + // if we changed the dimensions, clear the cache + *closure.borrow_mut() = None; + + Index(elements.len() - 1) + }) + .clone() } /// Indicate that `a < b` (where `<` is this relation) @@ -104,6 +113,20 @@ impl TransitiveRelation { } } + /// Returns a vector of all things less than `a`. + /// + /// Really this probably ought to be `impl Iterator`, but + /// I'm too lazy to make that work, and -- given the caching + /// strategy -- it'd be a touch tricky anyhow. + pub fn less_than(&self, a: &T) -> Vec<&T> { + match self.index(a) { + Some(a) => self.with_closure(|closure| { + closure.iter(a.0).map(|i| &self.elements[i]).collect() + }), + None => vec![], + } + } + /// Picks what I am referring to as the "postdominating" /// upper-bound for `a` and `b`. This is usually the least upper /// bound, but in cases where there is no single least upper @@ -314,7 +337,7 @@ fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { } impl Encodable for TransitiveRelation - where T: Encodable + Debug + PartialEq + where T: Clone + Encodable + Debug + Eq + Hash + Clone { fn encode(&self, s: &mut E) -> Result<(), E::Error> { s.emit_struct("TransitiveRelation", 2, |s| { @@ -326,19 +349,23 @@ impl Encodable for TransitiveRelation } impl Decodable for TransitiveRelation - where T: Decodable + Debug + PartialEq + where T: Clone + Decodable + Debug + Eq + Hash + Clone { fn decode(d: &mut D) -> Result { d.read_struct("TransitiveRelation", 2, |d| { - let elements = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?; + let elements: Vec = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?; let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?; - Ok(TransitiveRelation { elements, edges, closure: RefCell::new(None) }) + let map = elements.iter() + .enumerate() + .map(|(index, elem)| (elem.clone(), Index(index))) + .collect(); + Ok(TransitiveRelation { elements, edges, map, closure: RefCell::new(None) }) }) } } impl HashStable for TransitiveRelation - where T: HashStable + PartialEq + Debug + where T: HashStable + Eq + Debug + Clone + Hash { fn hash_stable(&self, hcx: &mut CTX, @@ -348,6 +375,8 @@ impl HashStable for TransitiveRelation let TransitiveRelation { ref elements, ref edges, + // "map" is just a copy of elements vec + map: _, // "closure" is just a copy of the data above closure: _ } = *self; diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 9e6a45e7f8b7c..9b0724ff65c4b 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -81,7 +81,7 @@ provide! { <'tcx> tcx, def_id, cdata let _ = cdata; tcx.calculate_dtor(def_id, &mut |_,_| Ok(())) } - variances => { Rc::new(cdata.get_item_variances(def_id.index)) } + item_variances => { Rc::new(cdata.get_item_variances(def_id.index)) } associated_item_def_ids => { let mut result = vec![]; cdata.each_child_of_item(def_id.index, |child| result.push(child.def.def_id())); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0754b52cf280a..3e8f6c91d2073 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -293,6 +293,7 @@ pub fn provide(providers: &mut Providers) { collect::provide(providers); coherence::provide(providers); check::provide(providers); + variance::provide(providers); } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) @@ -307,9 +308,6 @@ 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(tcx)); diff --git a/src/librustc_typeck/variance/README.md b/src/librustc_typeck/variance/README.md index ac785e4058bde..9ec20c1a45c34 100644 --- a/src/librustc_typeck/variance/README.md +++ b/src/librustc_typeck/variance/README.md @@ -97,51 +97,29 @@ types involved before considering variance. #### Dependency graph management -Because variance works in two phases, if we are not careful, we wind -up with a muddled mess of a dep-graph. Basically, when gathering up -the constraints, things are fairly well-structured, but then we do a -fixed-point iteration and write the results back where they -belong. You can't give this fixed-point iteration a single task -because it reads from (and writes to) the variance of all types in the -crate. In principle, we *could* switch the "current task" in a very -fine-grained way while propagating constraints in the fixed-point -iteration and everything would be automatically tracked, but that -would add some overhead and isn't really necessary anyway. - -Instead what we do is to add edges into the dependency graph as we -construct the constraint set: so, if computing the constraints for -node `X` requires loading the inference variables from node `Y`, then -we can add an edge `Y -> X`, since the variance we ultimately infer -for `Y` will affect the variance we ultimately infer for `X`. - -At this point, we've basically mirrored the inference graph in the -dependency graph. This means we can just completely ignore the -fixed-point iteration, since it is just shuffling values along this -graph. In other words, if we added the fine-grained switching of tasks -I described earlier, all it would show is that we repeatedly read the -values described by the constraints, but those edges were already -added when building the constraints in the first place. - -Here is how this is implemented (at least as of the time of this -writing). The associated `DepNode` for the variance map is (at least -presently) `Signature(DefId)`. This means that, in `constraints.rs`, -when we visit an item to load up its constraints, we set -`Signature(DefId)` as the current task (the "memoization" pattern -described in the `dep-graph` README). Then whenever we find an -embedded type or trait, we add a synthetic read of `Signature(DefId)`, -which covers the variances we will compute for all of its -parameters. This read is synthetic (i.e., we call -`variance_map.read()`) because, in fact, the final variance is not yet -computed -- the read *will* occur (repeatedly) during the fixed-point -iteration phase. - -In fact, we don't really *need* this synthetic read. That's because we -do wind up looking up the `TypeScheme` or `TraitDef` for all -references types/traits, and those reads add an edge from -`Signature(DefId)` (that is, they share the same dep node as -variance). However, I've kept the synthetic reads in place anyway, -just for future-proofing (in case we change the dep-nodes in the -future), and because it makes the intention a bit clearer I think. +Because variance is a whole-crate inference, its dependency graph +can become quite muddled if we are not careful. To resolve this, we refactor +into two queries: + +- `crate_variances` computes the variance for all items in the current crate. +- `item_variances` accesses the variance for an individual reading; it + works by requesting `crate_variances` and extracting the relevant data. + +If you limit yourself to reading `item_variances`, your code will only +depend then on the inference inferred for that particular item. + +Eventually, the goal is to rely on the red-green dependency management +algorithm. At the moment, however, we rely instead on a hack, where +`item_variances` ignores the dependencies of accessing +`crate_variances` and instead computes the *correct* dependencies +itself. To this end, when we build up the constraints in the system, +we also built up a transitive `dependencies` relation as part of the +crate map. A `(X, Y)` pair is added to the map each time we have a +constraint that the variance of some inferred for the item `X` depends +on the variance of some element of `Y`. This is to some extent a +mirroring of the inference graph in the dependency graph. This means +we can just completely ignore the fixed-point iteration, since it is +just shuffling values along this graph. ### Addendum: Variance on traits diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 1bde1eea37c39..900f16968b0b4 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -22,12 +22,12 @@ use syntax::ast; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc_data_structures::transitive_relation::TransitiveRelation; + use super::terms::*; use super::terms::VarianceTerm::*; use super::xform::*; -use dep_graph::DepNode::ItemSignature as VarianceDepNode; - pub struct ConstraintContext<'a, 'tcx: 'a> { pub terms_cx: TermsContext<'a, 'tcx>, @@ -38,6 +38,11 @@ pub struct ConstraintContext<'a, 'tcx: 'a> { bivariant: VarianceTermPtr<'a>, pub constraints: Vec>, + + /// This relation tracks the dependencies between the variance of + /// various items. In particular, if `a < b`, then the variance of + /// `a` depends on the sources of `b`. + pub dependencies: TransitiveRelation, } /// Declares that the variable `decl_id` appears in a location with @@ -48,6 +53,20 @@ pub struct Constraint<'a> { pub variance: &'a VarianceTerm<'a>, } +/// To build constriants, we visit one item (type, trait) at a time +/// and look at its contents. So e.g. if we have +/// +/// struct Foo { +/// b: Bar +/// } +/// +/// then while we are visiting `Bar`, the `CurrentItem` would have +/// the def-id and generics of `Foo`. +pub struct CurrentItem<'a> { + def_id: DefId, + generics: &'a ty::Generics, +} + pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>) -> ConstraintContext<'a, 'tcx> { let tcx = terms_cx.tcx; @@ -62,10 +81,11 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>) invariant: invariant, bivariant: bivariant, constraints: Vec::new(), + dependencies: TransitiveRelation::new(), }; // See README.md for a discussion on dep-graph management. - tcx.visit_all_item_likes_in_krate(VarianceDepNode, &mut constraint_cx); + tcx.hir.krate().visit_all_item_likes(&mut constraint_cx); constraint_cx } @@ -73,7 +93,7 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'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.hir.local_def_id(item.id); + let def_id = tcx.hir.local_def_id(item.id); debug!("visit_item item={}", tcx.hir.node_to_string(item.id)); @@ -81,7 +101,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { - let generics = tcx.item_generics(did); + let generics = tcx.item_generics(def_id); + let current_item = &CurrentItem { def_id, generics }; // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion @@ -89,23 +110,14 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { // // self.add_constraints_from_generics(generics); - for field in tcx.lookup_adt_def(did).all_fields() { - self.add_constraints_from_ty(generics, + for field in tcx.lookup_adt_def(def_id).all_fields() { + self.add_constraints_from_ty(current_item, tcx.item_type(field.did), self.covariant); } } - hir::ItemTrait(..) => { - let generics = tcx.item_generics(did); - let trait_ref = ty::TraitRef { - def_id: did, - substs: Substs::identity_for_item(tcx, did) - }; - self.add_constraints_from_trait_ref(generics, - trait_ref, - self.invariant); - } + hir::ItemTrait(..) | hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemStatic(..) | @@ -140,14 +152,19 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.terms_cx.tcx } - fn inferred_index(&self, param_id: ast::NodeId) -> InferredIndex { - match self.terms_cx.inferred_map.get(¶m_id) { - Some(&index) => index, - None => { - bug!("no inferred index entry for {}", - self.tcx().hir.node_to_string(param_id)); - } + /// Load the generics for another item, adding a corresponding + /// relation into the dependencies to indicate that the variance + /// for `current` relies on `def_id`. + fn read_generics(&mut self, current: &CurrentItem, def_id: DefId) -> &'tcx ty::Generics { + let generics = self.tcx().item_generics(def_id); + if self.tcx().dep_graph.is_fully_enabled() { + self.dependencies.add(current.def_id, def_id); } + generics + } + + fn opt_inferred_index(&self, param_id: ast::NodeId) -> Option<&InferredIndex> { + self.terms_cx.inferred_map.get(¶m_id) } fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId { @@ -228,8 +245,27 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // Parameter on an item defined within current crate: // variance not yet inferred, so return a symbolic // variance. - let InferredIndex(index) = self.inferred_index(param_node_id); - self.terms_cx.inferred_infos[index].term + if let Some(&InferredIndex(index)) = self.opt_inferred_index(param_node_id) { + self.terms_cx.inferred_infos[index].term + } else { + // If there is no inferred entry for a type parameter, + // it must be declared on a (locally defiend) trait -- they don't + // get inferreds because they are always invariant. + if cfg!(debug_assertions) { + let item_node_id = self.tcx().hir.as_local_node_id(item_def_id).unwrap(); + let item = self.tcx().hir.expect_item(item_node_id); + let success = match item.node { + hir::ItemTrait(..) => true, + _ => false, + }; + if !success { + bug!("parameter {:?} has no inferred, but declared on non-trait: {:?}", + item_def_id, + item); + } + } + self.invariant + } } else { // Parameter on an item defined within another crate: // variance already inferred, just look it up. @@ -279,7 +315,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } fn add_constraints_from_trait_ref(&mut self, - generics: &ty::Generics, + current: &CurrentItem, trait_ref: ty::TraitRef<'tcx>, variance: VarianceTermPtr<'a>) { debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}", @@ -288,12 +324,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let trait_generics = self.tcx().item_generics(trait_ref.def_id); - // This edge is actually implied by the call to - // `lookup_trait_def`, but I'm trying to be future-proof. See - // README.md for a discussion on dep-graph management. - self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id)); - - self.add_constraints_from_substs(generics, + self.add_constraints_from_substs(current, trait_ref.def_id, &trait_generics.types, &trait_generics.regions, @@ -305,7 +336,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { /// in a context with the generics defined in `generics` and /// ambient variance `variance` fn add_constraints_from_ty(&mut self, - generics: &ty::Generics, + current: &CurrentItem, ty: Ty<'tcx>, variance: VarianceTermPtr<'a>) { debug!("add_constraints_from_ty(ty={:?}, variance={:?})", @@ -325,34 +356,29 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyRef(region, ref mt) => { let contra = self.contravariant(variance); - self.add_constraints_from_region(generics, region, contra); - self.add_constraints_from_mt(generics, mt, variance); + self.add_constraints_from_region(current, region, contra); + self.add_constraints_from_mt(current, mt, variance); } ty::TyArray(typ, _) | ty::TySlice(typ) => { - self.add_constraints_from_ty(generics, typ, variance); + self.add_constraints_from_ty(current, typ, variance); } ty::TyRawPtr(ref mt) => { - self.add_constraints_from_mt(generics, mt, variance); + self.add_constraints_from_mt(current, mt, variance); } ty::TyTuple(subtys, _) => { for &subty in subtys { - self.add_constraints_from_ty(generics, subty, variance); + self.add_constraints_from_ty(current, subty, variance); } } ty::TyAdt(def, substs) => { - let adt_generics = self.tcx().item_generics(def.did); - - // This edge is actually implied by the call to - // `lookup_trait_def`, but I'm trying to be future-proof. See - // README.md for a discussion on dep-graph management. - self.tcx().dep_graph.read(VarianceDepNode(def.did)); + let adt_generics = self.read_generics(current, def.did); - self.add_constraints_from_substs(generics, + self.add_constraints_from_substs(current, def.did, &adt_generics.types, &adt_generics.regions, @@ -364,12 +390,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let trait_ref = &data.trait_ref; let trait_generics = self.tcx().item_generics(trait_ref.def_id); - // This edge is actually implied by the call to - // `lookup_trait_def`, but I'm trying to be future-proof. See - // README.md for a discussion on dep-graph management. - self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id)); - - self.add_constraints_from_substs(generics, + self.add_constraints_from_substs(current, trait_ref.def_id, &trait_generics.types, &trait_generics.regions, @@ -380,25 +401,25 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyDynamic(ref data, r) => { // The type `Foo` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); - self.add_constraints_from_region(generics, r, contra); + self.add_constraints_from_region(current, r, contra); if let Some(p) = data.principal() { let poly_trait_ref = p.with_self_ty(self.tcx(), self.tcx().types.err); - self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance); + self.add_constraints_from_trait_ref(current, poly_trait_ref.0, variance); } for projection in data.projection_bounds() { - self.add_constraints_from_ty(generics, projection.0.ty, self.invariant); + self.add_constraints_from_ty(current, projection.0.ty, self.invariant); } } ty::TyParam(ref data) => { - assert_eq!(generics.parent, None); + assert_eq!(current.generics.parent, None); let mut i = data.idx as usize; - if !generics.has_self || i > 0 { - i -= generics.regions.len(); + if !current.generics.has_self || i > 0 { + i -= current.generics.regions.len(); } - let def_id = generics.types[i].def_id; + let def_id = current.generics.types[i].def_id; let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap(); match self.terms_cx.inferred_map.get(&node_id) { Some(&index) => { @@ -414,7 +435,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => { - self.add_constraints_from_sig(generics, sig, variance); + self.add_constraints_from_sig(current, sig, variance); } ty::TyError => { @@ -433,7 +454,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { /// Adds constraints appropriate for a nominal type (enum, struct, /// object, etc) appearing in a context with ambient variance `variance` fn add_constraints_from_substs(&mut self, - generics: &ty::Generics, + current: &CurrentItem, def_id: DefId, type_param_defs: &[ty::TypeParameterDef], region_param_defs: &[ty::RegionParameterDef], @@ -451,44 +472,44 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}", variance_decl, variance_i); - self.add_constraints_from_ty(generics, substs_ty, variance_i); + self.add_constraints_from_ty(current, substs_ty, variance_i); } for p in region_param_defs { let variance_decl = self.declared_variance(p.def_id, def_id, p.index as usize); let variance_i = self.xform(variance, variance_decl); let substs_r = substs.region_for_def(p); - self.add_constraints_from_region(generics, substs_r, variance_i); + self.add_constraints_from_region(current, substs_r, variance_i); } } /// Adds constraints appropriate for a function with signature /// `sig` appearing in a context with ambient variance `variance` fn add_constraints_from_sig(&mut self, - generics: &ty::Generics, + current: &CurrentItem, sig: ty::PolyFnSig<'tcx>, variance: VarianceTermPtr<'a>) { let contra = self.contravariant(variance); for &input in sig.0.inputs() { - self.add_constraints_from_ty(generics, input, contra); + self.add_constraints_from_ty(current, input, contra); } - self.add_constraints_from_ty(generics, sig.0.output(), variance); + self.add_constraints_from_ty(current, sig.0.output(), variance); } /// Adds constraints appropriate for a region appearing in a /// context with ambient variance `variance` fn add_constraints_from_region(&mut self, - generics: &ty::Generics, + current: &CurrentItem, region: &'tcx ty::Region, variance: VarianceTermPtr<'a>) { match *region { ty::ReEarlyBound(ref data) => { - assert_eq!(generics.parent, None); - let i = data.index as usize - generics.has_self as usize; - let def_id = generics.regions[i].def_id; + assert_eq!(current.generics.parent, None); + let i = data.index as usize - current.generics.has_self as usize; + let def_id = current.generics.regions[i].def_id; let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap(); if self.is_to_be_inferred(node_id) { - let index = self.inferred_index(node_id); + let &index = self.opt_inferred_index(node_id).unwrap(); self.add_constraint(index, variance); } } @@ -518,17 +539,17 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { /// Adds constraints appropriate for a mutability-type pair /// appearing in a context with ambient variance `variance` fn add_constraints_from_mt(&mut self, - generics: &ty::Generics, + current: &CurrentItem, mt: &ty::TypeAndMut<'tcx>, variance: VarianceTermPtr<'a>) { match mt.mutbl { hir::MutMutable => { let invar = self.invariant(variance); - self.add_constraints_from_ty(generics, mt.ty, invar); + self.add_constraints_from_ty(current, mt.ty, invar); } hir::MutImmutable => { - self.add_constraints_from_ty(generics, mt.ty, variance); + self.add_constraints_from_ty(current, mt.ty, variance); } } } diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index cd0ab1cbb9543..79f9ec18fec3a 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -12,7 +12,13 @@ //! parameters. See README.md for details. use arena; -use rustc::ty::TyCtxt; +use rustc::dep_graph::DepNode; +use rustc::hir; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc::ty::{self, CrateVariancesMap, TyCtxt}; +use rustc::ty::maps::Providers; +use std::rc::Rc; +use syntax_pos::DUMMY_SP; /// Defines the `TermsContext` basically houses an arena where we can /// allocate terms. @@ -27,10 +33,62 @@ mod solve; /// Code for transforming variances. mod xform; -pub fn infer_variance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { +pub fn provide(providers: &mut Providers) { + *providers = Providers { + item_variances, + crate_variances, + ..*providers + }; +} + +fn crate_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) + -> Rc { + assert_eq!(crate_num, LOCAL_CRATE); let mut arena = arena::TypedArena::new(); let terms_cx = terms::determine_parameters_to_be_inferred(tcx, &mut arena); let constraints_cx = constraints::add_constraints_from_crate(terms_cx); - solve::solve_constraints(constraints_cx); - tcx.variance_computed.set(true); + Rc::new(solve::solve_constraints(constraints_cx)) +} + +fn item_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) + -> Rc> { + let item_id = tcx.hir.as_local_node_id(item_def_id).expect("expected local def-id"); + let item = tcx.hir.expect_item(item_id); + match item.node { + hir::ItemTrait(..) => { + // Traits are always invariant. + let generics = tcx.item_generics(item_def_id); + assert!(generics.parent.is_none()); + Rc::new(vec![ty::Variance::Invariant; generics.count()]) + } + + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) => { + // Everything else must be inferred. + + // Lacking red/green, we read the variances for all items here + // but ignore the dependencies, then re-synthesize the ones we need. + let crate_map = tcx.dep_graph.with_ignore(|| { + ty::queries::crate_variances::get(tcx, DUMMY_SP, LOCAL_CRATE) + }); + tcx.dep_graph.read(DepNode::Hir(item_def_id)); + for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) { + if dep_def_id.is_local() { + tcx.dep_graph.read(DepNode::Hir(dep_def_id)); + } else { + tcx.dep_graph.read(DepNode::ItemVariances(dep_def_id)); + } + } + + crate_map.variances.get(&item_def_id) + .unwrap_or(&crate_map.empty_variance) + .clone() + } + + _ => { + // Variance not relevant. + span_bug!(item.span, "asked to compute variance for wrong kind of item") + } + } } diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index 6628c7c521fd1..5ba5005ccc210 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -15,7 +15,9 @@ //! optimal solution to the constraints. The final variance for each //! inferred is then written into the `variance_map` in the tcx. +use rustc::hir::def_id::DefId; use rustc::ty; +use rustc_data_structures::fx::FxHashMap; use std::rc::Rc; use super::constraints::*; @@ -31,8 +33,8 @@ struct SolveContext<'a, 'tcx: 'a> { solutions: Vec, } -pub fn solve_constraints(constraints_cx: ConstraintContext) { - let ConstraintContext { terms_cx, constraints, .. } = constraints_cx; +pub fn solve_constraints(constraints_cx: ConstraintContext) -> ty::CrateVariancesMap { + let ConstraintContext { terms_cx, dependencies, constraints, .. } = constraints_cx; let solutions = terms_cx.inferred_infos .iter() @@ -45,7 +47,10 @@ pub fn solve_constraints(constraints_cx: ConstraintContext) { solutions: solutions, }; solutions_cx.solve(); - solutions_cx.write(); + let variances = solutions_cx.create_map(); + let empty_variance = Rc::new(Vec::new()); + + ty::CrateVariancesMap { dependencies, variances, empty_variance } } impl<'a, 'tcx> SolveContext<'a, 'tcx> { @@ -83,7 +88,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { } } - fn write(&self) { + fn create_map(&self) -> FxHashMap>> { // Collect all the variances for a particular item and stick // them into the variance map. We rely on the fact that we // generate all the inferreds for a particular item @@ -95,11 +100,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { let tcx = self.terms_cx.tcx; - // Ignore the writes here because the relevant edges were - // already accounted for in `constraints.rs`. See the section - // on dependency graph management in README.md for more - // information. - let _ignore = tcx.dep_graph.in_ignore(); + let mut map = FxHashMap(); let solutions = &self.solutions; let inferred_infos = &self.terms_cx.inferred_infos; @@ -137,10 +138,10 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { item_variances); } - tcx.maps.variances - .borrow_mut() - .insert(item_def_id, Rc::new(item_variances)); + map.insert(item_def_id, Rc::new(item_variances)); } + + map } fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance { diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 890414e317c62..ad787c57e76f2 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -32,8 +32,6 @@ use self::VarianceTerm::*; pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>; -use dep_graph::DepNode::ItemSignature as VarianceDepNode; - #[derive(Copy, Clone, Debug)] pub struct InferredIndex(pub usize); @@ -109,7 +107,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_item_likes_in_krate(|def_id| VarianceDepNode(def_id), &mut terms_cx); + tcx.hir.krate().visit_all_item_likes(&mut terms_cx); terms_cx } @@ -139,7 +137,6 @@ fn lang_items(tcx: TyCtxt) -> Vec<(ast::NodeId, Vec)> { impl<'a, 'tcx> TermsContext<'a, 'tcx> { fn add_inferreds_for_item(&mut self, item_id: ast::NodeId, - has_self: bool, generics: &hir::Generics) { //! Add "inferreds" for the generic parameters declared on this //! item. This has a lot of annoying parameters because we are @@ -149,39 +146,17 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { //! // NB: In the code below for writing the results back into the - // tcx, we rely on the fact that all inferreds for a particular - // item are assigned continuous indices. - - let inferreds_on_entry = self.num_inferred(); - - if has_self { - self.add_inferred(item_id, 0, item_id); - } + // `CrateVariancesMap`, we rely on the fact that all inferreds + // for a particular item are assigned continuous indices. - for (i, p) in generics.lifetimes.iter().enumerate() { + for (p, i) in generics.lifetimes.iter().zip(0..) { let id = p.lifetime.id; - let i = has_self as usize + i; self.add_inferred(item_id, i, id); } - for (i, p) in generics.ty_params.iter().enumerate() { - let i = has_self as usize + generics.lifetimes.len() + i; + for (p, i) in generics.ty_params.iter().zip(generics.lifetimes.len()..) { self.add_inferred(item_id, i, p.id); } - - // If this item has no type or lifetime parameters, - // then there are no variances to infer, so just - // insert an empty entry into the variance map. - // Arguably we could just leave the map empty in this - // case but it seems cleaner to be able to distinguish - // "invalid item id" from "item id with no - // parameters". - if self.num_inferred() == inferreds_on_entry { - let item_def_id = self.tcx.hir.local_def_id(item_id); - self.tcx.maps.variances - .borrow_mut() - .insert(item_def_id, self.empty_variances.clone()); - } } fn add_inferred(&mut self, item_id: ast::NodeId, index: usize, param_id: ast::NodeId) { @@ -233,15 +208,10 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { hir::ItemEnum(_, ref generics) | hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) => { - self.add_inferreds_for_item(item.id, false, generics); - } - hir::ItemTrait(_, ref generics, ..) => { - // Note: all inputs for traits are ultimately - // constrained to be invariant. See `visit_item` in - // the impl for `ConstraintContext` in `constraints.rs`. - self.add_inferreds_for_item(item.id, true, generics); + self.add_inferreds_for_item(item.id, generics); } + hir::ItemTrait(..) | hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemDefaultImpl(..) |