Skip to main content

rustc_next_trait_solver/solve/assembly/
structural_traits.rs

1//! Code which is used by built-in goals that match "structurally", such a auto
2//! traits, `Copy`/`Clone`.
3
4use derive_where::derive_where;
5use rustc_type_ir::data_structures::HashMap;
6use rustc_type_ir::inherent::*;
7use rustc_type_ir::lang_items::{SolverProjectionLangItem, SolverTraitLangItem};
8use rustc_type_ir::solve::SizedTraitKind;
9use rustc_type_ir::solve::inspect::ProbeKind;
10use rustc_type_ir::{
11    self as ty, Binder, FallibleTypeFolder, Interner, Movability, Mutability, Region, TypeFoldable,
12    TypeSuperFoldable, Unnormalized, Upcast as _, elaborate,
13};
14use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
15use tracing::instrument;
16
17use crate::delegate::SolverDelegate;
18use crate::solve::{
19    AdtDestructorKind, EvalCtxt, Goal, NoSolution, NoSolutionOrRerunNonErased, RerunNonErased,
20};
21
22// Calculates the constituent types of a type for `auto trait` purposes.
23x;#[instrument(level = "trace", skip(ecx), ret)]
24pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<D, I>(
25    ecx: &EvalCtxt<'_, D>,
26    ty: I::Ty,
27) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>
28where
29    D: SolverDelegate<Interner = I>,
30    I: Interner,
31{
32    let cx = ecx.cx();
33    match ty.kind() {
34        ty::Uint(_)
35        | ty::Int(_)
36        | ty::Bool
37        | ty::Float(_)
38        | ty::FnDef(..)
39        | ty::FnPtr(..)
40        | ty::Error(_)
41        | ty::Never
42        | ty::Char => Ok(ty::Binder::dummy(vec![])),
43
44        // This branch is only for `experimental_default_bounds`.
45        // Other foreign types were rejected earlier in
46        // `disqualify_auto_trait_candidate_due_to_possible_impl`.
47        ty::Foreign(..) => Ok(ty::Binder::dummy(vec![])),
48
49        // Treat `str` like it's defined as `struct str([u8]);`
50        ty::Str => Ok(ty::Binder::dummy(vec![Ty::new_slice(cx, Ty::new_u8(cx))])),
51
52        ty::Dynamic(..)
53        | ty::Param(..)
54        | ty::Alias(
55            ty::IsRigid::Yes,
56            ty::AliasTy {
57                kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. }, ..
58            },
59        )
60        | ty::Placeholder(..)
61        | ty::Alias(ty::IsRigid::No, _)
62        | ty::Bound(..)
63        | ty::Infer(_) => {
64            panic!("unexpected type `{ty:?}`")
65        }
66
67        ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => {
68            Ok(ty::Binder::dummy(vec![element_ty]))
69        }
70
71        ty::Pat(element_ty, _) | ty::Array(element_ty, _) | ty::Slice(element_ty) => {
72            Ok(ty::Binder::dummy(vec![element_ty]))
73        }
74
75        ty::Tuple(tys) => {
76            // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
77            Ok(ty::Binder::dummy(tys.to_vec()))
78        }
79
80        ty::Closure(_, args) => Ok(ty::Binder::dummy(vec![args.as_closure().tupled_upvars_ty()])),
81
82        ty::CoroutineClosure(_, args) => {
83            Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()]))
84        }
85
86        ty::Coroutine(def_id, args) => Ok(ty::Binder::dummy(vec![
87            args.as_coroutine().tupled_upvars_ty(),
88            Ty::new_coroutine_witness_for_coroutine(ecx.cx(), def_id, args),
89        ])),
90
91        ty::CoroutineWitness(def_id, args) => Ok(ecx
92            .cx()
93            .coroutine_hidden_types(def_id)
94            .instantiate(cx, args)
95            .skip_norm_wip()
96            .map_bound(|bound| bound.types.to_vec())),
97
98        ty::UnsafeBinder(bound_ty) => Ok(bound_ty.map_bound(|ty| vec![ty])),
99
100        // For `PhantomData<T>`, we pass `T`.
101        ty::Adt(def, args) if def.is_phantom_data() => Ok(ty::Binder::dummy(vec![args.type_at(0)])),
102
103        ty::Adt(def, args) => Ok(ty::Binder::dummy(
104            def.all_field_tys(cx)
105                .iter_instantiated(cx, args)
106                .map(Unnormalized::skip_norm_wip)
107                .collect(),
108        )),
109
110        ty::Alias(ty::IsRigid::Yes, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
111            // We can resolve the `impl Trait` to its concrete type,
112            // which enforces a DAG between the functions requiring
113            // the auto trait bounds in question.
114            Ok(ty::Binder::dummy(vec![
115                cx.type_of(def_id.into()).instantiate(cx, args).skip_norm_wip(),
116            ]))
117        }
118    }
119}
120
121x;#[instrument(level = "trace", skip(ecx), ret)]
122pub(in crate::solve) fn instantiate_constituent_tys_for_sizedness_trait<D, I>(
123    ecx: &EvalCtxt<'_, D>,
124    sizedness: SizedTraitKind,
125    ty: I::Ty,
126) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>
127where
128    D: SolverDelegate<Interner = I>,
129    I: Interner,
130{
131    match ty.kind() {
132        // impl {Meta,}Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char
133        // impl {Meta,}Sized for &mut? T, [T; N], dyn* Trait, !, Coroutine, CoroutineWitness
134        // impl {Meta,}Sized for Closure, CoroutineClosure
135        ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
136        | ty::Uint(_)
137        | ty::Int(_)
138        | ty::Bool
139        | ty::Float(_)
140        | ty::FnDef(..)
141        | ty::FnPtr(..)
142        | ty::RawPtr(..)
143        | ty::Char
144        | ty::Ref(..)
145        | ty::Coroutine(..)
146        | ty::CoroutineWitness(..)
147        | ty::Array(..)
148        | ty::Pat(..)
149        | ty::Closure(..)
150        | ty::CoroutineClosure(..)
151        | ty::Never
152        | ty::Error(_) => Ok(ty::Binder::dummy(vec![])),
153
154        // impl {Meta,}Sized for str, [T], dyn Trait
155        ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness {
156            SizedTraitKind::Sized => Err(NoSolution),
157            SizedTraitKind::MetaSized => Ok(ty::Binder::dummy(vec![])),
158        },
159
160        // impl {} for extern type
161        ty::Foreign(..) => Err(NoSolution),
162
163        ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => Err(NoSolution),
164
165        ty::Bound(..)
166        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
167            panic!("unexpected type `{ty:?}`")
168        }
169
170        ty::UnsafeBinder(bound_ty) => Ok(bound_ty.map_bound(|ty| vec![ty])),
171
172        // impl {Meta,}Sized for ()
173        // impl {Meta,}Sized for (T1, T2, .., Tn) where Tn: {Meta,}Sized if n >= 1
174        ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.last().map_or_else(Vec::new, |ty| vec![ty]))),
175
176        // impl {Meta,}Sized for Adt<Args...>
177        //   where {meta,pointee,}sized_constraint(Adt)<Args...>: {Meta,}Sized
178        //
179        //   `{meta,pointee,}sized_constraint(Adt)` is the deepest struct trail that can be
180        //   determined by the definition of `Adt`, independent of the generic args.
181        //
182        // impl {Meta,}Sized for Adt<Args...>
183        //   if {meta,pointee,}sized_constraint(Adt) == None
184        //
185        //   As a performance optimization, `{meta,pointee,}sized_constraint(Adt)` can return `None`
186        //   if the ADTs definition implies that it is {meta,}sized by for all possible args.
187        //   In this case, the builtin impl will have no nested subgoals. This is a
188        //   "best effort" optimization and `{meta,pointee,}sized_constraint` may return `Some`,
189        //   even if the ADT is {meta,pointee,}sized for all possible args.
190        ty::Adt(def, args) => {
191            if let Some(crit) = def.sizedness_constraint(ecx.cx(), sizedness) {
192                Ok(ty::Binder::dummy(vec![crit.instantiate(ecx.cx(), args).skip_norm_wip()]))
193            } else {
194                Ok(ty::Binder::dummy(vec![]))
195            }
196        }
197    }
198}
199
200x;#[instrument(level = "trace", skip(ecx), ret)]
201pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<D, I>(
202    ecx: &EvalCtxt<'_, D>,
203    ty: I::Ty,
204) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>
205where
206    D: SolverDelegate<Interner = I>,
207    I: Interner,
208{
209    match ty.kind() {
210        // impl Copy/Clone for FnDef, FnPtr
211        ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])),
212
213        // Implementations are provided in core
214        ty::Uint(_)
215        | ty::Int(_)
216        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
217        | ty::Bool
218        | ty::Float(_)
219        | ty::Char
220        | ty::RawPtr(..)
221        | ty::Never
222        | ty::Ref(_, _, Mutability::Not)
223        | ty::Array(..) => Err(NoSolution),
224
225        // Cannot implement in core, as we can't be generic over patterns yet,
226        // so we'd have to list all patterns and type combinations.
227        ty::Pat(ty, ..) => Ok(ty::Binder::dummy(vec![ty])),
228
229        ty::Dynamic(..)
230        | ty::Str
231        | ty::Slice(_)
232        | ty::Foreign(..)
233        | ty::Ref(_, _, Mutability::Mut)
234        | ty::Adt(_, _)
235        | ty::Alias(ty::IsRigid::Yes, _)
236        | ty::Param(_)
237        | ty::Placeholder(..) => Err(NoSolution),
238
239        // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone
240        ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.to_vec())),
241
242        // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone
243        ty::Closure(_, args) => Ok(ty::Binder::dummy(vec![args.as_closure().tupled_upvars_ty()])),
244
245        // impl Copy/Clone for CoroutineClosure where Self::TupledUpvars: Copy/Clone
246        ty::CoroutineClosure(_, args) => {
247            Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()]))
248        }
249
250        // only when `coroutine_clone` is enabled and the coroutine is movable
251        // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses)
252        ty::Coroutine(def_id, args) => match ecx.cx().coroutine_movability(def_id) {
253            Movability::Static => Err(NoSolution),
254            Movability::Movable => {
255                if ecx.cx().features().coroutine_clone() {
256                    Ok(ty::Binder::dummy(vec![
257                        args.as_coroutine().tupled_upvars_ty(),
258                        Ty::new_coroutine_witness_for_coroutine(ecx.cx(), def_id, args),
259                    ]))
260                } else {
261                    Err(NoSolution)
262                }
263            }
264        },
265
266        ty::UnsafeBinder(_) => Err(NoSolution),
267
268        // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
269        ty::CoroutineWitness(def_id, args) => Ok(ecx
270            .cx()
271            .coroutine_hidden_types(def_id)
272            .instantiate(ecx.cx(), args)
273            .skip_norm_wip()
274            .map_bound(|bound| bound.types.to_vec())),
275
276        ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
277        | ty::Alias(ty::IsRigid::No, _)
278        | ty::Bound(..) => {
279            panic!("unexpected type `{ty:?}`")
280        }
281    }
282}
283
284// Returns a binder of the tupled inputs types and output type from a builtin callable type.
285pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Interner>(
286    cx: I,
287    self_ty: I::Ty,
288    goal_kind: ty::ClosureKind,
289) -> Result<Option<ty::Binder<I, (I::Ty, I::Ty)>>, NoSolution> {
290    match self_ty.kind() {
291        // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
292        ty::FnDef(def_id, args) => {
293            let sig = cx.fn_sig(def_id);
294            if sig.skip_binder().is_fn_trait_compatible() && !cx.has_target_features(def_id) {
295                Ok(Some(
296                    sig.instantiate(cx, args.no_bound_vars().unwrap())
297                        .skip_norm_wip()
298                        .map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())),
299                ))
300            } else {
301                Err(NoSolution)
302            }
303        }
304        // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
305        ty::FnPtr(sig_tys, hdr) => {
306            let sig = sig_tys.with(hdr);
307            if sig.is_fn_trait_compatible() {
308                Ok(Some(
309                    sig.map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())),
310                ))
311            } else {
312                Err(NoSolution)
313            }
314        }
315        ty::Closure(_, args) => {
316            let closure_args = args.as_closure();
317            match closure_args.kind_ty().to_opt_closure_kind() {
318                // If the closure's kind doesn't extend the goal kind,
319                // then the closure doesn't implement the trait.
320                Some(closure_kind) => {
321                    if !closure_kind.extends(goal_kind) {
322                        return Err(NoSolution);
323                    }
324                }
325                // Closure kind is not yet determined, so we return ambiguity unless
326                // the expected kind is `FnOnce` as that is always implemented.
327                None => {
328                    if goal_kind != ty::ClosureKind::FnOnce {
329                        return Ok(None);
330                    }
331                }
332            }
333            Ok(Some(
334                closure_args.sig().map_bound(|sig| (sig.inputs().get(0).unwrap(), sig.output())),
335            ))
336        }
337
338        // Coroutine-closures don't implement `Fn` traits the normal way.
339        // Instead, they always implement `FnOnce`, but only implement
340        // `FnMut`/`Fn` if they capture no upvars, since those may borrow
341        // from the closure.
342        ty::CoroutineClosure(def_id, args) => {
343            let args = args.as_coroutine_closure();
344            let kind_ty = args.kind_ty();
345            let sig = args.coroutine_closure_sig().skip_binder();
346
347            let coroutine_ty = if let Some(kind) = kind_ty.to_opt_closure_kind()
348                && !args.tupled_upvars_ty().is_ty_var()
349            {
350                if !kind.extends(goal_kind) {
351                    return Err(NoSolution);
352                }
353
354                // A coroutine-closure implements `FnOnce` *always*, since it may
355                // always be called once. It additionally implements `Fn`/`FnMut`
356                // only if it has no upvars referencing the closure-env lifetime,
357                // and if the closure kind permits it.
358                if goal_kind != ty::ClosureKind::FnOnce && args.has_self_borrows() {
359                    return Err(NoSolution);
360                }
361
362                coroutine_closure_to_certain_coroutine(
363                    cx,
364                    goal_kind,
365                    // No captures by ref, so this doesn't matter.
366                    Region::new_static(cx),
367                    def_id,
368                    args,
369                    sig,
370                )
371            } else {
372                // Closure kind is not yet determined, so we return ambiguity unless
373                // the expected kind is `FnOnce` as that is always implemented.
374                if goal_kind != ty::ClosureKind::FnOnce {
375                    return Ok(None);
376                }
377
378                coroutine_closure_to_ambiguous_coroutine(
379                    cx,
380                    goal_kind, // No captures by ref, so this doesn't matter.
381                    Region::new_static(cx),
382                    def_id,
383                    args,
384                    sig,
385                )
386            };
387
388            Ok(Some(args.coroutine_closure_sig().rebind((sig.tupled_inputs_ty, coroutine_ty))))
389        }
390
391        ty::Bool
392        | ty::Char
393        | ty::Int(_)
394        | ty::Uint(_)
395        | ty::Float(_)
396        | ty::Adt(_, _)
397        | ty::Foreign(_)
398        | ty::Str
399        | ty::Array(_, _)
400        | ty::Slice(_)
401        | ty::RawPtr(_, _)
402        | ty::Ref(_, _, _)
403        | ty::Dynamic(_, _)
404        | ty::Coroutine(_, _)
405        | ty::CoroutineWitness(..)
406        | ty::Never
407        | ty::Tuple(_)
408        | ty::Pat(_, _)
409        | ty::UnsafeBinder(_)
410        | ty::Alias(ty::IsRigid::Yes, _)
411        | ty::Param(_)
412        | ty::Placeholder(..)
413        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
414        | ty::Error(_) => Err(NoSolution),
415
416        ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
417        | ty::Alias(ty::IsRigid::No, _)
418        | ty::Bound(..) => {
419            {
    ::core::panicking::panic_fmt(format_args!("unexpected type `{0:?}`",
            self_ty));
}panic!("unexpected type `{self_ty:?}`")
420        }
421    }
422}
423
424/// Relevant types for an async callable, including its inputs, output,
425/// and the return type you get from awaiting the output.
426#[automatically_derived]
impl<I: Interner> ::core::fmt::Debug for AsyncCallableRelevantTypes<I> where
    I: Interner {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            AsyncCallableRelevantTypes {
                tupled_inputs_ty: ref __field_tupled_inputs_ty,
                output_coroutine_ty: ref __field_output_coroutine_ty,
                coroutine_return_ty: ref __field_coroutine_return_ty } => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f,
                        "AsyncCallableRelevantTypes");
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "tupled_inputs_ty", __field_tupled_inputs_ty);
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "output_coroutine_ty", __field_output_coroutine_ty);
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "coroutine_return_ty", __field_coroutine_return_ty);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
        }
    }
}#[derive_where(Clone, Copy, Debug; I: Interner)]
427#[derive(const _: () =
    {
        impl<I: Interner> ::rustc_type_ir::TypeVisitable<I> for
            AsyncCallableRelevantTypes<I> where I: Interner,
            I::Ty: ::rustc_type_ir::TypeVisitable<I> {
            fn visit_with<__V: ::rustc_type_ir::TypeVisitor<I>>(&self,
                __visitor: &mut __V) -> __V::Result {
                match *self {
                    AsyncCallableRelevantTypes {
                        tupled_inputs_ty: ref __binding_0,
                        output_coroutine_ty: ref __binding_1,
                        coroutine_return_ty: ref __binding_2 } => {
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_1,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_2,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                }
                <__V::Result as ::rustc_type_ir::VisitorResult>::output()
            }
        }
    };TypeVisitable_Generic, const _: () =
    {
        impl<I: Interner> ::rustc_type_ir::TypeFoldable<I> for
            AsyncCallableRelevantTypes<I> where I: Interner,
            I::Ty: ::rustc_type_ir::TypeFoldable<I> {
            fn try_fold_with<__F: ::rustc_type_ir::FallibleTypeFolder<I>>(self,
                __folder: &mut __F) -> Result<Self, __F::Error> {
                Ok(match self {
                        AsyncCallableRelevantTypes {
                            tupled_inputs_ty: __binding_0,
                            output_coroutine_ty: __binding_1,
                            coroutine_return_ty: __binding_2 } => {
                            AsyncCallableRelevantTypes {
                                tupled_inputs_ty: ::rustc_type_ir::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                                output_coroutine_ty: ::rustc_type_ir::TypeFoldable::try_fold_with(__binding_1,
                                        __folder)?,
                                coroutine_return_ty: ::rustc_type_ir::TypeFoldable::try_fold_with(__binding_2,
                                        __folder)?,
                            }
                        }
                    })
            }
            fn fold_with<__F: ::rustc_type_ir::TypeFolder<I>>(self,
                __folder: &mut __F) -> Self {
                match self {
                    AsyncCallableRelevantTypes {
                        tupled_inputs_ty: __binding_0,
                        output_coroutine_ty: __binding_1,
                        coroutine_return_ty: __binding_2 } => {
                        AsyncCallableRelevantTypes {
                            tupled_inputs_ty: ::rustc_type_ir::TypeFoldable::fold_with(__binding_0,
                                __folder),
                            output_coroutine_ty: ::rustc_type_ir::TypeFoldable::fold_with(__binding_1,
                                __folder),
                            coroutine_return_ty: ::rustc_type_ir::TypeFoldable::fold_with(__binding_2,
                                __folder),
                        }
                    }
                }
            }
        }
    };TypeFoldable_Generic)]
