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