]>
Commit | Line | Data |
---|---|---|
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 | 4 | use rustc_data_structures::fx::FxHashSet; |
2b03887a | 5 | use rustc_errors::{struct_span_err, DelayDm}; |
064997fb | 6 | use rustc_errors::{Diagnostic, ErrorGuaranteed}; |
dfeec247 | 7 | use rustc_hir as hir; |
923072b8 FG |
8 | use rustc_middle::ty::subst::InternalSubsts; |
9 | use rustc_middle::ty::util::IgnoreRegions; | |
10 | use rustc_middle::ty::{ | |
9ffffee4 FG |
11 | self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, |
12 | TypeVisitor, | |
923072b8 | 13 | }; |
5099ac24 FG |
14 | use rustc_session::lint; |
15 | use rustc_span::def_id::{DefId, LocalDefId}; | |
3c0e092e | 16 | use rustc_span::Span; |
ba9703b0 | 17 | use rustc_trait_selection::traits; |
5099ac24 | 18 | use std::ops::ControlFlow; |
60c5eb7d | 19 | |
064997fb FG |
20 | #[instrument(skip(tcx), level = "debug")] |
21 | pub(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 |
36 | fn 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 | 303 | fn 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 |
453 | fn 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 |
476 | fn 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 | ||
555 | fn 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 | } |