Skip to main content

hir_ty/infer/
unify.rs

1//! Unification and canonicalization logic.
2
3use 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/// Whether to use subtyping or not when inspecting obligations.
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub(crate) enum UseSubtyping {
40    /// Do **not** use subtyping. [`InferenceTable::obligations_for_self_ty`] will only return
41    /// obligations where the self type is known to be equal to the provided vid.
42    No,
43
44    /// Use subtyping. [`InferenceTable::obligations_for_self_ty`] will return obligations
45    /// where the self type is related to the provided vid via subtyping.
46    ///
47    /// Using this requires extra care, as traits holding for a subtype or a supertype, does not
48    /// necessarily imply that they hold for the respective supertype or subtype.
49    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        // Using an intentionally low depth to minimize the chance of future
69        // breaking changes in case we adapt the approach later on. This also
70        // avoids any hangs for exponentially growing proof trees.
71        InspectConfig { max_depth: 5 }
72    }
73
74    fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'db>) {
75        // No need to walk into goal subtrees that certainly hold, since they
76        // wouldn't then be stalled on an infer var.
77        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 there's a unique way to prove a given goal, recurse into
93        // that candidate. This means that for `impl<F: FnOnce(u32)> Trait<F> for () {}`
94        // and a `(): Trait<?0>` goal we recurse into the impl and look at
95        // the nested `?0: FnOnce(u32)` goal.
96        if let Some(candidate) = inspect_goal.unique_applicable_candidate() {
97            candidate.visit_nested_no_probe(self)
98        }
99    }
100}
101
102/// Check if types unify.
103///
104/// Note that we consider placeholder types to unify with everything.
105/// This means that there may be some unresolved goals that actually set bounds for the placeholder
106/// type for the types to unify. For example `Option<T>` and `Option<U>` unify although there is
107/// unresolved goal `T = U`.
108pub 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
116/// Check if types unify eagerly making sure there are no unresolved goals.
117///
118/// This means that placeholder types are not considered to unify if there are any bounds set on
119/// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U`
120pub 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    /// Inside hir-ty you should use this for inference only, and always pass `owner`.
158    /// Outside it, always pass `owner = None`.
159    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        // NB: `T: Sized` implies that all subtypes and all supertypes of `T` are also sized,
200        // so it's valid to use subtyping here. (subtyping has to preserve layout and
201        // `T <: U => &T <: &U`, so subtyping can't change sizedness)
202        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    /// Create a `GenericArgs` full of infer vars for `def`.
356    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    /// Try to resolve `ty` to a structural type, normalizing aliases.
365    ///
366    /// In case there is still ambiguity, the returned type may be an inference
367    /// variable. This is different from `structurally_resolve_type` which errors
368    /// in this case.
369    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    /// checking later, during regionck, that `arg` is well-formed.
472    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    /// Registers obligations that all `args` are well-formed.
482    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    /// Whenever you lower a user-written type, you should call this.
496    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    /// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation,
501    /// while `process_user_written_ty()` should (but doesn't currently).
502    pub(crate) fn process_remote_user_written_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
503        let ty = self.insert_type_vars(ty);
504        // See https://github.com/rust-lang/rust/blob/cdb45c87e2cd43495379f7e867e3cc15dcee9f93/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs#L487-L495:
505        // Even though the new solver only lazily normalizes usually, here we eagerly normalize so that not everything needs
506        // to normalize before inspecting the `TyKind`.
507        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            // FIXME(next-solver): Handle `goals`.
609
610            *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            // Ignore diagnostics made from resolving diagnostics.
619            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                // Suppress duplicate diagnostics.
655                return;
656            }
657
658            if span.is_dummy() {
659                return;
660            }
661
662            // We have to be careful not to insert infer vars here, as we won't resolve this new diagnostic.
663            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                // For now, we don't error on regions.
748                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        /// Whether we should normalize, disabled when resolving predicates.
758        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                // FIXME: This should not use a dummy span.
781                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}