]>
Commit | Line | Data |
---|---|---|
8faf50e0 XL |
1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! This module contains the code to instantiate a "query result", and | |
12 | //! in particular to extract out the resulting region obligations and | |
13 | //! encode them therein. | |
14 | //! | |
15 | //! For an overview of what canonicaliation is and how it fits into | |
16 | //! rustc, check out the [chapter in the rustc guide][c]. | |
17 | //! | |
18 | //! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html | |
19 | ||
20 | use infer::canonical::substitute::substitute_value; | |
21 | use infer::canonical::{ | |
22 | Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResult, Certainty, | |
23 | QueryRegionConstraint, QueryResult, SmallCanonicalVarValues, | |
24 | }; | |
25 | use infer::region_constraints::{Constraint, RegionConstraintData}; | |
26 | use infer::InferCtxtBuilder; | |
27 | use infer::{InferCtxt, InferOk, InferResult, RegionObligation}; | |
28 | use rustc_data_structures::indexed_vec::Idx; | |
29 | use rustc_data_structures::indexed_vec::IndexVec; | |
30 | use rustc_data_structures::sync::Lrc; | |
31 | use std::fmt::Debug; | |
32 | use syntax::ast; | |
33 | use syntax_pos::DUMMY_SP; | |
34 | use traits::query::{Fallible, NoSolution}; | |
35 | use traits::{FulfillmentContext, TraitEngine}; | |
36 | use traits::{Obligation, ObligationCause, PredicateObligation}; | |
37 | use ty::fold::TypeFoldable; | |
38 | use ty::subst::{Kind, UnpackedKind}; | |
39 | use ty::{self, CanonicalVar, Lift, TyCtxt}; | |
40 | ||
41 | impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> { | |
42 | /// The "main method" for a canonicalized trait query. Given the | |
43 | /// canonical key `canonical_key`, this method will create a new | |
44 | /// inference context, instantiate the key, and run your operation | |
45 | /// `op`. The operation should yield up a result (of type `R`) as | |
46 | /// well as a set of trait obligations that must be fully | |
47 | /// satisfied. These obligations will be processed and the | |
48 | /// canonical result created. | |
49 | /// | |
50 | /// Returns `NoSolution` in the event of any error. | |
51 | /// | |
52 | /// (It might be mildly nicer to implement this on `TyCtxt`, and | |
53 | /// not `InferCtxtBuilder`, but that is a bit tricky right now. | |
54 | /// In part because we would need a `for<'gcx: 'tcx>` sort of | |
55 | /// bound for the closure and in part because it is convenient to | |
56 | /// have `'tcx` be free on this function so that we can talk about | |
57 | /// `K: TypeFoldable<'tcx>`.) | |
58 | pub fn enter_canonical_trait_query<K, R>( | |
59 | &'tcx mut self, | |
60 | canonical_key: &Canonical<'tcx, K>, | |
61 | operation: impl FnOnce(&InferCtxt<'_, 'gcx, 'tcx>, &mut FulfillmentContext<'tcx>, K) | |
62 | -> Fallible<R>, | |
63 | ) -> Fallible<CanonicalizedQueryResult<'gcx, R>> | |
64 | where | |
65 | K: TypeFoldable<'tcx>, | |
66 | R: Debug + Lift<'gcx> + TypeFoldable<'tcx>, | |
67 | { | |
68 | self.enter(|ref infcx| { | |
69 | let (key, canonical_inference_vars) = | |
70 | infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_key); | |
71 | let fulfill_cx = &mut FulfillmentContext::new(); | |
72 | let value = operation(infcx, fulfill_cx, key)?; | |
73 | infcx.make_canonicalized_query_result(canonical_inference_vars, value, fulfill_cx) | |
74 | }) | |
75 | } | |
76 | } | |
77 | ||
78 | impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { | |
79 | /// This method is meant to be invoked as the final step of a canonical query | |
80 | /// implementation. It is given: | |
81 | /// | |
82 | /// - the instantiated variables `inference_vars` created from the query key | |
83 | /// - the result `answer` of the query | |
84 | /// - a fulfillment context `fulfill_cx` that may contain various obligations which | |
85 | /// have yet to be proven. | |
86 | /// | |
87 | /// Given this, the function will process the obligations pending | |
88 | /// in `fulfill_cx`: | |
89 | /// | |
90 | /// - If all the obligations can be proven successfully, it will | |
91 | /// package up any resulting region obligations (extracted from | |
92 | /// `infcx`) along with the fully resolved value `answer` into a | |
93 | /// query result (which is then itself canonicalized). | |
94 | /// - If some obligations can be neither proven nor disproven, then | |
95 | /// the same thing happens, but the resulting query is marked as ambiguous. | |
96 | /// - Finally, if any of the obligations result in a hard error, | |
97 | /// then `Err(NoSolution)` is returned. | |
98 | pub fn make_canonicalized_query_result<T>( | |
99 | &self, | |
100 | inference_vars: CanonicalVarValues<'tcx>, | |
101 | answer: T, | |
102 | fulfill_cx: &mut FulfillmentContext<'tcx>, | |
103 | ) -> Fallible<CanonicalizedQueryResult<'gcx, T>> | |
104 | where | |
105 | T: Debug + Lift<'gcx> + TypeFoldable<'tcx>, | |
106 | { | |
107 | let query_result = self.make_query_result(inference_vars, answer, fulfill_cx)?; | |
108 | let canonical_result = self.canonicalize_response(&query_result); | |
109 | ||
110 | debug!( | |
111 | "make_canonicalized_query_result: canonical_result = {:#?}", | |
112 | canonical_result | |
113 | ); | |
114 | ||
115 | Ok(Lrc::new(canonical_result)) | |
116 | } | |
117 | ||
118 | /// Helper for `make_canonicalized_query_result` that does | |
119 | /// everything up until the final canonicalization. | |
120 | fn make_query_result<T>( | |
121 | &self, | |
122 | inference_vars: CanonicalVarValues<'tcx>, | |
123 | answer: T, | |
124 | fulfill_cx: &mut FulfillmentContext<'tcx>, | |
125 | ) -> Result<QueryResult<'tcx, T>, NoSolution> | |
126 | where | |
127 | T: Debug + TypeFoldable<'tcx> + Lift<'gcx>, | |
128 | { | |
129 | let tcx = self.tcx; | |
130 | ||
131 | debug!( | |
132 | "make_query_result(\ | |
133 | inference_vars={:?}, \ | |
134 | answer={:?})", | |
135 | inference_vars, answer, | |
136 | ); | |
137 | ||
138 | // Select everything, returning errors. | |
139 | let true_errors = match fulfill_cx.select_where_possible(self) { | |
140 | Ok(()) => vec![], | |
141 | Err(errors) => errors, | |
142 | }; | |
143 | debug!("true_errors = {:#?}", true_errors); | |
144 | ||
145 | if !true_errors.is_empty() { | |
146 | // FIXME -- we don't indicate *why* we failed to solve | |
147 | debug!("make_query_result: true_errors={:#?}", true_errors); | |
148 | return Err(NoSolution); | |
149 | } | |
150 | ||
151 | // Anything left unselected *now* must be an ambiguity. | |
152 | let ambig_errors = match fulfill_cx.select_all_or_error(self) { | |
153 | Ok(()) => vec![], | |
154 | Err(errors) => errors, | |
155 | }; | |
156 | debug!("ambig_errors = {:#?}", ambig_errors); | |
157 | ||
158 | let region_obligations = self.take_registered_region_obligations(); | |
159 | let region_constraints = self.with_region_constraints(|region_constraints| { | |
160 | make_query_outlives(tcx, region_obligations, region_constraints) | |
161 | }); | |
162 | ||
163 | let certainty = if ambig_errors.is_empty() { | |
164 | Certainty::Proven | |
165 | } else { | |
166 | Certainty::Ambiguous | |
167 | }; | |
168 | ||
169 | Ok(QueryResult { | |
170 | var_values: inference_vars, | |
171 | region_constraints, | |
172 | certainty, | |
173 | value: answer, | |
174 | }) | |
175 | } | |
176 | ||
177 | /// Given the (canonicalized) result to a canonical query, | |
178 | /// instantiates the result so it can be used, plugging in the | |
179 | /// values from the canonical query. (Note that the result may | |
180 | /// have been ambiguous; you should check the certainty level of | |
181 | /// the query before applying this function.) | |
182 | /// | |
183 | /// To get a good understanding of what is happening here, check | |
184 | /// out the [chapter in the rustc guide][c]. | |
185 | /// | |
186 | /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#processing-the-canonicalized-query-result | |
187 | pub fn instantiate_query_result_and_region_obligations<R>( | |
188 | &self, | |
189 | cause: &ObligationCause<'tcx>, | |
190 | param_env: ty::ParamEnv<'tcx>, | |
191 | original_values: &SmallCanonicalVarValues<'tcx>, | |
192 | query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, | |
193 | ) -> InferResult<'tcx, R> | |
194 | where | |
195 | R: Debug + TypeFoldable<'tcx>, | |
196 | { | |
197 | let InferOk { | |
198 | value: result_subst, | |
199 | mut obligations, | |
200 | } = self.query_result_substitution(cause, param_env, original_values, query_result)?; | |
201 | ||
202 | obligations.extend(self.query_region_constraints_into_obligations( | |
203 | cause, | |
204 | param_env, | |
205 | &query_result.value.region_constraints, | |
206 | &result_subst, | |
207 | )); | |
208 | ||
209 | let user_result: R = | |
210 | query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); | |
211 | ||
212 | Ok(InferOk { | |
213 | value: user_result, | |
214 | obligations, | |
215 | }) | |
216 | } | |
217 | ||
218 | /// An alternative to | |
219 | /// `instantiate_query_result_and_region_obligations` that is more | |
220 | /// efficient for NLL. NLL is a bit more advanced in the | |
221 | /// "transition to chalk" than the rest of the compiler. During | |
222 | /// the NLL type check, all of the "processing" of types and | |
223 | /// things happens in queries -- the NLL checker itself is only | |
224 | /// interested in the region obligations (`'a: 'b` or `T: 'b`) | |
225 | /// that come out of these queries, which it wants to convert into | |
226 | /// MIR-based constraints and solve. Therefore, it is most | |
227 | /// convenient for the NLL Type Checker to **directly consume** | |
228 | /// the `QueryRegionConstraint` values that arise from doing a | |
229 | /// query. This is contrast to other parts of the compiler, which | |
230 | /// would prefer for those `QueryRegionConstraint` to be converted | |
231 | /// into the older infcx-style constraints (e.g., calls to | |
232 | /// `sub_regions` or `register_region_obligation`). | |
233 | /// | |
234 | /// Therefore, `instantiate_nll_query_result_and_region_obligations` performs the same | |
235 | /// basic operations as `instantiate_query_result_and_region_obligations` but | |
236 | /// it returns its result differently: | |
237 | /// | |
238 | /// - It creates a substitution `S` that maps from the original | |
239 | /// query variables to the values computed in the query | |
240 | /// result. If any errors arise, they are propagated back as an | |
241 | /// `Err` result. | |
242 | /// - In the case of a successful substitution, we will append | |
243 | /// `QueryRegionConstraint` values onto the | |
244 | /// `output_query_region_constraints` vector for the solver to | |
245 | /// use (if an error arises, some values may also be pushed, but | |
246 | /// they should be ignored). | |
247 | /// - It **can happen** (though it rarely does currently) that | |
248 | /// equating types and things will give rise to subobligations | |
249 | /// that must be processed. In this case, those subobligations | |
250 | /// are propagated back in the return value. | |
251 | /// - Finally, the query result (of type `R`) is propagated back, | |
252 | /// after applying the substitution `S`. | |
253 | pub fn instantiate_nll_query_result_and_region_obligations<R>( | |
254 | &self, | |
255 | cause: &ObligationCause<'tcx>, | |
256 | param_env: ty::ParamEnv<'tcx>, | |
257 | original_values: &SmallCanonicalVarValues<'tcx>, | |
258 | query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, | |
259 | output_query_region_constraints: &mut Vec<QueryRegionConstraint<'tcx>>, | |
260 | ) -> InferResult<'tcx, R> | |
261 | where | |
262 | R: Debug + TypeFoldable<'tcx>, | |
263 | { | |
264 | // In an NLL query, there should be no type variables in the | |
265 | // query, only region variables. | |
266 | debug_assert!(query_result.variables.iter().all(|v| match v.kind { | |
267 | CanonicalVarKind::Ty(_) => false, | |
268 | CanonicalVarKind::Region => true, | |
269 | })); | |
270 | ||
271 | let result_subst = | |
272 | self.query_result_substitution_guess(cause, original_values, query_result); | |
273 | ||
274 | // Compute `QueryRegionConstraint` values that unify each of | |
275 | // the original values `v_o` that was canonicalized into a | |
276 | // variable... | |
277 | let mut obligations = vec![]; | |
278 | ||
279 | for (index, original_value) in original_values.iter().enumerate() { | |
280 | // ...with the value `v_r` of that variable from the query. | |
281 | let result_value = query_result.substitute_projected(self.tcx, &result_subst, |v| { | |
282 | &v.var_values[CanonicalVar::new(index)] | |
283 | }); | |
284 | match (original_value.unpack(), result_value.unpack()) { | |
285 | (UnpackedKind::Lifetime(ty::ReErased), UnpackedKind::Lifetime(ty::ReErased)) => { | |
286 | // no action needed | |
287 | } | |
288 | ||
289 | (UnpackedKind::Lifetime(v_o), UnpackedKind::Lifetime(v_r)) => { | |
290 | // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`. | |
291 | if v_o != v_r { | |
292 | output_query_region_constraints | |
293 | .push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r))); | |
294 | output_query_region_constraints | |
295 | .push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o))); | |
296 | } | |
297 | } | |
298 | ||
299 | (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => { | |
300 | let ok = self.at(cause, param_env).eq(v1, v2)?; | |
301 | obligations.extend(ok.into_obligations()); | |
302 | } | |
303 | ||
304 | _ => { | |
305 | bug!( | |
306 | "kind mismatch, cannot unify {:?} and {:?}", | |
307 | original_value, | |
308 | result_value | |
309 | ); | |
310 | } | |
311 | } | |
312 | } | |
313 | ||
314 | // ...also include the other query region constraints from the query. | |
315 | output_query_region_constraints.reserve(query_result.value.region_constraints.len()); | |
316 | for r_c in query_result.value.region_constraints.iter() { | |
317 | let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below | |
318 | let k1 = substitute_value(self.tcx, &result_subst, &k1); | |
319 | let r2 = substitute_value(self.tcx, &result_subst, &r2); | |
320 | if k1 != r2.into() { | |
321 | output_query_region_constraints | |
322 | .push(ty::Binder::bind(ty::OutlivesPredicate(k1, r2))); | |
323 | } | |
324 | } | |
325 | ||
326 | let user_result: R = | |
327 | query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); | |
328 | ||
329 | Ok(InferOk { | |
330 | value: user_result, | |
331 | obligations, | |
332 | }) | |
333 | } | |
334 | ||
335 | /// Given the original values and the (canonicalized) result from | |
336 | /// computing a query, returns a substitution that can be applied | |
337 | /// to the query result to convert the result back into the | |
338 | /// original namespace. | |
339 | /// | |
340 | /// The substitution also comes accompanied with subobligations | |
341 | /// that arose from unification; these might occur if (for | |
342 | /// example) we are doing lazy normalization and the value | |
343 | /// assigned to a type variable is unified with an unnormalized | |
344 | /// projection. | |
345 | fn query_result_substitution<R>( | |
346 | &self, | |
347 | cause: &ObligationCause<'tcx>, | |
348 | param_env: ty::ParamEnv<'tcx>, | |
349 | original_values: &SmallCanonicalVarValues<'tcx>, | |
350 | query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, | |
351 | ) -> InferResult<'tcx, CanonicalVarValues<'tcx>> | |
352 | where | |
353 | R: Debug + TypeFoldable<'tcx>, | |
354 | { | |
355 | debug!( | |
356 | "query_result_substitution(original_values={:#?}, query_result={:#?})", | |
357 | original_values, query_result, | |
358 | ); | |
359 | ||
360 | let result_subst = | |
361 | self.query_result_substitution_guess(cause, original_values, query_result); | |
362 | ||
363 | let obligations = self.unify_query_result_substitution_guess( | |
364 | cause, | |
365 | param_env, | |
366 | original_values, | |
367 | &result_subst, | |
368 | query_result, | |
369 | )? | |
370 | .into_obligations(); | |
371 | ||
372 | Ok(InferOk { | |
373 | value: result_subst, | |
374 | obligations, | |
375 | }) | |
376 | } | |
377 | ||
378 | /// Given the original values and the (canonicalized) result from | |
379 | /// computing a query, returns a **guess** at a substitution that | |
380 | /// can be applied to the query result to convert the result back | |
381 | /// into the original namespace. This is called a **guess** | |
382 | /// because it uses a quick heuristic to find the values for each | |
383 | /// canonical variable; if that quick heuristic fails, then we | |
384 | /// will instantiate fresh inference variables for each canonical | |
385 | /// variable instead. Therefore, the result of this method must be | |
386 | /// properly unified | |
387 | fn query_result_substitution_guess<R>( | |
388 | &self, | |
389 | cause: &ObligationCause<'tcx>, | |
390 | original_values: &SmallCanonicalVarValues<'tcx>, | |
391 | query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, | |
392 | ) -> CanonicalVarValues<'tcx> | |
393 | where | |
394 | R: Debug + TypeFoldable<'tcx>, | |
395 | { | |
396 | debug!( | |
397 | "query_result_substitution_guess(original_values={:#?}, query_result={:#?})", | |
398 | original_values, query_result, | |
399 | ); | |
400 | ||
401 | // Every canonical query result includes values for each of | |
402 | // the inputs to the query. Therefore, we begin by unifying | |
403 | // these values with the original inputs that were | |
404 | // canonicalized. | |
405 | let result_values = &query_result.value.var_values; | |
406 | assert_eq!(original_values.len(), result_values.len()); | |
407 | ||
408 | // Quickly try to find initial values for the canonical | |
409 | // variables in the result in terms of the query. We do this | |
410 | // by iterating down the values that the query gave to each of | |
411 | // the canonical inputs. If we find that one of those values | |
412 | // is directly equal to one of the canonical variables in the | |
413 | // result, then we can type the corresponding value from the | |
414 | // input. See the example above. | |
415 | let mut opt_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>> = | |
416 | IndexVec::from_elem_n(None, query_result.variables.len()); | |
417 | ||
418 | // In terms of our example above, we are iterating over pairs like: | |
419 | // [(?A, Vec<?0>), ('static, '?1), (?B, ?0)] | |
420 | for (original_value, result_value) in original_values.iter().zip(result_values) { | |
421 | match result_value.unpack() { | |
422 | UnpackedKind::Type(result_value) => { | |
423 | // e.g., here `result_value` might be `?0` in the example above... | |
424 | if let ty::TyInfer(ty::InferTy::CanonicalTy(index)) = result_value.sty { | |
425 | // in which case we would set `canonical_vars[0]` to `Some(?U)`. | |
426 | opt_values[index] = Some(*original_value); | |
427 | } | |
428 | } | |
429 | UnpackedKind::Lifetime(result_value) => { | |
430 | // e.g., here `result_value` might be `'?1` in the example above... | |
431 | if let &ty::RegionKind::ReCanonical(index) = result_value { | |
432 | // in which case we would set `canonical_vars[0]` to `Some('static)`. | |
433 | opt_values[index] = Some(*original_value); | |
434 | } | |
435 | } | |
436 | } | |
437 | } | |
438 | ||
439 | // Create a result substitution: if we found a value for a | |
440 | // given variable in the loop above, use that. Otherwise, use | |
441 | // a fresh inference variable. | |
442 | let result_subst = CanonicalVarValues { | |
443 | var_values: query_result | |
444 | .variables | |
445 | .iter() | |
446 | .enumerate() | |
447 | .map(|(index, info)| match opt_values[CanonicalVar::new(index)] { | |
448 | Some(k) => k, | |
449 | None => self.fresh_inference_var_for_canonical_var(cause.span, *info), | |
450 | }) | |
451 | .collect(), | |
452 | }; | |
453 | ||
454 | result_subst | |
455 | } | |
456 | ||
457 | /// Given a "guess" at the values for the canonical variables in | |
458 | /// the input, try to unify with the *actual* values found in the | |
459 | /// query result. Often, but not always, this is a no-op, because | |
460 | /// we already found the mapping in the "guessing" step. | |
461 | /// | |
462 | /// See also: `query_result_substitution_guess` | |
463 | fn unify_query_result_substitution_guess<R>( | |
464 | &self, | |
465 | cause: &ObligationCause<'tcx>, | |
466 | param_env: ty::ParamEnv<'tcx>, | |
467 | original_values: &SmallCanonicalVarValues<'tcx>, | |
468 | result_subst: &CanonicalVarValues<'tcx>, | |
469 | query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, | |
470 | ) -> InferResult<'tcx, ()> | |
471 | where | |
472 | R: Debug + TypeFoldable<'tcx>, | |
473 | { | |
474 | // A closure that yields the result value for the given | |
475 | // canonical variable; this is taken from | |
476 | // `query_result.var_values` after applying the substitution | |
477 | // `result_subst`. | |
478 | let substituted_query_result = |index: CanonicalVar| -> Kind<'tcx> { | |
479 | query_result.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]) | |
480 | }; | |
481 | ||
482 | // Unify the original value for each variable with the value | |
483 | // taken from `query_result` (after applying `result_subst`). | |
484 | Ok(self.unify_canonical_vars(cause, param_env, original_values, substituted_query_result)?) | |
485 | } | |
486 | ||
487 | /// Converts the region constraints resulting from a query into an | |
488 | /// iterator of obligations. | |
489 | fn query_region_constraints_into_obligations<'a>( | |
490 | &'a self, | |
491 | cause: &'a ObligationCause<'tcx>, | |
492 | param_env: ty::ParamEnv<'tcx>, | |
493 | unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>], | |
494 | result_subst: &'a CanonicalVarValues<'tcx>, | |
495 | ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a { | |
496 | Box::new( | |
497 | unsubstituted_region_constraints | |
498 | .iter() | |
499 | .map(move |constraint| { | |
500 | let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below | |
501 | let k1 = substitute_value(self.tcx, result_subst, k1); | |
502 | let r2 = substitute_value(self.tcx, result_subst, r2); | |
503 | match k1.unpack() { | |
504 | UnpackedKind::Lifetime(r1) => Obligation::new( | |
505 | cause.clone(), | |
506 | param_env, | |
507 | ty::Predicate::RegionOutlives(ty::Binder::dummy( | |
508 | ty::OutlivesPredicate(r1, r2), | |
509 | )), | |
510 | ), | |
511 | ||
512 | UnpackedKind::Type(t1) => Obligation::new( | |
513 | cause.clone(), | |
514 | param_env, | |
515 | ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate( | |
516 | t1, r2, | |
517 | ))), | |
518 | ), | |
519 | } | |
520 | }), | |
521 | ) as Box<dyn Iterator<Item = _>> | |
522 | } | |
523 | ||
524 | /// Given two sets of values for the same set of canonical variables, unify them. | |
525 | /// The second set is produced lazilly by supplying indices from the first set. | |
526 | fn unify_canonical_vars( | |
527 | &self, | |
528 | cause: &ObligationCause<'tcx>, | |
529 | param_env: ty::ParamEnv<'tcx>, | |
530 | variables1: &SmallCanonicalVarValues<'tcx>, | |
531 | variables2: impl Fn(CanonicalVar) -> Kind<'tcx>, | |
532 | ) -> InferResult<'tcx, ()> { | |
533 | self.commit_if_ok(|_| { | |
534 | let mut obligations = vec![]; | |
535 | for (index, value1) in variables1.iter().enumerate() { | |
536 | let value2 = variables2(CanonicalVar::new(index)); | |
537 | ||
538 | match (value1.unpack(), value2.unpack()) { | |
539 | (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => { | |
540 | obligations | |
541 | .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); | |
542 | } | |
543 | ( | |
544 | UnpackedKind::Lifetime(ty::ReErased), | |
545 | UnpackedKind::Lifetime(ty::ReErased), | |
546 | ) => { | |
547 | // no action needed | |
548 | } | |
549 | (UnpackedKind::Lifetime(v1), UnpackedKind::Lifetime(v2)) => { | |
550 | obligations | |
551 | .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); | |
552 | } | |
553 | _ => { | |
554 | bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); | |
555 | } | |
556 | } | |
557 | } | |
558 | Ok(InferOk { | |
559 | value: (), | |
560 | obligations, | |
561 | }) | |
562 | }) | |
563 | } | |
564 | } | |
565 | ||
566 | /// Given the region obligations and constraints scraped from the infcx, | |
567 | /// creates query region constraints. | |
568 | pub fn make_query_outlives<'tcx>( | |
569 | tcx: TyCtxt<'_, '_, 'tcx>, | |
570 | region_obligations: Vec<(ast::NodeId, RegionObligation<'tcx>)>, | |
571 | region_constraints: &RegionConstraintData<'tcx>, | |
572 | ) -> Vec<QueryRegionConstraint<'tcx>> { | |
573 | let RegionConstraintData { | |
574 | constraints, | |
575 | verifys, | |
576 | givens, | |
577 | } = region_constraints; | |
578 | ||
579 | assert!(verifys.is_empty()); | |
580 | assert!(givens.is_empty()); | |
581 | ||
582 | let mut outlives: Vec<_> = constraints | |
583 | .into_iter() | |
584 | .map(|(k, _)| match *k { | |
585 | // Swap regions because we are going from sub (<=) to outlives | |
586 | // (>=). | |
587 | Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( | |
588 | tcx.mk_region(ty::ReVar(v2)).into(), | |
589 | tcx.mk_region(ty::ReVar(v1)), | |
590 | ), | |
591 | Constraint::VarSubReg(v1, r2) => { | |
592 | ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1))) | |
593 | } | |
594 | Constraint::RegSubVar(r1, v2) => { | |
595 | ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1) | |
596 | } | |
597 | Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), | |
598 | }) | |
599 | .map(ty::Binder::dummy) // no bound regions in the code above | |
600 | .collect(); | |
601 | ||
602 | outlives.extend( | |
603 | region_obligations | |
604 | .into_iter() | |
605 | .map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region)) | |
606 | .map(ty::Binder::dummy), // no bound regions in the code above | |
607 | ); | |
608 | ||
609 | outlives | |
610 | } |