rustc_trait_selection/traits/
dyn_compatibility.rs

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