1use std::fmt;
4
5use base_db::Crate;
6use hir_def::{GenericParamId, TraitId};
7use rustc_hash::FxHashSet;
8use rustc_type_ir::{
9 TyVid, TypeFoldable, TypeVisitableExt,
10 inherent::{Const as _, GenericArg as _, IntoKind, Ty as _},
11 solve::Certainty,
12};
13use smallvec::SmallVec;
14use thin_vec::ThinVec;
15
16use crate::{
17 InferBodyId, InferenceDiagnostic, Span,
18 db::HirDatabase,
19 next_solver::{
20 Canonical, ClauseKind, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArg,
21 GenericArgs, ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, Ty,
22 TyKind, TypingMode,
23 fulfill::{FulfillmentCtxt, NextSolverError},
24 infer::{
25 DbInternerInferExt, InferCtxt, InferOk,
26 at::At,
27 snapshot::CombinedSnapshot,
28 traits::{Obligation, ObligationCause, PredicateObligation},
29 },
30 inspect::{InspectConfig, InspectGoal, ProofTreeVisitor},
31 obligation_ctxt::ObligationCtxt,
32 },
33 solver_errors::SolverDiagnostic,
34 traits::ParamEnvAndCrate,
35};
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub(crate) enum UseSubtyping {
40 No,
43
44 Yes,
50}
51
52struct NestedObligationsForSelfTy<'a, 'db> {
53 ctx: &'a InferenceTable<'db>,
54 self_ty: TyVid,
55 root_cause: &'a ObligationCause,
56 obligations_for_self_ty: &'a mut SmallVec<[Obligation<'db, Predicate<'db>>; 4]>,
57 subtyping: UseSubtyping,
58}
59
60impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> {
61 type Result = ();
62
63 fn span(&self) -> Span {
64 self.root_cause.span()
65 }
66
67 fn config(&self) -> InspectConfig {
68 InspectConfig { max_depth: 5 }
72 }
73
74 fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'db>) {
75 if inspect_goal.result() == Ok(Certainty::Yes) {
78 return;
79 }
80
81 let db = self.ctx.interner();
82 let goal = inspect_goal.goal();
83 if self.ctx.predicate_has_self_ty(goal.predicate, self.self_ty, self.subtyping) {
84 self.obligations_for_self_ty.push(Obligation::new(
85 db,
86 *self.root_cause,
87 goal.param_env,
88 goal.predicate,
89 ));
90 }
91
92 if let Some(candidate) = inspect_goal.unique_applicable_candidate() {
97 candidate.visit_nested_no_probe(self)
98 }
99 }
100}
101
102pub fn could_unify<'db>(
109 db: &'db dyn HirDatabase,
110 env: ParamEnvAndCrate<'db>,
111 tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>,
112) -> bool {
113 could_unify_impl(db, env, tys, |ctxt| ctxt.try_evaluate_obligations())
114}
115
116pub fn could_unify_deeply<'db>(
121 db: &'db dyn HirDatabase,
122 env: ParamEnvAndCrate<'db>,
123 tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>,
124) -> bool {
125 could_unify_impl(db, env, tys, |ctxt| ctxt.evaluate_obligations_error_on_ambiguity())
126}
127
128fn could_unify_impl<'db>(
129 db: &'db dyn HirDatabase,
130 env: ParamEnvAndCrate<'db>,
131 tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>,
132 select: for<'a> fn(&mut ObligationCtxt<'a, 'db>) -> Vec<NextSolverError<'db>>,
133) -> bool {
134 let interner = DbInterner::new_with(db, env.krate);
135 let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
136 let cause = ObligationCause::dummy();
137 let at = infcx.at(&cause, env.param_env);
138 let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(Span::Dummy, tys);
139 let mut ctxt = ObligationCtxt::new(&infcx);
140 let can_unify = at
141 .eq(ty1_with_vars, ty2_with_vars)
142 .map(|infer_ok| ctxt.register_infer_ok_obligations(infer_ok))
143 .is_ok();
144 can_unify && select(&mut ctxt).is_empty()
145}
146
147pub(crate) struct InferenceTable<'db> {
148 pub(crate) db: &'db dyn HirDatabase,
149 pub(crate) param_env: ParamEnv<'db>,
150 pub(crate) infer_ctxt: InferCtxt<'db>,
151 pub(super) fulfillment_cx: FulfillmentCtxt<'db>,
152 pub(super) diverging_type_vars: FxHashSet<Ty<'db>>,
153 pub(super) trait_errors: Vec<NextSolverError<'db>>,
154}
155
156impl<'db> InferenceTable<'db> {
157 pub(crate) fn new(
160 db: &'db dyn HirDatabase,
161 trait_env: ParamEnv<'db>,
162 krate: Crate,
163 owner: InferBodyId<'db>,
164 ) -> Self {
165 let interner = DbInterner::new_with(db, krate);
166 let typing_mode = TypingMode::typeck_for_body(interner, owner.into());
167 let infer_ctxt = interner.infer_ctxt().build(typing_mode);
168 InferenceTable {
169 db,
170 param_env: trait_env,
171 fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt),
172 infer_ctxt,
173 diverging_type_vars: FxHashSet::default(),
174 trait_errors: Vec::new(),
175 }
176 }
177
178 #[inline]
179 pub(crate) fn interner(&self) -> DbInterner<'db> {
180 self.infer_ctxt.interner
181 }
182
183 pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'db>) -> bool {
184 self.infer_ctxt.type_is_copy_modulo_regions(self.param_env, ty)
185 }
186
187 pub(crate) fn type_is_sized_modulo_regions(&self, ty: Ty<'db>) -> bool {
188 self.infer_ctxt.type_is_sized_modulo_regions(self.param_env, ty)
189 }
190
191 pub(crate) fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'db>) -> bool {
192 self.infer_ctxt.type_is_use_cloned_modulo_regions(self.param_env, ty)
193 }
194
195 pub(crate) fn type_var_is_sized(&self, self_ty: TyVid) -> bool {
196 let Some(sized_did) = self.interner().lang_items().Sized else {
197 return true;
198 };
199 self.obligations_for_self_ty(self_ty, UseSubtyping::Yes).into_iter().any(|obligation| {
203 match obligation.predicate.kind().skip_binder() {
204 PredicateKind::Clause(ClauseKind::Trait(data)) => data.def_id().0 == sized_did,
205 _ => false,
206 }
207 })
208 }
209
210 pub(super) fn obligations_for_self_ty(
211 &self,
212 self_ty: TyVid,
213 subtyping: UseSubtyping,
214 ) -> SmallVec<[Obligation<'db, Predicate<'db>>; 4]> {
215 let obligations = self.fulfillment_cx.pending_obligations();
216 let mut obligations_for_self_ty = SmallVec::new();
217 for obligation in obligations {
218 let mut visitor = NestedObligationsForSelfTy {
219 ctx: self,
220 self_ty,
221 obligations_for_self_ty: &mut obligations_for_self_ty,
222 root_cause: &obligation.cause,
223 subtyping,
224 };
225
226 let goal = obligation.as_goal();
227 self.infer_ctxt.visit_proof_tree(goal, &mut visitor);
228 }
229
230 obligations_for_self_ty.retain_mut(|obligation| {
231 obligation.predicate = self.infer_ctxt.resolve_vars_if_possible(obligation.predicate);
232 !obligation.predicate.has_placeholders()
233 });
234 obligations_for_self_ty
235 }
236
237 fn predicate_has_self_ty(
238 &self,
239 predicate: Predicate<'db>,
240 expected_vid: TyVid,
241 subtyping: UseSubtyping,
242 ) -> bool {
243 match predicate.kind().skip_binder() {
244 PredicateKind::Clause(ClauseKind::Trait(data)) => {
245 self.type_matches_expected_vid(expected_vid, data.self_ty(), subtyping)
246 }
247 PredicateKind::Clause(ClauseKind::Projection(data)) => self.type_matches_expected_vid(
248 expected_vid,
249 data.projection_term.self_ty(),
250 subtyping,
251 ),
252 PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
253 | PredicateKind::Subtype(..)
254 | PredicateKind::Coerce(..)
255 | PredicateKind::Clause(ClauseKind::RegionOutlives(..))
256 | PredicateKind::Clause(ClauseKind::TypeOutlives(..))
257 | PredicateKind::Clause(ClauseKind::WellFormed(..))
258 | PredicateKind::DynCompatible(..)
259 | PredicateKind::NormalizesTo(..)
260 | PredicateKind::AliasRelate(..)
261 | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
262 | PredicateKind::ConstEquate(..)
263 | PredicateKind::Clause(ClauseKind::HostEffect(..))
264 | PredicateKind::Clause(ClauseKind::UnstableFeature(_))
265 | PredicateKind::Ambiguous => false,
266 }
267 }
268
269 fn type_matches_expected_vid(
270 &self,
271 expected_vid: TyVid,
272 ty: Ty<'db>,
273 subtyping: UseSubtyping,
274 ) -> bool {
275 let ty = self.shallow_resolve(ty);
276
277 match ty.kind() {
278 TyKind::Infer(rustc_type_ir::TyVar(found_vid)) => match subtyping {
279 UseSubtyping::No => {
280 self.infer_ctxt.root_var(expected_vid) == self.infer_ctxt.root_var(found_vid)
281 }
282 UseSubtyping::Yes => {
283 self.infer_ctxt.sub_unification_table_root_var(expected_vid)
284 == self.infer_ctxt.sub_unification_table_root_var(found_vid)
285 }
286 },
287 _ => false,
288 }
289 }
290
291 pub(super) fn set_diverging(&mut self, ty: Ty<'db>) {
292 self.diverging_type_vars.insert(ty);
293 }
294
295 pub(crate) fn next_ty_var(&self, span: Span) -> Ty<'db> {
296 self.infer_ctxt.next_ty_var(span)
297 }
298
299 pub(crate) fn next_const_var(&self, span: Span) -> Const<'db> {
300 self.infer_ctxt.next_const_var(span)
301 }
302
303 pub(crate) fn next_int_var(&self) -> Ty<'db> {
304 self.infer_ctxt.next_int_var()
305 }
306
307 pub(crate) fn next_float_var(&self) -> Ty<'db> {
308 self.infer_ctxt.next_float_var()
309 }
310
311 pub(crate) fn new_maybe_never_var(&mut self, span: Span) -> Ty<'db> {
312 let var = self.next_ty_var(span);
313 self.set_diverging(var);
314 var
315 }
316
317 pub(crate) fn next_region_var(&self, span: Span) -> Region<'db> {
318 self.infer_ctxt.next_region_var(span)
319 }
320
321 pub(crate) fn var_for_def(&self, id: GenericParamId, span: Span) -> GenericArg<'db> {
322 self.infer_ctxt.var_for_def(id, span)
323 }
324
325 pub(crate) fn at<'a>(&'a self, cause: &'a ObligationCause) -> At<'a, 'db> {
326 self.infer_ctxt.at(cause, self.param_env)
327 }
328
329 pub(crate) fn shallow_resolve(&self, ty: Ty<'db>) -> Ty<'db> {
330 self.infer_ctxt.shallow_resolve(ty)
331 }
332
333 pub(crate) fn resolve_vars_if_possible<T: TypeFoldable<DbInterner<'db>>>(&self, t: T) -> T {
334 self.infer_ctxt.resolve_vars_if_possible(t)
335 }
336
337 pub(crate) fn resolve_vars_with_obligations<T>(&mut self, t: T) -> T
338 where
339 T: rustc_type_ir::TypeFoldable<DbInterner<'db>>,
340 {
341 if !t.has_non_region_infer() {
342 return t;
343 }
344
345 let t = self.infer_ctxt.resolve_vars_if_possible(t);
346
347 if !t.has_non_region_infer() {
348 return t;
349 }
350
351 self.select_obligations_where_possible();
352 self.infer_ctxt.resolve_vars_if_possible(t)
353 }
354
355 pub(crate) fn fresh_args_for_item(
357 &self,
358 span: Span,
359 def: SolverDefId<'db>,
360 ) -> GenericArgs<'db> {
361 self.infer_ctxt.fresh_args_for_item(span, def)
362 }
363
364 pub(crate) fn try_structurally_resolve_type(&mut self, span: Span, ty: Ty<'db>) -> Ty<'db> {
370 if let TyKind::Alias(..) = ty.kind() {
371 let result = self
372 .infer_ctxt
373 .at(&ObligationCause::new(span), self.param_env)
374 .structurally_normalize_ty(ty, &mut self.fulfillment_cx);
375 match result {
376 Ok(normalized_ty) => normalized_ty,
377 Err(errors) => {
378 self.trait_errors.extend(errors);
379 Ty::new_error(self.interner(), ErrorGuaranteed)
380 }
381 }
382 } else {
383 self.resolve_vars_with_obligations(ty)
384 }
385 }
386
387 pub(crate) fn try_structurally_resolve_const(
388 &mut self,
389 sp: Span,
390 ct: Const<'db>,
391 ) -> Const<'db> {
392 let ct = self.resolve_vars_with_obligations(ct);
393
394 if let ConstKind::Unevaluated(..) = ct.kind() {
395 let result = self
396 .infer_ctxt
397 .at(&ObligationCause::new(sp), self.param_env)
398 .structurally_normalize_const(ct, &mut self.fulfillment_cx);
399 match result {
400 Ok(normalized_ct) => normalized_ct,
401 Err(errors) => {
402 self.trait_errors.extend(errors);
403 Const::new_error(self.interner(), ErrorGuaranteed)
404 }
405 }
406 } else {
407 ct
408 }
409 }
410
411 pub(crate) fn snapshot(&mut self) -> CombinedSnapshot {
412 self.infer_ctxt.start_snapshot()
413 }
414
415 #[tracing::instrument(skip_all)]
416 pub(crate) fn rollback_to(&mut self, snapshot: CombinedSnapshot) {
417 self.infer_ctxt.rollback_to(snapshot);
418 }
419
420 pub(crate) fn commit_if_ok<T, E>(
421 &mut self,
422 f: impl FnOnce(&mut InferenceTable<'db>) -> Result<T, E>,
423 ) -> Result<T, E> {
424 let snapshot = self.snapshot();
425 let result = f(self);
426 match result {
427 Ok(_) => self.infer_ctxt.commit_from(snapshot),
428 Err(_) => self.rollback_to(snapshot),
429 }
430 result
431 }
432
433 pub(crate) fn register_bound(&mut self, ty: Ty<'db>, def_id: TraitId, cause: ObligationCause) {
434 if !ty.references_non_lt_error() {
435 let trait_ref = TraitRef::new(self.interner(), def_id.into(), [ty]);
436 self.register_predicate(Obligation::new(
437 self.interner(),
438 cause,
439 self.param_env,
440 trait_ref,
441 ));
442 }
443 }
444
445 pub(crate) fn register_infer_ok<T>(&mut self, infer_ok: InferOk<'db, T>) -> T {
446 let InferOk { value, obligations } = infer_ok;
447 self.register_predicates(obligations);
448 value
449 }
450
451 pub(crate) fn select_obligations_where_possible(&mut self) {
452 let errors = self.fulfillment_cx.try_evaluate_obligations(&self.infer_ctxt);
453 self.trait_errors.extend(errors);
454 }
455
456 pub(super) fn register_predicate(&mut self, obligation: PredicateObligation<'db>) {
457 if obligation.has_escaping_bound_vars() {
458 panic!("escaping bound vars in predicate {:?}", obligation);
459 }
460
461 self.fulfillment_cx.register_predicate_obligation(&self.infer_ctxt, obligation);
462 }
463
464 pub(crate) fn register_predicates<I>(&mut self, obligations: I)
465 where
466 I: IntoIterator<Item = PredicateObligation<'db>>,
467 {
468 self.fulfillment_cx.register_predicate_obligations(&self.infer_ctxt, obligations);
469 }
470
471 pub(crate) fn register_wf_obligation(&mut self, term: Term<'db>, cause: ObligationCause) {
473 self.register_predicate(Obligation::new(
474 self.interner(),
475 cause,
476 self.param_env,
477 ClauseKind::WellFormed(term),
478 ));
479 }
480
481 pub(crate) fn add_wf_bounds(&mut self, span: Span, args: GenericArgs<'db>) {
483 for term in args.iter().filter_map(|it| it.as_term()) {
484 self.register_wf_obligation(term, ObligationCause::new(span));
485 }
486 }
487
488 pub(super) fn insert_type_vars<T>(&mut self, ty: T) -> T
489 where
490 T: TypeFoldable<DbInterner<'db>>,
491 {
492 self.infer_ctxt.insert_type_vars(ty)
493 }
494
495 pub(crate) fn process_user_written_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
497 self.process_remote_user_written_ty(ty)
498 }
499
500 pub(crate) fn process_remote_user_written_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
503 let ty = self.insert_type_vars(ty);
504 self.try_structurally_resolve_type(Span::Dummy, ty)
508 }
509
510 fn emit_trait_errors(&mut self, diagnostics: &mut ThinVec<InferenceDiagnostic>) {
511 diagnostics.extend(std::mem::take(&mut self.trait_errors).into_iter().filter_map(
512 |error| {
513 let error = error.into_fulfillment_error(&self.infer_ctxt);
514 SolverDiagnostic::from_fulfillment_error(&error)
515 .map(InferenceDiagnostic::SolverDiagnostic)
516 },
517 ));
518 }
519}
520
521impl fmt::Debug for InferenceTable<'_> {
522 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
523 f.debug_struct("InferenceTable")
524 .field("name", &self.infer_ctxt.inner.borrow().type_variable_storage)
525 .field("fulfillment_cx", &self.fulfillment_cx)
526 .finish()
527 }
528}
529
530pub(super) mod resolve_completely {
531 use rustc_hash::FxHashSet;
532 use rustc_type_ir::{
533 DebruijnIndex, Flags, InferConst, InferTy, TypeFlags, TypeFoldable, TypeFolder,
534 TypeSuperFoldable, TypeVisitableExt, inherent::IntoKind,
535 };
536 use stdx::never;
537 use thin_vec::ThinVec;
538
539 use crate::{
540 InferenceDiagnostic, Span,
541 infer::unify::InferenceTable,
542 next_solver::{
543 Const, ConstKind, DbInterner, DefaultAny, GenericArg, Goal, Predicate, Region, Term,
544 TermKind, Ty, TyKind,
545 infer::{resolve::ReplaceInferWithError, traits::ObligationCause},
546 normalize::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals,
547 },
548 };
549
550 pub(crate) struct WriteBackCtxt<'db> {
551 table: InferenceTable<'db>,
552 diagnostics: ThinVec<InferenceDiagnostic>,
553 has_errors: bool,
554 spans_emitted_type_must_be_known_for: FxHashSet<Span>,
555 types: &'db DefaultAny<'db>,
556 }
557
558 impl<'db> WriteBackCtxt<'db> {
559 pub(crate) fn new(
560 table: InferenceTable<'db>,
561 diagnostics: ThinVec<InferenceDiagnostic>,
562 vars_emitted_type_must_be_known_for: FxHashSet<Term<'db>>,
563 ) -> Self {
564 let spans_emitted_type_must_be_known_for = vars_emitted_type_must_be_known_for
565 .into_iter()
566 .filter_map(|term| match term.kind() {
567 TermKind::Ty(ty) => match ty.kind() {
568 TyKind::Infer(InferTy::TyVar(vid)) => {
569 Some(table.infer_ctxt.type_var_span(vid))
570 }
571 _ => None,
572 },
573 TermKind::Const(ct) => match ct.kind() {
574 ConstKind::Infer(InferConst::Var(vid)) => {
575 table.infer_ctxt.const_var_span(vid)
576 }
577 _ => None,
578 },
579 })
580 .collect();
581
582 Self {
583 types: table.interner().default_types(),
584 table,
585 diagnostics,
586 has_errors: false,
587 spans_emitted_type_must_be_known_for,
588 }
589 }
590
591 pub(crate) fn resolve_completely<T>(&mut self, value_ref: &mut T)
592 where
593 T: TypeFoldable<DbInterner<'db>>,
594 {
595 self.resolve_completely_with_default(value_ref, value_ref.clone());
596 }
597
598 pub(crate) fn resolve_completely_with_default<T>(&mut self, value_ref: &mut T, default: T)
599 where
600 T: TypeFoldable<DbInterner<'db>>,
601 {
602 let value = std::mem::replace(value_ref, default);
603
604 let value = self.table.resolve_vars_if_possible(value);
605
606 let mut goals = vec![];
607
608 *value_ref = value.fold_with(&mut Resolver::new(self, true, &mut goals));
611 }
612
613 pub(crate) fn resolve_diagnostics(mut self) -> (ThinVec<InferenceDiagnostic>, bool) {
614 let has_errors = self.has_errors;
615
616 self.table.emit_trait_errors(&mut self.diagnostics);
617
618 let mut diagnostics = std::mem::take(&mut self.diagnostics);
620 diagnostics.retain_mut(|diagnostic| {
621 self.resolve_completely(diagnostic);
622
623 if let InferenceDiagnostic::CannotBeDereferenced { found: ty, .. }
624 | InferenceDiagnostic::CannotImplicitlyDerefTraitObject { found: ty, .. }
625 | InferenceDiagnostic::CannotIndexInto { found: ty, .. }
626 | InferenceDiagnostic::ExpectedFunction { found: ty, .. }
627 | InferenceDiagnostic::ExpectedArrayOrSlicePat { found: ty, .. }
628 | InferenceDiagnostic::UnaryOperatorCannotBeApplied { found: ty, .. }
629 | InferenceDiagnostic::UnresolvedField { receiver: ty, .. }
630 | InferenceDiagnostic::UnresolvedMethodCall { receiver: ty, .. } = diagnostic
631 && ty.as_ref().references_non_lt_error()
632 {
633 false
634 } else {
635 true
636 }
637 });
638 diagnostics.shrink_to_fit();
639
640 (diagnostics, has_errors)
641 }
642 }
643
644 struct DiagnoseInferVars<'a, 'db> {
645 ctx: &'a mut WriteBackCtxt<'db>,
646 top_term: Term<'db>,
647 }
648
649 impl<'db> DiagnoseInferVars<'_, 'db> {
650 const TYPE_FLAGS: TypeFlags = TypeFlags::HAS_INFER.union(TypeFlags::HAS_NON_REGION_ERROR);
651
652 fn err_on_span(&mut self, span: Span) {
653 if !self.ctx.spans_emitted_type_must_be_known_for.insert(span) {
654 return;
656 }
657
658 if span.is_dummy() {
659 return;
660 }
661
662 let top_term = self.top_term.fold_with(&mut ReplaceInferWithError::new(self.cx()));
664 self.ctx.diagnostics.push(InferenceDiagnostic::TypeMustBeKnown {
665 at_point: span,
666 top_term: Some(GenericArg::from(top_term).store()),
667 });
668 }
669 }
670
671 impl<'db> TypeFolder<DbInterner<'db>> for DiagnoseInferVars<'_, 'db> {
672 fn cx(&self) -> DbInterner<'db> {
673 self.ctx.table.interner()
674 }
675
676 fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
677 if !t.has_type_flags(Self::TYPE_FLAGS) {
678 return t;
679 }
680
681 match t.kind() {
682 TyKind::Error(_) => {
683 self.ctx.has_errors = true;
684 t
685 }
686 TyKind::Infer(infer_ty) => match infer_ty {
687 InferTy::TyVar(vid) => {
688 self.err_on_span(self.ctx.table.infer_ctxt.type_var_span(vid));
689 self.ctx.has_errors = true;
690 self.ctx.types.types.error
691 }
692 InferTy::IntVar(_) => {
693 never!("fallback should have resolved all int vars");
694 self.ctx.types.types.i32
695 }
696 InferTy::FloatVar(_) => {
697 never!("fallback should have resolved all float vars");
698 self.ctx.types.types.f64
699 }
700 InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_) => {
701 never!("should not have fresh infer vars outside of caching");
702 self.ctx.has_errors = true;
703 self.ctx.types.types.error
704 }
705 },
706 _ => t.super_fold_with(self),
707 }
708 }
709
710 fn fold_const(&mut self, c: Const<'db>) -> Const<'db> {
711 if !c.has_type_flags(Self::TYPE_FLAGS) {
712 return c;
713 }
714
715 match c.kind() {
716 ConstKind::Error(_) => {
717 self.ctx.has_errors = true;
718 c
719 }
720 ConstKind::Infer(infer_ct) => match infer_ct {
721 InferConst::Var(vid) => {
722 if let Some(span) = self.ctx.table.infer_ctxt.const_var_span(vid) {
723 self.err_on_span(span);
724 }
725 self.ctx.has_errors = true;
726 self.ctx.types.consts.error
727 }
728 InferConst::Fresh(_) => {
729 never!("should not have fresh infer vars outside of caching");
730 self.ctx.has_errors = true;
731 self.ctx.types.consts.error
732 }
733 },
734 _ => c.super_fold_with(self),
735 }
736 }
737
738 fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> {
739 if !p.has_type_flags(Self::TYPE_FLAGS) {
740 return p;
741 }
742 p.super_fold_with(self)
743 }
744
745 fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
746 if r.is_var() {
747 self.ctx.types.regions.error
749 } else {
750 r
751 }
752 }
753 }
754
755 pub(super) struct Resolver<'a, 'db> {
756 ctx: &'a mut WriteBackCtxt<'db>,
757 should_normalize: bool,
759 nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>,
760 }
761
762 impl<'a, 'db> Resolver<'a, 'db> {
763 pub(super) fn new(
764 ctx: &'a mut WriteBackCtxt<'db>,
765 should_normalize: bool,
766 nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>,
767 ) -> Resolver<'a, 'db> {
768 Resolver { ctx, nested_goals, should_normalize }
769 }
770
771 fn handle_term<T>(
772 &mut self,
773 value: T,
774 outer_exclusive_binder: impl FnOnce(T) -> DebruijnIndex,
775 ) -> T
776 where
777 T: Into<Term<'db>> + TypeSuperFoldable<DbInterner<'db>> + Copy,
778 {
779 let value = if self.should_normalize {
780 let cause = ObligationCause::new(Span::Dummy);
782 let at = self.ctx.table.at(&cause);
783 let universes = vec![None; outer_exclusive_binder(value).as_usize()];
784 match deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
785 at, value, universes,
786 ) {
787 Ok((value, goals)) => {
788 self.nested_goals.extend(goals);
789 value
790 }
791 Err(errors) => {
792 self.ctx.table.trait_errors.extend(errors);
793 value
794 }
795 }
796 } else {
797 value
798 };
799
800 value.fold_with(&mut DiagnoseInferVars { ctx: self.ctx, top_term: value.into() })
801 }
802 }
803
804 impl<'db> TypeFolder<DbInterner<'db>> for Resolver<'_, 'db> {
805 fn cx(&self) -> DbInterner<'db> {
806 self.ctx.table.interner()
807 }
808
809 fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
810 if r.is_var() { self.ctx.types.regions.error } else { r }
811 }
812
813 fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
814 self.handle_term(ty, |it| it.outer_exclusive_binder())
815 }
816
817 fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
818 self.handle_term(ct, |it| it.outer_exclusive_binder())
819 }
820
821 fn fold_predicate(&mut self, predicate: Predicate<'db>) -> Predicate<'db> {
822 assert!(
823 !self.should_normalize,
824 "normalizing predicates in writeback is not generally sound"
825 );
826 predicate.super_fold_with(self)
827 }
828 }
829}