428pub(in crate::solve) struct AsyncCallableRelevantTypes<I: Interner> {
429    pub tupled_inputs_ty: I::Ty,
430    /// Type returned by calling the closure
431    /// i.e. `f()`.
432    pub output_coroutine_ty: I::Ty,
433    /// Type returned by `await`ing the output
434    /// i.e. `f().await`.
435    pub coroutine_return_ty: I::Ty,
436}
437
438// Returns a binder of the tupled inputs types, output type, and coroutine type
439// from a builtin coroutine-closure type. If we don't yet know the closure kind of
440// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
441// which enforces the closure is actually callable with the given trait. When we
442// know the kind already, we can short-circuit this check.
443pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I: Interner>(
444    cx: I,
445    self_ty: I::Ty,
446    goal_kind: ty::ClosureKind,
447    env_region: Region<I>,
448) -> Result<(ty::Binder<I, AsyncCallableRelevantTypes<I>>, Vec<I::Predicate>), NoSolution> {
449    match self_ty.kind() {
450        ty::CoroutineClosure(def_id, args) => {
451            let args = args.as_coroutine_closure();
452            let kind_ty = args.kind_ty();
453            let sig = args.coroutine_closure_sig().skip_binder();
454            let mut nested = ::alloc::vec::Vec::new()vec![];
455
456            let coroutine_ty = if let Some(kind) = kind_ty.to_opt_closure_kind()
457                && !args.tupled_upvars_ty().is_ty_var()
458            {
459                if !kind.extends(goal_kind) {
460                    return Err(NoSolution);
461                }
462
463                coroutine_closure_to_certain_coroutine(cx, goal_kind, env_region, def_id, args, sig)
464            } else {
465                // When we don't know the closure kind (and therefore also the closure's upvars,
466                // which are computed at the same time), we must delay the computation of the
467                // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
468                // goal functions similarly to the old `ClosureKind` predicate, and ensures that
469                // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
470                // will project to the right upvars for the generator, appending the inputs and
471                // coroutine upvars respecting the closure kind.
472                nested.push(
473                    ty::TraitRef::new(
474                        cx,
475                        cx.require_trait_lang_item(SolverTraitLangItem::AsyncFnKindHelper),
476                        [kind_ty, Ty::from_closure_kind(cx, goal_kind)],
477                    )
478                    .upcast(cx),
479                );
480
481                coroutine_closure_to_ambiguous_coroutine(
482                    cx, goal_kind, env_region, def_id, args, sig,
483                )
484            };
485
486            Ok((
487                args.coroutine_closure_sig().rebind(AsyncCallableRelevantTypes {
488                    tupled_inputs_ty: sig.tupled_inputs_ty,
489                    output_coroutine_ty: coroutine_ty,
490                    coroutine_return_ty: sig.return_ty,
491                }),
492                nested,
493            ))
494        }
495
496        ty::FnDef(def_id, _) => {
497            let sig = self_ty.fn_sig(cx);
498            if sig.is_fn_trait_compatible() && !cx.has_target_features(def_id) {
499                fn_item_to_async_callable(cx, sig)
500            } else {
501                Err(NoSolution)
502            }
503        }
504        ty::FnPtr(..) => {
505            let sig = self_ty.fn_sig(cx);
506            if sig.is_fn_trait_compatible() {
507                fn_item_to_async_callable(cx, sig)
508            } else {
509                Err(NoSolution)
510            }
511        }
512
513        ty::Closure(_, args) => {
514            let args = args.as_closure();
515            let bound_sig = args.sig();
516            let sig = bound_sig.skip_binder();
517            let future_trait_def_id = cx.require_trait_lang_item(SolverTraitLangItem::Future);
518            // `Closure`s only implement `AsyncFn*` when their return type
519            // implements `Future`.
520            let mut nested = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [bound_sig.rebind(ty::TraitRef::new(cx, future_trait_def_id,
                            [sig.output()])).upcast(cx)]))vec![
521                bound_sig
522                    .rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()]))
523                    .upcast(cx),
524            ];
525
526            // Additionally, we need to check that the closure kind
527            // is still compatible.
528            let kind_ty = args.kind_ty();
529            if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
530                if !closure_kind.extends(goal_kind) {
531                    return Err(NoSolution);
532                }
533            } else {
534                let async_fn_kind_trait_def_id =
535                    cx.require_trait_lang_item(SolverTraitLangItem::AsyncFnKindHelper);
536                // When we don't know the closure kind (and therefore also the closure's upvars,
537                // which are computed at the same time), we must delay the computation of the
538                // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
539                // goal functions similarly to the old `ClosureKind` predicate, and ensures that
540                // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
541                // will project to the right upvars for the generator, appending the inputs and
542                // coroutine upvars respecting the closure kind.
543                nested.push(
544                    ty::TraitRef::new(
545                        cx,
546                        async_fn_kind_trait_def_id,
547                        [kind_ty, Ty::from_closure_kind(cx, goal_kind)],
548                    )
549                    .upcast(cx),
550                );
551            }
552
553            let future_output_def_id =
554                cx.require_projection_lang_item(SolverProjectionLangItem::FutureOutput);
555            let future_output_ty =
556                Ty::new_projection(cx, ty::IsRigid::No, future_output_def_id, [sig.output()]);
557            Ok((
558                bound_sig.rebind(AsyncCallableRelevantTypes {
559                    tupled_inputs_ty: sig.inputs().get(0).unwrap(),
560                    output_coroutine_ty: sig.output(),
561                    coroutine_return_ty: future_output_ty,
562                }),
563                nested,
564            ))
565        }
566
567        ty::Bool
568        | ty::Char
569        | ty::Int(_)
570        | ty::Uint(_)
571        | ty::Float(_)
572        | ty::Adt(_, _)
573        | ty::Foreign(_)
574        | ty::Str
575        | ty::Array(_, _)
576        | ty::Pat(_, _)
577        | ty::Slice(_)
578        | ty::RawPtr(_, _)
579        | ty::Ref(_, _, _)
580        | ty::Dynamic(_, _)
581        | ty::Coroutine(_, _)
582        | ty::CoroutineWitness(..)
583        | ty::Never
584        | ty::UnsafeBinder(_)
585        | ty::Tuple(_)
586        | ty::Alias(ty::IsRigid::Yes, _)
587        | ty::Param(_)
588        | ty::Placeholder(..)
589        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
590        | ty::Error(_) => Err(NoSolution),
591
592        ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
593        | ty::Alias(ty::IsRigid::No, _)
594        | ty::Bound(..) => {
595            {
    ::core::panicking::panic_fmt(format_args!("unexpected type `{0:?}`",
            self_ty));
}panic!("unexpected type `{self_ty:?}`")
596        }
597    }
598}
599
600fn fn_item_to_async_callable<I: Interner>(
601    cx: I,
602    bound_sig: ty::Binder<I, ty::FnSig<I>>,
603) -> Result<(ty::Binder<I, AsyncCallableRelevantTypes<I>>, Vec<I::Predicate>), NoSolution> {
604    let sig = bound_sig.skip_binder();
605    let future_trait_def_id = cx.require_trait_lang_item(SolverTraitLangItem::Future);
606    // `FnDef` and `FnPtr` only implement `AsyncFn*` when their
607    // return type implements `Future`.
608    let nested = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [bound_sig.rebind(ty::TraitRef::new(cx, future_trait_def_id,
                            [sig.output()])).upcast(cx)]))vec![
609        bound_sig.rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()])).upcast(cx),
610    ];
611    let future_output_def_id =
612        cx.require_projection_lang_item(SolverProjectionLangItem::FutureOutput);
613    let future_output_ty =
614        Ty::new_projection(cx, ty::IsRigid::No, future_output_def_id, [sig.output()]);
615    Ok((
616        bound_sig.rebind(AsyncCallableRelevantTypes {
617            tupled_inputs_ty: Ty::new_tup(cx, sig.inputs().as_slice()),
618            output_coroutine_ty: sig.output(),
619            coroutine_return_ty: future_output_ty,
620        }),
621        nested,
622    ))
623}
624
625/// Given a coroutine-closure, project to its returned coroutine when we are *certain*
626/// that the closure's kind is compatible with the goal.
627fn coroutine_closure_to_certain_coroutine<I: Interner>(
628    cx: I,
629    goal_kind: ty::ClosureKind,
630    goal_region: Region<I>,
631    def_id: I::CoroutineClosureId,
632    args: ty::CoroutineClosureArgs<I>,
633    sig: ty::CoroutineClosureSignature<I>,
634) -> I::Ty {
635    sig.to_coroutine_given_kind_and_upvars(
636        cx,
637        args.parent_args(),
638        cx.coroutine_for_closure(def_id),
639        goal_kind,
640        goal_region,
641        args.tupled_upvars_ty(),
642        args.coroutine_captures_by_ref_ty(),
643    )
644}
645
646/// Given a coroutine-closure, project to its returned coroutine when we are *not certain*
647/// that the closure's kind is compatible with the goal, and therefore also don't know
648/// yet what the closure's upvars are.
649///
650/// Note that we do not also push a `AsyncFnKindHelper` goal here.
651fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
652    cx: I,
653    goal_kind: ty::ClosureKind,
654    goal_region: Region<I>,
655    def_id: I::CoroutineClosureId,
656    args: ty::CoroutineClosureArgs<I>,
657    sig: ty::CoroutineClosureSignature<I>,
658) -> I::Ty {
659    let upvars_projection_def_id =
660        cx.require_projection_lang_item(SolverProjectionLangItem::AsyncFnKindUpvars);
661    let tupled_upvars_ty = Ty::new_projection(
662        cx,
663        ty::IsRigid::No,
664        upvars_projection_def_id,
665        [
666            I::GenericArg::from(args.kind_ty()),
667            Ty::from_closure_kind(cx, goal_kind).into(),
668            goal_region.into(),
669            sig.tupled_inputs_ty.into(),
670            args.tupled_upvars_ty().into(),
671            args.coroutine_captures_by_ref_ty().into(),
672        ],
673    );
674    sig.to_coroutine(
675        cx,
676        args.parent_args(),
677        Ty::from_closure_kind(cx, goal_kind),
678        cx.coroutine_for_closure(def_id),
679        tupled_upvars_ty,
680    )
681}
682
683/// This duplicates `extract_tupled_inputs_and_output_from_callable` but needs
684/// to return different information (namely, the def id and args) so that we can
685/// create const conditions.
686///
687/// Doing so on all calls to `extract_tupled_inputs_and_output_from_callable`
688/// would be wasteful.
689x;#[instrument(level = "trace", skip(cx), ret)]
690pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
691    cx: I,
692    self_ty: I::Ty,
693) -> Result<(ty::Binder<I, (I::Ty, I::Ty)>, I::DefId, I::GenericArgs), NoSolution> {
694    match self_ty.kind() {
695        ty::FnDef(def_id, args) => {
696            // FIXME
697            let args = args.no_bound_vars().unwrap();
698
699            let sig = cx.fn_sig(def_id);
700            if sig.skip_binder().is_fn_trait_compatible()
701                && !cx.has_target_features(def_id)
702                && cx.fn_is_const(def_id)
703            {
704                Ok((
705                    sig.instantiate(cx, args)
706                        .skip_norm_wip()
707                        .map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())),
708                    def_id.into(),
709                    args,
710                ))
711            } else {
712                return Err(NoSolution);
713            }
714        }
715        // `FnPtr`s are not const for now.
716        ty::FnPtr(..) => {
717            return Err(NoSolution);
718        }
719        ty::Closure(def, args) => {
720            if cx.closure_is_const(def) {
721                let closure_args = args.as_closure();
722                Ok((
723                    closure_args
724                        .sig()
725                        .map_bound(|sig| (sig.inputs().get(0).unwrap(), sig.output())),
726                    def.into(),
727                    args,
728                ))
729            } else {
730                return Err(NoSolution);
731            }
732        }
733        // `CoroutineClosure`s are not const for now.
734        ty::CoroutineClosure(..) => {
735            return Err(NoSolution);
736        }
737
738        ty::Bool
739        | ty::Char
740        | ty::Int(_)
741        | ty::Uint(_)
742        | ty::Float(_)
743        | ty::Adt(_, _)
744        | ty::Foreign(_)
745        | ty::Str
746        | ty::Array(_, _)
747        | ty::Slice(_)
748        | ty::RawPtr(_, _)
749        | ty::Ref(_, _, _)
750        | ty::Dynamic(_, _)
751        | ty::Coroutine(_, _)
752        | ty::CoroutineWitness(..)
753        | ty::Never
754        | ty::Tuple(_)
755        | ty::Pat(_, _)
756        | ty::Alias(ty::IsRigid::Yes, _)
757        | ty::Param(_)
758        | ty::Placeholder(..)
759        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
760        | ty::Error(_)
761        | ty::UnsafeBinder(_) => return Err(NoSolution),
762
763        ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
764        | ty::Alias(ty::IsRigid::No, _)
765        | ty::Bound(..) => {
766            panic!("unexpected type `{self_ty:?}`")
767        }
768    }
769}
770
771// NOTE: Keep this in sync with `evaluate_host_effect_for_destruct_goal` in
772// the old solver, for as long as that exists.
773pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
774    cx: I,
775    self_ty: I::Ty,
776) -> Result<Vec<ty::TraitRef<I>>, NoSolution> {
777    let destruct_def_id = cx.require_trait_lang_item(SolverTraitLangItem::Destruct);
778
779    match self_ty.kind() {
780        // `ManuallyDrop` is trivially `[const] Destruct` as we do not run any drop glue on it.
781        ty::Adt(adt_def, _) if adt_def.is_manually_drop() => Ok(::alloc::vec::Vec::new()vec![]),
782
783        // An ADT is `[const] Destruct` only if all of the fields are,
784        // *and* if there is a `Drop` impl, that `Drop` impl is also `[const]`.
785        ty::Adt(adt_def, args) => {
786            let mut const_conditions: Vec<_> = adt_def
787                .all_field_tys(cx)
788                .iter_instantiated(cx, args)
789                .map(Unnormalized::skip_norm_wip)
790                .map(|field_ty| ty::TraitRef::new(cx, destruct_def_id, [field_ty]))
791                .collect();
792            match adt_def.destructor(cx) {
793                // `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`.
794                Some(AdtDestructorKind::NotConst) => return Err(NoSolution),
795                // `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold.
796                Some(AdtDestructorKind::Const) => {
797                    let drop_def_id = cx.require_trait_lang_item(SolverTraitLangItem::Drop);
798                    let drop_trait_ref = ty::TraitRef::new(cx, drop_def_id, [self_ty]);
799                    const_conditions.push(drop_trait_ref);
800                }
801                // No `Drop` impl, no need to require anything else.
802                None => {}
803            }
804            Ok(const_conditions)
805        }
806
807        ty::Array(ty, _) | ty::Pat(ty, _) | ty::Slice(ty) => {
808            Ok(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [ty::TraitRef::new(cx, destruct_def_id, [ty])]))vec![ty::TraitRef::new(cx, destruct_def_id, [ty])])
809        }
810
811        ty::Tuple(tys) => Ok(tys
812            .iter()
813            .map(|field_ty| ty::TraitRef::new(cx, destruct_def_id, [field_ty]))
814            .collect()),
815
816        // Trivially implement `[const] Destruct`
817        ty::Bool
818        | ty::Char
819        | ty::Int(..)
820        | ty::Uint(..)
821        | ty::Float(..)
822        | ty::Str
823        | ty::RawPtr(..)
824        | ty::Ref(..)
825        | ty::FnDef(..)
826        | ty::FnPtr(..)
827        | ty::Never
828        | ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
829        | ty::Error(_) => Ok(::alloc::vec::Vec::new()vec![]),
830
831        // Closures are [const] Destruct when all of their upvars (captures) are [const] Destruct.
832        ty::Closure(_, args) => {
833            let closure_args = args.as_closure();
834            Ok(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [ty::TraitRef::new(cx, destruct_def_id,
                    [closure_args.tupled_upvars_ty()])]))vec![ty::TraitRef::new(cx, destruct_def_id, [closure_args.tupled_upvars_ty()])])
