]>
Commit | Line | Data |
---|---|---|
c295e0f8 | 1 | use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; |
5099ac24 | 2 | use rustc_middle::ty::{self, Region, Ty, TyCtxt}; |
add651ee | 3 | use rustc_middle::ty::{GenericArg, GenericArgKind}; |
dfeec247 | 4 | use rustc_span::Span; |
a1dfa0c6 | 5 | use smallvec::smallvec; |
e74abb32 | 6 | use std::collections::BTreeMap; |
94b46f34 XL |
7 | |
8 | /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred | |
9 | /// must be added to the struct header. | |
064997fb | 10 | pub(crate) type RequiredPredicates<'tcx> = |
e74abb32 | 11 | BTreeMap<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>, Span>; |
94b46f34 XL |
12 | |
13 | /// Given a requirement `T: 'a` or `'b: 'a`, deduce the | |
14 | /// outlives_component and add it to `required_predicates` | |
064997fb | 15 | pub(crate) fn insert_outlives_predicate<'tcx>( |
dc9dc135 | 16 | tcx: TyCtxt<'tcx>, |
e74abb32 | 17 | kind: GenericArg<'tcx>, |
94b46f34 | 18 | outlived_region: Region<'tcx>, |
e74abb32 | 19 | span: Span, |
94b46f34 XL |
20 | required_predicates: &mut RequiredPredicates<'tcx>, |
21 | ) { | |
22 | // If the `'a` region is bound within the field type itself, we | |
23 | // don't want to propagate this constraint to the header. | |
923072b8 | 24 | if !is_free_region(outlived_region) { |
94b46f34 XL |
25 | return; |
26 | } | |
27 | ||
28 | match kind.unpack() { | |
e74abb32 | 29 | GenericArgKind::Type(ty) => { |
94b46f34 XL |
30 | // `T: 'outlived_region` for some type `T` |
31 | // But T could be a lot of things: | |
32 | // e.g., if `T = &'b u32`, then `'b: 'outlived_region` is | |
33 | // what we want to add. | |
34 | // | |
35 | // Or if within `struct Foo<U>` you had `T = Vec<U>`, then | |
36 | // we would want to add `U: 'outlived_region` | |
a1dfa0c6 | 37 | let mut components = smallvec![]; |
c295e0f8 | 38 | push_outlives_components(tcx, ty, &mut components); |
a1dfa0c6 | 39 | for component in components { |
94b46f34 XL |
40 | match component { |
41 | Component::Region(r) => { | |
42 | // This would arise from something like: | |
43 | // | |
44 | // ``` | |
45 | // struct Foo<'a, 'b> { | |
46 | // x: &'a &'b u32 | |
47 | // } | |
48 | // ``` | |
49 | // | |
50 | // Here `outlived_region = 'a` and `kind = &'b | |
9c376795 | 51 | // u32`. Decomposing `&'b u32` into |
94b46f34 XL |
52 | // components would yield `'b`, and we add the |
53 | // where clause that `'b: 'a`. | |
54 | insert_outlives_predicate( | |
55 | tcx, | |
56 | r.into(), | |
57 | outlived_region, | |
e74abb32 | 58 | span, |
94b46f34 XL |
59 | required_predicates, |
60 | ); | |
61 | } | |
62 | ||
63 | Component::Param(param_ty) => { | |
64 | // param_ty: ty::ParamTy | |
65 | // This would arise from something like: | |
66 | // | |
67 | // ``` | |
68 | // struct Foo<'a, U> { | |
69 | // x: &'a Vec<U> | |
70 | // } | |
71 | // ``` | |
72 | // | |
73 | // Here `outlived_region = 'a` and `kind = | |
9c376795 | 74 | // Vec<U>`. Decomposing `Vec<U>` into |
94b46f34 XL |
75 | // components would yield `U`, and we add the |
76 | // where clause that `U: 'a`. | |
77 | let ty: Ty<'tcx> = param_ty.to_ty(tcx); | |
78 | required_predicates | |
e74abb32 XL |
79 | .entry(ty::OutlivesPredicate(ty.into(), outlived_region)) |
80 | .or_insert(span); | |
94b46f34 XL |
81 | } |
82 | ||
4b012472 FG |
83 | Component::Placeholder(_) => { |
84 | span_bug!(span, "Should not deduce placeholder outlives component"); | |
85 | } | |
86 | ||
9c376795 FG |
87 | Component::Alias(alias_ty) => { |
88 | // This would either arise from something like: | |
94b46f34 XL |
89 | // |
90 | // ``` | |
91 | // struct Foo<'a, T: Iterator> { | |
92 | // x: &'a <T as Iterator>::Item | |
93 | // } | |
94 | // ``` | |
95 | // | |
9c376795 | 96 | // or: |
2b03887a FG |
97 | // |
98 | // ```rust | |
99 | // type Opaque<T> = impl Sized; | |
100 | // fn defining<T>() -> Opaque<T> {} | |
101 | // struct Ss<'a, T>(&'a Opaque<T>); | |
102 | // ``` | |
103 | // | |
9c376795 FG |
104 | // Here we want to add an explicit `where <T as Iterator>::Item: 'a` |
105 | // or `Opaque<T>: 'a` depending on the alias kind. | |
106 | let ty = alias_ty.to_ty(tcx); | |
2b03887a FG |
107 | required_predicates |
108 | .entry(ty::OutlivesPredicate(ty.into(), outlived_region)) | |
109 | .or_insert(span); | |
110 | } | |
111 | ||
9c376795 | 112 | Component::EscapingAlias(_) => { |
94b46f34 | 113 | // As above, but the projection involves |
9c376795 | 114 | // late-bound regions. Therefore, the WF |
94b46f34 XL |
115 | // requirement is not checked in type definition |
116 | // but at fn call site, so ignore it. | |
117 | // | |
118 | // ``` | |
119 | // struct Foo<'a, T: Iterator> { | |
120 | // x: for<'b> fn(<&'b T as Iterator>::Item) | |
121 | // // ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
122 | // } | |
123 | // ``` | |
124 | // | |
125 | // Since `'b` is not in scope on `Foo`, can't | |
126 | // do anything here, ignore it. | |
127 | } | |
128 | ||
129 | Component::UnresolvedInferenceVariable(_) => bug!("not using infcx"), | |
130 | } | |
131 | } | |
132 | } | |
133 | ||
e74abb32 | 134 | GenericArgKind::Lifetime(r) => { |
923072b8 | 135 | if !is_free_region(r) { |
94b46f34 XL |
136 | return; |
137 | } | |
dfeec247 | 138 | required_predicates.entry(ty::OutlivesPredicate(kind, outlived_region)).or_insert(span); |
94b46f34 | 139 | } |
532ac7d7 | 140 | |
e74abb32 | 141 | GenericArgKind::Const(_) => { |
532ac7d7 XL |
142 | // Generic consts don't impose any constraints. |
143 | } | |
94b46f34 XL |
144 | } |
145 | } | |
146 | ||
923072b8 | 147 | fn is_free_region(region: Region<'_>) -> bool { |
94b46f34 | 148 | // First, screen for regions that might appear in a type header. |
5099ac24 | 149 | match *region { |
8faf50e0 | 150 | // These correspond to `T: 'a` relationships: |
94b46f34 XL |
151 | // |
152 | // struct Foo<'a, T> { | |
4b012472 | 153 | // field: &'a T, // this would generate a ReEarlyParam referencing `'a` |
94b46f34 XL |
154 | // } |
155 | // | |
156 | // We care about these, so fall through. | |
4b012472 | 157 | ty::ReEarlyParam(_) => true, |
8faf50e0 XL |
158 | |
159 | // These correspond to `T: 'static` relationships which can be | |
923072b8 | 160 | // rather surprising. |
8faf50e0 XL |
161 | // |
162 | // struct Foo<'a, T> { | |
163 | // field: &'static T, // this would generate a ReStatic | |
164 | // } | |
923072b8 | 165 | ty::ReStatic => false, |
94b46f34 XL |
166 | |
167 | // Late-bound regions can appear in `fn` types: | |
168 | // | |
169 | // struct Foo<T> { | |
170 | // field: for<'b> fn(&'b T) // e.g., 'b here | |
171 | // } | |
172 | // | |
173 | // The type above might generate a `T: 'b` bound, but we can | |
4b012472 FG |
174 | // ignore it. We can't name this lifetime pn the struct header anyway. |
175 | ty::ReBound(..) => false, | |
94b46f34 | 176 | |
9ffffee4 FG |
177 | ty::ReError(_) => false, |
178 | ||
94b46f34 | 179 | // These regions don't appear in types from type declarations: |
4b012472 | 180 | ty::ReErased | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReLateParam(..) => { |
94b46f34 XL |
181 | bug!("unexpected region in outlives inference: {:?}", region); |
182 | } | |
183 | } | |
184 | } |