diff options
Diffstat (limited to 'compiler/rustc_middle/src/ty/sty.rs')
| -rw-r--r-- | compiler/rustc_middle/src/ty/sty.rs | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ad64745d579..135ade6d684 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -24,6 +24,7 @@ use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi::{self, Abi}; use std::assert_matches::debug_assert_matches; use std::borrow::Cow; +use std::iter; use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; @@ -2316,6 +2317,152 @@ impl<'tcx> Ty<'tcx> { } } + /// Returns the type of the async destructor of this type. + pub fn async_destructor_ty(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Ty<'tcx> { + match *self.kind() { + ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => { + let assoc_items = tcx + .associated_item_def_ids(tcx.require_lang_item(LangItem::AsyncDestruct, None)); + Ty::new_projection(tcx, assoc_items[0], [self]) + } + + ty::Array(elem_ty, _) | ty::Slice(elem_ty) => { + let dtor = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropSlice) + .instantiate(tcx, &[elem_ty.into()]); + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse) + .instantiate(tcx, &[dtor.into()]) + } + + ty::Adt(adt_def, _) if adt_def.is_manually_drop() => { + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropNoop).instantiate_identity() + } + ty::Adt(adt_def, args) if adt_def.is_enum() || adt_def.is_struct() => self + .adt_async_destructor_ty( + tcx, + adt_def.variants().iter().map(|v| v.fields.iter().map(|f| f.ty(tcx, args))), + param_env, + ), + ty::Tuple(tys) => self.adt_async_destructor_ty(tcx, iter::once(tys), param_env), + ty::Closure(_, args) => self.adt_async_destructor_ty( + tcx, + iter::once(args.as_closure().upvar_tys()), + param_env, + ), + ty::CoroutineClosure(_, args) => self.adt_async_destructor_ty( + tcx, + iter::once(args.as_coroutine_closure().upvar_tys()), + param_env, + ), + + ty::Adt(adt_def, _) => { + assert!(adt_def.is_union()); + + match self.surface_async_dropper_ty(tcx, param_env) { + None => Ty::async_destructor_combinator(tcx, LangItem::AsyncDropNoop) + .instantiate_identity(), + Some(surface_drop) => { + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse) + .instantiate(tcx, &[surface_drop.into()]) + } + } + } + + ty::Never + | ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::RawPtr(_, _) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Error(_) => { + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropNoop).instantiate_identity() + } + + ty::Dynamic(..) | ty::CoroutineWitness(..) | ty::Coroutine(..) | ty::Pat(..) => { + bug!("`async_destructor_ty` is not yet implemented for type: {self:?}") + } + + ty::Bound(..) + | ty::Foreign(_) + | ty::Placeholder(_) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("`async_destructor_ty` applied to unexpected type: {self:?}") + } + } + } + + fn adt_async_destructor_ty<I>( + self, + tcx: TyCtxt<'tcx>, + variants: I, + param_env: ParamEnv<'tcx>, + ) -> Ty<'tcx> + where + I: Iterator + ExactSizeIterator, + I::Item: IntoIterator<Item = Ty<'tcx>>, + { + let defer = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropDefer); + let chain = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropChain); + + let noop = + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropNoop).instantiate_identity(); + let either = Ty::async_destructor_combinator(tcx, LangItem::AsyncDropEither); + + let variants_dtor = variants + .into_iter() + .map(|variant| { + variant + .into_iter() + .map(|ty| defer.instantiate(tcx, &[ty.into()])) + .reduce(|acc, next| chain.instantiate(tcx, &[acc.into(), next.into()])) + .unwrap_or(noop) + }) + .reduce(|other, matched| { + either.instantiate(tcx, &[other.into(), matched.into(), self.into()]) + }) + .unwrap_or(noop); + + let dtor = if let Some(dropper_ty) = self.surface_async_dropper_ty(tcx, param_env) { + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropChain) + .instantiate(tcx, &[dropper_ty.into(), variants_dtor.into()]) + } else { + variants_dtor + }; + + Ty::async_destructor_combinator(tcx, LangItem::AsyncDropFuse) + .instantiate(tcx, &[dtor.into()]) + } + + fn surface_async_dropper_ty( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Option<Ty<'tcx>> { + if self.has_surface_async_drop(tcx, param_env) { + Some(LangItem::SurfaceAsyncDropInPlace) + } else if self.has_surface_drop(tcx, param_env) { + Some(LangItem::AsyncDropSurfaceDropInPlace) + } else { + None + } + .map(|dropper| { + Ty::async_destructor_combinator(tcx, dropper).instantiate(tcx, &[self.into()]) + }) + } + + fn async_destructor_combinator( + tcx: TyCtxt<'tcx>, + lang_item: LangItem, + ) -> ty::EarlyBinder<Ty<'tcx>> { + tcx.fn_sig(tcx.require_lang_item(lang_item, None)) + .map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap()) + } + /// Returns the type of metadata for (potentially fat) pointers to this type, /// or the struct tail if the metadata type cannot be determined. pub fn ptr_metadata_ty_or_tail( |
