1use std::ops::ControlFlow;
8
9use rustc_errors::FatalError;
10use rustc_hir as hir;
11use rustc_hir::def_id::DefId;
12use rustc_middle::bug;
13use rustc_middle::query::Providers;
14use rustc_middle::ty::{
15 self, EarlyBinder, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
16 TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
17};
18use rustc_span::Span;
19use rustc_type_ir::elaborate;
20use smallvec::SmallVec;
21use tracing::{debug, instrument};
22
23use super::elaborate;
24use crate::infer::TyCtxtInferExt;
25pub use crate::traits::DynCompatibilityViolation;
26use crate::traits::query::evaluate_obligation::InferCtxtExt;
27use crate::traits::{MethodViolationCode, Obligation, ObligationCause, util};
28
29#[instrument(level = "debug", skip(tcx), ret)]
35pub fn hir_ty_lowering_dyn_compatibility_violations(
36 tcx: TyCtxt<'_>,
37 trait_def_id: DefId,
38) -> Vec<DynCompatibilityViolation> {
39 debug_assert!(tcx.generics_of(trait_def_id).has_self);
40 elaborate::supertrait_def_ids(tcx, trait_def_id)
41 .map(|def_id| predicates_reference_self(tcx, def_id, true))
42 .filter(|spans| !spans.is_empty())
43 .map(DynCompatibilityViolation::SupertraitSelf)
44 .collect()
45}
46
47fn dyn_compatibility_violations(
48 tcx: TyCtxt<'_>,
49 trait_def_id: DefId,
50) -> &'_ [DynCompatibilityViolation] {
51 debug_assert!(tcx.generics_of(trait_def_id).has_self);
52 debug!("dyn_compatibility_violations: {:?}", trait_def_id);
53 tcx.arena.alloc_from_iter(
54 elaborate::supertrait_def_ids(tcx, trait_def_id)
55 .flat_map(|def_id| dyn_compatibility_violations_for_trait(tcx, def_id)),
56 )
57}
58
59fn is_dyn_compatible(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
60 tcx.dyn_compatibility_violations(trait_def_id).is_empty()
61}
62
63pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool {
68 debug_assert!(tcx.generics_of(trait_def_id).has_self);
69 debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
70 if tcx.generics_require_sized_self(method.def_id) {
72 return false;
73 }
74
75 virtual_call_violations_for_method(tcx, trait_def_id, method).is_empty()
76}
77
78#[instrument(level = "debug", skip(tcx), ret)]
79fn dyn_compatibility_violations_for_trait(
80 tcx: TyCtxt<'_>,
81 trait_def_id: DefId,
82) -> Vec<DynCompatibilityViolation> {
83 let mut violations: Vec<_> = tcx
85 .associated_items(trait_def_id)
86 .in_definition_order()
87 .flat_map(|&item| dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, item))
88 .collect();
89
90 if trait_has_sized_self(tcx, trait_def_id) {
92 let spans = get_sized_bounds(tcx, trait_def_id);
94 violations.push(DynCompatibilityViolation::SizedSelf(spans));
95 }
96 let spans = predicates_reference_self(tcx, trait_def_id, false);
97 if !spans.is_empty() {
98 violations.push(DynCompatibilityViolation::SupertraitSelf(spans));
99 }
100 let spans = bounds_reference_self(tcx, trait_def_id);
101 if !spans.is_empty() {
102 violations.push(DynCompatibilityViolation::SupertraitSelf(spans));
103 }
104 let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id);
105 if !spans.is_empty() {
106 violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
107 }
108
109 violations
110}
111
112fn sized_trait_bound_spans<'tcx>(
113 tcx: TyCtxt<'tcx>,
114 bounds: hir::GenericBounds<'tcx>,
115) -> impl 'tcx + Iterator<Item = Span> {
116 bounds.iter().filter_map(move |b| match b {
117 hir::GenericBound::Trait(trait_ref)
118 if trait_has_sized_self(
119 tcx,
120 trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
121 ) =>
122 {
123 Some(trait_ref.span)
125 }
126 _ => None,
127 })
128}
129
130fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
131 tcx.hir()
132 .get_if_local(trait_def_id)
133 .and_then(|node| match node {
134 hir::Node::Item(hir::Item {
135 kind: hir::ItemKind::Trait(.., generics, bounds, _),
136 ..
137 }) => Some(
138 generics
139 .predicates
140 .iter()
141 .filter_map(|pred| {
142 match pred.kind {
143 hir::WherePredicateKind::BoundPredicate(pred)
144 if pred.bounded_ty.hir_id.owner.to_def_id() == trait_def_id =>
145 {
146 Some(sized_trait_bound_spans(tcx, pred.bounds))
149 }
150 _ => None,
151 }
152 })
153 .flatten()
154 .chain(sized_trait_bound_spans(tcx, bounds))
156 .collect::<SmallVec<[Span; 1]>>(),
157 ),
158 _ => None,
159 })
160 .unwrap_or_else(SmallVec::new)
161}
162
163fn predicates_reference_self(
164 tcx: TyCtxt<'_>,
165 trait_def_id: DefId,
166 supertraits_only: bool,
167) -> SmallVec<[Span; 1]> {
168 let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
169 let predicates = if supertraits_only {
170 tcx.explicit_super_predicates_of(trait_def_id).skip_binder()
171 } else {
172 tcx.predicates_of(trait_def_id).predicates
173 };
174 predicates
175 .iter()
176 .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp))
177 .filter_map(|(clause, sp)| {
178 predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::No)
183 })
184 .collect()
185}
186
187fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
188 tcx.associated_items(trait_def_id)
189 .in_definition_order()
190 .filter(|item| item.kind == ty::AssocKind::Type)
191 .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
192 .filter_map(|(clause, sp)| {
193 predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::Yes)
196 })
197 .collect()
198}
199
200fn predicate_references_self<'tcx>(
201 tcx: TyCtxt<'tcx>,
202 trait_def_id: DefId,
203 predicate: ty::Clause<'tcx>,
204 sp: Span,
205 allow_self_projections: AllowSelfProjections,
206) -> Option<Span> {
207 match predicate.kind().skip_binder() {
208 ty::ClauseKind::Trait(ref data) => {
209 data.trait_ref.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
211 }
212 ty::ClauseKind::Projection(ref data) => {
213 data.projection_term.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
229 }
230 ty::ClauseKind::ConstArgHasType(_ct, ty) => contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections).then_some(sp),
231
232 ty::ClauseKind::WellFormed(..)
233 | ty::ClauseKind::TypeOutlives(..)
234 | ty::ClauseKind::RegionOutlives(..)
235 | ty::ClauseKind::ConstEvaluatable(..)
237 | ty::ClauseKind::HostEffect(..)
238 => None,
239 }
240}
241
242fn super_predicates_have_non_lifetime_binders(
243 tcx: TyCtxt<'_>,
244 trait_def_id: DefId,
245) -> SmallVec<[Span; 1]> {
246 if !tcx.features().non_lifetime_binders() {
248 return SmallVec::new();
249 }
250 tcx.explicit_super_predicates_of(trait_def_id)
251 .iter_identity_copied()
252 .filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(span))
253 .collect()
254}
255
256fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
257 tcx.generics_require_sized_self(trait_def_id)
258}
259
260fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
261 let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
262 return false; };
264
265 let predicates = tcx.predicates_of(def_id);
267 let predicates = predicates.instantiate_identity(tcx).predicates;
268 elaborate(tcx, predicates).any(|pred| match pred.kind().skip_binder() {
269 ty::ClauseKind::Trait(ref trait_pred) => {
270 trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
271 }
272 ty::ClauseKind::RegionOutlives(_)
273 | ty::ClauseKind::TypeOutlives(_)
274 | ty::ClauseKind::Projection(_)
275 | ty::ClauseKind::ConstArgHasType(_, _)
276 | ty::ClauseKind::WellFormed(_)
277 | ty::ClauseKind::ConstEvaluatable(_)
278 | ty::ClauseKind::HostEffect(..) => false,
279 })
280}
281
282#[instrument(level = "debug", skip(tcx), ret)]
284pub fn dyn_compatibility_violations_for_assoc_item(
285 tcx: TyCtxt<'_>,
286 trait_def_id: DefId,
287 item: ty::AssocItem,
288) -> Vec<DynCompatibilityViolation> {
289 if tcx.generics_require_sized_self(item.def_id) {
292 return Vec::new();
293 }
294
295 match item.kind {
296 ty::AssocKind::Const => {
299 vec![DynCompatibilityViolation::AssocConst(item.name, item.ident(tcx).span)]
300 }
301 ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item)
302 .into_iter()
303 .map(|v| {
304 let node = tcx.hir().get_if_local(item.def_id);
305 let span = match (&v, node) {
307 (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
308 (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
309 (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
310 (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
311 node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
312 }
313 _ => item.ident(tcx).span,
314 };
315
316 DynCompatibilityViolation::Method(item.name, v, span)
317 })
318 .collect(),
319 ty::AssocKind::Type => {
321 if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() {
322 vec![DynCompatibilityViolation::GAT(item.name, item.ident(tcx).span)]
323 } else {
324 Vec::new()
327 }
328 }
329 }
330}
331
332fn virtual_call_violations_for_method<'tcx>(
337 tcx: TyCtxt<'tcx>,
338 trait_def_id: DefId,
339 method: ty::AssocItem,
340) -> Vec<MethodViolationCode> {
341 let sig = tcx.fn_sig(method.def_id).instantiate_identity();
342
343 if !method.fn_has_self_parameter {
345 let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
346 generics,
347 kind: hir::TraitItemKind::Fn(sig, _),
348 ..
349 })) = tcx.hir().get_if_local(method.def_id).as_ref()
350 {
351 let sm = tcx.sess.source_map();
352 Some((
353 (
354 format!("&self{}", if sig.decl.inputs.is_empty() { "" } else { ", " }),
355 sm.span_through_char(sig.span, '(').shrink_to_hi(),
356 ),
357 (
358 format!("{} Self: Sized", generics.add_where_or_trailing_comma()),
359 generics.tail_span_for_predicate_suggestion(),
360 ),
361 ))
362 } else {
363 None
364 };
365
366 return vec![MethodViolationCode::StaticMethod(sugg)];
369 }
370
371 let mut errors = Vec::new();
372
373 for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
374 if contains_illegal_self_type_reference(
375 tcx,
376 trait_def_id,
377 sig.rebind(input_ty),
378 AllowSelfProjections::Yes,
379 ) {
380 let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
381 kind: hir::TraitItemKind::Fn(sig, _),
382 ..
383 })) = tcx.hir().get_if_local(method.def_id).as_ref()
384 {
385 Some(sig.decl.inputs[i].span)
386 } else {
387 None
388 };
389 errors.push(MethodViolationCode::ReferencesSelfInput(span));
390 }
391 }
392 if contains_illegal_self_type_reference(
393 tcx,
394 trait_def_id,
395 sig.output(),
396 AllowSelfProjections::Yes,
397 ) {
398 errors.push(MethodViolationCode::ReferencesSelfOutput);
399 }
400 if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
401 errors.push(code);
402 }
403
404 let own_counts = tcx.generics_of(method.def_id).own_counts();
406 if own_counts.types > 0 || own_counts.consts > 0 {
407 errors.push(MethodViolationCode::Generic);
408 }
409
410 let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
411
412 if receiver_ty != tcx.types.self_param {
417 if !receiver_is_dispatchable(tcx, method, receiver_ty) {
418 let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
419 kind: hir::TraitItemKind::Fn(sig, _),
420 ..
421 })) = tcx.hir().get_if_local(method.def_id).as_ref()
422 {
423 Some(sig.decl.inputs[0].span)
424 } else {
425 None
426 };
427 errors.push(MethodViolationCode::UndispatchableReceiver(span));
428 } else {
429 }
432 }
433
434 if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, _span)| {
437 if pred.as_type_outlives_clause().is_some() {
447 return false;
448 }
449
450 if let ty::ClauseKind::Trait(ty::TraitPredicate {
464 trait_ref: pred_trait_ref,
465 polarity: ty::PredicatePolarity::Positive,
466 }) = pred.kind().skip_binder()
467 && pred_trait_ref.self_ty() == tcx.types.self_param
468 && tcx.trait_is_auto(pred_trait_ref.def_id)
469 {
470 if pred_trait_ref.args.len() != 1 {
475 assert!(
476 tcx.dcx().has_errors().is_some(),
477 "auto traits cannot have generic parameters"
478 );
479 }
480 return false;
481 }
482
483 contains_illegal_self_type_reference(tcx, trait_def_id, pred, AllowSelfProjections::Yes)
484 }) {
485 errors.push(MethodViolationCode::WhereClauseReferencesSelf);
486 }
487
488 errors
489}
490
491fn receiver_for_self_ty<'tcx>(
494 tcx: TyCtxt<'tcx>,
495 receiver_ty: Ty<'tcx>,
496 self_ty: Ty<'tcx>,
497 method_def_id: DefId,
498) -> Ty<'tcx> {
499 debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
500 let args = GenericArgs::for_item(tcx, method_def_id, |param, _| {
501 if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
502 });
503
504 let result = EarlyBinder::bind(receiver_ty).instantiate(tcx, args);
505 debug!(
506 "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
507 receiver_ty, self_ty, method_def_id, result
508 );
509 result
510}
511
512fn receiver_is_dispatchable<'tcx>(
559 tcx: TyCtxt<'tcx>,
560 method: ty::AssocItem,
561 receiver_ty: Ty<'tcx>,
562) -> bool {
563 debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
564
565 let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
566 let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else {
567 debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
568 return false;
569 };
570
571 let unsized_self_ty: Ty<'tcx> =
576 Ty::new_param(tcx, u32::MAX, rustc_span::sym::RustaceansAreAwesome);
577
578 let unsized_receiver_ty =
580 receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
581
582 let param_env = {
585 let param_env = tcx.param_env(method.def_id);
586
587 let unsize_predicate =
589 ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]).upcast(tcx);
590
591 let trait_predicate = {
593 let trait_def_id = method.trait_container(tcx).unwrap();
594 let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| {
595 if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
596 });
597
598 ty::TraitRef::new_from_args(tcx, trait_def_id, args).upcast(tcx)
599 };
600
601 let caller_bounds =
602 param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]);
603
604 ty::ParamEnv::new(tcx.mk_clauses_from_iter(caller_bounds))
605 };
606
607 let obligation = {
609 let predicate =
610 ty::TraitRef::new(tcx, dispatch_from_dyn_did, [receiver_ty, unsized_receiver_ty]);
611
612 Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
613 };
614
615 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
616 infcx.predicate_must_hold_modulo_regions(&obligation)
618}
619
620#[derive(Copy, Clone)]
621enum AllowSelfProjections {
622 Yes,
623 No,
624}
625
626fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
665 tcx: TyCtxt<'tcx>,
666 trait_def_id: DefId,
667 value: T,
668 allow_self_projections: AllowSelfProjections,
669) -> bool {
670 value
671 .visit_with(&mut IllegalSelfTypeVisitor {
672 tcx,
673 trait_def_id,
674 supertraits: None,
675 allow_self_projections,
676 })
677 .is_break()
678}
679
680struct IllegalSelfTypeVisitor<'tcx> {
681 tcx: TyCtxt<'tcx>,
682 trait_def_id: DefId,
683 supertraits: Option<Vec<ty::TraitRef<'tcx>>>,
684 allow_self_projections: AllowSelfProjections,
685}
686
687impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
688 type Result = ControlFlow<()>;
689
690 fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
691 match t.kind() {
692 ty::Param(_) => {
693 if t == self.tcx.types.self_param {
694 ControlFlow::Break(())
695 } else {
696 ControlFlow::Continue(())
697 }
698 }
699 ty::Alias(ty::Projection, ref data) if self.tcx.is_impl_trait_in_trait(data.def_id) => {
700 ControlFlow::Continue(())
702 }
703 ty::Alias(ty::Projection, ref data) => {
704 match self.allow_self_projections {
705 AllowSelfProjections::Yes => {
706 if self.supertraits.is_none() {
710 self.supertraits = Some(
711 util::supertraits(
712 self.tcx,
713 ty::Binder::dummy(ty::TraitRef::identity(
714 self.tcx,
715 self.trait_def_id,
716 )),
717 )
718 .map(|trait_ref| {
719 self.tcx.erase_regions(
720 self.tcx.instantiate_bound_regions_with_erased(trait_ref),
721 )
722 })
723 .collect(),
724 );
725 }
726
727 let is_supertrait_of_current_trait =
736 self.supertraits.as_ref().unwrap().contains(
737 &data.trait_ref(self.tcx).fold_with(
738 &mut EraseEscapingBoundRegions {
739 tcx: self.tcx,
740 binder: ty::INNERMOST,
741 },
742 ),
743 );
744
745 if is_supertrait_of_current_trait {
747 ControlFlow::Continue(())
748 } else {
749 t.super_visit_with(self) }
751 }
752 AllowSelfProjections::No => t.super_visit_with(self),
753 }
754 }
755 _ => t.super_visit_with(self),
756 }
757 }
758
759 fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
760 self.tcx.expand_abstract_consts(ct).super_visit_with(self)
763 }
764}
765
766struct EraseEscapingBoundRegions<'tcx> {
767 tcx: TyCtxt<'tcx>,
768 binder: ty::DebruijnIndex,
769}
770
771impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEscapingBoundRegions<'tcx> {
772 fn cx(&self) -> TyCtxt<'tcx> {
773 self.tcx
774 }
775
776 fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
777 where
778 T: TypeFoldable<TyCtxt<'tcx>>,
779 {
780 self.binder.shift_in(1);
781 let result = t.super_fold_with(self);
782 self.binder.shift_out(1);
783 result
784 }
785
786 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
787 if let ty::ReBound(debruijn, _) = *r
788 && debruijn < self.binder
789 {
790 r
791 } else {
792 self.tcx.lifetimes.re_erased
793 }
794 }
795}
796
797fn contains_illegal_impl_trait_in_trait<'tcx>(
798 tcx: TyCtxt<'tcx>,
799 fn_def_id: DefId,
800 ty: ty::Binder<'tcx, Ty<'tcx>>,
801) -> Option<MethodViolationCode> {
802 let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
803
804 if tcx.asyncness(fn_def_id).is_async() {
805 if tcx.features().async_fn_in_dyn_trait() {
809 let ty::Alias(ty::Projection, proj) = *ty.kind() else {
810 bug!("expected async fn in trait to return an RPITIT");
811 };
812 assert!(tcx.is_impl_trait_in_trait(proj.def_id));
813
814 for bound in tcx.item_bounds(proj.def_id).instantiate(tcx, proj.args) {
817 if let Some(violation) = bound
818 .visit_with(&mut IllegalRpititVisitor { tcx, allowed: Some(proj) })
819 .break_value()
820 {
821 return Some(violation);
822 }
823 }
824
825 None
826 } else {
827 Some(MethodViolationCode::AsyncFn)
829 }
830 } else {
831 ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
832 }
833}
834
835struct IllegalRpititVisitor<'tcx> {
836 tcx: TyCtxt<'tcx>,
837 allowed: Option<ty::AliasTy<'tcx>>,
838}
839
840impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
841 type Result = ControlFlow<MethodViolationCode>;
842
843 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
844 if let ty::Alias(ty::Projection, proj) = *ty.kind()
845 && Some(proj) != self.allowed
846 && self.tcx.is_impl_trait_in_trait(proj.def_id)
847 {
848 ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait(
849 self.tcx.def_span(proj.def_id),
850 ))
851 } else {
852 ty.super_visit_with(self)
853 }
854 }
855}
856
857pub(crate) fn provide(providers: &mut Providers) {
858 *providers = Providers {
859 dyn_compatibility_violations,
860 is_dyn_compatible,
861 generics_require_sized_self,
862 ..*providers
863 };
864}