• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Check properties that are required by built-in traits and set
2 //! up data structures required by type-checking/codegen.
3 
4 use crate::errors::{
5     ConstParamTyImplOnNonAdt, CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem,
6 };
7 use rustc_data_structures::fx::FxHashSet;
8 use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan};
9 use rustc_hir as hir;
10 use rustc_hir::def_id::{DefId, LocalDefId};
11 use rustc_hir::lang_items::LangItem;
12 use rustc_hir::ItemKind;
13 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
14 use rustc_infer::infer::{self, RegionResolutionError};
15 use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
16 use rustc_infer::traits::Obligation;
17 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
18 use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
19 use rustc_span::Span;
20 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
21 use rustc_trait_selection::traits::misc::{
22     type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
23     ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
24 };
25 use rustc_trait_selection::traits::ObligationCtxt;
26 use rustc_trait_selection::traits::{self, ObligationCause};
27 use std::collections::BTreeMap;
28 
check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId)29 pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
30     let lang_items = tcx.lang_items();
31     Checker { tcx, trait_def_id }
32         .check(lang_items.drop_trait(), visit_implementation_of_drop)
33         .check(lang_items.copy_trait(), visit_implementation_of_copy)
34         .check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty)
35         .check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
36         .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
37 }
38 
39 struct Checker<'tcx> {
40     tcx: TyCtxt<'tcx>,
41     trait_def_id: DefId,
42 }
43 
44 impl<'tcx> Checker<'tcx> {
check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self where F: FnMut(TyCtxt<'tcx>, LocalDefId),45     fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
46     where
47         F: FnMut(TyCtxt<'tcx>, LocalDefId),
48     {
49         if Some(self.trait_def_id) == trait_def_id {
50             for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
51                 f(self.tcx, impl_def_id);
52             }
53         }
54         self
55     }
56 }
57 
visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId)58 fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
59     // Destructors only work on local ADT types.
60     match tcx.type_of(impl_did).subst_identity().kind() {
61         ty::Adt(def, _) if def.did().is_local() => return,
62         ty::Error(_) => return,
63         _ => {}
64     }
65 
66     let impl_ = tcx.hir().expect_item(impl_did).expect_impl();
67 
68     tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span });
69 }
70 
visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId)71 fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
72     debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
73 
74     let self_type = tcx.type_of(impl_did).subst_identity();
75     debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
76 
77     let param_env = tcx.param_env(impl_did);
78     assert!(!self_type.has_escaping_bound_vars());
79 
80     debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
81 
82     let span = match tcx.hir().expect_item(impl_did).expect_impl() {
83         hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
84         hir::Impl { self_ty, .. } => self_ty.span,
85     };
86 
87     let cause = traits::ObligationCause::misc(span, impl_did);
88     match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
89         Ok(()) => {}
90         Err(CopyImplementationError::InfringingFields(fields)) => {
91             infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
92         }
93         Err(CopyImplementationError::NotAnAdt) => {
94             tcx.sess.emit_err(CopyImplOnNonAdt { span });
95         }
96         Err(CopyImplementationError::HasDestructor) => {
97             tcx.sess.emit_err(CopyImplOnTypeWithDtor { span });
98         }
99     }
100 }
101 
visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId)102 fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
103     let self_type = tcx.type_of(impl_did).subst_identity();
104     assert!(!self_type.has_escaping_bound_vars());
105 
106     let param_env = tcx.param_env(impl_did);
107 
108     let span = match tcx.hir().expect_item(impl_did).expect_impl() {
109         hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
110         impl_ => impl_.self_ty.span,
111     };
112 
113     let cause = traits::ObligationCause::misc(span, impl_did);
114     match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
115         Ok(()) => {}
116         Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
117             infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
118         }
119         Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
120             tcx.sess.emit_err(ConstParamTyImplOnNonAdt { span });
121         }
122     }
123 }
124 
visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId)125 fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
126     debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
127 
128     // Just compute this for the side-effects, in particular reporting
129     // errors; other parts of the code may demand it for the info of
130     // course.
131     let span = tcx.def_span(impl_did);
132     tcx.at(span).coerce_unsized_info(impl_did);
133 }
134 
visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDefId)135 fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
136     debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
137 
138     let span = tcx.def_span(impl_did);
139 
140     let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
141 
142     let source = tcx.type_of(impl_did).subst_identity();
143     assert!(!source.has_escaping_bound_vars());
144     let target = {
145         let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
146         assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
147 
148         trait_ref.substs.type_at(1)
149     };
150 
151     debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
152 
153     let param_env = tcx.param_env(impl_did);
154 
155     let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);
156 
157     let infcx = tcx.infer_ctxt().build();
158     let cause = ObligationCause::misc(span, impl_did);
159 
160     use rustc_type_ir::sty::TyKind::*;
161     match (source.kind(), target.kind()) {
162         (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
163             if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok()
164                 && mutbl_a == *mutbl_b => {}
165         (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
166         (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
167             if def_a.is_struct() && def_b.is_struct() =>
168         {
169             if def_a != def_b {
170                 let source_path = tcx.def_path_str(def_a.did());
171                 let target_path = tcx.def_path_str(def_b.did());
172 
173                 create_err(&format!(
174                     "the trait `DispatchFromDyn` may only be implemented \
175                             for a coercion between structures with the same \
176                             definition; expected `{}`, found `{}`",
177                     source_path, target_path,
178                 ))
179                 .emit();
180 
181                 return;
182             }
183 
184             if def_a.repr().c() || def_a.repr().packed() {
185                 create_err(
186                     "structs implementing `DispatchFromDyn` may not have \
187                          `#[repr(packed)]` or `#[repr(C)]`",
188                 )
189                 .emit();
190             }
191 
192             let fields = &def_a.non_enum_variant().fields;
193 
194             let coerced_fields = fields
195                 .iter()
196                 .filter(|field| {
197                     let ty_a = field.ty(tcx, substs_a);
198                     let ty_b = field.ty(tcx, substs_b);
199 
200                     if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
201                         if layout.is_zst() && layout.align.abi.bytes() == 1 {
202                             // ignore ZST fields with alignment of 1 byte
203                             return false;
204                         }
205                     }
206 
207                     if let Ok(ok) =
208                         infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b)
209                     {
210                         if ok.obligations.is_empty() {
211                             create_err(
212                                 "the trait `DispatchFromDyn` may only be implemented \
213                                  for structs containing the field being coerced, \
214                                  ZST fields with 1 byte alignment, and nothing else",
215                             )
216                             .note(format!(
217                                 "extra field `{}` of type `{}` is not allowed",
218                                 field.name, ty_a,
219                             ))
220                             .emit();
221 
222                             return false;
223                         }
224                     }
225 
226                     return true;
227                 })
228                 .collect::<Vec<_>>();
229 
230             if coerced_fields.is_empty() {
231                 create_err(
232                     "the trait `DispatchFromDyn` may only be implemented \
233                         for a coercion between structures with a single field \
234                         being coerced, none found",
235                 )
236                 .emit();
237             } else if coerced_fields.len() > 1 {
238                 create_err("implementing the `DispatchFromDyn` trait requires multiple coercions")
239                     .note(
240                         "the trait `DispatchFromDyn` may only be implemented \
241                             for a coercion between structures with a single field \
242                             being coerced",
243                     )
244                     .note(format!(
245                         "currently, {} fields need coercions: {}",
246                         coerced_fields.len(),
247                         coerced_fields
248                             .iter()
249                             .map(|field| {
250                                 format!(
251                                     "`{}` (`{}` to `{}`)",
252                                     field.name,
253                                     field.ty(tcx, substs_a),
254                                     field.ty(tcx, substs_b),
255                                 )
256                             })
257                             .collect::<Vec<_>>()
258                             .join(", ")
259                     ))
260                     .emit();
261             } else {
262                 let ocx = ObligationCtxt::new(&infcx);
263                 for field in coerced_fields {
264                     ocx.register_obligation(Obligation::new(
265                         tcx,
266                         cause.clone(),
267                         param_env,
268                         ty::TraitRef::new(
269                             tcx,
270                             dispatch_from_dyn_trait,
271                             [field.ty(tcx, substs_a), field.ty(tcx, substs_b)],
272                         ),
273                     ));
274                 }
275                 let errors = ocx.select_all_or_error();
276                 if !errors.is_empty() {
277                     infcx.err_ctxt().report_fulfillment_errors(&errors);
278                 }
279 
280                 // Finally, resolve all regions.
281                 let outlives_env = OutlivesEnvironment::new(param_env);
282                 let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
283             }
284         }
285         _ => {
286             create_err(
287                 "the trait `DispatchFromDyn` may only be implemented \
288                     for a coercion between structures",
289             )
290             .emit();
291         }
292     }
293 }
294 
coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> CoerceUnsizedInfo295 pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> CoerceUnsizedInfo {
296     debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
297     let span = tcx.def_span(impl_did);
298 
299     let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
300 
301     let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
302 
303     let source = tcx.type_of(impl_did).subst_identity();
304     let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
305     assert_eq!(trait_ref.def_id, coerce_unsized_trait);
306     let target = trait_ref.substs.type_at(1);
307     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
308 
309     let param_env = tcx.param_env(impl_did);
310     assert!(!source.has_escaping_bound_vars());
311 
312     let err_info = CoerceUnsizedInfo { custom_kind: None };
313 
314     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
315 
316     let infcx = tcx.infer_ctxt().build();
317     let cause = ObligationCause::misc(span, impl_did);
318     let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
319                        mt_b: ty::TypeAndMut<'tcx>,
320                        mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
321         if mt_a.mutbl < mt_b.mutbl {
322             infcx
323                 .err_ctxt()
324                 .report_mismatched_types(
325                     &cause,
326                     mk_ptr(mt_b.ty),
327                     target,
328                     ty::error::TypeError::Mutability,
329                 )
330                 .emit();
331         }
332         (mt_a.ty, mt_b.ty, unsize_trait, None)
333     };
334     let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
335         (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
336             infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
337             let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
338             let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
339             check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
340         }
341 
342         (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
343             let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
344             check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
345         }
346 
347         (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => {
348             check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
349         }
350 
351         (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b))
352             if def_a.is_struct() && def_b.is_struct() =>
353         {
354             if def_a != def_b {
355                 let source_path = tcx.def_path_str(def_a.did());
356                 let target_path = tcx.def_path_str(def_b.did());
357                 struct_span_err!(
358                     tcx.sess,
359                     span,
360                     E0377,
361                     "the trait `CoerceUnsized` may only be implemented \
362                            for a coercion between structures with the same \
363                            definition; expected `{}`, found `{}`",
364                     source_path,
365                     target_path
366                 )
367                 .emit();
368                 return err_info;
369             }
370 
371             // Here we are considering a case of converting
372             // `S<P0...Pn>` to `S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
373             // which acts like a pointer to `U`, but carries along some extra data of type `T`:
374             //
375             //     struct Foo<T, U> {
376             //         extra: T,
377             //         ptr: *mut U,
378             //     }
379             //
380             // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
381             // to `Foo<T, [i32]>`. That impl would look like:
382             //
383             //   impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
384             //
385             // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
386             // when this coercion occurs, we would be changing the
387             // field `ptr` from a thin pointer of type `*mut [i32;
388             // 3]` to a fat pointer of type `*mut [i32]` (with
389             // extra data `3`). **The purpose of this check is to
390             // make sure that we know how to do this conversion.**
391             //
392             // To check if this impl is legal, we would walk down
393             // the fields of `Foo` and consider their types with
394             // both substitutes. We are looking to find that
395             // exactly one (non-phantom) field has changed its
396             // type, which we will expect to be the pointer that
397             // is becoming fat (we could probably generalize this
398             // to multiple thin pointers of the same type becoming
399             // fat, but we don't). In this case:
400             //
401             // - `extra` has type `T` before and type `T` after
402             // - `ptr` has type `*mut U` before and type `*mut V` after
403             //
404             // Since just one field changed, we would then check
405             // that `*mut U: CoerceUnsized<*mut V>` is implemented
406             // (in other words, that we know how to do this
407             // conversion). This will work out because `U:
408             // Unsize<V>`, and we have a builtin rule that `*mut
409             // U` can be coerced to `*mut V` if `U: Unsize<V>`.
410             let fields = &def_a.non_enum_variant().fields;
411             let diff_fields = fields
412                 .iter_enumerated()
413                 .filter_map(|(i, f)| {
414                     let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
415 
416                     if tcx.type_of(f.did).subst_identity().is_phantom_data() {
417                         // Ignore PhantomData fields
418                         return None;
419                     }
420 
421                     // Ignore fields that aren't changed; it may
422                     // be that we could get away with subtyping or
423                     // something more accepting, but we use
424                     // equality because we want to be able to
425                     // perform this check without computing
426                     // variance where possible. (This is because
427                     // we may have to evaluate constraint
428                     // expressions in the course of execution.)
429                     // See e.g., #41936.
430                     if let Ok(ok) = infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, a, b) {
431                         if ok.obligations.is_empty() {
432                             return None;
433                         }
434                     }
435 
436                     // Collect up all fields that were significantly changed
437                     // i.e., those that contain T in coerce_unsized T -> U
438                     Some((i, a, b))
439                 })
440                 .collect::<Vec<_>>();
441 
442             if diff_fields.is_empty() {
443                 struct_span_err!(
444                     tcx.sess,
445                     span,
446                     E0374,
447                     "the trait `CoerceUnsized` may only be implemented \
448                            for a coercion between structures with one field \
449                            being coerced, none found"
450                 )
451                 .emit();
452                 return err_info;
453             } else if diff_fields.len() > 1 {
454                 let item = tcx.hir().expect_item(impl_did);
455                 let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
456                     t.path.span
457                 } else {
458                     tcx.def_span(impl_did)
459                 };
460 
461                 struct_span_err!(
462                     tcx.sess,
463                     span,
464                     E0375,
465                     "implementing the trait \
466                                                 `CoerceUnsized` requires multiple \
467                                                 coercions"
468                 )
469                 .note(
470                     "`CoerceUnsized` may only be implemented for \
471                           a coercion between structures with one field being coerced",
472                 )
473                 .note(format!(
474                     "currently, {} fields need coercions: {}",
475                     diff_fields.len(),
476                     diff_fields
477                         .iter()
478                         .map(|&(i, a, b)| { format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) })
479                         .collect::<Vec<_>>()
480                         .join(", ")
481                 ))
482                 .span_label(span, "requires multiple coercions")
483                 .emit();
484                 return err_info;
485             }
486 
487             let (i, a, b) = diff_fields[0];
488             let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
489             (a, b, coerce_unsized_trait, Some(kind))
490         }
491 
492         _ => {
493             struct_span_err!(
494                 tcx.sess,
495                 span,
496                 E0376,
497                 "the trait `CoerceUnsized` may only be implemented \
498                        for a coercion between structures"
499             )
500             .emit();
501             return err_info;
502         }
503     };
504 
505     // Register an obligation for `A: Trait<B>`.
506     let ocx = ObligationCtxt::new(&infcx);
507     let cause = traits::ObligationCause::misc(span, impl_did);
508     let obligation = Obligation::new(
509         tcx,
510         cause,
511         param_env,
512         ty::TraitRef::new(tcx, trait_def_id, [source, target]),
513     );
514     ocx.register_obligation(obligation);
515     let errors = ocx.select_all_or_error();
516     if !errors.is_empty() {
517         infcx.err_ctxt().report_fulfillment_errors(&errors);
518     }
519 
520     // Finally, resolve all regions.
521     let outlives_env = OutlivesEnvironment::new(param_env);
522     let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
523 
524     CoerceUnsizedInfo { custom_kind: kind }
525 }
526 
infringing_fields_error( tcx: TyCtxt<'_>, fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>, lang_item: LangItem, impl_did: LocalDefId, impl_span: Span, ) -> ErrorGuaranteed527 fn infringing_fields_error(
528     tcx: TyCtxt<'_>,
529     fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>,
530     lang_item: LangItem,
531     impl_did: LocalDefId,
532     impl_span: Span,
533 ) -> ErrorGuaranteed {
534     let trait_did = tcx.require_lang_item(lang_item, Some(impl_span));
535 
536     let trait_name = tcx.def_path_str(trait_did);
537 
538     let mut err = struct_span_err!(
539         tcx.sess,
540         impl_span,
541         E0204,
542         "the trait `{trait_name}` cannot be implemented for this type"
543     );
544 
545     // We'll try to suggest constraining type parameters to fulfill the requirements of
546     // their `Copy` implementation.
547     let mut errors: BTreeMap<_, Vec<_>> = Default::default();
548     let mut bounds = vec![];
549 
550     let mut seen_tys = FxHashSet::default();
551 
552     for (field, ty, reason) in fields {
553         // Only report an error once per type.
554         if !seen_tys.insert(ty) {
555             continue;
556         }
557 
558         let field_span = tcx.def_span(field.did);
559         err.span_label(field_span, format!("this field does not implement `{trait_name}`"));
560 
561         match reason {
562             InfringingFieldsReason::Fulfill(fulfillment_errors) => {
563                 for error in fulfillment_errors {
564                     let error_predicate = error.obligation.predicate;
565                     // Only note if it's not the root obligation, otherwise it's trivial and
566                     // should be self-explanatory (i.e. a field literally doesn't implement Copy).
567 
568                     // FIXME: This error could be more descriptive, especially if the error_predicate
569                     // contains a foreign type or if it's a deeply nested type...
570                     if error_predicate != error.root_obligation.predicate {
571                         errors
572                             .entry((ty.to_string(), error_predicate.to_string()))
573                             .or_default()
574                             .push(error.obligation.cause.span);
575                     }
576                     if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
577                         trait_ref,
578                         polarity: ty::ImplPolarity::Positive,
579                         ..
580                     })) = error_predicate.kind().skip_binder()
581                     {
582                         let ty = trait_ref.self_ty();
583                         if let ty::Param(_) = ty.kind() {
584                             bounds.push((
585                                 format!("{ty}"),
586                                 trait_ref.print_only_trait_path().to_string(),
587                                 Some(trait_ref.def_id),
588                             ));
589                         }
590                     }
591                 }
592             }
593             InfringingFieldsReason::Regions(region_errors) => {
594                 for error in region_errors {
595                     let ty = ty.to_string();
596                     match error {
597                         RegionResolutionError::ConcreteFailure(origin, a, b) => {
598                             let predicate = format!("{b}: {a}");
599                             errors
600                                 .entry((ty.clone(), predicate.clone()))
601                                 .or_default()
602                                 .push(origin.span());
603                             if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
604                                         bounds.push((b.to_string(), a.to_string(), None));
605                                     }
606                         }
607                         RegionResolutionError::GenericBoundFailure(origin, a, b) => {
608                             let predicate = format!("{a}: {b}");
609                             errors
610                                 .entry((ty.clone(), predicate.clone()))
611                                 .or_default()
612                                 .push(origin.span());
613                             if let infer::region_constraints::GenericKind::Param(_) = a {
614                                 bounds.push((a.to_string(), b.to_string(), None));
615                             }
616                         }
617                         _ => continue,
618                     }
619                 }
620             }
621         }
622     }
623     for ((ty, error_predicate), spans) in errors {
624         let span: MultiSpan = spans.into();
625         err.span_note(
626             span,
627             format!("the `{trait_name}` impl for `{ty}` requires that `{error_predicate}`"),
628         );
629     }
630     suggest_constraining_type_params(
631         tcx,
632         tcx.hir().get_generics(impl_did).expect("impls always have generics"),
633         &mut err,
634         bounds
635             .iter()
636             .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
637         None,
638     );
639 
640     err.emit()
641 }
642