diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 960a1bfdd2d57..88198a886bfdf 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1084,15 +1084,42 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { where I: Iterator>, { - let mut matching_candidates = all_candidates().filter(|r| { - self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Type, assoc_name) - }); - let mut const_candidates = all_candidates().filter(|r| { - self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name) - }); + let mut matching_candidates = all_candidates() + .filter(|r| { + self.trait_defines_associated_item_named( + r.def_id(), + ty::AssocKind::Type, + assoc_name, + ) + }) + // For the purposes of an associated type, we only care + // about supertraits where the host effect is set to true. + .filter(|trait_ref| { + let tcx = self.tcx(); + let generics = tcx.generics_of(trait_ref.def_id()); + generics.host_effect_index.map_or(true, |idx| { + trait_ref.skip_binder().args.const_at(idx) == tcx.consts.true_ + }) + }); + let mut const_candidates = all_candidates() + .filter(|r| { + self.trait_defines_associated_item_named( + r.def_id(), + ty::AssocKind::Const, + assoc_name, + ) + }) + // For the purposes of an associated const, we only care + // about supertraits where the host effect is set to true. + .filter(|trait_ref| { + let tcx = self.tcx(); + let generics = tcx.generics_of(trait_ref.def_id()); + generics.host_effect_index.map_or(true, |idx| { + trait_ref.skip_binder().args.const_at(idx) == tcx.consts.true_ + }) + }); - let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next()) - { + let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) { (Some(bound), _) => (bound, matching_candidates.next()), (None, Some(bound)) => (bound, const_candidates.next()), (None, None) => { @@ -1108,37 +1135,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; debug!(?bound); - // look for a candidate that is not the same as our first bound, disregarding - // whether the bound is const. - while let Some(mut bound2) = next_cand { - debug!(?bound2); - let tcx = self.tcx(); - if bound2.bound_vars() != bound.bound_vars() { - break; - } - - let generics = tcx.generics_of(bound.def_id()); - let Some(host_index) = generics.host_effect_index else { break }; - - // always return the bound that contains the host param. - if let ty::ConstKind::Param(_) = bound2.skip_binder().args.const_at(host_index).kind() { - (bound, bound2) = (bound2, bound); - } - - let unconsted_args = bound - .skip_binder() - .args - .iter() - .enumerate() - .map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg }); - - if unconsted_args.eq(bound2.skip_binder().args.iter()) { - next_cand = matching_candidates.next().or_else(|| const_candidates.next()); - } else { - break; - } - } - if let Some(bound2) = next_cand { debug!(?bound2); @@ -1226,9 +1222,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_name: Ident, span: Span, ) -> Result, ErrorGuaranteed> { - let mut matching_candidates = all_candidates.filter(|r| { - self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Fn, assoc_name) - }); + let mut matching_candidates = all_candidates + .filter(|r| { + self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Fn, assoc_name) + }) + // For the purposes of an RTN bound, we only care + // about supertraits where the host effect is set to true. + .filter(|trait_ref| { + let tcx = self.tcx(); + let generics = tcx.generics_of(trait_ref.def_id()); + generics.host_effect_index.map_or(true, |idx| { + trait_ref.skip_binder().args.const_at(idx) == tcx.consts.true_ + }) + }); let candidate = match matching_candidates.next() { Some(candidate) => candidate, diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index af1a4e5d99e98..1d9ae2b9cb730 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -43,33 +43,6 @@ impl<'tcx> Bounds<'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, span: Span, polarity: ty::ImplPolarity, - ) { - self.push_trait_bound_inner(tcx, trait_ref, span, polarity); - - // if we have a host param, we push an unconst trait bound in addition - // to the const one. - // FIXME(effects) we should find a better way than name matching - if tcx.features().effects && trait_ref.skip_binder().args.host_effect_param().is_some() { - let generics = tcx.generics_of(trait_ref.def_id()); - let Some(host_index) = generics.host_effect_index else { return }; - let trait_ref = trait_ref.map_bound(|mut trait_ref| { - trait_ref.args = - tcx.mk_args_from_iter(trait_ref.args.iter().enumerate().map(|(n, arg)| { - if host_index == n { tcx.consts.true_.into() } else { arg } - })); - trait_ref - }); - - self.push_trait_bound_inner(tcx, trait_ref, span, polarity); - } - } - - fn push_trait_bound_inner( - &mut self, - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - span: Span, - polarity: ty::ImplPolarity, ) { self.clauses.push(( trait_ref diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 104da581e019d..1b38f77654cfb 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus @@ -38,38 +38,11 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic // an obligation and instead be skipped. Otherwise we'd use // `tcx.def_span(def_id);` let span = rustc_span::DUMMY_SP; - let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) { - // when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound, - // because only implementing `Self: Trait<.., false>` is currently not possible. - Some(( - ty::TraitRef::new( - tcx, - def_id, - ty::GenericArgs::for_item(tcx, def_id, |param, _| { - if param.is_host_effect() { - tcx.consts.true_.into() - } else { - tcx.mk_param_from_def(param) - } - }), - ) - .to_predicate(tcx), + result.predicates = + tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( + ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), span, - )) - } else { - None - }; - result.predicates = tcx.arena.alloc_from_iter( - result - .predicates - .iter() - .copied() - .chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), - span, - ))) - .chain(non_const_bound), - ); + )))); } debug!("predicates_of(def_id={:?}) = {:?}", def_id, result); result diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 7677d6f953b6e..4a245d30c8e39 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -221,14 +221,14 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - // HACK(eddyb) should get the original `Span`. - let span = tcx.def_span(def_id); ty::GenericPredicates { parent: None, predicates: tcx.arena.alloc_from_iter( self.param_env.caller_bounds().iter().filter_map(|predicate| { match predicate.kind().skip_binder() { ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => { + // HACK(eddyb) should get the original `Span`. + let span = tcx.def_span(def_id); Some((predicate, span)) } _ => None, diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 93dfbe63bcd1c..1350acd0a4421 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -2,7 +2,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{self, Obligation, PredicateObligation}; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -76,7 +76,13 @@ impl<'tcx> Extend> for PredicateSet<'tcx> { pub struct Elaborator<'tcx, O> { stack: Vec, visited: PredicateSet<'tcx>, - only_self: bool, + mode: Filter, +} + +enum Filter { + All, + OnlySelf, + OnlySelfThatDefines(Ident), } /// Describes how to elaborate an obligation into a sub-obligation. @@ -224,7 +230,7 @@ pub fn elaborate<'tcx, O: Elaboratable<'tcx>>( obligations: impl IntoIterator, ) -> Elaborator<'tcx, O> { let mut elaborator = - Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), only_self: false }; + Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), mode: Filter::All }; elaborator.extend_deduped(obligations); elaborator } @@ -242,7 +248,13 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { /// Filter to only the supertraits of trait predicates, i.e. only the predicates /// that have `Self` as their self type, instead of all implied predicates. pub fn filter_only_self(mut self) -> Self { - self.only_self = true; + self.mode = Filter::OnlySelf; + self + } + + /// Filter to only the supertraits of trait predicates that define the assoc_ty. + pub fn filter_only_self_that_defines(mut self, assoc_ty: Ident) -> Self { + self.mode = Filter::OnlySelfThatDefines(assoc_ty); self } @@ -257,10 +269,12 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { return; } // Get predicates implied by the trait, or only super predicates if we only care about self predicates. - let predicates = if self.only_self { - tcx.super_predicates_of(data.def_id()) - } else { - tcx.implied_predicates_of(data.def_id()) + let predicates = match self.mode { + Filter::All => tcx.implied_predicates_of(data.def_id()), + Filter::OnlySelf => tcx.super_predicates_of(data.def_id()), + Filter::OnlySelfThatDefines(ident) => { + tcx.super_predicates_that_define_assoc_item((data.def_id(), ident)) + } }; let obligations = @@ -274,6 +288,22 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { }); debug!(?data, ?obligations, "super_predicates"); self.extend_deduped(obligations); + + // Also elaborate `~const Trait` into `Trait`. + let generics = tcx.generics_of(data.def_id()); + if let Some(host_param_idx) = generics.host_effect_index + && data.trait_ref.args.const_at(host_param_idx) != tcx.consts.true_ + { + let mut trait_predicate_with_host = data; + trait_predicate_with_host.trait_ref.args = tcx.mk_args_from_iter( + data.trait_ref.args.iter().enumerate().map(|(idx, arg)| { + if idx == host_param_idx { tcx.consts.true_.into() } else { arg } + }), + ); + self.extend_deduped([ + elaboratable.child(trait_predicate_with_host.to_predicate(tcx)) + ]); + } } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) => { // Currently, we do not elaborate WF predicates, @@ -416,7 +446,7 @@ pub fn supertraits<'tcx>( pub fn transitive_bounds<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator>, -) -> impl Iterator> { +) -> FilterToTraits>> { elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx))) .filter_only_self() .filter_to_traits() @@ -429,31 +459,12 @@ pub fn transitive_bounds<'tcx>( /// `T::Item` and helps to avoid cycle errors (see e.g. #35237). pub fn transitive_bounds_that_define_assoc_item<'tcx>( tcx: TyCtxt<'tcx>, - bounds: impl Iterator>, + trait_refs: impl Iterator>, assoc_name: Ident, -) -> impl Iterator> { - let mut stack: Vec<_> = bounds.collect(); - let mut visited = FxIndexSet::default(); - - std::iter::from_fn(move || { - while let Some(trait_ref) = stack.pop() { - let anon_trait_ref = tcx.anonymize_bound_vars(trait_ref); - if visited.insert(anon_trait_ref) { - let super_predicates = - tcx.super_predicates_that_define_assoc_item((trait_ref.def_id(), assoc_name)); - for (super_predicate, _) in super_predicates.predicates { - let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref); - if let Some(binder) = subst_predicate.as_trait_clause() { - stack.push(binder.map_bound(|t| t.trait_ref)); - } - } - - return Some(trait_ref); - } - } - - return None; - }) +) -> FilterToTraits>> { + elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx))) + .filter_only_self_that_defines(assoc_name) + .filter_to_traits() } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 44e88d3e2302f..8e6c1cd4bbb66 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -79,10 +79,6 @@ impl GenericParamDef { } } - pub fn is_host_effect(&self) -> bool { - matches!(self.kind, GenericParamDefKind::Const { is_host_effect: true, .. }) - } - pub fn default_value<'tcx>( &self, tcx: TyCtxt<'tcx>,