Skip to main content

rustc_trait_selection/solve/fulfill/
derive_errors.rs

1use std::ops::ControlFlow;
2
3use rustc_hir::LangItem;
4use rustc_infer::infer::InferCtxt;
5use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
6use rustc_infer::traits::{
7    self, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
8    PredicateObligation, SelectionError,
9};
10use rustc_middle::traits::query::NoSolution;
11use rustc_middle::ty::error::{ExpectedFound, TypeError};
12use rustc_middle::ty::{self, Ty, TyCtxt};
13use rustc_middle::{bug, span_bug};
14use rustc_next_trait_solver::solve::{GoalEvaluation, MaybeInfo, SolverDelegateEvalExt as _};
15use tracing::{instrument, trace};
16
17use crate::solve::delegate::SolverDelegate;
18use crate::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor};
19use crate::solve::{Certainty, deeply_normalize_for_diagnostics};
20use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
21
22pub(super) fn fulfillment_error_for_no_solution<'tcx>(
23    infcx: &InferCtxt<'tcx>,
24    root_obligation: PredicateObligation<'tcx>,
25) -> FulfillmentError<'tcx> {
26    let obligation = find_best_leaf_obligation(infcx, &root_obligation, false);
27
28    let code = match obligation.predicate.kind().skip_binder() {
29        ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
30            FulfillmentErrorCode::Project(
31                // FIXME: This could be a `Sorts` if the term is a type
32                MismatchedProjectionTypes { err: TypeError::Mismatch },
33            )
34        }
35        ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, expected_ty)) => {
36            let ct_ty = match ct.kind() {
37                ty::ConstKind::Unevaluated(uv) => {
38                    infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args).skip_norm_wip()
39                }
40                ty::ConstKind::Param(param_ct) => {
41                    param_ct.find_const_ty_from_env(obligation.param_env)
42                }
43                ty::ConstKind::Value(cv) => cv.ty,
44                kind => ::rustc_middle::util::bug::span_bug_fmt(obligation.cause.span,
    format_args!("ConstArgHasWrongType failed but we don\'t know how to compute type for {0:?}",
        kind))span_bug!(
45                    obligation.cause.span,
46                    "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}"
47                ),
48            };
49            FulfillmentErrorCode::Select(SelectionError::ConstArgHasWrongType {
50                ct,
51                ct_ty,
52                expected_ty,
53            })
54        }
55        ty::PredicateKind::NormalizesTo(..) => {
56            FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
57        }
58        ty::PredicateKind::AliasRelate(_, _, _) => {
59            FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
60        }
61        ty::PredicateKind::Subtype(pred) => {
62            let (a, b) = infcx.enter_forall_and_leak_universe(
63                obligation.predicate.kind().rebind((pred.a, pred.b)),
64            );
65            let expected_found = ExpectedFound::new(a, b);
66            FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
67        }
68        ty::PredicateKind::Coerce(pred) => {
69            let (a, b) = infcx.enter_forall_and_leak_universe(
70                obligation.predicate.kind().rebind((pred.a, pred.b)),
71            );
72            let expected_found = ExpectedFound::new(b, a);
73            FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
74        }
75        ty::PredicateKind::Clause(_)
76        | ty::PredicateKind::DynCompatible(_)
77        | ty::PredicateKind::Ambiguous => {
78            FulfillmentErrorCode::Select(SelectionError::Unimplemented)
79        }
80        ty::PredicateKind::ConstEquate(..) => {
81            ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected goal: {0:?}",
        obligation))bug!("unexpected goal: {obligation:?}")
