]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_hir_analysis/src/coherence/orphan.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_hir_analysis / src / coherence / orphan.rs
CommitLineData
1a4d82fc
JJ
1//! Orphan checker: every impl either implements a trait defined in this
2//! crate or pertains to a type defined in this crate.
3
5099ac24 4use rustc_data_structures::fx::FxHashSet;
2b03887a 5use rustc_errors::{struct_span_err, DelayDm};
064997fb 6use rustc_errors::{Diagnostic, ErrorGuaranteed};
dfeec247 7use rustc_hir as hir;
923072b8
FG
8use rustc_middle::ty::subst::InternalSubsts;
9use rustc_middle::ty::util::IgnoreRegions;
10use rustc_middle::ty::{
9ffffee4
FG
11 self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
12 TypeVisitor,
923072b8 13};
5099ac24
FG
14use rustc_session::lint;
15use rustc_span::def_id::{DefId, LocalDefId};
3c0e092e 16use rustc_span::Span;
ba9703b0 17use rustc_trait_selection::traits;
5099ac24 18use std::ops::ControlFlow;
60c5eb7d 19
064997fb
FG
20#[instrument(skip(tcx), level = "debug")]
21pub(crate) fn orphan_check_impl(
22 tcx: TyCtxt<'_>,
23 impl_def_id: LocalDefId,
24) -> Result<(), ErrorGuaranteed> {
9c376795 25 let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
487cf647 26 trait_ref.error_reported()?;
5099ac24 27
064997fb
FG
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);
3c0e092e 31 }
064997fb
FG
32
33 ret
1a4d82fc
JJ
34}
35
064997fb
FG
36fn do_orphan_check_impl<'tcx>(
37 tcx: TyCtxt<'tcx>,
38 trait_ref: ty::TraitRef<'tcx>,
39 def_id: LocalDefId,
40) -> Result<(), ErrorGuaranteed> {
3c0e092e 41 let trait_def_id = trait_ref.def_id;
1a4d82fc 42
9ffffee4 43 match traits::orphan_check(tcx, def_id.to_def_id()) {
3c0e092e 44 Ok(()) => {}
9ffffee4
FG
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 }
3c0e092e
XL
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 { }
9ffffee4 92 // impl !Foo for (A, B) { }
3c0e092e
XL
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
9ffffee4 105 if tcx.trait_is_auto(trait_def_id) {
3c0e092e 106 let self_ty = trait_ref.self_ty();
60c5eb7d 107
9ffffee4
FG
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
3c0e092e 170 } else {
9ffffee4
FG
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 // trait Id { type This: ?Sized; }
204 // impl<T: ?Sized> Id for T {
205 // type This = T;
206 // }
207 // impl<T: ?Sized> AutoTrait for <T as Id>::This {}
208 ty::Alias(AliasKind::Projection, _) => (
209 LocalImpl::Disallow { problematic_kind: "associated type" },
210 NonlocalImpl::DisallowOther,
211 ),
212
213 // type Opaque = impl Trait;
214 // impl AutoTrait for Opaque {}
215 ty::Alias(AliasKind::Opaque, _) => (
216 LocalImpl::Disallow { problematic_kind: "opaque type" },
217 NonlocalImpl::DisallowOther,
218 ),
219
220 ty::Bool
221 | ty::Char
222 | ty::Int(..)
223 | ty::Uint(..)
224 | ty::Float(..)
225 | ty::Str
226 | ty::Array(..)
227 | ty::Slice(..)
228 | ty::RawPtr(..)
229 | ty::Ref(..)
230 | ty::FnDef(..)
231 | ty::FnPtr(..)
232 | ty::Never
233 | ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
234
235 ty::Closure(..)
236 | ty::Generator(..)
237 | ty::GeneratorWitness(..)
238 | ty::GeneratorWitnessMIR(..)
239 | ty::Bound(..)
240 | ty::Placeholder(..)
241 | ty::Infer(..) => {
242 let sp = tcx.def_span(def_id);
243 span_bug!(sp, "weird self type for autotrait impl")
0bf4aa26 244 }
9ffffee4
FG
245
246 ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
3c0e092e 247 };
c34b1796 248
9ffffee4
FG
249 if trait_def_id.is_local() {
250 match local_impl {
251 LocalImpl::Allow => {}
252 LocalImpl::Disallow { problematic_kind } => {
253 let msg = format!(
254 "traits with a default impl, like `{trait}`, \
255 cannot be implemented for {problematic_kind} `{self_ty}`",
256 trait = tcx.def_path_str(trait_def_id),
257 );
258 let label = format!(
259 "a trait object implements `{trait}` if and only if `{trait}` \
260 is one of the trait object's trait bounds",
261 trait = tcx.def_path_str(trait_def_id),
262 );
263 let sp = tcx.def_span(def_id);
264 let reported =
265 struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit();
266 return Err(reported);
267 }
268 }
269 } else {
270 if let Some((msg, label)) = match nonlocal_impl {
271 NonlocalImpl::Allow => None,
272 NonlocalImpl::DisallowBecauseNonlocal => Some((
273 format!(
274 "cross-crate traits with a default impl, like `{}`, \
275 can only be implemented for a struct/enum type \
276 defined in the current crate",
277 tcx.def_path_str(trait_def_id)
278 ),
279 "can't implement cross-crate trait for type in another crate",
280 )),
281 NonlocalImpl::DisallowOther => Some((
282 format!(
283 "cross-crate traits with a default impl, like `{}`, can \
284 only be implemented for a struct/enum type, not `{}`",
285 tcx.def_path_str(trait_def_id),
286 self_ty
287 ),
288 "can't implement cross-crate trait with a default impl for \
289 non-struct/enum type",
290 )),
291 } {
292 let sp = tcx.def_span(def_id);
293 let reported =
294 struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
295 return Err(reported);
296 }
3c0e092e
XL
297 }
298 }
299
3c0e092e
XL
300 Ok(())
301}
302
a2a8927a 303fn emit_orphan_check_error<'tcx>(
3c0e092e
XL
304 tcx: TyCtxt<'tcx>,
305 sp: Span,
064997fb 306 full_impl_span: Span,
3c0e092e 307 trait_span: Span,
9c376795 308 trait_ref: ty::TraitRef<'tcx>,
3c0e092e
XL
309 self_ty_span: Span,
310 generics: &hir::Generics<'tcx>,
311 err: traits::OrphanCheckErr<'tcx>,
5e7ed085 312) -> Result<!, ErrorGuaranteed> {
9c376795 313 let self_ty = trait_ref.self_ty();
5e7ed085 314 Err(match err {
3c0e092e 315 traits::OrphanCheckErr::NonLocalInputType(tys) => {
04454e1e
FG
316 let msg = match self_ty.kind() {
317 ty::Adt(..) => "can be implemented for types defined outside of the crate",
318 _ if self_ty.is_primitive() => "can be implemented for primitive types",
319 _ => "can be implemented for arbitrary types",
320 };
3c0e092e
XL
321 let mut err = struct_span_err!(
322 tcx.sess,
323 sp,
324 E0117,
04454e1e 325 "only traits defined in the current crate {msg}"
dfeec247 326 );
3c0e092e 327 err.span_label(sp, "impl doesn't use only types from inside the current crate");
2b03887a
FG
328 for &(mut ty, is_target_ty) in &tys {
329 ty = tcx.erase_regions(ty);
3c0e092e
XL
330 ty = match ty.kind() {
331 // Remove the type arguments from the output, as they are not relevant.
332 // You can think of this as the reverse of `resolve_vars_if_possible`.
333 // That way if we had `Vec<MyType>`, we will properly attribute the
334 // problem to `Vec<T>` and avoid confusing the user if they were to see
335 // `MyType` in the error.
5e7ed085 336 ty::Adt(def, _) => tcx.mk_adt(*def, ty::List::empty()),
3c0e092e 337 _ => ty,
0bf4aa26 338 };
9c376795
FG
339 let msg = |ty: &str, postfix: &str| {
340 format!("{ty} is not defined in the current crate{postfix}")
341 };
342
343 let this = |name: &str| {
344 if !trait_ref.def_id.is_local() && !is_target_ty {
345 msg("this", &format!(" because this is a foreign trait"))
346 } else {
347 msg("this", &format!(" because {name} are always foreign"))
348 }
349 };
350 let msg = match &ty.kind() {
351 ty::Slice(_) => this("slices"),
352 ty::Array(..) => this("arrays"),
353 ty::Tuple(..) => this("tuples"),
354 ty::Alias(ty::Opaque, ..) => {
355 "type alias impl trait is treated as if it were foreign, \
356 because its hidden type could be from a foreign crate"
357 .to_string()
358 }
064997fb
FG
359 ty::RawPtr(ptr_ty) => {
360 emit_newtype_suggestion_for_raw_ptr(
361 full_impl_span,
362 self_ty,
363 self_ty_span,
364 ptr_ty,
365 &mut err,
366 );
367
9c376795 368 msg(&format!("`{ty}`"), " because raw pointers are always foreign")
064997fb 369 }
9c376795 370 _ => msg(&format!("`{ty}`"), ""),
0bf4aa26 371 };
064997fb 372
2b03887a 373 if is_target_ty {
3c0e092e
XL
374 // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
375 err.span_label(self_ty_span, &msg);
376 } else {
377 // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
378 err.span_label(trait_span, &msg);
379 }
380 }
381 err.note("define and implement a trait or new type instead");
382 err.emit()
383 }
384 traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
385 let mut sp = sp;
386 for param in generics.params {
387 if param.name.ident().to_string() == param_ty.to_string() {
388 sp = param.span;
1a4d82fc 389 }
c34b1796 390 }
1b1a35ee 391
3c0e092e
XL
392 match local_type {
393 Some(local_type) => struct_span_err!(
394 tcx.sess,
395 sp,
396 E0210,
397 "type parameter `{}` must be covered by another type \
398 when it appears before the first local type (`{}`)",
399 param_ty,
400 local_type
401 )
402 .span_label(
403 sp,
404 format!(
405 "type parameter `{}` must be covered by another type \
406 when it appears before the first local type (`{}`)",
407 param_ty, local_type
408 ),
409 )
410 .note(
411 "implementing a foreign trait is only possible if at \
412 least one of the types for which it is implemented is local, \
413 and no uncovered type parameters appear before that first \
414 local type",
415 )
416 .note(
417 "in this case, 'before' refers to the following order: \
418 `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
419 where `T0` is the first and `Tn` is the last",
420 )
421 .emit(),
422 None => struct_span_err!(
423 tcx.sess,
424 sp,
425 E0210,
426 "type parameter `{}` must be used as the type parameter for some \
427 local type (e.g., `MyStruct<{}>`)",
428 param_ty,
429 param_ty
430 )
431 .span_label(
432 sp,
433 format!(
434 "type parameter `{}` must be used as the type parameter for some \
435 local type",
436 param_ty,
437 ),
438 )
439 .note(
440 "implementing a foreign trait is only possible if at \
441 least one of the types for which it is implemented is local",
442 )
443 .note(
444 "only traits defined in the current crate can be \
445 implemented for a type parameter",
446 )
447 .emit(),
1b1a35ee 448 }
1a4d82fc 449 }
5e7ed085 450 })
1a4d82fc 451}
5099ac24 452
064997fb
FG
453fn emit_newtype_suggestion_for_raw_ptr(
454 full_impl_span: Span,
455 self_ty: Ty<'_>,
456 self_ty_span: Span,
457 ptr_ty: &ty::TypeAndMut<'_>,
458 diag: &mut Diagnostic,
459) {
460 if !self_ty.needs_subst() {
487cf647 461 let mut_key = ptr_ty.mutbl.prefix_str();
064997fb
FG
462 let msg_sugg = "consider introducing a new wrapper type".to_owned();
463 let sugg = vec![
464 (
465 full_impl_span.shrink_to_lo(),
466 format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty),
467 ),
468 (self_ty_span, "WrapperType".to_owned()),
469 ];
470 diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect);
471 }
472}
473
5099ac24
FG
474/// Lint impls of auto traits if they are likely to have
475/// unsound or surprising effects on auto impls.
064997fb
FG
476fn lint_auto_trait_impl<'tcx>(
477 tcx: TyCtxt<'tcx>,
478 trait_ref: ty::TraitRef<'tcx>,
479 impl_def_id: LocalDefId,
480) {
481 if tcx.impl_polarity(impl_def_id) != ImplPolarity::Positive {
482 return;
483 }
5099ac24 484
064997fb
FG
485 assert_eq!(trait_ref.substs.len(), 1);
486 let self_ty = trait_ref.self_ty();
487 let (self_type_did, substs) = match self_ty.kind() {
488 ty::Adt(def, substs) => (def.did(), substs),
489 _ => {
490 // FIXME: should also lint for stuff like `&i32` but
491 // considering that auto traits are unstable, that
492 // isn't too important for now as this only affects
493 // crates using `nightly`, and std.
5099ac24
FG
494 return;
495 }
064997fb 496 };
5099ac24 497
064997fb
FG
498 // Impls which completely cover a given root type are fine as they
499 // disable auto impls entirely. So only lint if the substs
500 // are not a permutation of the identity substs.
501 let Err(arg) = tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) else {
502 // ok
503 return;
504 };
5099ac24 505
064997fb
FG
506 // Ideally:
507 //
508 // - compute the requirements for the auto impl candidate
509 // - check whether these are implied by the non covering impls
510 // - if not, emit the lint
511 //
512 // What we do here is a bit simpler:
513 //
514 // - badly check if an auto impl candidate definitely does not apply
515 // for the given simplified type
516 // - if so, do not lint
517 if fast_reject_auto_impl(tcx, trait_ref.def_id, self_ty) {
518 // ok
519 return;
5099ac24
FG
520 }
521
064997fb
FG
522 tcx.struct_span_lint_hir(
523 lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
524 tcx.hir().local_def_id_to_hir_id(impl_def_id),
525 tcx.def_span(impl_def_id),
2b03887a
FG
526 DelayDm(|| {
527 format!(
064997fb 528 "cross-crate traits with a default impl, like `{}`, \
5099ac24 529 should not be specialized",
064997fb 530 tcx.def_path_str(trait_ref.def_id),
2b03887a
FG
531 )
532 }),
533 |lint| {
534 let item_span = tcx.def_span(self_type_did);
9ffffee4 535 let self_descr = tcx.def_descr(self_type_did);
064997fb
FG
536 match arg {
537 ty::util::NotUniqueParam::DuplicateParam(arg) => {
2b03887a 538 lint.note(&format!("`{}` is mentioned multiple times", arg));
923072b8 539 }
064997fb 540 ty::util::NotUniqueParam::NotParam(arg) => {
2b03887a 541 lint.note(&format!("`{}` is not a generic parameter", arg));
064997fb
FG
542 }
543 }
2b03887a 544 lint.span_note(
064997fb
FG
545 item_span,
546 &format!(
547 "try using the same sequence of generic parameters as the {} definition",
548 self_descr,
549 ),
2b03887a 550 )
064997fb
FG
551 },
552 );
5099ac24
FG
553}
554
555fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>) -> bool {
556 struct DisableAutoTraitVisitor<'tcx> {
557 tcx: TyCtxt<'tcx>,
558 trait_def_id: DefId,
559 self_ty_root: Ty<'tcx>,
560 seen: FxHashSet<DefId>,
561 }
562
9ffffee4 563 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for DisableAutoTraitVisitor<'tcx> {
5099ac24
FG
564 type BreakTy = ();
565 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
566 let tcx = self.tcx;
567 if t != self.self_ty_root {
568 for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) {
569 match tcx.impl_polarity(impl_def_id) {
9c376795 570 ImplPolarity::Negative => return ControlFlow::Break(()),
5099ac24
FG
571 ImplPolarity::Reservation => {}
572 // FIXME(@lcnr): That's probably not good enough, idk
573 //
574 // We might just want to take the rustdoc code and somehow avoid
575 // explicit impls for `Self`.
9c376795 576 ImplPolarity::Positive => return ControlFlow::Continue(()),
5099ac24
FG
577 }
578 }
579 }
580
581 match t.kind() {
923072b8 582 ty::Adt(def, substs) if def.is_phantom_data() => substs.visit_with(self),
5099ac24
FG
583 ty::Adt(def, substs) => {
584 // @lcnr: This is the only place where cycles can happen. We avoid this
585 // by only visiting each `DefId` once.
586 //
587 // This will be is incorrect in subtle cases, but I don't care :)
5e7ed085 588 if self.seen.insert(def.did()) {
5099ac24
FG
589 for ty in def.all_fields().map(|field| field.ty(tcx, substs)) {
590 ty.visit_with(self)?;
591 }
592 }
593
9c376795 594 ControlFlow::Continue(())
5099ac24
FG
595 }
596 _ => t.super_visit_with(self),
597 }
598 }
599 }
600
601 let self_ty_root = match self_ty.kind() {
5e7ed085 602 ty::Adt(def, _) => tcx.mk_adt(*def, InternalSubsts::identity_for_item(tcx, def.did())),
5099ac24
FG
603 _ => unimplemented!("unexpected self ty {:?}", self_ty),
604 };
605
606 self_ty_root
607 .visit_with(&mut DisableAutoTraitVisitor {
608 tcx,
609 self_ty_root,
610 trait_def_id,
611 seen: FxHashSet::default(),
612 })
613 .is_break()
614}