rustc_trait_selection/traits/
dyn_compatibility.rs1use std::ops::ControlFlow;
8
9use rustc_errors::FatalError;
10use rustc_hir::def_id::DefId;
11use rustc_hir::{self as hir, LangItem};
12use rustc_middle::query::Providers;
13use rustc_middle::ty::{
14 self, EarlyBinder, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
15 TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
16 elaborate,
17};
18use rustc_span::{DUMMY_SP, Span};
19use smallvec::SmallVec;
20use tracing::{debug, instrument};
21
22use super::elaborate;
23use crate::infer::TyCtxtInferExt;
24pub use crate::traits::DynCompatibilityViolation;
25use crate::traits::query::evaluate_obligation::InferCtxtExt;
26use crate::traits::{
27 MethodViolationCode, Obligation, ObligationCause, normalize_param_env_or_error, util,
28};
29
30#[instrument(level = "debug", skip(tcx), ret)]
36pub fn hir_ty_lowering_dyn_compatibility_violations(
37 tcx: TyCtxt<'_>,
38 trait_def_id: DefId,
39) -> Vec<DynCompatibilityViolation> {
40 debug_assert!(tcx.generics_of(trait_def_id).has_self);
41 elaborate::supertrait_def_ids(tcx, trait_def_id)
42 .map(|def_id| predicates_reference_self(tcx, def_id, true))
43 .filter(|spans| !spans.is_empty())
44 .map(DynCompatibilityViolation::SupertraitSelf)
45 .collect()
46}
47
48fn dyn_compatibility_violations(
49 tcx: TyCtxt<'_>,
50 trait_def_id: DefId,
51) -> &'_ [DynCompatibilityViolation] {
52 debug_assert!(tcx.generics_of(trait_def_id).has_self);
53 debug!("dyn_compatibility_violations: {:?}", trait_def_id);
54 tcx.arena.alloc_from_iter(
55 elaborate::supertrait_def_ids(tcx, trait_def_id)
56 .flat_map(|def_id| dyn_compatibility_violations_for_trait(tcx, def_id)),
57 )
58}
59
60fn is_dyn_compatible(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
61 tcx.dyn_compatibility_violations(trait_def_id).is_empty()
62}
63
64pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool {
69 debug_assert!(tcx.generics_of(trait_def_id).has_self);
70 debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
71 if tcx.generics_require_sized_self(method.def_id) {
73 return false;
74 }
75
76 virtual_call_violations_for_method(tcx, trait_def_id, method).is_empty()
77}
78
79#[instrument(level = "debug", skip(tcx), ret)]
80fn dyn_compatibility_violations_for_trait(
81 tcx: TyCtxt<'_>,
82 trait_def_id: DefId,
83) -> Vec<DynCompatibilityViolation> {
84 let mut violations: Vec<_> = tcx
86 .associated_items(trait_def_id)
87 .in_definition_order()
88 .flat_map(|&item| dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, item))
89 .collect();
90
91 if trait_has_sized_self(tcx, trait_def_id) {
93 let spans = get_sized_bounds(tcx, trait_def_id);
95 violations.push(DynCompatibilityViolation::SizedSelf(spans));
96 }
97 let spans = predicates_reference_self(tcx, trait_def_id, false);
98 if !spans.is_empty() {
99 violations.push(DynCompatibilityViolation::SupertraitSelf(spans));
100 }
101 let spans = bounds_reference_self(tcx, trait_def_id);
102 if !spans.is_empty() {
103 violations.push(DynCompatibilityViolation::SupertraitSelf(spans));
104 }
105 let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id);
106 if !spans.is_empty() {
107 violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
108 }
109
110 violations
111}
112
113fn sized_trait_bound_spans<'tcx>(
114 tcx: TyCtxt<'tcx>,
115 bounds: hir::GenericBounds<'tcx>,
116) -> impl 'tcx + Iterator<Item = Span> {
117 bounds.iter().filter_map(move |b| match b {
118 hir::GenericBound::Trait(trait_ref)
119 if trait_has_sized_self(
120 tcx,
121 trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
122 ) =>
123 {
124 Some(trait_ref.span)
126 }
127 _ => None,
128 })
129}
130
131fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
132 tcx.hir_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.is_type())
192 .filter(|item| !tcx.generics_require_sized_self(item.def_id))
194 .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
195 .filter_map(|(clause, sp)| {
196 predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::Yes)
199 })
200 .collect()
201}
202
203fn predicate_references_self<'tcx>(
204 tcx: TyCtxt<'tcx>,
205 trait_def_id: DefId,
206 predicate: ty::Clause<'tcx>,
207 sp: Span,
208 allow_self_projections: AllowSelfProjections,
209) -> Option<Span> {
210 match predicate.kind().skip_binder() {
211 ty::ClauseKind::Trait(ref data) => {
212 data.trait_ref.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
214 }
215 ty::ClauseKind::Projection(ref data) => {
216 data.projection_term.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
232 }
233 ty::ClauseKind::ConstArgHasType(_ct, ty) => contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections).then_some(sp),
234
235 ty::ClauseKind::WellFormed(..)
236 | ty::ClauseKind::TypeOutlives(..)
237 | ty::ClauseKind::RegionOutlives(..)
238 | ty::ClauseKind::ConstEvaluatable(..)
240 | ty::ClauseKind::HostEffect(..)
241 | ty::ClauseKind::UnstableFeature(_)
242 => None,
243 }
244}
245
246fn super_predicates_have_non_lifetime_binders(
247 tcx: TyCtxt<'_>,
248 trait_def_id: DefId,
249) -> SmallVec<[Span; 1]> {
250 if !tcx.features().non_lifetime_binders() {
252 return SmallVec::new();
253 }
254 tcx.explicit_super_predicates_of(trait_def_id)
255 .iter_identity_copied()
256 .filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(span))
257 .collect()
258}
259
260fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
261 tcx.generics_require_sized_self(trait_def_id)
262}
263
264fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
265 let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
266 return false; };
268
269 let predicates = tcx.predicates_of(def_id);
271 let predicates = predicates.instantiate_identity(tcx).predicates;
272 elaborate(tcx, predicates).any(|pred| match pred.kind().skip_binder() {
273 ty::ClauseKind::Trait(ref trait_pred) => {
274 trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
275 }
276 ty::ClauseKind::RegionOutlives(_)
277 | ty::ClauseKind::TypeOutlives(_)
278 | ty::ClauseKind::Projection(_)
279 | ty::ClauseKind::ConstArgHasType(_, _)
280 | ty::ClauseKind::WellFormed(_)
281 | ty::ClauseKind::ConstEvaluatable(_)
282 | ty::ClauseKind::UnstableFeature(_)
283 | ty::ClauseKind::HostEffect(..) => false,
284 })
285}
286
287#[instrument(level = "debug", skip(tcx), ret)]
289pub fn dyn_compatibility_violations_for_assoc_item(
290 tcx: TyCtxt<'_>,
291 trait_def_id: DefId,
292 item: ty::AssocItem,
293) -> Vec<DynCompatibilityViolation> {
294 if tcx.generics_require_sized_self(item.def_id) {
297 return Vec::new();
298 }
299
300 match item.kind {
301 ty::AssocKind::Const { name } => {
304 vec![DynCompatibilityViolation::AssocConst(name, item.ident(tcx).span)]
305 }
306 ty::AssocKind::Fn { name, .. } => {
307 virtual_call_violations_for_method(tcx, trait_def_id, item)
308 .into_iter()
309 .map(|v| {
310 let node = tcx.hir_get_if_local(item.def_id);
311 let span = match (&v, node) {
313 (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
314 (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
315 (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
316 (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
317 node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
318 }
319 _ => item.ident(tcx).span,
320 };
321
322 DynCompatibilityViolation::Method(name, v, span)
323 })
324 .collect()
325 }
326 ty::AssocKind::Type { .. } => {
328 if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() {
329 vec![DynCompatibilityViolation::GAT(item.name(), item.ident(tcx).span)]
330 } else {
331 Vec::new()
334 }
335 }
336 }
337}
338
339fn virtual_call_violations_for_method<'tcx>(
344 tcx: TyCtxt<'tcx>,
345 trait_def_id: DefId,
346 method: ty::AssocItem,
347) -> Vec<MethodViolationCode> {
348 let sig = tcx.fn_sig(method.def_id).instantiate_identity();
349
350 if !method.is_method() {
352 let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
353 generics,
354 kind: hir::TraitItemKind::Fn(sig, _),
355 ..
356 })) = tcx.hir_get_if_local(method.def_id).as_ref()
357 {
358 let sm = tcx.sess.source_map();
359 Some((
360 (
361 format!("&self{}", if sig.decl.inputs.is_empty() { "" } else { ", " }),
362 sm.span_through_char(sig.span, '(').shrink_to_hi(),
363 ),
364 (
365 format!("{} Self: Sized", generics.add_where_or_trailing_comma()),
366 generics.tail_span_for_predicate_suggestion(),
367 ),
368 ))
369 } else {
370 None
371 };
372
373 return vec![MethodViolationCode::StaticMethod(sugg)];
376 }
377
378 let mut errors = Vec::new();
379
380 for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
381 if contains_illegal_self_type_reference(
382 tcx,
383 trait_def_id,
384 sig.rebind(input_ty),
385 AllowSelfProjections::Yes,
386 ) {
387 let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
388 kind: hir::TraitItemKind::Fn(sig, _),
389 ..
390 })) = tcx.hir_get_if_local(method.def_id).as_ref()
391 {
392 Some(sig.decl.inputs[i].span)
393 } else {
394 None
395 };
396 errors.push(MethodViolationCode::ReferencesSelfInput(span));
397 }
398 }
399 if contains_illegal_self_type_reference(
400 tcx,
401 trait_def_id,
402 sig.output(),
403 AllowSelfProjections::Yes,
404 ) {
405 errors.push(MethodViolationCode::ReferencesSelfOutput);
406 }
407 if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
408 errors.push(code);
409 }
410
411 let own_counts = tcx.generics_of(method.def_id).own_counts();
413 if own_counts.types > 0 || own_counts.consts > 0 {
414 errors.push(MethodViolationCode::Generic);
415 }
416
417 let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
418
419 if receiver_ty != tcx.types.self_param {
424 if !receiver_is_dispatchable(tcx, method, receiver_ty) {
425 let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
426 kind: hir::TraitItemKind::Fn(sig, _),
427 ..
428 })) = tcx.hir_get_if_local(method.def_id).as_ref()
429 {
430 Some(sig.decl.inputs[0].span)
431 } else {
432 None
433 };
434 errors.push(MethodViolationCode::UndispatchableReceiver(span));
435 } else {
436 }
439 }
440
441 if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, _span)| {
444 if pred.as_type_outlives_clause().is_some() {
454 return false;
455 }
456
457 if let ty::ClauseKind::Trait(ty::TraitPredicate {
471 trait_ref: pred_trait_ref,
472 polarity: ty::PredicatePolarity::Positive,
473 }) = pred.kind().skip_binder()
474 && pred_trait_ref.self_ty() == tcx.types.self_param
475 && tcx.trait_is_auto(pred_trait_ref.def_id)
476 {
477 if pred_trait_ref.args.len() != 1 {
482 assert!(
483 tcx.dcx().has_errors().is_some(),
484 "auto traits cannot have generic parameters"
485 );
486 }
487 return false;
488 }
489
490 contains_illegal_self_type_reference(tcx, trait_def_id, pred, AllowSelfProjections::Yes)
491 }) {
492 errors.push(MethodViolationCode::WhereClauseReferencesSelf);
493 }
494
495 errors
496}
497
498fn receiver_for_self_ty<'tcx>(
501 tcx: TyCtxt<'tcx>,
502 receiver_ty: Ty<'tcx>,
503 self_ty: Ty<'tcx>,
504 method_def_id: DefId,
505) -> Ty<'tcx> {
506 debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
507 let args = GenericArgs::for_item(tcx, method_def_id, |param, _| {
508 if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
509 });
510
511 let result = EarlyBinder::bind(receiver_ty).instantiate(tcx, args);
512 debug!(
513 "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
514 receiver_ty, self_ty, method_def_id, result
515 );
516 result
517}
518
519fn receiver_is_dispatchable<'tcx>(
566 tcx: TyCtxt<'tcx>,
567 method: ty::AssocItem,
568 receiver_ty: Ty<'tcx>,
569) -> bool {
570 debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
571
572 let (Some(unsize_did), Some(dispatch_from_dyn_did)) =
573 (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait())
574 else {
575 debug!("receiver_is_dispatchable: Missing `Unsize` or `DispatchFromDyn` traits");
576 return false;
577 };
578
579 let unsized_self_ty: Ty<'tcx> =
582 Ty::new_param(tcx, u32::MAX, rustc_span::sym::RustaceansAreAwesome);
583
584 let unsized_receiver_ty =
586 receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
587
588 let param_env = {
591 let mut predicates = tcx.predicates_of(method.def_id).instantiate_identity(tcx).predicates;
604
605 let unsize_predicate =
607 ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]);
608 predicates.push(unsize_predicate.upcast(tcx));
609
610 let trait_def_id = method.trait_container(tcx).unwrap();
612 let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| {
613 if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
614 });
615 let trait_predicate = ty::TraitRef::new_from_args(tcx, trait_def_id, args);
616 predicates.push(trait_predicate.upcast(tcx));
617
618 let meta_sized_predicate = {
619 let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, DUMMY_SP);
620 ty::TraitRef::new(tcx, meta_sized_did, [unsized_self_ty]).upcast(tcx)
621 };
622 predicates.push(meta_sized_predicate);
623
624 normalize_param_env_or_error(
625 tcx,
626 ty::ParamEnv::new(tcx.mk_clauses(&predicates)),
627 ObligationCause::dummy_with_span(tcx.def_span(method.def_id)),
628 )
629 };
630
631 let obligation = {
633 let predicate =
634 ty::TraitRef::new(tcx, dispatch_from_dyn_did, [receiver_ty, unsized_receiver_ty]);
635
636 Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
637 };
638
639 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
640 infcx.predicate_must_hold_modulo_regions(&obligation)
642}
643
644#[derive(Copy, Clone)]
645enum AllowSelfProjections {
646 Yes,
647 No,
648}
649
650fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
689 tcx: TyCtxt<'tcx>,
690 trait_def_id: DefId,
691 value: T,
692 allow_self_projections: AllowSelfProjections,
693) -> bool {
694 value
695 .visit_with(&mut IllegalSelfTypeVisitor {
696 tcx,
697 trait_def_id,
698 supertraits: None,
699 allow_self_projections,
700 })
701 .is_break()
702}
703
704struct IllegalSelfTypeVisitor<'tcx> {
705 tcx: TyCtxt<'tcx>,
706 trait_def_id: DefId,
707 supertraits: Option<Vec<ty::TraitRef<'tcx>>>,
708 allow_self_projections: AllowSelfProjections,
709}
710
711impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
712 type Result = ControlFlow<()>;
713
714 fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
715 match t.kind() {
716 ty::Param(_) => {
717 if t == self.tcx.types.self_param {
718 ControlFlow::Break(())
719 } else {
720 ControlFlow::Continue(())
721 }
722 }
723 ty::Alias(ty::Projection, data) if self.tcx.is_impl_trait_in_trait(data.def_id) => {
724 ControlFlow::Continue(())
726 }
727 ty::Alias(ty::Projection, data) => {
728 match self.allow_self_projections {
729 AllowSelfProjections::Yes => {
730 if self.supertraits.is_none() {
734 self.supertraits = Some(
735 util::supertraits(
736 self.tcx,
737 ty::Binder::dummy(ty::TraitRef::identity(
738 self.tcx,
739 self.trait_def_id,
740 )),
741 )
742 .map(|trait_ref| {
743 self.tcx.erase_regions(
744 self.tcx.instantiate_bound_regions_with_erased(trait_ref),
745 )
746 })
747 .collect(),
748 );
749 }
750
751 let is_supertrait_of_current_trait =
760 self.supertraits.as_ref().unwrap().contains(
761 &data.trait_ref(self.tcx).fold_with(
762 &mut EraseEscapingBoundRegions {
763 tcx: self.tcx,
764 binder: ty::INNERMOST,
765 },
766 ),
767 );
768
769 if is_supertrait_of_current_trait {
771 ControlFlow::Continue(())
772 } else {
773 t.super_visit_with(self) }
775 }
776 AllowSelfProjections::No => t.super_visit_with(self),
777 }
778 }
779 _ => t.super_visit_with(self),
780 }
781 }
782
783 fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
784 self.tcx.expand_abstract_consts(ct).super_visit_with(self)
787 }
788}
789
790struct EraseEscapingBoundRegions<'tcx> {
791 tcx: TyCtxt<'tcx>,
792 binder: ty::DebruijnIndex,
793}
794
795impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEscapingBoundRegions<'tcx> {
796 fn cx(&self) -> TyCtxt<'tcx> {
797 self.tcx
798 }
799
800 fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
801 where
802 T: TypeFoldable<TyCtxt<'tcx>>,
803 {
804 self.binder.shift_in(1);
805 let result = t.super_fold_with(self);
806 self.binder.shift_out(1);
807 result
808 }
809
810 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
811 if let ty::ReBound(debruijn, _) = r.kind()
812 && debruijn < self.binder
813 {
814 r
815 } else {
816 self.tcx.lifetimes.re_erased
817 }
818 }
819}
820
821fn contains_illegal_impl_trait_in_trait<'tcx>(
822 tcx: TyCtxt<'tcx>,
823 fn_def_id: DefId,
824 ty: ty::Binder<'tcx, Ty<'tcx>>,
825) -> Option<MethodViolationCode> {
826 let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
827
828 if tcx.asyncness(fn_def_id).is_async() {
829 Some(MethodViolationCode::AsyncFn)
831 } else {
832 ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
833 }
834}
835
836struct IllegalRpititVisitor<'tcx> {
837 tcx: TyCtxt<'tcx>,
838 allowed: Option<ty::AliasTy<'tcx>>,
839}
840
841impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
842 type Result = ControlFlow<MethodViolationCode>;
843
844 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
845 if let ty::Alias(ty::Projection, proj) = *ty.kind()
846 && Some(proj) != self.allowed
847 && self.tcx.is_impl_trait_in_trait(proj.def_id)
848 {
849 ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait(
850 self.tcx.def_span(proj.def_id),
851 ))
852 } else {
853 ty.super_visit_with(self)
854 }
855 }
856}
857
858pub(crate) fn provide(providers: &mut Providers) {
859 *providers = Providers {
860 dyn_compatibility_violations,
861 is_dyn_compatible,
862 generics_require_sized_self,
863 ..*providers
864 };
865}