|
8 | 8 | // option. This file may not be copied, modified, or distributed
|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 |
| -// The outlines relation `T: 'a` or `'a: 'b`. |
| 11 | +// The outlines relation `T: 'a` or `'a: 'b`. This code frequently |
| 12 | +// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that |
| 13 | +// RFC for reference. |
12 | 14 |
|
13 | 15 | use middle::infer::InferCtxt;
|
14 | 16 | use middle::ty::{self, RegionEscape, Ty};
|
@@ -67,123 +69,139 @@ pub fn components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
67 | 69 | }
|
68 | 70 |
|
69 | 71 | fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
70 |
| - ty0: Ty<'tcx>, |
| 72 | + ty: Ty<'tcx>, |
71 | 73 | out: &mut Vec<Component<'tcx>>) {
|
72 | 74 | // Descend through the types, looking for the various "base"
|
73 | 75 | // components and collecting them into `out`. This is not written
|
74 | 76 | // with `collect()` because of the need to sometimes skip subtrees
|
75 | 77 | // in the `subtys` iterator (e.g., when encountering a
|
76 | 78 | // projection).
|
77 |
| - let mut subtys = ty0.walk(); |
78 |
| - while let Some(ty) = subtys.next() { |
79 |
| - match ty.sty { |
80 |
| - ty::TyClosure(_, ref substs) => { |
81 |
| - // FIXME(#27086). We do not accumulate from substs, since they |
82 |
| - // don't represent reachable data. This means that, in |
83 |
| - // practice, some of the lifetime parameters might not |
84 |
| - // be in scope when the body runs, so long as there is |
85 |
| - // no reachable data with that lifetime. For better or |
86 |
| - // worse, this is consistent with fn types, however, |
87 |
| - // which can also encapsulate data in this fashion |
88 |
| - // (though it's somewhat harder, and typically |
89 |
| - // requires virtual dispatch). |
90 |
| - // |
91 |
| - // Note that changing this (in a naive way, at least) |
92 |
| - // causes regressions for what appears to be perfectly |
93 |
| - // reasonable code like this: |
94 |
| - // |
95 |
| - // ``` |
96 |
| - // fn foo<'a>(p: &Data<'a>) { |
97 |
| - // bar(|q: &mut Parser| q.read_addr()) |
98 |
| - // } |
99 |
| - // fn bar(p: Box<FnMut(&mut Parser)+'static>) { |
100 |
| - // } |
101 |
| - // ``` |
102 |
| - // |
103 |
| - // Note that `p` (and `'a`) are not used in the |
104 |
| - // closure at all, but to meet the requirement that |
105 |
| - // the closure type `C: 'static` (so it can be coerced |
106 |
| - // to the object type), we get the requirement that |
107 |
| - // `'a: 'static` since `'a` appears in the closure |
108 |
| - // type `C`. |
109 |
| - // |
110 |
| - // A smarter fix might "prune" unused `func_substs` -- |
111 |
| - // this would avoid breaking simple examples like |
112 |
| - // this, but would still break others (which might |
113 |
| - // indeed be invalid, depending on your POV). Pruning |
114 |
| - // would be a subtle process, since we have to see |
115 |
| - // what func/type parameters are used and unused, |
116 |
| - // taking into consideration UFCS and so forth. |
117 |
| - |
118 |
| - for &upvar_ty in &substs.upvar_tys { |
119 |
| - compute_components(infcx, upvar_ty, out); |
120 |
| - } |
121 |
| - subtys.skip_current_subtree(); |
| 79 | + match ty.sty { |
| 80 | + ty::TyClosure(_, ref substs) => { |
| 81 | + // FIXME(#27086). We do not accumulate from substs, since they |
| 82 | + // don't represent reachable data. This means that, in |
| 83 | + // practice, some of the lifetime parameters might not |
| 84 | + // be in scope when the body runs, so long as there is |
| 85 | + // no reachable data with that lifetime. For better or |
| 86 | + // worse, this is consistent with fn types, however, |
| 87 | + // which can also encapsulate data in this fashion |
| 88 | + // (though it's somewhat harder, and typically |
| 89 | + // requires virtual dispatch). |
| 90 | + // |
| 91 | + // Note that changing this (in a naive way, at least) |
| 92 | + // causes regressions for what appears to be perfectly |
| 93 | + // reasonable code like this: |
| 94 | + // |
| 95 | + // ``` |
| 96 | + // fn foo<'a>(p: &Data<'a>) { |
| 97 | + // bar(|q: &mut Parser| q.read_addr()) |
| 98 | + // } |
| 99 | + // fn bar(p: Box<FnMut(&mut Parser)+'static>) { |
| 100 | + // } |
| 101 | + // ``` |
| 102 | + // |
| 103 | + // Note that `p` (and `'a`) are not used in the |
| 104 | + // closure at all, but to meet the requirement that |
| 105 | + // the closure type `C: 'static` (so it can be coerced |
| 106 | + // to the object type), we get the requirement that |
| 107 | + // `'a: 'static` since `'a` appears in the closure |
| 108 | + // type `C`. |
| 109 | + // |
| 110 | + // A smarter fix might "prune" unused `func_substs` -- |
| 111 | + // this would avoid breaking simple examples like |
| 112 | + // this, but would still break others (which might |
| 113 | + // indeed be invalid, depending on your POV). Pruning |
| 114 | + // would be a subtle process, since we have to see |
| 115 | + // what func/type parameters are used and unused, |
| 116 | + // taking into consideration UFCS and so forth. |
| 117 | + |
| 118 | + for &upvar_ty in &substs.upvar_tys { |
| 119 | + compute_components(infcx, upvar_ty, out); |
122 | 120 | }
|
123 |
| - ty::TyBareFn(..) | ty::TyTrait(..) => { |
124 |
| - subtys.skip_current_subtree(); |
| 121 | + } |
| 122 | + |
| 123 | + // Bare functions and traits are both binders. In the RFC, |
| 124 | + // this means we would add the bound regions to the "bound |
| 125 | + // regions list". In our representation, no such list is |
| 126 | + // maintained explicitly, because bound regions themselves can |
| 127 | + // be readily identified. However, because the outlives |
| 128 | + // relation did not used to be applied to fn/trait-object |
| 129 | + // arguments, we due wrap the resulting components in an |
| 130 | + // RFC1214 wrapper so we can issue warnings. |
| 131 | + ty::TyBareFn(..) | ty::TyTrait(..) => { |
| 132 | + // OutlivesFunction, OutlivesObject, OutlivesFragment |
| 133 | + let subcomponents = capture_components(infcx, ty); |
| 134 | + out.push(Component::RFC1214(subcomponents)); |
| 135 | + } |
| 136 | + |
| 137 | + // OutlivesTypeParameterEnv -- the actual checking that `X:'a` |
| 138 | + // is implied by the environment is done in regionck. |
| 139 | + ty::TyParam(p) => { |
| 140 | + out.push(Component::Param(p)); |
| 141 | + } |
| 142 | + |
| 143 | + // For projections, we prefer to generate an obligation like |
| 144 | + // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the |
| 145 | + // regionck more ways to prove that it holds. However, |
| 146 | + // regionck is not (at least currently) prepared to deal with |
| 147 | + // higher-ranked regions that may appear in the |
| 148 | + // trait-ref. Therefore, if we see any higher-ranke regions, |
| 149 | + // we simply fallback to the most restrictive rule, which |
| 150 | + // requires that `Pi: 'a` for all `i`. |
| 151 | + ty::TyProjection(ref data) => { |
| 152 | + if !data.has_escaping_regions() { |
| 153 | + // best case: no escaping regions, so push the |
| 154 | + // projection and skip the subtree (thus generating no |
| 155 | + // constraints for Pi). This defers the choice between |
| 156 | + // the rules OutlivesProjectionEnv, |
| 157 | + // OutlivesProjectionTraitDef, and |
| 158 | + // OutlivesProjectionComponents to regionck. |
| 159 | + out.push(Component::Projection(*data)); |
| 160 | + } else { |
| 161 | + // fallback case: hard code |
| 162 | + // OutlivesProjectionComponents. Continue walking |
| 163 | + // through and constrain Pi. |
125 | 164 | let subcomponents = capture_components(infcx, ty);
|
126 |
| - out.push(Component::RFC1214(subcomponents)); |
127 |
| - } |
128 |
| - ty::TyParam(p) => { |
129 |
| - out.push(Component::Param(p)); |
130 |
| - subtys.skip_current_subtree(); |
131 |
| - } |
132 |
| - ty::TyProjection(ref data) => { |
133 |
| - // For projections, we prefer to generate an |
134 |
| - // obligation like `<P0 as Trait<P1...Pn>>::Foo: 'a`, |
135 |
| - // because this gives the regionck more ways to prove |
136 |
| - // that it holds. However, regionck is not (at least |
137 |
| - // currently) prepared to deal with higher-ranked |
138 |
| - // regions that may appear in the |
139 |
| - // trait-ref. Therefore, if we see any higher-ranke |
140 |
| - // regions, we simply fallback to the most restrictive |
141 |
| - // rule, which requires that `Pi: 'a` for all `i`. |
142 |
| - |
143 |
| - if !data.has_escaping_regions() { |
144 |
| - // best case: no escaping regions, so push the |
145 |
| - // projection and skip the subtree (thus |
146 |
| - // generating no constraints for Pi). |
147 |
| - out.push(Component::Projection(*data)); |
148 |
| - } else { |
149 |
| - // fallback case: continue walking through and |
150 |
| - // constrain Pi. |
151 |
| - let subcomponents = capture_components(infcx, ty); |
152 |
| - out.push(Component::EscapingProjection(subcomponents)); |
153 |
| - } |
154 |
| - subtys.skip_current_subtree(); |
| 165 | + out.push(Component::EscapingProjection(subcomponents)); |
155 | 166 | }
|
156 |
| - ty::TyInfer(_) => { |
157 |
| - let ty = infcx.resolve_type_vars_if_possible(&ty); |
158 |
| - if let ty::TyInfer(infer_ty) = ty.sty { |
159 |
| - out.push(Component::UnresolvedInferenceVariable(infer_ty)); |
160 |
| - } else { |
161 |
| - compute_components(infcx, ty, out); |
162 |
| - } |
| 167 | + } |
| 168 | + |
| 169 | + // If we encounter an inference variable, try to resolve it |
| 170 | + // and proceed with resolved version. If we cannot resolve it, |
| 171 | + // then record the unresolved variable as a component. |
| 172 | + ty::TyInfer(_) => { |
| 173 | + let ty = infcx.resolve_type_vars_if_possible(&ty); |
| 174 | + if let ty::TyInfer(infer_ty) = ty.sty { |
| 175 | + out.push(Component::UnresolvedInferenceVariable(infer_ty)); |
| 176 | + } else { |
| 177 | + compute_components(infcx, ty, out); |
163 | 178 | }
|
| 179 | + } |
164 | 180 |
|
165 |
| - // Most types do not introduce any region binders, nor |
166 |
| - // involve any other subtle cases, and so the WF relation |
167 |
| - // simply constraints any regions referenced directly by |
168 |
| - // the type and then visits the types that are lexically |
169 |
| - // contained within. (The comments refer to relevant rules |
170 |
| - // from RFC1214.) |
171 |
| - ty::TyBool(..) | // OutlivesScalar |
172 |
| - ty::TyChar(..) | // OutlivesScalar |
173 |
| - ty::TyInt(..) | // OutlivesScalar |
174 |
| - ty::TyUint(..) | // OutlivesScalar |
175 |
| - ty::TyFloat(..) | // OutlivesScalar |
176 |
| - ty::TyEnum(..) | // OutlivesNominalType |
177 |
| - ty::TyStruct(..) | // OutlivesNominalType |
178 |
| - ty::TyBox(..) | // OutlivesNominalType (ish) |
179 |
| - ty::TyStr(..) | // OutlivesScalar (ish) |
180 |
| - ty::TyArray(..) | // ... |
181 |
| - ty::TySlice(..) | // ... |
182 |
| - ty::TyRawPtr(..) | // ... |
183 |
| - ty::TyRef(..) | // OutlivesReference |
184 |
| - ty::TyTuple(..) | // ... |
185 |
| - ty::TyError(..) => { |
186 |
| - push_region_constraints(out, ty.regions()); |
| 181 | + // Most types do not introduce any region binders, nor |
| 182 | + // involve any other subtle cases, and so the WF relation |
| 183 | + // simply constraints any regions referenced directly by |
| 184 | + // the type and then visits the types that are lexically |
| 185 | + // contained within. (The comments refer to relevant rules |
| 186 | + // from RFC1214.) |
| 187 | + ty::TyBool(..) | // OutlivesScalar |
| 188 | + ty::TyChar(..) | // OutlivesScalar |
| 189 | + ty::TyInt(..) | // OutlivesScalar |
| 190 | + ty::TyUint(..) | // OutlivesScalar |
| 191 | + ty::TyFloat(..) | // OutlivesScalar |
| 192 | + ty::TyEnum(..) | // OutlivesNominalType |
| 193 | + ty::TyStruct(..) | // OutlivesNominalType |
| 194 | + ty::TyBox(..) | // OutlivesNominalType (ish) |
| 195 | + ty::TyStr(..) | // OutlivesScalar (ish) |
| 196 | + ty::TyArray(..) | // ... |
| 197 | + ty::TySlice(..) | // ... |
| 198 | + ty::TyRawPtr(..) | // ... |
| 199 | + ty::TyRef(..) | // OutlivesReference |
| 200 | + ty::TyTuple(..) | // ... |
| 201 | + ty::TyError(..) => { |
| 202 | + push_region_constraints(out, ty.regions()); |
| 203 | + for subty in ty.walk_shallow() { |
| 204 | + compute_components(infcx, subty, out); |
187 | 205 | }
|
188 | 206 | }
|
189 | 207 | }
|
|
0 commit comments