From 58aad3c72c32936b49f92f552e0157b9c8c862ee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 6 Jul 2024 11:54:22 -0400 Subject: [PATCH 1/4] iter_identity is a better name --- .../rustc_hir_analysis/src/check/wfcheck.rs | 23 +++++++++---------- compiler/rustc_hir_typeck/src/coercion.rs | 9 ++++---- .../src/opaque_hidden_inferred_bound.rs | 4 +--- compiler/rustc_lint/src/unused.rs | 4 +--- compiler/rustc_middle/src/ty/generics.rs | 2 +- .../src/traits/object_safety.rs | 2 +- compiler/rustc_ty_utils/src/opaque_types.rs | 6 ++--- compiler/rustc_ty_utils/src/sig_types.rs | 2 +- compiler/rustc_type_ir/src/binder.rs | 6 ++--- src/librustdoc/clean/mod.rs | 3 +-- src/tools/clippy/clippy_utils/src/ty.rs | 2 +- 11 files changed, 26 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 2230528a5ae11..c31f7487dcdfb 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -477,7 +477,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { param_env, item_def_id, tcx.explicit_item_bounds(item_def_id) - .instantiate_identity_iter_copied() + .iter_identity_copied() .collect::>(), &FxIndexSet::default(), gat_def_id, @@ -1204,17 +1204,16 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt let bounds = wfcx.tcx().explicit_item_bounds(item.def_id); debug!("check_associated_type_bounds: bounds={:?}", bounds); - let wf_obligations = - bounds.instantiate_identity_iter_copied().flat_map(|(bound, bound_span)| { - let normalized_bound = wfcx.normalize(span, None, bound); - traits::wf::clause_obligations( - wfcx.infcx, - wfcx.param_env, - wfcx.body_def_id, - normalized_bound, - bound_span, - ) - }); + let wf_obligations = bounds.iter_identity_copied().flat_map(|(bound, bound_span)| { + let normalized_bound = wfcx.normalize(span, None, bound); + traits::wf::clause_obligations( + wfcx.infcx, + wfcx.param_env, + wfcx.body_def_id, + normalized_bound, + bound_span, + ) + }); wfcx.register_obligations(wf_obligations); } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index f72e8a4afdef6..4f0a089ee956f 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1752,10 +1752,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx.probe(|_| { let ocx = ObligationCtxt::new(fcx); ocx.register_obligations( - fcx.tcx - .item_super_predicates(rpit_def_id) - .instantiate_identity_iter() - .filter_map(|clause| { + fcx.tcx.item_super_predicates(rpit_def_id).iter_identity().filter_map( + |clause| { let predicate = clause .kind() .map_bound(|clause| match clause { @@ -1776,7 +1774,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx.param_env, predicate, )) - }), + }, + ), ); ocx.select_where_possible().is_empty() }) diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 8b669bcc13f0b..5ee73dbfdc658 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -76,9 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // For every projection predicate in the opaque type's explicit bounds, // check that the type that we're assigning actually satisfies the bounds // of the associated type. - for (pred, pred_span) in - cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() - { + for (pred, pred_span) in cx.tcx.explicit_item_bounds(def_id).iter_identity_copied() { infcx.enter_forall(pred.kind(), |predicate| { let ty::ClauseKind::Projection(proj) = predicate else { return; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 195a0f72475f0..65d42ed8054f9 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -298,9 +298,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => { elaborate( cx.tcx, - cx.tcx - .explicit_item_super_predicates(def) - .instantiate_identity_iter_copied(), + cx.tcx.explicit_item_super_predicates(def).iter_identity_copied(), ) // We only care about self bounds for the impl-trait .filter_only_self() diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 844023df1e315..11ed0bdaa7028 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -394,7 +394,7 @@ impl<'tcx> GenericPredicates<'tcx> { } pub fn instantiate_own_identity(&self) -> impl Iterator, Span)> { - EarlyBinder::bind(self.predicates).instantiate_identity_iter_copied() + EarlyBinder::bind(self.predicates).iter_identity_copied() } #[instrument(level = "debug", skip(self, tcx))] diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 5b2c8fb1950d8..1c6993bdd3729 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -203,7 +203,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span tcx.associated_items(trait_def_id) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) - .flat_map(|item| tcx.explicit_item_bounds(item.def_id).instantiate_identity_iter_copied()) + .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied()) .filter_map(|c| predicate_references_self(tcx, c)) .collect() } diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 686f2f04ad9a7..5e91320f89753 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -169,10 +169,8 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { // Collect opaque types nested within the associated type bounds of this opaque type. // We use identity args here, because we already know that the opaque type uses // only generic parameters, and thus instantiating would not give us more information. - for (pred, span) in self - .tcx - .explicit_item_bounds(alias_ty.def_id) - .instantiate_identity_iter_copied() + for (pred, span) in + self.tcx.explicit_item_bounds(alias_ty.def_id).iter_identity_copied() { trace!(?pred); self.visit_spanned(span, pred); diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index 97a1b94263e90..eb6cb369974fd 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -62,7 +62,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( } } DefKind::OpaqueTy => { - for (pred, span) in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() { + for (pred, span) in tcx.explicit_item_bounds(item).iter_identity_copied() { try_visit!(visitor.visit(span, pred)); } } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 491ef34430c15..2531219baecc8 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -448,7 +448,7 @@ where /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), /// but on an iterator of `TypeFoldable` values. - pub fn instantiate_identity_iter(self) -> Iter::IntoIter { + pub fn iter_identity(self) -> Iter::IntoIter { self.value.into_iter() } } @@ -515,9 +515,7 @@ where /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), /// but on an iterator of values that deref to a `TypeFoldable`. - pub fn instantiate_identity_iter_copied( - self, - ) -> impl Iterator::Target> { + pub fn iter_identity_copied(self) -> impl Iterator::Target> { self.value.into_iter().map(|v| *v) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b5660cd849246..aa596897fc42f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1404,8 +1404,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates; if let ty::TraitContainer = assoc_item.container { - let bounds = - tcx.explicit_item_bounds(assoc_item.def_id).instantiate_identity_iter_copied(); + let bounds = tcx.explicit_item_bounds(assoc_item.def_id).iter_identity_copied(); predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied())); } let mut generics = clean_ty_generics( diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index e5d2056419681..acaeb93f44a6e 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -99,7 +99,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' for (predicate, _span) in cx .tcx .explicit_item_super_predicates(def_id) - .instantiate_identity_iter_copied() + .iter_identity_copied() { match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through From 90423a7abbddd98b6fbb22e9780991c736b51ca4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 6 Jul 2024 12:21:00 -0400 Subject: [PATCH 2/4] Uplift elaboration --- compiler/rustc_infer/src/traits/util.rs | 349 +----------------- compiler/rustc_middle/src/ty/context.rs | 21 +- .../rustc_middle/src/ty/elaborate_impl.rs | 84 +++++ compiler/rustc_middle/src/ty/mod.rs | 1 + compiler/rustc_middle/src/ty/predicate.rs | 10 +- compiler/rustc_middle/src/ty/sty.rs | 8 + .../src/solve/assembly/structural_traits.rs | 4 +- compiler/rustc_type_ir/src/elaborate.rs | 277 ++++++++++++++ compiler/rustc_type_ir/src/inherent.rs | 37 +- compiler/rustc_type_ir/src/interner.rs | 14 +- compiler/rustc_type_ir/src/lib.rs | 1 + 11 files changed, 437 insertions(+), 369 deletions(-) create mode 100644 compiler/rustc_middle/src/ty/elaborate_impl.rs create mode 100644 compiler/rustc_type_ir/src/elaborate.rs diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index b269bfcbfebc2..f54d041859581 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,12 +1,10 @@ -use smallvec::smallvec; - use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::ToPolyTraitRef; -use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::Ident; use rustc_span::Span; -use rustc_type_ir::outlives::{push_outlives_components, Component}; +pub use rustc_type_ir::elaborate::*; pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, @@ -64,50 +62,9 @@ impl<'tcx> Extend> for PredicateSet<'tcx> { } } -/////////////////////////////////////////////////////////////////////////// -// `Elaboration` iterator -/////////////////////////////////////////////////////////////////////////// - -/// "Elaboration" is the process of identifying all the predicates that -/// are implied by a source predicate. Currently, this basically means -/// walking the "supertraits" and other similar assumptions. For example, -/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd` -/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that -/// `T: Foo`, then we know that `T: 'static`. -pub struct Elaborator<'tcx, O> { - stack: Vec, - visited: PredicateSet<'tcx>, - mode: Filter, -} - -enum Filter { - All, - OnlySelf, -} - -/// Describes how to elaborate an obligation into a sub-obligation. -/// /// For [`Obligation`], a sub-obligation is combined with the current obligation's -/// param-env and cause code. For [`ty::Predicate`], none of this is needed, since -/// there is no param-env or cause code to copy over. -pub trait Elaboratable<'tcx> { - fn predicate(&self) -> ty::Predicate<'tcx>; - - // Makes a new `Self` but with a different clause that comes from elaboration. - fn child(&self, clause: ty::Clause<'tcx>) -> Self; - - // Makes a new `Self` but with a different clause and a different cause - // code (if `Self` has one, such as [`PredicateObligation`]). - fn child_with_derived_cause( - &self, - clause: ty::Clause<'tcx>, - span: Span, - parent_trait_pred: ty::PolyTraitPredicate<'tcx>, - index: usize, - ) -> Self; -} - -impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> { +/// param-env and cause code. +impl<'tcx> Elaboratable> for PredicateObligation<'tcx> { fn predicate(&self) -> ty::Predicate<'tcx> { self.predicate } @@ -145,270 +102,6 @@ impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> { } } -impl<'tcx> Elaboratable<'tcx> for ty::Predicate<'tcx> { - fn predicate(&self) -> ty::Predicate<'tcx> { - *self - } - - fn child(&self, clause: ty::Clause<'tcx>) -> Self { - clause.as_predicate() - } - - fn child_with_derived_cause( - &self, - clause: ty::Clause<'tcx>, - _span: Span, - _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, - _index: usize, - ) -> Self { - clause.as_predicate() - } -} - -impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) { - fn predicate(&self) -> ty::Predicate<'tcx> { - self.0 - } - - fn child(&self, clause: ty::Clause<'tcx>) -> Self { - (clause.as_predicate(), self.1) - } - - fn child_with_derived_cause( - &self, - clause: ty::Clause<'tcx>, - _span: Span, - _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, - _index: usize, - ) -> Self { - (clause.as_predicate(), self.1) - } -} - -impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) { - fn predicate(&self) -> ty::Predicate<'tcx> { - self.0.as_predicate() - } - - fn child(&self, clause: ty::Clause<'tcx>) -> Self { - (clause, self.1) - } - - fn child_with_derived_cause( - &self, - clause: ty::Clause<'tcx>, - _span: Span, - _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, - _index: usize, - ) -> Self { - (clause, self.1) - } -} - -impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> { - fn predicate(&self) -> ty::Predicate<'tcx> { - self.as_predicate() - } - - fn child(&self, clause: ty::Clause<'tcx>) -> Self { - clause - } - - fn child_with_derived_cause( - &self, - clause: ty::Clause<'tcx>, - _span: Span, - _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, - _index: usize, - ) -> Self { - clause - } -} - -pub fn elaborate<'tcx, O: Elaboratable<'tcx>>( - tcx: TyCtxt<'tcx>, - obligations: impl IntoIterator, -) -> Elaborator<'tcx, O> { - let mut elaborator = - Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), mode: Filter::All }; - elaborator.extend_deduped(obligations); - elaborator -} - -impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { - fn extend_deduped(&mut self, obligations: impl IntoIterator) { - // Only keep those bounds that we haven't already seen. - // This is necessary to prevent infinite recursion in some - // cases. One common case is when people define - // `trait Sized: Sized { }` rather than `trait Sized { }`. - // let visited = &mut self.visited; - self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate()))); - } - - /// 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.mode = Filter::OnlySelf; - self - } - - fn elaborate(&mut self, elaboratable: &O) { - let tcx = self.visited.tcx; - - // We only elaborate clauses. - let Some(clause) = elaboratable.predicate().as_clause() else { - return; - }; - - let bound_clause = clause.kind(); - match bound_clause.skip_binder() { - ty::ClauseKind::Trait(data) => { - // Negative trait bounds do not imply any supertrait bounds - if data.polarity != ty::PredicatePolarity::Positive { - return; - } - // Get predicates implied by the trait, or only super predicates if we only care about self predicates. - let predicates = match self.mode { - Filter::All => tcx.explicit_implied_predicates_of(data.def_id()), - Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()), - }; - - let obligations = - predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| { - elaboratable.child_with_derived_cause( - clause.instantiate_supertrait(tcx, bound_clause.rebind(data.trait_ref)), - span, - bound_clause.rebind(data), - index, - ) - }); - debug!(?data, ?obligations, "super_predicates"); - self.extend_deduped(obligations); - } - ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => { - // We know that `T: 'a` for some type `T`. We can - // often elaborate this. For example, if we know that - // `[U]: 'a`, that implies that `U: 'a`. Similarly, if - // we know `&'a U: 'b`, then we know that `'a: 'b` and - // `U: 'b`. - // - // We can basically ignore bound regions here. So for - // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to - // `'a: 'b`. - - // Ignore `for<'a> T: 'a` -- we might in the future - // consider this as evidence that `T: 'static`, but - // I'm a bit wary of such constructions and so for now - // I want to be conservative. --nmatsakis - if r_min.is_bound() { - return; - } - - let mut components = smallvec![]; - push_outlives_components(tcx, ty_max, &mut components); - self.extend_deduped( - components - .into_iter() - .filter_map(|component| match component { - Component::Region(r) => { - if r.is_bound() { - None - } else { - Some(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( - r, r_min, - ))) - } - } - - Component::Param(p) => { - let ty = Ty::new_param(tcx, p.index, p.name); - Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min))) - } - - Component::Placeholder(p) => { - let ty = Ty::new_placeholder(tcx, p); - Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min))) - } - - Component::UnresolvedInferenceVariable(_) => None, - - Component::Alias(alias_ty) => { - // We might end up here if we have `Foo<::Assoc>: 'a`. - // With this, we can deduce that `::Assoc: 'a`. - Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( - alias_ty.to_ty(tcx), - r_min, - ))) - } - - Component::EscapingAlias(_) => { - // We might be able to do more here, but we don't - // want to deal with escaping vars right now. - None - } - }) - .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(tcx))), - ); - } - ty::ClauseKind::RegionOutlives(..) => { - // Nothing to elaborate from `'a: 'b`. - } - ty::ClauseKind::WellFormed(..) => { - // Currently, we do not elaborate WF predicates, - // although we easily could. - } - ty::ClauseKind::Projection(..) => { - // Nothing to elaborate in a projection predicate. - } - ty::ClauseKind::ConstEvaluatable(..) => { - // Currently, we do not elaborate const-evaluatable - // predicates. - } - ty::ClauseKind::ConstArgHasType(..) => { - // Nothing to elaborate - } - } - } -} - -impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> { - type Item = O; - - fn size_hint(&self) -> (usize, Option) { - (self.stack.len(), None) - } - - fn next(&mut self) -> Option { - // Extract next item from top-most stack frame, if any. - if let Some(obligation) = self.stack.pop() { - self.elaborate(&obligation); - Some(obligation) - } else { - None - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Supertrait iterator -/////////////////////////////////////////////////////////////////////////// - -pub fn supertraits<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> FilterToTraits>> { - elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits() -} - -pub fn transitive_bounds<'tcx>( - tcx: TyCtxt<'tcx>, - trait_refs: impl Iterator>, -) -> FilterToTraits>> { - elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) - .filter_only_self() - .filter_to_traits() -} - /// A specialized variant of `elaborate` that only elaborates trait references that may /// define the given associated item with the name `assoc_name`. It uses the /// `explicit_supertraits_containing_assoc_item` query to avoid enumerating super-predicates that @@ -443,37 +136,3 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>( None }) } - -/////////////////////////////////////////////////////////////////////////// -// Other -/////////////////////////////////////////////////////////////////////////// - -impl<'tcx> Elaborator<'tcx, ty::Clause<'tcx>> { - fn filter_to_traits(self) -> FilterToTraits { - FilterToTraits { base_iterator: self } - } -} - -/// A filter around an iterator of predicates that makes it yield up -/// just trait references. -pub struct FilterToTraits { - base_iterator: I, -} - -impl<'tcx, I: Iterator>> Iterator for FilterToTraits { - type Item = ty::PolyTraitRef<'tcx>; - - fn next(&mut self) -> Option> { - while let Some(pred) = self.base_iterator.next() { - if let Some(data) = pred.as_trait_clause() { - return Some(data.map_bound(|t| t.trait_ref)); - } - } - None - } - - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.base_iterator.size_hint(); - (0, upper) - } -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index dca48069974f0..59ab5d791399b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -347,12 +347,16 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn explicit_super_predicates_of( self, def_id: DefId, - ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { + ) -> ty::EarlyBinder<'tcx, impl IntoIterator, Span)>> { + ty::EarlyBinder::bind(self.explicit_super_predicates_of(def_id).instantiate_identity(self)) + } + + fn explicit_implied_predicates_of( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator, Span)>> { ty::EarlyBinder::bind( - self.explicit_super_predicates_of(def_id) - .instantiate_identity(self) - .predicates - .into_iter(), + self.explicit_implied_predicates_of(def_id).instantiate_identity(self), ) } @@ -569,6 +573,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> Ty<'tcx> { placeholder.find_const_ty_from_env(param_env) } + + fn anonymize_bound_vars>>( + self, + binder: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { + self.anonymize_bound_vars(binder) + } } macro_rules! bidirectional_lang_item_map { diff --git a/compiler/rustc_middle/src/ty/elaborate_impl.rs b/compiler/rustc_middle/src/ty/elaborate_impl.rs new file mode 100644 index 0000000000000..8c89a2d884b30 --- /dev/null +++ b/compiler/rustc_middle/src/ty/elaborate_impl.rs @@ -0,0 +1,84 @@ +use rustc_span::Span; +use rustc_type_ir::elaborate::Elaboratable; + +use crate::ty::{self, TyCtxt}; + +impl<'tcx> Elaboratable> for ty::Clause<'tcx> { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.as_predicate() + } + + fn child(&self, clause: ty::Clause<'tcx>) -> Self { + clause + } + + fn child_with_derived_cause( + &self, + clause: ty::Clause<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + clause + } +} + +impl<'tcx> Elaboratable> for ty::Predicate<'tcx> { + fn predicate(&self) -> ty::Predicate<'tcx> { + *self + } + + fn child(&self, clause: ty::Clause<'tcx>) -> Self { + clause.as_predicate() + } + + fn child_with_derived_cause( + &self, + clause: ty::Clause<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + clause.as_predicate() + } +} + +impl<'tcx> Elaboratable> for (ty::Predicate<'tcx>, Span) { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.0 + } + + fn child(&self, clause: ty::Clause<'tcx>) -> Self { + (clause.as_predicate(), self.1) + } + + fn child_with_derived_cause( + &self, + clause: ty::Clause<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + (clause.as_predicate(), self.1) + } +} + +impl<'tcx> Elaboratable> for (ty::Clause<'tcx>, Span) { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.0.as_predicate() + } + + fn child(&self, clause: ty::Clause<'tcx>) -> Self { + (clause, self.1) + } + + fn child_with_derived_cause( + &self, + clause: ty::Clause<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + (clause, self.1) + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7d57d88f40f4a..4470db47474cb 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -148,6 +148,7 @@ mod closure; mod consts; mod context; mod diagnostics; +mod elaborate_impl; mod erase_regions; mod generic_args; mod generics; diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index e9b37503bb3e5..c2cc3be3aaa56 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -46,6 +46,10 @@ pub struct Predicate<'tcx>( ); impl<'tcx> rustc_type_ir::inherent::Predicate> for Predicate<'tcx> { + fn as_clause(self) -> Option> { + self.as_clause() + } + fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool { self.is_coinductive(interner) } @@ -173,7 +177,11 @@ pub struct Clause<'tcx>( pub(super) Interned<'tcx, WithCachedTypeInfo>>>, ); -impl<'tcx> rustc_type_ir::inherent::Clause> for Clause<'tcx> {} +impl<'tcx> rustc_type_ir::inherent::Clause> for Clause<'tcx> { + fn instantiate_supertrait(self, tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> Self { + self.instantiate_supertrait(tcx, trait_ref) + } +} impl<'tcx> rustc_type_ir::inherent::IntoKind for Clause<'tcx> { type Kind = ty::Binder<'tcx, ClauseKind<'tcx>>; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 52690ae678d6c..d2b444a066bcc 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -811,6 +811,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { Ty::new_var(tcx, vid) } + fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamTy) -> Self { + Ty::new_param(tcx, param.index, param.name) + } + + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType) -> Self { + Ty::new_placeholder(tcx, placeholder) + } + fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundTy) -> Self { Ty::new_bound(interner, debruijn, var) } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 3447b39fa5b40..7df14e81ab5d4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -669,7 +669,9 @@ where let cx = ecx.cx(); let mut requirements = vec![]; requirements.extend( - cx.explicit_super_predicates_of(trait_ref.def_id).iter_instantiated(cx, trait_ref.args), + cx.explicit_super_predicates_of(trait_ref.def_id) + .iter_instantiated(cx, trait_ref.args) + .map(|(pred, _)| pred), ); // FIXME(associated_const_equality): Also add associated consts to diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs new file mode 100644 index 0000000000000..04cdf29a77799 --- /dev/null +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -0,0 +1,277 @@ +use std::marker::PhantomData; + +use smallvec::smallvec; + +use crate::data_structures::HashSet; +use crate::outlives::{push_outlives_components, Component}; +use crate::{self as ty, Interner}; +use crate::{inherent::*, Upcast as _}; + +/// "Elaboration" is the process of identifying all the predicates that +/// are implied by a source predicate. Currently, this basically means +/// walking the "supertraits" and other similar assumptions. For example, +/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd` +/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that +/// `T: Foo`, then we know that `T: 'static`. +pub struct Elaborator { + cx: I, + stack: Vec, + visited: HashSet>>, + mode: Filter, +} + +enum Filter { + All, + OnlySelf, +} + +/// Describes how to elaborate an obligation into a sub-obligation. +pub trait Elaboratable { + fn predicate(&self) -> I::Predicate; + + // Makes a new `Self` but with a different clause that comes from elaboration. + fn child(&self, clause: I::Clause) -> Self; + + // Makes a new `Self` but with a different clause and a different cause + // code (if `Self` has one, such as [`PredicateObligation`]). + fn child_with_derived_cause( + &self, + clause: I::Clause, + span: I::Span, + parent_trait_pred: ty::Binder>, + index: usize, + ) -> Self; +} + +pub fn elaborate>( + cx: I, + obligations: impl IntoIterator, +) -> Elaborator { + let mut elaborator = + Elaborator { cx, stack: Vec::new(), visited: HashSet::default(), mode: Filter::All }; + elaborator.extend_deduped(obligations); + elaborator +} + +impl> Elaborator { + fn extend_deduped(&mut self, obligations: impl IntoIterator) { + // Only keep those bounds that we haven't already seen. + // This is necessary to prevent infinite recursion in some + // cases. One common case is when people define + // `trait Sized: Sized { }` rather than `trait Sized { }`. + self.stack.extend( + obligations.into_iter().filter(|o| { + self.visited.insert(self.cx.anonymize_bound_vars(o.predicate().kind())) + }), + ); + } + + /// 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.mode = Filter::OnlySelf; + self + } + + fn elaborate(&mut self, elaboratable: &O) { + let cx = self.cx; + + // We only elaborate clauses. + let Some(clause) = elaboratable.predicate().as_clause() else { + return; + }; + + let bound_clause = clause.kind(); + match bound_clause.skip_binder() { + ty::ClauseKind::Trait(data) => { + // Negative trait bounds do not imply any supertrait bounds + if data.polarity != ty::PredicatePolarity::Positive { + return; + } + + let map_to_child_clause = + |(index, (clause, span)): (usize, (I::Clause, I::Span))| { + elaboratable.child_with_derived_cause( + clause.instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)), + span, + bound_clause.rebind(data), + index, + ) + }; + + // Get predicates implied by the trait, or only super predicates if we only care about self predicates. + match self.mode { + Filter::All => self.extend_deduped( + cx.explicit_implied_predicates_of(data.def_id()) + .iter_identity() + .enumerate() + .map(map_to_child_clause), + ), + Filter::OnlySelf => self.extend_deduped( + cx.explicit_super_predicates_of(data.def_id()) + .iter_identity() + .enumerate() + .map(map_to_child_clause), + ), + }; + } + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => { + // We know that `T: 'a` for some type `T`. We can + // often elaborate this. For example, if we know that + // `[U]: 'a`, that implies that `U: 'a`. Similarly, if + // we know `&'a U: 'b`, then we know that `'a: 'b` and + // `U: 'b`. + // + // We can basically ignore bound regions here. So for + // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to + // `'a: 'b`. + + // Ignore `for<'a> T: 'a` -- we might in the future + // consider this as evidence that `T: 'static`, but + // I'm a bit wary of such constructions and so for now + // I want to be conservative. --nmatsakis + if r_min.is_bound() { + return; + } + + let mut components = smallvec![]; + push_outlives_components(cx, ty_max, &mut components); + self.extend_deduped( + components + .into_iter() + .filter_map(|component| elaborate_component_to_clause(cx, component, r_min)) + .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(cx))), + ); + } + ty::ClauseKind::RegionOutlives(..) => { + // Nothing to elaborate from `'a: 'b`. + } + ty::ClauseKind::WellFormed(..) => { + // Currently, we do not elaborate WF predicates, + // although we easily could. + } + ty::ClauseKind::Projection(..) => { + // Nothing to elaborate in a projection predicate. + } + ty::ClauseKind::ConstEvaluatable(..) => { + // Currently, we do not elaborate const-evaluatable + // predicates. + } + ty::ClauseKind::ConstArgHasType(..) => { + // Nothing to elaborate + } + } + } +} + +fn elaborate_component_to_clause( + cx: I, + component: Component, + outlives_region: I::Region, +) -> Option> { + match component { + Component::Region(r) => { + if r.is_bound() { + None + } else { + Some(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r, outlives_region))) + } + } + + Component::Param(p) => { + let ty = Ty::new_param(cx, p); + Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, outlives_region))) + } + + Component::Placeholder(p) => { + let ty = Ty::new_placeholder(cx, p); + Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, outlives_region))) + } + + Component::UnresolvedInferenceVariable(_) => None, + + Component::Alias(alias_ty) => { + // We might end up here if we have `Foo<::Assoc>: 'a`. + // With this, we can deduce that `::Assoc: 'a`. + Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( + alias_ty.to_ty(cx), + outlives_region, + ))) + } + + Component::EscapingAlias(_) => { + // We might be able to do more here, but we don't + // want to deal with escaping vars right now. + None + } + } +} + +impl> Iterator for Elaborator { + type Item = O; + + fn size_hint(&self) -> (usize, Option) { + (self.stack.len(), None) + } + + fn next(&mut self) -> Option { + // Extract next item from top-most stack frame, if any. + if let Some(obligation) = self.stack.pop() { + self.elaborate(&obligation); + Some(obligation) + } else { + None + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Supertrait iterator +/////////////////////////////////////////////////////////////////////////// + +pub fn supertraits( + tcx: I, + trait_ref: ty::Binder>, +) -> FilterToTraits> { + elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits() +} + +pub fn transitive_bounds( + tcx: I, + trait_refs: impl Iterator>>, +) -> FilterToTraits> { + elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) + .filter_only_self() + .filter_to_traits() +} + +impl Elaborator { + fn filter_to_traits(self) -> FilterToTraits { + FilterToTraits { _cx: PhantomData, base_iterator: self } + } +} + +/// A filter around an iterator of predicates that makes it yield up +/// just trait references. +pub struct FilterToTraits> { + _cx: PhantomData, + base_iterator: It, +} + +impl> Iterator for FilterToTraits { + type Item = ty::Binder>; + + fn next(&mut self) -> Option>> { + while let Some(pred) = self.base_iterator.next() { + if let Some(data) = pred.as_trait_clause() { + return Some(data.map_bound(|t| t.trait_ref)); + } + } + None + } + + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.base_iterator.size_hint(); + (0, upper) + } +} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 68c2575258d2f..1db55b26719b0 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -9,6 +9,7 @@ use std::hash::Hash; use rustc_ast_ir::Mutability; use crate::data_structures::HashSet; +use crate::elaborate::Elaboratable; use crate::fold::{TypeFoldable, TypeSuperFoldable}; use crate::relate::Relate; use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal}; @@ -40,6 +41,10 @@ pub trait Ty>: fn new_var(interner: I, var: ty::TyVid) -> Self; + fn new_param(interner: I, param: I::ParamTy) -> Self; + + fn new_placeholder(interner: I, param: I::PlaceholderTy) -> Self; + fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundTy) -> Self; fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; @@ -429,6 +434,8 @@ pub trait Predicate>: + UpcastFrom> + IntoKind>> { + fn as_clause(self) -> Option; + fn is_coinductive(self, interner: I) -> bool; // FIXME: Eventually uplift the impl out of rustc and make this defaulted. @@ -441,35 +448,35 @@ pub trait Clause>: + Hash + Eq + TypeFoldable - // FIXME: Remove these, uplift the `Upcast` impls. + + UpcastFrom>> + UpcastFrom> + UpcastFrom>> + UpcastFrom> + UpcastFrom>> + IntoKind>> + + Elaboratable { fn as_trait_clause(self) -> Option>> { self.kind() - .map_bound(|clause| { - if let ty::ClauseKind::Trait(t) = clause { - Some(t) - } else { - None - } - }) + .map_bound(|clause| if let ty::ClauseKind::Trait(t) = clause { Some(t) } else { None }) .transpose() } + fn as_projection_clause(self) -> Option>> { self.kind() - .map_bound(|clause| { - if let ty::ClauseKind::Projection(p) = clause { - Some(p) - } else { - None - } - }) + .map_bound( + |clause| { + if let ty::ClauseKind::Projection(p) = clause { Some(p) } else { None } + }, + ) .transpose() } + + /// Performs a instantiation suitable for going from a + /// poly-trait-ref to supertraits that must hold if that + /// poly-trait-ref holds. This is slightly different from a normal + /// instantiation in terms of what happens with bound regions. + fn instantiate_supertrait(self, tcx: I, trait_ref: ty::Binder>) -> Self; } /// Common capabilities of placeholder kinds diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6e013768c3ea8..446a4060e62f8 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -32,7 +32,7 @@ pub trait Interner: { type DefId: DefId; type LocalDefId: Copy + Debug + Hash + Eq + Into + TypeFoldable; - type Span: Copy + Debug + Hash + Eq; + type Span: Copy + Debug + Hash + Eq + TypeFoldable; type GenericArgs: GenericArgs; type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike; @@ -213,7 +213,12 @@ pub trait Interner: fn explicit_super_predicates_of( self, def_id: Self::DefId, - ) -> ty::EarlyBinder>; + ) -> ty::EarlyBinder>; + + fn explicit_implied_predicates_of( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; fn has_target_features(self, def_id: Self::DefId) -> bool; @@ -268,6 +273,11 @@ pub trait Interner: param_env: Self::ParamEnv, placeholder: Self::PlaceholderConst, ) -> Self::Ty; + + fn anonymize_bound_vars>( + self, + binder: ty::Binder, + ) -> ty::Binder; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 2a909b06baf3a..b14a65fc77958 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -20,6 +20,7 @@ pub mod visit; #[cfg(feature = "nightly")] pub mod codec; pub mod data_structures; +pub mod elaborate; pub mod error; pub mod fast_reject; pub mod fold; From 66eb346770a97fe96c02a79a740cb151e5232010 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 6 Jul 2024 12:33:03 -0400 Subject: [PATCH 3/4] Get rid of the redundant elaboration in middle --- compiler/rustc_middle/src/traits/mod.rs | 1 - compiler/rustc_middle/src/traits/util.rs | 62 ------------------- compiler/rustc_middle/src/ty/context.rs | 26 +------- compiler/rustc_middle/src/ty/print/pretty.rs | 15 ++--- .../src/solve/trait_goals.rs | 5 +- compiler/rustc_type_ir/src/elaborate.rs | 28 +++++++++ compiler/rustc_type_ir/src/interner.rs | 3 - 7 files changed, 40 insertions(+), 100 deletions(-) delete mode 100644 compiler/rustc_middle/src/traits/util.rs diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index b4e3fae1b43b0..b74775142e487 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -7,7 +7,6 @@ pub mod select; pub mod solve; pub mod specialization_graph; mod structural_impls; -pub mod util; use crate::mir::ConstraintCategory; use crate::ty::abstract_const::NotConstEvaluatable; diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs deleted file mode 100644 index 7437be7a74c14..0000000000000 --- a/compiler/rustc_middle/src/traits/util.rs +++ /dev/null @@ -1,62 +0,0 @@ -use rustc_data_structures::fx::FxHashSet; - -use crate::ty::{Clause, PolyTraitRef, ToPolyTraitRef, TyCtxt, Upcast}; - -/// Given a [`PolyTraitRef`], get the [`Clause`]s implied by the trait's definition. -/// -/// This only exists in `rustc_middle` because the more powerful elaborator depends on -/// `rustc_infer` for elaborating outlives bounds -- this should only be used for pretty -/// printing. -pub fn super_predicates_for_pretty_printing<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: PolyTraitRef<'tcx>, -) -> impl Iterator> { - let clause = trait_ref.upcast(tcx); - Elaborator { tcx, visited: FxHashSet::from_iter([clause]), stack: vec![clause] } -} - -/// Like [`super_predicates_for_pretty_printing`], except it only returns traits and filters out -/// all other [`Clause`]s. -pub fn supertraits_for_pretty_printing<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: PolyTraitRef<'tcx>, -) -> impl Iterator> { - super_predicates_for_pretty_printing(tcx, trait_ref).filter_map(|clause| { - clause.as_trait_clause().map(|trait_clause| trait_clause.to_poly_trait_ref()) - }) -} - -struct Elaborator<'tcx> { - tcx: TyCtxt<'tcx>, - visited: FxHashSet>, - stack: Vec>, -} - -impl<'tcx> Elaborator<'tcx> { - fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) { - let super_predicates = - self.tcx.explicit_super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( - |&(pred, _)| { - let clause = pred.instantiate_supertrait(self.tcx, trait_ref); - self.visited.insert(clause).then_some(clause) - }, - ); - - self.stack.extend(super_predicates); - } -} - -impl<'tcx> Iterator for Elaborator<'tcx> { - type Item = Clause<'tcx>; - - fn next(&mut self) -> Option> { - if let Some(clause) = self.stack.pop() { - if let Some(trait_clause) = clause.as_trait_clause() { - self.elaborate(trait_clause.to_poly_trait_ref()); - } - Some(clause) - } else { - None - } - } -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 59ab5d791399b..c249579c5d723 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -37,7 +37,7 @@ use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; @@ -532,10 +532,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_def(trait_def_id).implement_via_object } - fn supertrait_def_ids(self, trait_def_id: DefId) -> impl IntoIterator { - self.supertrait_def_ids(trait_def_id) - } - fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed { self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string()) } @@ -2495,25 +2491,7 @@ impl<'tcx> TyCtxt<'tcx> { /// to identify which traits may define a given associated type to help avoid cycle errors, /// and to make size estimates for vtable layout computation. pub fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator + 'tcx { - let mut set = FxHashSet::default(); - let mut stack = vec![trait_def_id]; - - set.insert(trait_def_id); - - iter::from_fn(move || -> Option { - let trait_did = stack.pop()?; - let generic_predicates = self.explicit_super_predicates_of(trait_did); - - for (predicate, _) in generic_predicates.predicates { - if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() { - if set.insert(data.def_id()) { - stack.push(data.def_id()); - } - } - } - - Some(trait_did) - }) + rustc_type_ir::elaborate::supertrait_def_ids(self, trait_def_id) } /// Given a closure signature, returns an equivalent fn signature. Detuples diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7e64c50740659..df080b2887b89 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,7 +1,6 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::query::IntoQueryParam; use crate::query::Providers; -use crate::traits::util::{super_predicates_for_pretty_printing, supertraits_for_pretty_printing}; use crate::ty::GenericArgKind; use crate::ty::{ ConstInt, Expr, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable, @@ -23,6 +22,7 @@ use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::FileNameDisplayPreference; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use rustc_type_ir::{elaborate, Upcast as _}; use smallvec::SmallVec; use std::cell::Cell; @@ -1255,14 +1255,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { entry.has_fn_once = true; return; } else if self.tcx().is_lang_item(trait_def_id, LangItem::FnMut) { - let super_trait_ref = supertraits_for_pretty_printing(self.tcx(), trait_ref) + let super_trait_ref = elaborate::supertraits(self.tcx(), trait_ref) .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait) .unwrap(); fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref); return; } else if self.tcx().is_lang_item(trait_def_id, LangItem::Fn) { - let super_trait_ref = supertraits_for_pretty_printing(self.tcx(), trait_ref) + let super_trait_ref = elaborate::supertraits(self.tcx(), trait_ref) .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait) .unwrap(); @@ -1343,10 +1343,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let bound_principal_with_self = bound_principal .with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self); - let super_projections: Vec<_> = - super_predicates_for_pretty_printing(cx.tcx(), bound_principal_with_self) - .filter_map(|clause| clause.as_projection_clause()) - .collect(); + let clause: ty::Clause<'tcx> = bound_principal_with_self.upcast(cx.tcx()); + let super_projections: Vec<_> = elaborate::elaborate(cx.tcx(), [clause]) + .filter_only_self() + .filter_map(|clause| clause.as_projection_clause()) + .collect(); let mut projections: Vec<_> = predicates .projection_bounds() diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index b2a59eece0d16..f1128f70aaaa6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -6,7 +6,7 @@ use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _}; +use rustc_type_ir::{self as ty, elaborate, Interner, TraitPredicate, Upcast as _}; use tracing::{instrument, trace}; use crate::delegate::SolverDelegate; @@ -862,8 +862,7 @@ where .auto_traits() .into_iter() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { - self.cx() - .supertrait_def_ids(principal_def_id) + elaborate::supertrait_def_ids(self.cx(), principal_def_id) .into_iter() .filter(|def_id| self.cx().trait_is_auto(*def_id)) })) diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 04cdf29a77799..0def7d12f742a 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -229,6 +229,34 @@ impl> Iterator for Elaborator { // Supertrait iterator /////////////////////////////////////////////////////////////////////////// +/// Computes the def-ids of the transitive supertraits 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, +/// and to make size estimates for vtable layout computation. +pub fn supertrait_def_ids( + cx: I, + trait_def_id: I::DefId, +) -> impl Iterator { + let mut set = HashSet::default(); + let mut stack = vec![trait_def_id]; + + set.insert(trait_def_id); + + std::iter::from_fn(move || { + let trait_def_id = stack.pop()?; + + for (predicate, _) in cx.explicit_super_predicates_of(trait_def_id).iter_identity() { + if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() { + if set.insert(data.def_id()) { + stack.push(data.def_id()); + } + } + } + + Some(trait_def_id) + }) +} + pub fn supertraits( tcx: I, trait_ref: ty::Binder>, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 446a4060e62f8..6a291a02d6126 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -253,9 +253,6 @@ pub trait Interner: fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool; - fn supertrait_def_ids(self, trait_def_id: Self::DefId) - -> impl IntoIterator; - fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed; fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool; From 15d16f1cd6f4daea12c7be4e34ff3b5a776671d2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 6 Jul 2024 12:37:04 -0400 Subject: [PATCH 4/4] Finish uplifting supertraits --- compiler/rustc_next_trait_solver/src/delegate.rs | 6 ------ .../rustc_next_trait_solver/src/solve/assembly/mod.rs | 3 ++- compiler/rustc_next_trait_solver/src/solve/trait_goals.rs | 2 +- compiler/rustc_trait_selection/src/solve/delegate.rs | 8 -------- 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 31032dc679ac3..cdea7363d0e62 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -32,12 +32,6 @@ pub trait SolverDelegate: // FIXME: Uplift the leak check into this crate. fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>; - // FIXME: This is only here because elaboration lives in `rustc_infer`! - fn elaborate_supertraits( - cx: Self::Interner, - trait_ref: ty::Binder>, - ) -> impl Iterator>>; - fn try_const_eval_resolve( &self, param_env: ::ParamEnv, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 38a4f7dfe25cb..01dde9ca587ca 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -2,6 +2,7 @@ pub(super) mod structural_traits; +use rustc_type_ir::elaborate; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; @@ -667,7 +668,7 @@ where // a projection goal. if let Some(principal) = bounds.principal() { let principal_trait_ref = principal.with_self_ty(cx, self_ty); - for (idx, assumption) in D::elaborate_supertraits(cx, principal_trait_ref).enumerate() { + for (idx, assumption) in elaborate::supertraits(cx, principal_trait_ref).enumerate() { candidates.extend(G::probe_and_consider_object_bound_candidate( self, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)), diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index f1128f70aaaa6..4474bbc235198 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -787,7 +787,7 @@ where )); } else if let Some(a_principal) = a_data.principal() { for new_a_principal in - D::elaborate_supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty)).skip(1) + elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty)).skip(1) { responses.extend(self.consider_builtin_upcast_to_principal( goal, diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index f98744e906f05..03743e57333a7 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -8,7 +8,6 @@ use rustc_infer::infer::canonical::{ }; use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::solve::Goal; -use rustc_infer::traits::util::supertraits; use rustc_infer::traits::{ObligationCause, Reveal}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; @@ -82,13 +81,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution) } - fn elaborate_supertraits( - interner: TyCtxt<'tcx>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - ) -> impl Iterator>> { - supertraits(interner, trait_ref) - } - fn try_const_eval_resolve( &self, param_env: ty::ParamEnv<'tcx>,