Skip to main content

rustc_hir_analysis/coherence/
orphan.rs

1//! Orphan checker: every impl either implements a trait defined in this
2//! crate or pertains to a type defined in this crate.
3
4use rustc_data_structures::fx::FxIndexSet;
5use rustc_errors::ErrorGuaranteed;
6use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
7use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION;
8use rustc_middle::ty::{
9    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
10    Unnormalized,
11};
12use rustc_middle::{bug, span_bug};
13use rustc_span::def_id::{DefId, LocalDefId};
14use rustc_trait_selection::traits::{
15    self, IsFirstInputType, OrphanCheckErr, OrphanCheckMode, UncoveredTyParams,
16};
17use tracing::{debug, instrument};
18
19use crate::errors;
20
21#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::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("orphan_check_impl",
                                    "rustc_hir_analysis::coherence::orphan",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/orphan.rs"),
                                    ::tracing_core::__macro_support::Option::Some(21u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::orphan"),
                                    ::tracing_core::field::FieldSet::new(&["impl_def_id"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::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(&::tracing::field::debug(&impl_def_id)
                                                            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: Result<(), ErrorGuaranteed> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            let trait_ref =
                tcx.impl_trait_ref(impl_def_id).instantiate_identity().skip_norm_wip();
            trait_ref.error_reported()?;
            match orphan_check(tcx, impl_def_id, OrphanCheckMode::Proper) {
                Ok(()) => {}
                Err(err) =>
                    match orphan_check(tcx, impl_def_id,
                            OrphanCheckMode::Compat) {
                        Ok(()) =>
                            match err {
                                OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => {
                                    lint_uncovered_ty_params(tcx, uncovered_ty_params,
                                        impl_def_id)
                                }
                                OrphanCheckErr::NonLocalInputType(_) => {
                                    ::rustc_middle::util::bug::bug_fmt(format_args!("orphanck: shouldn\'t\'ve gotten non-local input tys in compat mode"))
                                }
                            },
                        Err(err) =>
                            return Err(emit_orphan_check_error(tcx, trait_ref,
                                        impl_def_id, err)),
                    },
            }
            let trait_def_id = trait_ref.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_hir_analysis/src/coherence/orphan.rs:78",
                                    "rustc_hir_analysis::coherence::orphan",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/orphan.rs"),
                                    ::tracing_core::__macro_support::Option::Some(78u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::orphan"),
                                    ::tracing_core::field::FieldSet::new(&["message"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::DEBUG <=
                                ::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!("trait_ref={0:?} trait_def_id={1:?} trait_is_auto={2}",
                                                                trait_ref, trait_def_id, tcx.trait_is_auto(trait_def_id)) as
                                                        &dyn Value))])
                        });
                } else { ; }
            };
            if tcx.trait_is_auto(trait_def_id) {
                let self_ty = trait_ref.self_ty();
                enum LocalImpl {
                    Allow,
                    Disallow {
                        problematic_kind: &'static str,
                    },
                }
                enum NonlocalImpl {
                    Allow,
                    DisallowBecauseNonlocal,
                    DisallowOther,
                }
                let (local_impl, nonlocal_impl) =
                    match self_ty.kind() {
                        ty::Adt(self_def, _) =>
                            (LocalImpl::Allow,
                                if self_def.did().is_local() {
                                    NonlocalImpl::Allow
                                } else { NonlocalImpl::DisallowBecauseNonlocal }),
                        ty::Foreign(did) =>
                            (LocalImpl::Allow,
                                if did.is_local() {
                                    NonlocalImpl::Allow
                                } else { NonlocalImpl::DisallowBecauseNonlocal }),
                        ty::Dynamic(..) =>
                            (LocalImpl::Disallow { problematic_kind: "trait object" },
                                NonlocalImpl::DisallowOther),
                        ty::Param(..) =>
                            (if self_ty.is_sized(tcx,
                                        ty::TypingEnv::non_body_analysis(tcx, impl_def_id)) {
                                    LocalImpl::Allow
                                } else {
                                    LocalImpl::Disallow { problematic_kind: "generic type" }
                                }, NonlocalImpl::DisallowOther),
                        ty::Alias(ty::AliasTy { kind, .. }) => {
                            let problematic_kind =
                                match kind {
                                    ty::Projection { .. } => "associated type",
                                    ty::Free { .. } => "type alias",
                                    ty::Opaque { .. } => "opaque type",
                                    ty::Inherent { .. } => "associated type",
                                };
                            (LocalImpl::Disallow { problematic_kind },
                                NonlocalImpl::DisallowOther)
                        }
                        ty::Bool | ty::Pat(..) | ty::Char | ty::Int(..) |
                            ty::Uint(..) | ty::Float(..) | ty::Str | ty::Array(..) |
                            ty::Slice(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..)
                            | ty::Never | ty::Tuple(..) | ty::UnsafeBinder(_) =>
                            (LocalImpl::Allow, NonlocalImpl::DisallowOther),
                        ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) |
                            ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Bound(..)
                            | ty::Placeholder(..) | ty::Infer(..) => {
                            let sp = tcx.def_span(impl_def_id);
                            ::rustc_middle::util::bug::span_bug_fmt(sp,
                                format_args!("weird self type for autotrait impl"))
                        }
                        ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
                    };
                if trait_def_id.is_local() {
                    match local_impl {
                        LocalImpl::Allow => {}
                        LocalImpl::Disallow { problematic_kind } => {
                            return Err(tcx.dcx().emit_err(errors::TraitsWithDefaultImpl {
                                            span: tcx.def_span(impl_def_id),
                                            traits: tcx.def_path_str(trait_def_id),
                                            problematic_kind,
                                            self_ty,
                                        }));
                        }
                    }
                } else {
                    match nonlocal_impl {
                        NonlocalImpl::Allow => {}
                        NonlocalImpl::DisallowBecauseNonlocal => {
                            return Err(tcx.dcx().emit_err(errors::CrossCrateTraitsDefined {
                                            span: tcx.def_span(impl_def_id),
                                            traits: tcx.def_path_str(trait_def_id),
                                        }));
                        }
                        NonlocalImpl::DisallowOther => {
                            return Err(tcx.dcx().emit_err(errors::CrossCrateTraits {
                                            span: tcx.def_span(impl_def_id),
                                            traits: tcx.def_path_str(trait_def_id),
                                            self_ty,
                                        }));
                        }
                    }
                }
            }
            Ok(())
        }
    }
}#[instrument(level = "debug", skip(tcx))]
22pub(crate) fn orphan_check_impl(
23    tcx: TyCtxt<'_>,
24    impl_def_id: LocalDefId,
25) -> Result<(), ErrorGuaranteed> {
26    let trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate_identity().skip_norm_wip();
27    trait_ref.error_reported()?;
28
29    match orphan_check(tcx, impl_def_id, OrphanCheckMode::Proper) {
30        Ok(()) => {}
31        Err(err) => match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) {
32            Ok(()) => match err {
33                OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => {
34                    lint_uncovered_ty_params(tcx, uncovered_ty_params, impl_def_id)
35                }
36                OrphanCheckErr::NonLocalInputType(_) => {
37                    bug!("orphanck: shouldn't've gotten non-local input tys in compat mode")
38                }
39            },
40            Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)),
41        },
42    }
43
44    let trait_def_id = trait_ref.def_id;
45
46    // In addition to the above rules, we restrict impls of auto traits
47    // so that they can only be implemented on nominal types, such as structs,
48    // enums or foreign types. To see why this restriction exists, consider the
49    // following example (#22978). Imagine that crate A defines an auto trait
50    // `Foo` and a fn that operates on pairs of types:
51    //
52    // ```
53    // // Crate A
54    // auto trait Foo { }
55    // fn two_foos<A:Foo,B:Foo>(..) {
56    //     one_foo::<(A,B)>(..)
57    // }
58    // fn one_foo<T:Foo>(..) { .. }
59    // ```
60    //
61    // This type-checks fine; in particular the fn
62    // `two_foos` is able to conclude that `(A,B):Foo`
63    // because `A:Foo` and `B:Foo`.
64    //
65    // Now imagine that crate B comes along and does the following:
66    //
67    // ```
68    // struct A { }
69    // struct B { }
70    // impl Foo for A { }
71    // impl Foo for B { }
72    // impl !Foo for (A, B) { }
73    // ```
74    //
75    // This final impl is legal according to the orphan
76    // rules, but it invalidates the reasoning from
77    // `two_foos` above.
78    debug!(
79        "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
80        trait_ref,
81        trait_def_id,
82        tcx.trait_is_auto(trait_def_id)
83    );
84
85    if tcx.trait_is_auto(trait_def_id) {
86        let self_ty = trait_ref.self_ty();
87
88        // If the impl is in the same crate as the auto-trait, almost anything
89        // goes.
90        //
91        //     impl MyAuto for Rc<Something> {}  // okay
92        //     impl<T> !MyAuto for *const T {}   // okay
93        //     impl<T> MyAuto for T {}           // okay
94        //
95        // But there is one important exception: implementing for a trait object
96        // is not allowed.
97        //
98        //     impl MyAuto for dyn Trait {}      // NOT OKAY
99        //     impl<T: ?Sized> MyAuto for T {}   // NOT OKAY
100        //
101        // With this restriction, it's guaranteed that an auto-trait is
102        // implemented for a trait object if and only if the auto-trait is one
103        // of the trait object's trait bounds (or a supertrait of a bound). In
104        // other words `dyn Trait + AutoTrait` always implements AutoTrait,
105        // while `dyn Trait` never implements AutoTrait.
106        //
107        // This is necessary in order for autotrait bounds on methods of trait
108        // objects to be sound.
109        //
110        //     auto trait AutoTrait {}
111        //
112        //     trait DynCompatibleTrait {
113        //         fn f(&self) where Self: AutoTrait;
114        //     }
115        //
116        // We can allow f to be called on `dyn DynCompatibleTrait + AutoTrait`.
117        //
118        // If we didn't deny `impl AutoTrait for dyn Trait`, it would be unsound
119        // for the `DynCompatibleTrait` shown above to be dyn-compatible because someone
120        // could take some type implementing `DynCompatibleTrait` but not `AutoTrait`,
121        // unsize it to `dyn DynCompatibleTrait`, and call `.f()` which has no
122        // concrete implementation (issue #50781).
123        enum LocalImpl {
124            Allow,
125            Disallow { problematic_kind: &'static str },
126        }
127
128        // If the auto-trait is from a dependency, it must only be getting
129        // implemented for a nominal type, and specifically one local to the
130        // current crate.
131        //
132        //     impl<T> Sync for MyStruct<T> {}   // okay
133        //
134        //     impl Sync for Rc<MyStruct> {}     // NOT OKAY
135        enum NonlocalImpl {
136            Allow,
137            DisallowBecauseNonlocal,
138            DisallowOther,
139        }
140
141        // Exhaustive match considering that this logic is essential for
142        // soundness.
143        let (local_impl, nonlocal_impl) = match self_ty.kind() {
144            // struct Struct<T>;
145            // impl AutoTrait for Struct<Foo> {}
146            ty::Adt(self_def, _) => (
147                LocalImpl::Allow,
148                if self_def.did().is_local() {
149                    NonlocalImpl::Allow
150                } else {
151                    NonlocalImpl::DisallowBecauseNonlocal
152                },
153            ),
154
155            // extern { type OpaqueType; }
156            // impl AutoTrait for OpaqueType {}
157            ty::Foreign(did) => (
158                LocalImpl::Allow,
159                if did.is_local() {
160                    NonlocalImpl::Allow
161                } else {
162                    NonlocalImpl::DisallowBecauseNonlocal
163                },
164            ),
165
166            // impl AutoTrait for dyn Trait {}
167            ty::Dynamic(..) => (
168                LocalImpl::Disallow { problematic_kind: "trait object" },
169                NonlocalImpl::DisallowOther,
170            ),
171
172            // impl<T> AutoTrait for T {}
173            // impl<T: ?Sized> AutoTrait for T {}
174            ty::Param(..) => (
175                if self_ty.is_sized(tcx, ty::TypingEnv::non_body_analysis(tcx, impl_def_id)) {
176                    LocalImpl::Allow
177                } else {
178                    LocalImpl::Disallow { problematic_kind: "generic type" }
179                },
180                NonlocalImpl::DisallowOther,
181            ),
182
183            ty::Alias(ty::AliasTy { kind, .. }) => {
184                let problematic_kind = match kind {
185                    // trait Id { type This: ?Sized; }
186                    // impl<T: ?Sized> Id for T {
187                    //     type This = T;
188                    // }
189                    // impl<T: ?Sized> AutoTrait for <T as Id>::This {}
190                    ty::Projection { .. } => "associated type",
191                    // type Foo = (impl Sized, bool)
192                    // impl AutoTrait for Foo {}
193                    ty::Free { .. } => "type alias",
194                    // type Opaque = impl Trait;
195                    // impl AutoTrait for Opaque {}
196                    ty::Opaque { .. } => "opaque type",
197                    // ```
198                    // struct S<T>(T);
199                    // impl<T: ?Sized> S<T> {
200                    //     type This = T;
201                    // }
202                    // impl<T: ?Sized> AutoTrait for S<T>::This {}
203                    // ```
204                    // FIXME(inherent_associated_types): The example code above currently leads to a cycle
205                    ty::Inherent { .. } => "associated type",
206                };
207                (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
208            }
209
210            ty::Bool
211            | ty::Pat(..)
212            | ty::Char
213            | ty::Int(..)
214            | ty::Uint(..)
215            | ty::Float(..)
216            | ty::Str
217            | ty::Array(..)
218            | ty::Slice(..)
219            | ty::RawPtr(..)
220            | ty::Ref(..)
221            | ty::FnPtr(..)
222            | ty::Never
223            | ty::Tuple(..)
224            | ty::UnsafeBinder(_) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
225
226            ty::FnDef(..)
227            | ty::Closure(..)
228            | ty::CoroutineClosure(..)
229            | ty::Coroutine(..)
230            | ty::CoroutineWitness(..)
231            | ty::Bound(..)
232            | ty::Placeholder(..)
233            | ty::Infer(..) => {
234                let sp = tcx.def_span(impl_def_id);
235                span_bug!(sp, "weird self type for autotrait impl")
236            }
237
238            ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
239        };
240
241        if trait_def_id.is_local() {
242            match local_impl {
243                LocalImpl::Allow => {}
244                LocalImpl::Disallow { problematic_kind } => {
245                    return Err(tcx.dcx().emit_err(errors::TraitsWithDefaultImpl {
246                        span: tcx.def_span(impl_def_id),
247                        traits: tcx.def_path_str(trait_def_id),
248                        problematic_kind,
249                        self_ty,
250                    }));
251                }
252            }
253        } else {
254            match nonlocal_impl {
255                NonlocalImpl::Allow => {}
256                NonlocalImpl::DisallowBecauseNonlocal => {
257                    return Err(tcx.dcx().emit_err(errors::CrossCrateTraitsDefined {
258                        span: tcx.def_span(impl_def_id),
259                        traits: tcx.def_path_str(trait_def_id),
260                    }));
261                }
262                NonlocalImpl::DisallowOther => {
263                    return Err(tcx.dcx().emit_err(errors::CrossCrateTraits {
264                        span: tcx.def_span(impl_def_id),
265                        traits: tcx.def_path_str(trait_def_id),
266                        self_ty,
267                    }));
268                }
269            }
270        }
271    }
272
273    Ok(())
274}
275
276/// Checks the coherence orphan rules.
277///
278/// `impl_def_id` should be the `DefId` of a trait impl.
279///
280/// To pass, either the trait must be local, or else two conditions must be satisfied:
281///
282/// 1. All type parameters in `Self` must be "covered" by some local type constructor.
283/// 2. Some local type must appear in `Self`.
284x;#[instrument(level = "debug", skip(tcx), ret)]
285fn orphan_check<'tcx>(
286    tcx: TyCtxt<'tcx>,
287    impl_def_id: LocalDefId,
288    mode: OrphanCheckMode,
289) -> Result<(), OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>> {
290    // We only accept this routine to be invoked on implementations
291    // of a trait, not inherent implementations.
292    let trait_ref = tcx.impl_trait_ref(impl_def_id);
293    debug!(trait_ref = ?trait_ref.skip_binder());
294
295    // If the *trait* is local to the crate, ok.
296    if let Some(def_id) = trait_ref.skip_binder().def_id.as_local() {
297        debug!("trait {def_id:?} is local to current crate");
298        return Ok(());
299    }
300
301    // (1)  Instantiate all generic params with fresh inference vars.
302    let infcx = tcx.infer_ctxt().build(TypingMode::Coherence);
303    let cause = traits::ObligationCause::dummy();
304    let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id());
305    let trait_ref = trait_ref.instantiate(tcx, args).skip_norm_wip();
306
307    let lazily_normalize_ty = |user_ty: Ty<'tcx>| {
308        let ty::Alias(..) = user_ty.kind() else { return Ok(user_ty) };
309
310        let ocx = traits::ObligationCtxt::new(&infcx);
311        let ty = ocx.normalize(&cause, ty::ParamEnv::empty(), Unnormalized::new_wip(user_ty));
312        let ty = infcx.resolve_vars_if_possible(ty);
313        let errors = ocx.try_evaluate_obligations();
314        if !errors.is_empty() {
315            return Ok(user_ty);
316        }
317
318        Ok::<_, !>(ty)
319    };
320
321    let result = traits::orphan_check_trait_ref(
322        &infcx,
323        trait_ref,
324        traits::InCrate::Local { mode },
325        lazily_normalize_ty,
326    )
327    .into_ok();
328
329    // (2)  Try to map the remaining inference vars back to generic params.
330    result.map_err(|err| match err {
331        OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
332            let mut collector =
333                UncoveredTyParamCollector { infcx: &infcx, uncovered_params: Default::default() };
334            uncovered.visit_with(&mut collector);
335            // FIXME(fmease): This is very likely reachable.
336            debug_assert!(!collector.uncovered_params.is_empty());
337
338            OrphanCheckErr::UncoveredTyParams(UncoveredTyParams {
339                uncovered: collector.uncovered_params,
340                local_ty,
341            })
342        }
343        OrphanCheckErr::NonLocalInputType(tys) => {
344            let tys = infcx.probe(|_| {
345                // Map the unconstrained args back to their params,
346                // ignoring any type unification errors.
347                for (arg, id_arg) in
348                    std::iter::zip(args, ty::GenericArgs::identity_for_item(tcx, impl_def_id))
349                {
350                    let _ = infcx.at(&cause, ty::ParamEnv::empty()).eq(
351                        DefineOpaqueTypes::No,
352                        arg,
353                        id_arg,
354                    );
355                }
356                infcx.resolve_vars_if_possible(tys)
357            });
358            OrphanCheckErr::NonLocalInputType(tys)
359        }
360    })
361}
362
363fn emit_orphan_check_error<'tcx>(
364    tcx: TyCtxt<'tcx>,
365    trait_ref: ty::TraitRef<'tcx>,
366    impl_def_id: LocalDefId,
367    err: traits::OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>,
368) -> ErrorGuaranteed {
369    match err {
370        traits::OrphanCheckErr::NonLocalInputType(tys) => {
371            let item = tcx.hir_expect_item(impl_def_id);
372            let impl_ = item.expect_impl();
373            let of_trait = impl_.of_trait.unwrap();
374
375            let span = tcx.def_span(impl_def_id);
376            let mut diag = tcx.dcx().create_err(match trait_ref.self_ty().kind() {
377                ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span, note: () },
378                _ if trait_ref.self_ty().is_primitive() => {
379                    errors::OnlyCurrentTraits::Primitive { span, note: () }
380                }
381                _ => errors::OnlyCurrentTraits::Arbitrary { span, note: () },
382            });
383
384            for &(mut ty, is_target_ty) in &tys {
385                let span = if #[allow(non_exhaustive_omitted_patterns)] match is_target_ty {
    IsFirstInputType::Yes => true,
    _ => false,
}matches!(is_target_ty, IsFirstInputType::Yes) {
386                    // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
387                    impl_.self_ty.span
388                } else {
389                    // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
390                    of_trait.trait_ref.path.span
391                };
392
393                ty = tcx.erase_and_anonymize_regions(ty);
394
395                let is_foreign =
396                    !trait_ref.def_id.is_local() && #[allow(non_exhaustive_omitted_patterns)] match is_target_ty {
    IsFirstInputType::No => true,
    _ => false,
}matches!(is_target_ty, IsFirstInputType::No);
397
398                match *ty.kind() {
399                    ty::Slice(_) => {
400                        if is_foreign {
401                            diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
402                        } else {
403                            diag.subdiagnostic(errors::OnlyCurrentTraitsName {
404                                span,
405                                name: "slices",
406                            });
407                        }
408                    }
409                    ty::Array(..) => {
410                        if is_foreign {
411                            diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
412                        } else {
413                            diag.subdiagnostic(errors::OnlyCurrentTraitsName {
414                                span,
415                                name: "arrays",
416                            });
417                        }
418                    }
419                    ty::Tuple(..) => {
420                        if is_foreign {
421                            diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
422                        } else {
423                            diag.subdiagnostic(errors::OnlyCurrentTraitsName {
424                                span,
425                                name: "tuples",
426                            });
427                        }
428                    }
429                    ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
430                        diag.subdiagnostic(errors::OnlyCurrentTraitsOpaque { span });
431                    }
432                    ty::RawPtr(ptr_ty, mutbl) => {
433                        if !trait_ref.self_ty().has_param() {
434                            diag.subdiagnostic(errors::OnlyCurrentTraitsPointerSugg {
435                                wrapper_span: impl_.self_ty.span,
436                                struct_span: item.span.shrink_to_lo(),
437                                mut_key: mutbl.prefix_str(),
438                                ptr_ty,
439                            });
440                        }
441                        diag.subdiagnostic(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
442                    }
443                    ty::Adt(adt_def, _) => {
444                        diag.subdiagnostic(errors::OnlyCurrentTraitsAdt {
445                            span,
446                            name: tcx.def_path_str(adt_def.did()),
447                        });
448                    }
449                    _ => {
450                        diag.subdiagnostic(errors::OnlyCurrentTraitsTy { span, ty });
451                    }
452                }
453            }
454
455            diag.emit()
456        }
457        traits::OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
458            let mut reported = None;
459            for param_def_id in uncovered {
460                let name = tcx.item_ident(param_def_id);
461                let span = name.span;
462
463                reported.get_or_insert(match local_ty {
464                    Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
465                        span,
466                        note: (),
467                        param: name,
468                        local_type,
469                    }),
470                    None => tcx.dcx().emit_err(errors::TyParamSome { span, note: (), param: name }),
471                });
472            }
473            reported.unwrap() // FIXME(fmease): This is very likely reachable.
474        }
475    }
476}
477
478fn lint_uncovered_ty_params<'tcx>(
479    tcx: TyCtxt<'tcx>,
480    UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<TyCtxt<'tcx>, FxIndexSet<DefId>>,
481    impl_def_id: LocalDefId,
482) {
483    let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);
484
485    for param_def_id in uncovered {
486        let span = tcx.def_ident_span(param_def_id).unwrap();
487        let name = tcx.item_ident(param_def_id);
488
489        match local_ty {
490            Some(local_type) => tcx.emit_node_span_lint(
491                UNCOVERED_PARAM_IN_PROJECTION,
492                hir_id,
493                span,
494                errors::TyParamFirstLocalLint { span, note: (), param: name, local_type },
495            ),
496            None => tcx.emit_node_span_lint(
497                UNCOVERED_PARAM_IN_PROJECTION,
498                hir_id,
499                span,
500                errors::TyParamSomeLint { span, note: (), param: name },
501            ),
502        };
503    }
504}
505
506struct UncoveredTyParamCollector<'cx, 'tcx> {
507    infcx: &'cx InferCtxt<'tcx>,
508    uncovered_params: FxIndexSet<DefId>,
509}
510
511impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'_, 'tcx> {
512    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
513        if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
514            return;
515        }
516        let ty::Infer(ty::TyVar(vid)) = *ty.kind() else {
517            return ty.super_visit_with(self);
518        };
519        let origin = self.infcx.type_var_origin(vid);
520        if let Some(def_id) = origin.param_def_id {
521            self.uncovered_params.insert(def_id);
522        }
523    }
524
525    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
526        if ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
527            ct.super_visit_with(self)
528        }
529    }
530}