diff options
Diffstat (limited to 'compiler/rustc_middle/src')
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/context.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/query/keys.rs | 24 |
3 files changed, 73 insertions, 4 deletions
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7822ecc2c1f..b516810205f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -433,12 +433,23 @@ rustc_queries! { /// full predicates are available (note that supertraits have /// additional acyclicity requirements). query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) } + desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } + } + + /// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query + /// returns the full set of predicates. If `Some<Ident>`, then the query returns only the + /// subset of super-predicates that reference traits that define the given associated type. + /// This is used to avoid cycles in resolving types like `T::Item`. + query super_predicates_that_define_assoc_type(key: (DefId, Option<rustc_span::symbol::Ident>)) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing the super traits of `{}`{}", + tcx.def_path_str(key.0), + if let Some(assoc_name) = key.1 { format!(" with associated type name `{}`", assoc_name) } else { "".to_string() }, + } } /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> { + query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the bounds for type parameter `{}`", { let id = tcx.hir().local_def_id_to_hir_id(key.1); tcx.hir().ty_param_name(id) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7207e5a179e..744aa39b96c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -51,7 +51,7 @@ use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; use rustc_session::Session; use rustc_span::source_map::MultiSpan; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; @@ -2085,6 +2085,42 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig })) } + /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` + /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. + pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool { + self.super_traits_of(trait_def_id).any(|trait_did| { + self.associated_items(trait_did) + .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did) + .is_some() + }) + } + + /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) + /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used + /// to identify which traits may define a given associated type to help avoid cycle errors. + /// Returns a `DefId` iterator. + fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { + let mut set = FxHashSet::default(); + let mut stack = vec![trait_def_id]; + + set.insert(trait_def_id); + + iter::from_fn(move || -> Option<DefId> { + let trait_did = stack.pop()?; + let generic_predicates = self.super_predicates_of(trait_did); + + for (predicate, _) in generic_predicates.predicates { + if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { + if set.insert(data.def_id()) { + stack.push(data.def_id()); + } + } + } + + Some(trait_did) + }) + } + /// Given a closure signature, returns an equivalent fn signature. Detuples /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then /// you would get a `fn(u32, i32)`. diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs index a005990264c..3949c303f72 100644 --- a/compiler/rustc_middle/src/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -7,7 +7,7 @@ use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_query_system::query::DefaultCacheSelector; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; /// The `Key` trait controls what types can legally be used as the key @@ -149,6 +149,28 @@ impl Key for (LocalDefId, DefId) { } } +impl Key for (DefId, Option<Ident>) { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.0) + } +} + +impl Key for (DefId, LocalDefId, Ident) { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.1.default_span(tcx) + } +} + impl Key for (CrateNum, DefId) { type CacheSelector = DefaultCacheSelector; |
