2023-07-23 12:30:52 -07:00
|
|
|
//! Code which is used by built-in goals that match "structurally", such a auto
|
|
|
|
//! traits, `Copy`/`Clone`.
|
2023-02-22 01:11:57 +00:00
|
|
|
use rustc_data_structures::fx::FxHashMap;
|
2024-01-24 22:27:25 +00:00
|
|
|
use rustc_hir::LangItem;
|
2023-02-22 01:26:01 +00:00
|
|
|
use rustc_hir::{def_id::DefId, Movability, Mutability};
|
2023-02-16 02:28:10 +00:00
|
|
|
use rustc_infer::traits::query::NoSolution;
|
2023-07-26 22:29:52 +00:00
|
|
|
use rustc_middle::traits::solve::Goal;
|
2023-03-30 03:51:27 +00:00
|
|
|
use rustc_middle::ty::{
|
2024-03-14 11:51:22 -04:00
|
|
|
self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
2023-03-30 03:51:27 +00:00
|
|
|
};
|
2024-01-25 03:50:23 +00:00
|
|
|
use rustc_span::sym;
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2023-02-16 02:28:10 +00:00
|
|
|
use crate::solve::EvalCtxt;
|
|
|
|
|
2023-01-18 14:56:44 +00:00
|
|
|
// Calculates the constituent types of a type for `auto trait` purposes.
|
|
|
|
//
|
2023-10-19 21:46:28 +00:00
|
|
|
// For types with an "existential" binder, i.e. coroutine witnesses, we also
|
2023-01-18 14:56:44 +00:00
|
|
|
// instantiate the binder with placeholders eagerly.
|
2023-11-08 12:24:19 +01:00
|
|
|
#[instrument(level = "debug", skip(ecx), ret)]
|
2023-03-30 11:49:06 +02:00
|
|
|
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
2023-02-16 02:28:10 +00:00
|
|
|
ecx: &EvalCtxt<'_, 'tcx>,
|
2023-01-18 14:56:44 +00:00
|
|
|
ty: Ty<'tcx>,
|
2024-01-30 01:27:06 +00:00
|
|
|
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
|
2023-02-16 02:28:10 +00:00
|
|
|
let tcx = ecx.tcx();
|
2023-01-18 14:56:44 +00:00
|
|
|
match *ty.kind() {
|
|
|
|
ty::Uint(_)
|
|
|
|
| ty::Int(_)
|
|
|
|
| ty::Bool
|
|
|
|
| ty::Float(_)
|
|
|
|
| ty::FnDef(..)
|
|
|
|
| ty::FnPtr(_)
|
|
|
|
| ty::Error(_)
|
|
|
|
| ty::Never
|
|
|
|
| ty::Char => Ok(vec![]),
|
|
|
|
|
2023-04-03 23:24:47 +00:00
|
|
|
// Treat `str` like it's defined as `struct str([u8]);`
|
2024-01-30 01:27:06 +00:00
|
|
|
ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, tcx.types.u8))]),
|
2023-02-11 23:01:22 +00:00
|
|
|
|
2023-01-25 00:38:34 +00:00
|
|
|
ty::Dynamic(..)
|
2023-01-18 14:56:44 +00:00
|
|
|
| ty::Param(..)
|
|
|
|
| ty::Foreign(..)
|
2023-03-07 12:03:11 +00:00
|
|
|
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
2023-04-03 23:24:47 +00:00
|
|
|
| ty::Placeholder(..)
|
|
|
|
| ty::Bound(..)
|
|
|
|
| ty::Infer(_) => {
|
2023-01-25 00:38:34 +00:00
|
|
|
bug!("unexpected type `{ty}`")
|
|
|
|
}
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2024-03-21 17:11:06 -04:00
|
|
|
ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => {
|
2024-01-30 01:27:06 +00:00
|
|
|
Ok(vec![ty::Binder::dummy(element_ty)])
|
2023-01-18 14:56:44 +00:00
|
|
|
}
|
|
|
|
|
2024-01-30 01:27:06 +00:00
|
|
|
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![ty::Binder::dummy(element_ty)]),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2023-11-21 20:07:32 +01:00
|
|
|
ty::Tuple(tys) => {
|
2023-01-18 14:56:44 +00:00
|
|
|
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
|
2024-01-30 01:27:06 +00:00
|
|
|
Ok(tys.iter().map(ty::Binder::dummy).collect())
|
2023-01-18 14:56:44 +00:00
|
|
|
}
|
|
|
|
|
2024-01-30 01:27:06 +00:00
|
|
|
ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2024-02-08 13:19:20 +00:00
|
|
|
ty::CoroutineClosure(_, args) => {
|
|
|
|
Ok(vec![ty::Binder::dummy(args.as_coroutine_closure().tupled_upvars_ty())])
|
|
|
|
}
|
2024-01-24 18:01:56 +00:00
|
|
|
|
2023-12-21 01:52:10 +00:00
|
|
|
ty::Coroutine(_, args) => {
|
2023-10-19 21:46:28 +00:00
|
|
|
let coroutine_args = args.as_coroutine();
|
2024-01-30 01:27:06 +00:00
|
|
|
Ok(vec![
|
|
|
|
ty::Binder::dummy(coroutine_args.tupled_upvars_ty()),
|
|
|
|
ty::Binder::dummy(coroutine_args.witness()),
|
|
|
|
])
|
2023-01-18 14:56:44 +00:00
|
|
|
}
|
|
|
|
|
2023-10-19 16:06:43 +00:00
|
|
|
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
2023-03-30 03:51:27 +00:00
|
|
|
.tcx()
|
2024-03-14 11:51:22 -04:00
|
|
|
.bound_coroutine_hidden_types(def_id)
|
|
|
|
.map(|bty| bty.instantiate(tcx, args))
|
2023-03-30 03:51:27 +00:00
|
|
|
.collect()),
|
2022-10-01 14:56:24 +02:00
|
|
|
|
2023-01-18 14:56:44 +00:00
|
|
|
// For `PhantomData<T>`, we pass `T`.
|
2024-01-30 01:27:06 +00:00
|
|
|
ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2024-01-30 01:27:06 +00:00
|
|
|
ty::Adt(def, args) => {
|
|
|
|
Ok(def.all_fields().map(|f| ty::Binder::dummy(f.ty(tcx, args))).collect())
|
|
|
|
}
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
|
2023-01-18 14:56:44 +00:00
|
|
|
// We can resolve the `impl Trait` to its concrete type,
|
|
|
|
// which enforces a DAG between the functions requiring
|
|
|
|
// the auto trait bounds in question.
|
2024-01-30 01:27:06 +00:00
|
|
|
Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, args))])
|
2023-01-18 14:56:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-08 12:24:19 +01:00
|
|
|
#[instrument(level = "debug", skip(ecx), ret)]
|
2023-03-30 11:49:06 +02:00
|
|
|
pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
2023-02-16 02:28:10 +00:00
|
|
|
ecx: &EvalCtxt<'_, 'tcx>,
|
2023-01-18 14:56:44 +00:00
|
|
|
ty: Ty<'tcx>,
|
2024-01-30 01:27:06 +00:00
|
|
|
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
|
2023-01-18 14:56:44 +00:00
|
|
|
match *ty.kind() {
|
2024-03-14 20:18:04 +08:00
|
|
|
// impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, !
|
|
|
|
// impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure
|
2023-01-18 14:56:44 +00:00
|
|
|
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
|
|
|
| ty::Uint(_)
|
|
|
|
| ty::Int(_)
|
|
|
|
| ty::Bool
|
|
|
|
| ty::Float(_)
|
|
|
|
| ty::FnDef(..)
|
|
|
|
| ty::FnPtr(_)
|
|
|
|
| ty::RawPtr(..)
|
|
|
|
| ty::Char
|
|
|
|
| ty::Ref(..)
|
2023-10-19 16:06:43 +00:00
|
|
|
| ty::Coroutine(..)
|
|
|
|
| ty::CoroutineWitness(..)
|
2023-01-18 14:56:44 +00:00
|
|
|
| ty::Array(..)
|
|
|
|
| ty::Closure(..)
|
2024-01-24 18:01:56 +00:00
|
|
|
| ty::CoroutineClosure(..)
|
2023-01-18 14:56:44 +00:00
|
|
|
| ty::Never
|
|
|
|
| ty::Dynamic(_, _, ty::DynStar)
|
|
|
|
| ty::Error(_) => Ok(vec![]),
|
|
|
|
|
|
|
|
ty::Str
|
|
|
|
| ty::Slice(_)
|
|
|
|
| ty::Dynamic(..)
|
|
|
|
| ty::Foreign(..)
|
|
|
|
| ty::Alias(..)
|
2023-01-19 15:24:00 +00:00
|
|
|
| ty::Param(_)
|
2023-01-25 00:38:34 +00:00
|
|
|
| ty::Placeholder(..) => Err(NoSolution),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2023-01-25 00:38:34 +00:00
|
|
|
ty::Bound(..)
|
|
|
|
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
|
|
|
bug!("unexpected type `{ty}`")
|
|
|
|
}
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2024-03-13 23:35:24 +01:00
|
|
|
// impl Sized for ()
|
|
|
|
// impl Sized for (T1, T2, .., Tn) where Tn: Sized if n >= 1
|
|
|
|
ty::Tuple(tys) => Ok(tys.last().map_or_else(Vec::new, |&ty| vec![ty::Binder::dummy(ty)])),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2024-03-13 23:33:45 +01:00
|
|
|
// impl Sized for Adt<Args...> where sized_constraint(Adt)<Args...>: Sized
|
|
|
|
// `sized_constraint(Adt)` is the deepest struct trail that can be determined
|
|
|
|
// by the definition of `Adt`, independent of the generic args.
|
|
|
|
// impl Sized for Adt<Args...> if sized_constraint(Adt) == None
|
|
|
|
// As a performance optimization, `sized_constraint(Adt)` can return `None`
|
|
|
|
// if the ADTs definition implies that it is sized by for all possible args.
|
|
|
|
// In this case, the builtin impl will have no nested subgoals. This is a
|
|
|
|
// "best effort" optimization and `sized_constraint` may return `Some`, even
|
|
|
|
// if the ADT is sized for all possible args.
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Adt(def, args) => {
|
2024-03-18 22:28:29 +01:00
|
|
|
if let Some(sized_crit) = def.sized_constraint(ecx.tcx()) {
|
|
|
|
Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.tcx(), args))])
|
|
|
|
} else {
|
|
|
|
Ok(vec![])
|
|
|
|
}
|
2023-01-18 14:56:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-08 12:24:19 +01:00
|
|
|
#[instrument(level = "debug", skip(ecx), ret)]
|
2023-03-30 11:49:06 +02:00
|
|
|
pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
2023-02-16 02:28:10 +00:00
|
|
|
ecx: &EvalCtxt<'_, 'tcx>,
|
2023-01-18 14:56:44 +00:00
|
|
|
ty: Ty<'tcx>,
|
2024-01-30 01:27:06 +00:00
|
|
|
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
|
2023-01-18 14:56:44 +00:00
|
|
|
match *ty.kind() {
|
2024-03-14 20:18:04 +08:00
|
|
|
// impl Copy/Clone for FnDef, FnPtr
|
2023-08-11 19:08:11 +02:00
|
|
|
ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
|
|
|
// Implementations are provided in core
|
|
|
|
ty::Uint(_)
|
|
|
|
| ty::Int(_)
|
2023-08-11 19:08:11 +02:00
|
|
|
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
2023-01-18 14:56:44 +00:00
|
|
|
| ty::Bool
|
|
|
|
| ty::Float(_)
|
|
|
|
| ty::Char
|
|
|
|
| ty::RawPtr(..)
|
|
|
|
| ty::Never
|
|
|
|
| ty::Ref(_, _, Mutability::Not)
|
|
|
|
| ty::Array(..) => Err(NoSolution),
|
|
|
|
|
|
|
|
ty::Dynamic(..)
|
|
|
|
| ty::Str
|
|
|
|
| ty::Slice(_)
|
|
|
|
| ty::Foreign(..)
|
|
|
|
| ty::Ref(_, _, Mutability::Mut)
|
|
|
|
| ty::Adt(_, _)
|
|
|
|
| ty::Alias(_, _)
|
2023-01-19 15:24:00 +00:00
|
|
|
| ty::Param(_)
|
2023-01-25 00:38:34 +00:00
|
|
|
| ty::Placeholder(..) => Err(NoSolution),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2023-01-25 00:38:34 +00:00
|
|
|
ty::Bound(..)
|
|
|
|
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
|
|
|
bug!("unexpected type `{ty}`")
|
|
|
|
}
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2024-03-14 20:18:04 +08:00
|
|
|
// impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone
|
2024-01-30 01:27:06 +00:00
|
|
|
ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2024-03-14 20:18:04 +08:00
|
|
|
// impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone
|
2024-01-30 01:27:06 +00:00
|
|
|
ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2024-01-24 18:01:56 +00:00
|
|
|
ty::CoroutineClosure(..) => Err(NoSolution),
|
|
|
|
|
2024-03-14 20:18:04 +08:00
|
|
|
// only when `coroutine_clone` is enabled and the coroutine is movable
|
|
|
|
// impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses)
|
2023-12-26 22:43:11 +00:00
|
|
|
ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) {
|
2023-12-21 01:52:10 +00:00
|
|
|
Movability::Static => Err(NoSolution),
|
|
|
|
Movability::Movable => {
|
|
|
|
if ecx.tcx().features().coroutine_clone {
|
|
|
|
let coroutine = args.as_coroutine();
|
2024-01-30 01:27:06 +00:00
|
|
|
Ok(vec![
|
|
|
|
ty::Binder::dummy(coroutine.tupled_upvars_ty()),
|
|
|
|
ty::Binder::dummy(coroutine.witness()),
|
|
|
|
])
|
2023-12-21 01:52:10 +00:00
|
|
|
} else {
|
|
|
|
Err(NoSolution)
|
|
|
|
}
|
2023-01-18 14:56:44 +00:00
|
|
|
}
|
2023-12-21 01:52:10 +00:00
|
|
|
},
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2024-03-14 20:18:04 +08:00
|
|
|
// impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
|
2023-10-19 16:06:43 +00:00
|
|
|
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
2023-03-30 03:51:27 +00:00
|
|
|
.tcx()
|
2024-03-14 11:51:22 -04:00
|
|
|
.bound_coroutine_hidden_types(def_id)
|
|
|
|
.map(|bty| bty.instantiate(ecx.tcx(), args))
|
2023-03-30 03:51:27 +00:00
|
|
|
.collect()),
|
2023-01-18 14:56:44 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-19 01:20:34 +00:00
|
|
|
|
2023-01-24 23:38:20 +00:00
|
|
|
// Returns a binder of the tupled inputs types and output type from a builtin callable type.
|
2023-03-30 11:49:06 +02:00
|
|
|
pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
2023-01-19 01:20:34 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
self_ty: Ty<'tcx>,
|
|
|
|
goal_kind: ty::ClosureKind,
|
|
|
|
) -> Result<Option<ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, NoSolution> {
|
|
|
|
match *self_ty.kind() {
|
2023-03-21 11:44:36 +00:00
|
|
|
// keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::FnDef(def_id, args) => {
|
2023-03-21 11:44:36 +00:00
|
|
|
let sig = tcx.fn_sig(def_id);
|
|
|
|
if sig.skip_binder().is_fn_trait_compatible()
|
|
|
|
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
|
|
|
{
|
|
|
|
Ok(Some(
|
2023-07-11 22:35:29 +01:00
|
|
|
sig.instantiate(tcx, args)
|
2023-07-05 20:13:26 +01:00
|
|
|
.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())),
|
2023-03-21 11:44:36 +00:00
|
|
|
))
|
|
|
|
} else {
|
|
|
|
Err(NoSolution)
|
|
|
|
}
|
|
|
|
}
|
2023-03-21 11:11:32 +00:00
|
|
|
// keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
|
|
|
|
ty::FnPtr(sig) => {
|
2023-03-21 11:38:13 +00:00
|
|
|
if sig.is_fn_trait_compatible() {
|
2023-07-05 20:13:26 +01:00
|
|
|
Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output()))))
|
2023-03-21 11:11:32 +00:00
|
|
|
} else {
|
|
|
|
Err(NoSolution)
|
|
|
|
}
|
|
|
|
}
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Closure(_, args) => {
|
|
|
|
let closure_args = args.as_closure();
|
|
|
|
match closure_args.kind_ty().to_opt_closure_kind() {
|
2023-03-29 23:36:27 +00:00
|
|
|
// If the closure's kind doesn't extend the goal kind,
|
|
|
|
// then the closure doesn't implement the trait.
|
|
|
|
Some(closure_kind) => {
|
|
|
|
if !closure_kind.extends(goal_kind) {
|
|
|
|
return Err(NoSolution);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Closure kind is not yet determined, so we return ambiguity unless
|
|
|
|
// the expected kind is `FnOnce` as that is always implemented.
|
|
|
|
None => {
|
|
|
|
if goal_kind != ty::ClosureKind::FnOnce {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
}
|
2023-01-19 01:20:34 +00:00
|
|
|
}
|
2023-07-11 22:35:29 +01:00
|
|
|
Ok(Some(closure_args.sig().map_bound(|sig| (sig.inputs()[0], sig.output()))))
|
2023-01-19 01:20:34 +00:00
|
|
|
}
|
2024-01-24 18:01:56 +00:00
|
|
|
|
2024-01-25 03:50:23 +00:00
|
|
|
// Coroutine-closures don't implement `Fn` traits the normal way.
|
2024-02-26 23:43:10 +00:00
|
|
|
// Instead, they always implement `FnOnce`, but only implement
|
|
|
|
// `FnMut`/`Fn` if they capture no upvars, since those may borrow
|
|
|
|
// from the closure.
|
|
|
|
ty::CoroutineClosure(def_id, args) => {
|
|
|
|
let args = args.as_coroutine_closure();
|
|
|
|
let kind_ty = args.kind_ty();
|
|
|
|
let sig = args.coroutine_closure_sig().skip_binder();
|
|
|
|
|
|
|
|
let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
|
|
|
if !closure_kind.extends(goal_kind) {
|
|
|
|
return Err(NoSolution);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If `Fn`/`FnMut`, we only implement this goal if we
|
|
|
|
// have no captures.
|
|
|
|
let no_borrows = match args.tupled_upvars_ty().kind() {
|
|
|
|
ty::Tuple(tys) => tys.is_empty(),
|
|
|
|
ty::Error(_) => false,
|
|
|
|
_ => bug!("tuple_fields called on non-tuple"),
|
|
|
|
};
|
|
|
|
if closure_kind != ty::ClosureKind::FnOnce && !no_borrows {
|
|
|
|
return Err(NoSolution);
|
|
|
|
}
|
|
|
|
|
2024-02-27 15:43:42 +00:00
|
|
|
coroutine_closure_to_certain_coroutine(
|
2024-02-26 23:43:10 +00:00
|
|
|
tcx,
|
|
|
|
goal_kind,
|
|
|
|
// No captures by ref, so this doesn't matter.
|
|
|
|
tcx.lifetimes.re_static,
|
2024-02-27 15:43:42 +00:00
|
|
|
def_id,
|
|
|
|
args,
|
|
|
|
sig,
|
2024-02-26 23:43:10 +00:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
// Closure kind is not yet determined, so we return ambiguity unless
|
|
|
|
// the expected kind is `FnOnce` as that is always implemented.
|
|
|
|
if goal_kind != ty::ClosureKind::FnOnce {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
2024-02-27 15:43:42 +00:00
|
|
|
coroutine_closure_to_ambiguous_coroutine(
|
2024-02-26 23:43:10 +00:00
|
|
|
tcx,
|
2024-02-27 15:43:42 +00:00
|
|
|
goal_kind, // No captures by ref, so this doesn't matter.
|
|
|
|
tcx.lifetimes.re_static,
|
|
|
|
def_id,
|
|
|
|
args,
|
|
|
|
sig,
|
2024-02-26 23:43:10 +00:00
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Some(args.coroutine_closure_sig().rebind((sig.tupled_inputs_ty, coroutine_ty))))
|
|
|
|
}
|
2024-01-24 18:01:56 +00:00
|
|
|
|
2023-01-19 01:20:34 +00:00
|
|
|
ty::Bool
|
|
|
|
| ty::Char
|
|
|
|
| ty::Int(_)
|
|
|
|
| ty::Uint(_)
|
|
|
|
| ty::Float(_)
|
|
|
|
| ty::Adt(_, _)
|
|
|
|
| ty::Foreign(_)
|
|
|
|
| ty::Str
|
|
|
|
| ty::Array(_, _)
|
|
|
|
| ty::Slice(_)
|
2024-03-21 17:11:06 -04:00
|
|
|
| ty::RawPtr(_, _)
|
2023-01-19 01:20:34 +00:00
|
|
|
| ty::Ref(_, _, _)
|
|
|
|
| ty::Dynamic(_, _, _)
|
2023-12-21 01:52:10 +00:00
|
|
|
| ty::Coroutine(_, _)
|
2023-10-19 16:06:43 +00:00
|
|
|
| ty::CoroutineWitness(..)
|
2023-01-19 01:20:34 +00:00
|
|
|
| ty::Never
|
2024-01-24 22:27:25 +00:00
|
|
|
| ty::Tuple(_)
|
|
|
|
| ty::Alias(_, _)
|
|
|
|
| ty::Param(_)
|
|
|
|
| ty::Placeholder(..)
|
|
|
|
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
|
|
|
| ty::Error(_) => Err(NoSolution),
|
|
|
|
|
|
|
|
ty::Bound(..)
|
|
|
|
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
|
|
|
bug!("unexpected type `{self_ty}`")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-27 15:43:42 +00:00
|
|
|
/// Relevant types for an async callable, including its inputs, output,
|
|
|
|
/// and the return type you get from awaiting the output.
|
|
|
|
#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)]
|
|
|
|
pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> {
|
|
|
|
pub tupled_inputs_ty: Ty<'tcx>,
|
|
|
|
/// Type returned by calling the closure
|
|
|
|
/// i.e. `f()`.
|
|
|
|
pub output_coroutine_ty: Ty<'tcx>,
|
|
|
|
/// Type returned by `await`ing the output
|
|
|
|
/// i.e. `f().await`.
|
|
|
|
pub coroutine_return_ty: Ty<'tcx>,
|
|
|
|
}
|
|
|
|
|
2024-01-24 22:27:25 +00:00
|
|
|
// Returns a binder of the tupled inputs types, output type, and coroutine type
|
2024-01-25 19:17:21 +00:00
|
|
|
// from a builtin coroutine-closure type. If we don't yet know the closure kind of
|
|
|
|
// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
|
|
|
|
// which enforces the closure is actually callable with the given trait. When we
|
|
|
|
// know the kind already, we can short-circuit this check.
|
2024-01-24 22:27:25 +00:00
|
|
|
pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
self_ty: Ty<'tcx>,
|
|
|
|
goal_kind: ty::ClosureKind,
|
|
|
|
env_region: ty::Region<'tcx>,
|
2024-02-27 15:43:42 +00:00
|
|
|
) -> Result<
|
|
|
|
(ty::Binder<'tcx, AsyncCallableRelevantTypes<'tcx>>, Vec<ty::Predicate<'tcx>>),
|
|
|
|
NoSolution,
|
|
|
|
> {
|
2024-01-24 22:27:25 +00:00
|
|
|
match *self_ty.kind() {
|
|
|
|
ty::CoroutineClosure(def_id, args) => {
|
|
|
|
let args = args.as_coroutine_closure();
|
|
|
|
let kind_ty = args.kind_ty();
|
2024-02-05 18:33:41 +00:00
|
|
|
let sig = args.coroutine_closure_sig().skip_binder();
|
|
|
|
let mut nested = vec![];
|
|
|
|
let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
2024-01-24 22:27:25 +00:00
|
|
|
if !closure_kind.extends(goal_kind) {
|
|
|
|
return Err(NoSolution);
|
|
|
|
}
|
2024-02-27 15:43:42 +00:00
|
|
|
|
|
|
|
coroutine_closure_to_certain_coroutine(
|
|
|
|
tcx, goal_kind, env_region, def_id, args, sig,
|
2024-02-05 18:33:41 +00:00
|
|
|
)
|
2024-01-24 22:27:25 +00:00
|
|
|
} else {
|
2024-01-25 19:17:21 +00:00
|
|
|
// When we don't know the closure kind (and therefore also the closure's upvars,
|
|
|
|
// which are computed at the same time), we must delay the computation of the
|
|
|
|
// generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
|
|
|
|
// goal functions similarly to the old `ClosureKind` predicate, and ensures that
|
|
|
|
// the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
|
|
|
|
// will project to the right upvars for the generator, appending the inputs and
|
|
|
|
// coroutine upvars respecting the closure kind.
|
2024-02-05 18:33:41 +00:00
|
|
|
nested.push(
|
|
|
|
ty::TraitRef::new(
|
|
|
|
tcx,
|
2024-02-27 15:43:42 +00:00
|
|
|
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None),
|
2024-02-05 18:33:41 +00:00
|
|
|
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
|
|
|
|
)
|
|
|
|
.to_predicate(tcx),
|
|
|
|
);
|
2024-02-27 15:43:42 +00:00
|
|
|
|
|
|
|
coroutine_closure_to_ambiguous_coroutine(
|
|
|
|
tcx, goal_kind, env_region, def_id, args, sig,
|
2024-02-05 18:33:41 +00:00
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok((
|
2024-02-27 15:43:42 +00:00
|
|
|
args.coroutine_closure_sig().rebind(AsyncCallableRelevantTypes {
|
|
|
|
tupled_inputs_ty: sig.tupled_inputs_ty,
|
|
|
|
output_coroutine_ty: coroutine_ty,
|
|
|
|
coroutine_return_ty: sig.return_ty,
|
|
|
|
}),
|
2024-02-05 18:33:41 +00:00
|
|
|
nested,
|
|
|
|
))
|
2024-01-24 22:27:25 +00:00
|
|
|
}
|
|
|
|
|
2024-02-05 19:17:18 +00:00
|
|
|
ty::FnDef(..) | ty::FnPtr(..) => {
|
|
|
|
let bound_sig = self_ty.fn_sig(tcx);
|
|
|
|
let sig = bound_sig.skip_binder();
|
|
|
|
let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
|
|
|
|
// `FnDef` and `FnPtr` only implement `AsyncFn*` when their
|
|
|
|
// return type implements `Future`.
|
|
|
|
let nested = vec![
|
|
|
|
bound_sig
|
|
|
|
.rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]))
|
|
|
|
.to_predicate(tcx),
|
|
|
|
];
|
|
|
|
let future_output_def_id = tcx
|
|
|
|
.associated_items(future_trait_def_id)
|
|
|
|
.filter_by_name_unhygienic(sym::Output)
|
|
|
|
.next()
|
|
|
|
.unwrap()
|
|
|
|
.def_id;
|
|
|
|
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
|
|
|
|
Ok((
|
2024-02-27 15:43:42 +00:00
|
|
|
bound_sig.rebind(AsyncCallableRelevantTypes {
|
|
|
|
tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs()),
|
|
|
|
output_coroutine_ty: sig.output(),
|
|
|
|
coroutine_return_ty: future_output_ty,
|
|
|
|
}),
|
2024-02-05 19:17:18 +00:00
|
|
|
nested,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
ty::Closure(_, args) => {
|
|
|
|
let args = args.as_closure();
|
|
|
|
let bound_sig = args.sig();
|
|
|
|
let sig = bound_sig.skip_binder();
|
|
|
|
let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
|
|
|
|
// `Closure`s only implement `AsyncFn*` when their return type
|
|
|
|
// implements `Future`.
|
|
|
|
let mut nested = vec![
|
|
|
|
bound_sig
|
|
|
|
.rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]))
|
|
|
|
.to_predicate(tcx),
|
|
|
|
];
|
|
|
|
|
|
|
|
// Additionally, we need to check that the closure kind
|
|
|
|
// is still compatible.
|
|
|
|
let kind_ty = args.kind_ty();
|
|
|
|
if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
|
|
|
if !closure_kind.extends(goal_kind) {
|
|
|
|
return Err(NoSolution);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let async_fn_kind_trait_def_id =
|
|
|
|
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
|
|
|
// When we don't know the closure kind (and therefore also the closure's upvars,
|
|
|
|
// which are computed at the same time), we must delay the computation of the
|
|
|
|
// generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
|
|
|
|
// goal functions similarly to the old `ClosureKind` predicate, and ensures that
|
|
|
|
// the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
|
|
|
|
// will project to the right upvars for the generator, appending the inputs and
|
|
|
|
// coroutine upvars respecting the closure kind.
|
|
|
|
nested.push(
|
|
|
|
ty::TraitRef::new(
|
|
|
|
tcx,
|
|
|
|
async_fn_kind_trait_def_id,
|
|
|
|
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
|
|
|
|
)
|
|
|
|
.to_predicate(tcx),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let future_output_def_id = tcx
|
|
|
|
.associated_items(future_trait_def_id)
|
|
|
|
.filter_by_name_unhygienic(sym::Output)
|
|
|
|
.next()
|
|
|
|
.unwrap()
|
|
|
|
.def_id;
|
|
|
|
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
|
2024-02-27 15:43:42 +00:00
|
|
|
Ok((
|
|
|
|
bound_sig.rebind(AsyncCallableRelevantTypes {
|
|
|
|
tupled_inputs_ty: sig.inputs()[0],
|
|
|
|
output_coroutine_ty: sig.output(),
|
|
|
|
coroutine_return_ty: future_output_ty,
|
|
|
|
}),
|
|
|
|
nested,
|
|
|
|
))
|
2024-02-05 19:17:18 +00:00
|
|
|
}
|
2024-01-24 22:27:25 +00:00
|
|
|
|
|
|
|
ty::Bool
|
|
|
|
| ty::Char
|
|
|
|
| ty::Int(_)
|
|
|
|
| ty::Uint(_)
|
|
|
|
| ty::Float(_)
|
|
|
|
| ty::Adt(_, _)
|
|
|
|
| ty::Foreign(_)
|
|
|
|
| ty::Str
|
|
|
|
| ty::Array(_, _)
|
|
|
|
| ty::Slice(_)
|
2024-03-21 17:11:06 -04:00
|
|
|
| ty::RawPtr(_, _)
|
2024-01-24 22:27:25 +00:00
|
|
|
| ty::Ref(_, _, _)
|
|
|
|
| ty::Dynamic(_, _, _)
|
|
|
|
| ty::Coroutine(_, _)
|
|
|
|
| ty::CoroutineWitness(..)
|
|
|
|
| ty::Never
|
2023-01-19 01:20:34 +00:00
|
|
|
| ty::Tuple(_)
|
|
|
|
| ty::Alias(_, _)
|
|
|
|
| ty::Param(_)
|
2023-01-25 00:38:34 +00:00
|
|
|
| ty::Placeholder(..)
|
|
|
|
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
2023-01-19 01:20:34 +00:00
|
|
|
| ty::Error(_) => Err(NoSolution),
|
2023-01-25 00:38:34 +00:00
|
|
|
|
|
|
|
ty::Bound(..)
|
|
|
|
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
|
|
|
bug!("unexpected type `{self_ty}`")
|
|
|
|
}
|
2023-01-19 01:20:34 +00:00
|
|
|
}
|
|
|
|
}
|
2023-02-22 01:11:57 +00:00
|
|
|
|
2024-02-27 15:43:42 +00:00
|
|
|
/// Given a coroutine-closure, project to its returned coroutine when we are *certain*
|
|
|
|
/// that the closure's kind is compatible with the goal.
|
|
|
|
fn coroutine_closure_to_certain_coroutine<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
goal_kind: ty::ClosureKind,
|
|
|
|
goal_region: ty::Region<'tcx>,
|
|
|
|
def_id: DefId,
|
|
|
|
args: ty::CoroutineClosureArgs<'tcx>,
|
|
|
|
sig: ty::CoroutineClosureSignature<'tcx>,
|
|
|
|
) -> Ty<'tcx> {
|
|
|
|
sig.to_coroutine_given_kind_and_upvars(
|
|
|
|
tcx,
|
|
|
|
args.parent_args(),
|
|
|
|
tcx.coroutine_for_closure(def_id),
|
|
|
|
goal_kind,
|
|
|
|
goal_region,
|
|
|
|
args.tupled_upvars_ty(),
|
|
|
|
args.coroutine_captures_by_ref_ty(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Given a coroutine-closure, project to its returned coroutine when we are *not certain*
|
|
|
|
/// that the closure's kind is compatible with the goal, and therefore also don't know
|
|
|
|
/// yet what the closure's upvars are.
|
|
|
|
///
|
|
|
|
/// Note that we do not also push a `AsyncFnKindHelper` goal here.
|
|
|
|
fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
goal_kind: ty::ClosureKind,
|
|
|
|
goal_region: ty::Region<'tcx>,
|
|
|
|
def_id: DefId,
|
|
|
|
args: ty::CoroutineClosureArgs<'tcx>,
|
|
|
|
sig: ty::CoroutineClosureSignature<'tcx>,
|
|
|
|
) -> Ty<'tcx> {
|
|
|
|
let async_fn_kind_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
|
|
|
let upvars_projection_def_id = tcx
|
|
|
|
.associated_items(async_fn_kind_trait_def_id)
|
|
|
|
.filter_by_name_unhygienic(sym::Upvars)
|
|
|
|
.next()
|
|
|
|
.unwrap()
|
|
|
|
.def_id;
|
|
|
|
let tupled_upvars_ty = Ty::new_projection(
|
|
|
|
tcx,
|
|
|
|
upvars_projection_def_id,
|
|
|
|
[
|
|
|
|
ty::GenericArg::from(args.kind_ty()),
|
|
|
|
Ty::from_closure_kind(tcx, goal_kind).into(),
|
|
|
|
goal_region.into(),
|
|
|
|
sig.tupled_inputs_ty.into(),
|
|
|
|
args.tupled_upvars_ty().into(),
|
|
|
|
args.coroutine_captures_by_ref_ty().into(),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
sig.to_coroutine(
|
|
|
|
tcx,
|
|
|
|
args.parent_args(),
|
|
|
|
Ty::from_closure_kind(tcx, goal_kind),
|
|
|
|
tcx.coroutine_for_closure(def_id),
|
|
|
|
tupled_upvars_ty,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-02-22 01:39:41 +00:00
|
|
|
/// Assemble a list of predicates that would be present on a theoretical
|
|
|
|
/// user impl for an object type. These predicates must be checked any time
|
|
|
|
/// we assemble a built-in object candidate for an object type, since they
|
|
|
|
/// are not implied by the well-formedness of the type.
|
|
|
|
///
|
|
|
|
/// For example, given the following traits:
|
|
|
|
///
|
|
|
|
/// ```rust,ignore (theoretical code)
|
|
|
|
/// trait Foo: Baz {
|
|
|
|
/// type Bar: Copy;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// trait Baz {}
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// For the dyn type `dyn Foo<Item = Ty>`, we can imagine there being a
|
|
|
|
/// pair of theoretical impls:
|
|
|
|
///
|
|
|
|
/// ```rust,ignore (theoretical code)
|
|
|
|
/// impl Foo for dyn Foo<Item = Ty>
|
|
|
|
/// where
|
|
|
|
/// Self: Baz,
|
|
|
|
/// <Self as Foo>::Bar: Copy,
|
|
|
|
/// {
|
|
|
|
/// type Bar = Ty;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl Baz for dyn Foo<Item = Ty> {}
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// However, in order to make such impls well-formed, we need to do an
|
|
|
|
/// additional step of eagerly folding the associated types in the where
|
|
|
|
/// clauses of the impl. In this example, that means replacing
|
|
|
|
/// `<Self as Foo>::Bar` with `Ty` in the first impl.
|
2023-03-30 11:49:06 +02:00
|
|
|
///
|
|
|
|
// FIXME: This is only necessary as `<Self as Trait>::Assoc: ItemBound`
|
|
|
|
// bounds in impls are trivially proven using the item bound candidates.
|
|
|
|
// This is unsound in general and once that is fixed, we don't need to
|
|
|
|
// normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9
|
|
|
|
// for more details.
|
|
|
|
pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
|
2023-02-22 01:26:01 +00:00
|
|
|
ecx: &EvalCtxt<'_, 'tcx>,
|
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2023-02-22 01:11:57 +00:00
|
|
|
trait_ref: ty::TraitRef<'tcx>,
|
|
|
|
object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
2023-07-26 22:29:52 +00:00
|
|
|
) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> {
|
2023-02-22 01:26:01 +00:00
|
|
|
let tcx = ecx.tcx();
|
2023-02-22 01:11:57 +00:00
|
|
|
let mut requirements = vec![];
|
|
|
|
requirements.extend(
|
2023-07-11 22:35:29 +01:00
|
|
|
tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.args).predicates,
|
2023-02-22 01:11:57 +00:00
|
|
|
);
|
|
|
|
for item in tcx.associated_items(trait_ref.def_id).in_definition_order() {
|
2023-02-22 01:39:41 +00:00
|
|
|
// FIXME(associated_const_equality): Also add associated consts to
|
|
|
|
// the requirements here.
|
2023-02-22 01:11:57 +00:00
|
|
|
if item.kind == ty::AssocKind::Type {
|
2023-09-02 05:06:21 +00:00
|
|
|
// associated types that require `Self: Sized` do not show up in the built-in
|
|
|
|
// implementation of `Trait for dyn Trait`, and can be dropped here.
|
|
|
|
if tcx.generics_require_sized_self(item.def_id) {
|
2023-09-02 04:33:58 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-07-17 17:49:47 +00:00
|
|
|
requirements
|
|
|
|
.extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, trait_ref.args));
|
2023-02-22 01:11:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut replace_projection_with = FxHashMap::default();
|
|
|
|
for bound in object_bound {
|
2023-02-22 01:26:01 +00:00
|
|
|
if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() {
|
2023-02-22 01:11:57 +00:00
|
|
|
let proj = proj.with_self_ty(tcx, trait_ref.self_ty());
|
2023-02-22 01:26:01 +00:00
|
|
|
let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj));
|
2023-02-22 01:11:57 +00:00
|
|
|
assert_eq!(
|
|
|
|
old_ty,
|
|
|
|
None,
|
2024-02-12 15:39:32 +09:00
|
|
|
"{} has two generic parameters: {} and {}",
|
2023-02-22 01:11:57 +00:00
|
|
|
proj.projection_ty,
|
|
|
|
proj.term,
|
|
|
|
old_ty.unwrap()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-26 22:29:52 +00:00
|
|
|
let mut folder =
|
|
|
|
ReplaceProjectionWith { ecx, param_env, mapping: replace_projection_with, nested: vec![] };
|
|
|
|
let folded_requirements = requirements.fold_with(&mut folder);
|
|
|
|
|
|
|
|
folder
|
|
|
|
.nested
|
|
|
|
.into_iter()
|
|
|
|
.chain(folded_requirements.into_iter().map(|clause| Goal::new(tcx, param_env, clause)))
|
|
|
|
.collect()
|
2023-02-22 01:11:57 +00:00
|
|
|
}
|
|
|
|
|
2023-02-22 01:26:01 +00:00
|
|
|
struct ReplaceProjectionWith<'a, 'tcx> {
|
|
|
|
ecx: &'a EvalCtxt<'a, 'tcx>,
|
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
|
|
|
mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
|
2023-07-26 22:29:52 +00:00
|
|
|
nested: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
2023-02-22 01:11:57 +00:00
|
|
|
}
|
|
|
|
|
2023-02-22 01:26:01 +00:00
|
|
|
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
|
2023-02-22 01:11:57 +00:00
|
|
|
fn interner(&self) -> TyCtxt<'tcx> {
|
2023-02-22 01:26:01 +00:00
|
|
|
self.ecx.tcx()
|
2023-02-22 01:11:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
|
|
|
if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
|
2023-02-22 01:26:01 +00:00
|
|
|
&& let Some(replacement) = self.mapping.get(&alias_ty.def_id)
|
2023-02-22 01:11:57 +00:00
|
|
|
{
|
2023-02-22 01:39:41 +00:00
|
|
|
// We may have a case where our object type's projection bound is higher-ranked,
|
|
|
|
// but the where clauses we instantiated are not. We can solve this by instantiating
|
|
|
|
// the binder at the usage site.
|
2023-02-22 01:26:01 +00:00
|
|
|
let proj = self.ecx.instantiate_binder_with_infer(*replacement);
|
2023-07-26 22:29:52 +00:00
|
|
|
// FIXME: Technically this equate could be fallible...
|
|
|
|
self.nested.extend(
|
|
|
|
self.ecx
|
|
|
|
.eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
|
|
|
|
.expect("expected to be able to unify goal projection with dyn's projection"),
|
|
|
|
);
|
2023-02-22 01:26:01 +00:00
|
|
|
proj.term.ty().unwrap()
|
2023-02-22 01:11:57 +00:00
|
|
|
} else {
|
|
|
|
ty.super_fold_with(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|