Skip to main content

rustc_trait_selection/solve/
delegate.rs

1use std::collections::hash_map::Entry;
2use std::fmt::Debug;
3use std::ops::{ControlFlow, Deref};
4
5use rustc_attr_ir::lang_items::LangItem;
6use rustc_data_structures::fx::{FxHashMap, FxHashSet};
7use rustc_hir::CRATE_HIR_ID;
8use rustc_hir::def::Namespace;
9use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE};
10use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
11use rustc_infer::infer::canonical::{
12    Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues,
13    Canonicalized, QueryRegionConstraint, instantiate_value,
14};
15use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt};
16use rustc_infer::traits::solve::{
17    ComputeGoalFastPathOutcome, FetchEligibleAssocItemResponse, Goal, SucceededInErased,
18};
19use rustc_lint_defs::builtin::RECURSION_DEPTH_EXCEEDING_LIMIT;
20use rustc_middle::traits::query::NoSolution;
21use rustc_middle::traits::solve::MaybeInfo;
22use rustc_middle::ty::print::{FmtPrinter, Print};
23use rustc_middle::ty::transmute::Answer;
24use rustc_middle::ty::{
25    self, CanonicalizerState, MayBeErased, Region, Ty, TyCtxt, TypeFlags, TypeFoldable,
26    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
27};
28use rustc_next_trait_solver::solve::{GoalStalledOn, GoalStalledOnOpaques, TyOrConstInferVar};
29use rustc_span::{DUMMY_SP, Span};
30use rustc_structures::Limit;
31use rustc_transmute::TransmuteTypeEnv;
32use thin_vec::{ThinVec, thin_vec};
33
34use super::inspect::InferCtxtProofTreeExt;
35use crate::solve::inspect::{self, InspectConfig, ProofTreeVisitor};
36use crate::traits::{EvaluateConstErr, ObligationCause, implicit_fast_path, specialization_graph};
37
38#[repr(transparent)]
39pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
40
41impl<'a, 'tcx> From<&'a InferCtxt<'tcx>> for &'a SolverDelegate<'tcx> {
42    fn from(infcx: &'a InferCtxt<'tcx>) -> Self {
43        // SAFETY: `repr(transparent)`
44        unsafe { std::mem::transmute(infcx) }
45    }
46}
47
48impl<'tcx> Deref for SolverDelegate<'tcx> {
49    type Target = InferCtxt<'tcx>;
50
51    fn deref(&self) -> &Self::Target {
52        &self.0
53    }
54}
55
56impl<'tcx> SolverDelegate<'tcx> {
57    fn known_no_opaque_types_in_storage(&self) -> bool {
58        self.inner.borrow_mut().opaque_types().is_empty()
59            // in erased mode, observing that opaques are empty aren't enough to give a result
60            // here, so let's try the slow path instead.
61            && !self.typing_mode_raw().is_erased_not_coherence()
62    }
63}
64
65/// Create a [`ComputeGoalFastPathOutcome`] signalling the goal is stalled
66/// on a list of [`ty::GenericArg`]
67fn goal_stalled_on_args<'tcx>(
68    stalled_vars: ThinVec<TyOrConstInferVar>,
69) -> ComputeGoalFastPathOutcome<'tcx> {
70    ComputeGoalFastPathOutcome::TriviallyStalled {
71        stalled_on: GoalStalledOn {
72            stalled_vars,
73            sub_roots: ThinVec::new(),
74            stalled_maybe_info: MaybeInfo::AMBIGUOUS,
75            opaques: GoalStalledOnOpaques::No,
76        },
77    }
78}
79
80/// Create a [`ComputeGoalFastPathOutcome`] signalling the  goal is stalled
81/// on a list of [`ty::GenericArg`] *or* the opaque type storage being nonempty.
82///
83fn goal_stalled_on_args_or_nonempty_opaques<'tcx>(
84    stalled_vars: ThinVec<TyOrConstInferVar>,
85) -> ComputeGoalFastPathOutcome<'tcx> {
86    ComputeGoalFastPathOutcome::TriviallyStalled {
87        stalled_on: GoalStalledOn {
88            stalled_vars,
89            sub_roots: ThinVec::new(),
90            stalled_maybe_info: MaybeInfo::AMBIGUOUS,
91            opaques: GoalStalledOnOpaques::Yes {
92                num_opaques_in_storage: 0,
93                // This function should only be called when not in erased mode,
94                // otherwise this is wrong. The `compute_goal_fast_path` does this
95                // through `known_no_opaque_types_in_storage`
96                previously_succeeded_in_erased: SucceededInErased::No,
97            },
98        },
99    }
100}
101
102struct CollectNonRegionInfer<'tcx> {
103    infers: ThinVec<ty::GenericArg<'tcx>>,
104    visited: FxHashSet<Ty<'tcx>>,
105}
106
107impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CollectNonRegionInfer<'tcx> {
108    fn visit_ty(&mut self, ty: Ty<'tcx>) {
109        if self.visited.contains(&ty) {
110            return;
111        }
112
113        match ty.kind() {
114            ty::Infer(_) => self.infers.push(ty.into()),
115            _ => ty.super_visit_with(self),
116        }
117
118        self.visited.insert(ty);
119    }
120
121    fn visit_const(&mut self, ct: ty::Const<'tcx>) {
122        match ct.kind() {
123            ty::ConstKind::Infer(_) => self.infers.push(ct.into()),
124            _ => ct.super_visit_with(self),
125        }
126    }
127}
128
129impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<'tcx> {
130    type Infcx = InferCtxt<'tcx>;
131    type Interner = TyCtxt<'tcx>;
132
133    fn cx(&self) -> TyCtxt<'tcx> {
134        self.0.tcx
135    }
136
137    fn build_with_canonical<V>(
138        interner: TyCtxt<'tcx>,
139        canonical: &CanonicalQueryInput<'tcx, V>,
140    ) -> (Self, V, CanonicalVarValues<'tcx>)
141    where
142        V: TypeFoldable<TyCtxt<'tcx>>,
143    {
144        let (infcx, value, vars) = interner
145            .infer_ctxt()
146            .with_next_trait_solver(true)
147            .build_with_canonical(DUMMY_SP, canonical);
148        (SolverDelegate(infcx), value, vars)
149    }
150
151    fn compute_goal_fast_path(
152        &self,
153        goal: Goal<'tcx, ty::Predicate<'tcx>>,
154        span: Span,
155    ) -> ComputeGoalFastPathOutcome<'tcx> {
156        use ComputeGoalFastPathOutcome as Outcome;
157
158        // FIXME(-Zassumptions-on-binders): actually handle fast path
159        if self.tcx.assumptions_on_binders() {
160            return Outcome::NoFastPath;
161        }
162
163        let pred = goal.predicate.kind();
164        match pred.skip_binder() {
165            ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
166                let trait_pred = pred.rebind(trait_pred);
167
168                let self_ty = self.shallow_resolve(trait_pred.self_ty().skip_binder());
169                if let Some(vid) = self_ty.ty_vid()
170                // We don't do this fast path when opaques are defined since we may
171                // eventually use opaques to incompletely guide inference via ty var
172                // self types.
173                // FIXME: Properly consider opaques here.
174                && self.known_no_opaque_types_in_storage()
175                {
176                    goal_stalled_on_args_or_nonempty_opaques({
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(TyOrConstInferVar::Ty(vid));
    vec
}thin_vec![TyOrConstInferVar::Ty(vid)])
177                } else if trait_pred.polarity() == ty::ClausePolarity::Positive {
178                    match self.0.tcx.as_lang_item(trait_pred.def_id()) {
179                        Some(LangItem::Sized) | Some(LangItem::MetaSized) => {
180                            let predicate = self.deeply_resolve_ignoring_regions(goal.predicate);
181                            if implicit_fast_path(self.tcx, predicate, goal.param_env) {
182                                Outcome::TriviallyHolds
183                            } else {
184                                Outcome::NoFastPath
185                            }
186                        }
187                        Some(LangItem::Copy | LangItem::Clone) => {
188                            let self_ty = self.deeply_resolve_ignoring_regions(
189                                trait_pred.self_ty().skip_binder(),
190                            );
191                            // Unlike `Sized` traits, which always prefer the built-in impl,
192                            // `Copy`/`Clone` may be shadowed by a param-env candidate which
193                            // could force a lifetime error or guide inference. While that's
194                            // not generally desirable, it is observable, so for now let's
195                            // ignore this fast path for types that have regions or infer.
196                            if !self_ty
197                                .has_type_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_INFER)
198                                && self_ty.is_trivially_pure_clone_copy()
199                            {
200                                Outcome::TriviallyHolds
201                            } else {
202                                Outcome::NoFastPath
203                            }
204                        }
205                        _ => Outcome::NoFastPath,
206                    }
207                } else {
208                    Outcome::NoFastPath
209                }
210            }
211            ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => {
212                Outcome::TriviallyHolds
213            }
214            ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => {
215                if outlives.has_escaping_bound_vars() {
216                    return Outcome::NoFastPath;
217                }
218
219                // We use `VisibleForLeakCheck::Yes` for `RegionOutlives` goals without
220                // the fast path. However, we always change region constraints from nested
221                // goals to `VisibleForLeakCheck::No`, so to be consistent with this
222                // behavior as we avoid the nested goal boundary, we have to manually
223                // set the flag.
224                self.0.sub_regions(
225                    SubregionOrigin::RelateRegionParamBound(span, None),
226                    outlives.1,
227                    outlives.0,
228                    ty::VisibleForLeakCheck::No,
229                );
230                Outcome::TriviallyHolds
231            }
232            ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
233                if outlives.has_escaping_bound_vars() {
234                    return Outcome::NoFastPath;
235                }
236
237                let ty = self.deeply_resolve_ignoring_regions(outlives.0);
238                if ty.has_non_rigid_aliases() {
239                    return Outcome::NoFastPath;
240                }
241
242                let mut infer_collector = CollectNonRegionInfer {
243                    infers: Default::default(),
244                    visited: Default::default(),
245                };
246                ty.visit_with(&mut infer_collector);
247                let infers = infer_collector.infers;
248                if !infers.is_empty() {
249                    return goal_stalled_on_args(
250                        infers
251                            .into_iter()
252                            .map(|i| {
253                                TyOrConstInferVar::maybe_from_generic_arg::<Self::Interner>(i)
254                                    .unwrap()
255                            })
256                            .collect(),
257                    );
258                }
259
260                self.0.register_type_outlives_constraint(
261                    outlives.0,
262                    outlives.1,
263                    &ObligationCause::dummy_with_span(span),
264                );
265
266                Outcome::TriviallyHolds
267            }
268            ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, .. })
269            | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
270                if a.has_escaping_bound_vars() || b.has_escaping_bound_vars() {
271                    return Outcome::NoFastPath;
272                }
273
274                match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) {
275                    (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
276                        self.sub_unify_ty_vids_raw(a_vid, b_vid);
277                        goal_stalled_on_args({
    let len = [(), ()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(TyOrConstInferVar::Ty(a_vid));
    vec.push(TyOrConstInferVar::Ty(b_vid));
    vec
}thin_vec![
278                            TyOrConstInferVar::Ty(a_vid),
279                            TyOrConstInferVar::Ty(b_vid),
280                        ])
281                    }
282                    _ => Outcome::NoFastPath,
283                }
284            }
285            ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) => {
286                if ct.has_escaping_bound_vars() {
287                    return Outcome::NoFastPath;
288                }
289
290                let arg = self.shallow_resolve_const(ct);
291                if let Some(vid) = arg.ct_vid() {
292                    goal_stalled_on_args({
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(TyOrConstInferVar::Const(vid));
    vec
}thin_vec![TyOrConstInferVar::Const(vid)])
293                } else {
294                    Outcome::NoFastPath
295                }
296            }
297            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
298                if arg.has_escaping_bound_vars() {
299                    return Outcome::NoFastPath;
300                }
301
302                let arg = self.shallow_resolve_term(arg);
303                if arg.is_trivially_wf(self.tcx) {
304                    Outcome::TriviallyHolds
305                } else if arg.is_infer() {
306                    goal_stalled_on_args({
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(TyOrConstInferVar::maybe_from_term::<TyCtxt<'tcx>>(arg).expect("its an infer var"));
    vec
}thin_vec![
307                        TyOrConstInferVar::maybe_from_term::<TyCtxt<'tcx>>(arg)
308                            .expect("its an infer var"),
309                    ])
310                } else {
311                    Outcome::NoFastPath
312                }
313            }
314            _ => Outcome::NoFastPath,
315        }
316    }
317
318    fn fresh_var_for_kind(
319        &self,
320        arg: ty::GenericArg<'tcx>,
321        span: Span,
322        universe: ty::UniverseIndex,
323    ) -> ty::GenericArg<'tcx> {
324        match arg.kind() {
325            ty::GenericArgKind::Lifetime(_) => {
326                self.next_region_var_in_universe(RegionVariableOrigin::Misc(span), universe).into()
327            }
328            ty::GenericArgKind::Type(_) => self.next_ty_var_in_universe(span, universe).into(),
329            ty::GenericArgKind::Const(_) => self.next_const_var_in_universe(span, universe).into(),
330        }
331    }
332
333    fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> {
334        self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
335    }
336
337    fn evaluate_const<E: Debug>(
338        &self,
339        param_env: ty::ParamEnv<'tcx>,
340        alias_const: ty::AliasConst<'tcx>,
341        normalize_ty: impl FnOnce(ty::Unnormalized<'tcx, Ty<'tcx>>) -> Result<Ty<'tcx>, E>,
342    ) -> Result<Option<ty::Const<'tcx>>, E> {
343        let ct = ty::Const::new_alias(self.tcx, ty::IsRigid::No, alias_const);
344
345        match crate::traits::try_evaluate_const(&self.0, ct, param_env, normalize_ty) {
346            Ok(ct) => Ok(Some(ct)),
347            Err(EvaluateConstErr::EvaluationFailure(e)) => {
348                Ok(Some(ty::Const::new_error(self.tcx, e)))
349            }
350            Err(
351                EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers,
352            ) => Ok(None),
353            Err(EvaluateConstErr::FailedNormalization(e)) => Err(e),
354        }
355    }
356
357    fn well_formed_goals(
358        &self,
359        param_env: ty::ParamEnv<'tcx>,
360        term: ty::Term<'tcx>,
361    ) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> {
362        crate::traits::wf::unnormalized_obligations(
363            &self.0,
364            param_env,
365            term,
366            DUMMY_SP,
367            CRATE_DEF_ID,
368        )
369        .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect())
370    }
371
372    fn make_deduplicated_region_constraints(
373        &self,
374    ) -> Vec<(ty::RegionConstraint<'tcx>, ty::VisibleForLeakCheck)> {
375        // Cannot use `take_registered_region_obligations` as we may compute the response
376        // inside of a `probe` whenever we have multiple choices inside of the solver.
377        let region_obligations = self.0.inner.borrow().region_obligations().to_owned();
378        let region_assumptions = self.0.inner.borrow().region_assumptions().to_owned();
379        let region_constraints = self.0.with_region_constraints(|region_constraints| {
380            make_query_region_constraints(
381                region_obligations,
382                region_constraints,
383                region_assumptions,
384            )
385        });
386
387        let mut seen = FxHashMap::default();
388        let mut constraints = ::alloc::vec::Vec::new()vec![];
389        for QueryRegionConstraint { constraint: outlives, visible_for_leak_check: vis, .. } in
390            region_constraints.constraints
391        {
392            match seen.entry(outlives) {
393                Entry::Occupied(occupied) => {
394                    let idx = occupied.get();
395                    let (_, prev_vis): &mut (_, ty::VisibleForLeakCheck) =
396                        constraints.get_mut(*idx).unwrap();
397                    *prev_vis = (*prev_vis).or(vis);
398                }
399                Entry::Vacant(vacant) => {
400                    vacant.insert(constraints.len());
401                    constraints.push((outlives, vis));
402                }
403            }
404        }
405        constraints
406    }
407
408    fn instantiate_value<V>(&self, value: Canonicalized<V>, values: CanonicalVarValues<'tcx>) -> V
409    where
410        V: TypeFoldable<TyCtxt<'tcx>>,
411    {
412        instantiate_value(self.tcx, &values, value.into_uninstantiated())
413    }
414
415    fn instantiate_canonical<V>(
416        &self,
417        canonical: Canonical<'tcx, V>,
418        values: CanonicalVarValues<'tcx>,
419    ) -> V
420    where
421        V: TypeFoldable<TyCtxt<'tcx>>,
422    {
423        canonical.instantiate(self.tcx, &values)
424    }
425
426    fn instantiate_canonical_var(
427        &self,
428        kind: CanonicalVarKind<'tcx>,
429        span: Span,
430        prev_var_values: &[ty::GenericArg<'tcx>],
431        universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
432    ) -> ty::GenericArg<'tcx> {
433        self.0.instantiate_canonical_var(span, kind, prev_var_values, universe_map)
434    }
435
436    fn add_item_bounds_for_hidden_type(
437        &self,
438        def_id: DefId,
439        args: ty::GenericArgs<'tcx>,
440        param_env: ty::ParamEnv<'tcx>,
441        hidden_ty: Ty<'tcx>,
442        goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
443    ) {
444        self.0.add_item_bounds_for_hidden_type(def_id, args, param_env, hidden_ty, goals);
445    }
446
447    fn fetch_eligible_assoc_item(
448        &self,
449        goal_trait_ref: ty::TraitRef<'tcx>,
450        trait_assoc_def_id: DefId,
451        impl_def_id: DefId,
452    ) -> FetchEligibleAssocItemResponse<'tcx> {
453        let node_item =
454            match specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id) {
455                Ok(i) => i,
456                Err(guar) => return FetchEligibleAssocItemResponse::Err(guar),
457            };
458
459        let typing_mode = self.typing_mode_raw();
460
461        let eligible = if node_item.is_final() {
462            // Non-specializable items are always projectable.
463            true
464        } else {
465            // Only reveal a specializable default if we're past type-checking
466            // and the obligation is monomorphic, otherwise passes such as
467            // transmute checking and polymorphic MIR optimizations could
468            // get a result which isn't correct for all monomorphizations.
469            match typing_mode {
470                TypingMode::Coherence
471                | TypingMode::Typeck { .. }
472                | TypingMode::PostTypeckThroughBorrowck { .. }
473                | TypingMode::Reflection
474                | TypingMode::PostBorrowck { .. } => false,
475                TypingMode::PostAnalysis | TypingMode::Codegen => {
476                    let poly_trait_ref = self.deeply_resolve_ignoring_regions(goal_trait_ref);
477                    !poly_trait_ref.still_further_specializable()
478                }
479                TypingMode::ErasedNotCoherence(MayBeErased) => {
480                    return FetchEligibleAssocItemResponse::NotFoundBecauseErased;
481                }
482            }
483        };
484
485        // FIXME: Check for defaultness here may cause diagnostics problems.
486        if eligible {
487            FetchEligibleAssocItemResponse::Found(node_item.item.def_id)
488        } else {
489            // We know it's not erased since then we'd have returned in the match above,
490            // or node_item.final() was true and eligible is always true.
491            FetchEligibleAssocItemResponse::NotFound(typing_mode.assert_not_erased())
492        }
493    }
494
495    // FIXME: This actually should destructure the `Result` we get from transmutability and
496    // register candidates. We probably need to register >1 since we may have an OR of ANDs.
497    fn is_transmutable(
498        &self,
499        src: Ty<'tcx>,
500        dst: Ty<'tcx>,
501        assume: ty::Const<'tcx>,
502    ) -> Result<Answer<Region<'tcx>, Ty<'tcx>>, NoSolution> {
503        rustc_transmute::Assume::from_const(self.tcx, assume)
504            .map(|assume| TransmuteTypeEnv::new(self.0.tcx).is_transmutable(src, dst, assume))
505            .ok_or(NoSolution)
506    }
507
508    fn obtain_canonicalizer_state(&self) -> Box<CanonicalizerState<Self::Interner>> {
509        // Get the top state, or create a new one if none are available.
510        self.cx()
511            .caches
512            .canonicalizer_states
513            .lock()
514            .pop()
515            .unwrap_or_else(|| Box::new(CanonicalizerState::default()))
516    }
517
518    fn release_canonicalizer_state(&self, mut state: Box<CanonicalizerState<Self::Interner>>) {
519        // Clear (don't deallocate) the state for later reuse.
520        state.clear();
521        self.cx().caches.canonicalizer_states.lock().push(state);
522    }
523
524    fn emit_next_solver_overflow_fcw(&self, goal: Goal<'tcx, ty::Predicate<'tcx>>, span: Span) {
525        let tcx = self.tcx;
526        tcx.emit_node_span_lint(
527            RECURSION_DEPTH_EXCEEDING_LIMIT,
528            CRATE_HIR_ID,
529            span,
530            rustc_errors::DiagDecorator(|diag| {
531                // We do this in the decorator as that avoids the work
532                // if we don't actually emit the lint.
533                let goal = self.deeply_resolve_ignoring_regions(goal);
534                let recursion_limit = if let Some(specified_limit) = tcx.next_solver_overflow_fcw_limit()
535                {
536                    // Double default limit allows us to see the whole chain.
537                    usize::min(specified_limit, tcx.recursion_limit().0 * 2)
538                } else {
539                    usize::min(16, tcx.recursion_limit().0)
540                };
541                let mut visitor = OverflowedGoalChain {
542                    span,
543                    predicates: ::alloc::vec::Vec::new()vec![],
544                    recursion_limit,
545                };
546
547                let _ = self.with_disabled_next_solver_overflow_fcw(|| {
548                    self.visit_proof_tree(goal, &mut visitor)
549                });
550
551                // FIXME: share this with overflow error in fulfillment instead of duplicating.
552                let pred_str = |pred: ty::Predicate<'tcx>| {
553                    let s = pred.to_string();
554                    if s.len() > 80 {
555                        let mut p: FmtPrinter<'_, '_> =
556                            FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, Limit(10));
557                        pred.print(&mut p).unwrap();
558                        p.into_buffer()
559                    } else {
560                        s
561                    }
562                };
563                diag.primary_message(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("overflow evaluating the requirement `{0}`",
                pred_str(goal.predicate)))
    })format!(
564                    "overflow evaluating the requirement `{}`",
565                    pred_str(goal.predicate),
566                ));
567                for p in visitor.predicates.into_iter().skip(1) {
568                    diag.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("which requires `{0}`",
                pred_str(p)))
    })format!("which requires `{}`", pred_str(p)));
