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 let spans = super_predicates_are_unconditionally_const(tcx, trait_def_id);
110 if !spans.is_empty() {
111 violations.push(DynCompatibilityViolation::SupertraitConst(spans));
112 }
113
114 violations
115}
116
117fn sized_trait_bound_spans<'tcx>(
118 tcx: TyCtxt<'tcx>,
119 bounds: hir::GenericBounds<'tcx>,
120) -> impl 'tcx + Iterator<Item = Span> {
121 bounds.iter().filter_map(move |b| match b {
122 hir::GenericBound::Trait(trait_ref)
123 if trait_has_sized_self(
124 tcx,
125 trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
126 ) =>
127 {
128 Some(trait_ref.span)
130 }
131 _ => None,
132 })
133}
134
135fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
136 tcx.hir_get_if_local(trait_def_id)
137 .and_then(|node| match node {
138 hir::Node::Item(hir::Item {
139 kind: hir::ItemKind::Trait(.., generics, bounds, _),
140 ..
141 }) => Some(
142 generics
143 .predicates
144 .iter()
145 .filter_map(|pred| {
146 match pred.kind {
147 hir::WherePredicateKind::BoundPredicate(pred)
148 if pred.bounded_ty.hir_id.owner.to_def_id() == trait_def_id =>
149 {
150 Some(sized_trait_bound_spans(tcx, pred.bounds))
153 }
154 _ => None,
155 }
156 })
157 .flatten()
158 .chain(sized_trait_bound_spans(tcx, bounds))
160 .collect::<SmallVec<[Span; 1]>>(),
161 ),
162 _ => None,
163 })
164 .unwrap_or_else(SmallVec::new)
165}
166
167fn predicates_reference_self(
168 tcx: TyCtxt<'_>,
169 trait_def_id: DefId,
170 supertraits_only: bool,
171) -> SmallVec<[Span; 1]> {
172 let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
173 let predicates = if supertraits_only {
174 tcx.explicit_super_predicates_of(trait_def_id).skip_binder()
175 } else {
176 tcx.predicates_of(trait_def_id).predicates
177 };
178 predicates
179 .iter()
180 .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp))
181 .filter_map(|(clause, sp)| {
182 predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::No)
187 })
188 .collect()
189}
190
191fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
192 tcx.associated_items(trait_def_id)
193 .in_definition_order()
194 .filter(|item| item.is_type())
196 .filter(|item| !tcx.generics_require_sized_self(item.def_id))
198 .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
199 .filter_map(|(clause, sp)| {
200 predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::Yes)
203 })
204 .collect()
205}
206
207fn predicate_references_self<'tcx>(
208 tcx: TyCtxt<'tcx>,
209 trait_def_id: DefId,
210 predicate: ty::Clause<'tcx>,
211 sp: Span,
212 allow_self_projections: AllowSelfProjections,
213) -> Option<Span> {
214 match predicate.kind().skip_binder() {
215 ty::ClauseKind::Trait(ref data) => {
216 data.trait_ref.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
218 }
219 ty::ClauseKind::Projection(ref data) => {
220 data.projection_term.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
236 }
237 ty::ClauseKind::ConstArgHasType(_ct, ty) => contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections).then_some(sp),
238
239 ty::ClauseKind::WellFormed(..)
240 | ty::ClauseKind::TypeOutlives(..)
241 | ty::ClauseKind::RegionOutlives(..)
242 | ty::ClauseKind::ConstEvaluatable(..)
244 | ty::ClauseKind::HostEffect(..)
245 | ty::ClauseKind::UnstableFeature(_)
246 => None,
247 }
248}
249
250fn super_predicates_have_non_lifetime_binders(
251 tcx: TyCtxt<'_>,
252 trait_def_id: DefId,
253) -> SmallVec<[Span; 1]> {
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 super_predicates_are_unconditionally_const(
264 tcx: TyCtxt<'_>,
265 trait_def_id: DefId,
266) -> SmallVec<[Span; 1]> {
267 tcx.explicit_super_predicates_of(trait_def_id)
268 .iter_identity_copied()
269 .filter_map(|(pred, span)| {
270 if let ty::ClauseKind::HostEffect(_) = pred.kind().skip_binder() {
271 Some(span)
272 } else {
273 None
274 }
275 })
276 .collect()
277}
278
279fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
280 tcx.generics_require_sized_self(trait_def_id)
281}
282
283fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
284 let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
285 return false; };
287
288 let predicates = tcx.predicates_of(def_id);
290 let predicates = predicates.instantiate_identity(tcx).predicates;
291 elaborate(tcx, predicates).any(|pred| match pred.kind().skip_binder() {
292 ty::ClauseKind::Trait(ref trait_pred) => {
293 trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
294 }
295 ty::ClauseKind::RegionOutlives(_)
296 | ty::ClauseKind::TypeOutlives(_)
297 | ty::ClauseKind::Projection(_)
298 | ty::ClauseKind::ConstArgHasType(_, _)
299 | ty::ClauseKind::WellFormed(_)
300 | ty::ClauseKind::ConstEvaluatable(_)
301 | ty::ClauseKind::UnstableFeature(_)
302 | ty::ClauseKind::HostEffect(..) => false,
303 })
304}
305
306#[instrument(level = "debug", skip(tcx), ret)]
308pub fn dyn_compatibility_violations_for_assoc_item(
309 tcx: TyCtxt<'_>,
310 trait_def_id: DefId,
311 item: ty::AssocItem,
312) -> Vec<DynCompatibilityViolation> {
313 if tcx.generics_require_sized_self(item.def_id) {
316 return Vec::new();
317 }
318
319 match item.kind {
320 ty::AssocKind::Const { name } => {
323 vec![DynCompatibilityViolation::AssocConst(name, item.ident(tcx).span)]
324 }
325 ty::AssocKind::Fn { name, .. } => {
326 virtual_call_violations_for_method(tcx, trait_def_id, item)
327 .into_iter()
328 .map(|v| {
329 let node = tcx.hir_get_if_local(item.def_id);
330 let span = match (&v, node) {
332 (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
333 (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
334 (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
335 (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
336 node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
337 }
338 _ => item.ident(tcx).span,
339 };
340
341 DynCompatibilityViolation::Method(name, v, span)
342 })
343 .collect()
344 }
345 ty::AssocKind::Type { .. } => {
347 if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() {
348 vec![DynCompatibilityViolation::GAT(item.name(), item.ident(tcx).span)]
349 } else {
350 Vec::new()
353 }
354 }
355 }
356}
357
358fn virtual_call_violations_for_method<'tcx>(
363 tcx: TyCtxt<'tcx>,
364 trait_def_id: DefId,
365 method: ty::AssocItem,
366) -> Vec<MethodViolationCode> {
367 let sig = tcx.fn_sig(method.def_id).instantiate_identity();
368
369 if !method.is_method() {
371 let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
372 generics,
373 kind: hir::TraitItemKind::Fn(sig, _),
374 ..
375 })) = tcx.hir_get_if_local(method.def_id).as_ref()
376 {
377 let sm = tcx.sess.source_map();
378 Some((
379 (
380 format!("&self{}", if sig.decl.inputs.is_empty() { "" } else { ", " }),
381 sm.span_through_char(sig.span, '(').shrink_to_hi(),
382 ),
383 (
384 format!("{} Self: Sized", generics.add_where_or_trailing_comma()),
385 generics.tail_span_for_predicate_suggestion(),
386 ),
387 ))
388 } else {
389 None
390 };
391
392 return vec![MethodViolationCode::StaticMethod(sugg)];
395 }
396
397 let mut errors = Vec::new();
398
399 for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
400 if contains_illegal_self_type_reference(
401 tcx,
402 trait_def_id,
403 sig.rebind(input_ty),
404 AllowSelfProjections::Yes,
405 ) {
406 let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
407 kind: hir::TraitItemKind::Fn(sig, _),
408 ..
409 })) = tcx.hir_get_if_local(method.def_id).as_ref()
410 {
411 Some(sig.decl.inputs[i].span)
412 } else {
413 None
414 };
415 errors.push(MethodViolationCode::ReferencesSelfInput(span));
416 }
417 }
418 if contains_illegal_self_type_reference(
419 tcx,
420 trait_def_id,
421 sig.output(),
422 AllowSelfProjections::Yes,
423 ) {
424 errors.push(MethodViolationCode::ReferencesSelfOutput);
425 }
426 if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
427 errors.push(code);
428 }
429 if sig.skip_binder().c_variadic {
430 errors.push(MethodViolationCode::CVariadic);
431 }
432
433 let own_counts = tcx.generics_of(method.def_id).own_counts();
435 if own_counts.types > 0 || own_counts.consts > 0 {
436 errors.push(MethodViolationCode::Generic);
437 }
438
439 let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
440
441 if receiver_ty != tcx.types.self_param {
446 if !receiver_is_dispatchable(tcx, method, receiver_ty) {
447 let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
448 kind: hir::TraitItemKind::Fn(sig, _),
449 ..
450 })) = tcx.hir_get_if_local(method.def_id).as_ref()
451 {
452 Some(sig.decl.inputs[0].span)
453 } else {
454 None
455 };
456 errors.push(MethodViolationCode::UndispatchableReceiver(span));
457 } else {
458 }
461 }
462
463 if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, _span)| {
466 if pred.as_type_outlives_clause().is_some() {
476 return false;
477 }
478
479 if let ty::ClauseKind::Trait(ty::TraitPredicate {
493 trait_ref: pred_trait_ref,
494 polarity: ty::PredicatePolarity::Positive,
495 }) = pred.kind().skip_binder()
496 && pred_trait_ref.self_ty() == tcx.types.self_param
497 && tcx.trait_is_auto(pred_trait_ref.def_id)
498 {
499 if pred_trait_ref.args.len() != 1 {
504 assert!(
505 tcx.dcx().has_errors().is_some(),
506 "auto traits cannot have generic parameters"
507 );
508 }
509 return false;
510 }
511
512 contains_illegal_self_type_reference(tcx, trait_def_id, pred, AllowSelfProjections::Yes)
513 }) {
514 errors.push(MethodViolationCode::WhereClauseReferencesSelf);
515 }
516
517 errors
518}
519
520fn receiver_for_self_ty<'tcx>(
523 tcx: TyCtxt<'tcx>,
524 receiver_ty: Ty<'tcx>,
525 self_ty: Ty<'tcx>,
526 method_def_id: DefId,
527) -> Ty<'tcx> {
528 debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
529 let args = GenericArgs::for_item(tcx, method_def_id, |param, _| {
530 if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
531 });
532
533 let result = EarlyBinder::bind(receiver_ty).instantiate(tcx, args);
534 debug!(
535 "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
536 receiver_ty, self_ty, method_def_id, result
537 );
538 result
539}
540
541fn receiver_is_dispatchable<'tcx>(
588 tcx: TyCtxt<'tcx>,
589 method: ty::AssocItem,
590 receiver_ty: Ty<'tcx>,
591) -> bool {
592 debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
593
594 let (Some(unsize_did), Some(dispatch_from_dyn_did)) =
595 (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait())
596 else {
597 debug!("receiver_is_dispatchable: Missing `Unsize` or `DispatchFromDyn` traits");
598 return false;
599 };
600
601 let unsized_self_ty: Ty<'tcx> =
604 Ty::new_param(tcx, u32::MAX, rustc_span::sym::RustaceansAreAwesome);
605
606 let unsized_receiver_ty =
608 receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
609
610 let param_env = {
613 let mut predicates = tcx.predicates_of(method.def_id).instantiate_identity(tcx).predicates;
626
627 let unsize_predicate =
629 ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]);
630 predicates.push(unsize_predicate.upcast(tcx));
631
632 let trait_def_id = method.trait_container(tcx).unwrap();
634 let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| {
635 if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
636 });
637 let trait_predicate = ty::TraitRef::new_from_args(tcx, trait_def_id, args);
638 predicates.push(trait_predicate.upcast(tcx));
639
640 let meta_sized_predicate = {
641 let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, DUMMY_SP);
642 ty::TraitRef::new(tcx, meta_sized_did, [unsized_self_ty]).upcast(tcx)
643 };
644 predicates.push(meta_sized_predicate);
645
646 normalize_param_env_or_error(
647 tcx,
648 ty::ParamEnv::new(tcx.mk_clauses(&predicates)),
649 ObligationCause::dummy_with_span(tcx.def_span(method.def_id)),
650 )
651 };
652
653 let obligation = {
655 let predicate =
656 ty::TraitRef::new(tcx, dispatch_from_dyn_did, [receiver_ty, unsized_receiver_ty]);
657
658 Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
659 };
660
661 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
662 infcx.predicate_must_hold_modulo_regions(&obligation)
664}
665
666#[derive(Copy, Clone)]
667enum AllowSelfProjections {
668 Yes,
669 No,
670}
671
672fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
711 tcx: TyCtxt<'tcx>,
712 trait_def_id: DefId,
713 value: T,
714 allow_self_projections: AllowSelfProjections,
715) -> bool {
716 value
717 .visit_with(&mut IllegalSelfTypeVisitor {
718 tcx,
719 trait_def_id,
720 supertraits: None,
721 allow_self_projections,
722 })
723 .is_break()
724}
725
726struct IllegalSelfTypeVisitor<'tcx> {
727 tcx: TyCtxt<'tcx>,
728 trait_def_id: DefId,
729 supertraits: Option<Vec<ty::TraitRef<'tcx>>>,
730 allow_self_projections: AllowSelfProjections,
731}
732
733impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
734 type Result = ControlFlow<()>;
735
736 fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
737 match t.kind() {
738 ty::Param(_) => {
739 if t == self.tcx.types.self_param {
740 ControlFlow::Break(())
741 } else {
742 ControlFlow::Continue(())
743 }
744 }
745 ty::Alias(ty::Projection, data) if self.tcx.is_impl_trait_in_trait(data.def_id) => {
746 ControlFlow::Continue(())
748 }
749 ty::Alias(ty::Projection, data) => {
750 match self.allow_self_projections {
751 AllowSelfProjections::Yes => {
752 if self.supertraits.is_none() {
756 self.supertraits = Some(
757 util::supertraits(
758 self.tcx,
759 ty::Binder::dummy(ty::TraitRef::identity(
760 self.tcx,
761 self.trait_def_id,
762 )),
763 )
764 .map(|trait_ref| {
765 self.tcx.erase_and_anonymize_regions(
766 self.tcx.instantiate_bound_regions_with_erased(trait_ref),
767 )
768 })
769 .collect(),
770 );
771 }
772
773 let is_supertrait_of_current_trait =
782 self.supertraits.as_ref().unwrap().contains(
783 &data.trait_ref(self.tcx).fold_with(
784 &mut EraseEscapingBoundRegions {
785 tcx: self.tcx,
786 binder: ty::INNERMOST,
787 },
788 ),
789 );
790
791 if is_supertrait_of_current_trait {
793 ControlFlow::Continue(())
794 } else {
795 t.super_visit_with(self) }
797 }
798 AllowSelfProjections::No => t.super_visit_with(self),
799 }
800 }
801 _ => t.super_visit_with(self),
802 }
803 }
804
805 fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
806 self.tcx.expand_abstract_consts(ct).super_visit_with(self)
809 }
810}
811
812struct EraseEscapingBoundRegions<'tcx> {
813 tcx: TyCtxt<'tcx>,
814 binder: ty::DebruijnIndex,
815}
816
817impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEscapingBoundRegions<'tcx> {
818 fn cx(&self) -> TyCtxt<'tcx> {
819 self.tcx
820 }
821
822 fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
823 where
824 T: TypeFoldable<TyCtxt<'tcx>>,
825 {
826 self.binder.shift_in(1);
827 let result = t.super_fold_with(self);
828 self.binder.shift_out(1);
829 result
830 }
831
832 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
833 if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind()
834 && debruijn < self.binder
835 {
836 r
837 } else {
838 self.tcx.lifetimes.re_erased
839 }
840 }
841}
842
843fn contains_illegal_impl_trait_in_trait<'tcx>(
844 tcx: TyCtxt<'tcx>,
845 fn_def_id: DefId,
846 ty: ty::Binder<'tcx, Ty<'tcx>>,
847) -> Option<MethodViolationCode> {
848 let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
849
850 if tcx.asyncness(fn_def_id).is_async() {
851 Some(MethodViolationCode::AsyncFn)
853 } else {
854 ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
855 }
856}
857
858struct IllegalRpititVisitor<'tcx> {
859 tcx: TyCtxt<'tcx>,
860 allowed: Option<ty::AliasTy<'tcx>>,
861}
862
863impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
864 type Result = ControlFlow<MethodViolationCode>;
865
866 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
867 if let ty::Alias(ty::Projection, proj) = *ty.kind()
868 && Some(proj) != self.allowed
869 && self.tcx.is_impl_trait_in_trait(proj.def_id)
870 {
871 ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait(
872 self.tcx.def_span(proj.def_id),
873 ))
874 } else {
875 ty.super_visit_with(self)
876 }
877 }
878}
879
880pub(crate) fn provide(providers: &mut Providers) {
881 *providers = Providers {
882 dyn_compatibility_violations,
883 is_dyn_compatible,
884 generics_require_sized_self,
885 ..*providers
886 };
887}