blob: b6688e0ce29e00a523c3bc716a0b2fd22256440a [file] [log] [blame]
//! Bounds are restrictions applied to some types after they've been converted into the
//! `ty` form from the HIR.
use rustc_hir::LangItem;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_span::Span;
/// Collects together a list of type bounds. These lists of bounds occur in many places
/// in Rust's syntax:
///
/// ```text
/// trait Foo: Bar + Baz { }
/// ^^^^^^^^^ supertrait list bounding the `Self` type parameter
///
/// fn foo<T: Bar + Baz>() { }
/// ^^^^^^^^^ bounding the type parameter `T`
///
/// impl dyn Bar + Baz
/// ^^^^^^^^^ bounding the type-erased dynamic type
/// ```
///
/// Our representation is a bit mixed here -- in some cases, we
/// include the self type (e.g., `trait_bounds`) but in others we do not
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
pub clauses: Vec<(ty::Clause<'tcx>, Span)>,
}
impl<'tcx> Bounds<'tcx> {
pub fn push_region_bound(
&mut self,
tcx: TyCtxt<'tcx>,
region: ty::PolyTypeOutlivesPredicate<'tcx>,
span: Span,
) {
self.clauses
.push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).to_predicate(tcx), span));
}
pub fn push_trait_bound(
&mut self,
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
polarity: ty::ImplPolarity,
) {
self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
// push a non-const (`host = true`) version of the bound if it is `~const`.
if tcx.features().effects
&& let Some(host_effect_idx) = tcx.generics_of(trait_ref.def_id()).host_effect_index
&& trait_ref.skip_binder().args.const_at(host_effect_idx) != tcx.consts.true_
{
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
.map_bound(|trait_ref| {
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
})
.to_predicate(tcx),
span,
));
}
pub fn push_projection_bound(
&mut self,
tcx: TyCtxt<'tcx>,
projection: ty::PolyProjectionPredicate<'tcx>,
span: Span,
) {
self.clauses.push((
projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).to_predicate(tcx),
span,
));
}
pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]);
// Preferable to put this obligation first, since we report better errors for sized ambiguity.
self.clauses.insert(0, (trait_ref.to_predicate(tcx), span));
}
pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
self.clauses.iter().cloned()
}
}