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