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