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_attr_ir::lang_items::LangItem;
10use rustc_errors::FatalError;
11use rustc_hir as hir;
12use rustc_hir::def_id::DefId;
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, kw, sym};
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.
37{}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::DEBUG <=
                ::tracing::level_filters::LevelFilter::current() || { false }
    {
    __tracing_attr_span =
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("hir_ty_lowering_dyn_compatibility_violations",
                                "rustc_trait_selection::traits::dyn_compatibility",
                                ::tracing::Level::DEBUG,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                                ::tracing_core::__macro_support::Option::Some(37u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("trait_def_id")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("trait_def_id");
                                                    NAME.as_str()
                                                }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::SPAN)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let mut interest = ::tracing::subscriber::Interest::never();
            if ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        { interest = __CALLSITE.interest(); !interest.is_never() }
                    &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest) {
                let meta = __CALLSITE.metadata();
                ::tracing::Span::new(meta,
                    &{
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&trait_def_id)
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[allow(unknown_lints, unreachable_code, clippy ::
                    diverging_sub_expression, clippy :: empty_loop, clippy ::
                    let_unit_value, clippy :: let_with_type_underscore, clippy
                    :: needless_return, clippy :: unreachable)]
                    if false {
                        let __tracing_attr_fake_return:
                                Vec<DynCompatibilityViolation> = loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        if true {
                            if !tcx.generics_of(trait_def_id).has_self {
                                ::core::panicking::panic("assertion failed: tcx.generics_of(trait_def_id).has_self")
                            };
                        };
                        elaborate::supertrait_def_ids(tcx,
                                            trait_def_id).map(|def_id|
                                            clauses_reference_self(tcx, def_id,
                                                true)).filter(|spans|
                                        !spans.is_empty()).map(DynCompatibilityViolation::SupertraitSelf).collect()
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:37",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(37u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[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| clauses_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 /rustc-dev/5f4effd579500175af844241eb179e756190f1e7/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("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("dyn_compatibility_violations: {0:?}",
                                                    trait_def_id) as &dyn ::tracing::field::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 /rustc-dev/5f4effd579500175af844241eb179e756190f1e7/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("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("is_vtable_safe_method({0:?}, {1:?})",
                                                    trait_def_id, method) as &dyn ::tracing::field::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
81{}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::DEBUG <=
                ::tracing::level_filters::LevelFilter::current() || { false }
    {
    __tracing_attr_span =
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("dyn_compatibility_violations_for_trait",
                                "rustc_trait_selection::traits::dyn_compatibility",
                                ::tracing::Level::DEBUG,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                                ::tracing_core::__macro_support::Option::Some(81u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("trait_def_id")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("trait_def_id");
                                                    NAME.as_str()
                                                }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::SPAN)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let mut interest = ::tracing::subscriber::Interest::never();
            if ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        { interest = __CALLSITE.interest(); !interest.is_never() }
                    &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest) {
                let meta = __CALLSITE.metadata();
                ::tracing::Span::new(meta,
                    &{
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&trait_def_id)
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[allow(unknown_lints, unreachable_code, clippy ::
                    diverging_sub_expression, clippy :: empty_loop, clippy ::
                    let_unit_value, clippy :: let_with_type_underscore, clippy
                    :: needless_return, clippy :: unreachable)]
                    if false {
                        let __tracing_attr_fake_return:
                                Vec<DynCompatibilityViolation> = loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        let mut violations: Vec<_> =
                            tcx.associated_items(trait_def_id).in_definition_order().flat_map(|&item|
                                        dyn_compatibility_violations_for_assoc_item(tcx,
                                            trait_def_id, item)).collect();
                        if trait_has_sized_self(tcx, trait_def_id) {
                            let spans = get_sized_bounds(tcx, trait_def_id);
                            violations.push(DynCompatibilityViolation::SizedSelf(spans));
                        } else if let Some(span) =
                                tcx.trait_def(trait_def_id).force_dyn_incompatible {
                            violations.push(DynCompatibilityViolation::ExplicitlyDynIncompatible([span].into()));
                        }
                        let spans =
                            clauses_reference_self(tcx, trait_def_id, false);
                        if !spans.is_empty() {
                            violations.push(DynCompatibilityViolation::SupertraitSelf(spans));
                        }
                        let spans = bounds_reference_self(tcx, trait_def_id);
                        if !spans.is_empty() {
                            violations.push(DynCompatibilityViolation::SupertraitSelf(spans));
                        }
                        let spans =
                            super_clauses_have_non_lifetime_binders(tcx, trait_def_id);
                        if !spans.is_empty() {
                            violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
                        }
                        let spans =
                            super_clauses_are_unconditionally_const(tcx, trait_def_id);
                        if !spans.is_empty() {
                            violations.push(DynCompatibilityViolation::SupertraitConst(spans));
                        }
                        violations
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:81",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(81u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[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 = clauses_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_clauses_have_non_lifetime_binders(tcx, trait_def_id);
111    if !spans.is_empty() {
112        violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
113    }
114    let spans = super_clauses_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 clauses_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 clauses = if supertraits_only {
179        tcx.explicit_super_clauses_of(trait_def_id).skip_binder()
180    } else {
181        tcx.clauses_of(trait_def_id).clauses
182    };
183    clauses
184        .iter()
185        .map(|&(clause, sp)| (clause.instantiate_supertrait(tcx, trait_ref), sp))
186        .filter_map(|(clause, sp)| {
187            // Super clauses 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.as_slice()[1..]
227                .iter()
228                .any(|&arg| {
229                    contains_illegal_self_type_reference(
230                        tcx,
231                        trait_def_id,
232                        arg,
233                        allow_self_projections,
234                    )
235                })
236                .then_some(sp)
237        }
238        ty::ClauseKind::Projection(ref data) => {
239            // And similarly for projections. This should be redundant with
240            // the previous check because any projection should have a
241            // matching `Trait` predicate with the same inputs, but we do
242            // the check to be safe.
243            //
244            // It's also won't be redundant if we allow type-generic associated
245            // types for trait objects.
246            //
247            // Note that we *do* allow projection *outputs* to contain
248            // `Self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
249            // we just require the user to specify *both* outputs
250            // in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
251            //
252            // This is ALT2 in issue #56288, see that for discussion of the
253            // possible alternatives.
254            data.projection_term.args.as_slice()[1..]
255                .iter()
256                .any(|&arg| {
257                    contains_illegal_self_type_reference(
258                        tcx,
259                        trait_def_id,
260                        arg,
261                        allow_self_projections,
262                    )
263                })
264                .then_some(sp)
265        }
266        ty::ClauseKind::ConstArgHasType(_ct, ty) => {
267            contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections)
268                .then_some(sp)
269        }
270
271        ty::ClauseKind::WellFormed(..)
272        | ty::ClauseKind::TypeOutlives(..)
273        | ty::ClauseKind::RegionOutlives(..)
274        | ty::ClauseKind::HostEffect(..)
275        | ty::ClauseKind::UnstableFeature(_) => None,
276
277        // FIXME(generic_const_exprs): this can mention `Self`
278        ty::ClauseKind::ConstEvaluatable(..) => None,
279    }
280}
281
282fn super_clauses_have_non_lifetime_binders(
283    tcx: TyCtxt<'_>,
284    trait_def_id: DefId,
285) -> SmallVec<[Span; 1]> {
286    tcx.explicit_super_clauses_of(trait_def_id)
287        .iter_identity_copied()
288        .map(Unnormalized::skip_norm_wip)
289        .filter_map(|(clause, span)| clause.has_non_region_bound_vars().then_some(span))
290        .collect()
291}
292
293/// Checks for `const Trait` supertraits. We're okay with `[const] Trait`,
294/// supertraits since for a non-const instantiation of that trait, the
295/// conditionally-const supertrait is also not required to be const.
296fn super_clauses_are_unconditionally_const(
297    tcx: TyCtxt<'_>,
298    trait_def_id: DefId,
299) -> SmallVec<[Span; 1]> {
300    tcx.explicit_super_clauses_of(trait_def_id)
301        .iter_identity_copied()
302        .map(Unnormalized::skip_norm_wip)
303        .filter_map(|(clause, span)| {
304            if let ty::ClauseKind::HostEffect(_) = clause.kind().skip_binder() {
305                Some(span)
306            } else {
307                None
308            }
309        })
310        .collect()
311}
312
313fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
314    tcx.generics_require_sized_self(trait_def_id)
315}
316
317fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
318    let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
319        return false; /* No Sized trait, can't require it! */
320    };
321
322    // Search for a clause like `Self: Sized` amongst the trait bounds.
323    let clauses: Vec<_> = tcx
324        .clauses_of(def_id)
325        .instantiate_identity(tcx)
326        .clauses
327        .into_iter()
328        .map(Unnormalized::skip_norm_wip)
329        .collect();
330    elaborate(tcx, clauses).any(|clause| match clause.kind().skip_binder() {
331        ty::ClauseKind::Trait(ref trait_pred) => {
332            trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
333        }
334        ty::ClauseKind::RegionOutlives(_)
335        | ty::ClauseKind::TypeOutlives(_)
336        | ty::ClauseKind::Projection(_)
337        | ty::ClauseKind::ConstArgHasType(_, _)
338        | ty::ClauseKind::WellFormed(_)
339        | ty::ClauseKind::ConstEvaluatable(_)
340        | ty::ClauseKind::UnstableFeature(_)
341        | ty::ClauseKind::HostEffect(..) => false,
342    })
343}
344
345{}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::DEBUG <=
                ::tracing::level_filters::LevelFilter::current() || { false }
    {
    __tracing_attr_span =
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("dyn_compatibility_violations_for_assoc_item",
                                "rustc_trait_selection::traits::dyn_compatibility",
                                ::tracing::Level::DEBUG,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                                ::tracing_core::__macro_support::Option::Some(345u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("trait_def_id")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("trait_def_id");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("item")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("item");
                                                    NAME.as_str()
                                                }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::SPAN)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let mut interest = ::tracing::subscriber::Interest::never();
            if ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        { interest = __CALLSITE.interest(); !interest.is_never() }
                    &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest) {
                let meta = __CALLSITE.metadata();
                ::tracing::Span::new(meta,
                    &{
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&trait_def_id)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&item)
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[allow(unknown_lints, unreachable_code, clippy ::
                    diverging_sub_expression, clippy :: empty_loop, clippy ::
                    let_unit_value, clippy :: let_with_type_underscore, clippy
                    :: needless_return, clippy :: unreachable)]
                    if false {
                        let __tracing_attr_fake_return:
                                Vec<DynCompatibilityViolation> = loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        if tcx.defaultness(item.def_id).is_final() {
                            return Vec::new();
                        }
                        if tcx.generics_require_sized_self(item.def_id) {
                            return Vec::new();
                        }
                        let span = || item.ident(tcx).span;
                        match item.kind {
                            ty::AssocKind::Const { data: ty::AssocConstData::Anonymous }
                                => {
                                {
                                    ::core::panicking::panic_fmt(format_args!("anonymous associated consts shouldn\'t end up here"));
                                }
                            }
                            ty::AssocKind::Const { data: ty::AssocConstData::Named(name)
                                } => {
                                let mut errors = Vec::new();
                                if tcx.features().gca_min_const_items() {
                                    if !tcx.generics_of(item.def_id).is_own_empty() {
                                        errors.push(AssocConstViolation::Generic);
                                    } else if !tcx.is_always_gca(item.def_id) &&
                                            !tcx.features().gca_const_items() {
                                        errors.push(AssocConstViolation::NonType);
                                    }
                                    let ty =
                                        ty::Binder::dummy(tcx.type_of(item.def_id).instantiate_identity().skip_norm_wip());
                                    if contains_illegal_self_type_reference(tcx, trait_def_id,
                                            ty, AllowSelfProjections::Yes) {
                                        errors.push(AssocConstViolation::TypeReferencesSelf);
                                    }
                                } else {
                                    errors.push(AssocConstViolation::FeatureNotEnabled);
                                }
                                errors.into_iter().map(|error|
                                            DynCompatibilityViolation::AssocConst(name, error,
                                                span())).collect()
                            }
                            ty::AssocKind::Fn { name, .. } => {
                                virtual_call_violations_for_method(tcx, trait_def_id,
                                                item).into_iter().map(|v|
                                            {
                                                let node = tcx.hir_get_if_local(item.def_id);
                                                let span =
                                                    match (&v, node) {
                                                        (MethodViolation::ReferencesSelfInput(Some(span)), _) =>
                                                            *span,
                                                        (MethodViolation::UndispatchableReceiver(Some((span, _))),
                                                            _) => *span,
                                                        (MethodViolation::ReferencesImplTraitInTrait(span), _) =>
                                                            *span,
                                                        (MethodViolation::ReferencesSelfOutput, Some(node)) => {
                                                            node.fn_decl().map_or(item.ident(tcx).span,
                                                                |decl| decl.output.span())
                                                        }
                                                        _ => span(),
                                                    };
                                                DynCompatibilityViolation::Method(name, v, span)
                                            }).collect()
                            }
                            ty::AssocKind::Type { data } => {
                                if !tcx.generics_of(item.def_id).is_own_empty() &&
                                        let ty::AssocTypeData::Normal(name) = data {
                                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                                            [DynCompatibilityViolation::GenericAssocTy(name, span())]))
                                } else { Vec::new() }
                            }
                        }
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:345",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(345u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::dyn_compatibility"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(level = "debug", skip(tcx), ret)]
346pub fn dyn_compatibility_violations_for_assoc_item(
347    tcx: TyCtxt<'_>,
348    trait_def_id: DefId,
349    item: ty::AssocItem,
350) -> Vec<DynCompatibilityViolation> {
351    // `final` assoc functions don't prevent a trait from being dyn-compatible
352    if tcx.defaultness(item.def_id).is_final() {
353        return Vec::new();
354    }
355
356    // Any item that has a `Self: Sized` requisite is otherwise exempt from the regulations.
357    if tcx.generics_require_sized_self(item.def_id) {
358        return Vec::new();
359    }
360
361    let span = || item.ident(tcx).span;
362
363    match item.kind {
364        ty::AssocKind::Const { data: ty::AssocConstData::Anonymous } => {
365            panic!("anonymous associated consts shouldn't end up here")
366        }
367        ty::AssocKind::Const { data: ty::AssocConstData::Named(name) } => {
368            // We will permit type associated consts if they are explicitly mentioned in the
369            // trait object type. We can't check this here, as here we only check if it is
370            // guaranteed to not be possible.
371
372            let mut errors = Vec::new();
373
374            if tcx.features().gca_min_const_items() {
375                if !tcx.generics_of(item.def_id).is_own_empty() {
376                    errors.push(AssocConstViolation::Generic);
377                } else if !tcx.is_always_gca(item.def_id) && !tcx.features().gca_const_items() {
378                    errors.push(AssocConstViolation::NonType);
379                }
380
381                let ty = ty::Binder::dummy(
382                    tcx.type_of(item.def_id).instantiate_identity().skip_norm_wip(),
383                );
384                if contains_illegal_self_type_reference(
385                    tcx,
386                    trait_def_id,
387                    ty,
388                    AllowSelfProjections::Yes,
389                ) {
390                    errors.push(AssocConstViolation::TypeReferencesSelf);
391                }
392            } else {
393                errors.push(AssocConstViolation::FeatureNotEnabled);
394            }
395
396            errors
397                .into_iter()
398                .map(|error| DynCompatibilityViolation::AssocConst(name, error, span()))
399                .collect()
400        }
401        ty::AssocKind::Fn { name, .. } => {
402            virtual_call_violations_for_method(tcx, trait_def_id, item)
403                .into_iter()
404                .map(|v| {
405                    let node = tcx.hir_get_if_local(item.def_id);
406                    // Get an accurate span depending on the violation.
407                    let span = match (&v, node) {
408                        (MethodViolation::ReferencesSelfInput(Some(span)), _) => *span,
409                        (MethodViolation::UndispatchableReceiver(Some((span, _))), _) => *span,
410                        (MethodViolation::ReferencesImplTraitInTrait(span), _) => *span,
411                        (MethodViolation::ReferencesSelfOutput, Some(node)) => {
412                            node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
413                        }
414                        _ => span(),
415                    };
416
417                    DynCompatibilityViolation::Method(name, v, span)
418                })
419                .collect()
420        }
421        ty::AssocKind::Type { data } => {
422            if !tcx.generics_of(item.def_id).is_own_empty()
423                && let ty::AssocTypeData::Normal(name) = data
424            {
425                vec![DynCompatibilityViolation::GenericAssocTy(name, span())]
426            } else {
427                // We will permit associated types if they are explicitly mentioned in the trait
428                // object type. We can't check this here, as here we only check if it is
429                // guaranteed to not be possible.
430                Vec::new()
431            }
432        }
433    }
434}
435
436/// Returns `Some(_)` if this method cannot be called on a trait
437/// object; this does not necessarily imply that the enclosing trait
438/// is dyn-incompatible, because the method might have a where clause
439/// `Self: Sized`.
440fn virtual_call_violations_for_method<'tcx>(
441    tcx: TyCtxt<'tcx>,
442    trait_def_id: DefId,
443    method: ty::AssocItem,
444) -> Vec<MethodViolation> {
445    let sig = tcx.fn_sig(method.def_id).instantiate_identity().skip_norm_wip();
446
447    // The method's first parameter must be named `self`
448    if !method.is_method() {
449        let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
450            generics,
451            kind: hir::TraitItemKind::Fn(sig, _),
452            ..
453        })) = tcx.hir_get_if_local(method.def_id).as_ref()
454        {
455            let sm = tcx.sess.source_map();
456            Some((
457                (
458                    ::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 { ", " }),
459                    sm.span_through_char(sig.span, '(').shrink_to_hi(),
460                ),
461                (
462                    ::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()),
463                    generics.tail_span_for_predicate_suggestion(),
464                ),
465            ))
466        } else {
467            None
468        };
469
470        // Not having `self` parameter messes up the later checks,
471        // so we need to return instead of pushing
472        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)];
473    }
474
475    let mut errors = Vec::new();
476
477    for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
478        if contains_illegal_self_type_reference(
479            tcx,
480            trait_def_id,
481            sig.rebind(input_ty),
482            AllowSelfProjections::Yes,
483        ) {
484            let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
485                kind: hir::TraitItemKind::Fn(sig, _),
486                ..
487            })) = tcx.hir_get_if_local(method.def_id).as_ref()
488            {
489                Some(sig.decl.inputs[i].span)
490            } else {
491                None
492            };
493            errors.push(MethodViolation::ReferencesSelfInput(span));
494        }
495    }
496    if contains_illegal_self_type_reference(
497        tcx,
498        trait_def_id,
499        sig.output(),
500        AllowSelfProjections::Yes,
501    ) {
502        errors.push(MethodViolation::ReferencesSelfOutput);
503    }
504    if let Some(error) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
505        errors.push(error);
506    }
507    if sig.skip_binder().c_variadic() {
508        errors.push(MethodViolation::CVariadic);
509    }
510
511    // We can't monomorphize things like `fn foo<A>(...)`.
512    let own_counts = tcx.generics_of(method.def_id).own_counts();
513    if own_counts.types > 0 || own_counts.consts > 0 {
514        errors.push(MethodViolation::Generic);
515    }
516
517    let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
518
519    // `self: Self` can't be dispatched on.
520    // However, this is considered dyn compatible. We allow it as a special case here.
521    // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
522    // `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
523    if receiver_ty != tcx.types.self_param {
524        if !receiver_is_dispatchable(tcx, method, receiver_ty) {
525            let span_n_lt = if let Some(hir::Node::TraitItem(hir::TraitItem {
526                kind: hir::TraitItemKind::Fn(sig, trait_fn),
527                ..
528            })) = tcx.hir_get_if_local(method.def_id).as_ref()
529            {
530                // If we have `self: &'a Ty`, get `'a`, so that we can suggest `&'a self`.
531                let lt = match sig.decl.inputs[0].kind {
532                    hir::TyKind::Ref(lt, ..) if lt.ident.name == kw::UnderscoreLifetime => {
533                        sym::empty
534                    }
535                    hir::TyKind::Ref(lt, ..) => lt.ident.name,
536                    _ => sym::empty,
537                };
538                // Get the `Span` for all of `self: Ty`, not just `Ty`.
539                match trait_fn {
540                    hir::TraitFn::Required([Some(name), ..])
541                        if name.span.ctxt() == sig.decl.inputs[0].span.ctxt() =>
542                    {
543                        Some(name.span.to(sig.decl.inputs[0].span))
544                    }
545                    hir::TraitFn::Provided(body_id)
546                        if let body = tcx.hir_body(*body_id)
547                            && let Some(p) = body.params.get(0)
548                            && p.span.ctxt() == p.ty_span.ctxt() =>
549                    {
550                        Some(p.span.to(p.ty_span))
551                    }
552                    _ => None,
553                }
554                .map(|sp| (sp, lt))
555            } else {
556                None
557            };
558            errors.push(MethodViolation::UndispatchableReceiver(span_n_lt));
559        } else {
560            // We confirm that the `receiver_is_dispatchable` is accurate later,
561            // see `check_receiver_correct`. It should be kept in sync with this code.
562        }
563    }
564
565    // NOTE: This check happens last, because it results in a lint, and not a
566    // hard error.
567    if tcx.clauses_of(method.def_id).clauses.iter().any(|&(clause, _span)| {
568        // dyn Trait is okay:
569        //
570        //     trait Trait {
571        //         fn f(&self) where Self: 'static;
572        //     }
573        //
574        // because a trait object can't claim to live longer than the concrete
575        // type. If the lifetime bound holds on dyn Trait then it's guaranteed
576        // to hold as well on the concrete type.
577        if clause.as_type_outlives_clause().is_some() {
578            return false;
579        }
580
581        // dyn Trait is okay:
582        //
583        //     auto trait AutoTrait {}
584        //
585        //     trait Trait {
586        //         fn f(&self) where Self: AutoTrait;
587        //     }
588        //
589        // because `impl AutoTrait for dyn Trait` is disallowed by coherence.
590        // Traits with a default impl are implemented for a trait object if and
591        // only if the autotrait is one of the trait object's trait bounds, like
592        // in `dyn Trait + AutoTrait`. This guarantees that trait objects only
593        // implement auto traits if the underlying type does as well.
594        if let ty::ClauseKind::Trait(ty::TraitClause {
595            trait_ref: pred_trait_ref,
596            polarity: ty::ClausePolarity::Positive,
597        }) = clause.kind().skip_binder()
598            && pred_trait_ref.self_ty() == tcx.types.self_param
599            && tcx.trait_is_auto(pred_trait_ref.def_id)
600        {
601            // Consider bounds like `Self: Bound<Self>`. Auto traits are not
602            // allowed to have generic parameters so `auto trait Bound<T> {}`
603            // would already have reported an error at the definition of the
604            // auto trait.
605            if pred_trait_ref.args.len() != 1 {
606                if !tcx.dcx().has_errors().is_some() {
    {
        ::core::panicking::panic_fmt(format_args!("auto traits cannot have generic parameters"));
    }
};assert!(
607                    tcx.dcx().has_errors().is_some(),
608                    "auto traits cannot have generic parameters"
609                );
610            }
611            return false;
612        }
613
614        contains_illegal_self_type_reference(tcx, trait_def_id, clause, AllowSelfProjections::Yes)
615    }) {
616        errors.push(MethodViolation::WhereClauseReferencesSelf);
617    }
618
619    errors
620}
621
622/// Performs a type instantiation to produce the version of `receiver_ty` when `Self = self_ty`.
623/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
624fn receiver_for_self_ty<'tcx>(
625    tcx: TyCtxt<'tcx>,
626    receiver_ty: Ty<'tcx>,
627    self_ty: Ty<'tcx>,
628    method_def_id: DefId,
629) -> Ty<'tcx> {
630    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:630",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(630u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("receiver_for_self_ty({0:?}, {1:?}, {2:?})",
                                                    receiver_ty, self_ty, method_def_id) as
                                            &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
