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::{InferCtxt, TyCtxtInferExt};
7use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION;
8use rustc_middle::ty::{
9    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
10    TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
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#[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).unwrap().instantiate_identity();
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(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::Weak => "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::Pat(..) => (
211                LocalImpl::Disallow { problematic_kind: "pattern type" },
212                NonlocalImpl::DisallowOther,
213            ),
214
215            ty::Bool
216            | ty::Char
217            | ty::Int(..)
218            | ty::Uint(..)
219            | ty::Float(..)
220            | ty::Str
221            | ty::Array(..)
222            | ty::Slice(..)
223            | ty::RawPtr(..)
224            | ty::Ref(..)
225            | ty::FnDef(..)
226            | ty::FnPtr(..)
227            | ty::Never
228            | ty::Tuple(..)
229            | ty::UnsafeBinder(_) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
230
231            ty::Closure(..)
232            | ty::CoroutineClosure(..)
233            | ty::Coroutine(..)
234            | ty::CoroutineWitness(..)
235            | ty::Bound(..)
236            | ty::Placeholder(..)
237            | ty::Infer(..) => {
238                let sp = tcx.def_span(impl_def_id);
239                span_bug!(sp, "weird self type for autotrait impl")
240            }
241
242            ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
243        };
244
245        if trait_def_id.is_local() {
246            match local_impl {
247                LocalImpl::Allow => {}
248                LocalImpl::Disallow { problematic_kind } => {
249                    return Err(tcx.dcx().emit_err(errors::TraitsWithDefaultImpl {
250                        span: tcx.def_span(impl_def_id),
251                        traits: tcx.def_path_str(trait_def_id),
252                        problematic_kind,
253                        self_ty,
254                    }));
255                }
256            }
257        } else {
258            match nonlocal_impl {
259                NonlocalImpl::Allow => {}
260                NonlocalImpl::DisallowBecauseNonlocal => {
261                    return Err(tcx.dcx().emit_err(errors::CrossCrateTraitsDefined {
262                        span: tcx.def_span(impl_def_id),
263                        traits: tcx.def_path_str(trait_def_id),
264                    }));
265                }
266                NonlocalImpl::DisallowOther => {
267                    return Err(tcx.dcx().emit_err(errors::CrossCrateTraits {
268                        span: tcx.def_span(impl_def_id),
269                        traits: tcx.def_path_str(trait_def_id),
270                        self_ty,
271                    }));
272                }
273            }
274        }
275    }
276
277    Ok(())
278}
279
280/// Checks the coherence orphan rules.
281///
282/// `impl_def_id` should be the `DefId` of a trait impl.
283///
284/// To pass, either the trait must be local, or else two conditions must be satisfied:
285///
286/// 1. All type parameters in `Self` must be "covered" by some local type constructor.
287/// 2. Some local type must appear in `Self`.
288#[instrument(level = "debug", skip(tcx), ret)]
289fn orphan_check<'tcx>(
290    tcx: TyCtxt<'tcx>,
291    impl_def_id: LocalDefId,
292    mode: OrphanCheckMode,
293) -> Result<(), OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>> {
294    // We only accept this routine to be invoked on implementations
295    // of a trait, not inherent implementations.
296    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
297    debug!(trait_ref = ?trait_ref.skip_binder());
298
299    // If the *trait* is local to the crate, ok.
300    if let Some(def_id) = trait_ref.skip_binder().def_id.as_local() {
301        debug!("trait {def_id:?} is local to current crate");
302        return Ok(());
303    }
304
305    // (1)  Instantiate all generic params with fresh inference vars.
306    let infcx = tcx.infer_ctxt().build(TypingMode::Coherence);
307    let cause = traits::ObligationCause::dummy();
308    let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id());
309    let trait_ref = trait_ref.instantiate(tcx, args);
310
311    let lazily_normalize_ty = |user_ty: Ty<'tcx>| {
312        let ty::Alias(..) = user_ty.kind() else { return Ok(user_ty) };
313
314        let ocx = traits::ObligationCtxt::new(&infcx);
315        let ty = ocx.normalize(&cause, ty::ParamEnv::empty(), user_ty);
316        let ty = infcx.resolve_vars_if_possible(ty);
317        let errors = ocx.select_where_possible();
318        if !errors.is_empty() {
319            return Ok(user_ty);
320        }
321
322        let ty = if infcx.next_trait_solver() {
323            ocx.structurally_normalize_ty(
324                &cause,
325                ty::ParamEnv::empty(),
326                infcx.resolve_vars_if_possible(ty),
327            )
328            .unwrap_or(ty)
329        } else {
330            ty
331        };
332
333        Ok::<_, !>(ty)
334    };
335
336    let result = traits::orphan_check_trait_ref(
337        &infcx,
338        trait_ref,
339        traits::InCrate::Local { mode },
340        lazily_normalize_ty,
341    )
342    .into_ok();
343
344    // (2)  Try to map the remaining inference vars back to generic params.
345    result.map_err(|err| match err {
346        OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
347            let mut collector =
348                UncoveredTyParamCollector { infcx: &infcx, uncovered_params: Default::default() };
349            uncovered.visit_with(&mut collector);
350            // FIXME(fmease): This is very likely reachable.
351            debug_assert!(!collector.uncovered_params.is_empty());
352
353            OrphanCheckErr::UncoveredTyParams(UncoveredTyParams {
354                uncovered: collector.uncovered_params,
355                local_ty,
356            })
357        }
358        OrphanCheckErr::NonLocalInputType(tys) => {
359            let generics = tcx.generics_of(impl_def_id);
360            let tys = tys
361                .into_iter()
362                .map(|(ty, is_target_ty)| {
363                    (ty.fold_with(&mut TyVarReplacer { infcx: &infcx, generics }), is_target_ty)
364                })
365                .collect();
366            OrphanCheckErr::NonLocalInputType(tys)
367        }
368    })
369}
370
371fn emit_orphan_check_error<'tcx>(
372    tcx: TyCtxt<'tcx>,
373    trait_ref: ty::TraitRef<'tcx>,
374    impl_def_id: LocalDefId,
375    err: traits::OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>,
376) -> ErrorGuaranteed {
377    match err {
378        traits::OrphanCheckErr::NonLocalInputType(tys) => {
379            let item = tcx.hir().expect_item(impl_def_id);
380            let impl_ = item.expect_impl();
381            let hir_trait_ref = impl_.of_trait.as_ref().unwrap();
382
383            let span = tcx.def_span(impl_def_id);
384            let mut diag = tcx.dcx().create_err(match trait_ref.self_ty().kind() {
385                ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span, note: () },
386                _ if trait_ref.self_ty().is_primitive() => {
387                    errors::OnlyCurrentTraits::Primitive { span, note: () }
388                }
389                _ => errors::OnlyCurrentTraits::Arbitrary { span, note: () },
390            });
391
392            for &(mut ty, is_target_ty) in &tys {
393                let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
394                    // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
395                    impl_.self_ty.span
396                } else {
397                    // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
398                    hir_trait_ref.path.span
399                };
400
401                ty = tcx.erase_regions(ty);
402
403                let is_foreign =
404                    !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
405
406                match *ty.kind() {
407                    ty::Slice(_) => {
408                        if is_foreign {
409                            diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
410                        } else {
411                            diag.subdiagnostic(errors::OnlyCurrentTraitsName {
412                                span,
413                                name: "slices",
414                            });
415                        }
416                    }
417                    ty::Array(..) => {
418                        if is_foreign {
419                            diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
420                        } else {
421                            diag.subdiagnostic(errors::OnlyCurrentTraitsName {
422                                span,
423                                name: "arrays",
424                            });
425                        }
426                    }
427                    ty::Tuple(..) => {
428                        if is_foreign {
429                            diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
430                        } else {
431                            diag.subdiagnostic(errors::OnlyCurrentTraitsName {
432                                span,
433                                name: "tuples",
434                            });
435                        }
436                    }
437                    ty::Alias(ty::Opaque, ..) => {
438                        diag.subdiagnostic(errors::OnlyCurrentTraitsOpaque { span });
439                    }
440                    ty::RawPtr(ptr_ty, mutbl) => {
441                        if !trait_ref.self_ty().has_param() {
442                            diag.subdiagnostic(errors::OnlyCurrentTraitsPointerSugg {
443                                wrapper_span: impl_.self_ty.span,
444                                struct_span: item.span.shrink_to_lo(),
445                                mut_key: mutbl.prefix_str(),
446                                ptr_ty,
447                            });
448                        }
449                        diag.subdiagnostic(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
450                    }
451                    ty::Adt(adt_def, _) => {
452                        diag.subdiagnostic(errors::OnlyCurrentTraitsAdt {
453                            span,
454                            name: tcx.def_path_str(adt_def.did()),
455                        });
456                    }
457                    _ => {
458                        diag.subdiagnostic(errors::OnlyCurrentTraitsTy { span, ty });
459                    }
460                }
461            }
462
463            diag.emit()
464        }
465        traits::OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
466            let mut reported = None;
467            for param_def_id in uncovered {
468                let name = tcx.item_ident(param_def_id);
469                let span = name.span;
470
471                reported.get_or_insert(match local_ty {
472                    Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
473                        span,
474                        note: (),
475                        param: name,
476                        local_type,
477                    }),
478                    None => tcx.dcx().emit_err(errors::TyParamSome { span, note: (), param: name }),
479                });
480            }
481            reported.unwrap() // FIXME(fmease): This is very likely reachable.
482        }
483    }
484}
485
486fn lint_uncovered_ty_params<'tcx>(
487    tcx: TyCtxt<'tcx>,
488    UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<TyCtxt<'tcx>, FxIndexSet<DefId>>,
489    impl_def_id: LocalDefId,
490) {
491    let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);
492
493    for param_def_id in uncovered {
494        let span = tcx.def_ident_span(param_def_id).unwrap();
495        let name = tcx.item_ident(param_def_id);
496
497        match local_ty {
498            Some(local_type) => tcx.emit_node_span_lint(
499                UNCOVERED_PARAM_IN_PROJECTION,
500                hir_id,
501                span,
502                errors::TyParamFirstLocalLint { span, note: (), param: name, local_type },
503            ),
504            None => tcx.emit_node_span_lint(
505                UNCOVERED_PARAM_IN_PROJECTION,
506                hir_id,
507                span,
508                errors::TyParamSomeLint { span, note: (), param: name },
509            ),
510        };
511    }
512}
513
514struct UncoveredTyParamCollector<'cx, 'tcx> {
515    infcx: &'cx InferCtxt<'tcx>,
516    uncovered_params: FxIndexSet<DefId>,
517}
518
519impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'_, 'tcx> {
520    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
521        if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
522            return;
523        }
524        let ty::Infer(ty::TyVar(vid)) = *ty.kind() else {
525            return ty.super_visit_with(self);
526        };
527        let origin = self.infcx.type_var_origin(vid);
528        if let Some(def_id) = origin.param_def_id {
529            self.uncovered_params.insert(def_id);
530        }
531    }
532
533    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
534        if ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
535            ct.super_visit_with(self)
536        }
537    }
538}
539
540struct TyVarReplacer<'cx, 'tcx> {
541    infcx: &'cx InferCtxt<'tcx>,
542    generics: &'tcx ty::Generics,
543}
544
545impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for TyVarReplacer<'cx, 'tcx> {
546    fn cx(&self) -> TyCtxt<'tcx> {
547        self.infcx.tcx
548    }
549
550    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
551        if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
552            return ty;
553        }
554        let ty::Infer(ty::TyVar(vid)) = *ty.kind() else {
555            return ty.super_fold_with(self);
556        };
557        let origin = self.infcx.type_var_origin(vid);
558        if let Some(def_id) = origin.param_def_id {
559            // The generics of an `impl` don't have a parent, we can index directly.
560            let index = self.generics.param_def_id_to_index[&def_id];
561            let name = self.generics.own_params[index as usize].name;
562
563            Ty::new_param(self.infcx.tcx, index, name)
564        } else {
565            ty
566        }
567    }
568
569    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
570        if !ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
571            return ct;
572        }
573        ct.super_fold_with(self)
574    }
575}