mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-17 01:13:11 +00:00
91 lines
3.6 KiB
Rust
91 lines
3.6 KiB
Rust
//! Bounds are restrictions applied to some types after they've been converted into the
|
|
//! `ty` form from the HIR.
|
|
|
|
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 forgotten 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> {
|
|
/// A list of region bounds on the (implicit) self type. So if you
|
|
/// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
|
|
/// the `T` is not explicitly included).
|
|
pub region_bounds: Vec<(ty::Binder<'tcx, ty::Region<'tcx>>, Span)>,
|
|
|
|
/// A list of trait bounds. So if you had `T: Debug` this would be
|
|
/// `T: Debug`. Note that the self-type is explicit here.
|
|
pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, ty::BoundConstness)>,
|
|
|
|
/// A list of projection equality bounds. So if you had `T:
|
|
/// Iterator<Item = u32>` this would include `<T as
|
|
/// Iterator>::Item => u32`. Note that the self-type is explicit
|
|
/// here.
|
|
pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
|
|
|
|
/// `Some` if there is *no* `?Sized` predicate. The `span`
|
|
/// is the location in the source of the `T` declaration which can
|
|
/// be cited as the source of the `T: Sized` requirement.
|
|
pub implicitly_sized: Option<Span>,
|
|
}
|
|
|
|
impl<'tcx> Bounds<'tcx> {
|
|
/// Converts a bounds list into a flat set of predicates (like
|
|
/// where-clauses). Because some of our bounds listings (e.g.,
|
|
/// regions) don't include the self-type, you must supply the
|
|
/// self-type here (the `param_ty` parameter).
|
|
pub fn predicates<'out, 's>(
|
|
&'s self,
|
|
tcx: TyCtxt<'tcx>,
|
|
param_ty: Ty<'tcx>,
|
|
// the output must live shorter than the duration of the borrow of self and 'tcx.
|
|
) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
|
|
where
|
|
'tcx: 'out,
|
|
's: 'out,
|
|
{
|
|
// If it could be sized, and is, add the `Sized` predicate.
|
|
let sized_predicate = self.implicitly_sized.and_then(|span| {
|
|
tcx.lang_items().sized_trait().map(move |sized| {
|
|
let trait_ref = ty::Binder::dummy(ty::TraitRef {
|
|
def_id: sized,
|
|
substs: tcx.mk_substs_trait(param_ty, &[]),
|
|
});
|
|
(trait_ref.without_const().to_predicate(tcx), span)
|
|
})
|
|
});
|
|
|
|
let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
|
|
let pred = region_bound
|
|
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
|
|
.to_predicate(tcx);
|
|
(pred, span)
|
|
});
|
|
let trait_bounds =
|
|
self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
|
|
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
|
|
(predicate, span)
|
|
});
|
|
let projection_bounds = self
|
|
.projection_bounds
|
|
.iter()
|
|
.map(move |&(projection, span)| (projection.to_predicate(tcx), span));
|
|
|
|
sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
|
|
}
|
|
}
|