diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 8947e7a2216..7f4ab352ef2 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -9,7 +9,7 @@ use rustc_span::Span; use rustc_span::def_id::DefId; -use crate::hir_ty_lowering::OnlySelfBounds; +use crate::hir_ty_lowering::PredicateFilter; /// Collects together a list of type bounds. These lists of bounds occur in many places /// in Rust's syntax: @@ -52,7 +52,7 @@ pub(crate) fn push_trait_bound( span: Span, polarity: ty::PredicatePolarity, constness: ty::BoundConstness, - only_self_bounds: OnlySelfBounds, + predicate_filter: PredicateFilter, ) { let clause = ( bound_trait_ref @@ -72,9 +72,18 @@ pub(crate) fn push_trait_bound( // FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else. // Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated // type bounds. - if !tcx.features().effects || only_self_bounds.0 { + if !tcx.features().effects { return; } + match predicate_filter { + PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { + return; + } + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { + // Ok. + } + } + // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the // associated type of `` and make sure that the effect is compatible. let compat_val = match (tcx.def_kind(defining_def_id), constness) { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index a87b29b3093..421ba40aa88 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -16,7 +16,7 @@ use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; use crate::delegation::inherit_predicates_for_delegation_item; -use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason}; +use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus @@ -270,7 +270,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bound_pred.bounds.iter(), &mut bounds, bound_vars, - OnlySelfBounds(false), + PredicateFilter::All, ); predicates.extend(bounds.clauses(tcx)); effects_min_tys.extend(bounds.effects_min_tys()); @@ -825,20 +825,6 @@ fn probe_ty_param_bounds_in_generics( continue; }; - // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we - // want to only consider predicates with `Self: ...`, but we don't want - // `OnlySelfBounds(true)` since we want to collect the nested associated - // type bound as well. - let (only_self_bounds, assoc_name) = match filter { - PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { - (OnlySelfBounds(false), None) - } - PredicateFilter::SelfOnly => (OnlySelfBounds(true), None), - PredicateFilter::SelfThatDefines(assoc_name) => { - (OnlySelfBounds(true), Some(assoc_name)) - } - }; - let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) { ty } else if matches!(filter, PredicateFilter::All) { @@ -850,31 +836,13 @@ fn probe_ty_param_bounds_in_generics( let bound_vars = self.tcx.late_bound_vars(predicate.hir_id); self.lowerer().lower_poly_bounds( bound_ty, - predicate.bounds.iter().filter(|bound| { - assoc_name - .map_or(true, |assoc_name| self.bound_defines_assoc_item(bound, assoc_name)) - }), + predicate.bounds.iter(), &mut bounds, bound_vars, - only_self_bounds, + filter, ); } bounds.clauses(self.tcx).collect() } - - #[instrument(level = "trace", skip(self))] - fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool { - match b { - hir::GenericBound::Trait(poly_trait_ref) => { - let trait_ref = &poly_trait_ref.trait_ref; - if let Some(trait_did) = trait_ref.trait_def_id() { - self.tcx.trait_may_define_assoc_item(trait_did, assoc_name) - } else { - false - } - } - _ => false, - } - } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 8f7ca089c91..171acbcef86 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -19,9 +19,7 @@ use super::errors::GenericsArgsErrExtend; use crate::bounds::Bounds; use crate::errors; -use crate::hir_ty_lowering::{ - AssocItemQSelf, HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason, -}; +use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer, PredicateFilter, RegionInferReason}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `Sized` bound to the `bounds` if appropriate. @@ -150,11 +148,25 @@ pub(crate) fn lower_poly_bounds<'hir, I: Iterator, bound_vars: &'tcx ty::List, - only_self_bounds: OnlySelfBounds, + predicate_filter: PredicateFilter, ) where 'tcx: 'hir, { for hir_bound in hir_bounds { + // In order to avoid cycles, when we're lowering `SelfThatDefines`, + // we skip over any traits that don't define the given associated type. + + if let PredicateFilter::SelfThatDefines(assoc_name) = predicate_filter { + if let Some(trait_ref) = hir_bound.trait_ref() + && let Some(trait_did) = trait_ref.trait_def_id() + && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name) + { + // Okay + } else { + continue; + } + } + match hir_bound { hir::GenericBound::Trait(poly_trait_ref) => { let (constness, polarity) = match poly_trait_ref.modifiers { @@ -179,7 +191,7 @@ pub(crate) fn lower_poly_bounds<'hir, I: Iterator { @@ -213,37 +225,16 @@ pub(crate) fn lower_mono_bounds( &self, param_ty: Ty<'tcx>, hir_bounds: &[hir::GenericBound<'tcx>], - filter: PredicateFilter, + predicate_filter: PredicateFilter, ) -> Bounds<'tcx> { let mut bounds = Bounds::default(); - let only_self_bounds = match filter { - PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { - OnlySelfBounds(false) - } - PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true), - }; - self.lower_poly_bounds( param_ty, - hir_bounds.iter().filter(|bound| match filter { - PredicateFilter::All - | PredicateFilter::SelfOnly - | PredicateFilter::SelfAndAssociatedTypeBounds => true, - PredicateFilter::SelfThatDefines(assoc_name) => { - if let Some(trait_ref) = bound.trait_ref() - && let Some(trait_did) = trait_ref.trait_def_id() - && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name) - { - true - } else { - false - } - } - }), + hir_bounds.iter(), &mut bounds, ty::List::empty(), - only_self_bounds, + predicate_filter, ); debug!(?bounds); @@ -267,7 +258,7 @@ pub(super) fn lower_assoc_item_constraint( bounds: &mut Bounds<'tcx>, duplicates: &mut FxIndexMap, path_span: Span, - only_self_bounds: OnlySelfBounds, + predicate_filter: PredicateFilter, ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx(); @@ -444,21 +435,23 @@ pub(super) fn lower_assoc_item_constraint( // Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator` // to a bound involving a projection: `::Item: Debug`. hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => { - // NOTE: If `only_self_bounds` is true, do NOT expand this associated type bound into - // a trait predicate, since we only want to add predicates for the `Self` type. - if !only_self_bounds.0 { - let projection_ty = projection_term - .map_bound(|projection_term| projection_term.expect_ty(self.tcx())); - // Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty` - // parameter to have a skipped binder. - let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder()); - self.lower_poly_bounds( - param_ty, - hir_bounds.iter(), - bounds, - projection_ty.bound_vars(), - only_self_bounds, - ); + match predicate_filter { + PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {} + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { + let projection_ty = projection_term + .map_bound(|projection_term| projection_term.expect_ty(self.tcx())); + // Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty` + // parameter to have a skipped binder. + let param_ty = + Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder()); + self.lower_poly_bounds( + param_ty, + hir_bounds.iter(), + bounds, + projection_ty.bound_vars(), + predicate_filter, + ); + } } } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 98822eec2ac..2cf97e29060 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -20,7 +20,7 @@ use super::HirTyLowerer; use crate::bounds::Bounds; use crate::hir_ty_lowering::{ - GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason, + GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason, }; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { @@ -55,9 +55,7 @@ pub(super) fn lower_trait_object_ty( ty::PredicatePolarity::Positive, dummy_self, &mut bounds, - // True so we don't populate `bounds` with associated type bounds, even - // though they're disallowed from object types. - OnlySelfBounds(true), + PredicateFilter::SelfOnly, ) { potential_assoc_types.extend(cur_potential_assoc_types); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d760acf53bd..f5d9d186f13 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -64,9 +64,6 @@ #[derive(Debug)] pub struct GenericPathSegment(pub DefId, pub usize); -#[derive(Copy, Clone, Debug)] -pub struct OnlySelfBounds(pub bool); - #[derive(Copy, Clone, Debug)] pub enum PredicateFilter { /// All predicates may be implied by the trait. @@ -76,7 +73,8 @@ pub enum PredicateFilter { SelfOnly, /// Only traits that reference `Self: ..` and define an associated type - /// with the given ident are implied by the trait. + /// with the given ident are implied by the trait. This mode exists to + /// side-step query cycles when lowering associated types. SelfThatDefines(Ident), /// Only traits that reference `Self: ..` and their associated type bounds. @@ -683,7 +681,7 @@ pub(crate) fn lower_poly_trait_ref( polarity: ty::PredicatePolarity, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, - only_self_bounds: OnlySelfBounds, + predicate_filter: PredicateFilter, ) -> GenericArgCountResult { let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); let trait_segment = trait_ref.path.segments.last().unwrap(); @@ -720,7 +718,7 @@ pub(crate) fn lower_poly_trait_ref( span, polarity, constness, - only_self_bounds, + predicate_filter, ); let mut dup_constraints = FxIndexMap::default(); @@ -744,7 +742,7 @@ pub(crate) fn lower_poly_trait_ref( bounds, &mut dup_constraints, constraint.span, - only_self_bounds, + predicate_filter, ); // Okay to ignore `Err` because of `ErrorGuaranteed` (see above). }