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