diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index b269bfcbfeb..f54d0418595 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 dca48069974..59ab5d79139 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 00000000000..8c89a2d884b --- /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 7d57d88f40f..4470db47474 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 e9b37503bb3..c2cc3be3aaa 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 52690ae678d..d2b444a066b 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 3447b39fa5b..7df14e81ab5 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 00000000000..04cdf29a777 --- /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 68c2575258d..1db55b26719 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 6e013768c3e..446a4060e62 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 2a909b06baf..b14a65fc779 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;