• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Orphan checker: every impl either implements a trait defined in this
2 //! crate or pertains to a type defined in this crate.
3 
4 use rustc_data_structures::fx::FxHashSet;
5 use rustc_errors::{struct_span_err, DelayDm};
6 use rustc_errors::{Diagnostic, ErrorGuaranteed};
7 use rustc_hir as hir;
8 use rustc_middle::ty::subst::InternalSubsts;
9 use rustc_middle::ty::util::CheckRegions;
10 use rustc_middle::ty::{
11     self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
12     TypeVisitor,
13 };
14 use rustc_session::lint;
15 use rustc_span::def_id::{DefId, LocalDefId};
16 use rustc_span::Span;
17 use rustc_trait_selection::traits;
18 use std::ops::ControlFlow;
19 
20 #[instrument(skip(tcx), level = "debug")]
orphan_check_impl( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed>21 pub(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().subst_identity();
26     trait_ref.error_reported()?;
27 
28     let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
29     if tcx.trait_is_auto(trait_ref.def_id) {
30         lint_auto_trait_impl(tcx, trait_ref, impl_def_id);
31     }
32 
33     ret
34 }
35 
do_orphan_check_impl<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed>36 fn do_orphan_check_impl<'tcx>(
37     tcx: TyCtxt<'tcx>,
38     trait_ref: ty::TraitRef<'tcx>,
39     def_id: LocalDefId,
40 ) -> Result<(), ErrorGuaranteed> {
41     let trait_def_id = trait_ref.def_id;
42 
43     match traits::orphan_check(tcx, def_id.to_def_id()) {
44         Ok(()) => {}
45         Err(err) => {
46             let item = tcx.hir().expect_item(def_id);
47             let hir::ItemKind::Impl(impl_) = item.kind else {
48                 bug!("{:?} is not an impl: {:?}", def_id, item);
49             };
50             let tr = impl_.of_trait.as_ref().unwrap();
51             let sp = tcx.def_span(def_id);
52 
53             emit_orphan_check_error(
54                 tcx,
55                 sp,
56                 item.span,
57                 tr.path.span,
58                 trait_ref,
59                 impl_.self_ty.span,
60                 &impl_.generics,
61                 err,
62             )?
63         }
64     }
65 
66     // In addition to the above rules, we restrict impls of auto traits
67     // so that they can only be implemented on nominal types, such as structs,
68     // enums or foreign types. To see why this restriction exists, consider the
69     // following example (#22978). Imagine that crate A defines an auto trait
70     // `Foo` and a fn that operates on pairs of types:
71     //
72     // ```
73     // // Crate A
74     // auto trait Foo { }
75     // fn two_foos<A:Foo,B:Foo>(..) {
76     //     one_foo::<(A,B)>(..)
77     // }
78     // fn one_foo<T:Foo>(..) { .. }
79     // ```
80     //
81     // This type-checks fine; in particular the fn
82     // `two_foos` is able to conclude that `(A,B):Foo`
83     // because `A:Foo` and `B:Foo`.
84     //
85     // Now imagine that crate B comes along and does the following:
86     //
87     // ```
88     // struct A { }
89     // struct B { }
90     // impl Foo for A { }
91     // impl Foo for B { }
92     // impl !Foo for (A, B) { }
93     // ```
94     //
95     // This final impl is legal according to the orphan
96     // rules, but it invalidates the reasoning from
97     // `two_foos` above.
98     debug!(
99         "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
100         trait_ref,
101         trait_def_id,
102         tcx.trait_is_auto(trait_def_id)
103     );
104 
105     if tcx.trait_is_auto(trait_def_id) {
106         let self_ty = trait_ref.self_ty();
107 
108         // If the impl is in the same crate as the auto-trait, almost anything
109         // goes.
110         //
111         //     impl MyAuto for Rc<Something> {}  // okay
112         //     impl<T> !MyAuto for *const T {}   // okay
113         //     impl<T> MyAuto for T {}           // okay
114         //
115         // But there is one important exception: implementing for a trait object
116         // is not allowed.
117         //
118         //     impl MyAuto for dyn Trait {}      // NOT OKAY
119         //     impl<T: ?Sized> MyAuto for T {}   // NOT OKAY
120         //
121         // With this restriction, it's guaranteed that an auto-trait is
122         // implemented for a trait object if and only if the auto-trait is one
123         // of the trait object's trait bounds (or a supertrait of a bound). In
124         // other words `dyn Trait + AutoTrait` always implements AutoTrait,
125         // while `dyn Trait` never implements AutoTrait.
126         //
127         // This is necessary in order for autotrait bounds on methods of trait
128         // objects to be sound.
129         //
130         //     auto trait AutoTrait {}
131         //
132         //     trait ObjectSafeTrait {
133         //         fn f(&self) where Self: AutoTrait;
134         //     }
135         //
136         // We can allow f to be called on `dyn ObjectSafeTrait + AutoTrait`.
137         //
138         // If we didn't deny `impl AutoTrait for dyn Trait`, it would be unsound
139         // for the ObjectSafeTrait shown above to be object safe because someone
140         // could take some type implementing ObjectSafeTrait but not AutoTrait,
141         // unsize it to `dyn ObjectSafeTrait`, and call .f() which has no
142         // concrete implementation (issue #50781).
143         enum LocalImpl {
144             Allow,
145             Disallow { problematic_kind: &'static str },
146         }
147 
148         // If the auto-trait is from a dependency, it must only be getting
149         // implemented for a nominal type, and specifically one local to the
150         // current crate.
151         //
152         //     impl<T> Sync for MyStruct<T> {}   // okay
153         //
154         //     impl Sync for Rc<MyStruct> {}     // NOT OKAY
155         enum NonlocalImpl {
156             Allow,
157             DisallowBecauseNonlocal,
158             DisallowOther,
159         }
160 
161         // Exhaustive match considering that this logic is essential for
162         // soundness.
163         let (local_impl, nonlocal_impl) = match self_ty.kind() {
164             // struct Struct<T>;
165             // impl AutoTrait for Struct<Foo> {}
166             ty::Adt(self_def, _) => (
167                 LocalImpl::Allow,
168                 if self_def.did().is_local() {
169                     NonlocalImpl::Allow
170                 } else {
171                     NonlocalImpl::DisallowBecauseNonlocal
172                 },
173             ),
174 
175             // extern { type OpaqueType; }
176             // impl AutoTrait for OpaqueType {}
177             ty::Foreign(did) => (
178                 LocalImpl::Allow,
179                 if did.is_local() {
180                     NonlocalImpl::Allow
181                 } else {
182                     NonlocalImpl::DisallowBecauseNonlocal
183                 },
184             ),
185 
186             // impl AutoTrait for dyn Trait {}
187             ty::Dynamic(..) => (
188                 LocalImpl::Disallow { problematic_kind: "trait object" },
189                 NonlocalImpl::DisallowOther,
190             ),
191 
192             // impl<T> AutoTrait for T {}
193             // impl<T: ?Sized> AutoTrait for T {}
194             ty::Param(..) => (
195                 if self_ty.is_sized(tcx, tcx.param_env(def_id)) {
196                     LocalImpl::Allow
197                 } else {
198                     LocalImpl::Disallow { problematic_kind: "generic type" }
199                 },
200                 NonlocalImpl::DisallowOther,
201             ),
202 
203             ty::Alias(kind, _) => {
204                 let problematic_kind = match kind {
205                     // trait Id { type This: ?Sized; }
206                     // impl<T: ?Sized> Id for T {
207                     //     type This = T;
208                     // }
209                     // impl<T: ?Sized> AutoTrait for <T as Id>::This {}
210                     AliasKind::Projection => "associated type",
211                     // type Foo = (impl Sized, bool)
212                     // impl AutoTrait for Foo {}
213                     AliasKind::Weak => "type alias",
214                     // type Opaque = impl Trait;
215                     // impl AutoTrait for Opaque {}
216                     AliasKind::Opaque => "opaque type",
217                     // ```
218                     // struct S<T>(T);
219                     // impl<T: ?Sized> S<T> {
220                     //     type This = T;
221                     // }
222                     // impl<T: ?Sized> AutoTrait for S<T>::This {}
223                     // ```
224                     // FIXME(inherent_associated_types): The example code above currently leads to a cycle
225                     AliasKind::Inherent => "associated type",
226                 };
227                 (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
228             }
229 
230             ty::Bool
231             | ty::Char
232             | ty::Int(..)
233             | ty::Uint(..)
234             | ty::Float(..)
235             | ty::Str
236             | ty::Array(..)
237             | ty::Slice(..)
238             | ty::RawPtr(..)
239             | ty::Ref(..)
240             | ty::FnDef(..)
241             | ty::FnPtr(..)
242             | ty::Never
243             | ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
244 
245             ty::Closure(..)
246             | ty::Generator(..)
247             | ty::GeneratorWitness(..)
248             | ty::GeneratorWitnessMIR(..)
249             | ty::Bound(..)
250             | ty::Placeholder(..)
251             | ty::Infer(..) => {
252                 let sp = tcx.def_span(def_id);
253                 span_bug!(sp, "weird self type for autotrait impl")
254             }
255 
256             ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
257         };
258 
259         if trait_def_id.is_local() {
260             match local_impl {
261                 LocalImpl::Allow => {}
262                 LocalImpl::Disallow { problematic_kind } => {
263                     let msg = format!(
264                         "traits with a default impl, like `{trait}`, \
265                                 cannot be implemented for {problematic_kind} `{self_ty}`",
266                         trait = tcx.def_path_str(trait_def_id),
267                     );
268                     let label = format!(
269                         "a trait object implements `{trait}` if and only if `{trait}` \
270                                 is one of the trait object's trait bounds",
271                         trait = tcx.def_path_str(trait_def_id),
272                     );
273                     let sp = tcx.def_span(def_id);
274                     let reported =
275                         struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit();
276                     return Err(reported);
277                 }
278             }
279         } else {
280             if let Some((msg, label)) = match nonlocal_impl {
281                 NonlocalImpl::Allow => None,
282                 NonlocalImpl::DisallowBecauseNonlocal => Some((
283                     format!(
284                         "cross-crate traits with a default impl, like `{}`, \
285                                 can only be implemented for a struct/enum type \
286                                 defined in the current crate",
287                         tcx.def_path_str(trait_def_id)
288                     ),
289                     "can't implement cross-crate trait for type in another crate",
290                 )),
291                 NonlocalImpl::DisallowOther => Some((
292                     format!(
293                         "cross-crate traits with a default impl, like `{}`, can \
294                                 only be implemented for a struct/enum type, not `{}`",
295                         tcx.def_path_str(trait_def_id),
296                         self_ty
297                     ),
298                     "can't implement cross-crate trait with a default impl for \
299                             non-struct/enum type",
300                 )),
301             } {
302                 let sp = tcx.def_span(def_id);
303                 let reported =
304                     struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
305                 return Err(reported);
306             }
307         }
308     }
309 
310     Ok(())
311 }
312 
emit_orphan_check_error<'tcx>( tcx: TyCtxt<'tcx>, sp: Span, full_impl_span: Span, trait_span: Span, trait_ref: ty::TraitRef<'tcx>, self_ty_span: Span, generics: &hir::Generics<'tcx>, err: traits::OrphanCheckErr<'tcx>, ) -> Result<!, ErrorGuaranteed>313 fn emit_orphan_check_error<'tcx>(
314     tcx: TyCtxt<'tcx>,
315     sp: Span,
316     full_impl_span: Span,
317     trait_span: Span,
318     trait_ref: ty::TraitRef<'tcx>,
319     self_ty_span: Span,
320     generics: &hir::Generics<'tcx>,
321     err: traits::OrphanCheckErr<'tcx>,
322 ) -> Result<!, ErrorGuaranteed> {
323     let self_ty = trait_ref.self_ty();
324     Err(match err {
325         traits::OrphanCheckErr::NonLocalInputType(tys) => {
326             let msg = match self_ty.kind() {
327                 ty::Adt(..) => "can be implemented for types defined outside of the crate",
328                 _ if self_ty.is_primitive() => "can be implemented for primitive types",
329                 _ => "can be implemented for arbitrary types",
330             };
331             let mut err = struct_span_err!(
332                 tcx.sess,
333                 sp,
334                 E0117,
335                 "only traits defined in the current crate {msg}"
336             );
337             err.span_label(sp, "impl doesn't use only types from inside the current crate");
338             for &(mut ty, is_target_ty) in &tys {
339                 ty = tcx.erase_regions(ty);
340                 ty = match ty.kind() {
341                     // Remove the type arguments from the output, as they are not relevant.
342                     // You can think of this as the reverse of `resolve_vars_if_possible`.
343                     // That way if we had `Vec<MyType>`, we will properly attribute the
344                     // problem to `Vec<T>` and avoid confusing the user if they were to see
345                     // `MyType` in the error.
346                     ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()),
347                     _ => ty,
348                 };
349                 let msg = |ty: &str, postfix: &str| {
350                     format!("{ty} is not defined in the current crate{postfix}")
351                 };
352 
353                 let this = |name: &str| {
354                     if !trait_ref.def_id.is_local() && !is_target_ty {
355                         msg("this", &format!(" because this is a foreign trait"))
356                     } else {
357                         msg("this", &format!(" because {name} are always foreign"))
358                     }
359                 };
360                 let msg = match &ty.kind() {
361                     ty::Slice(_) => this("slices"),
362                     ty::Array(..) => this("arrays"),
363                     ty::Tuple(..) => this("tuples"),
364                     ty::Alias(ty::Opaque, ..) => {
365                         "type alias impl trait is treated as if it were foreign, \
366                         because its hidden type could be from a foreign crate"
367                             .to_string()
368                     }
369                     ty::RawPtr(ptr_ty) => {
370                         emit_newtype_suggestion_for_raw_ptr(
371                             full_impl_span,
372                             self_ty,
373                             self_ty_span,
374                             ptr_ty,
375                             &mut err,
376                         );
377 
378                         msg(&format!("`{ty}`"), " because raw pointers are always foreign")
379                     }
380                     _ => msg(&format!("`{ty}`"), ""),
381                 };
382 
383                 if is_target_ty {
384                     // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
385                     err.span_label(self_ty_span, msg);
386                 } else {
387                     // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
388                     err.span_label(trait_span, msg);
389                 }
390             }
391             err.note("define and implement a trait or new type instead");
392             err.emit()
393         }
394         traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
395             let mut sp = sp;
396             for param in generics.params {
397                 if param.name.ident().to_string() == param_ty.to_string() {
398                     sp = param.span;
399                 }
400             }
401 
402             match local_type {
403                 Some(local_type) => struct_span_err!(
404                     tcx.sess,
405                     sp,
406                     E0210,
407                     "type parameter `{}` must be covered by another type \
408                     when it appears before the first local type (`{}`)",
409                     param_ty,
410                     local_type
411                 )
412                 .span_label(
413                     sp,
414                     format!(
415                         "type parameter `{}` must be covered by another type \
416                     when it appears before the first local type (`{}`)",
417                         param_ty, local_type
418                     ),
419                 )
420                 .note(
421                     "implementing a foreign trait is only possible if at \
422                         least one of the types for which it is implemented is local, \
423                         and no uncovered type parameters appear before that first \
424                         local type",
425                 )
426                 .note(
427                     "in this case, 'before' refers to the following order: \
428                         `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
429                         where `T0` is the first and `Tn` is the last",
430                 )
431                 .emit(),
432                 None => struct_span_err!(
433                     tcx.sess,
434                     sp,
435                     E0210,
436                     "type parameter `{}` must be used as the type parameter for some \
437                     local type (e.g., `MyStruct<{}>`)",
438                     param_ty,
439                     param_ty
440                 )
441                 .span_label(
442                     sp,
443                     format!(
444                         "type parameter `{}` must be used as the type parameter for some \
445                     local type",
446                         param_ty,
447                     ),
448                 )
449                 .note(
450                     "implementing a foreign trait is only possible if at \
451                         least one of the types for which it is implemented is local",
452                 )
453                 .note(
454                     "only traits defined in the current crate can be \
455                         implemented for a type parameter",
456                 )
457                 .emit(),
458             }
459         }
460     })
461 }
462 
emit_newtype_suggestion_for_raw_ptr( full_impl_span: Span, self_ty: Ty<'_>, self_ty_span: Span, ptr_ty: &ty::TypeAndMut<'_>, diag: &mut Diagnostic, )463 fn emit_newtype_suggestion_for_raw_ptr(
464     full_impl_span: Span,
465     self_ty: Ty<'_>,
466     self_ty_span: Span,
467     ptr_ty: &ty::TypeAndMut<'_>,
468     diag: &mut Diagnostic,
469 ) {
470     if !self_ty.has_param() {
471         let mut_key = ptr_ty.mutbl.prefix_str();
472         let msg_sugg = "consider introducing a new wrapper type".to_owned();
473         let sugg = vec![
474             (
475                 full_impl_span.shrink_to_lo(),
476                 format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty),
477             ),
478             (self_ty_span, "WrapperType".to_owned()),
479         ];
480         diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect);
481     }
482 }
483 
484 /// Lint impls of auto traits if they are likely to have
485 /// unsound or surprising effects on auto impls.
lint_auto_trait_impl<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, impl_def_id: LocalDefId, )486 fn lint_auto_trait_impl<'tcx>(
487     tcx: TyCtxt<'tcx>,
488     trait_ref: ty::TraitRef<'tcx>,
489     impl_def_id: LocalDefId,
490 ) {
491     assert_eq!(trait_ref.substs.len(), 1);
492     let self_ty = trait_ref.self_ty();
493     let (self_type_did, substs) = match self_ty.kind() {
494         ty::Adt(def, substs) => (def.did(), substs),
495         _ => {
496             // FIXME: should also lint for stuff like `&i32` but
497             // considering that auto traits are unstable, that
498             // isn't too important for now as this only affects
499             // crates using `nightly`, and std.
500             return;
501         }
502     };
503 
504     // Impls which completely cover a given root type are fine as they
505     // disable auto impls entirely. So only lint if the substs
506     // are not a permutation of the identity substs.
507     let Err(arg) = tcx.uses_unique_generic_params(substs, CheckRegions::No) else {
508         // ok
509         return;
510     };
511 
512     // Ideally:
513     //
514     // - compute the requirements for the auto impl candidate
515     // - check whether these are implied by the non covering impls
516     // - if not, emit the lint
517     //
518     // What we do here is a bit simpler:
519     //
520     // - badly check if an auto impl candidate definitely does not apply
521     //   for the given simplified type
522     // - if so, do not lint
523     if fast_reject_auto_impl(tcx, trait_ref.def_id, self_ty) {
524         // ok
525         return;
526     }
527 
528     tcx.struct_span_lint_hir(
529         lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
530         tcx.hir().local_def_id_to_hir_id(impl_def_id),
531         tcx.def_span(impl_def_id),
532         DelayDm(|| {
533             format!(
534                 "cross-crate traits with a default impl, like `{}`, \
535                          should not be specialized",
536                 tcx.def_path_str(trait_ref.def_id),
537             )
538         }),
539         |lint| {
540             let item_span = tcx.def_span(self_type_did);
541             let self_descr = tcx.def_descr(self_type_did);
542             match arg {
543                 ty::util::NotUniqueParam::DuplicateParam(arg) => {
544                     lint.note(format!("`{}` is mentioned multiple times", arg));
545                 }
546                 ty::util::NotUniqueParam::NotParam(arg) => {
547                     lint.note(format!("`{}` is not a generic parameter", arg));
548                 }
549             }
550             lint.span_note(
551                 item_span,
552                 format!(
553                     "try using the same sequence of generic parameters as the {} definition",
554                     self_descr,
555                 ),
556             )
557         },
558     );
559 }
560 
fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>) -> bool561 fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>) -> bool {
562     struct DisableAutoTraitVisitor<'tcx> {
563         tcx: TyCtxt<'tcx>,
564         trait_def_id: DefId,
565         self_ty_root: Ty<'tcx>,
566         seen: FxHashSet<DefId>,
567     }
568 
569     impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for DisableAutoTraitVisitor<'tcx> {
570         type BreakTy = ();
571         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
572             let tcx = self.tcx;
573             if t != self.self_ty_root {
574                 for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) {
575                     match tcx.impl_polarity(impl_def_id) {
576                         ImplPolarity::Negative => return ControlFlow::Break(()),
577                         ImplPolarity::Reservation => {}
578                         // FIXME(@lcnr): That's probably not good enough, idk
579                         //
580                         // We might just want to take the rustdoc code and somehow avoid
581                         // explicit impls for `Self`.
582                         ImplPolarity::Positive => return ControlFlow::Continue(()),
583                     }
584                 }
585             }
586 
587             match t.kind() {
588                 ty::Adt(def, substs) if def.is_phantom_data() => substs.visit_with(self),
589                 ty::Adt(def, substs) => {
590                     // @lcnr: This is the only place where cycles can happen. We avoid this
591                     // by only visiting each `DefId` once.
592                     //
593                     // This will be is incorrect in subtle cases, but I don't care :)
594                     if self.seen.insert(def.did()) {
595                         for ty in def.all_fields().map(|field| field.ty(tcx, substs)) {
596                             ty.visit_with(self)?;
597                         }
598                     }
599 
600                     ControlFlow::Continue(())
601                 }
602                 _ => t.super_visit_with(self),
603             }
604         }
605     }
606 
607     let self_ty_root = match self_ty.kind() {
608         ty::Adt(def, _) => {
609             Ty::new_adt(tcx, *def, InternalSubsts::identity_for_item(tcx, def.did()))
610         }
611         _ => unimplemented!("unexpected self ty {:?}", self_ty),
612     };
613 
614     self_ty_root
615         .visit_with(&mut DisableAutoTraitVisitor {
616             tcx,
617             self_ty_root,
618             trait_def_id,
619             seen: FxHashSet::default(),
620         })
621         .is_break()
622 }
623