835        }
836        // Coroutines could implement `[const] Drop`,
837        // but they don't really need to right now.
838        ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(_, _) => {
839            Err(NoSolution)
840        }
841
842        // FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop`
843        // if their inner type implements it.
844        ty::UnsafeBinder(_) => Err(NoSolution),
845
846        ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => {
847            Err(NoSolution)
848        }
849
850        ty::Bound(..)
851        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
852            {
    ::core::panicking::panic_fmt(format_args!("unexpected type `{0:?}`",
            self_ty));
}panic!("unexpected type `{self_ty:?}`")
853        }
854    }
855}
856
857/// Assemble a list of predicates that would be present on a theoretical
858/// user impl for an object type. These predicates must be checked any time
859/// we assemble a built-in object candidate for an object type, since they
860/// are not implied by the well-formedness of the type.
861///
862/// For example, given the following traits:
863///
864/// ```rust,ignore (theoretical code)
865/// trait Foo: Baz {
866///     type Bar: Copy;
867/// }
868///
869/// trait Baz {}
870/// ```
871///
872/// For the dyn type `dyn Foo<Item = Ty>`, we can imagine there being a
873/// pair of theoretical impls:
874///
875/// ```rust,ignore (theoretical code)
876/// impl Foo for dyn Foo<Item = Ty>
877/// where
878///     Self: Baz,
879///     <Self as Foo>::Bar: Copy,
880/// {
881///     type Bar = Ty;
882/// }
883///
884/// impl Baz for dyn Foo<Item = Ty> {}
885/// ```
886///
887/// However, in order to make such impls non-cyclical, we need to do an
888/// additional step of eagerly folding the associated types in the where
889/// clauses of the impl. In this example, that means replacing
890/// `<Self as Foo>::Bar` with `Ty` in the first impl.
891pub(in crate::solve) fn predicates_for_object_candidate<D, I>(
892    ecx: &mut EvalCtxt<'_, D>,
893    param_env: I::ParamEnv,
894    trait_ref: Binder<I, ty::TraitRef<I>>,
895    object_bounds: I::BoundExistentialPredicates,
896) -> Result<Vec<Goal<I, I::Predicate>>, AmbiguousOrRerunNonErased>
897where
898    D: SolverDelegate<Interner = I>,
899    I: Interner,
900{
901    let cx = ecx.cx();
902    let trait_ref = ecx.instantiate_binder_with_infer(trait_ref);
903    let mut requirements = ::alloc::vec::Vec::new()vec![];
904    // Elaborating all supertrait outlives obligations here is not soundness critical,
905    // since if we just used the unelaborated set, then the transitive supertraits would
906    // be reachable when proving the former. However, since we elaborate all supertrait
907    // outlives obligations when confirming impls, we would end up with a different set
908    // of outlives obligations here if we didn't do the same, leading to ambiguity.
909    // FIXME(-Znext-solver=coinductive): Adding supertraits here can be removed once we
910    // make impls coinductive always, since they'll always need to prove their supertraits.
911    requirements.extend(elaborate::elaborate(
912        cx,
913        cx.explicit_super_clauses_of(trait_ref.def_id)
914            .iter_instantiated(cx, trait_ref.args)
915            .map(Unnormalized::skip_norm_wip)
916            .map(|(pred, _)| pred),
917    ));
918
919    // FIXME(mgca): Also add associated consts to
920    // the requirements here.
921    for associated_type_def_id in cx.associated_type_def_ids(trait_ref.def_id) {
922        // associated types that require `Self: Sized` do not show up in the built-in
923        // implementation of `Trait for dyn Trait`, and can be dropped here.
924        if cx.generics_require_sized_self(associated_type_def_id) {
925            continue;
926        }
927
928        requirements.extend(
929            cx.item_bounds(associated_type_def_id)
930                .iter_instantiated(cx, trait_ref.args)
931                .map(Unnormalized::skip_norm_wip),
932        );
933    }
934
935    let mut replace_projection_with: HashMap<_, Vec<_>> = HashMap::default();
936    for bound in object_bounds.iter() {
937        if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() {
938            // FIXME: We *probably* should replace this with a dummy placeholder,
939            // b/c don't want to replace literal instances of this dyn type that
940            // show up in the bounds, but just ones that come from substituting
941            // `Self` with the dyn type.
942            let proj = proj.with_self_ty(cx, trait_ref.self_ty());
943            replace_projection_with.entry(proj.def_id()).or_default().push(bound.rebind(proj));
944        }
945    }
946
947    let mut folder = ReplaceProjectionWith {
948        ecx,
949        param_env,
950        self_ty: trait_ref.self_ty(),
951        mapping: &replace_projection_with,
952        nested: ::alloc::vec::Vec::new()vec![],
953    };
954
955    let requirements = requirements.try_fold_with(&mut folder)?;
956    Ok(folder
957        .nested
958        .into_iter()
959        .chain(requirements.into_iter().map(|clause| Goal::new(cx, param_env, clause)))
960        .collect())
961}
962
963struct ReplaceProjectionWith<'a, 'b, I: Interner, D: SolverDelegate<Interner = I>> {
964    ecx: &'a mut EvalCtxt<'b, D>,
965    param_env: I::ParamEnv,
966    self_ty: I::Ty,
967    mapping: &'a HashMap<I::TraitAssocTermId, Vec<ty::Binder<I, ty::ProjectionPredicate<I>>>>,
968    nested: Vec<Goal<I, I::Predicate>>,
969}
970
971impl<D, I> ReplaceProjectionWith<'_, '_, I, D>
972where
973    D: SolverDelegate<Interner = I>,
974    I: Interner,
975{
976    fn projection_may_match(
977        &mut self,
978        source_projection: ty::Binder<I, ty::ProjectionPredicate<I>>,
979        target_projection: ty::AliasTerm<I>,
980    ) -> Result<bool, RerunNonErased> {
981        if source_projection.item_def_id() != target_projection.expect_projection_def_id() {
982            return Ok(false);
983        }
984        match self
985            .ecx
986            .probe(|_| ProbeKind::ProjectionCompatibility)
987            .enter_without_propagated_nested_goals(|ecx| {
988                let source_projection = ecx.instantiate_binder_with_infer(source_projection);
989                ecx.eq(self.param_env, source_projection.projection_term, target_projection)?;
990                ecx.try_evaluate_added_goals()
991            }) {
992            Ok(_) => Ok(true),
993            Err(NoSolutionOrRerunNonErased::NoSolution(_)) => Ok(false),
994            Err(NoSolutionOrRerunNonErased::RerunNonErased(rerun)) => Err(rerun),
995        }
996    }
997
998    /// Try to replace an alias with the term present in the projection bounds of the self type.
999    /// Returns `Ok<None>` if this alias is not eligible to be replaced, or bail with
1000    /// `Err(Ambiguous)` if it's uncertain which projection bound to replace the term with due
1001    /// to multiple bounds applying, or with `Err(RerunNonErased)` if we have to rerun the
1002    /// goal in original `TypingMode`.
1003    fn try_eagerly_replace_alias(
1004        &mut self,
1005        alias_term: ty::AliasTerm<I>,
1006    ) -> Result<Option<I::Term>, AmbiguousOrRerunNonErased> {
1007        if alias_term.self_ty() != self.self_ty {
1008            return Ok(None);
1009        }
1010
1011        let Some(replacements) = self.mapping.get(&alias_term.expect_projection_def_id()) else {
1012            return Ok(None);
1013        };
1014
1015        // This is quite similar to the `projection_may_match` we use in unsizing,
1016        // but here we want to unify a projection predicate against an alias term
1017        // so we can replace it with the projection predicate's term.
1018        let mut matching_projection = None;
1019        for source_projection in replacements {
1020            if self.projection_may_match(*source_projection, alias_term)? {
1021                // FIXME: This *may* have issues with duplicated projections.
1022                if matching_projection.is_some() {
1023                    // If there's more than one projection that we can unify here, then we
1024                    // need to stall until inference constrains things so that there's only
1025                    // one choice.
1026                    return Err(AmbiguousOrRerunNonErased::Ambiguous);
1027                }
1028                matching_projection = Some(source_projection)
1029            }
1030        }
1031
1032        let Some(matching) = matching_projection else {
1033            // This shouldn't happen.
1034            {
    ::core::panicking::panic_fmt(format_args!("could not replace {1:?} with term from from {0:?}",
            self.self_ty, alias_term));
};panic!("could not replace {alias_term:?} with term from from {:?}", self.self_ty);
1035        };
1036
1037        let replacement = self.ecx.instantiate_binder_with_infer(*matching);
1038        self.nested.extend(
1039            self.ecx
1040                .eq_and_get_goals(self.param_env, alias_term, replacement.projection_term)
1041                .expect("expected to be able to unify goal projection with dyn's projection"),
1042        );
1043
1044        Ok(Some(replacement.term))
1045    }
1046}
1047
1048pub(crate) enum AmbiguousOrRerunNonErased {
1049    /// Marker for bailing with ambiguity.
1050    Ambiguous,
1051    RerunNonErased(RerunNonErased),
1052}
1053
1054impl From<RerunNonErased> for AmbiguousOrRerunNonErased {
1055    fn from(rerun: RerunNonErased) -> Self {
1056        AmbiguousOrRerunNonErased::RerunNonErased(rerun)
1057    }
1058}
1059
1060impl<D, I> FallibleTypeFolder<I> for ReplaceProjectionWith<'_, '_, I, D>
1061where
1062    D: SolverDelegate<Interner = I>,
1063    I: Interner,
1064{
1065    type Error = AmbiguousOrRerunNonErased;
1066
1067    fn cx(&self) -> I {
1068        self.ecx.cx()
1069    }
1070
1071    fn try_fold_ty(&mut self, ty: I::Ty) -> Result<I::Ty, Self::Error> {
1072        if let ty::Alias(_, alias_ty @ ty::AliasTy { kind: ty::Projection { .. }, .. }) = ty.kind()
1073            && let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())?
1074        {
1075            Ok(term.expect_ty())
1076        } else {
1077            ty.try_super_fold_with(self)
1078        }
1079    }
1080}