Skip to main content

rustc_trait_selection/traits/
dyn_compatibility.rs

1//! "Dyn-compatibility"[^1] refers to the ability for a trait to be converted
2//! to a trait object. In general, traits may only be converted to a trait
3//! object if certain criteria are met.
4//!
5//! [^1]: Formerly known as "object safety".
6
7use std::ops::ControlFlow;
8
9use rustc_errors::FatalError;
10use rustc_hir::def::DefKind;
11use rustc_hir::def_id::DefId;
12use rustc_hir::{self as hir, LangItem};
13use rustc_middle::query::Providers;
14use rustc_middle::ty::{
15    self, EarlyBinder, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
16    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Unnormalized,
17    Upcast, elaborate,
18};
19use rustc_span::{DUMMY_SP, Span};
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::{
28    AssocConstViolation, MethodViolation, Obligation, ObligationCause,
29    normalize_param_env_or_error, util,
30};
31
32/// Returns the dyn-compatibility violations that affect HIR ty lowering.
33///
34/// Currently that is `Self` in supertraits. This is needed
35/// because `dyn_compatibility_violations` can't be used during
36/// type collection, as type collection is needed for `dyn_compatibility_violations` itself.
37x;#[instrument(level = "debug", skip(tcx), ret)]
38pub fn hir_ty_lowering_dyn_compatibility_violations(
39    tcx: TyCtxt<'_>,
40    trait_def_id: DefId,
41) -> Vec<DynCompatibilityViolation> {
42    debug_assert!(tcx.generics_of(trait_def_id).has_self);
43    elaborate::supertrait_def_ids(tcx, trait_def_id)
44        .map(|def_id| predicates_reference_self(tcx, def_id, true))
45        .filter(|spans| !spans.is_empty())
46        .map(DynCompatibilityViolation::SupertraitSelf)
47        .collect()
48}
49
50fn dyn_compatibility_violations(
51    tcx: TyCtxt<'_>,
52    trait_def_id: DefId,
53) -> &'_ [DynCompatibilityViolation] {
54    if true {
    if !tcx.generics_of(trait_def_id).has_self {
        ::core::panicking::panic("assertion failed: tcx.generics_of(trait_def_id).has_self")
    };
};debug_assert!(tcx.generics_of(trait_def_id).has_self);
55    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:55",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(55u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("dyn_compatibility_violations: {0:?}",
                                                    trait_def_id) as &dyn Value))])
            });
    } else { ; }
};debug!("dyn_compatibility_violations: {:?}", trait_def_id);
56    tcx.arena.alloc_from_iter(
57        elaborate::supertrait_def_ids(tcx, trait_def_id)
58            .flat_map(|def_id| dyn_compatibility_violations_for_trait(tcx, def_id)),
59    )
60}
61
62fn is_dyn_compatible(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
63    tcx.dyn_compatibility_violations(trait_def_id).is_empty()
64}
65
66/// We say a method is *vtable safe* if it can be invoked on a trait
67/// object. Note that dyn-compatible traits can have some
68/// non-vtable-safe methods, so long as they require `Self: Sized` or
69/// otherwise ensure that they cannot be used when `Self = Trait`.
70pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool {
71    if true {
    if !tcx.generics_of(trait_def_id).has_self {
        ::core::panicking::panic("assertion failed: tcx.generics_of(trait_def_id).has_self")
    };
};debug_assert!(tcx.generics_of(trait_def_id).has_self);
72    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:72",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(72u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("is_vtable_safe_method({0:?}, {1:?})",
                                                    trait_def_id, method) as &dyn Value))])
            });
    } else { ; }
};debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
73    // Any method that has a `Self: Sized` bound cannot be called.
74    if tcx.generics_require_sized_self(method.def_id) {
75        return false;
76    }
77
78    virtual_call_violations_for_method(tcx, trait_def_id, method).is_empty()
79}
80
81x;#[instrument(level = "debug", skip(tcx), ret)]
82fn dyn_compatibility_violations_for_trait(
83    tcx: TyCtxt<'_>,
84    trait_def_id: DefId,
85) -> Vec<DynCompatibilityViolation> {
86    // Check assoc items for violations.
87    let mut violations: Vec<_> = tcx
88        .associated_items(trait_def_id)
89        .in_definition_order()
90        .flat_map(|&item| dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, item))
91        .collect();
92
93    // Check the trait itself.
94    if trait_has_sized_self(tcx, trait_def_id) {
95        // We don't want to include the requirement from `Sized` itself to be `Sized` in the list.
96        let spans = get_sized_bounds(tcx, trait_def_id);
97        violations.push(DynCompatibilityViolation::SizedSelf(spans));
98    } else if let Some(span) = tcx.trait_def(trait_def_id).force_dyn_incompatible {
99        violations.push(DynCompatibilityViolation::ExplicitlyDynIncompatible([span].into()));
100    }
101
102    let spans = predicates_reference_self(tcx, trait_def_id, false);
103    if !spans.is_empty() {
104        violations.push(DynCompatibilityViolation::SupertraitSelf(spans));
105    }
106    let spans = bounds_reference_self(tcx, trait_def_id);
107    if !spans.is_empty() {
108        violations.push(DynCompatibilityViolation::SupertraitSelf(spans));
109    }
110    let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id);
111    if !spans.is_empty() {
112        violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
113    }
114    let spans = super_predicates_are_unconditionally_const(tcx, trait_def_id);
115    if !spans.is_empty() {
116        violations.push(DynCompatibilityViolation::SupertraitConst(spans));
117    }
118
119    violations
120}
121
122fn sized_trait_bound_spans<'tcx>(
123    tcx: TyCtxt<'tcx>,
124    bounds: hir::GenericBounds<'tcx>,
125) -> impl 'tcx + Iterator<Item = Span> {
126    bounds.iter().filter_map(move |b| match b {
127        hir::GenericBound::Trait(trait_ref)
128            if trait_has_sized_self(
129                tcx,
130                trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
131            ) =>
132        {
133            // Fetch spans for supertraits that are `Sized`: `trait T: Super`
134            Some(trait_ref.span)
135        }
136        _ => None,
137    })
138}
139
140fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
141    tcx.hir_get_if_local(trait_def_id)
142        .and_then(|node| match node {
143            hir::Node::Item(hir::Item {
144                kind: hir::ItemKind::Trait(.., generics, bounds, _),
145                ..
146            }) => Some(
147                generics
148                    .predicates
149                    .iter()
150                    .filter_map(|pred| {
151                        match pred.kind {
152                            hir::WherePredicateKind::BoundPredicate(pred)
153                                if pred.bounded_ty.hir_id.owner.to_def_id() == trait_def_id =>
154                            {
155                                // Fetch spans for trait bounds that are Sized:
156                                // `trait T where Self: Pred`
157                                Some(sized_trait_bound_spans(tcx, pred.bounds))
158                            }
159                            _ => None,
160                        }
161                    })
162                    .flatten()
163                    // Fetch spans for supertraits that are `Sized`: `trait T: Super`.
164                    .chain(sized_trait_bound_spans(tcx, bounds))
165                    .collect::<SmallVec<[Span; 1]>>(),
166            ),
167            _ => None,
168        })
169        .unwrap_or_else(SmallVec::new)
170}
171
172fn predicates_reference_self(
173    tcx: TyCtxt<'_>,
174    trait_def_id: DefId,
175    supertraits_only: bool,
176) -> SmallVec<[Span; 1]> {
177    let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
178    let predicates = if supertraits_only {
179        tcx.explicit_super_predicates_of(trait_def_id).skip_binder()
180    } else {
181        tcx.predicates_of(trait_def_id).predicates
182    };
183    predicates
184        .iter()
185        .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp))
186        .filter_map(|(clause, sp)| {
187            // Super predicates cannot allow self projections, since they're
188            // impossible to make into existential bounds without eager resolution
189            // or something.
190            // e.g. `trait A: B<Item = Self::Assoc>`.
191            predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::No)
192        })
193        .collect()
194}
195
196fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
197    tcx.associated_items(trait_def_id)
198        .in_definition_order()
199        // We're only looking at associated type bounds
200        .filter(|item| item.is_type())
201        // Ignore GATs with `Self: Sized`
202        .filter(|item| !tcx.generics_require_sized_self(item.def_id))
203        .flat_map(|item| {
204            tcx.explicit_item_bounds(item.def_id)
205                .iter_identity_copied()
206                .map(Unnormalized::skip_norm_wip)
207        })
208        .filter_map(|(clause, sp)| {
209            // Item bounds *can* have self projections, since they never get
210            // their self type erased.
211            predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::Yes)
212        })
213        .collect()
214}
215
216fn predicate_references_self<'tcx>(
217    tcx: TyCtxt<'tcx>,
218    trait_def_id: DefId,
219    predicate: ty::Clause<'tcx>,
220    sp: Span,
221    allow_self_projections: AllowSelfProjections,
222) -> Option<Span> {
223    match predicate.kind().skip_binder() {
224        ty::ClauseKind::Trait(ref data) => {
225            // In the case of a trait predicate, we can skip the "self" type.
226            data.trait_ref.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
227        }
228        ty::ClauseKind::Projection(ref data) => {
229            // And similarly for projections. This should be redundant with
230            // the previous check because any projection should have a
231            // matching `Trait` predicate with the same inputs, but we do
232            // the check to be safe.
233            //
234            // It's also won't be redundant if we allow type-generic associated
235            // types for trait objects.
236            //
237            // Note that we *do* allow projection *outputs* to contain
238            // `Self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
239            // we just require the user to specify *both* outputs
240            // in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
241            //
242            // This is ALT2 in issue #56288, see that for discussion of the
243            // possible alternatives.
244            data.projection_term.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
245        }
246        ty::ClauseKind::ConstArgHasType(_ct, ty) => contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections).then_some(sp),
247
248        ty::ClauseKind::WellFormed(..)
249        | ty::ClauseKind::TypeOutlives(..)
250        | ty::ClauseKind::RegionOutlives(..)
251        // FIXME(generic_const_exprs): this can mention `Self`
252        | ty::ClauseKind::ConstEvaluatable(..)
253        | ty::ClauseKind::HostEffect(..)
254        | ty::ClauseKind::UnstableFeature(_)
255         => None,
256    }
257}
258
259fn super_predicates_have_non_lifetime_binders(
260    tcx: TyCtxt<'_>,
261    trait_def_id: DefId,
262) -> SmallVec<[Span; 1]> {
263    tcx.explicit_super_predicates_of(trait_def_id)
264        .iter_identity_copied()
265        .map(Unnormalized::skip_norm_wip)
266        .filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(span))
267        .collect()
268}
269
270/// Checks for `const Trait` supertraits. We're okay with `[const] Trait`,
271/// supertraits since for a non-const instantiation of that trait, the
272/// conditionally-const supertrait is also not required to be const.
273fn super_predicates_are_unconditionally_const(
274    tcx: TyCtxt<'_>,
275    trait_def_id: DefId,
276) -> SmallVec<[Span; 1]> {
277    tcx.explicit_super_predicates_of(trait_def_id)
278        .iter_identity_copied()
279        .map(Unnormalized::skip_norm_wip)
280        .filter_map(|(pred, span)| {
281            if let ty::ClauseKind::HostEffect(_) = pred.kind().skip_binder() {
282                Some(span)
283            } else {
284                None
285            }
286        })
287        .collect()
288}
289
290fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
291    tcx.generics_require_sized_self(trait_def_id)
292}
293
294fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
295    let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
296        return false; /* No Sized trait, can't require it! */
297    };
298
299    // Search for a predicate like `Self: Sized` amongst the trait bounds.
300    let predicates: Vec<_> = tcx
301        .predicates_of(def_id)
302        .instantiate_identity(tcx)
303        .predicates
304        .into_iter()
305        .map(Unnormalized::skip_norm_wip)
306        .collect();
307    elaborate(tcx, predicates).any(|pred| match pred.kind().skip_binder() {
308        ty::ClauseKind::Trait(ref trait_pred) => {
309            trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
310        }
311        ty::ClauseKind::RegionOutlives(_)
312        | ty::ClauseKind::TypeOutlives(_)
313        | ty::ClauseKind::Projection(_)
314        | ty::ClauseKind::ConstArgHasType(_, _)
315        | ty::ClauseKind::WellFormed(_)
316        | ty::ClauseKind::ConstEvaluatable(_)
317        | ty::ClauseKind::UnstableFeature(_)
318        | ty::ClauseKind::HostEffect(..) => false,
319    })
320}
321
322x;#[instrument(level = "debug", skip(tcx), ret)]
323pub fn dyn_compatibility_violations_for_assoc_item(
324    tcx: TyCtxt<'_>,
325    trait_def_id: DefId,
326    item: ty::AssocItem,
327) -> Vec<DynCompatibilityViolation> {
328    // `final` assoc functions don't prevent a trait from being dyn-compatible
329    if tcx.defaultness(item.def_id).is_final() {
330        return Vec::new();
331    }
332
333    // Any item that has a `Self: Sized` requisite is otherwise exempt from the regulations.
334    if tcx.generics_require_sized_self(item.def_id) {
335        return Vec::new();
336    }
337
338    let span = || item.ident(tcx).span;
339
340    match item.kind {
341        ty::AssocKind::Const { name, is_type_const } => {
342            // We will permit type associated consts if they are explicitly mentioned in the
343            // trait object type. We can't check this here, as here we only check if it is
344            // guaranteed to not be possible.
345
346            let mut errors = Vec::new();
347
348            if tcx.features().min_generic_const_args() {
349                if !tcx.generics_of(item.def_id).is_own_empty() {
350                    errors.push(AssocConstViolation::Generic);
351                } else if !is_type_const {
352                    errors.push(AssocConstViolation::NonType);
353                }
354
355                let ty = ty::Binder::dummy(
356                    tcx.type_of(item.def_id).instantiate_identity().skip_norm_wip(),
357                );
358                if contains_illegal_self_type_reference(
359                    tcx,
360                    trait_def_id,
361                    ty,
362                    AllowSelfProjections::Yes,
363                ) {
364                    errors.push(AssocConstViolation::TypeReferencesSelf);
365                }
366            } else {
367                errors.push(AssocConstViolation::FeatureNotEnabled);
368            }
369
370            errors
371                .into_iter()
372                .map(|error| DynCompatibilityViolation::AssocConst(name, error, span()))
373                .collect()
374        }
375        ty::AssocKind::Fn { name, .. } => {
376            virtual_call_violations_for_method(tcx, trait_def_id, item)
377                .into_iter()
378                .map(|v| {
379                    let node = tcx.hir_get_if_local(item.def_id);
380                    // Get an accurate span depending on the violation.
381                    let span = match (&v, node) {
382                        (MethodViolation::ReferencesSelfInput(Some(span)), _) => *span,
383                        (MethodViolation::UndispatchableReceiver(Some(span)), _) => *span,
384                        (MethodViolation::ReferencesImplTraitInTrait(span), _) => *span,
385                        (MethodViolation::ReferencesSelfOutput, Some(node)) => {
386                            node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
387                        }
388                        _ => span(),
389                    };
390
391                    DynCompatibilityViolation::Method(name, v, span)
392                })
393                .collect()
394        }
395        ty::AssocKind::Type { data } => {
396            if !tcx.generics_of(item.def_id).is_own_empty()
397                && let ty::AssocTypeData::Normal(name) = data
398            {
399                vec![DynCompatibilityViolation::GenericAssocTy(name, span())]
400            } else {
401                // We will permit associated types if they are explicitly mentioned in the trait
402                // object type. We can't check this here, as here we only check if it is
403                // guaranteed to not be possible.
404                Vec::new()
405            }
406        }
407    }
408}
409
410/// Returns `Some(_)` if this method cannot be called on a trait
411/// object; this does not necessarily imply that the enclosing trait
412/// is dyn-incompatible, because the method might have a where clause
413/// `Self: Sized`.
414fn virtual_call_violations_for_method<'tcx>(
415    tcx: TyCtxt<'tcx>,
416    trait_def_id: DefId,
417    method: ty::AssocItem,
418) -> Vec<MethodViolation> {
419    let sig = tcx.fn_sig(method.def_id).instantiate_identity().skip_norm_wip();
420
421    // The method's first parameter must be named `self`
422    if !method.is_method() {
423        let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
424            generics,
425            kind: hir::TraitItemKind::Fn(sig, _),
426            ..
427        })) = tcx.hir_get_if_local(method.def_id).as_ref()
428        {
429            let sm = tcx.sess.source_map();
430            Some((
431                (
432                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("&self{0}",
                if sig.decl.inputs.is_empty() { "" } else { ", " }))
    })format!("&self{}", if sig.decl.inputs.is_empty() { "" } else { ", " }),
433                    sm.span_through_char(sig.span, '(').shrink_to_hi(),
434                ),
435                (
436                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} Self: Sized",
                generics.add_where_or_trailing_comma()))
    })format!("{} Self: Sized", generics.add_where_or_trailing_comma()),