631    let args = GenericArgs::for_item(tcx, method_def_id, |param, _| {
632        if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
633    });
634
635    let result = EarlyBinder::bind(tcx, receiver_ty).instantiate(tcx, args).skip_norm_wip();
636    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:636",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(636u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::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 ::tracing::field::Value))])
            });
    } else { ; }
};debug!(
637        "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
638        receiver_ty, self_ty, method_def_id, result
639    );
640    result
641}
642
643/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
644/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
645/// in the following way:
646/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`,
647/// - require the following bound:
648///
649///   ```ignore (not-rust)
650///   Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
651///   ```
652///
653///   where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
654///   (instantiation notation).
655///
656/// Some examples of receiver types and their required obligation:
657/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`,
658/// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`,
659/// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
660///
661/// The only case where the receiver is not dispatchable, but is still a valid receiver
662/// type (just not dyn compatible), is when there is more than one level of pointer indirection.
663/// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
664/// is no way, or at least no inexpensive way, to coerce the receiver from the version where
665/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
666/// contained by the trait object, because the object that needs to be coerced is behind
667/// a pointer.
668///
669/// If lowering already produced an error in the receiver type, we conservatively treat it as
670/// undispatchable instead of asking the solver.
671///
672/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result in
673/// a new check that `Trait` is dyn-compatible, creating a cycle.
674/// Instead, we emulate a placeholder by introducing a new type parameter `U` such that
675/// `Self: Unsize<U>` and `U: Trait + MetaSized`, and use `U` in place of `dyn Trait`.
676///
677/// Written as a chalk-style query:
678/// ```ignore (not-rust)
679/// forall (U: Trait + MetaSized) {
680///     if (Self: Unsize<U>) {
681///         Receiver: DispatchFromDyn<Receiver[Self => U]>
682///     }
683/// }
684/// ```
685/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
686/// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
687/// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
688//
689// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
690// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
691// `self: Wrapper<Self>`.
692fn receiver_is_dispatchable<'tcx>(
693    tcx: TyCtxt<'tcx>,
694    method: ty::AssocItem,
695    receiver_ty: Ty<'tcx>,
696) -> bool {
697    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:697",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(697u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("receiver_is_dispatchable: method = {0:?}, receiver_ty = {1:?}",
                                                    method, receiver_ty) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
