1use std::{cell::RefCell, fmt, iter};
2
3use flux_common::{bug, dbg, tracked_span_assert_eq, tracked_span_bug, tracked_span_dbg_assert_eq};
4use flux_config::{self as config, InferOpts, OverflowMode, RawDerefMode};
5use flux_macros::{TypeFoldable, TypeVisitable};
6use flux_middle::{
7 FixpointQueryKind, PanicSpec,
8 def_id::MaybeExternId,
9 global_env::GlobalEnv,
10 metrics::{self, Metric},
11 queries::{QueryErr, QueryResult},
12 query_bug,
13 rty::{
14 self, AliasKind, AliasTy, BaseTy, Binder, BoundReftKind, BoundVariableKinds,
15 CoroutineObligPredicate, Ctor, ESpan, EVid, EarlyBinder, Expr, ExprKind, FieldProj,
16 GenericArg, HoleKind, InferMode, Lambda, List, Loc, Mutability, Name, NameProvenance, Path,
17 PolyVariant, PtrKind, RefineArgs, RefineArgsExt, Region, Sort, Ty, TyCtor, TyKind, Var,
18 canonicalize::{Hoister, HoisterDelegate},
19 fold::TypeFoldable,
20 },
21};
22use itertools::{Itertools, izip};
23use rustc_hir::def_id::{DefId, LocalDefId};
24use rustc_macros::extension;
25use rustc_middle::{
26 mir::BasicBlock,
27 ty::{TyCtxt, Variance},
28};
29use rustc_span::{Span, Symbol};
30use rustc_type_ir::Variance::Invariant;
31
32use crate::{
33 evars::{EVarState, EVarStore},
34 fixpoint_encoding::{
35 Answer, Backend, FixQueryCache, FixpointCtxt, KVarGen, lean_task_key, record_lean_task,
36 },
37 fn_subtyping::{SubFn, check_fn_subtyping},
38 lean_encoding::{hyperlink_proof, log_proof},
39 projections::NormalizeExt as _,
40 refine_tree::{Cursor, Marker, RefineTree, Scope},
41};
42
43pub type InferResult<T = ()> = std::result::Result<T, InferErr>;
44
45#[derive(PartialEq, Eq, Clone, Copy, Hash)]
46pub struct Tag {
47 pub reason: ConstrReason,
48 pub src_span: Span,
49 pub dst_span: Option<ESpan>,
50}
51
52impl Tag {
53 pub fn new(reason: ConstrReason, span: Span) -> Self {
54 Self { reason, src_span: span, dst_span: None }
55 }
56
57 pub fn with_dst(self, dst_span: Option<ESpan>) -> Self {
58 Self { dst_span, ..self }
59 }
60}
61
62#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
63pub enum SubtypeReason {
64 Input,
65 Output,
66 Requires,
67 Ensures,
68}
69
70#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
71pub enum ConstrReason {
72 Call,
73 Assign,
74 Ret,
75 Fold,
76 FoldLocal,
77 Predicate,
78 Assert(&'static str),
79 Div,
80 Rem,
81 Goto(BasicBlock),
82 Overflow,
83 Underflow,
84 Subtype(SubtypeReason),
85 NoPanic(DefId, PanicSpec),
86 Other,
87}
88
89pub struct InferCtxtRoot<'genv, 'tcx> {
90 pub genv: GlobalEnv<'genv, 'tcx>,
91 inner: RefCell<InferCtxtInner>,
92 refine_tree: RefineTree,
93 opts: InferOpts,
94}
95
96pub struct InferCtxtRootBuilder<'a, 'genv, 'tcx> {
97 genv: GlobalEnv<'genv, 'tcx>,
98 opts: InferOpts,
99 params: Vec<(Var, Sort)>,
100 assumptions: Vec<Expr>,
102 infcx: &'a rustc_infer::infer::InferCtxt<'tcx>,
103 dummy_kvars: bool,
104}
105
106#[extension(pub trait GlobalEnvExt<'genv, 'tcx>)]
107impl<'genv, 'tcx> GlobalEnv<'genv, 'tcx> {
108 fn infcx_root<'a>(
109 self,
110 infcx: &'a rustc_infer::infer::InferCtxt<'tcx>,
111 opts: InferOpts,
112 ) -> InferCtxtRootBuilder<'a, 'genv, 'tcx> {
113 InferCtxtRootBuilder {
114 genv: self,
115 infcx,
116 params: vec![],
117 assumptions: vec![],
118 opts,
119 dummy_kvars: false,
120 }
121 }
122}
123
124impl<'genv, 'tcx> InferCtxtRootBuilder<'_, 'genv, 'tcx> {
125 pub fn with_dummy_kvars(mut self) -> Self {
126 self.dummy_kvars = true;
127 self
128 }
129
130 pub fn with_const_generics(mut self, def_id: DefId) -> QueryResult<Self> {
133 let tcx = self.genv.tcx();
134 for (param_const, sort, param_def_id) in
135 self.genv.generics_of(def_id)?.const_params(self.genv)?
136 {
137 let param_ty = tcx
139 .type_of(param_def_id)
140 .instantiate_identity()
141 .skip_normalization();
142 let bty = match param_ty.kind() {
143 rustc_middle::ty::Uint(uint_ty) => Some(BaseTy::Uint(*uint_ty)),
144 rustc_middle::ty::Int(int_ty) => Some(BaseTy::Int(*int_ty)),
145 rustc_middle::ty::Char => Some(BaseTy::Char),
146 _ => None,
147 };
148 if let Some(bty) = bty {
149 let idx = Expr::const_generic(param_const);
150 self.assumptions.extend(
151 bty.invariants(self.genv, self.opts.check_overflow)
152 .map(|inv| inv.apply(&idx)),
153 );
154 }
155 self.params.push((Var::ConstGeneric(param_const), sort));
156 }
157 Ok(self)
158 }
159
160 pub fn with_refinement_generics(
161 mut self,
162 def_id: DefId,
163 args: &[GenericArg],
164 ) -> QueryResult<Self> {
165 for (index, param) in self
166 .genv
167 .refinement_generics_of(def_id)?
168 .iter_own_params()
169 .enumerate()
170 {
171 let param = param.instantiate(self.genv.tcx(), args, &[]);
172 let sort = param
173 .sort
174 .deeply_normalize_sorts(def_id, self.genv, self.infcx)?;
175
176 let var =
177 Var::EarlyParam(rty::EarlyReftParam { index: index as u32, name: param.name });
178 self.params.push((var, sort));
179 }
180 Ok(self)
181 }
182
183 pub fn identity_for_item(mut self, def_id: DefId) -> QueryResult<Self> {
184 self = self.with_const_generics(def_id)?;
185 let offset = self.params.len();
186 self.genv.refinement_generics_of(def_id)?.fill_item(
187 self.genv,
188 &mut self.params,
189 &mut |param, index| {
190 let index = (index - offset) as u32;
191 let param = param.instantiate_identity();
192 let sort = param
193 .sort
194 .deeply_normalize_sorts(def_id, self.genv, self.infcx)?;
195
196 let var = Var::EarlyParam(rty::EarlyReftParam { index, name: param.name });
197 Ok((var, sort))
198 },
199 )?;
200 Ok(self)
201 }
202
203 pub fn build(self) -> QueryResult<InferCtxtRoot<'genv, 'tcx>> {
204 Ok(InferCtxtRoot {
205 genv: self.genv,
206 inner: RefCell::new(InferCtxtInner::new(self.dummy_kvars)),
207 refine_tree: RefineTree::new(self.params, self.assumptions),
208 opts: self.opts,
209 })
210 }
211}
212
213impl<'genv, 'tcx> InferCtxtRoot<'genv, 'tcx> {
214 pub fn infcx<'a>(
215 &'a mut self,
216 def_id: DefId,
217 region_infcx: &'a rustc_infer::infer::InferCtxt<'tcx>,
218 ) -> InferCtxt<'a, 'genv, 'tcx> {
219 InferCtxt {
220 genv: self.genv,
221 region_infcx,
222 def_id,
223 cursor: self.refine_tree.cursor_at_root(),
224 inner: &self.inner,
225 check_overflow: self.opts.check_overflow,
226 allow_raw_deref: self.opts.allow_raw_deref,
227 }
228 }
229
230 pub fn fresh_kvar_in_scope(&self, binders: &[BoundVariableKinds], scope: &Scope) -> Expr {
231 let inner = &mut *self.inner.borrow_mut();
232 inner.kvars.fresh(binders, scope.iter())
233 }
234
235 pub fn execute_lean_query(
236 self,
237 cache: &mut FixQueryCache,
238 def_id: MaybeExternId,
239 ) -> QueryResult {
240 let inner = self.inner.into_inner();
241 let kvars = inner.kvars;
242 let evars = inner.evars;
243 let mut refine_tree = self.refine_tree;
244 refine_tree.replace_evars(&evars).unwrap();
245 refine_tree.simplify(self.genv);
246
247 let solver = match self.opts.solver {
248 flux_config::SmtSolver::Z3 => liquid_fixpoint::SmtSolver::Z3,
249 flux_config::SmtSolver::CVC5 => liquid_fixpoint::SmtSolver::CVC5,
250 };
251 let mut fcx = FixpointCtxt::new(self.genv, def_id, kvars, Backend::Lean, self.opts.uif_ops);
252 let cstr = refine_tree.to_fixpoint(&mut fcx)?;
253 let (task, _) = fcx.create_task(def_id, cstr, self.opts.scrape_quals, solver)?;
254
255 log_proof(self.genv, def_id)?;
256 let key = lean_task_key(self.genv.tcx(), def_id.resolved_id());
258 let hash = task.hash_with_default();
259 let cached = config::is_cache_enabled() && cache.lookup(&key, hash).is_some();
260 if !cached {
261 fcx.generate_lean_files(def_id, task)?;
262 if config::is_cache_enabled() {
263 record_lean_task(cache, key, hash);
264 }
265 }
266 hyperlink_proof(self.genv, def_id);
268 Ok(())
269 }
270
271 pub fn execute_fixpoint_query(
272 self,
273 cache: &mut FixQueryCache,
274 def_id: MaybeExternId,
275 kind: FixpointQueryKind,
276 ) -> QueryResult<Answer<Tag>> {
277 let inner = self.inner.into_inner();
278 let kvars = inner.kvars;
279 let evars = inner.evars;
280
281 let ext = kind.ext();
282
283 let mut refine_tree = self.refine_tree;
284
285 refine_tree.replace_evars(&evars).unwrap();
286
287 if config::dump_constraint() {
288 dbg::dump_item_info(self.genv.tcx(), def_id.resolved_id(), ext, &refine_tree).unwrap();
289 }
290 refine_tree.simplify(self.genv);
291 if config::dump_constraint() {
292 let simp_ext = format!("simp.{ext}");
293 dbg::dump_item_info(self.genv.tcx(), def_id.resolved_id(), simp_ext, &refine_tree)
294 .unwrap();
295 }
296
297 let backend = match self.opts.solver {
298 flux_config::SmtSolver::Z3 => liquid_fixpoint::SmtSolver::Z3,
299 flux_config::SmtSolver::CVC5 => liquid_fixpoint::SmtSolver::CVC5,
300 };
301
302 let mut fcx =
303 FixpointCtxt::new(self.genv, def_id, kvars, Backend::Fixpoint, self.opts.uif_ops);
304 let cstr = refine_tree.to_fixpoint(&mut fcx)?;
305
306 let count = cstr.concrete_head_count();
308 metrics::incr_metric(Metric::CsTotal, count as u32);
309 if count == 0 {
310 metrics::incr_metric_if(kind.is_body(), Metric::FnTrivial);
311 return Ok(Answer::trivial());
312 }
313
314 let (task, suggestion_ctx) =
315 fcx.create_task(def_id, cstr, self.opts.scrape_quals, backend)?;
316 let result = fcx.run_task(cache, def_id, kind, &task)?;
317 fcx.result_to_answer(result, suggestion_ctx)
318 }
319
320 pub fn split(self) -> (RefineTree, KVarGen) {
321 (self.refine_tree, self.inner.into_inner().kvars)
322 }
323}
324
325pub struct InferCtxt<'infcx, 'genv, 'tcx> {
326 pub genv: GlobalEnv<'genv, 'tcx>,
327 pub region_infcx: &'infcx rustc_infer::infer::InferCtxt<'tcx>,
328 pub def_id: DefId,
329 pub check_overflow: OverflowMode,
330 pub allow_raw_deref: flux_config::RawDerefMode,
331 cursor: Cursor<'infcx>,
332 inner: &'infcx RefCell<InferCtxtInner>,
333}
334
335struct InferCtxtInner {
336 kvars: KVarGen,
337 evars: EVarStore,
338}
339
340impl InferCtxtInner {
341 fn new(dummy_kvars: bool) -> Self {
342 Self { kvars: KVarGen::new(dummy_kvars), evars: Default::default() }
343 }
344}
345
346impl<'infcx, 'genv, 'tcx> InferCtxt<'infcx, 'genv, 'tcx> {
347 pub fn at(&mut self, span: Span) -> InferCtxtAt<'_, 'infcx, 'genv, 'tcx> {
348 InferCtxtAt { infcx: self, span }
349 }
350
351 pub fn instantiate_refine_args(
352 &mut self,
353 callee_def_id: DefId,
354 args: &[rty::GenericArg],
355 ) -> InferResult<List<Expr>> {
356 Ok(RefineArgs::for_item(self.genv, callee_def_id, |param, _| {
357 let param = param.instantiate(self.genv.tcx(), args, &[]);
358 Ok(self.fresh_infer_var(¶m.sort, param.mode))
359 })?)
360 }
361
362 pub fn instantiate_generic_args(&mut self, args: &[GenericArg]) -> Vec<GenericArg> {
363 args.iter()
364 .map(|a| a.replace_holes(|binders, kind| self.fresh_infer_var_for_hole(binders, kind)))
365 .collect_vec()
366 }
367
368 pub fn fresh_infer_var(&self, sort: &Sort, mode: InferMode) -> Expr {
369 match mode {
370 InferMode::KVar => {
371 let fsort = sort.expect_func().expect_mono();
372 let vars = fsort.inputs().iter().cloned().map_into().collect();
373 let kvar = self.fresh_kvar(&[vars]);
374 Expr::abs(Lambda::bind_with_fsort(kvar, fsort))
375 }
376 InferMode::EVar => self.fresh_evar(),
377 }
378 }
379
380 pub fn fresh_infer_var_for_hole(
381 &mut self,
382 binders: &[BoundVariableKinds],
383 kind: HoleKind,
384 ) -> Expr {
385 match kind {
386 HoleKind::Pred => self.fresh_kvar(binders),
387 HoleKind::Expr(_) => {
388 self.fresh_evar()
392 }
393 }
394 }
395
396 pub fn fresh_kvar_in_scope(&self, binders: &[BoundVariableKinds], scope: &Scope) -> Expr {
398 let inner = &mut *self.inner.borrow_mut();
399 inner.kvars.fresh(binders, scope.iter())
400 }
401
402 pub fn fresh_kvar(&self, binders: &[BoundVariableKinds]) -> Expr {
404 let inner = &mut *self.inner.borrow_mut();
405 inner.kvars.fresh(binders, self.cursor.vars())
406 }
407
408 fn fresh_evar(&self) -> Expr {
409 let evars = &mut self.inner.borrow_mut().evars;
410 Expr::evar(evars.fresh(self.cursor.marker()))
411 }
412
413 pub fn unify_exprs(&self, a: &Expr, b: &Expr) {
414 if a.has_evars() {
415 return;
416 }
417 let evars = &mut self.inner.borrow_mut().evars;
418 if let ExprKind::Var(Var::EVar(evid)) = b.kind()
419 && let EVarState::Unsolved(marker) = evars.get(*evid)
420 && !marker.has_free_vars(a)
421 {
422 evars.solve(*evid, a.clone());
423 }
424 }
425
426 fn enter_exists<T, U>(
427 &mut self,
428 t: &Binder<T>,
429 f: impl FnOnce(&mut InferCtxt<'_, 'genv, 'tcx>, T) -> InferResult<U>,
430 ) -> InferResult<U>
431 where
432 T: TypeFoldable,
433 {
434 self.ensure_resolved_evars(|infcx| {
435 let t = t.replace_bound_refts_with(|sort, mode, _| infcx.fresh_infer_var(sort, mode));
436 f(infcx, t)
437 })
438 }
439
440 pub fn push_evar_scope(&mut self) {
445 self.inner.borrow_mut().evars.push_scope();
446 }
447
448 pub fn pop_evar_scope(&mut self) -> InferResult {
451 self.inner
452 .borrow_mut()
453 .evars
454 .pop_scope()
455 .map_err(InferErr::UnsolvedEvar)
456 }
457
458 pub fn ensure_resolved_evars<R>(
460 &mut self,
461 f: impl FnOnce(&mut Self) -> InferResult<R>,
462 ) -> InferResult<R> {
463 self.push_evar_scope();
464 let r = f(self)?;
465 self.pop_evar_scope()?;
466 Ok(r)
467 }
468
469 pub fn fully_resolve_evars<T: TypeFoldable>(&self, t: &T) -> T {
470 self.inner.borrow().evars.replace_evars(t).unwrap()
471 }
472
473 pub fn tcx(&self) -> TyCtxt<'tcx> {
474 self.genv.tcx()
475 }
476
477 pub fn cursor(&self) -> &Cursor<'infcx> {
478 &self.cursor
479 }
480
481 pub fn allow_raw_deref(&self) -> bool {
482 matches!(self.allow_raw_deref, RawDerefMode::Ok)
483 }
484}
485
486impl<'infcx, 'genv, 'tcx> InferCtxt<'infcx, 'genv, 'tcx> {
488 pub fn change_item<'a>(
489 &'a mut self,
490 def_id: LocalDefId,
491 region_infcx: &'a rustc_infer::infer::InferCtxt<'tcx>,
492 ) -> InferCtxt<'a, 'genv, 'tcx> {
493 InferCtxt {
494 def_id: def_id.to_def_id(),
495 cursor: self.cursor.branch(),
496 region_infcx,
497 ..*self
498 }
499 }
500
501 pub fn move_to(&mut self, marker: &Marker, clear_children: bool) -> InferCtxt<'_, 'genv, 'tcx> {
502 InferCtxt {
503 cursor: self
504 .cursor
505 .move_to(marker, clear_children)
506 .unwrap_or_else(|| tracked_span_bug!()),
507 ..*self
508 }
509 }
510
511 pub fn branch(&mut self) -> InferCtxt<'_, 'genv, 'tcx> {
512 InferCtxt { cursor: self.cursor.branch(), ..*self }
513 }
514
515 fn define_var(&mut self, sort: &Sort, provenance: NameProvenance) -> Name {
516 self.cursor.define_var(sort, provenance)
517 }
518
519 pub fn define_bound_reft_var(&mut self, sort: &Sort, kind: BoundReftKind) -> Name {
520 self.define_var(sort, NameProvenance::UnfoldBoundReft(kind))
521 }
522
523 pub fn define_unknown_var(&mut self, sort: &Sort) -> Name {
524 self.cursor.define_var(sort, NameProvenance::Unknown)
525 }
526
527 pub fn check_pred(&mut self, pred: impl Into<Expr>, tag: Tag) {
528 self.cursor.check_pred(pred, tag);
529 }
530
531 pub fn assume_pred(&mut self, pred: impl Into<Expr>) {
532 self.cursor.assume_pred(pred);
533 }
534
535 pub fn unpack(&mut self, ty: &Ty) -> Ty {
536 self.hoister(false).hoist(ty)
537 }
538
539 pub fn unpack_at_name(&mut self, name: Option<Symbol>, ty: &Ty) -> Ty {
540 let mut hoister = self.hoister(false);
541 hoister.delegate.name = name;
542 hoister.hoist(ty)
543 }
544
545 pub fn marker(&self) -> Marker {
546 self.cursor.marker()
547 }
548
549 pub fn hoister(
550 &mut self,
551 assume_invariants: bool,
552 ) -> Hoister<Unpacker<'_, 'infcx, 'genv, 'tcx>> {
553 Hoister::with_delegate(Unpacker { infcx: self, assume_invariants, name: None })
554 .transparent()
555 }
556
557 pub fn assume_invariants(&mut self, ty: &Ty) {
558 self.cursor
559 .assume_invariants(self.genv, ty, self.check_overflow);
560 }
561
562 fn check_impl(&mut self, pred1: impl Into<Expr>, pred2: impl Into<Expr>, tag: Tag) {
563 self.cursor.check_impl(pred1, pred2, tag);
564 }
565}
566
567pub struct Unpacker<'a, 'infcx, 'genv, 'tcx> {
568 infcx: &'a mut InferCtxt<'infcx, 'genv, 'tcx>,
569 assume_invariants: bool,
570 name: Option<Symbol>,
571}
572
573impl HoisterDelegate for Unpacker<'_, '_, '_, '_> {
574 fn hoist_exists(&mut self, ty_ctor: &TyCtor) -> Ty {
575 let ty = ty_ctor.replace_bound_refts_with(|sort, _, kind| {
576 let kind = if let Some(name) = self.name { BoundReftKind::Named(name) } else { kind };
577 Expr::fvar(self.infcx.define_bound_reft_var(sort, kind))
578 });
579 if self.assume_invariants {
580 self.infcx.assume_invariants(&ty);
581 }
582 ty
583 }
584
585 fn hoist_constr(&mut self, pred: Expr) {
586 self.infcx.assume_pred(pred);
587 }
588}
589
590impl std::fmt::Debug for InferCtxt<'_, '_, '_> {
591 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
592 std::fmt::Debug::fmt(&self.cursor, f)
593 }
594}
595
596#[derive(Debug)]
597pub struct InferCtxtAt<'a, 'infcx, 'genv, 'tcx> {
598 pub infcx: &'a mut InferCtxt<'infcx, 'genv, 'tcx>,
599 pub span: Span,
600}
601
602impl<'genv, 'tcx> InferCtxtAt<'_, '_, 'genv, 'tcx> {
603 fn tag(&self, reason: ConstrReason) -> Tag {
604 Tag::new(reason, self.span)
605 }
606
607 pub fn check_pred(&mut self, pred: impl Into<Expr>, reason: ConstrReason) {
608 let tag = self.tag(reason);
609 self.infcx.check_pred(pred, tag);
610 }
611
612 pub fn check_non_closure_clauses(
613 &mut self,
614 clauses: &[rty::Clause],
615 reason: ConstrReason,
616 ) -> InferResult {
617 for clause in clauses {
618 if let rty::ClauseKind::Projection(projection_pred) = clause.kind_skipping_binder() {
619 let impl_elem = BaseTy::Alias(projection_pred.projection_term.to_alias_ty())
620 .to_ty()
621 .deeply_normalize(self)?;
622 let term = projection_pred.term.to_ty().deeply_normalize(self)?;
623
624 self.subtyping(&impl_elem, &term, reason)?;
626 self.subtyping(&term, &impl_elem, reason)?;
627 }
628 }
629 Ok(())
630 }
631
632 pub fn subtyping_with_env(
635 &mut self,
636 env: &mut impl LocEnv,
637 a: &Ty,
638 b: &Ty,
639 reason: ConstrReason,
640 ) -> InferResult<Vec<Binder<rty::CoroutineObligPredicate>>> {
641 let mut sub = Sub::new(env, reason, self.span);
642 sub.tys(self.infcx, a, b)?;
643 Ok(sub.obligations)
644 }
645
646 pub fn subtyping(
651 &mut self,
652 a: &Ty,
653 b: &Ty,
654 reason: ConstrReason,
655 ) -> InferResult<Vec<Binder<rty::CoroutineObligPredicate>>> {
656 let mut env = DummyEnv;
657 let mut sub = Sub::new(&mut env, reason, self.span);
658 sub.tys(self.infcx, a, b)?;
659 Ok(sub.obligations)
660 }
661
662 pub fn subtyping_generic_args(
663 &mut self,
664 variance: Variance,
665 a: &GenericArg,
666 b: &GenericArg,
667 reason: ConstrReason,
668 ) -> InferResult<Vec<Binder<rty::CoroutineObligPredicate>>> {
669 let mut env = DummyEnv;
670 let mut sub = Sub::new(&mut env, reason, self.span);
671 sub.generic_args(self.infcx, variance, a, b)?;
672 Ok(sub.obligations)
673 }
674
675 pub fn check_constructor(
679 &mut self,
680 variant: EarlyBinder<PolyVariant>,
681 generic_args: &[GenericArg],
682 fields: &[Ty],
683 reason: ConstrReason,
684 ) -> InferResult<Ty> {
685 let ret = self.ensure_resolved_evars(|this| {
686 let generic_args = this.instantiate_generic_args(generic_args);
688
689 let variant = variant
690 .instantiate(this.tcx(), &generic_args, &[])
691 .replace_bound_refts_with(|sort, mode, _| this.fresh_infer_var(sort, mode));
692
693 for (actual, formal) in iter::zip(fields, variant.fields()) {
695 this.subtyping(actual, formal, reason)?;
696 }
697
698 for require in &variant.requires {
700 this.check_pred(require, ConstrReason::Fold);
701 }
702
703 Ok(variant.ret())
704 })?;
705 Ok(self.fully_resolve_evars(&ret))
706 }
707
708 pub fn ensure_resolved_evars<R>(
709 &mut self,
710 f: impl FnOnce(&mut InferCtxtAt<'_, '_, 'genv, 'tcx>) -> InferResult<R>,
711 ) -> InferResult<R> {
712 self.infcx
713 .ensure_resolved_evars(|infcx| f(&mut infcx.at(self.span)))
714 }
715}
716
717impl<'a, 'genv, 'tcx> std::ops::Deref for InferCtxtAt<'_, 'a, 'genv, 'tcx> {
718 type Target = InferCtxt<'a, 'genv, 'tcx>;
719
720 fn deref(&self) -> &Self::Target {
721 self.infcx
722 }
723}
724
725impl std::ops::DerefMut for InferCtxtAt<'_, '_, '_, '_> {
726 fn deref_mut(&mut self) -> &mut Self::Target {
727 self.infcx
728 }
729}
730
731#[derive(TypeVisitable, TypeFoldable)]
735pub(crate) enum TypeTrace {
736 Types(Ty, Ty),
737 BaseTys(BaseTy, BaseTy),
738}
739
740#[expect(dead_code, reason = "we use this for debugging some time")]
741impl TypeTrace {
742 fn tys(a: &Ty, b: &Ty) -> Self {
743 Self::Types(a.clone(), b.clone())
744 }
745
746 fn btys(a: &BaseTy, b: &BaseTy) -> Self {
747 Self::BaseTys(a.clone(), b.clone())
748 }
749}
750
751impl fmt::Debug for TypeTrace {
752 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
753 match self {
754 TypeTrace::Types(a, b) => write!(f, "{a:?} - {b:?}"),
755 TypeTrace::BaseTys(a, b) => write!(f, "{a:?} - {b:?}"),
756 }
757 }
758}
759
760pub trait LocEnv {
761 fn ptr_to_ref(
762 &mut self,
763 infcx: &mut InferCtxtAt,
764 reason: ConstrReason,
765 re: Region,
766 path: &Path,
767 bound: Ty,
768 ) -> InferResult<Ty>;
769
770 fn unfold_strg_ref(&mut self, infcx: &mut InferCtxt, path: &Path, ty: &Ty) -> InferResult<Loc>;
771
772 fn unfold_local_ptr(&mut self, infcx: &mut InferCtxt, bound: &Ty) -> InferResult<Loc>;
774
775 fn fold_local_ptrs(&mut self, infcx: &mut InferCtxtAt) -> InferResult;
777
778 fn get(&self, path: &Path) -> Ty;
779
780 fn update_path(&mut self, path: &Path, new_ty: Ty, span: Span);
781
782 fn assume_ensures(&mut self, infcx: &mut InferCtxt, ensures: &[rty::Ensures], span: Span) {
783 for ensure in ensures {
784 match ensure {
785 rty::Ensures::Type(path, updated_ty) => {
786 let updated_ty = infcx.unpack(updated_ty);
787 infcx.assume_invariants(&updated_ty);
788 self.update_path(path, updated_ty, span);
789 }
790 rty::Ensures::Pred(e) => infcx.assume_pred(e),
791 }
792 }
793 }
794
795 fn check_ensures(
796 &mut self,
797 at: &mut InferCtxtAt,
798 ensures: &[rty::Ensures],
799 reason: ConstrReason,
800 ) -> InferResult {
801 for constraint in ensures {
802 match constraint {
803 rty::Ensures::Type(path, ty) => {
804 let actual_ty = self.get(path).unblocked(); at.subtyping(&actual_ty, ty, reason)?;
806 }
807 rty::Ensures::Pred(e) => {
808 at.check_pred(e, ConstrReason::Ret);
809 }
810 }
811 }
812 Ok(())
813 }
814}
815
816pub(crate) struct DummyEnv;
819
820impl LocEnv for DummyEnv {
821 fn ptr_to_ref(
822 &mut self,
823 _: &mut InferCtxtAt,
824 _: ConstrReason,
825 _: Region,
826 _: &Path,
827 _: Ty,
828 ) -> InferResult<Ty> {
829 tracked_span_bug!("call to `ptr_to_ref` on `DummyEnv`")
830 }
831
832 fn unfold_strg_ref(&mut self, _: &mut InferCtxt, _: &Path, _: &Ty) -> InferResult<Loc> {
833 tracked_span_bug!("call to `unfold_str_ref` on `DummyEnv`")
834 }
835
836 fn unfold_local_ptr(&mut self, _: &mut InferCtxt, _: &Ty) -> InferResult<Loc> {
837 tracked_span_bug!("call to `unfold_local_ptr` on `DummyEnv`")
838 }
839
840 fn fold_local_ptrs(&mut self, _: &mut InferCtxtAt) -> InferResult {
841 Ok(())
843 }
844
845 fn get(&self, _: &Path) -> Ty {
846 tracked_span_bug!("call to `get` on `DummyEnv`")
847 }
848
849 fn update_path(&mut self, _: &Path, _: Ty, _: Span) {
850 tracked_span_bug!("call to `update_path` on `DummyEnv`");
851 }
852}
853
854struct Sub<'a, E> {
856 env: &'a mut E,
858 reason: ConstrReason,
859 span: Span,
860 obligations: Vec<Binder<rty::CoroutineObligPredicate>>,
864}
865
866impl<'a, E: LocEnv> Sub<'a, E> {
867 fn new(env: &'a mut E, reason: ConstrReason, span: Span) -> Self {
868 Self { env, reason, span, obligations: vec![] }
869 }
870
871 fn tag(&self) -> Tag {
872 Tag::new(self.reason, self.span)
873 }
874
875 fn tys(&mut self, infcx: &mut InferCtxt, a: &Ty, b: &Ty) -> InferResult {
876 let infcx = &mut infcx.branch();
877 let a = infcx.unpack(a);
883
884 match (a.kind(), b.kind()) {
885 (TyKind::Exists(..), _) => {
886 bug!("existentials should have been removed by the unpacking above");
887 }
888 (TyKind::Constr(..), _) => {
889 bug!("constraint types should have been removed by the unpacking above");
890 }
891
892 (_, TyKind::Exists(ctor_b)) => {
893 infcx.enter_exists(ctor_b, |infcx, ty_b| self.tys(infcx, &a, &ty_b))
894 }
895 (_, TyKind::Constr(pred_b, ty_b)) => {
896 infcx.check_pred(pred_b, self.tag());
897 self.tys(infcx, &a, ty_b)
898 }
899
900 (TyKind::Ptr(PtrKind::Mut(_), path_a), TyKind::StrgRef(_, path_b, ty_b)) => {
901 let ty_a = self.env.get(path_a);
905 infcx.unify_exprs(&path_a.to_expr(), &path_b.to_expr());
906 self.tys(infcx, &ty_a, ty_b)
907 }
908 (TyKind::StrgRef(_, path_a, ty_a), TyKind::StrgRef(_, path_b, ty_b)) => {
909 self.env.unfold_strg_ref(infcx, path_a, ty_a)?;
921 let ty_a = self.env.get(path_a);
922 infcx.unify_exprs(&path_a.to_expr(), &path_b.to_expr());
923 self.tys(infcx, &ty_a, ty_b)
924 }
925 (
926 TyKind::Ptr(PtrKind::Mut(re), path),
927 TyKind::Indexed(BaseTy::Ref(_, bound, Mutability::Mut), idx),
928 ) => {
929 self.idxs_eq(infcx, &Expr::unit(), idx);
932
933 self.env.ptr_to_ref(
934 &mut infcx.at(self.span),
935 self.reason,
936 *re,
937 path,
938 bound.clone(),
939 )?;
940 Ok(())
941 }
942
943 (TyKind::Indexed(bty_a, idx_a), TyKind::Indexed(bty_b, idx_b)) => {
944 self.btys(infcx, bty_a, bty_b)?;
945 self.idxs_eq(infcx, idx_a, idx_b);
946 Ok(())
947 }
948 (TyKind::Ptr(pk_a, path_a), TyKind::Ptr(pk_b, path_b)) => {
949 debug_assert_eq!(pk_a, pk_b);
950 debug_assert_eq!(path_a, path_b);
951 Ok(())
952 }
953 (TyKind::Param(param_ty_a), TyKind::Param(param_ty_b)) => {
954 debug_assert_eq!(param_ty_a, param_ty_b);
955 Ok(())
956 }
957 (_, TyKind::Uninit) => Ok(()),
958 (TyKind::Downcast(.., fields_a), TyKind::Downcast(.., fields_b)) => {
959 debug_assert_eq!(fields_a.len(), fields_b.len());
960 for (ty_a, ty_b) in iter::zip(fields_a, fields_b) {
961 self.tys(infcx, ty_a, ty_b)?;
962 }
963 Ok(())
964 }
965 _ => Err(query_bug!("incompatible types: `{a:?}` - `{b:?}`"))?,
966 }
967 }
968
969 fn btys(&mut self, infcx: &mut InferCtxt, a: &BaseTy, b: &BaseTy) -> InferResult {
970 match (a, b) {
973 (BaseTy::Int(int_ty_a), BaseTy::Int(int_ty_b)) => {
974 debug_assert_eq!(int_ty_a, int_ty_b);
975 Ok(())
976 }
977 (BaseTy::Uint(uint_ty_a), BaseTy::Uint(uint_ty_b)) => {
978 debug_assert_eq!(uint_ty_a, uint_ty_b);
979 Ok(())
980 }
981 (BaseTy::Adt(a_adt, a_args), BaseTy::Adt(b_adt, b_args)) => {
982 tracked_span_dbg_assert_eq!(a_adt.did(), b_adt.did());
983 tracked_span_dbg_assert_eq!(a_args.len(), b_args.len());
984 let variances = infcx.genv.variances_of(a_adt.did());
985 for (variance, ty_a, ty_b) in izip!(variances, a_args.iter(), b_args.iter()) {
986 self.generic_args(infcx, *variance, ty_a, ty_b)?;
987 }
988 Ok(())
989 }
990 (BaseTy::FnDef(a_def_id, a_args), BaseTy::FnDef(b_def_id, b_args)) => {
991 debug_assert_eq!(a_def_id, b_def_id);
992 debug_assert_eq!(a_args.len(), b_args.len());
993 for (arg_a, arg_b) in iter::zip(a_args, b_args) {
1001 match (arg_a, arg_b) {
1002 (GenericArg::Ty(ty_a), GenericArg::Ty(ty_b)) => {
1003 let bty_a = ty_a.as_bty_skipping_existentials();
1004 let bty_b = ty_b.as_bty_skipping_existentials();
1005 tracked_span_dbg_assert_eq!(bty_a, bty_b);
1006 }
1007 (GenericArg::Base(ctor_a), GenericArg::Base(ctor_b)) => {
1008 let bty_a = ctor_a.as_bty_skipping_binder();
1009 let bty_b = ctor_b.as_bty_skipping_binder();
1010 tracked_span_dbg_assert_eq!(bty_a, bty_b);
1011 }
1012 (_, _) => tracked_span_dbg_assert_eq!(arg_a, arg_b),
1013 }
1014 }
1015 Ok(())
1016 }
1017 (BaseTy::Float(float_ty_a), BaseTy::Float(float_ty_b)) => {
1018 debug_assert_eq!(float_ty_a, float_ty_b);
1019 Ok(())
1020 }
1021 (BaseTy::Slice(ty_a), BaseTy::Slice(ty_b)) => self.tys(infcx, ty_a, ty_b),
1022
1023 (BaseTy::RawPtr(ty_a, mut_a), BaseTy::RawPtr(ty_b, mut_b)) => {
1024 debug_assert_eq!(mut_a, mut_b);
1025 self.tys(infcx, ty_a, ty_b)?;
1026 if matches!(mut_a, Mutability::Mut) {
1027 self.tys(infcx, ty_b, ty_a)?;
1028 }
1029 Ok(())
1030 }
1031
1032 (BaseTy::Ref(_, ty_a, Mutability::Mut), BaseTy::Ref(_, ty_b, Mutability::Mut)) => {
1033 if ty_a.is_slice()
1034 && let TyKind::Indexed(_, idx_a) = ty_a.kind()
1035 && let TyKind::Exists(bty_b) = ty_b.kind()
1036 {
1037 self.tys(infcx, ty_a, ty_b)?;
1042 self.tys(infcx, &bty_b.replace_bound_reft(idx_a), ty_a)
1043 } else {
1044 self.tys(infcx, ty_a, ty_b)?;
1045 self.tys(infcx, ty_b, ty_a)
1046 }
1047 }
1048 (BaseTy::Ref(_, ty_a, Mutability::Not), BaseTy::Ref(_, ty_b, Mutability::Not)) => {
1049 self.tys(infcx, ty_a, ty_b)
1050 }
1051 (BaseTy::Tuple(tys_a), BaseTy::Tuple(tys_b)) => {
1052 debug_assert_eq!(tys_a.len(), tys_b.len());
1053 for (ty_a, ty_b) in iter::zip(tys_a, tys_b) {
1054 self.tys(infcx, ty_a, ty_b)?;
1055 }
1056 Ok(())
1057 }
1058 (
1059 BaseTy::Alias(AliasTy {
1060 kind: AliasKind::Opaque { def_id: def_id_a },
1061 args: args_a,
1062 refine_args: refine_args_a,
1063 }),
1064 BaseTy::Alias(AliasTy {
1065 kind: AliasKind::Opaque { def_id: def_id_b },
1066 args: args_b,
1067 refine_args: refine_args_b,
1068 }),
1069 ) => {
1070 debug_assert_eq!(def_id_a, def_id_b);
1071
1072 for (ty_a, ty_b) in izip!(args_a.iter(), args_b.iter()) {
1074 self.generic_args(infcx, Invariant, ty_a, ty_b)?;
1075 }
1076
1077 debug_assert_eq!(refine_args_a.len(), refine_args_b.len());
1079 iter::zip(refine_args_a.iter(), refine_args_b.iter())
1080 .for_each(|(expr_a, expr_b)| infcx.unify_exprs(expr_a, expr_b));
1081
1082 Ok(())
1083 }
1084 (
1085 _,
1086 BaseTy::Alias(AliasTy { kind: AliasKind::Opaque { def_id }, args, refine_args }),
1087 ) => {
1088 self.handle_opaque_type(infcx, a, *def_id, args, refine_args)
1090 }
1091 (
1092 BaseTy::Alias(alias_ty_a @ AliasTy { kind: AliasKind::Projection { .. }, .. }),
1093 BaseTy::Alias(alias_ty_b @ AliasTy { kind: AliasKind::Projection { .. }, .. }),
1094 ) => {
1095 tracked_span_dbg_assert_eq!(alias_ty_a.erase_regions(), alias_ty_b.erase_regions());
1096 Ok(())
1097 }
1098 (BaseTy::Array(ty_a, len_a), BaseTy::Array(ty_b, len_b)) => {
1099 tracked_span_dbg_assert_eq!(len_a, len_b);
1100 self.tys(infcx, ty_a, ty_b)
1101 }
1102 (BaseTy::Param(param_a), BaseTy::Param(param_b)) => {
1103 debug_assert_eq!(param_a, param_b);
1104 Ok(())
1105 }
1106 (BaseTy::Bool, BaseTy::Bool)
1107 | (BaseTy::Str, BaseTy::Str)
1108 | (BaseTy::Char, BaseTy::Char)
1109 | (BaseTy::RawPtrMetadata(_), BaseTy::RawPtrMetadata(_)) => Ok(()),
1110 (BaseTy::Dynamic(preds_a, _), BaseTy::Dynamic(preds_b, _)) => {
1111 tracked_span_assert_eq!(preds_a.erase_regions(), preds_b.erase_regions());
1112 Ok(())
1113 }
1114 (BaseTy::Closure(did1, tys_a, _, _), BaseTy::Closure(did2, tys_b, _, _))
1115 if did1 == did2 =>
1116 {
1117 debug_assert_eq!(tys_a.len(), tys_b.len());
1118 for (ty_a, ty_b) in iter::zip(tys_a, tys_b) {
1119 self.tys(infcx, ty_a, ty_b)?;
1120 }
1121 Ok(())
1122 }
1123 (BaseTy::FnPtr(sig_a), BaseTy::FnPtr(sig_b)) => {
1124 if sig_a == sig_b {
1125 return Ok(());
1126 }
1127 let sub_sig = SubFn::Mono(sig_a.clone());
1128 check_fn_subtyping(infcx, &mut DummyEnv, sub_sig, sig_b, self.span)
1129 }
1130 (BaseTy::Never, BaseTy::Never) => Ok(()),
1131 (
1132 BaseTy::Coroutine(did1, resume_ty_a, tys_a, _),
1133 BaseTy::Coroutine(did2, resume_ty_b, tys_b, _),
1134 ) if did1 == did2 => {
1135 debug_assert_eq!(tys_a.len(), tys_b.len());
1136 for (ty_a, ty_b) in iter::zip(tys_a, tys_b) {
1137 self.tys(infcx, ty_a, ty_b)?;
1138 }
1139 self.tys(infcx, resume_ty_b, resume_ty_a)?;
1141 self.tys(infcx, resume_ty_a, resume_ty_b)?;
1142
1143 Ok(())
1144 }
1145 (BaseTy::Foreign(did_a), BaseTy::Foreign(did_b)) if did_a == did_b => Ok(()),
1146 _ => Err(query_bug!("incompatible base types: `{a:#?}` - `{b:#?}`"))?,
1147 }
1148 }
1149
1150 fn generic_args(
1151 &mut self,
1152 infcx: &mut InferCtxt,
1153 variance: Variance,
1154 a: &GenericArg,
1155 b: &GenericArg,
1156 ) -> InferResult {
1157 let (ty_a, ty_b) = match (a, b) {
1158 (GenericArg::Ty(ty_a), GenericArg::Ty(ty_b)) => (ty_a.clone(), ty_b.clone()),
1159 (GenericArg::Base(ctor_a), GenericArg::Base(ctor_b)) => {
1160 tracked_span_dbg_assert_eq!(
1161 ctor_a.sort().erase_regions(),
1162 ctor_b.sort().erase_regions()
1163 );
1164 (ctor_a.to_ty(), ctor_b.to_ty())
1165 }
1166 (GenericArg::Lifetime(_), GenericArg::Lifetime(_)) => return Ok(()),
1167 (GenericArg::Const(cst_a), GenericArg::Const(cst_b)) => {
1168 debug_assert_eq!(cst_a, cst_b);
1169 return Ok(());
1170 }
1171 _ => Err(query_bug!("incompatible generic args: `{a:?}` `{b:?}`"))?,
1172 };
1173 match variance {
1174 Variance::Covariant => self.tys(infcx, &ty_a, &ty_b),
1175 Variance::Invariant => {
1176 self.tys(infcx, &ty_a, &ty_b)?;
1177 self.tys(infcx, &ty_b, &ty_a)
1178 }
1179 Variance::Contravariant => self.tys(infcx, &ty_b, &ty_a),
1180 Variance::Bivariant => Ok(()),
1181 }
1182 }
1183
1184 fn idxs_eq(&mut self, infcx: &mut InferCtxt, a: &Expr, b: &Expr) {
1185 if a == b {
1186 return;
1187 }
1188 match (a.kind(), b.kind()) {
1189 (
1190 ExprKind::Ctor(Ctor::Struct(did_a), flds_a),
1191 ExprKind::Ctor(Ctor::Struct(did_b), flds_b),
1192 ) => {
1193 debug_assert_eq!(did_a, did_b);
1194 for (a, b) in iter::zip(flds_a, flds_b) {
1195 self.idxs_eq(infcx, a, b);
1196 }
1197 }
1198 (ExprKind::Tuple(flds_a), ExprKind::Tuple(flds_b)) => {
1199 for (a, b) in iter::zip(flds_a, flds_b) {
1200 self.idxs_eq(infcx, a, b);
1201 }
1202 }
1203 (ExprKind::Ctor(Ctor::RawPtr, flds_a), ExprKind::Ctor(Ctor::RawPtr, flds_b)) => {
1204 for (a, b) in iter::zip(flds_a, flds_b) {
1205 self.idxs_eq(infcx, a, b);
1206 }
1207 }
1208 (_, ExprKind::Tuple(flds_b)) => {
1209 for (f, b) in flds_b.iter().enumerate() {
1210 let proj = FieldProj::Tuple { arity: flds_b.len(), field: f as u32 };
1211 let a = a.proj_and_reduce(proj);
1212 self.idxs_eq(infcx, &a, b);
1213 }
1214 }
1215 (_, ExprKind::Ctor(Ctor::RawPtr, flds_b)) => {
1216 for (f, b) in flds_b.iter().enumerate() {
1217 let field = rty::RawPtrField::from_index(f as u32).unwrap();
1218 let a = a.proj_and_reduce(FieldProj::RawPtr { field });
1219 self.idxs_eq(infcx, &a, b);
1220 }
1221 }
1222
1223 (_, ExprKind::Ctor(Ctor::Struct(def_id), flds_b)) => {
1224 for (f, b) in flds_b.iter().enumerate() {
1225 let proj = FieldProj::Adt { def_id: *def_id, field: f as u32 };
1226 let a = a.proj_and_reduce(proj);
1227 self.idxs_eq(infcx, &a, b);
1228 }
1229 }
1230
1231 (ExprKind::Tuple(flds_a), _) => {
1232 infcx.unify_exprs(a, b);
1233 for (f, a) in flds_a.iter().enumerate() {
1234 let proj = FieldProj::Tuple { arity: flds_a.len(), field: f as u32 };
1235 let b = b.proj_and_reduce(proj);
1236 self.idxs_eq(infcx, a, &b);
1237 }
1238 }
1239 (ExprKind::Ctor(Ctor::RawPtr, flds_a), _) => {
1240 infcx.unify_exprs(a, b);
1241 for (f, a) in flds_a.iter().enumerate() {
1242 let field = rty::RawPtrField::from_index(f as u32).unwrap();
1243 let b = b.proj_and_reduce(FieldProj::RawPtr { field });
1244 self.idxs_eq(infcx, a, &b);
1245 }
1246 }
1247 (ExprKind::Ctor(Ctor::Struct(def_id), flds_a), _) => {
1248 infcx.unify_exprs(a, b);
1249 for (f, a) in flds_a.iter().enumerate() {
1250 let proj = FieldProj::Adt { def_id: *def_id, field: f as u32 };
1251 let b = b.proj_and_reduce(proj);
1252 self.idxs_eq(infcx, a, &b);
1253 }
1254 }
1255 (ExprKind::Abs(lam_a), ExprKind::Abs(lam_b)) => {
1256 self.abs_eq(infcx, lam_a, lam_b);
1257 }
1258 (_, ExprKind::Abs(lam_b)) => {
1259 self.abs_eq(infcx, &a.eta_expand_abs(lam_b.vars(), lam_b.output()), lam_b);
1260 }
1261 (ExprKind::Abs(lam_a), _) => {
1262 infcx.unify_exprs(a, b);
1263 self.abs_eq(infcx, lam_a, &b.eta_expand_abs(lam_a.vars(), lam_a.output()));
1264 }
1265 (ExprKind::KVar(_), _) | (_, ExprKind::KVar(_)) => {
1266 infcx.check_impl(a, b, self.tag());
1267 infcx.check_impl(b, a, self.tag());
1268 }
1269 _ => {
1270 infcx.unify_exprs(a, b);
1271 let span = b.span();
1272 infcx.check_pred(Expr::binary_op(rty::BinOp::Eq, a, b).at_opt(span), self.tag());
1273 }
1274 }
1275 }
1276
1277 fn abs_eq(&mut self, infcx: &mut InferCtxt, a: &Lambda, b: &Lambda) {
1278 debug_assert_eq!(a.vars().len(), b.vars().len());
1279 let vars = a
1280 .vars()
1281 .iter()
1282 .map(|kind| {
1283 let (sort, _, kind) = kind.expect_refine();
1284 Expr::fvar(infcx.define_bound_reft_var(sort, kind))
1285 })
1286 .collect_vec();
1287 let body_a = a.apply(&vars);
1288 let body_b = b.apply(&vars);
1289 self.idxs_eq(infcx, &body_a, &body_b);
1290 }
1291
1292 fn handle_opaque_type(
1293 &mut self,
1294 infcx: &mut InferCtxt,
1295 bty: &BaseTy,
1296 opaque_def_id: DefId,
1297 opaque_args: &rty::GenericArgs,
1298 opaque_refine_args: &rty::RefineArgs,
1299 ) -> InferResult {
1300 if let BaseTy::Coroutine(def_id, resume_ty, upvar_tys, args) = bty {
1301 let obligs = mk_coroutine_obligations(
1302 infcx.genv,
1303 def_id,
1304 resume_ty,
1305 upvar_tys,
1306 &opaque_def_id,
1307 args.clone(),
1308 )?;
1309 self.obligations.extend(obligs);
1310 } else {
1311 let bounds = infcx.genv.item_bounds(opaque_def_id)?.instantiate(
1312 infcx.tcx(),
1313 opaque_args,
1314 opaque_refine_args,
1315 );
1316 for clause in &bounds {
1317 if !clause.kind().vars().is_empty() {
1318 Err(query_bug!("handle_opaque_types: clause with bound vars: `{clause:?}`"))?;
1319 }
1320 if let rty::ClauseKind::Projection(pred) = clause.kind_skipping_binder() {
1321 let alias_ty = pred
1322 .projection_term
1323 .with_self_ty(bty.to_subset_ty_ctor())
1324 .to_alias_ty();
1325 let ty1 = BaseTy::Alias(alias_ty)
1326 .to_ty()
1327 .deeply_normalize(&mut infcx.at(self.span))?;
1328 let ty2 = pred.term.to_ty();
1329 self.tys(infcx, &ty1, &ty2)?;
1330 }
1331 }
1332 }
1333 Ok(())
1334 }
1335}
1336
1337fn mk_coroutine_obligations(
1338 genv: GlobalEnv,
1339 generator_did: &DefId,
1340 resume_ty: &Ty,
1341 upvar_tys: &List<Ty>,
1342 opaque_def_id: &DefId,
1343 args: flux_rustc_bridge::ty::GenericArgs,
1344) -> InferResult<Vec<Binder<rty::CoroutineObligPredicate>>> {
1345 let bounds = genv.item_bounds(*opaque_def_id)?.skip_binder();
1346 for bound in &bounds {
1347 if let Some(proj_clause) = bound.as_projection_clause() {
1348 return Ok(vec![proj_clause.map(|proj_clause| {
1349 let output = proj_clause.term;
1350 CoroutineObligPredicate {
1351 def_id: *generator_did,
1352 resume_ty: resume_ty.clone(),
1353 upvar_tys: upvar_tys.clone(),
1354 output: output.to_ty(),
1355 args,
1356 }
1357 })]);
1358 }
1359 }
1360 bug!("no projection predicate")
1361}
1362
1363#[derive(Debug)]
1364pub enum InferErr {
1365 UnsolvedEvar(EVid),
1366 Query(QueryErr),
1367}
1368
1369impl From<QueryErr> for InferErr {
1370 fn from(v: QueryErr) -> Self {
1371 Self::Query(v)
1372 }
1373}
1374
1375mod pretty {
1376 use std::fmt;
1377
1378 use flux_middle::pretty::*;
1379
1380 use super::*;
1381
1382 impl Pretty for Tag {
1383 fn fmt(&self, cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1384 w!(cx, f, "{:?} at {:?}", ^self.reason, self.src_span)?;
1385 if let Some(dst_span) = self.dst_span {
1386 w!(cx, f, " ({:?})", ^dst_span)?;
1387 }
1388 Ok(())
1389 }
1390 }
1391
1392 impl_debug_with_default_cx!(Tag);
1393}