437                    generics.tail_span_for_predicate_suggestion(),
438                ),
439            ))
440        } else {
441            None
442        };
443
444        // Not having `self` parameter messes up the later checks,
445        // so we need to return instead of pushing
446        return ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [MethodViolation::StaticMethod(sugg)]))vec![MethodViolation::StaticMethod(sugg)];
447    }
448
449    let mut errors = Vec::new();
450
451    for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
452        if contains_illegal_self_type_reference(
453            tcx,
454            trait_def_id,
455            sig.rebind(input_ty),
456            AllowSelfProjections::Yes,
457        ) {
458            let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
459                kind: hir::TraitItemKind::Fn(sig, _),
460                ..
461            })) = tcx.hir_get_if_local(method.def_id).as_ref()
462            {
463                Some(sig.decl.inputs[i].span)
464            } else {
465                None
466            };
467            errors.push(MethodViolation::ReferencesSelfInput(span));
468        }
469    }
470    if contains_illegal_self_type_reference(
471        tcx,
472        trait_def_id,
473        sig.output(),
474        AllowSelfProjections::Yes,
475    ) {
476        errors.push(MethodViolation::ReferencesSelfOutput);
477    }
478    if let Some(error) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
479        errors.push(error);
480    }
481    if sig.skip_binder().c_variadic() {
482        errors.push(MethodViolation::CVariadic);
483    }
484
485    // We can't monomorphize things like `fn foo<A>(...)`.
486    let own_counts = tcx.generics_of(method.def_id).own_counts();
487    if own_counts.types > 0 || own_counts.consts > 0 {
488        errors.push(MethodViolation::Generic);
489    }
490
491    let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
492
493    // `self: Self` can't be dispatched on.
494    // However, this is considered dyn compatible. We allow it as a special case here.
495    // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
496    // `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
497    if receiver_ty != tcx.types.self_param {
498        if !receiver_is_dispatchable(tcx, method, receiver_ty) {
499            let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
500                kind: hir::TraitItemKind::Fn(sig, _),
501                ..
502            })) = tcx.hir_get_if_local(method.def_id).as_ref()
503            {
504                Some(sig.decl.inputs[0].span)
505            } else {
506                None
507            };
508            errors.push(MethodViolation::UndispatchableReceiver(span));
509        } else {
510            // We confirm that the `receiver_is_dispatchable` is accurate later,
511            // see `check_receiver_correct`. It should be kept in sync with this code.
512        }
513    }
514
515    // NOTE: This check happens last, because it results in a lint, and not a
516    // hard error.
517    if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, _span)| {
518        // dyn Trait is okay:
519        //
520        //     trait Trait {
521        //         fn f(&self) where Self: 'static;
522        //     }
523        //
524        // because a trait object can't claim to live longer than the concrete
525        // type. If the lifetime bound holds on dyn Trait then it's guaranteed
526        // to hold as well on the concrete type.
527        if pred.as_type_outlives_clause().is_some() {
528            return false;
529        }
530
531        // dyn Trait is okay:
532        //
533        //     auto trait AutoTrait {}
534        //
535        //     trait Trait {
536        //         fn f(&self) where Self: AutoTrait;
537        //     }
538        //
539        // because `impl AutoTrait for dyn Trait` is disallowed by coherence.
540        // Traits with a default impl are implemented for a trait object if and
541        // only if the autotrait is one of the trait object's trait bounds, like
542        // in `dyn Trait + AutoTrait`. This guarantees that trait objects only
543        // implement auto traits if the underlying type does as well.
544        if let ty::ClauseKind::Trait(ty::TraitPredicate {
545            trait_ref: pred_trait_ref,
546            polarity: ty::PredicatePolarity::Positive,
547        }) = pred.kind().skip_binder()
548            && pred_trait_ref.self_ty() == tcx.types.self_param
549            && tcx.trait_is_auto(pred_trait_ref.def_id)
550        {
551            // Consider bounds like `Self: Bound<Self>`. Auto traits are not
552            // allowed to have generic parameters so `auto trait Bound<T> {}`
553            // would already have reported an error at the definition of the
554            // auto trait.
555            if pred_trait_ref.args.len() != 1 {
556                if !tcx.dcx().has_errors().is_some() {
    {
        ::core::panicking::panic_fmt(format_args!("auto traits cannot have generic parameters"));
    }
};assert!(
557                    tcx.dcx().has_errors().is_some(),
558                    "auto traits cannot have generic parameters"
559                );
560            }
561            return false;
562        }
563
564        contains_illegal_self_type_reference(tcx, trait_def_id, pred, AllowSelfProjections::Yes)
565    }) {
566        errors.push(MethodViolation::WhereClauseReferencesSelf);
567    }
568
569    errors
570}
571
572/// Performs a type instantiation to produce the version of `receiver_ty` when `Self = self_ty`.
573/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
574fn receiver_for_self_ty<'tcx>(
575    tcx: TyCtxt<'tcx>,
576    receiver_ty: Ty<'tcx>,
577    self_ty: Ty<'tcx>,
578    method_def_id: DefId,
579) -> Ty<'tcx> {
580    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:580",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(580u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("receiver_for_self_ty({0:?}, {1:?}, {2:?})",
                                                    receiver_ty, self_ty, method_def_id) as &dyn Value))])
            });
    } else { ; }
};debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
581    let args = GenericArgs::for_item(tcx, method_def_id, |param, _| {
582        if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
583    });
584
585    let result = EarlyBinder::bind(receiver_ty).instantiate(tcx, args).skip_norm_wip();
586    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:586",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(586u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("receiver_for_self_ty({0:?}, {1:?}, {2:?}) = {3:?}",
                                                    receiver_ty, self_ty, method_def_id, result) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(
587        "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
588        receiver_ty, self_ty, method_def_id, result
589    );
590    result
591}
592
593/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
594/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
595/// in the following way:
596/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`,
597/// - require the following bound:
598///
599///   ```ignore (not-rust)
600///   Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
601///   ```
602///
603///   where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
604///   (instantiation notation).
605///
606/// Some examples of receiver types and their required obligation:
607/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`,
608/// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`,
609/// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
610///
611/// The only case where the receiver is not dispatchable, but is still a valid receiver
612/// type (just not dyn compatible), is when there is more than one level of pointer indirection.
613/// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
614/// is no way, or at least no inexpensive way, to coerce the receiver from the version where
615/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
616/// contained by the trait object, because the object that needs to be coerced is behind
617/// a pointer.
618///
619/// If lowering already produced an error in the receiver type, we conservatively treat it as
620/// undispatchable instead of asking the solver.
621///
622/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result in
623/// a new check that `Trait` is dyn-compatible, creating a cycle.
624/// Instead, we emulate a placeholder by introducing a new type parameter `U` such that
625/// `Self: Unsize<U>` and `U: Trait + MetaSized`, and use `U` in place of `dyn Trait`.
626///
627/// Written as a chalk-style query:
628/// ```ignore (not-rust)
629/// forall (U: Trait + MetaSized) {
630///     if (Self: Unsize<U>) {
631///         Receiver: DispatchFromDyn<Receiver[Self => U]>
632///     }
633/// }
634/// ```
635/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
636/// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
637/// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
638//
639// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
640// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
641// `self: Wrapper<Self>`.
642fn receiver_is_dispatchable<'tcx>(
643    tcx: TyCtxt<'tcx>,
644    method: ty::AssocItem,
645    receiver_ty: Ty<'tcx>,
646) -> bool {
647    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:647",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(647u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("receiver_is_dispatchable: method = {0:?}, receiver_ty = {1:?}",
                                                    method, receiver_ty) as &dyn Value))])
            });
    } else { ; }
};debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
648
649    if receiver_ty.references_error() {
650        return false;
651    }
652
653    let (Some(unsize_did), Some(dispatch_from_dyn_did)) =
654        (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait())
655    else {
656        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:656",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(656u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("receiver_is_dispatchable: Missing `Unsize` or `DispatchFromDyn` traits")
                                            as &dyn Value))])
            });
    } else { ; }
};debug!("receiver_is_dispatchable: Missing `Unsize` or `DispatchFromDyn` traits");
657        return false;
658    };
659
660    // the type `U` in the query
661    // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now.
662    let unsized_self_ty: Ty<'tcx> =
663        Ty::new_param(tcx, u32::MAX, rustc_span::sym::RustaceansAreAwesome);
664
665    // `Receiver[Self => U]`
666    let unsized_receiver_ty =
667        receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
668
669    // create a modified param env, with `Self: Unsize<U>` and `U: Trait` (and all of
670    // its supertraits) added to caller bounds. `U: MetaSized` is already implied here.
671    let param_env = {
672        // N.B. We generally want to emulate the construction of the `unnormalized_param_env`
673        // in the param-env query here. The fact that we don't just start with the clauses
674        // in the param-env of the method is because those are already normalized, and mixing
675        // normalized and unnormalized copies of predicates in `normalize_param_env_or_error`
676        // will cause ambiguity that the user can't really avoid.
677        //
678        // We leave out certain complexities of the param-env query here. Specifically, we:
679        // 1. Do not add `[const]` bounds since there are no `dyn const Trait`s.
680        // 2. Do not add RPITIT self projection bounds for defaulted methods, since we
681        //    are not constructing a param-env for "inside" of the body of the defaulted
682        //    method, so we don't really care about projecting to a specific RPIT type,
683        //    and because RPITITs are not dyn compatible (yet).
684        let mut predicates: Vec<_> = tcx
685            .predicates_of(method.def_id)
686            .instantiate_identity(tcx)
687            .predicates
688            .into_iter()
689            .map(Unnormalized::skip_norm_wip)
690            .collect();
691
692        // Self: Unsize<U>
693        let unsize_predicate =
694            ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]);
695        predicates.push(unsize_predicate.upcast(tcx));
696
697        // U: Trait<Arg1, ..., ArgN>
698        let trait_def_id = method.trait_container(tcx).unwrap();
699        let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| {
700            if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
701        });
702        let trait_predicate = ty::TraitRef::new_from_args(tcx, trait_def_id, args);
703        predicates.push(trait_predicate.upcast(tcx));
704
705        let meta_sized_predicate = {
706            let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, DUMMY_SP);
707            ty::TraitRef::new(tcx, meta_sized_did, [unsized_self_ty]).upcast(tcx)
708        };
709        predicates.push(meta_sized_predicate);
710
711        normalize_param_env_or_error(
712            tcx,
713            ty::ParamEnv::new(tcx.mk_clauses(&predicates)),
714            ObligationCause::dummy_with_span(tcx.def_span(method.def_id)),
715        )
716    };
717
718    // Receiver: DispatchFromDyn<Receiver[Self => U]>
719    let obligation = {
720        let predicate =
721            ty::TraitRef::new(tcx, dispatch_from_dyn_did, [receiver_ty, unsized_receiver_ty]);
722
723        Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
724    };
725
726    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
727    // the receiver is dispatchable iff the obligation holds
728    infcx.predicate_must_hold_modulo_regions(&obligation)
729}
730
731#[derive(#[automatically_derived]
impl ::core::marker::Copy for AllowSelfProjections { }Copy, #[automatically_derived]
impl ::core::clone::Clone for AllowSelfProjections {
    #[inline]
    fn clone(&self) -> AllowSelfProjections { *self }
}Clone)]
732enum AllowSelfProjections {
733    Yes,
734    No,
735}
736
737/// Check if the given value contains illegal `Self` references.
738///
739/// This is somewhat subtle. In general, we want to forbid references to `Self` in the
740/// argument and return types, since the value of `Self` is erased.
741///
742/// However, there is one exception: It is ok to reference `Self` in order to access an
743/// associated type of the current trait, since we retain the value of those associated
744/// types in the trait object type itself.
745///
746/// The same thing holds for associated consts under feature `min_generic_const_args`.
747///
748/// ```rust,ignore (example)
749/// trait SuperTrait {
750///     type X;
751/// }
752///
753/// trait Trait : SuperTrait {
754///     type Y;
755///     fn foo(&self, x: Self) // bad
756///     fn foo(&self) -> Self // bad
757///     fn foo(&self) -> Option<Self> // bad
758///     fn foo(&self) -> Self::Y // OK, desugars to next example
759///     fn foo(&self) -> <Self as Trait>::Y // OK
760///     fn foo(&self) -> Self::X // OK, desugars to next example
761///     fn foo(&self) -> <Self as SuperTrait>::X // OK
762/// }
763/// ```
764///
765/// However, it is not as simple as allowing `Self` in a projected
766/// type, because there are illegal ways to use `Self` as well:
767///
768/// ```rust,ignore (example)
769/// trait Trait : SuperTrait {
770///     ...
771///     fn foo(&self) -> <Self as SomeOtherTrait>::X;
772/// }
773/// ```
774///
775/// Here we will not have the type of `X` recorded in the
776/// object type, and we cannot resolve `Self as SomeOtherTrait`
777/// without knowing what `Self` is.
778fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
779    tcx: TyCtxt<'tcx>,
780    trait_def_id: DefId,
781    value: T,
782    allow_self_projections: AllowSelfProjections,
783) -> bool {
784    value
785        .visit_with(&mut IllegalSelfTypeVisitor {
786            tcx,
787            trait_def_id,
788            supertraits: None,
789            allow_self_projections,
790        })
791        .is_break()
792}
793
794struct IllegalSelfTypeVisitor<'tcx> {
795    tcx: TyCtxt<'tcx>,
796    trait_def_id: DefId,
797    supertraits: Option<Vec<ty::TraitRef<'tcx>>>,
798    allow_self_projections: AllowSelfProjections,
799}
800
801impl<'tcx> IllegalSelfTypeVisitor<'tcx> {
802    fn is_supertrait_of_current_trait(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
803        // Compute supertraits of current trait lazily.
804        let supertraits = self.supertraits.get_or_insert_with(|| {
805            util::supertraits(
806                self.tcx,
807                ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id)),
808            )
809            .map(|trait_ref| {
810                self.tcx.erase_and_anonymize_regions(
811                    self.tcx.instantiate_bound_regions_with_erased(trait_ref),
812                )
813            })
814            .collect()
815        });
816
817        // Determine whether the given trait ref is in fact a supertrait of the current trait.
818        // In that case, any derived projections are legal, because the term will be specified
819        // in the trait object type.
820        // Note that we can just use direct equality here because all of these types are part of
821        // the formal parameter listing, and hence there should be no inference variables.
822        let trait_ref = trait_ref
823            .fold_with(&mut EraseEscapingBoundRegions { tcx: self.tcx, binder: ty::INNERMOST });
824        supertraits.contains(&trait_ref)
825    }
826}
827
828impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
829    type Result = ControlFlow<()>;
830
831    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
832        match ty.kind() {
833            ty::Param(_) => {
834                if ty == self.tcx.types.self_param {
835                    ControlFlow::Break(())
836                } else {
837                    ControlFlow::Continue(())
838                }
839            }
840            ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, .. })
841                if self.tcx.is_impl_trait_in_trait(*def_id) =>
842            {
843                // We'll deny these later in their own pass
844                ControlFlow::Continue(())
845            }
846            ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { .. }, .. }) => {
847                match self.allow_self_projections {
848                    AllowSelfProjections::Yes => {
849                        // Only walk contained types if the parent trait is not a supertrait.
850                        if self.is_supertrait_of_current_trait(proj.trait_ref(self.tcx)) {
851                            ControlFlow::Continue(())
852                        } else {
853                            ty.super_visit_with(self)
854                        }
855                    }
856                    AllowSelfProjections::No => ty.super_visit_with(self),
857                }
858            }
859            _ => ty.super_visit_with(self),
860        }
861    }
862
863    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
864        let ct = self.tcx.expand_abstract_consts(ct);
865
866        match ct.kind() {
867            ty::ConstKind::Unevaluated(proj) if self.tcx.features().min_generic_const_args() => {
868                match self.allow_self_projections {
869                    AllowSelfProjections::Yes
870                        if let trait_def_id = self.tcx.parent(proj.def)
871                            && self.tcx.def_kind(trait_def_id) == DefKind::Trait =>
872                    {
873                        let trait_ref = ty::TraitRef::from_assoc(self.tcx, trait_def_id, proj.args);
874
875                        // Only walk contained consts if the parent trait is not a supertrait.
876                        if self.is_supertrait_of_current_trait(trait_ref) {
877                            ControlFlow::Continue(())
878                        } else {
879                            ct.super_visit_with(self)
880                        }
881                    }
882                    _ => ct.super_visit_with(self),
883                }
884            }
885            _ => ct.super_visit_with(self),
886        }
887    }
888}
889
890struct EraseEscapingBoundRegions<'tcx> {
891    tcx: TyCtxt<'tcx>,
892    binder: ty::DebruijnIndex,
893}
894
895impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEscapingBoundRegions<'tcx> {
896    fn cx(&self) -> TyCtxt<'tcx> {
897        self.tcx
898    }
899
900    fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
901    where
902        T: TypeFoldable<TyCtxt<'tcx>>,
903    {
904        self.binder.shift_in(1);
905        let result = t.super_fold_with(self);
906        self.binder.shift_out(1);
907        result
908    }
909
910    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
911        if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind()
912            && debruijn < self.binder
913        {
914            r
915        } else {
916            self.tcx.lifetimes.re_erased
917        }
918    }
919}
920
921fn contains_illegal_impl_trait_in_trait<'tcx>(
922    tcx: TyCtxt<'tcx>,
923    fn_def_id: DefId,
924    ty: ty::Binder<'tcx, Ty<'tcx>>,
925) -> Option<MethodViolation> {
926    let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
927
928    if tcx.asyncness(fn_def_id).is_async() {
929        // Rendering the error as a separate `async-specific` message is better.
930        Some(MethodViolation::AsyncFn)
931    } else {
932        ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
933    }
934}
935
936struct IllegalRpititVisitor<'tcx> {
937    tcx: TyCtxt<'tcx>,
938    allowed: Option<ty::AliasTy<'tcx>>,
939}
940
941impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
942    type Result = ControlFlow<MethodViolation>;
943
944    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
945        if let ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { def_id }, .. }) = *ty.kind()
946            && Some(proj) != self.allowed
947            && self.tcx.is_impl_trait_in_trait(def_id)
948        {
949            ControlFlow::Break(MethodViolation::ReferencesImplTraitInTrait(
950                self.tcx.def_span(def_id),
951            ))
952        } else {
953            ty.super_visit_with(self)
954        }
955    }
956}
957
958pub(crate) fn provide(providers: &mut Providers) {
959    *providers = Providers {
960        dyn_compatibility_violations,
961        is_dyn_compatible,
962        generics_require_sized_self,
963        ..*providers
964    };
965}