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-01-24 22:27:25 +00:00
|
|
|
self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
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>,
|
|
|
|
) -> Result<Vec<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]);`
|
2023-07-05 20:13:26 +01:00
|
|
|
ty::Str => Ok(vec![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
|
|
|
|
|
|
|
ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
|
|
|
|
Ok(vec![element_ty])
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
|
|
|
|
|
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
|
|
|
|
Ok(tys.iter().collect())
|
|
|
|
}
|
|
|
|
|
2023-11-21 20:07:32 +01:00
|
|
|
ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2024-01-24 18:01:56 +00:00
|
|
|
ty::CoroutineClosure(_, args) => Ok(vec![args.as_coroutine_closure().tupled_upvars_ty()]),
|
|
|
|
|
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();
|
|
|
|
Ok(vec![coroutine_args.tupled_upvars_ty(), 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()
|
2023-10-19 21:46:28 +00:00
|
|
|
.coroutine_hidden_types(def_id)
|
2023-03-30 03:51:27 +00:00
|
|
|
.map(|bty| {
|
|
|
|
ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars(
|
|
|
|
tcx,
|
2023-07-11 22:35:29 +01:00
|
|
|
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`.
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![args.type_at(0)]),
|
2023-01-18 14:56:44 +00:00
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Adt(def, args) => Ok(def.all_fields().map(|f| 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.
|
2023-07-11 22:35:29 +01:00
|
|
|
Ok(vec![tcx.type_of(def_id).instantiate(tcx, args)])
|
2023-01-18 14:56:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-30 11:49:06 +02:00
|
|
|
pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>(
|
2023-03-30 03:51:27 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
) -> ty::Binder<'tcx, Ty<'tcx>> {
|
2023-11-13 14:12:56 +00:00
|
|
|
debug_assert!(!ty.has_bound_regions());
|
2023-03-30 03:51:27 +00:00
|
|
|
let mut counter = 0;
|
2023-04-26 10:14:16 +10:00
|
|
|
let ty = tcx.fold_regions(ty, |r, current_depth| match r.kind() {
|
|
|
|
ty::ReErased => {
|
2023-08-03 15:56:56 +00:00
|
|
|
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(counter), kind: ty::BrAnon };
|
2023-03-30 03:51:27 +00:00
|
|
|
counter += 1;
|
2023-11-13 14:00:05 +00:00
|
|
|
ty::Region::new_bound(tcx, current_depth, br)
|
2023-03-30 03:51:27 +00:00
|
|
|
}
|
2023-04-26 10:14:16 +10:00
|
|
|
// All free regions should be erased here.
|
|
|
|
r => bug!("unexpected region: {r:?}"),
|
2023-03-30 03:51:27 +00:00
|
|
|
});
|
|
|
|
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
|
2023-08-03 15:56:56 +00:00
|
|
|
(0..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon)),
|
2023-03-30 03:51:27 +00:00
|
|
|
);
|
|
|
|
ty::Binder::bind_with_vars(ty, bound_vars)
|
|
|
|
}
|
|
|
|
|
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>,
|
|
|
|
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
|
|
|
match *ty.kind() {
|
|
|
|
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
|
|
|
|
|
|
|
ty::Tuple(tys) => Ok(tys.to_vec()),
|
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Adt(def, args) => {
|
2023-02-16 02:28:10 +00:00
|
|
|
let sized_crit = def.sized_constraint(ecx.tcx());
|
2023-08-01 00:52:16 +00:00
|
|
|
Ok(sized_crit.iter_instantiated(ecx.tcx(), args).collect())
|
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>,
|
|
|
|
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
|
|
|
match *ty.kind() {
|
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
|
|
|
|
|
|
|
ty::Tuple(tys) => Ok(tys.to_vec()),
|
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Closure(_, args) => Ok(vec![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),
|
|
|
|
|
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();
|
|
|
|
Ok(vec![coroutine.tupled_upvars_ty(), coroutine.witness()])
|
|
|
|
} 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
|
|
|
|
2023-10-19 16:06:43 +00:00
|
|
|
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
2023-03-30 03:51:27 +00:00
|
|
|
.tcx()
|
2023-10-19 21:46:28 +00:00
|
|
|
.coroutine_hidden_types(def_id)
|
2023-03-30 03:51:27 +00:00
|
|
|
.map(|bty| {
|
|
|
|
ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars(
|
|
|
|
ecx.tcx(),
|
2023-07-11 22:35:29 +01:00
|
|
|
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-01-24 18:01:56 +00:00
|
|
|
ty::CoroutineClosure(..) => Err(NoSolution),
|
|
|
|
|
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(_)
|
|
|
|
| ty::RawPtr(_)
|
|
|
|
| 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}`")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a binder of the tupled inputs types, output type, and coroutine type
|
|
|
|
// from a builtin async closure type.
|
|
|
|
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>,
|
|
|
|
) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec<ty::Predicate<'tcx>>), NoSolution>
|
|
|
|
{
|
|
|
|
match *self_ty.kind() {
|
|
|
|
ty::CoroutineClosure(def_id, args) => {
|
|
|
|
let args = args.as_coroutine_closure();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
Ok((
|
|
|
|
args.coroutine_closure_sig().map_bound(|sig| {
|
|
|
|
let coroutine_ty = sig.to_coroutine_given_kind_and_upvars(
|
|
|
|
tcx,
|
|
|
|
args.parent_args(),
|
|
|
|
tcx.coroutine_for_closure(def_id),
|
|
|
|
goal_kind,
|
|
|
|
env_region,
|
|
|
|
args.tupled_upvars_ty(),
|
|
|
|
args.coroutine_captures_by_ref_ty(),
|
|
|
|
);
|
|
|
|
(sig.tupled_inputs_ty, sig.return_ty, coroutine_ty)
|
|
|
|
}),
|
|
|
|
vec![],
|
|
|
|
))
|
|
|
|
} else {
|
2024-01-25 03:50:23 +00:00
|
|
|
let async_fn_kind_trait_def_id =
|
|
|
|
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
2024-01-24 22:27:25 +00:00
|
|
|
let upvars_projection_def_id = tcx
|
2024-01-25 03:50:23 +00:00
|
|
|
.associated_items(async_fn_kind_trait_def_id)
|
|
|
|
.filter_by_name_unhygienic(sym::Upvars)
|
2024-01-24 22:27:25 +00:00
|
|
|
.next()
|
|
|
|
.unwrap()
|
|
|
|
.def_id;
|
|
|
|
Ok((
|
|
|
|
args.coroutine_closure_sig().map_bound(|sig| {
|
|
|
|
let tupled_upvars_ty = Ty::new_projection(
|
|
|
|
tcx,
|
|
|
|
upvars_projection_def_id,
|
|
|
|
[
|
|
|
|
ty::GenericArg::from(kind_ty),
|
|
|
|
Ty::from_closure_kind(tcx, goal_kind).into(),
|
|
|
|
env_region.into(),
|
|
|
|
sig.tupled_inputs_ty.into(),
|
|
|
|
args.tupled_upvars_ty().into(),
|
|
|
|
args.coroutine_captures_by_ref_ty().into(),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
let coroutine_ty = sig.to_coroutine(
|
|
|
|
tcx,
|
|
|
|
args.parent_args(),
|
2024-01-24 23:38:33 +00:00
|
|
|
Ty::from_closure_kind(tcx, goal_kind),
|
2024-01-24 22:27:25 +00:00
|
|
|
tcx.coroutine_for_closure(def_id),
|
|
|
|
tupled_upvars_ty,
|
|
|
|
);
|
|
|
|
(sig.tupled_inputs_ty, sig.return_ty, coroutine_ty)
|
|
|
|
}),
|
|
|
|
vec![
|
|
|
|
ty::TraitRef::new(
|
|
|
|
tcx,
|
2024-01-25 03:50:23 +00:00
|
|
|
async_fn_kind_trait_def_id,
|
2024-01-24 22:27:25 +00:00
|
|
|
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
|
|
|
|
)
|
|
|
|
.to_predicate(tcx),
|
|
|
|
],
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) => Err(NoSolution),
|
|
|
|
|
|
|
|
ty::Bool
|
|
|
|
| ty::Char
|
|
|
|
| ty::Int(_)
|
|
|
|
| ty::Uint(_)
|
|
|
|
| ty::Float(_)
|
|
|
|
| ty::Adt(_, _)
|
|
|
|
| ty::Foreign(_)
|
|
|
|
| ty::Str
|
|
|
|
| ty::Array(_, _)
|
|
|
|
| ty::Slice(_)
|
|
|
|
| ty::RawPtr(_)
|
|
|
|
| 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
|
|
|
|
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,
|
|
|
|
"{} has two substitutions: {} and {}",
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|