698
699    if receiver_ty.references_error() {
700        return false;
701    }
702
703    let (Some(unsize_did), Some(dispatch_from_dyn_did)) =
704        (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait())
705    else {
706        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs:706",
                        "rustc_trait_selection::traits::dyn_compatibility",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5f4effd579500175af844241eb179e756190f1e7/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs"),
                        ::tracing_core::__macro_support::Option::Some(706u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("receiver_is_dispatchable: Missing `Unsize` or `DispatchFromDyn` traits")
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("receiver_is_dispatchable: Missing `Unsize` or `DispatchFromDyn` traits");
707        return false;
708    };
709
710    // the type `U` in the query
711    // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now.
712    let unsized_self_ty: Ty<'tcx> =
713        Ty::new_param(tcx, u32::MAX, rustc_span::sym::RustaceansAreAwesome);
714
715    // `Receiver[Self => U]`
716    let unsized_receiver_ty =
717        receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
718
719    // create a modified param env, with `Self: Unsize<U>` and `U: Trait` (and all of
720    // its supertraits) added to caller bounds. `U: MetaSized` is already implied here.
721    let param_env = {
722        // N.B. We generally want to emulate the construction of the `unnormalized_param_env`
723        // in the param-env query here. The fact that we don't just start with the clauses
724        // in the param-env of the method is because those are already normalized, and mixing
725        // normalized and unnormalized copies of predicates in `normalize_param_env_or_error`
726        // will cause ambiguity that the user can't really avoid.
727        //
728        // We leave out certain complexities of the param-env query here. Specifically, we:
729        // 1. Do not add `[const]` bounds since there are no `dyn const Trait`s.
730        // 2. Do not add RPITIT self projection bounds for defaulted methods, since we
731        //    are not constructing a param-env for "inside" of the body of the defaulted
732        //    method, so we don't really care about projecting to a specific RPIT type,
733        //    and because RPITITs are not dyn compatible (yet).
734        let mut clauses: Vec<_> = tcx
735            .clauses_of(method.def_id)
736            .instantiate_identity(tcx)
737            .clauses
738            .into_iter()
739            .map(Unnormalized::skip_norm_wip)
740            .collect();
741
742        // Self: Unsize<U>
743        let unsize_predicate =
744            ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]);
745        clauses.push(unsize_predicate.upcast(tcx));
746
747        // U: Trait<Arg1, ..., ArgN>
748        let trait_def_id = method.trait_container(tcx).unwrap();
749        let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| {
750            if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
751        });
752        let trait_predicate = ty::TraitRef::new_from_args(tcx, trait_def_id, args);
753        clauses.push(trait_predicate.upcast(tcx));
754
755        // U satisfies Trait's trait bounds. Supertrait bounds are already included by the expansion
756        // of `U: Trait<...>` done by param-env normalization. However, normalizing aliases in the
757        // arguments of those supertrait bounds can generate trait obligations which may only be
758        // provable using other where-clauses from Trait (#161621).
759        clauses.extend(
760            tcx.clauses_of(trait_def_id)
761                .instantiate(tcx, args)
762                .clauses
763                .into_iter()
764                .map(Unnormalized::skip_norm_wip)
765                // For simplicity, add all trait clauses, though strictly this should only need to
766                // add non-supertrait clauses involving Self.
767                .filter(|clause| #[allow(non_exhaustive_omitted_patterns)] match clause.kind().skip_binder() {
    ty::ClauseKind::Trait(_) => true,
    _ => false,
}matches!(clause.kind().skip_binder(), ty::ClauseKind::Trait(_))),
768        );
769
770        // When Self appears in the arguments of a projection clause, we also need a corresponding
771        // projection for U. We don't want U in the targets of projections that doesn't also have
772        // U in the alias, since that can lead to ambiguity (#163550). For example, if we have
773        // `(): HasAssoc<Assoc = Self>` in Trait's clauses, `<() as HasAssoc>::Assoc` normalizes to
774        // Self during dispatchability checking, since we assume `method`'s clauses. This should be
775        // fine: if `dyn Trait<...>: Trait<...>` isn't satisfied, you can't call methods on such a
776        // trait object anyway.
777        //
778        // HACK: This relies on param-env normalization jank. We don't normalize the left-hand side
779        // of bounds like `<Self as HasAssoc1>::Assoc: HasAssoc2<Assoc = Self>` in the param-env we
780        // use to normalize our param-env. If it's someday possible for `<Self as HasAssoc1>::Assoc`
781        // to normalize there, we won't know whether Self is in the arguments of
782        // `<<Self as HasAssoc1>::Assoc as HasAssoc2>::Assoc == Self` or not. In that case, this may
783        // need first to normalize Trait's projection clauses or do additional hacks to avoid adding
784        // ambiguity.
785        clauses.extend(
786            tcx.clauses_of(trait_def_id)
787                .instantiate_identity(tcx)
788                .clauses
789                .into_iter()
790                .map(Unnormalized::skip_norm_wip)
791                .filter_map(|clause| -> Option<ty::Clause<'tcx>> {
792                    clause
793                        .as_projection_clause()
794                        // For each clause `Alias == ProjectionTarget` with Self in Alias, make a
795                        // copy of the clause with U in place of Self. Strictly, this should only
796                        // need to add clauses that didn't come from supertrait bounds.
797                        .filter(|proj| {
798                            proj.skip_binder().projection_term.args.iter().any(|arg| {
799                                arg.as_type().is_some_and(|arg| arg.contains(tcx.types.self_param))
800                            })
801                        })
802                        .map(|proj| {
803                            proj.map_bound(|proj| {
804                                EarlyBinder::bind(tcx, proj).instantiate(tcx, args).skip_norm_wip()
805                            })
806                            .upcast(tcx)
807                        })
808                }),
809        );
810
811        let meta_sized_predicate = {
812            let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, DUMMY_SP);
813            ty::TraitRef::new(tcx, meta_sized_did, [unsized_self_ty])
814        };
815        clauses.push(meta_sized_predicate.upcast(tcx));
816
817        normalize_param_env_or_error(
818            tcx,
819            ty::ParamEnv::new(tcx, clauses),
820            ObligationCause::dummy_with_span(tcx.def_span(method.def_id)),
821        )
822    };
823
824    // Receiver: DispatchFromDyn<Receiver[Self => U]>
825    let obligation = {
826        let predicate =
827            ty::TraitRef::new(tcx, dispatch_from_dyn_did, [receiver_ty, unsized_receiver_ty]);
828
829        Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
830    };
831
832    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
833    // the receiver is dispatchable iff the obligation holds
834    infcx.predicate_must_hold_modulo_regions(&obligation)
835}
836
837#[derive(#[automatically_derived]impl ::core::marker::Copy for AllowSelfProjections { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for AllowSelfProjections {
}
#[automatically_derived]impl ::core::clone::Clone for AllowSelfProjections {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self { *self }
}Clone)]
838enum AllowSelfProjections {
839    Yes,
840    No,
841}
842
843/// Check if the given value contains illegal `Self` references.
844///
845/// This is somewhat subtle. In general, we want to forbid references to `Self` in the
846/// argument and return types, since the value of `Self` is erased.
847///
848/// However, there is one exception: It is ok to reference `Self` in order to access an
849/// associated type of the current trait, since we retain the value of those associated
850/// types in the trait object type itself.
851///
852/// The same thing holds for associated consts under feature `gca_min_const_items`.
853///
854/// ```rust,ignore (example)
855/// trait SuperTrait {
856///     type X;
857/// }
858///
859/// trait Trait : SuperTrait {
860///     type Y;
861///     fn foo(&self, x: Self) // bad
862///     fn foo(&self) -> Self // bad
863///     fn foo(&self) -> Option<Self> // bad
864///     fn foo(&self) -> Self::Y // OK, desugars to next example
865///     fn foo(&self) -> <Self as Trait>::Y // OK
866///     fn foo(&self) -> Self::X // OK, desugars to next example
867///     fn foo(&self) -> <Self as SuperTrait>::X // OK
868/// }
869/// ```
870///
871/// However, it is not as simple as allowing `Self` in a projected
872/// type, because there are illegal ways to use `Self` as well:
873///
874/// ```rust,ignore (example)
875/// trait Trait : SuperTrait {
876///     ...
877///     fn foo(&self) -> <Self as SomeOtherTrait>::X;
878/// }
879/// ```
880///
881/// Here we will not have the type of `X` recorded in the
882/// object type, and we cannot resolve `Self as SomeOtherTrait`
883/// without knowing what `Self` is.
884fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
885    tcx: TyCtxt<'tcx>,
886    trait_def_id: DefId,
887    value: T,
888    allow_self_projections: AllowSelfProjections,
889) -> bool {
890    value
891        .visit_with(&mut IllegalSelfTypeVisitor {
892            tcx,
893            trait_def_id,
894            supertraits: None,
895            allow_self_projections,
896        })
897        .is_break()
898}
899
900struct IllegalSelfTypeVisitor<'tcx> {
901    tcx: TyCtxt<'tcx>,
902    trait_def_id: DefId,
903    supertraits: Option<Vec<ty::TraitRef<'tcx>>>,
904    allow_self_projections: AllowSelfProjections,
905}
906
907impl<'tcx> IllegalSelfTypeVisitor<'tcx> {
908    fn is_supertrait_of_current_trait(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
909        // Compute supertraits of current trait lazily.
910        let supertraits = self.supertraits.get_or_insert_with(|| {
911            util::supertraits(
912                self.tcx,
913                ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id)),
914            )
915            .map(|trait_ref| {
916                self.tcx.erase_and_anonymize_regions(
917                    self.tcx.instantiate_bound_regions_with_erased(trait_ref),
918                )
919            })
920            .collect()
921        });
922
923        // Determine whether the given trait ref is in fact a supertrait of the current trait.
924        // In that case, any derived projections are legal, because the term will be specified
925        // in the trait object type.
926        // Note that we can just use direct equality here because all of these types are part of
927        // the formal parameter listing, and hence there should be no inference variables.
928        let trait_ref = trait_ref
929            .fold_with(&mut EraseEscapingBoundRegions { tcx: self.tcx, binder: ty::INNERMOST });
930        supertraits.contains(&trait_ref)
931    }
932}
933
934impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
935    type Result = ControlFlow<()>;
936
937    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
938        match ty.kind() {
939            ty::Param(_) => {
940                if ty == self.tcx.types.self_param {
941                    ControlFlow::Break(())
942                } else {
943                    ControlFlow::Continue(())
944                }
945            }
946            ty::Alias(_, ty::AliasTy { kind: ty::Projection { def_id }, .. })
947                if self.tcx.is_impl_trait_in_trait(*def_id) =>
948            {
949                // We'll deny these later in their own pass
950                ControlFlow::Continue(())
951            }
952            ty::Alias(_, proj @ ty::AliasTy { kind: ty::Projection { .. }, .. }) => {
953                match self.allow_self_projections {
954                    AllowSelfProjections::Yes => {
955                        // Only walk contained types if the parent trait is not a supertrait.
956                        if self.is_supertrait_of_current_trait(proj.trait_ref(self.tcx)) {
957                            ControlFlow::Continue(())
958                        } else {
959                            ty.super_visit_with(self)
960                        }
961                    }
962                    AllowSelfProjections::No => ty.super_visit_with(self),
963                }
964            }
965            _ => ty.super_visit_with(self),
966        }
967    }
968
969    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
970        let ct = self.tcx.expand_abstract_consts(ct);
971
972        match ct.kind() {
973            ty::ConstKind::Alias(
974                _,
975                ty::AliasConst { kind: ty::AliasConstKind::Projection { def_id }, args, .. },
976            ) if self.tcx.features().gca_min_const_items() => {
977                match self.allow_self_projections {
978                    AllowSelfProjections::Yes => {
979                        let trait_def_id = self.tcx.parent(def_id);
980                        let trait_ref = ty::TraitRef::from_assoc(self.tcx, trait_def_id, args);
981
982                        // Only walk contained consts if the parent trait is not a supertrait.
983                        if self.is_supertrait_of_current_trait(trait_ref) {
984                            ControlFlow::Continue(())
985                        } else {
986                            ct.super_visit_with(self)
987                        }
988                    }
989                    AllowSelfProjections::No => ct.super_visit_with(self),
990                }
991            }
992            _ => ct.super_visit_with(self),
993        }
994    }
995}
996
997struct EraseEscapingBoundRegions<'tcx> {
998    tcx: TyCtxt<'tcx>,
999    binder: ty::DebruijnIndex,
1000}
1001
1002impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEscapingBoundRegions<'tcx> {
1003    fn cx(&self) -> TyCtxt<'tcx> {
1004        self.tcx
1005    }
1006
1007    fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
1008    where
1009        T: TypeFoldable<TyCtxt<'tcx>>,
1010    {
1011        self.binder.shift_in(1);
1012        let result = t.super_fold_with(self);
1013        self.binder.shift_out(1);
1014        result
1015    }
1016
1017    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
1018        if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind()
1019            && debruijn < self.binder
1020        {
1021            r
1022        } else {
1023            self.tcx.lifetimes.re_erased
1024        }
1025    }
1026}
1027
1028fn contains_illegal_impl_trait_in_trait<'tcx>(
1029    tcx: TyCtxt<'tcx>,
1030    fn_def_id: DefId,
1031    ty: ty::Binder<'tcx, Ty<'tcx>>,
1032) -> Option<MethodViolation> {
1033    let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
1034
1035    if tcx.asyncness(fn_def_id).is_async() {
1036        // Rendering the error as a separate `async-specific` message is better.
1037        Some(MethodViolation::AsyncFn)
1038    } else {
1039        ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
1040    }
1041}
1042
1043struct IllegalRpititVisitor<'tcx> {
1044    tcx: TyCtxt<'tcx>,
1045    allowed: Option<ty::AliasTy<'tcx>>,
1046}
1047
1048impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
1049    type Result = ControlFlow<MethodViolation>;
1050
1051    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
1052        if let ty::Alias(_, proj @ ty::AliasTy { kind: ty::Projection { def_id }, .. }) = *ty.kind()
1053            && Some(proj) != self.allowed
1054            && self.tcx.is_impl_trait_in_trait(def_id)
1055        {
1056            ControlFlow::Break(MethodViolation::ReferencesImplTraitInTrait(
1057                self.tcx.def_span(def_id),
1058            ))
1059        } else {
1060            ty.super_visit_with(self)
1061        }
1062    }
1063}
1064
1065pub(crate) fn provide(providers: &mut Providers) {
1066    *providers = Providers {
1067        dyn_compatibility_violations,
1068        is_dyn_compatible,
1069        generics_require_sized_self,
1070        ..*providers
1071    };
1072}