]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/coherence/orphan.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / compiler / rustc_typeck / 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;
dfeec247 5use rustc_errors::struct_span_err;
064997fb 6use rustc_errors::{Diagnostic, ErrorGuaranteed};
dfeec247 7use rustc_hir as hir;
74b04a01 8use rustc_infer::infer::TyCtxtInferExt;
04454e1e 9use rustc_middle::ty::subst::GenericArgKind;
923072b8
FG
10use rustc_middle::ty::subst::InternalSubsts;
11use rustc_middle::ty::util::IgnoreRegions;
12use rustc_middle::ty::{
064997fb 13 self, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
923072b8 14};
5099ac24
FG
15use rustc_session::lint;
16use rustc_span::def_id::{DefId, LocalDefId};
3c0e092e 17use rustc_span::Span;
ba9703b0 18use rustc_trait_selection::traits;
5099ac24 19use std::ops::ControlFlow;
60c5eb7d 20
064997fb
FG
21#[instrument(skip(tcx), level = "debug")]
22pub(crate) fn orphan_check_impl(
23 tcx: TyCtxt<'_>,
24 impl_def_id: LocalDefId,
25) -> Result<(), ErrorGuaranteed> {
26 let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
27 if let Some(err) = trait_ref.error_reported() {
28 return Err(err);
29 }
5099ac24 30
064997fb
FG
31 let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
32 if tcx.trait_is_auto(trait_ref.def_id) {
33 lint_auto_trait_impl(tcx, trait_ref, impl_def_id);
3c0e092e 34 }
064997fb
FG
35
36 ret
1a4d82fc
JJ
37}
38
064997fb
FG
39fn do_orphan_check_impl<'tcx>(
40 tcx: TyCtxt<'tcx>,
41 trait_ref: ty::TraitRef<'tcx>,
42 def_id: LocalDefId,
43) -> Result<(), ErrorGuaranteed> {
3c0e092e 44 let trait_def_id = trait_ref.def_id;
1a4d82fc 45
3c0e092e 46 let item = tcx.hir().item(hir::ItemId { def_id });
5e7ed085
FG
47 let hir::ItemKind::Impl(ref impl_) = item.kind else {
48 bug!("{:?} is not an impl: {:?}", def_id, item);
3c0e092e 49 };
064997fb 50 let sp = tcx.def_span(def_id);
3c0e092e 51 let tr = impl_.of_trait.as_ref().unwrap();
04454e1e
FG
52
53 // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
54 // and #84660 where it would otherwise allow unsoundness.
55 if trait_ref.has_opaque_types() {
56 trace!("{:#?}", item);
57 // First we find the opaque type in question.
58 for ty in trait_ref.substs {
59 for ty in ty.walk() {
60 let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue };
61 let ty::Opaque(def_id, _) = *ty.kind() else { continue };
62 trace!(?def_id);
63
64 // Then we search for mentions of the opaque type's type alias in the HIR
65 struct SpanFinder<'tcx> {
66 sp: Span,
67 def_id: DefId,
68 tcx: TyCtxt<'tcx>,
69 }
70 impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
71 #[instrument(level = "trace", skip(self, _id))]
72 fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
73 // You can't mention an opaque type directly, so we look for type aliases
74 if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
75 // And check if that type alias's type contains the opaque type we're looking for
76 for arg in self.tcx.type_of(def_id).walk() {
77 if let GenericArgKind::Type(ty) = arg.unpack() {
78 if let ty::Opaque(def_id, _) = *ty.kind() {
79 if def_id == self.def_id {
80 // Finally we update the span to the mention of the type alias
81 self.sp = path.span;
82 return;
83 }
84 }
85 }
86 }
87 }
88 hir::intravisit::walk_path(self, path)
89 }
90 }
91
92 let mut visitor = SpanFinder { sp, def_id, tcx };
93 hir::intravisit::walk_item(&mut visitor, item);
94 let reported = tcx
95 .sess
96 .struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait")
97 .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
98 .emit();
99 return Err(reported);
100 }
101 }
102 span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
103 }
104
3c0e092e
XL
105 match traits::orphan_check(tcx, item.def_id.to_def_id()) {
106 Ok(()) => {}
107 Err(err) => emit_orphan_check_error(
108 tcx,
109 sp,
064997fb 110 item.span,
3c0e092e 111 tr.path.span,
04454e1e 112 trait_ref.self_ty(),
3c0e092e
XL
113 impl_.self_ty.span,
114 &impl_.generics,
115 err,
116 )?,
117 }
118
119 // In addition to the above rules, we restrict impls of auto traits
120 // so that they can only be implemented on nominal types, such as structs,
121 // enums or foreign types. To see why this restriction exists, consider the
122 // following example (#22978). Imagine that crate A defines an auto trait
123 // `Foo` and a fn that operates on pairs of types:
124 //
125 // ```
126 // // Crate A
127 // auto trait Foo { }
128 // fn two_foos<A:Foo,B:Foo>(..) {
129 // one_foo::<(A,B)>(..)
130 // }
131 // fn one_foo<T:Foo>(..) { .. }
132 // ```
133 //
134 // This type-checks fine; in particular the fn
135 // `two_foos` is able to conclude that `(A,B):Foo`
136 // because `A:Foo` and `B:Foo`.
137 //
138 // Now imagine that crate B comes along and does the following:
139 //
140 // ```
141 // struct A { }
142 // struct B { }
143 // impl Foo for A { }
144 // impl Foo for B { }
145 // impl !Send for (A, B) { }
146 // ```
147 //
148 // This final impl is legal according to the orphan
149 // rules, but it invalidates the reasoning from
150 // `two_foos` above.
151 debug!(
152 "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
153 trait_ref,
154 trait_def_id,
155 tcx.trait_is_auto(trait_def_id)
156 );
157
158 if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
159 let self_ty = trait_ref.self_ty();
160 let opt_self_def_id = match *self_ty.kind() {
5e7ed085 161 ty::Adt(self_def, _) => Some(self_def.did()),
3c0e092e
XL
162 ty::Foreign(did) => Some(did),
163 _ => None,
164 };
60c5eb7d 165
3c0e092e
XL
166 let msg = match opt_self_def_id {
167 // We only want to permit nominal types, but not *all* nominal types.
168 // They must be local to the current crate, so that people
169 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
170 // `impl !Send for Box<SomethingLocalAndSend>`.
171 Some(self_def_id) => {
172 if self_def_id.is_local() {
173 None
174 } else {
175 Some((
176 format!(
177 "cross-crate traits with a default impl, like `{}`, \
178 can only be implemented for a struct/enum type \
179 defined in the current crate",
180 tcx.def_path_str(trait_def_id)
181 ),
182 "can't implement cross-crate trait for type in another crate",
183 ))
c34b1796 184 }
0bf4aa26 185 }
3c0e092e
XL
186 _ => Some((
187 format!(
188 "cross-crate traits with a default impl, like `{}`, can \
189 only be implemented for a struct/enum type, not `{}`",
190 tcx.def_path_str(trait_def_id),
191 self_ty
192 ),
193 "can't implement cross-crate trait with a default impl for \
194 non-struct/enum type",
195 )),
196 };
c34b1796 197
3c0e092e 198 if let Some((msg, label)) = msg {
5e7ed085
FG
199 let reported =
200 struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
201 return Err(reported);
3c0e092e
XL
202 }
203 }
204
3c0e092e
XL
205 Ok(())
206}
207
a2a8927a 208fn emit_orphan_check_error<'tcx>(
3c0e092e
XL
209 tcx: TyCtxt<'tcx>,
210 sp: Span,
064997fb 211 full_impl_span: Span,
3c0e092e 212 trait_span: Span,
04454e1e 213 self_ty: Ty<'tcx>,
3c0e092e
XL
214 self_ty_span: Span,
215 generics: &hir::Generics<'tcx>,
216 err: traits::OrphanCheckErr<'tcx>,
5e7ed085
FG
217) -> Result<!, ErrorGuaranteed> {
218 Err(match err {
3c0e092e 219 traits::OrphanCheckErr::NonLocalInputType(tys) => {
04454e1e
FG
220 let msg = match self_ty.kind() {
221 ty::Adt(..) => "can be implemented for types defined outside of the crate",
222 _ if self_ty.is_primitive() => "can be implemented for primitive types",
223 _ => "can be implemented for arbitrary types",
224 };
3c0e092e
XL
225 let mut err = struct_span_err!(
226 tcx.sess,
227 sp,
228 E0117,
04454e1e 229 "only traits defined in the current crate {msg}"
dfeec247 230 );
3c0e092e
XL
231 err.span_label(sp, "impl doesn't use only types from inside the current crate");
232 for (ty, is_target_ty) in &tys {
233 let mut ty = *ty;
234 tcx.infer_ctxt().enter(|infcx| {
235 // Remove the lifetimes unnecessary for this error.
236 ty = infcx.freshen(ty);
237 });
238 ty = match ty.kind() {
239 // Remove the type arguments from the output, as they are not relevant.
240 // You can think of this as the reverse of `resolve_vars_if_possible`.
241 // That way if we had `Vec<MyType>`, we will properly attribute the
242 // problem to `Vec<T>` and avoid confusing the user if they were to see
243 // `MyType` in the error.
5e7ed085 244 ty::Adt(def, _) => tcx.mk_adt(*def, ty::List::empty()),
3c0e092e 245 _ => ty,
0bf4aa26 246 };
3c0e092e
XL
247 let this = "this".to_string();
248 let (ty, postfix) = match &ty.kind() {
249 ty::Slice(_) => (this, " because slices are always foreign"),
250 ty::Array(..) => (this, " because arrays are always foreign"),
251 ty::Tuple(..) => (this, " because tuples are always foreign"),
064997fb
FG
252 ty::RawPtr(ptr_ty) => {
253 emit_newtype_suggestion_for_raw_ptr(
254 full_impl_span,
255 self_ty,
256 self_ty_span,
257 ptr_ty,
258 &mut err,
259 );
260
261 (format!("`{}`", ty), " because raw pointers are always foreign")
262 }
3c0e092e 263 _ => (format!("`{}`", ty), ""),
0bf4aa26 264 };
064997fb 265
3c0e092e
XL
266 let msg = format!("{} is not defined in the current crate{}", ty, postfix);
267 if *is_target_ty {
268 // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
269 err.span_label(self_ty_span, &msg);
270 } else {
271 // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
272 err.span_label(trait_span, &msg);
273 }
274 }
275 err.note("define and implement a trait or new type instead");
276 err.emit()
277 }
278 traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
279 let mut sp = sp;
280 for param in generics.params {
281 if param.name.ident().to_string() == param_ty.to_string() {
282 sp = param.span;
1a4d82fc 283 }
c34b1796 284 }
1b1a35ee 285
3c0e092e
XL
286 match local_type {
287 Some(local_type) => struct_span_err!(
288 tcx.sess,
289 sp,
290 E0210,
291 "type parameter `{}` must be covered by another type \
292 when it appears before the first local type (`{}`)",
293 param_ty,
294 local_type
295 )
296 .span_label(
297 sp,
298 format!(
299 "type parameter `{}` must be covered by another type \
300 when it appears before the first local type (`{}`)",
301 param_ty, local_type
302 ),
303 )
304 .note(
305 "implementing a foreign trait is only possible if at \
306 least one of the types for which it is implemented is local, \
307 and no uncovered type parameters appear before that first \
308 local type",
309 )
310 .note(
311 "in this case, 'before' refers to the following order: \
312 `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
313 where `T0` is the first and `Tn` is the last",
314 )
315 .emit(),
316 None => struct_span_err!(
317 tcx.sess,
318 sp,
319 E0210,
320 "type parameter `{}` must be used as the type parameter for some \
321 local type (e.g., `MyStruct<{}>`)",
322 param_ty,
323 param_ty
324 )
325 .span_label(
326 sp,
327 format!(
328 "type parameter `{}` must be used as the type parameter for some \
329 local type",
330 param_ty,
331 ),
332 )
333 .note(
334 "implementing a foreign trait is only possible if at \
335 least one of the types for which it is implemented is local",
336 )
337 .note(
338 "only traits defined in the current crate can be \
339 implemented for a type parameter",
340 )
341 .emit(),
1b1a35ee 342 }
1a4d82fc 343 }
5e7ed085 344 })
1a4d82fc 345}
5099ac24 346
064997fb
FG
347fn emit_newtype_suggestion_for_raw_ptr(
348 full_impl_span: Span,
349 self_ty: Ty<'_>,
350 self_ty_span: Span,
351 ptr_ty: &ty::TypeAndMut<'_>,
352 diag: &mut Diagnostic,
353) {
354 if !self_ty.needs_subst() {
355 let mut_key = if ptr_ty.mutbl == rustc_middle::mir::Mutability::Mut { "mut " } else { "" };
356 let msg_sugg = "consider introducing a new wrapper type".to_owned();
357 let sugg = vec![
358 (
359 full_impl_span.shrink_to_lo(),
360 format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty),
361 ),
362 (self_ty_span, "WrapperType".to_owned()),
363 ];
364 diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect);
365 }
366}
367
5099ac24
FG
368/// Lint impls of auto traits if they are likely to have
369/// unsound or surprising effects on auto impls.
064997fb
FG
370fn lint_auto_trait_impl<'tcx>(
371 tcx: TyCtxt<'tcx>,
372 trait_ref: ty::TraitRef<'tcx>,
373 impl_def_id: LocalDefId,
374) {
375 if tcx.impl_polarity(impl_def_id) != ImplPolarity::Positive {
376 return;
377 }
5099ac24 378
064997fb
FG
379 assert_eq!(trait_ref.substs.len(), 1);
380 let self_ty = trait_ref.self_ty();
381 let (self_type_did, substs) = match self_ty.kind() {
382 ty::Adt(def, substs) => (def.did(), substs),
383 _ => {
384 // FIXME: should also lint for stuff like `&i32` but
385 // considering that auto traits are unstable, that
386 // isn't too important for now as this only affects
387 // crates using `nightly`, and std.
5099ac24
FG
388 return;
389 }
064997fb 390 };
5099ac24 391
064997fb
FG
392 // Impls which completely cover a given root type are fine as they
393 // disable auto impls entirely. So only lint if the substs
394 // are not a permutation of the identity substs.
395 let Err(arg) = tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) else {
396 // ok
397 return;
398 };
5099ac24 399
064997fb
FG
400 // Ideally:
401 //
402 // - compute the requirements for the auto impl candidate
403 // - check whether these are implied by the non covering impls
404 // - if not, emit the lint
405 //
406 // What we do here is a bit simpler:
407 //
408 // - badly check if an auto impl candidate definitely does not apply
409 // for the given simplified type
410 // - if so, do not lint
411 if fast_reject_auto_impl(tcx, trait_ref.def_id, self_ty) {
412 // ok
413 return;
5099ac24
FG
414 }
415
064997fb
FG
416 tcx.struct_span_lint_hir(
417 lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
418 tcx.hir().local_def_id_to_hir_id(impl_def_id),
419 tcx.def_span(impl_def_id),
420 |err| {
421 let item_span = tcx.def_span(self_type_did);
422 let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
423 let mut err = err.build(&format!(
424 "cross-crate traits with a default impl, like `{}`, \
5099ac24 425 should not be specialized",
064997fb
FG
426 tcx.def_path_str(trait_ref.def_id),
427 ));
428 match arg {
429 ty::util::NotUniqueParam::DuplicateParam(arg) => {
430 err.note(&format!("`{}` is mentioned multiple times", arg));
923072b8 431 }
064997fb
FG
432 ty::util::NotUniqueParam::NotParam(arg) => {
433 err.note(&format!("`{}` is not a generic parameter", arg));
434 }
435 }
436 err.span_note(
437 item_span,
438 &format!(
439 "try using the same sequence of generic parameters as the {} definition",
440 self_descr,
441 ),
442 );
443 err.emit();
444 },
445 );
5099ac24
FG
446}
447
448fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>) -> bool {
449 struct DisableAutoTraitVisitor<'tcx> {
450 tcx: TyCtxt<'tcx>,
451 trait_def_id: DefId,
452 self_ty_root: Ty<'tcx>,
453 seen: FxHashSet<DefId>,
454 }
455
456 impl<'tcx> TypeVisitor<'tcx> for DisableAutoTraitVisitor<'tcx> {
457 type BreakTy = ();
458 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
459 let tcx = self.tcx;
460 if t != self.self_ty_root {
461 for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) {
462 match tcx.impl_polarity(impl_def_id) {
463 ImplPolarity::Negative => return ControlFlow::BREAK,
464 ImplPolarity::Reservation => {}
465 // FIXME(@lcnr): That's probably not good enough, idk
466 //
467 // We might just want to take the rustdoc code and somehow avoid
468 // explicit impls for `Self`.
469 ImplPolarity::Positive => return ControlFlow::CONTINUE,
470 }
471 }
472 }
473
474 match t.kind() {
923072b8 475 ty::Adt(def, substs) if def.is_phantom_data() => substs.visit_with(self),
5099ac24
FG
476 ty::Adt(def, substs) => {
477 // @lcnr: This is the only place where cycles can happen. We avoid this
478 // by only visiting each `DefId` once.
479 //
480 // This will be is incorrect in subtle cases, but I don't care :)
5e7ed085 481 if self.seen.insert(def.did()) {
5099ac24
FG
482 for ty in def.all_fields().map(|field| field.ty(tcx, substs)) {
483 ty.visit_with(self)?;
484 }
485 }
486
487 ControlFlow::CONTINUE
488 }
489 _ => t.super_visit_with(self),
490 }
491 }
492 }
493
494 let self_ty_root = match self_ty.kind() {
5e7ed085 495 ty::Adt(def, _) => tcx.mk_adt(*def, InternalSubsts::identity_for_item(tcx, def.did())),
5099ac24
FG
496 _ => unimplemented!("unexpected self ty {:?}", self_ty),
497 };
498
499 self_ty_root
500 .visit_with(&mut DisableAutoTraitVisitor {
501 tcx,
502 self_ty_root,
503 trait_def_id,
504 seen: FxHashSet::default(),
505 })
506 .is_break()
507}