rustc_hir_analysis/
bounds.rs

1//! Bounds are restrictions applied to some types after they've been lowered from the HIR to the
2//! [`rustc_middle::ty`] form.
3
4use rustc_hir::LangItem;
5use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
6use rustc_span::Span;
7
8/// Collects together a list of type bounds. These lists of bounds occur in many places
9/// in Rust's syntax:
10///
11/// ```text
12/// trait Foo: Bar + Baz { }
13///            ^^^^^^^^^ supertrait list bounding the `Self` type parameter
14///
15/// fn foo<T: Bar + Baz>() { }
16///           ^^^^^^^^^ bounding the type parameter `T`
17///
18/// impl dyn Bar + Baz
19///          ^^^^^^^^^ bounding the type-erased dynamic type
20/// ```
21///
22/// Our representation is a bit mixed here -- in some cases, we
23/// include the self type (e.g., `trait_bounds`) but in others we do not
24#[derive(Default, PartialEq, Eq, Clone, Debug)]
25pub(crate) struct Bounds<'tcx> {
26    clauses: Vec<(ty::Clause<'tcx>, Span)>,
27}
28
29impl<'tcx> Bounds<'tcx> {
30    pub(crate) fn push_region_bound(
31        &mut self,
32        tcx: TyCtxt<'tcx>,
33        region: ty::PolyTypeOutlivesPredicate<'tcx>,
34        span: Span,
35    ) {
36        self.clauses
37            .push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).upcast(tcx), span));
38    }
39
40    pub(crate) fn push_trait_bound(
41        &mut self,
42        tcx: TyCtxt<'tcx>,
43        bound_trait_ref: ty::PolyTraitRef<'tcx>,
44        span: Span,
45        polarity: ty::PredicatePolarity,
46    ) {
47        let clause = (
48            bound_trait_ref
49                .map_bound(|trait_ref| {
50                    ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
51                })
52                .upcast(tcx),
53            span,
54        );
55        // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
56        if tcx.is_lang_item(bound_trait_ref.def_id(), LangItem::Sized) {
57            self.clauses.insert(0, clause);
58        } else {
59            self.clauses.push(clause);
60        }
61    }
62
63    pub(crate) fn push_projection_bound(
64        &mut self,
65        tcx: TyCtxt<'tcx>,
66        projection: ty::PolyProjectionPredicate<'tcx>,
67        span: Span,
68    ) {
69        self.clauses.push((
70            projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).upcast(tcx),
71            span,
72        ));
73    }
74
75    pub(crate) fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
76        let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
77        let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]);
78        // Preferable to put this obligation first, since we report better errors for sized ambiguity.
79        self.clauses.insert(0, (trait_ref.upcast(tcx), span));
80    }
81
82    /// Push a `const` or `~const` bound as a `HostEffect` predicate.
83    pub(crate) fn push_const_bound(
84        &mut self,
85        tcx: TyCtxt<'tcx>,
86        bound_trait_ref: ty::PolyTraitRef<'tcx>,
87        constness: ty::BoundConstness,
88        span: Span,
89    ) {
90        if tcx.is_const_trait(bound_trait_ref.def_id()) {
91            self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, constness), span));
92        } else {
93            tcx.dcx().span_delayed_bug(span, "tried to lower {host:?} bound for non-const trait");
94        }
95    }
96
97    pub(crate) fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
98        self.clauses.iter().cloned()
99    }
100}