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