1use std::fmt::Debug;
11use std::iter;
12
13use rustc_index::{Idx, IndexVec};
14use rustc_middle::arena::ArenaAllocatable;
15use rustc_middle::mir::ConstraintCategory;
16use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable};
17use rustc_middle::{bug, span_bug};
18use tracing::{debug, instrument};
19
20use crate::infer::canonical::instantiate::{CanonicalExt, instantiate_value};
21use crate::infer::canonical::{
22 Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
23 QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
24};
25use crate::infer::region_constraints::{Constraint, RegionConstraintData};
26use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult};
27use crate::traits::query::NoSolution;
28use crate::traits::{
29 Obligation, ObligationCause, PredicateObligation, PredicateObligations, ScrubbedTraitError,
30 TraitEngine,
31};
32
33impl<'tcx> InferCtxt<'tcx> {
34 #[instrument(skip(self, inference_vars, answer, fulfill_cx), level = "trace")]
54 pub fn make_canonicalized_query_response<T>(
55 &self,
56 inference_vars: CanonicalVarValues<'tcx>,
57 answer: T,
58 fulfill_cx: &mut dyn TraitEngine<'tcx, ScrubbedTraitError<'tcx>>,
59 ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
60 where
61 T: Debug + TypeFoldable<TyCtxt<'tcx>>,
62 Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
63 {
64 let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?;
65 debug!("query_response = {:#?}", query_response);
66 let canonical_result = self.canonicalize_response(query_response);
67 debug!("canonical_result = {:#?}", canonical_result);
68
69 Ok(self.tcx.arena.alloc(canonical_result))
70 }
71
72 pub fn make_query_response_ignoring_pending_obligations<T>(
82 &self,
83 inference_vars: CanonicalVarValues<'tcx>,
84 answer: T,
85 ) -> Canonical<'tcx, QueryResponse<'tcx, T>>
86 where
87 T: Debug + TypeFoldable<TyCtxt<'tcx>>,
88 {
89 self.canonicalize_response(QueryResponse {
90 var_values: inference_vars,
91 region_constraints: QueryRegionConstraints::default(),
92 certainty: Certainty::Proven, opaque_types: vec![],
94 value: answer,
95 })
96 }
97
98 #[instrument(skip(self, fulfill_cx), level = "debug")]
101 fn make_query_response<T>(
102 &self,
103 inference_vars: CanonicalVarValues<'tcx>,
104 answer: T,
105 fulfill_cx: &mut dyn TraitEngine<'tcx, ScrubbedTraitError<'tcx>>,
106 ) -> Result<QueryResponse<'tcx, T>, NoSolution>
107 where
108 T: Debug + TypeFoldable<TyCtxt<'tcx>>,
109 {
110 let tcx = self.tcx;
111
112 let errors = fulfill_cx.select_all_or_error(self);
114
115 if errors.iter().any(|e| e.is_true_error()) {
117 return Err(NoSolution);
118 }
119
120 let region_obligations = self.take_registered_region_obligations();
121 debug!(?region_obligations);
122 let region_constraints = self.with_region_constraints(|region_constraints| {
123 make_query_region_constraints(
124 tcx,
125 region_obligations
126 .iter()
127 .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())),
128 region_constraints,
129 )
130 });
131 debug!(?region_constraints);
132
133 let certainty = if errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
134
135 let opaque_types = self.take_opaque_types_for_query_response();
136
137 Ok(QueryResponse {
138 var_values: inference_vars,
139 region_constraints,
140 certainty,
141 value: answer,
142 opaque_types,
143 })
144 }
145
146 pub fn clone_opaque_types_for_query_response(
149 &self,
150 ) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
151 self.inner
152 .borrow()
153 .opaque_type_storage
154 .opaque_types
155 .iter()
156 .map(|(k, v)| (*k, v.ty))
157 .collect()
158 }
159
160 fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
161 self.take_opaque_types().into_iter().map(|(k, v)| (k, v.ty)).collect()
162 }
163
164 pub fn instantiate_query_response_and_region_obligations<R>(
175 &self,
176 cause: &ObligationCause<'tcx>,
177 param_env: ty::ParamEnv<'tcx>,
178 original_values: &OriginalQueryValues<'tcx>,
179 query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
180 ) -> InferResult<'tcx, R>
181 where
182 R: Debug + TypeFoldable<TyCtxt<'tcx>>,
183 {
184 let InferOk { value: result_args, mut obligations } =
185 self.query_response_instantiation(cause, param_env, original_values, query_response)?;
186
187 obligations.extend(self.query_outlives_constraints_into_obligations(
188 cause,
189 param_env,
190 &query_response.value.region_constraints.outlives,
191 &result_args,
192 ));
193
194 let user_result: R =
195 query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
196
197 Ok(InferOk { value: user_result, obligations })
198 }
199
200 pub fn instantiate_nll_query_response_and_region_obligations<R>(
236 &self,
237 cause: &ObligationCause<'tcx>,
238 param_env: ty::ParamEnv<'tcx>,
239 original_values: &OriginalQueryValues<'tcx>,
240 query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
241 output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
242 ) -> InferResult<'tcx, R>
243 where
244 R: Debug + TypeFoldable<TyCtxt<'tcx>>,
245 {
246 let InferOk { value: result_args, mut obligations } = self
247 .query_response_instantiation_guess(
248 cause,
249 param_env,
250 original_values,
251 query_response,
252 )?;
253
254 let constraint_category = cause.to_constraint_category();
259
260 for (index, original_value) in original_values.var_values.iter().enumerate() {
261 let result_value = query_response.instantiate_projected(self.tcx, &result_args, |v| {
263 v.var_values[BoundVar::new(index)]
264 });
265 match (original_value.unpack(), result_value.unpack()) {
266 (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
267 if re1.is_erased() && re2.is_erased() =>
268 {
269 }
271
272 (GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
273 if v_o != v_r {
275 output_query_region_constraints
276 .outlives
277 .push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
278 output_query_region_constraints
279 .outlives
280 .push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
281 }
282 }
283
284 (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
285 obligations.extend(
286 self.at(&cause, param_env)
287 .eq(DefineOpaqueTypes::Yes, v1, v2)?
288 .into_obligations(),
289 );
290 }
291
292 (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
293 obligations.extend(
294 self.at(&cause, param_env)
295 .eq(DefineOpaqueTypes::Yes, v1, v2)?
296 .into_obligations(),
297 );
298 }
299
300 _ => {
301 bug!("kind mismatch, cannot unify {:?} and {:?}", original_value, result_value);
302 }
303 }
304 }
305
306 output_query_region_constraints.outlives.extend(
308 query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| {
309 let r_c = instantiate_value(self.tcx, &result_args, r_c);
310
311 let ty::OutlivesPredicate(k1, r2) = r_c.0;
313 if k1 != r2.into() { Some(r_c) } else { None }
314 }),
315 );
316
317 let user_result: R =
318 query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
319
320 Ok(InferOk { value: user_result, obligations })
321 }
322
323 fn query_response_instantiation<R>(
334 &self,
335 cause: &ObligationCause<'tcx>,
336 param_env: ty::ParamEnv<'tcx>,
337 original_values: &OriginalQueryValues<'tcx>,
338 query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
339 ) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
340 where
341 R: Debug + TypeFoldable<TyCtxt<'tcx>>,
342 {
343 debug!(
344 "query_response_instantiation(original_values={:#?}, query_response={:#?})",
345 original_values, query_response,
346 );
347
348 let mut value = self.query_response_instantiation_guess(
349 cause,
350 param_env,
351 original_values,
352 query_response,
353 )?;
354
355 value.obligations.extend(
356 self.unify_query_response_instantiation_guess(
357 cause,
358 param_env,
359 original_values,
360 &value.value,
361 query_response,
362 )?
363 .into_obligations(),
364 );
365
366 Ok(value)
367 }
368
369 #[instrument(level = "debug", skip(self, param_env))]
379 fn query_response_instantiation_guess<R>(
380 &self,
381 cause: &ObligationCause<'tcx>,
382 param_env: ty::ParamEnv<'tcx>,
383 original_values: &OriginalQueryValues<'tcx>,
384 query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
385 ) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
386 where
387 R: Debug + TypeFoldable<TyCtxt<'tcx>>,
388 {
389 let mut universe_map = original_values.universe_map.clone();
393 let num_universes_in_query = original_values.universe_map.len();
394 let num_universes_in_response = query_response.max_universe.as_usize() + 1;
395 for _ in num_universes_in_query..num_universes_in_response {
396 universe_map.push(self.create_next_universe());
397 }
398 assert!(!universe_map.is_empty()); assert_eq!(universe_map[ty::UniverseIndex::ROOT.as_usize()], ty::UniverseIndex::ROOT);
400
401 let result_values = &query_response.value.var_values;
406 assert_eq!(original_values.var_values.len(), result_values.len());
407
408 let mut opt_values: IndexVec<BoundVar, Option<GenericArg<'tcx>>> =
416 IndexVec::from_elem_n(None, query_response.variables.len());
417
418 for (original_value, result_value) in iter::zip(&original_values.var_values, result_values)
421 {
422 match result_value.unpack() {
423 GenericArgKind::Type(result_value) => {
424 if let ty::Bound(debruijn, b) = *result_value.kind() {
426 assert_eq!(debruijn, ty::INNERMOST);
430 opt_values[b.var] = Some(*original_value);
431 }
432 }
433 GenericArgKind::Lifetime(result_value) => {
434 if let ty::ReBound(debruijn, br) = *result_value {
436 assert_eq!(debruijn, ty::INNERMOST);
440 opt_values[br.var] = Some(*original_value);
441 }
442 }
443 GenericArgKind::Const(result_value) => {
444 if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() {
445 assert_eq!(debruijn, ty::INNERMOST);
449 opt_values[b] = Some(*original_value);
450 }
451 }
452 }
453 }
454
455 let result_args = CanonicalVarValues {
459 var_values: self.tcx.mk_args_from_iter(
460 query_response.variables.iter().enumerate().map(|(index, info)| {
461 if info.universe() != ty::UniverseIndex::ROOT {
462 self.instantiate_canonical_var(cause.span, info, |u| {
465 universe_map[u.as_usize()]
466 })
467 } else if info.is_existential() {
468 match opt_values[BoundVar::new(index)] {
469 Some(k) => k,
470 None => self.instantiate_canonical_var(cause.span, info, |u| {
471 universe_map[u.as_usize()]
472 }),
473 }
474 } else {
475 opt_values[BoundVar::new(index)].expect(
478 "expected placeholder to be unified with itself during response",
479 )
480 }
481 }),
482 ),
483 };
484
485 let mut obligations = PredicateObligations::new();
486
487 for &(a, b) in &query_response.value.opaque_types {
489 let a = instantiate_value(self.tcx, &result_args, a);
490 let b = instantiate_value(self.tcx, &result_args, b);
491 debug!(?a, ?b, "constrain opaque type");
492 obligations.extend(
497 self.at(cause, param_env)
498 .eq(
499 DefineOpaqueTypes::Yes,
500 Ty::new_opaque(self.tcx, a.def_id.to_def_id(), a.args),
501 b,
502 )?
503 .obligations,
504 );
505 }
506
507 Ok(InferOk { value: result_args, obligations })
508 }
509
510 fn unify_query_response_instantiation_guess<R>(
517 &self,
518 cause: &ObligationCause<'tcx>,
519 param_env: ty::ParamEnv<'tcx>,
520 original_values: &OriginalQueryValues<'tcx>,
521 result_args: &CanonicalVarValues<'tcx>,
522 query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
523 ) -> InferResult<'tcx, ()>
524 where
525 R: Debug + TypeFoldable<TyCtxt<'tcx>>,
526 {
527 let instantiated_query_response = |index: BoundVar| -> GenericArg<'tcx> {
532 query_response.instantiate_projected(self.tcx, result_args, |v| v.var_values[index])
533 };
534
535 self.unify_canonical_vars(cause, param_env, original_values, instantiated_query_response)
538 }
539
540 fn query_outlives_constraints_into_obligations(
543 &self,
544 cause: &ObligationCause<'tcx>,
545 param_env: ty::ParamEnv<'tcx>,
546 uninstantiated_region_constraints: &[QueryOutlivesConstraint<'tcx>],
547 result_args: &CanonicalVarValues<'tcx>,
548 ) -> impl Iterator<Item = PredicateObligation<'tcx>> {
549 uninstantiated_region_constraints.iter().map(move |&constraint| {
550 let predicate = instantiate_value(self.tcx, result_args, constraint);
551 self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env)
552 })
553 }
554
555 pub fn query_outlives_constraint_to_obligation(
556 &self,
557 (predicate, _): QueryOutlivesConstraint<'tcx>,
558 cause: ObligationCause<'tcx>,
559 param_env: ty::ParamEnv<'tcx>,
560 ) -> Obligation<'tcx, ty::Predicate<'tcx>> {
561 let ty::OutlivesPredicate(k1, r2) = predicate;
562
563 let atom = match k1.unpack() {
564 GenericArgKind::Lifetime(r1) => ty::PredicateKind::Clause(
565 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)),
566 ),
567 GenericArgKind::Type(t1) => ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
568 ty::OutlivesPredicate(t1, r2),
569 )),
570 GenericArgKind::Const(..) => {
571 span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
574 }
575 };
576 let predicate = ty::Binder::dummy(atom);
577
578 Obligation::new(self.tcx, cause, param_env, predicate)
579 }
580
581 fn unify_canonical_vars(
584 &self,
585 cause: &ObligationCause<'tcx>,
586 param_env: ty::ParamEnv<'tcx>,
587 variables1: &OriginalQueryValues<'tcx>,
588 variables2: impl Fn(BoundVar) -> GenericArg<'tcx>,
589 ) -> InferResult<'tcx, ()> {
590 let mut obligations = PredicateObligations::new();
591 for (index, value1) in variables1.var_values.iter().enumerate() {
592 let value2 = variables2(BoundVar::new(index));
593
594 match (value1.unpack(), value2.unpack()) {
595 (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
596 obligations.extend(
597 self.at(cause, param_env)
598 .eq(DefineOpaqueTypes::Yes, v1, v2)?
599 .into_obligations(),
600 );
601 }
602 (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
603 if re1.is_erased() && re2.is_erased() =>
604 {
605 }
607 (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => {
608 obligations.extend(
609 self.at(cause, param_env)
610 .eq(DefineOpaqueTypes::Yes, v1, v2)?
611 .into_obligations(),
612 );
613 }
614 (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
615 let ok = self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, v1, v2)?;
616 obligations.extend(ok.into_obligations());
617 }
618 _ => {
619 bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,);
620 }
621 }
622 }
623 Ok(InferOk { value: (), obligations })
624 }
625}
626
627pub fn make_query_region_constraints<'tcx>(
630 tcx: TyCtxt<'tcx>,
631 outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>,
632 region_constraints: &RegionConstraintData<'tcx>,
633) -> QueryRegionConstraints<'tcx> {
634 let RegionConstraintData { constraints, verifys } = region_constraints;
635
636 assert!(verifys.is_empty());
637
638 debug!(?constraints);
639
640 let outlives: Vec<_> = constraints
641 .iter()
642 .map(|(k, origin)| {
643 let constraint = match *k {
644 Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
647 ty::Region::new_var(tcx, v2).into(),
648 ty::Region::new_var(tcx, v1),
649 ),
650 Constraint::VarSubReg(v1, r2) => {
651 ty::OutlivesPredicate(r2.into(), ty::Region::new_var(tcx, v1))
652 }
653 Constraint::RegSubVar(r1, v2) => {
654 ty::OutlivesPredicate(ty::Region::new_var(tcx, v2).into(), r1)
655 }
656 Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
657 };
658 (constraint, origin.to_constraint_category())
659 })
660 .chain(outlives_obligations.map(|(ty, r, constraint_category)| {
661 (ty::OutlivesPredicate(ty.into(), r), constraint_category)
662 }))
663 .collect();
664
665 QueryRegionConstraints { outlives }
666}