1 //! Orphan checker: every impl either implements a trait defined in this
2 //! crate or pertains to a type defined in this crate.
4 use rustc_data_structures::fx::FxHashSet;
5 use rustc_errors::struct_span_err;
6 use rustc_errors::{Diagnostic, ErrorGuaranteed};
8 use rustc_middle::ty::subst::GenericArgKind;
9 use rustc_middle::ty::subst::InternalSubsts;
10 use rustc_middle::ty::util::IgnoreRegions;
11 use rustc_middle::ty::{
12 self, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
14 use rustc_session::lint;
15 use rustc_span::def_id::{DefId, LocalDefId};
17 use rustc_trait_selection::traits;
18 use std::ops::ControlFlow;
20 #[instrument(skip(tcx), level = "debug")]
21 pub(crate) fn orphan_check_impl(
23 impl_def_id: LocalDefId,
24 ) -> Result<(), ErrorGuaranteed> {
25 let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
26 if let Some(err) = trait_ref.error_reported() {
30 let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
31 if tcx.trait_is_auto(trait_ref.def_id) {
32 lint_auto_trait_impl(tcx, trait_ref, impl_def_id);
38 fn do_orphan_check_impl<'tcx>(
40 trait_ref: ty::TraitRef<'tcx>,
42 ) -> Result<(), ErrorGuaranteed> {
43 let trait_def_id = trait_ref.def_id;
45 let item = tcx.hir().item(hir::ItemId { def_id });
46 let hir::ItemKind::Impl(ref impl_) = item.kind else {
47 bug!("{:?} is not an impl: {:?}", def_id, item);
49 let sp = tcx.def_span(def_id);
50 let tr = impl_.of_trait.as_ref().unwrap();
52 // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
53 // and #84660 where it would otherwise allow unsoundness.
54 if trait_ref.has_opaque_types() {
55 trace!("{:#?}", item);
56 // First we find the opaque type in question.
57 for ty in trait_ref.substs {
59 let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue };
60 let ty::Opaque(def_id, _) = *ty.kind() else { continue };
63 // Then we search for mentions of the opaque type's type alias in the HIR
64 struct SpanFinder<'tcx> {
69 impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
70 #[instrument(level = "trace", skip(self, _id))]
71 fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
72 // You can't mention an opaque type directly, so we look for type aliases
73 if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
74 // And check if that type alias's type contains the opaque type we're looking for
75 for arg in self.tcx.type_of(def_id).walk() {
76 if let GenericArgKind::Type(ty) = arg.unpack() {
77 if let ty::Opaque(def_id, _) = *ty.kind() {
78 if def_id == self.def_id {
79 // Finally we update the span to the mention of the type alias
87 hir::intravisit::walk_path(self, path)
91 let mut visitor = SpanFinder { sp, def_id, tcx };
92 hir::intravisit::walk_item(&mut visitor, item);
95 .struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait")
96 .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
101 span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
104 match traits::orphan_check(tcx, item.def_id.to_def_id()) {
106 Err(err) => emit_orphan_check_error(
118 // In addition to the above rules, we restrict impls of auto traits
119 // so that they can only be implemented on nominal types, such as structs,
120 // enums or foreign types. To see why this restriction exists, consider the
121 // following example (#22978). Imagine that crate A defines an auto trait
122 // `Foo` and a fn that operates on pairs of types:
126 // auto trait Foo { }
127 // fn two_foos<A:Foo,B:Foo>(..) {
128 // one_foo::<(A,B)>(..)
130 // fn one_foo<T:Foo>(..) { .. }
133 // This type-checks fine; in particular the fn
134 // `two_foos` is able to conclude that `(A,B):Foo`
135 // because `A:Foo` and `B:Foo`.
137 // Now imagine that crate B comes along and does the following:
142 // impl Foo for A { }
143 // impl Foo for B { }
144 // impl !Send for (A, B) { }
147 // This final impl is legal according to the orphan
148 // rules, but it invalidates the reasoning from
151 "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
154 tcx.trait_is_auto(trait_def_id)
157 if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
158 let self_ty = trait_ref.self_ty();
159 let opt_self_def_id = match *self_ty.kind() {
160 ty::Adt(self_def, _) => Some(self_def.did()),
161 ty::Foreign(did) => Some(did),
165 let msg = match opt_self_def_id {
166 // We only want to permit nominal types, but not *all* nominal types.
167 // They must be local to the current crate, so that people
168 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
169 // `impl !Send for Box<SomethingLocalAndSend>`.
170 Some(self_def_id) => {
171 if self_def_id.is_local() {
176 "cross-crate traits with a default impl, like `{}`, \
177 can only be implemented for a struct/enum type \
178 defined in the current crate",
179 tcx.def_path_str(trait_def_id)
181 "can't implement cross-crate trait for type in another crate",
187 "cross-crate traits with a default impl, like `{}`, can \
188 only be implemented for a struct/enum type, not `{}`",
189 tcx.def_path_str(trait_def_id),
192 "can't implement cross-crate trait with a default impl for \
193 non-struct/enum type",
197 if let Some((msg, label)) = msg {
199 struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
200 return Err(reported);
207 fn emit_orphan_check_error<'tcx>(
210 full_impl_span: Span,
214 generics: &hir::Generics<'tcx>,
215 err: traits::OrphanCheckErr<'tcx>,
216 ) -> Result<!, ErrorGuaranteed> {
218 traits::OrphanCheckErr::NonLocalInputType(tys) => {
219 let msg = match self_ty.kind() {
220 ty::Adt(..) => "can be implemented for types defined outside of the crate",
221 _ if self_ty.is_primitive() => "can be implemented for primitive types",
222 _ => "can be implemented for arbitrary types",
224 let mut err = struct_span_err!(
228 "only traits defined in the current crate {msg}"
230 err.span_label(sp, "impl doesn't use only types from inside the current crate");
231 for &(mut ty, is_target_ty) in &tys {
232 ty = tcx.erase_regions(ty);
233 ty = match ty.kind() {
234 // Remove the type arguments from the output, as they are not relevant.
235 // You can think of this as the reverse of `resolve_vars_if_possible`.
236 // That way if we had `Vec<MyType>`, we will properly attribute the
237 // problem to `Vec<T>` and avoid confusing the user if they were to see
238 // `MyType` in the error.
239 ty::Adt(def, _) => tcx.mk_adt(*def, ty::List::empty()),
242 let this = "this".to_string();
243 let (ty, postfix) = match &ty.kind() {
244 ty::Slice(_) => (this, " because slices are always foreign"),
245 ty::Array(..) => (this, " because arrays are always foreign"),
246 ty::Tuple(..) => (this, " because tuples are always foreign"),
247 ty::RawPtr(ptr_ty) => {
248 emit_newtype_suggestion_for_raw_ptr(
256 (format!("`{}`", ty), " because raw pointers are always foreign")
258 _ => (format!("`{}`", ty), ""),
261 let msg = format!("{} is not defined in the current crate{}", ty, postfix);
263 // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
264 err.span_label(self_ty_span, &msg);
266 // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
267 err.span_label(trait_span, &msg);
270 err.note("define and implement a trait or new type instead");
273 traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
275 for param in generics.params {
276 if param.name.ident().to_string() == param_ty.to_string() {
282 Some(local_type) => struct_span_err!(
286 "type parameter `{}` must be covered by another type \
287 when it appears before the first local type (`{}`)",
294 "type parameter `{}` must be covered by another type \
295 when it appears before the first local type (`{}`)",
300 "implementing a foreign trait is only possible if at \
301 least one of the types for which it is implemented is local, \
302 and no uncovered type parameters appear before that first \
306 "in this case, 'before' refers to the following order: \
307 `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
308 where `T0` is the first and `Tn` is the last",
311 None => struct_span_err!(
315 "type parameter `{}` must be used as the type parameter for some \
316 local type (e.g., `MyStruct<{}>`)",
323 "type parameter `{}` must be used as the type parameter for some \
329 "implementing a foreign trait is only possible if at \
330 least one of the types for which it is implemented is local",
333 "only traits defined in the current crate can be \
334 implemented for a type parameter",
342 fn emit_newtype_suggestion_for_raw_ptr(
343 full_impl_span: Span,
346 ptr_ty: &ty::TypeAndMut<'_>,
347 diag: &mut Diagnostic,
349 if !self_ty.needs_subst() {
350 let mut_key = if ptr_ty.mutbl == rustc_middle::mir::Mutability::Mut { "mut " } else { "" };
351 let msg_sugg = "consider introducing a new wrapper type".to_owned();
354 full_impl_span.shrink_to_lo(),
355 format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty),
357 (self_ty_span, "WrapperType".to_owned()),
359 diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect);
363 /// Lint impls of auto traits if they are likely to have
364 /// unsound or surprising effects on auto impls.
365 fn lint_auto_trait_impl<'tcx>(
367 trait_ref: ty::TraitRef<'tcx>,
368 impl_def_id: LocalDefId,
370 if tcx.impl_polarity(impl_def_id) != ImplPolarity::Positive {
374 assert_eq!(trait_ref.substs.len(), 1);
375 let self_ty = trait_ref.self_ty();
376 let (self_type_did, substs) = match self_ty.kind() {
377 ty::Adt(def, substs) => (def.did(), substs),
379 // FIXME: should also lint for stuff like `&i32` but
380 // considering that auto traits are unstable, that
381 // isn't too important for now as this only affects
382 // crates using `nightly`, and std.
387 // Impls which completely cover a given root type are fine as they
388 // disable auto impls entirely. So only lint if the substs
389 // are not a permutation of the identity substs.
390 let Err(arg) = tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) else {
397 // - compute the requirements for the auto impl candidate
398 // - check whether these are implied by the non covering impls
399 // - if not, emit the lint
401 // What we do here is a bit simpler:
403 // - badly check if an auto impl candidate definitely does not apply
404 // for the given simplified type
405 // - if so, do not lint
406 if fast_reject_auto_impl(tcx, trait_ref.def_id, self_ty) {
411 tcx.struct_span_lint_hir(
412 lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
413 tcx.hir().local_def_id_to_hir_id(impl_def_id),
414 tcx.def_span(impl_def_id),
416 let item_span = tcx.def_span(self_type_did);
417 let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
418 let mut err = err.build(&format!(
419 "cross-crate traits with a default impl, like `{}`, \
420 should not be specialized",
421 tcx.def_path_str(trait_ref.def_id),
424 ty::util::NotUniqueParam::DuplicateParam(arg) => {
425 err.note(&format!("`{}` is mentioned multiple times", arg));
427 ty::util::NotUniqueParam::NotParam(arg) => {
428 err.note(&format!("`{}` is not a generic parameter", arg));
434 "try using the same sequence of generic parameters as the {} definition",
443 fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>) -> bool {
444 struct DisableAutoTraitVisitor<'tcx> {
447 self_ty_root: Ty<'tcx>,
448 seen: FxHashSet<DefId>,
451 impl<'tcx> TypeVisitor<'tcx> for DisableAutoTraitVisitor<'tcx> {
453 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
455 if t != self.self_ty_root {
456 for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) {
457 match tcx.impl_polarity(impl_def_id) {
458 ImplPolarity::Negative => return ControlFlow::BREAK,
459 ImplPolarity::Reservation => {}
460 // FIXME(@lcnr): That's probably not good enough, idk
462 // We might just want to take the rustdoc code and somehow avoid
463 // explicit impls for `Self`.
464 ImplPolarity::Positive => return ControlFlow::CONTINUE,
470 ty::Adt(def, substs) if def.is_phantom_data() => substs.visit_with(self),
471 ty::Adt(def, substs) => {
472 // @lcnr: This is the only place where cycles can happen. We avoid this
473 // by only visiting each `DefId` once.
475 // This will be is incorrect in subtle cases, but I don't care :)
476 if self.seen.insert(def.did()) {
477 for ty in def.all_fields().map(|field| field.ty(tcx, substs)) {
478 ty.visit_with(self)?;
482 ControlFlow::CONTINUE
484 _ => t.super_visit_with(self),
489 let self_ty_root = match self_ty.kind() {
490 ty::Adt(def, _) => tcx.mk_adt(*def, InternalSubsts::identity_for_item(tcx, def.did())),
491 _ => unimplemented!("unexpected self ty {:?}", self_ty),
495 .visit_with(&mut DisableAutoTraitVisitor {
499 seen: FxHashSet::default(),