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