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