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
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: InferBodyId<'db>,
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::UnaryOperatorCannotBeApplied { found: ty, .. }
590 | InferenceDiagnostic::UnresolvedField { receiver: ty, .. }
591 | InferenceDiagnostic::UnresolvedMethodCall { receiver: ty, .. } = diagnostic
592 && ty.as_ref().references_non_lt_error()
593 {
594 false
595 } else {
596 true
597 }
598 });
599 diagnostics.shrink_to_fit();
600
601 (diagnostics, has_errors)
602 }
603 }
604
605 struct DiagnoseInferVars<'a, 'db> {
606 ctx: &'a mut WriteBackCtxt<'db>,
607 top_term: Term<'db>,
608 }
609
610 impl<'db> DiagnoseInferVars<'_, 'db> {
611 const TYPE_FLAGS: TypeFlags = TypeFlags::HAS_INFER.union(TypeFlags::HAS_NON_REGION_ERROR);
612
613 fn err_on_span(&mut self, span: Span) {
614 if !self.ctx.spans_emitted_type_must_be_known_for.insert(span) {
615 return;
617 }
618
619 if span.is_dummy() {
620 return;
621 }
622
623 let top_term = self.top_term.fold_with(&mut ReplaceInferWithError::new(self.cx()));
625 self.ctx.diagnostics.push(InferenceDiagnostic::TypeMustBeKnown {
626 at_point: span,
627 top_term: Some(GenericArg::from(top_term).store()),
628 });
629 }
630 }
631
632 impl<'db> TypeFolder<DbInterner<'db>> for DiagnoseInferVars<'_, 'db> {
633 fn cx(&self) -> DbInterner<'db> {
634 self.ctx.table.interner()
635 }
636
637 fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
638 if !t.has_type_flags(Self::TYPE_FLAGS) {
639 return t;
640 }
641
642 match t.kind() {
643 TyKind::Error(_) => {
644 self.ctx.has_errors = true;
645 t
646 }
647 TyKind::Infer(infer_ty) => match infer_ty {
648 InferTy::TyVar(vid) => {
649 self.err_on_span(self.ctx.table.infer_ctxt.type_var_span(vid));
650 self.ctx.has_errors = true;
651 self.ctx.types.types.error
652 }
653 InferTy::IntVar(_) => {
654 never!("fallback should have resolved all int vars");
655 self.ctx.types.types.i32
656 }
657 InferTy::FloatVar(_) => {
658 never!("fallback should have resolved all float vars");
659 self.ctx.types.types.f64
660 }
661 InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_) => {
662 never!("should not have fresh infer vars outside of caching");
663 self.ctx.has_errors = true;
664 self.ctx.types.types.error
665 }
666 },
667 _ => t.super_fold_with(self),
668 }
669 }
670
671 fn fold_const(&mut self, c: Const<'db>) -> Const<'db> {
672 if !c.has_type_flags(Self::TYPE_FLAGS) {
673 return c;
674 }
675
676 match c.kind() {
677 ConstKind::Error(_) => {
678 self.ctx.has_errors = true;
679 c
680 }
681 ConstKind::Infer(infer_ct) => match infer_ct {
682 InferConst::Var(vid) => {
683 if let Some(span) = self.ctx.table.infer_ctxt.const_var_span(vid) {
684 self.err_on_span(span);
685 }
686 self.ctx.has_errors = true;
687 self.ctx.types.consts.error
688 }
689 InferConst::Fresh(_) => {
690 never!("should not have fresh infer vars outside of caching");
691 self.ctx.has_errors = true;
692 self.ctx.types.consts.error
693 }
694 },
695 _ => c.super_fold_with(self),
696 }
697 }
698
699 fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> {
700 if !p.has_type_flags(Self::TYPE_FLAGS) {
701 return p;
702 }
703 p.super_fold_with(self)
704 }
705
706 fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
707 if r.is_var() {
708 self.ctx.types.regions.error
710 } else {
711 r
712 }
713 }
714 }
715
716 pub(super) struct Resolver<'a, 'db> {
717 ctx: &'a mut WriteBackCtxt<'db>,
718 should_normalize: bool,
720 nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>,
721 }
722
723 impl<'a, 'db> Resolver<'a, 'db> {
724 pub(super) fn new(
725 ctx: &'a mut WriteBackCtxt<'db>,
726 should_normalize: bool,
727 nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>,
728 ) -> Resolver<'a, 'db> {
729 Resolver { ctx, nested_goals, should_normalize }
730 }
731
732 fn handle_term<T>(
733 &mut self,
734 value: T,
735 outer_exclusive_binder: impl FnOnce(T) -> DebruijnIndex,
736 ) -> T
737 where
738 T: Into<Term<'db>> + TypeSuperFoldable<DbInterner<'db>> + Copy,
739 {
740 let value = if self.should_normalize {
741 let cause = ObligationCause::new(Span::Dummy);
743 let at = self.ctx.table.at(&cause);
744 let universes = vec![None; outer_exclusive_binder(value).as_usize()];
745 match deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
746 at, value, universes,
747 ) {
748 Ok((value, goals)) => {
749 self.nested_goals.extend(goals);
750 value
751 }
752 Err(errors) => {
753 self.ctx.table.trait_errors.extend(errors);
754 value
755 }
756 }
757 } else {
758 value
759 };
760
761 value.fold_with(&mut DiagnoseInferVars { ctx: self.ctx, top_term: value.into() })
762 }
763 }
764
765 impl<'db> TypeFolder<DbInterner<'db>> for Resolver<'_, 'db> {
766 fn cx(&self) -> DbInterner<'db> {
767 self.ctx.table.interner()
768 }
769
770 fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
771 if r.is_var() { self.ctx.types.regions.error } else { r }
772 }
773
774 fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
775 self.handle_term(ty, |it| it.outer_exclusive_binder())
776 }
777
778 fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
779 self.handle_term(ct, |it| it.outer_exclusive_binder())
780 }
781
782 fn fold_predicate(&mut self, predicate: Predicate<'db>) -> Predicate<'db> {
783 assert!(
784 !self.should_normalize,
785 "normalizing predicates in writeback is not generally sound"
786 );
787 predicate.super_fold_with(self)
788 }
789 }
790}