569                }
570                diag.note("and so on...");
571                diag.help(
572                    "consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved",
573                );
574                diag.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("or consider increasing the recursion limit by adding a `#![recursion_limit = \"{0}\"]` attribute to your crate (`{1}`)",
                tcx.recursion_limit() * 2, tcx.crate_name(LOCAL_CRATE)))
    })format!(
575                    "or consider increasing the recursion limit by adding a \
576                     `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
577                    tcx.recursion_limit() * 2,
578                    tcx.crate_name(LOCAL_CRATE),
579                ));
580                diag.note("this lint is attached to the whole crate and can't be disabled on a per-function basis");
581            }),
582        )
583    }
584}
585
586struct OverflowedGoalChain<'tcx> {
587    span: Span,
588    predicates: Vec<ty::Predicate<'tcx>>,
589    recursion_limit: usize,
590}
591
592impl<'tcx> ProofTreeVisitor<'tcx> for OverflowedGoalChain<'tcx> {
593    type Result = ControlFlow<()>;
594
595    fn span(&self) -> Span {
596        self.span
597    }
598
599    fn config(&self) -> InspectConfig {
600        InspectConfig { max_depth: self.recursion_limit }
601    }
602
603    fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
604        self.predicates.push(goal.goal().predicate);
605        if let Some(cand) = goal.unique_applicable_candidate() {
606            goal.infcx().probe(|_| {
607                if let Some(nested_goal_with_largest_required_depth) = cand
608                    .instantiate_nested_goals(self.span)
609                    .into_iter()
610                    .max_by_key(|g| g.required_depth())
611                {
612                    nested_goal_with_largest_required_depth.visit_with(self)
613                } else {
614                    ControlFlow::Continue(())
615                }
616            })?;
617        }
618        ControlFlow::Continue(())
619    }
620
621    fn on_recursion_limit(&mut self) -> Self::Result {
622        ControlFlow::Break(())
623    }
624}