82        }
83    };
84
85    FulfillmentError { obligation, code, root_obligation }
86}
87
88pub(super) fn fulfillment_error_for_stalled<'tcx>(
89    infcx: &InferCtxt<'tcx>,
90    root_obligation: PredicateObligation<'tcx>,
91) -> FulfillmentError<'tcx> {
92    let (code, refine_obligation) = infcx.probe(|_| {
93        match <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
94            root_obligation.as_goal(),
95            root_obligation.cause.span,
96            None,
97        ) {
98            Ok(GoalEvaluation {
99                certainty:
100                    Certainty::Maybe(MaybeInfo {
101                        cause: MaybeCause::Ambiguity,
102                        opaque_types_jank: _,
103                        stalled_on_coroutines: _,
104                    }),
105                ..
106            }) => (FulfillmentErrorCode::Ambiguity { overflow: None }, true),
107            Ok(GoalEvaluation {
108                certainty:
109                    Certainty::Maybe(MaybeInfo {
110                        cause:
111                            MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: _ },
112                        opaque_types_jank: _,
113                        stalled_on_coroutines: _,
114                    }),
115                ..
116            }) => (
117                FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
118                // Don't look into overflows because we treat overflows weirdly anyways.
119                // We discard the inference constraints from overflowing goals, so
120                // recomputing the goal again during `find_best_leaf_obligation` may apply
121                // inference guidance that makes other goals go from ambig -> pass, for example.
122                //
123                // FIXME: We should probably just look into overflows here.
124                false,
125            ),
126            Ok(GoalEvaluation { certainty: Certainty::Yes, .. }) => {
127                ::rustc_middle::util::bug::span_bug_fmt(root_obligation.cause.span,
    format_args!("did not expect successful goal when collecting ambiguity errors for `{0:?}`",
        infcx.resolve_vars_if_possible(root_obligation.predicate)))span_bug!(
128                    root_obligation.cause.span,
129                    "did not expect successful goal when collecting ambiguity errors for `{:?}`",
130                    infcx.resolve_vars_if_possible(root_obligation.predicate),
131                )
132            }
133            Err(_) => {
134                ::rustc_middle::util::bug::span_bug_fmt(root_obligation.cause.span,
    format_args!("did not expect selection error when collecting ambiguity errors for `{0:?}`",
        infcx.resolve_vars_if_possible(root_obligation.predicate)))span_bug!(
135                    root_obligation.cause.span,
136                    "did not expect selection error when collecting ambiguity errors for `{:?}`",
137                    infcx.resolve_vars_if_possible(root_obligation.predicate),
138                )
139            }
140        }
141    });
142
143    FulfillmentError {
144        obligation: if refine_obligation {
145            find_best_leaf_obligation(infcx, &root_obligation, true)
146        } else {
147            root_obligation.clone()
148        },
149        code,
150        root_obligation,
151    }
152}
153
154pub(super) fn fulfillment_error_for_overflow<'tcx>(
155    infcx: &InferCtxt<'tcx>,
156    root_obligation: PredicateObligation<'tcx>,
157) -> FulfillmentError<'tcx> {
158    FulfillmentError {
159        obligation: find_best_leaf_obligation(infcx, &root_obligation, true),
160        code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
161        root_obligation,
162    }
163}
164
165x;#[instrument(level = "debug", skip(infcx), ret)]
166fn find_best_leaf_obligation<'tcx>(
167    infcx: &InferCtxt<'tcx>,
168    obligation: &PredicateObligation<'tcx>,
169    consider_ambiguities: bool,
170) -> PredicateObligation<'tcx> {
171    let obligation = infcx.resolve_vars_if_possible(obligation.clone());
172    // FIXME: we use a probe here as the `BestObligation` visitor does not
173    // check whether it uses candidates which get shadowed by where-bounds.
174    //
175    // We should probably fix the visitor to not do so instead, as this also
176    // means the leaf obligation may be incorrect.
177    let obligation = infcx
178        .fudge_inference_if_ok(|| {
179            infcx
180                .visit_proof_tree(
181                    obligation.as_goal(),
182                    &mut BestObligation { obligation: obligation.clone(), consider_ambiguities },
183                )
184                .break_value()
185                .ok_or(())
186                // walk around the fact that the cause in `Obligation` is ignored by folders so that
187                // we can properly fudge the infer vars in cause code.
188                .map(|o| (o.cause.clone(), o))
189        })
190        .map(|(cause, o)| PredicateObligation { cause, ..o })
191        .unwrap_or(obligation);
192    deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation)
193}
194
195struct BestObligation<'tcx> {
196    obligation: PredicateObligation<'tcx>,
197    consider_ambiguities: bool,
198}
199
200impl<'tcx> BestObligation<'tcx> {
201    fn with_derived_obligation(
202        &mut self,
203        derived_obligation: PredicateObligation<'tcx>,
204        and_then: impl FnOnce(&mut Self) -> <Self as ProofTreeVisitor<'tcx>>::Result,
205    ) -> <Self as ProofTreeVisitor<'tcx>>::Result {
206        let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation);
207        let res = and_then(self);
208        self.obligation = old_obligation;
209        res
210    }
211
212    /// Filter out the candidates that aren't interesting to visit for the
213    /// purposes of reporting errors. For ambiguities, we only consider
214    /// candidates that may hold. For errors, we only consider candidates that
215    /// *don't* hold and which have impl-where clauses that also don't hold.
216    fn non_trivial_candidates<'a>(
217        &self,
218        goal: &'a inspect::InspectGoal<'a, 'tcx>,
219    ) -> Vec<inspect::InspectCandidate<'a, 'tcx>> {
220        let mut candidates = goal.candidates();
221        match self.consider_ambiguities {
222            true => {
223                // If we have an ambiguous obligation, we must consider *all* candidates
224                // that hold, or else we may guide inference causing other goals to go
225                // from ambig -> pass/fail.
226                candidates.retain(|candidate| candidate.result().is_ok());
227            }
228            false => {
229                // We always handle rigid alias candidates separately as we may not add them for
230                // aliases whose trait bound doesn't hold.
231                candidates.retain(|c| !#[allow(non_exhaustive_omitted_patterns)] match c.kind() {
    inspect::ProbeKind::RigidAlias { .. } => true,
    _ => false,
}matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. }));
232                // If we have >1 candidate, one may still be due to "boring" reasons, like
233                // an alias-relate that failed to hold when deeply evaluated. We really
234                // don't care about reasons like this.
235                if candidates.len() > 1 {
236                    candidates.retain(|candidate| {
237                        goal.infcx().probe(|_| {
238                            candidate.instantiate_nested_goals(self.span()).iter().any(
239                                |nested_goal| {
240                                    #[allow(non_exhaustive_omitted_patterns)] match nested_goal.source() {
    GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition |
        GoalSource::AliasWellFormed => true,
    _ => false,
}matches!(
241                                        nested_goal.source(),
242                                        GoalSource::ImplWhereBound
243                                            | GoalSource::AliasBoundConstCondition
244                                            | GoalSource::AliasWellFormed
245                                    ) && nested_goal.result().is_err()
246                                },
247                            )
248                        })
249                    });
250                }
251            }
252        }
253
254        candidates
255    }
256
257    /// HACK: We walk the nested obligations for a well-formed arg manually,
258    /// since there's nontrivial logic in `wf.rs` to set up an obligation cause.
259    /// Ideally we'd be able to track this better.
260    fn visit_well_formed_goal(
261        &mut self,
262        candidate: &inspect::InspectCandidate<'_, 'tcx>,
263        term: ty::Term<'tcx>,
264    ) -> ControlFlow<PredicateObligation<'tcx>> {
265        let infcx = candidate.goal().infcx();
266        let param_env = candidate.goal().goal().param_env;
267        let body_id = self.obligation.cause.body_id;
268
269        for obligation in wf::unnormalized_obligations(infcx, param_env, term, self.span(), body_id)
270            .into_iter()
271            .flatten()
272        {
273            let nested_goal = candidate.instantiate_proof_tree_for_nested_goal(
274                GoalSource::Misc,
275                obligation.as_goal(),
276                self.span(),
277            );
278            // Skip nested goals that aren't the *reason* for our goal's failure.
279            match (self.consider_ambiguities, nested_goal.result()) {
280                (
281                    true,
282                    Ok(Certainty::Maybe(MaybeInfo {
283                        cause: MaybeCause::Ambiguity,
284                        opaque_types_jank: _,
285                        stalled_on_coroutines: _,
286                    })),
287                )
288                | (false, Err(_)) => {}
289                _ => continue,
290            }
291
292            self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
293        }
294
295        ControlFlow::Break(self.obligation.clone())
296    }
297
298    /// If a normalization of an associated item or a trait goal fails without trying any
299    /// candidates it's likely that normalizing its self type failed. We manually detect
300    /// such cases here.
301    fn detect_error_in_self_ty_normalization(
302        &mut self,
303        goal: &inspect::InspectGoal<'_, 'tcx>,
304        self_ty: Ty<'tcx>,
305    ) -> ControlFlow<PredicateObligation<'tcx>> {
306        if !!self.consider_ambiguities {
    ::core::panicking::panic("assertion failed: !self.consider_ambiguities")
};assert!(!self.consider_ambiguities);
307        let tcx = goal.infcx().tcx;
308        if let ty::Alias(..) = self_ty.kind() {
309            let infer_term = goal.infcx().next_ty_var(self.obligation.cause.span);
310            let pred = ty::PredicateKind::AliasRelate(
311                self_ty.into(),
312                infer_term.into(),
313                ty::AliasRelationDirection::Equate,
314            );
315            let obligation =
316                Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, pred);
317            self.with_derived_obligation(obligation, |this| {
318                goal.infcx().visit_proof_tree_at_depth(
319                    goal.goal().with(tcx, pred),
320                    goal.depth() + 1,
321                    this,
322                )
323            })
324        } else {
325            ControlFlow::Continue(())
326        }
327    }
328
329    /// When a higher-ranked projection goal fails, check that the corresponding
330    /// higher-ranked trait goal holds or not. This is because the process of
331    /// instantiating and then re-canonicalizing the binder of the projection goal
332    /// forces us to be unable to see that the leak check failed in the nested
333    /// `NormalizesTo` goal, so we don't fall back to the rigid projection check
334    /// that should catch when a projection goal fails due to an unsatisfied trait
335    /// goal.
336    fn detect_trait_error_in_higher_ranked_projection(
337        &mut self,
338        goal: &inspect::InspectGoal<'_, 'tcx>,
339    ) -> ControlFlow<PredicateObligation<'tcx>> {
340        let tcx = goal.infcx().tcx;
341        if let Some(projection_clause) = goal.goal().predicate.as_projection_clause()
342            && !projection_clause.bound_vars().is_empty()
343        {
344            let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
345            let obligation = Obligation::new(
346                tcx,
347                self.obligation.cause.clone(),
348                goal.goal().param_env,
349                deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred),
350            );
351            self.with_derived_obligation(obligation, |this| {
352                goal.infcx().visit_proof_tree_at_depth(
353                    goal.goal().with(tcx, pred),
354                    goal.depth() + 1,
355                    this,
356                )
357            })
358        } else {
359            ControlFlow::Continue(())
360        }
361    }
362
363    /// It is likely that `NormalizesTo` failed without any applicable candidates
364    /// because the alias is not well-formed.
365    ///
366    /// As we only enter `RigidAlias` candidates if the trait bound of the associated type
367    /// holds, we discard these candidates in `non_trivial_candidates` and always manually
368    /// check this here.
369    fn detect_non_well_formed_assoc_item(
370        &mut self,
371        goal: &inspect::InspectGoal<'_, 'tcx>,
372        alias: ty::AliasTerm<'tcx>,
373    ) -> ControlFlow<PredicateObligation<'tcx>> {
374        let tcx = goal.infcx().tcx;
375        let obligation = Obligation::new(
376            tcx,
377            self.obligation.cause.clone(),
378            goal.goal().param_env,
379            alias.trait_ref(tcx),
380        );
381        self.with_derived_obligation(obligation, |this| {
382            goal.infcx().visit_proof_tree_at_depth(
383                goal.goal().with(tcx, alias.trait_ref(tcx)),
384                goal.depth() + 1,
385                this,
386            )
387        })
388    }
389
390    /// If we have no candidates, then it's likely that there is a
391    /// non-well-formed alias in the goal.
392    fn detect_error_from_empty_candidates(
393        &mut self,
394        goal: &inspect::InspectGoal<'_, 'tcx>,
395    ) -> ControlFlow<PredicateObligation<'tcx>> {
396        let tcx = goal.infcx().tcx;
397        let pred_kind = goal.goal().predicate.kind();
398
399        match pred_kind.no_bound_vars() {
400            Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) => {
401                self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?;
402            }
403            Some(ty::PredicateKind::NormalizesTo(pred))
404                if let ty::AliasTermKind::ProjectionTy { .. }
405                | ty::AliasTermKind::ProjectionConst { .. } = pred.alias.kind(tcx) =>
406            {
407                self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?;
408                self.detect_non_well_formed_assoc_item(goal, pred.alias)?;
409            }
410            Some(_) | None => {}
411        }
412
413        ControlFlow::Break(self.obligation.clone())
414    }
415}
416
417impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
418    type Result = ControlFlow<PredicateObligation<'tcx>>;
419
420    fn span(&self) -> rustc_span::Span {
421        self.obligation.cause.span
422    }
423
424    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("visit_goal",
                                    "rustc_trait_selection::solve::fulfill::derive_errors",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs"),
                                    ::tracing_core::__macro_support::Option::Some(424u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::fulfill::derive_errors"),
                                    ::tracing_core::field::FieldSet::new(&["goal"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&debug(&goal.goal())
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: Self::Result = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let tcx = goal.infcx().tcx;
            match (self.consider_ambiguities, goal.result()) {
                (true,
                    Ok(Certainty::Maybe(MaybeInfo {
                    cause: MaybeCause::Ambiguity,
                    opaque_types_jank: _,
                    stalled_on_coroutines: _ }))) | (false, Err(_)) => {}
                _ => return ControlFlow::Continue(()),
            }
            let pred = goal.goal().predicate;
            let candidates = self.non_trivial_candidates(goal);
            let candidate =
                match candidates.as_slice() {
                    [candidate] => candidate,
                    [] => return self.detect_error_from_empty_candidates(goal),
                    _ => return ControlFlow::Break(self.obligation.clone()),
                };
            if let inspect::ProbeKind::TraitCandidate {
                        source: CandidateSource::Impl(impl_def_id), result: _ } =
                        candidate.kind() && tcx.do_not_recommend_impl(impl_def_id) {
                {
                    use ::tracing::__macro_support::Callsite as _;
                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                        {
                            static META: ::tracing::Metadata<'static> =
                                {
                                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs:457",
                                        "rustc_trait_selection::solve::fulfill::derive_errors",
                                        ::tracing::Level::TRACE,
                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs"),
                                        ::tracing_core::__macro_support::Option::Some(457u32),
                                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::fulfill::derive_errors"),
                                        ::tracing_core::field::FieldSet::new(&["message"],
                                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                        ::tracing::metadata::Kind::EVENT)
                                };
                            ::tracing::callsite::DefaultCallsite::new(&META)
                        };
                    let enabled =
                        ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            {
                                let interest = __CALLSITE.interest();
                                !interest.is_never() &&
                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                        interest)
                            };
                    if enabled {
                        (|value_set: ::tracing::field::ValueSet|
                                    {
                                        let meta = __CALLSITE.metadata();
                                        ::tracing::Event::dispatch(meta, &value_set);
                                        ;
                                    })({
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&format_args!("#[diagnostic::do_not_recommend] -> exit")
                                                            as &dyn Value))])
                            });
                    } else { ; }
                };
                return ControlFlow::Break(self.obligation.clone());
            }
            let child_mode =
                match pred.kind().skip_binder() {
                    ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))
                        => {
                        ChildMode::Trait(pred.kind().rebind(trait_pred))
                    }
                    ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(host_pred))
                        => {
                        ChildMode::Host(pred.kind().rebind(host_pred))
                    }
                    ty::PredicateKind::NormalizesTo(normalizes_to) if
                        #[allow(non_exhaustive_omitted_patterns)] match normalizes_to.alias.kind(tcx)
                            {
                            ty::AliasTermKind::ProjectionTy { .. } |
                                ty::AliasTermKind::ProjectionConst { .. } => true,
                            _ => false,
                        } => {
                        ChildMode::Trait(pred.kind().rebind(ty::TraitPredicate {
                                    trait_ref: normalizes_to.alias.trait_ref(tcx),
                                    polarity: ty::PredicatePolarity::Positive,
                                }))
                    }
                    ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term))
                        => {
                        return self.visit_well_formed_goal(candidate, term);
                    }
                    _ => ChildMode::PassThrough,
                };
            let nested_goals =
                candidate.instantiate_nested_goals(self.span());
            for nested_goal in &nested_goals {
                if let Some(poly_trait_pred) =
                                nested_goal.goal().predicate.as_trait_clause() &&
                            tcx.is_lang_item(poly_trait_pred.def_id(),
                                LangItem::FnPtrTrait) &&
                        let Err(NoSolution) = nested_goal.result() {
                    return ControlFlow::Break(self.obligation.clone());
                }
            }
            let mut impl_where_bound_count = 0;
            for nested_goal in nested_goals {
                {
                    use ::tracing::__macro_support::Callsite as _;
                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                        {
                            static META: ::tracing::Metadata<'static> =
                                {
                                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs:508",
                                        "rustc_trait_selection::solve::fulfill::derive_errors",
                                        ::tracing::Level::TRACE,
                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs"),
                                        ::tracing_core::__macro_support::Option::Some(508u32),
                                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::fulfill::derive_errors"),
                                        ::tracing_core::field::FieldSet::new(&["nested_goal"],
                                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                        ::tracing::metadata::Kind::EVENT)
                                };
                            ::tracing::callsite::DefaultCallsite::new(&META)
                        };
                    let enabled =
                        ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            {
                                let interest = __CALLSITE.interest();
                                !interest.is_never() &&
                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                        interest)
                            };
                    if enabled {
                        (|value_set: ::tracing::field::ValueSet|
                                    {
                                        let meta = __CALLSITE.metadata();
                                        ::tracing::Event::dispatch(meta, &value_set);
                                        ;
                                    })({
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&debug(&(nested_goal.goal(),
                                                                            nested_goal.source(), nested_goal.result())) as
                                                            &dyn Value))])
                            });
                    } else { ; }
                };
                let nested_pred = nested_goal.goal().predicate;
                let make_obligation =
                    |cause|
                        Obligation {
                            cause,
                            param_env: nested_goal.goal().param_env,
                            predicate: nested_pred,
                            recursion_depth: self.obligation.recursion_depth + 1,
                        };
                let obligation;
                match (child_mode, nested_goal.source()) {
                    (ChildMode::Trait(_) | ChildMode::Host(_),
                        GoalSource::Misc | GoalSource::TypeRelating |
                        GoalSource::NormalizeGoal(_)) => {
                        continue;
                    }
                    (ChildMode::Trait(parent_trait_pred),
                        GoalSource::ImplWhereBound) => {
                        obligation =
                            make_obligation(derive_cause(tcx, candidate.kind(),
                                    self.obligation.cause.clone(), impl_where_bound_count,
                                    parent_trait_pred));
                        impl_where_bound_count += 1;
                    }
                    (ChildMode::Host(parent_host_pred),
                        GoalSource::ImplWhereBound |
                        GoalSource::AliasBoundConstCondition) => {
                        obligation =
                            make_obligation(derive_host_cause(tcx, candidate.kind(),
                                    self.obligation.cause.clone(), impl_where_bound_count,
                                    parent_host_pred));
                        impl_where_bound_count += 1;
                    }
                    (ChildMode::PassThrough, _) |
                        (_,
                        GoalSource::AliasWellFormed |
                        GoalSource::AliasBoundConstCondition) => {
                        obligation = make_obligation(self.obligation.cause.clone());
                    }
                }
                self.with_derived_obligation(obligation,
                        |this| nested_goal.visit_with(this))?;
            }
            if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) =
                    pred.kind().no_bound_vars() {
                goal.infcx().visit_proof_tree_at_depth(goal.goal().with(tcx,
                            ty::ClauseKind::WellFormed(lhs.into())), goal.depth() + 1,
                        self)?;
                goal.infcx().visit_proof_tree_at_depth(goal.goal().with(tcx,
                            ty::ClauseKind::WellFormed(rhs.into())), goal.depth() + 1,
                        self)?;
            }
            self.detect_trait_error_in_higher_ranked_projection(goal)?;
            ControlFlow::Break(self.obligation.clone())
        }
    }
}#[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))]
425    fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
426        let tcx = goal.infcx().tcx;
427        // Skip goals that aren't the *reason* for our goal's failure.
428        match (self.consider_ambiguities, goal.result()) {
429            (
430                true,
431                Ok(Certainty::Maybe(MaybeInfo {
432                    cause: MaybeCause::Ambiguity,
433                    opaque_types_jank: _,
434                    stalled_on_coroutines: _,
435                })),
436            )
437            | (false, Err(_)) => {}
438            _ => return ControlFlow::Continue(()),
439        }
440
441        let pred = goal.goal().predicate;
442
443        let candidates = self.non_trivial_candidates(goal);
444        let candidate = match candidates.as_slice() {
445            [candidate] => candidate,
446            [] => return self.detect_error_from_empty_candidates(goal),
447            _ => return ControlFlow::Break(self.obligation.clone()),
448        };
449
450        // Don't walk into impls that have `do_not_recommend`.
451        if let inspect::ProbeKind::TraitCandidate {
452            source: CandidateSource::Impl(impl_def_id),
453            result: _,
454        } = candidate.kind()
455            && tcx.do_not_recommend_impl(impl_def_id)
456        {
457            trace!("#[diagnostic::do_not_recommend] -> exit");
458            return ControlFlow::Break(self.obligation.clone());
459        }
460
461        // FIXME: Also, what about considering >1 layer up the stack? May be necessary
462        // for normalizes-to.
463        let child_mode = match pred.kind().skip_binder() {
464            ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
465                ChildMode::Trait(pred.kind().rebind(trait_pred))
466            }
467            ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(host_pred)) => {
468                ChildMode::Host(pred.kind().rebind(host_pred))
469            }
470            ty::PredicateKind::NormalizesTo(normalizes_to)
471                if matches!(
472                    normalizes_to.alias.kind(tcx),
473                    ty::AliasTermKind::ProjectionTy { .. }
474                        | ty::AliasTermKind::ProjectionConst { .. }
475                ) =>
476            {
477                ChildMode::Trait(pred.kind().rebind(ty::TraitPredicate {
478                    trait_ref: normalizes_to.alias.trait_ref(tcx),
479                    polarity: ty::PredicatePolarity::Positive,
480                }))
481            }
482            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
483                return self.visit_well_formed_goal(candidate, term);
484            }
485            _ => ChildMode::PassThrough,
486        };
487
488        let nested_goals = candidate.instantiate_nested_goals(self.span());
489
490        // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as
491        // an actual candidate, instead we should treat them as if the impl was never considered to
492        // have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written
493        // instead of `impl<T: FnPtr> Trait for T`.
494        //
495        // We do this as a separate loop so that we do not choose to tell the user about some nested
496        // goal before we encounter a `T: FnPtr` nested goal.
497        for nested_goal in &nested_goals {
498            if let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
499                && tcx.is_lang_item(poly_trait_pred.def_id(), LangItem::FnPtrTrait)
500                && let Err(NoSolution) = nested_goal.result()
501            {
502                return ControlFlow::Break(self.obligation.clone());
503            }
504        }
505
506        let mut impl_where_bound_count = 0;
507        for nested_goal in nested_goals {
508            trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
509
510            let nested_pred = nested_goal.goal().predicate;
511
512            let make_obligation = |cause| Obligation {
513                cause,
514                param_env: nested_goal.goal().param_env,
515                predicate: nested_pred,
516                recursion_depth: self.obligation.recursion_depth + 1,
517            };
518
519            let obligation;
520            match (child_mode, nested_goal.source()) {
521                (
522                    ChildMode::Trait(_) | ChildMode::Host(_),
523                    GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_),
524                ) => {
525                    continue;
526                }
527                (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
528                    obligation = make_obligation(derive_cause(
529                        tcx,
530                        candidate.kind(),
531                        self.obligation.cause.clone(),
532                        impl_where_bound_count,
533                        parent_trait_pred,
534                    ));
535                    impl_where_bound_count += 1;
536                }
537                (
538                    ChildMode::Host(parent_host_pred),
539                    GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
540                ) => {
541                    obligation = make_obligation(derive_host_cause(
542                        tcx,
543                        candidate.kind(),
544                        self.obligation.cause.clone(),
545                        impl_where_bound_count,
546                        parent_host_pred,
547                    ));
548                    impl_where_bound_count += 1;
549                }
550                (ChildMode::PassThrough, _)
551                | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
552                    obligation = make_obligation(self.obligation.cause.clone());
553                }
554            }
555
556            self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
557        }
558
559        // alias-relate may fail because the lhs or rhs can't be normalized,
560        // and therefore is treated as rigid.
561        if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred.kind().no_bound_vars() {
562            goal.infcx().visit_proof_tree_at_depth(
563                goal.goal().with(tcx, ty::ClauseKind::WellFormed(lhs.into())),
564                goal.depth() + 1,
565                self,
566            )?;
567            goal.infcx().visit_proof_tree_at_depth(
568                goal.goal().with(tcx, ty::ClauseKind::WellFormed(rhs.into())),
569                goal.depth() + 1,
570                self,
571            )?;
572        }
573
574        self.detect_trait_error_in_higher_ranked_projection(goal)?;
575
576        ControlFlow::Break(self.obligation.clone())
577    }
578}
579
580#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for ChildMode<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ChildMode::Trait(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Trait",
                    &__self_0),
            ChildMode::Host(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Host",
                    &__self_0),
            ChildMode::PassThrough =>
                ::core::fmt::Formatter::write_str(f, "PassThrough"),
        }
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for ChildMode<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for ChildMode<'tcx> {
    #[inline]
    fn clone(&self) -> ChildMode<'tcx> {
        let _:
                ::core::clone::AssertParamIsClone<ty::PolyTraitPredicate<'tcx>>;
        let _:
                ::core::clone::AssertParamIsClone<ty::Binder<'tcx,
                ty::HostEffectPredicate<'tcx>>>;
        *self
    }
}Clone)]
581enum ChildMode<'tcx> {
582    // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
583    // and skip all `GoalSource::Misc`, which represent useless obligations
584    // such as alias-eq which may not hold.
585    Trait(ty::PolyTraitPredicate<'tcx>),
586    // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
587    // and skip all `GoalSource::Misc`, which represent useless obligations
588    // such as alias-eq which may not hold.
589    Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>),
590    // Skip trying to derive an `ObligationCause` from this obligation, and
591    // report *all* sub-obligations as if they came directly from the parent
592    // obligation.
593    PassThrough,
594}
595
596fn derive_cause<'tcx>(
597    tcx: TyCtxt<'tcx>,
598    candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
599    mut cause: ObligationCause<'tcx>,
600    idx: usize,
601    parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
602) -> ObligationCause<'tcx> {
603    match candidate_kind {
604        inspect::ProbeKind::TraitCandidate {
605            source: CandidateSource::Impl(impl_def_id),
606            result: _,
607        } => {
608            if let Some((_, span)) =
609                tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
610            {
611                cause = cause.derived_cause(parent_trait_pred, |derived| {
612                    ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
613                        derived,
614                        impl_or_alias_def_id: impl_def_id,
615                        impl_def_predicate_index: Some(idx),
616                        span,
617                    }))
618                })
619            }
620        }
621        inspect::ProbeKind::TraitCandidate {
622            source: CandidateSource::BuiltinImpl(..),
623            result: _,
624        } => {
625            cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived);
626        }
627        _ => {}
628    };
629    cause
630}
631
632fn derive_host_cause<'tcx>(
633    tcx: TyCtxt<'tcx>,
634    candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
635    mut cause: ObligationCause<'tcx>,
636    idx: usize,
637    parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
638) -> ObligationCause<'tcx> {
639    match candidate_kind {
640        inspect::ProbeKind::TraitCandidate {
641            source: CandidateSource::Impl(impl_def_id),
642            result: _,
643        } => {
644            if let Some((_, span)) = tcx
645                .predicates_of(impl_def_id)
646                .instantiate_identity(tcx)
647                .into_iter()
648                .chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map(
649                    |(trait_ref, span)| {
650                        (
651                            trait_ref.to_host_effect_clause(
652                                tcx,
653                                parent_host_pred.skip_binder().constness,
654                            ),
655                            span,
656                        )
657                    },
658                ))
659                .nth(idx)
660            {
661                cause =
662                    cause.derived_host_cause(parent_host_pred, |derived| {
663                        ObligationCauseCode::ImplDerivedHost(Box::new(
664                            traits::ImplDerivedHostCause { derived, impl_def_id, span },
665                        ))
666                    })
667            }
668        }
669        inspect::ProbeKind::TraitCandidate {
670            source: CandidateSource::BuiltinImpl(..),
671            result: _,
672        } => {
673            cause =
674                cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost);
675        }
676        _ => {}
677    };
678    cause
679}