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