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