rustc_trait_selection/traits/
coherence.rs

1//! See Rustc Dev Guide chapters on [trait-resolution] and [trait-specialization] for more info on
2//! how this works.
3//!
4//! [trait-resolution]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
5//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
6
7use std::fmt::Debug;
8
9use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
10use rustc_errors::{Diag, EmissionGuarantee};
11use rustc_hir::def::DefKind;
12use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
13use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
14use rustc_infer::traits::PredicateObligations;
15use rustc_middle::bug;
16use rustc_middle::traits::query::NoSolution;
17use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
18use rustc_middle::traits::specialization_graph::OverlapMode;
19use rustc_middle::ty::fast_reject::DeepRejectCtxt;
20use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
21use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
22pub use rustc_next_trait_solver::coherence::*;
23use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
24use rustc_span::{DUMMY_SP, Span, sym};
25use tracing::{debug, instrument, warn};
26
27use super::ObligationCtxt;
28use crate::error_reporting::traits::suggest_new_overflow_limit;
29use crate::infer::InferOk;
30use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
31use crate::solve::{SolverDelegate, deeply_normalize_for_diagnostics, inspect};
32use crate::traits::query::evaluate_obligation::InferCtxtExt;
33use crate::traits::select::IntercrateAmbiguityCause;
34use crate::traits::{
35    FulfillmentErrorCode, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
36    SelectionContext, SkipLeakCheck, util,
37};
38
39pub struct OverlapResult<'tcx> {
40    pub impl_header: ty::ImplHeader<'tcx>,
41    pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
42
43    /// `true` if the overlap might've been permitted before the shift
44    /// to universes.
45    pub involves_placeholder: bool,
46
47    /// Used in the new solver to suggest increasing the recursion limit.
48    pub overflowing_predicates: Vec<ty::Predicate<'tcx>>,
49}
50
51pub fn add_placeholder_note<G: EmissionGuarantee>(err: &mut Diag<'_, G>) {
52    err.note(
53        "this behavior recently changed as a result of a bug fix; \
54         see rust-lang/rust#56105 for details",
55    );
56}
57
58pub(crate) fn suggest_increasing_recursion_limit<'tcx, G: EmissionGuarantee>(
59    tcx: TyCtxt<'tcx>,
60    err: &mut Diag<'_, G>,
61    overflowing_predicates: &[ty::Predicate<'tcx>],
62) {
63    for pred in overflowing_predicates {
64        err.note(format!("overflow evaluating the requirement `{}`", pred));
65    }
66
67    suggest_new_overflow_limit(tcx, err);
68}
69
70#[derive(Debug, Clone, Copy)]
71enum TrackAmbiguityCauses {
72    Yes,
73    No,
74}
75
76impl TrackAmbiguityCauses {
77    fn is_yes(self) -> bool {
78        match self {
79            TrackAmbiguityCauses::Yes => true,
80            TrackAmbiguityCauses::No => false,
81        }
82    }
83}
84
85/// If there are types that satisfy both impls, returns `Some`
86/// with a suitably-freshened `ImplHeader` with those types
87/// instantiated. Otherwise, returns `None`.
88#[instrument(skip(tcx, skip_leak_check), level = "debug")]
89pub fn overlapping_impls(
90    tcx: TyCtxt<'_>,
91    impl1_def_id: DefId,
92    impl2_def_id: DefId,
93    skip_leak_check: SkipLeakCheck,
94    overlap_mode: OverlapMode,
95) -> Option<OverlapResult<'_>> {
96    // Before doing expensive operations like entering an inference context, do
97    // a quick check via fast_reject to tell if the impl headers could possibly
98    // unify.
99    let drcx = DeepRejectCtxt::relate_infer_infer(tcx);
100    let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
101    let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
102    let may_overlap = match (impl1_ref, impl2_ref) {
103        (Some(a), Some(b)) => drcx.args_may_unify(a.skip_binder().args, b.skip_binder().args),
104        (None, None) => {
105            let self_ty1 = tcx.type_of(impl1_def_id).skip_binder();
106            let self_ty2 = tcx.type_of(impl2_def_id).skip_binder();
107            drcx.types_may_unify(self_ty1, self_ty2)
108        }
109        _ => bug!("unexpected impls: {impl1_def_id:?} {impl2_def_id:?}"),
110    };
111
112    if !may_overlap {
113        // Some types involved are definitely different, so the impls couldn't possibly overlap.
114        debug!("overlapping_impls: fast_reject early-exit");
115        return None;
116    }
117
118    if tcx.next_trait_solver_in_coherence() {
119        overlap(
120            tcx,
121            TrackAmbiguityCauses::Yes,
122            skip_leak_check,
123            impl1_def_id,
124            impl2_def_id,
125            overlap_mode,
126        )
127    } else {
128        let _overlap_with_bad_diagnostics = overlap(
129            tcx,
130            TrackAmbiguityCauses::No,
131            skip_leak_check,
132            impl1_def_id,
133            impl2_def_id,
134            overlap_mode,
135        )?;
136
137        // In the case where we detect an error, run the check again, but
138        // this time tracking intercrate ambiguity causes for better
139        // diagnostics. (These take time and can lead to false errors.)
140        let overlap = overlap(
141            tcx,
142            TrackAmbiguityCauses::Yes,
143            skip_leak_check,
144            impl1_def_id,
145            impl2_def_id,
146            overlap_mode,
147        )
148        .unwrap();
149        Some(overlap)
150    }
151}
152
153fn fresh_impl_header<'tcx>(infcx: &InferCtxt<'tcx>, impl_def_id: DefId) -> ty::ImplHeader<'tcx> {
154    let tcx = infcx.tcx;
155    let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
156
157    ty::ImplHeader {
158        impl_def_id,
159        impl_args,
160        self_ty: tcx.type_of(impl_def_id).instantiate(tcx, impl_args),
161        trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.instantiate(tcx, impl_args)),
162        predicates: tcx
163            .predicates_of(impl_def_id)
164            .instantiate(tcx, impl_args)
165            .iter()
166            .map(|(c, _)| c.as_predicate())
167            .collect(),
168    }
169}
170
171fn fresh_impl_header_normalized<'tcx>(
172    infcx: &InferCtxt<'tcx>,
173    param_env: ty::ParamEnv<'tcx>,
174    impl_def_id: DefId,
175) -> ty::ImplHeader<'tcx> {
176    let header = fresh_impl_header(infcx, impl_def_id);
177
178    let InferOk { value: mut header, obligations } =
179        infcx.at(&ObligationCause::dummy(), param_env).normalize(header);
180
181    header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
182    header
183}
184
185/// Can both impl `a` and impl `b` be satisfied by a common type (including
186/// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls.
187#[instrument(level = "debug", skip(tcx))]
188fn overlap<'tcx>(
189    tcx: TyCtxt<'tcx>,
190    track_ambiguity_causes: TrackAmbiguityCauses,
191    skip_leak_check: SkipLeakCheck,
192    impl1_def_id: DefId,
193    impl2_def_id: DefId,
194    overlap_mode: OverlapMode,
195) -> Option<OverlapResult<'tcx>> {
196    if overlap_mode.use_negative_impl() {
197        if impl_intersection_has_negative_obligation(tcx, impl1_def_id, impl2_def_id)
198            || impl_intersection_has_negative_obligation(tcx, impl2_def_id, impl1_def_id)
199        {
200            return None;
201        }
202    }
203
204    let infcx = tcx
205        .infer_ctxt()
206        .skip_leak_check(skip_leak_check.is_yes())
207        .with_next_trait_solver(tcx.next_trait_solver_in_coherence())
208        .build(TypingMode::Coherence);
209    let selcx = &mut SelectionContext::new(&infcx);
210    if track_ambiguity_causes.is_yes() {
211        selcx.enable_tracking_intercrate_ambiguity_causes();
212    }
213
214    // For the purposes of this check, we don't bring any placeholder
215    // types into scope; instead, we replace the generic types with
216    // fresh type variables, and hence we do our evaluations in an
217    // empty environment.
218    let param_env = ty::ParamEnv::empty();
219
220    let impl1_header = fresh_impl_header_normalized(selcx.infcx, param_env, impl1_def_id);
221    let impl2_header = fresh_impl_header_normalized(selcx.infcx, param_env, impl2_def_id);
222
223    // Equate the headers to find their intersection (the general type, with infer vars,
224    // that may apply both impls).
225    let mut obligations =
226        equate_impl_headers(selcx.infcx, param_env, &impl1_header, &impl2_header)?;
227    debug!("overlap: unification check succeeded");
228
229    obligations.extend(
230        [&impl1_header.predicates, &impl2_header.predicates].into_iter().flatten().map(
231            |&predicate| Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate),
232        ),
233    );
234
235    let mut overflowing_predicates = Vec::new();
236    if overlap_mode.use_implicit_negative() {
237        match impl_intersection_has_impossible_obligation(selcx, &obligations) {
238            IntersectionHasImpossibleObligations::Yes => return None,
239            IntersectionHasImpossibleObligations::No { overflowing_predicates: p } => {
240                overflowing_predicates = p
241            }
242        }
243    }
244
245    // We toggle the `leak_check` by using `skip_leak_check` when constructing the
246    // inference context, so this may be a noop.
247    if infcx.leak_check(ty::UniverseIndex::ROOT, None).is_err() {
248        debug!("overlap: leak check failed");
249        return None;
250    }
251
252    let intercrate_ambiguity_causes = if !overlap_mode.use_implicit_negative() {
253        Default::default()
254    } else if infcx.next_trait_solver() {
255        compute_intercrate_ambiguity_causes(&infcx, &obligations)
256    } else {
257        selcx.take_intercrate_ambiguity_causes()
258    };
259
260    debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
261    let involves_placeholder = infcx
262        .inner
263        .borrow_mut()
264        .unwrap_region_constraints()
265        .data()
266        .constraints
267        .iter()
268        .any(|c| c.0.involves_placeholders());
269
270    let mut impl_header = infcx.resolve_vars_if_possible(impl1_header);
271
272    // Deeply normalize the impl header for diagnostics, ignoring any errors if this fails.
273    if infcx.next_trait_solver() {
274        impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header);
275    }
276
277    Some(OverlapResult {
278        impl_header,
279        intercrate_ambiguity_causes,
280        involves_placeholder,
281        overflowing_predicates,
282    })
283}
284
285#[instrument(level = "debug", skip(infcx), ret)]
286fn equate_impl_headers<'tcx>(
287    infcx: &InferCtxt<'tcx>,
288    param_env: ty::ParamEnv<'tcx>,
289    impl1: &ty::ImplHeader<'tcx>,
290    impl2: &ty::ImplHeader<'tcx>,
291) -> Option<PredicateObligations<'tcx>> {
292    let result =
293        match (impl1.trait_ref, impl2.trait_ref) {
294            (Some(impl1_ref), Some(impl2_ref)) => infcx
295                .at(&ObligationCause::dummy(), param_env)
296                .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref),
297            (None, None) => infcx.at(&ObligationCause::dummy(), param_env).eq(
298                DefineOpaqueTypes::Yes,
299                impl1.self_ty,
300                impl2.self_ty,
301            ),
302            _ => bug!("equate_impl_headers given mismatched impl kinds"),
303        };
304
305    result.map(|infer_ok| infer_ok.obligations).ok()
306}
307
308/// The result of [fn impl_intersection_has_impossible_obligation].
309#[derive(Debug)]
310enum IntersectionHasImpossibleObligations<'tcx> {
311    Yes,
312    No {
313        /// With `-Znext-solver=coherence`, some obligations may
314        /// fail if only the user increased the recursion limit.
315        ///
316        /// We return those obligations here and mention them in the
317        /// error message.
318        overflowing_predicates: Vec<ty::Predicate<'tcx>>,
319    },
320}
321
322/// Check if both impls can be satisfied by a common type by considering whether
323/// any of either impl's obligations is not known to hold.
324///
325/// For example, given these two impls:
326///     `impl From<MyLocalType> for Box<dyn Error>` (in my crate)
327///     `impl<E> From<E> for Box<dyn Error> where E: Error` (in libstd)
328///
329/// After replacing both impl headers with inference vars (which happens before
330/// this function is called), we get:
331///     `Box<dyn Error>: From<MyLocalType>`
332///     `Box<dyn Error>: From<?E>`
333///
334/// This gives us `?E = MyLocalType`. We then certainly know that `MyLocalType: Error`
335/// never holds in intercrate mode since a local impl does not exist, and a
336/// downstream impl cannot be added -- therefore can consider the intersection
337/// of the two impls above to be empty.
338///
339/// Importantly, this works even if there isn't a `impl !Error for MyLocalType`.
340#[instrument(level = "debug", skip(selcx), ret)]
341fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
342    selcx: &mut SelectionContext<'cx, 'tcx>,
343    obligations: &'a [PredicateObligation<'tcx>],
344) -> IntersectionHasImpossibleObligations<'tcx> {
345    let infcx = selcx.infcx;
346
347    if infcx.next_trait_solver() {
348        // A fast path optimization, try evaluating all goals with
349        // a very low recursion depth and bail if any of them don't
350        // hold.
351        if !obligations.iter().all(|o| {
352            <&SolverDelegate<'tcx>>::from(infcx)
353                .root_goal_may_hold_with_depth(8, Goal::new(infcx.tcx, o.param_env, o.predicate))
354        }) {
355            return IntersectionHasImpossibleObligations::Yes;
356        }
357
358        let ocx = ObligationCtxt::new_with_diagnostics(infcx);
359        ocx.register_obligations(obligations.iter().cloned());
360        let errors_and_ambiguities = ocx.select_all_or_error();
361        // We only care about the obligations that are *definitely* true errors.
362        // Ambiguities do not prove the disjointness of two impls.
363        let (errors, ambiguities): (Vec<_>, Vec<_>) =
364            errors_and_ambiguities.into_iter().partition(|error| error.is_true_error());
365
366        if errors.is_empty() {
367            IntersectionHasImpossibleObligations::No {
368                overflowing_predicates: ambiguities
369                    .into_iter()
370                    .filter(|error| {
371                        matches!(
372                            error.code,
373                            FulfillmentErrorCode::Ambiguity { overflow: Some(true) }
374                        )
375                    })
376                    .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
377                    .collect(),
378            }
379        } else {
380            IntersectionHasImpossibleObligations::Yes
381        }
382    } else {
383        for obligation in obligations {
384            // We use `evaluate_root_obligation` to correctly track intercrate
385            // ambiguity clauses.
386            let evaluation_result = selcx.evaluate_root_obligation(obligation);
387
388            match evaluation_result {
389                Ok(result) => {
390                    if !result.may_apply() {
391                        return IntersectionHasImpossibleObligations::Yes;
392                    }
393                }
394                // If overflow occurs, we need to conservatively treat the goal as possibly holding,
395                // since there can be instantiations of this goal that don't overflow and result in
396                // success. While this isn't much of a problem in the old solver, since we treat overflow
397                // fatally, this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>.
398                Err(_overflow) => {}
399            }
400        }
401
402        IntersectionHasImpossibleObligations::No { overflowing_predicates: Vec::new() }
403    }
404}
405
406/// Check if both impls can be satisfied by a common type by considering whether
407/// any of first impl's obligations is known not to hold *via a negative predicate*.
408///
409/// For example, given these two impls:
410///     `struct MyCustomBox<T: ?Sized>(Box<T>);`
411///     `impl From<&str> for MyCustomBox<dyn Error>` (in my crate)
412///     `impl<E> From<E> for MyCustomBox<dyn Error> where E: Error` (in my crate)
413///
414/// After replacing the second impl's header with inference vars, we get:
415///     `MyCustomBox<dyn Error>: From<&str>`
416///     `MyCustomBox<dyn Error>: From<?E>`
417///
418/// This gives us `?E = &str`. We then try to prove the first impl's predicates
419/// after negating, giving us `&str: !Error`. This is a negative impl provided by
420/// libstd, and therefore we can guarantee for certain that libstd will never add
421/// a positive impl for `&str: Error` (without it being a breaking change).
422fn impl_intersection_has_negative_obligation(
423    tcx: TyCtxt<'_>,
424    impl1_def_id: DefId,
425    impl2_def_id: DefId,
426) -> bool {
427    debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
428
429    // N.B. We need to unify impl headers *with* intercrate mode, even if proving negative predicates
430    // do not need intercrate mode enabled.
431    let ref infcx = tcx.infer_ctxt().with_next_trait_solver(true).build(TypingMode::Coherence);
432    let root_universe = infcx.universe();
433    assert_eq!(root_universe, ty::UniverseIndex::ROOT);
434
435    let impl1_header = fresh_impl_header(infcx, impl1_def_id);
436    let param_env =
437        ty::EarlyBinder::bind(tcx.param_env(impl1_def_id)).instantiate(tcx, impl1_header.impl_args);
438
439    let impl2_header = fresh_impl_header(infcx, impl2_def_id);
440
441    // Equate the headers to find their intersection (the general type, with infer vars,
442    // that may apply both impls).
443    let Some(equate_obligations) =
444        equate_impl_headers(infcx, param_env, &impl1_header, &impl2_header)
445    else {
446        return false;
447    };
448
449    // FIXME(with_negative_coherence): the infcx has constraints from equating
450    // the impl headers. We should use these constraints as assumptions, not as
451    // requirements, when proving the negated where clauses below.
452    drop(equate_obligations);
453    drop(infcx.take_registered_region_obligations());
454    drop(infcx.take_and_reset_region_constraints());
455
456    plug_infer_with_placeholders(
457        infcx,
458        root_universe,
459        (impl1_header.impl_args, impl2_header.impl_args),
460    );
461    let param_env = infcx.resolve_vars_if_possible(param_env);
462
463    util::elaborate(tcx, tcx.predicates_of(impl2_def_id).instantiate(tcx, impl2_header.impl_args))
464        .any(|(clause, _)| try_prove_negated_where_clause(infcx, clause, param_env))
465}
466
467fn plug_infer_with_placeholders<'tcx>(
468    infcx: &InferCtxt<'tcx>,
469    universe: ty::UniverseIndex,
470    value: impl TypeVisitable<TyCtxt<'tcx>>,
471) {
472    struct PlugInferWithPlaceholder<'a, 'tcx> {
473        infcx: &'a InferCtxt<'tcx>,
474        universe: ty::UniverseIndex,
475        var: ty::BoundVar,
476    }
477
478    impl<'tcx> PlugInferWithPlaceholder<'_, 'tcx> {
479        fn next_var(&mut self) -> ty::BoundVar {
480            let var = self.var;
481            self.var = self.var + 1;
482            var
483        }
484    }
485
486    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for PlugInferWithPlaceholder<'_, 'tcx> {
487        fn visit_ty(&mut self, ty: Ty<'tcx>) {
488            let ty = self.infcx.shallow_resolve(ty);
489            if ty.is_ty_var() {
490                let Ok(InferOk { value: (), obligations }) =
491                    self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
492                        // Comparing against a type variable never registers hidden types anyway
493                        DefineOpaqueTypes::Yes,
494                        ty,
495                        Ty::new_placeholder(
496                            self.infcx.tcx,
497                            ty::Placeholder {
498                                universe: self.universe,
499                                bound: ty::BoundTy {
500                                    var: self.next_var(),
501                                    kind: ty::BoundTyKind::Anon,
502                                },
503                            },
504                        ),
505                    )
506                else {
507                    bug!("we always expect to be able to plug an infer var with placeholder")
508                };
509                assert_eq!(obligations.len(), 0);
510            } else {
511                ty.super_visit_with(self);
512            }
513        }
514
515        fn visit_const(&mut self, ct: ty::Const<'tcx>) {
516            let ct = self.infcx.shallow_resolve_const(ct);
517            if ct.is_ct_infer() {
518                let Ok(InferOk { value: (), obligations }) =
519                    self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
520                        // The types of the constants are the same, so there is no hidden type
521                        // registration happening anyway.
522                        DefineOpaqueTypes::Yes,
523                        ct,
524                        ty::Const::new_placeholder(
525                            self.infcx.tcx,
526                            ty::Placeholder { universe: self.universe, bound: self.next_var() },
527                        ),
528                    )
529                else {
530                    bug!("we always expect to be able to plug an infer var with placeholder")
531                };
532                assert_eq!(obligations.len(), 0);
533            } else {
534                ct.super_visit_with(self);
535            }
536        }
537
538        fn visit_region(&mut self, r: ty::Region<'tcx>) {
539            if let ty::ReVar(vid) = *r {
540                let r = self
541                    .infcx
542                    .inner
543                    .borrow_mut()
544                    .unwrap_region_constraints()
545                    .opportunistic_resolve_var(self.infcx.tcx, vid);
546                if r.is_var() {
547                    let Ok(InferOk { value: (), obligations }) =
548                        self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
549                            // Lifetimes don't contain opaque types (or any types for that matter).
550                            DefineOpaqueTypes::Yes,
551                            r,
552                            ty::Region::new_placeholder(
553                                self.infcx.tcx,
554                                ty::Placeholder {
555                                    universe: self.universe,
556                                    bound: ty::BoundRegion {
557                                        var: self.next_var(),
558                                        kind: ty::BoundRegionKind::Anon,
559                                    },
560                                },
561                            ),
562                        )
563                    else {
564                        bug!("we always expect to be able to plug an infer var with placeholder")
565                    };
566                    assert_eq!(obligations.len(), 0);
567                }
568            }
569        }
570    }
571
572    value.visit_with(&mut PlugInferWithPlaceholder { infcx, universe, var: ty::BoundVar::ZERO });
573}
574
575fn try_prove_negated_where_clause<'tcx>(
576    root_infcx: &InferCtxt<'tcx>,
577    clause: ty::Clause<'tcx>,
578    param_env: ty::ParamEnv<'tcx>,
579) -> bool {
580    let Some(negative_predicate) = clause.as_predicate().flip_polarity(root_infcx.tcx) else {
581        return false;
582    };
583
584    // N.B. We don't need to use intercrate mode here because we're trying to prove
585    // the *existence* of a negative goal, not the non-existence of a positive goal.
586    // Without this, we over-eagerly register coherence ambiguity candidates when
587    // impl candidates do exist.
588    // FIXME(#132279): `TypingMode::non_body_analysis` is a bit questionable here as it
589    // would cause us to reveal opaque types to leak their auto traits.
590    let ref infcx = root_infcx.fork_with_typing_mode(TypingMode::non_body_analysis());
591    let ocx = ObligationCtxt::new(infcx);
592    ocx.register_obligation(Obligation::new(
593        infcx.tcx,
594        ObligationCause::dummy(),
595        param_env,
596        negative_predicate,
597    ));
598    if !ocx.select_all_or_error().is_empty() {
599        return false;
600    }
601
602    // FIXME: We could use the assumed_wf_types from both impls, I think,
603    // if that wasn't implemented just for LocalDefId, and we'd need to do
604    // the normalization ourselves since this is totally fallible...
605    let errors = ocx.resolve_regions(CRATE_DEF_ID, param_env, []);
606    if !errors.is_empty() {
607        return false;
608    }
609
610    true
611}
612
613/// Compute the `intercrate_ambiguity_causes` for the new solver using
614/// "proof trees".
615///
616/// This is a bit scuffed but seems to be good enough, at least
617/// when looking at UI tests. Given that it is only used to improve
618/// diagnostics this is good enough. We can always improve it once there
619/// are test cases where it is currently not enough.
620fn compute_intercrate_ambiguity_causes<'tcx>(
621    infcx: &InferCtxt<'tcx>,
622    obligations: &[PredicateObligation<'tcx>],
623) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
624    let mut causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>> = Default::default();
625
626    for obligation in obligations {
627        search_ambiguity_causes(infcx, obligation.clone().into(), &mut causes);
628    }
629
630    causes
631}
632
633struct AmbiguityCausesVisitor<'a, 'tcx> {
634    cache: FxHashSet<Goal<'tcx, ty::Predicate<'tcx>>>,
635    causes: &'a mut FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
636}
637
638impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
639    fn span(&self) -> Span {
640        DUMMY_SP
641    }
642
643    fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) {
644        if !self.cache.insert(goal.goal()) {
645            return;
646        }
647
648        let infcx = goal.infcx();
649        for cand in goal.candidates() {
650            cand.visit_nested_in_probe(self);
651        }
652        // When searching for intercrate ambiguity causes, we only need to look
653        // at ambiguous goals, as for others the coherence unknowable candidate
654        // was irrelevant.
655        match goal.result() {
656            Ok(Certainty::Yes) | Err(NoSolution) => return,
657            Ok(Certainty::Maybe(_)) => {}
658        }
659
660        // For bound predicates we simply call `infcx.enter_forall`
661        // and then prove the resulting predicate as a nested goal.
662        let Goal { param_env, predicate } = goal.goal();
663        let trait_ref = match predicate.kind().no_bound_vars() {
664            Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
665            Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)))
666                if matches!(
667                    infcx.tcx.def_kind(proj.projection_term.def_id),
668                    DefKind::AssocTy | DefKind::AssocConst
669                ) =>
670            {
671                proj.projection_term.trait_ref(infcx.tcx)
672            }
673            _ => return,
674        };
675
676        if trait_ref.references_error() {
677            return;
678        }
679
680        let mut candidates = goal.candidates();
681        for cand in goal.candidates() {
682            if let inspect::ProbeKind::TraitCandidate {
683                source: CandidateSource::Impl(def_id),
684                result: Ok(_),
685            } = cand.kind()
686            {
687                if let ty::ImplPolarity::Reservation = infcx.tcx.impl_polarity(def_id) {
688                    let message = infcx
689                        .tcx
690                        .get_attr(def_id, sym::rustc_reservation_impl)
691                        .and_then(|a| a.value_str());
692                    if let Some(message) = message {
693                        self.causes.insert(IntercrateAmbiguityCause::ReservationImpl { message });
694                    }
695                }
696            }
697        }
698
699        // We also look for unknowable candidates. In case a goal is unknowable, there's
700        // always exactly 1 candidate.
701        let Some(cand) = candidates.pop() else {
702            return;
703        };
704
705        let inspect::ProbeKind::TraitCandidate {
706            source: CandidateSource::CoherenceUnknowable,
707            result: Ok(_),
708        } = cand.kind()
709        else {
710            return;
711        };
712
713        let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
714            if matches!(ty.kind(), ty::Alias(..)) {
715                let ocx = ObligationCtxt::new(infcx);
716                ty = ocx
717                    .structurally_normalize_ty(&ObligationCause::dummy(), param_env, ty)
718                    .map_err(|_| ())?;
719                if !ocx.select_where_possible().is_empty() {
720                    return Err(());
721                }
722            }
723            Ok(ty)
724        };
725
726        infcx.probe(|_| {
727            let conflict = match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
728                Err(()) => return,
729                Ok(Ok(())) => {
730                    warn!("expected an unknowable trait ref: {trait_ref:?}");
731                    return;
732                }
733                Ok(Err(conflict)) => conflict,
734            };
735
736            // It is only relevant that a goal is unknowable if it would have otherwise
737            // failed.
738            // FIXME(#132279): Forking with `TypingMode::non_body_analysis` is a bit questionable
739            // as it would allow us to reveal opaque types, potentially causing unexpected
740            // cycles.
741            let non_intercrate_infcx = infcx.fork_with_typing_mode(TypingMode::non_body_analysis());
742            if non_intercrate_infcx.predicate_may_hold(&Obligation::new(
743                infcx.tcx,
744                ObligationCause::dummy(),
745                param_env,
746                predicate,
747            )) {
748                return;
749            }
750
751            // Normalize the trait ref for diagnostics, ignoring any errors if this fails.
752            let trait_ref = deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
753            let self_ty = trait_ref.self_ty();
754            let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
755            self.causes.insert(match conflict {
756                Conflict::Upstream => {
757                    IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty }
758                }
759                Conflict::Downstream => {
760                    IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty }
761                }
762            });
763        });
764    }
765}
766
767fn search_ambiguity_causes<'tcx>(
768    infcx: &InferCtxt<'tcx>,
769    goal: Goal<'tcx, ty::Predicate<'tcx>>,
770    causes: &mut FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
771) {
772    infcx.probe(|_| {
773        infcx.visit_proof_tree(
774            goal,
775            &mut AmbiguityCausesVisitor { cache: Default::default(), causes },
776        )
777    });
778}