]>
Commit | Line | Data |
---|---|---|
3dfed10e XL |
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_hir::Constness; | |
5 | use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; | |
6 | use 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 forgotten 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)] | |
25 | pub struct Bounds<'tcx> { | |
26 | /// A list of region bounds on the (implicit) self type. So if you | |
27 | /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but | |
28 | /// the `T` is not explicitly included). | |
29 | pub region_bounds: Vec<(ty::Region<'tcx>, Span)>, | |
30 | ||
31 | /// A list of trait bounds. So if you had `T: Debug` this would be | |
32 | /// `T: Debug`. Note that the self-type is explicit here. | |
33 | pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>, | |
34 | ||
35 | /// A list of projection equality bounds. So if you had `T: | |
36 | /// Iterator<Item = u32>` this would include `<T as | |
37 | /// Iterator>::Item => u32`. Note that the self-type is explicit | |
38 | /// here. | |
39 | pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>, | |
40 | ||
41 | /// `Some` if there is *no* `?Sized` predicate. The `span` | |
42 | /// is the location in the source of the `T` declaration which can | |
43 | /// be cited as the source of the `T: Sized` requirement. | |
44 | pub implicitly_sized: Option<Span>, | |
45 | } | |
46 | ||
47 | impl<'tcx> Bounds<'tcx> { | |
48 | /// Converts a bounds list into a flat set of predicates (like | |
49 | /// where-clauses). Because some of our bounds listings (e.g., | |
50 | /// regions) don't include the self-type, you must supply the | |
51 | /// self-type here (the `param_ty` parameter). | |
52 | pub fn predicates( | |
53 | &self, | |
54 | tcx: TyCtxt<'tcx>, | |
55 | param_ty: Ty<'tcx>, | |
56 | ) -> Vec<(ty::Predicate<'tcx>, Span)> { | |
57 | // If it could be sized, and is, add the `Sized` predicate. | |
58 | let sized_predicate = self.implicitly_sized.and_then(|span| { | |
59 | tcx.lang_items().sized_trait().map(|sized| { | |
60 | let trait_ref = ty::Binder::bind(ty::TraitRef { | |
61 | def_id: sized, | |
62 | substs: tcx.mk_substs_trait(param_ty, &[]), | |
63 | }); | |
64 | (trait_ref.without_const().to_predicate(tcx), span) | |
65 | }) | |
66 | }); | |
67 | ||
68 | sized_predicate | |
69 | .into_iter() | |
70 | .chain( | |
71 | self.region_bounds | |
72 | .iter() | |
73 | .map(|&(region_bound, span)| { | |
3dfed10e XL |
74 | let outlives = ty::OutlivesPredicate(param_ty, region_bound); |
75 | (ty::Binder::bind(outlives).to_predicate(tcx), span) | |
76 | }) | |
77 | .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { | |
78 | let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); | |
79 | (predicate, span) | |
80 | })) | |
81 | .chain( | |
82 | self.projection_bounds | |
83 | .iter() | |
84 | .map(|&(projection, span)| (projection.to_predicate(tcx), span)), | |
85 | ), | |
86 | ) | |
87 | .collect() | |
88 | } | |
89 | } |