]>
Commit | Line | Data |
---|---|---|
abe05a73 | 1 | //! Code that handles "type-outlives" constraints like `T: 'a`. This |
c295e0f8 | 2 | //! is based on the `push_outlives_components` function defined in rustc_infer, |
abe05a73 XL |
3 | //! but it adds a bit of heuristics on top, in particular to deal with |
4 | //! associated types and projections. | |
5 | //! | |
6 | //! When we process a given `T: 'a` obligation, we may produce two | |
7 | //! kinds of constraints for the region inferencer: | |
8 | //! | |
9 | //! - Relationships between inference variables and other regions. | |
10 | //! For example, if we have `&'?0 u32: 'a`, then we would produce | |
11 | //! a constraint that `'a <= '?0`. | |
12 | //! - "Verifys" that must be checked after inferencing is done. | |
13 | //! For example, if we know that, for some type parameter `T`, | |
14 | //! `T: 'a + 'b`, and we have a requirement that `T: '?1`, | |
15 | //! then we add a "verify" that checks that `'?1 <= 'a || '?1 <= 'b`. | |
16 | //! - Note the difference with the previous case: here, the region | |
17 | //! variable must be less than something else, so this doesn't | |
18 | //! affect how inference works (it finds the smallest region that | |
19 | //! will do); it's just a post-condition that we have to check. | |
20 | //! | |
21 | //! **The key point is that once this function is done, we have | |
22 | //! reduced all of our "type-region outlives" obligations into relationships | |
23 | //! between individual regions.** | |
24 | //! | |
25 | //! One key input to this function is the set of "region-bound pairs". | |
26 | //! These are basically the relationships between type parameters and | |
27 | //! regions that are in scope at the point where the outlives | |
28 | //! obligation was incurred. **When type-checking a function, | |
29 | //! particularly in the face of closures, this is not known until | |
30 | //! regionck runs!** This is because some of those bounds come | |
31 | //! from things we have yet to infer. | |
32 | //! | |
33 | //! Consider: | |
34 | //! | |
35 | //! ``` | |
36 | //! fn bar<T>(a: T, b: impl for<'a> Fn(&'a T)); | |
37 | //! fn foo<T>(x: T) { | |
38 | //! bar(x, |y| { ... }) | |
39 | //! // ^ closure arg | |
40 | //! } | |
41 | //! ``` | |
42 | //! | |
43 | //! Here, the type of `y` may involve inference variables and the | |
44 | //! like, and it may also contain implied bounds that are needed to | |
45 | //! type-check the closure body (e.g., here it informs us that `T` | |
46 | //! outlives the late-bound region `'a`). | |
47 | //! | |
48 | //! Note that by delaying the gathering of implied bounds until all | |
49 | //! inference information is known, we may find relationships between | |
50 | //! bound regions and other regions in the environment. For example, | |
51 | //! when we first check a closure like the one expected as argument | |
52 | //! to `foo`: | |
53 | //! | |
54 | //! ``` | |
55 | //! fn foo<U, F: for<'a> FnMut(&'a U)>(_f: F) {} | |
56 | //! ``` | |
57 | //! | |
9fa01778 | 58 | //! the type of the closure's first argument would be `&'a ?U`. We |
abe05a73 XL |
59 | //! might later infer `?U` to something like `&'b u32`, which would |
60 | //! imply that `'b: 'a`. | |
61 | ||
c295e0f8 | 62 | use crate::infer::outlives::components::{push_outlives_components, Component}; |
9fa01778 XL |
63 | use crate::infer::outlives::env::RegionBoundPairs; |
64 | use crate::infer::outlives::verify::VerifyBoundCx; | |
f9f354fc XL |
65 | use crate::infer::{ |
66 | self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound, | |
67 | }; | |
94222f64 | 68 | use crate::traits::{ObligationCause, ObligationCauseCode}; |
ba9703b0 XL |
69 | use rustc_middle::ty::subst::GenericArgKind; |
70 | use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; | |
74b04a01 | 71 | |
dfeec247 | 72 | use rustc_data_structures::fx::FxHashMap; |
f9f354fc | 73 | use rustc_data_structures::undo_log::UndoLogs; |
dfeec247 | 74 | use rustc_hir as hir; |
74b04a01 | 75 | use smallvec::smallvec; |
abe05a73 | 76 | |
dc9dc135 | 77 | impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { |
abe05a73 XL |
78 | /// Registers that the given region obligation must be resolved |
79 | /// from within the scope of `body_id`. These regions are enqueued | |
80 | /// and later processed by regionck, when full type information is | |
81 | /// available (see `region_obligations` field for more | |
82 | /// information). | |
83 | pub fn register_region_obligation( | |
84 | &self, | |
9fa01778 | 85 | body_id: hir::HirId, |
abe05a73 XL |
86 | obligation: RegionObligation<'tcx>, |
87 | ) { | |
dfeec247 | 88 | debug!("register_region_obligation(body_id={:?}, obligation={:?})", body_id, obligation); |
ff7c6d11 | 89 | |
f9f354fc XL |
90 | let mut inner = self.inner.borrow_mut(); |
91 | inner.undo_log.push(UndoLog::PushRegionObligation); | |
92 | inner.region_obligations.push((body_id, obligation)); | |
abe05a73 XL |
93 | } |
94 | ||
0bf4aa26 XL |
95 | pub fn register_region_obligation_with_cause( |
96 | &self, | |
97 | sup_type: Ty<'tcx>, | |
98 | sub_region: Region<'tcx>, | |
99 | cause: &ObligationCause<'tcx>, | |
100 | ) { | |
101 | let origin = SubregionOrigin::from_obligation_cause(cause, || { | |
94222f64 XL |
102 | infer::RelateParamBound( |
103 | cause.span, | |
104 | sup_type, | |
105 | match cause.code.peel_derives() { | |
106 | ObligationCauseCode::BindingObligation(_, span) => Some(*span), | |
107 | _ => None, | |
108 | }, | |
109 | ) | |
0bf4aa26 XL |
110 | }); |
111 | ||
112 | self.register_region_obligation( | |
113 | cause.body_id, | |
dfeec247 | 114 | RegionObligation { sup_type, sub_region, origin }, |
0bf4aa26 XL |
115 | ); |
116 | } | |
117 | ||
0531ce1d | 118 | /// Trait queries just want to pass back type obligations "as is" |
9fa01778 | 119 | pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> { |
29967ef6 | 120 | std::mem::take(&mut self.inner.borrow_mut().region_obligations) |
0531ce1d XL |
121 | } |
122 | ||
abe05a73 XL |
123 | /// Process the region obligations that must be proven (during |
124 | /// `regionck`) for the given `body_id`, given information about | |
125 | /// the region bounds in scope and so forth. This function must be | |
126 | /// invoked for all relevant body-ids before region inference is | |
127 | /// done (or else an assert will fire). | |
128 | /// | |
129 | /// See the `region_obligations` field of `InferCtxt` for some | |
0531ce1d | 130 | /// comments about how this function fits into the overall expected |
a1dfa0c6 | 131 | /// flow of the inferencer. The key point is that it is |
abe05a73 XL |
132 | /// invoked after all type-inference variables have been bound -- |
133 | /// towards the end of regionck. This also ensures that the | |
134 | /// region-bound-pairs are available (see comments above regarding | |
135 | /// closures). | |
136 | /// | |
137 | /// # Parameters | |
138 | /// | |
139 | /// - `region_bound_pairs`: the set of region bounds implied by | |
140 | /// the parameters and where-clauses. In particular, each pair | |
141 | /// `('a, K)` in this list tells us that the bounds in scope | |
142 | /// indicate that `K: 'a`, where `K` is either a generic | |
143 | /// parameter like `T` or a projection like `T::Item`. | |
144 | /// - `implicit_region_bound`: if some, this is a region bound | |
145 | /// that is considered to hold for all type parameters (the | |
146 | /// function body). | |
147 | /// - `param_env` is the parameter environment for the enclosing function. | |
148 | /// - `body_id` is the body-id whose region obligations are being | |
149 | /// processed. | |
150 | /// | |
151 | /// # Returns | |
152 | /// | |
153 | /// This function may have to perform normalizations, and hence it | |
154 | /// returns an `InferOk` with subobligations that must be | |
155 | /// processed. | |
156 | pub fn process_registered_region_obligations( | |
157 | &self, | |
9fa01778 | 158 | region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>, |
abe05a73 XL |
159 | implicit_region_bound: Option<ty::Region<'tcx>>, |
160 | param_env: ty::ParamEnv<'tcx>, | |
abe05a73 XL |
161 | ) { |
162 | assert!( | |
163 | !self.in_snapshot.get(), | |
164 | "cannot process registered region obligations in a snapshot" | |
165 | ); | |
166 | ||
ff7c6d11 XL |
167 | debug!("process_registered_region_obligations()"); |
168 | ||
0bf4aa26 | 169 | let my_region_obligations = self.take_registered_region_obligations(); |
abe05a73 | 170 | |
dfeec247 | 171 | for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations { |
ff7c6d11 | 172 | debug!( |
0bf4aa26 XL |
173 | "process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}", |
174 | sup_type, sub_region, origin | |
ff7c6d11 XL |
175 | ); |
176 | ||
fc512014 | 177 | let sup_type = self.resolve_vars_if_possible(sup_type); |
0bf4aa26 XL |
178 | |
179 | if let Some(region_bound_pairs) = region_bound_pairs_map.get(&body_id) { | |
180 | let outlives = &mut TypeOutlives::new( | |
181 | self, | |
182 | self.tcx, | |
183 | ®ion_bound_pairs, | |
184 | implicit_region_bound, | |
185 | param_env, | |
186 | ); | |
187 | outlives.type_must_outlive(origin, sup_type, sub_region); | |
188 | } else { | |
189 | self.tcx.sess.delay_span_bug( | |
190 | origin.span(), | |
191 | &format!("no region-bound-pairs for {:?}", body_id), | |
192 | ) | |
193 | } | |
abe05a73 XL |
194 | } |
195 | } | |
abe05a73 XL |
196 | } |
197 | ||
8faf50e0 | 198 | /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` |
60c5eb7d | 199 | /// obligation into a series of `'a: 'b` constraints and "verify"s, as |
8faf50e0 XL |
200 | /// described on the module comment. The final constraints are emitted |
201 | /// via a "delegate" of type `D` -- this is usually the `infcx`, which | |
202 | /// accrues them into the `region_obligations` code, but for NLL we | |
203 | /// use something else. | |
dc9dc135 | 204 | pub struct TypeOutlives<'cx, 'tcx, D> |
8faf50e0 XL |
205 | where |
206 | D: TypeOutlivesDelegate<'tcx>, | |
207 | { | |
abe05a73 XL |
208 | // See the comments on `process_registered_region_obligations` for the meaning |
209 | // of these fields. | |
8faf50e0 | 210 | delegate: D, |
dc9dc135 XL |
211 | tcx: TyCtxt<'tcx>, |
212 | verify_bound: VerifyBoundCx<'cx, 'tcx>, | |
abe05a73 XL |
213 | } |
214 | ||
8faf50e0 XL |
215 | pub trait TypeOutlivesDelegate<'tcx> { |
216 | fn push_sub_region_constraint( | |
217 | &mut self, | |
218 | origin: SubregionOrigin<'tcx>, | |
219 | a: ty::Region<'tcx>, | |
220 | b: ty::Region<'tcx>, | |
221 | ); | |
222 | ||
223 | fn push_verify( | |
224 | &mut self, | |
225 | origin: SubregionOrigin<'tcx>, | |
226 | kind: GenericKind<'tcx>, | |
227 | a: ty::Region<'tcx>, | |
228 | bound: VerifyBound<'tcx>, | |
229 | ); | |
230 | } | |
231 | ||
dc9dc135 | 232 | impl<'cx, 'tcx, D> TypeOutlives<'cx, 'tcx, D> |
8faf50e0 XL |
233 | where |
234 | D: TypeOutlivesDelegate<'tcx>, | |
235 | { | |
236 | pub fn new( | |
237 | delegate: D, | |
dc9dc135 | 238 | tcx: TyCtxt<'tcx>, |
0bf4aa26 | 239 | region_bound_pairs: &'cx RegionBoundPairs<'tcx>, |
abe05a73 XL |
240 | implicit_region_bound: Option<ty::Region<'tcx>>, |
241 | param_env: ty::ParamEnv<'tcx>, | |
242 | ) -> Self { | |
243 | Self { | |
8faf50e0 XL |
244 | delegate, |
245 | tcx, | |
0bf4aa26 XL |
246 | verify_bound: VerifyBoundCx::new( |
247 | tcx, | |
248 | region_bound_pairs, | |
249 | implicit_region_bound, | |
250 | param_env, | |
251 | ), | |
abe05a73 XL |
252 | } |
253 | } | |
254 | ||
255 | /// Adds constraints to inference such that `T: 'a` holds (or | |
256 | /// reports an error if it cannot). | |
257 | /// | |
258 | /// # Parameters | |
259 | /// | |
260 | /// - `origin`, the reason we need this constraint | |
261 | /// - `ty`, the type `T` | |
262 | /// - `region`, the region `'a` | |
8faf50e0 XL |
263 | pub fn type_must_outlive( |
264 | &mut self, | |
abe05a73 XL |
265 | origin: infer::SubregionOrigin<'tcx>, |
266 | ty: Ty<'tcx>, | |
267 | region: ty::Region<'tcx>, | |
268 | ) { | |
dfeec247 | 269 | debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})", ty, region, origin); |
abe05a73 | 270 | |
a1dfa0c6 | 271 | assert!(!ty.has_escaping_bound_vars()); |
abe05a73 | 272 | |
a1dfa0c6 | 273 | let mut components = smallvec![]; |
c295e0f8 | 274 | push_outlives_components(self.tcx, ty, &mut components); |
a1dfa0c6 | 275 | self.components_must_outlive(origin, &components, region); |
abe05a73 XL |
276 | } |
277 | ||
abe05a73 | 278 | fn components_must_outlive( |
8faf50e0 | 279 | &mut self, |
abe05a73 | 280 | origin: infer::SubregionOrigin<'tcx>, |
a1dfa0c6 | 281 | components: &[Component<'tcx>], |
abe05a73 XL |
282 | region: ty::Region<'tcx>, |
283 | ) { | |
a1dfa0c6 | 284 | for component in components.iter() { |
abe05a73 XL |
285 | let origin = origin.clone(); |
286 | match component { | |
287 | Component::Region(region1) => { | |
dfeec247 | 288 | self.delegate.push_sub_region_constraint(origin, region, region1); |
abe05a73 XL |
289 | } |
290 | Component::Param(param_ty) => { | |
a1dfa0c6 | 291 | self.param_ty_must_outlive(origin, region, *param_ty); |
abe05a73 XL |
292 | } |
293 | Component::Projection(projection_ty) => { | |
a1dfa0c6 | 294 | self.projection_must_outlive(origin, region, *projection_ty); |
abe05a73 XL |
295 | } |
296 | Component::EscapingProjection(subcomponents) => { | |
a1dfa0c6 | 297 | self.components_must_outlive(origin, &subcomponents, region); |
abe05a73 XL |
298 | } |
299 | Component::UnresolvedInferenceVariable(v) => { | |
300 | // ignore this, we presume it will yield an error | |
301 | // later, since if a type variable is not resolved by | |
302 | // this point it never will be | |
8faf50e0 | 303 | self.tcx.sess.delay_span_bug( |
abe05a73 XL |
304 | origin.span(), |
305 | &format!("unresolved inference variable in outlives: {:?}", v), | |
306 | ); | |
307 | } | |
308 | } | |
309 | } | |
310 | } | |
311 | ||
312 | fn param_ty_must_outlive( | |
8faf50e0 | 313 | &mut self, |
abe05a73 XL |
314 | origin: infer::SubregionOrigin<'tcx>, |
315 | region: ty::Region<'tcx>, | |
316 | param_ty: ty::ParamTy, | |
317 | ) { | |
318 | debug!( | |
319 | "param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", | |
8faf50e0 | 320 | region, param_ty, origin |
abe05a73 XL |
321 | ); |
322 | ||
abe05a73 | 323 | let generic = GenericKind::Param(param_ty); |
0bf4aa26 | 324 | let verify_bound = self.verify_bound.generic_bound(generic); |
dfeec247 | 325 | self.delegate.push_verify(origin, generic, region, verify_bound); |
abe05a73 XL |
326 | } |
327 | ||
328 | fn projection_must_outlive( | |
8faf50e0 | 329 | &mut self, |
abe05a73 XL |
330 | origin: infer::SubregionOrigin<'tcx>, |
331 | region: ty::Region<'tcx>, | |
332 | projection_ty: ty::ProjectionTy<'tcx>, | |
333 | ) { | |
334 | debug!( | |
335 | "projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})", | |
8faf50e0 | 336 | region, projection_ty, origin |
abe05a73 XL |
337 | ); |
338 | ||
339 | // This case is thorny for inference. The fundamental problem is | |
340 | // that there are many cases where we have choice, and inference | |
341 | // doesn't like choice (the current region inference in | |
342 | // particular). :) First off, we have to choose between using the | |
343 | // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and | |
344 | // OutlivesProjectionComponent rules, any one of which is | |
345 | // sufficient. If there are no inference variables involved, it's | |
346 | // not hard to pick the right rule, but if there are, we're in a | |
347 | // bit of a catch 22: if we picked which rule we were going to | |
348 | // use, we could add constraints to the region inference graph | |
349 | // that make it apply, but if we don't add those constraints, the | |
350 | // rule might not apply (but another rule might). For now, we err | |
351 | // on the side of adding too few edges into the graph. | |
352 | ||
13cf67c4 XL |
353 | // Compute the bounds we can derive from the trait definition. |
354 | // These are guaranteed to apply, no matter the inference | |
355 | // results. | |
dfeec247 XL |
356 | let trait_bounds: Vec<_> = |
357 | self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect(); | |
13cf67c4 | 358 | |
0bf4aa26 XL |
359 | // Compute the bounds we can derive from the environment. This |
360 | // is an "approximate" match -- in some cases, these bounds | |
361 | // may not apply. | |
dfeec247 XL |
362 | let mut approx_env_bounds = |
363 | self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty); | |
364 | debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds); | |
abe05a73 | 365 | |
13cf67c4 XL |
366 | // Remove outlives bounds that we get from the environment but |
367 | // which are also deducable from the trait. This arises (cc | |
0731742a | 368 | // #55756) in cases where you have e.g., `<T as Foo<'a>>::Item: |
13cf67c4 XL |
369 | // 'a` in the environment but `trait Foo<'b> { type Item: 'b |
370 | // }` in the trait definition. | |
1b1a35ee | 371 | approx_env_bounds.retain(|bound| match *bound.0.kind() { |
dfeec247 XL |
372 | ty::Projection(projection_ty) => self |
373 | .verify_bound | |
374 | .projection_declared_bounds_from_trait(projection_ty) | |
375 | .all(|r| r != bound.1), | |
13cf67c4 | 376 | |
dfeec247 | 377 | _ => panic!("expected only projection types from env, not {:?}", bound.0), |
13cf67c4 | 378 | }); |
abe05a73 XL |
379 | |
380 | // If declared bounds list is empty, the only applicable rule is | |
381 | // OutlivesProjectionComponent. If there are inference variables, | |
382 | // then, we can break down the outlives into more primitive | |
383 | // components without adding unnecessary edges. | |
384 | // | |
385 | // If there are *no* inference variables, however, we COULD do | |
386 | // this, but we choose not to, because the error messages are less | |
387 | // good. For example, a requirement like `T::Item: 'r` would be | |
388 | // translated to a requirement that `T: 'r`; when this is reported | |
389 | // to the user, it will thus say "T: 'r must hold so that T::Item: | |
390 | // 'r holds". But that makes it sound like the only way to fix | |
391 | // the problem is to add `T: 'r`, which isn't true. So, if there are no | |
392 | // inference variables, we use a verify constraint instead of adding | |
393 | // edges, which winds up enforcing the same condition. | |
394 | let needs_infer = projection_ty.needs_infer(); | |
0bf4aa26 | 395 | if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer { |
abe05a73 XL |
396 | debug!("projection_must_outlive: no declared bounds"); |
397 | ||
532ac7d7 XL |
398 | for k in projection_ty.substs { |
399 | match k.unpack() { | |
e74abb32 | 400 | GenericArgKind::Lifetime(lt) => { |
532ac7d7 XL |
401 | self.delegate.push_sub_region_constraint(origin.clone(), region, lt); |
402 | } | |
e74abb32 | 403 | GenericArgKind::Type(ty) => { |
532ac7d7 XL |
404 | self.type_must_outlive(origin.clone(), ty, region); |
405 | } | |
e74abb32 | 406 | GenericArgKind::Const(_) => { |
532ac7d7 XL |
407 | // Const parameters don't impose constraints. |
408 | } | |
409 | } | |
abe05a73 XL |
410 | } |
411 | ||
412 | return; | |
413 | } | |
414 | ||
0bf4aa26 XL |
415 | // If we found a unique bound `'b` from the trait, and we |
416 | // found nothing else from the environment, then the best | |
417 | // action is to require that `'b: 'r`, so do that. | |
418 | // | |
419 | // This is best no matter what rule we use: | |
abe05a73 | 420 | // |
0bf4aa26 XL |
421 | // - OutlivesProjectionEnv: these would translate to the requirement that `'b:'r` |
422 | // - OutlivesProjectionTraitDef: these would translate to the requirement that `'b:'r` | |
423 | // - OutlivesProjectionComponent: this would require `'b:'r` | |
424 | // in addition to other conditions | |
425 | if !trait_bounds.is_empty() | |
426 | && trait_bounds[1..] | |
427 | .iter() | |
428 | .chain(approx_env_bounds.iter().map(|b| &b.1)) | |
429 | .all(|b| *b == trait_bounds[0]) | |
430 | { | |
431 | let unique_bound = trait_bounds[0]; | |
dfeec247 | 432 | debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound); |
0bf4aa26 | 433 | debug!("projection_must_outlive: unique declared bound appears in trait ref"); |
dfeec247 | 434 | self.delegate.push_sub_region_constraint(origin, region, unique_bound); |
0bf4aa26 | 435 | return; |
abe05a73 XL |
436 | } |
437 | ||
438 | // Fallback to verifying after the fact that there exists a | |
439 | // declared bound, or that all the components appearing in the | |
440 | // projection outlive; in some cases, this may add insufficient | |
441 | // edges into the inference graph, leading to inference failures | |
442 | // even though a satisfactory solution exists. | |
abe05a73 | 443 | let generic = GenericKind::Projection(projection_ty); |
0bf4aa26 | 444 | let verify_bound = self.verify_bound.generic_bound(generic); |
ba9703b0 | 445 | self.delegate.push_verify(origin, generic, region, verify_bound); |
abe05a73 | 446 | } |
abe05a73 | 447 | } |
8faf50e0 | 448 | |
dc9dc135 | 449 | impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> { |
8faf50e0 XL |
450 | fn push_sub_region_constraint( |
451 | &mut self, | |
452 | origin: SubregionOrigin<'tcx>, | |
453 | a: ty::Region<'tcx>, | |
454 | b: ty::Region<'tcx>, | |
455 | ) { | |
456 | self.sub_regions(origin, a, b) | |
457 | } | |
458 | ||
459 | fn push_verify( | |
460 | &mut self, | |
461 | origin: SubregionOrigin<'tcx>, | |
462 | kind: GenericKind<'tcx>, | |
463 | a: ty::Region<'tcx>, | |
464 | bound: VerifyBound<'tcx>, | |
465 | ) { | |
466 | self.verify_generic_bound(origin, kind, a, bound) | |
467 | } | |
468 | } |