]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_hir_analysis/src/bounds.rs
Rollup merge of #102232 - Urgau:stabilize-bench_black_box, r=TaKO8Ki
[rust.git] / compiler / rustc_hir_analysis / src / bounds.rs
1 //! Bounds are restrictions applied to some types after they've been converted into the
2 //! `ty` form from the HIR.
3
4 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
5 use rustc_span::Span;
6
7 /// Collects together a list of type bounds. These lists of bounds occur in many places
8 /// in Rust's syntax:
9 ///
10 /// ```text
11 /// trait Foo: Bar + Baz { }
12 ///            ^^^^^^^^^ supertrait list bounding the `Self` type parameter
13 ///
14 /// fn foo<T: Bar + Baz>() { }
15 ///           ^^^^^^^^^ bounding the type parameter `T`
16 ///
17 /// impl dyn Bar + Baz
18 ///          ^^^^^^^^^ bounding the forgotten dynamic type
19 /// ```
20 ///
21 /// Our representation is a bit mixed here -- in some cases, we
22 /// include the self type (e.g., `trait_bounds`) but in others we do not
23 #[derive(Default, PartialEq, Eq, Clone, Debug)]
24 pub struct Bounds<'tcx> {
25     /// A list of region bounds on the (implicit) self type. So if you
26     /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
27     /// the `T` is not explicitly included).
28     pub region_bounds: Vec<(ty::Binder<'tcx, ty::Region<'tcx>>, Span)>,
29
30     /// A list of trait bounds. So if you had `T: Debug` this would be
31     /// `T: Debug`. Note that the self-type is explicit here.
32     pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, ty::BoundConstness)>,
33
34     /// A list of projection equality bounds. So if you had `T:
35     /// Iterator<Item = u32>` this would include `<T as
36     /// Iterator>::Item => u32`. Note that the self-type is explicit
37     /// here.
38     pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
39
40     /// `Some` if there is *no* `?Sized` predicate. The `span`
41     /// is the location in the source of the `T` declaration which can
42     /// be cited as the source of the `T: Sized` requirement.
43     pub implicitly_sized: Option<Span>,
44 }
45
46 impl<'tcx> Bounds<'tcx> {
47     /// Converts a bounds list into a flat set of predicates (like
48     /// where-clauses). Because some of our bounds listings (e.g.,
49     /// regions) don't include the self-type, you must supply the
50     /// self-type here (the `param_ty` parameter).
51     pub fn predicates<'out, 's>(
52         &'s self,
53         tcx: TyCtxt<'tcx>,
54         param_ty: Ty<'tcx>,
55         // the output must live shorter than the duration of the borrow of self and 'tcx.
56     ) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
57     where
58         'tcx: 'out,
59         's: 'out,
60     {
61         // If it could be sized, and is, add the `Sized` predicate.
62         let sized_predicate = self.implicitly_sized.and_then(|span| {
63             tcx.lang_items().sized_trait().map(move |sized| {
64                 let trait_ref = ty::Binder::dummy(ty::TraitRef {
65                     def_id: sized,
66                     substs: tcx.mk_substs_trait(param_ty, &[]),
67                 });
68                 (trait_ref.without_const().to_predicate(tcx), span)
69             })
70         });
71
72         let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
73             let pred = region_bound
74                 .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
75                 .to_predicate(tcx);
76             (pred, span)
77         });
78         let trait_bounds =
79             self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
80                 let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
81                 (predicate, span)
82             });
83         let projection_bounds = self
84             .projection_bounds
85             .iter()
86             .map(move |&(projection, span)| (projection.to_predicate(tcx), span));
87
88         sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
89     }
90 }