Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/drop.rs')
| -rw-r--r-- | crates/hir-ty/src/drop.rs | 180 |
1 files changed, 86 insertions, 94 deletions
diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs index 5577be890d..b09d1fb196 100644 --- a/crates/hir-ty/src/drop.rs +++ b/crates/hir-ty/src/drop.rs @@ -1,16 +1,20 @@ //! Utilities for computing drop info about types. -use chalk_ir::cast::Cast; -use hir_def::AdtId; -use hir_def::lang_item::LangItem; -use hir_def::signatures::StructFlags; +use hir_def::{AdtId, lang_item::LangItem, signatures::StructFlags}; +use rustc_hash::FxHashSet; +use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike}; use stdx::never; use triomphe::Arc; use crate::{ - AliasTy, Canonical, CanonicalVarKinds, ConcreteConst, ConstScalar, ConstValue, InEnvironment, - Interner, ProjectionTy, TraitEnvironment, Ty, TyBuilder, TyKind, db::HirDatabase, + TraitEnvironment, consteval, + db::HirDatabase, method_resolution::TyFingerprint, + next_solver::{ + Ty, TyKind, + infer::{InferCtxt, traits::ObligationCause}, + obligation_ctxt::ObligationCtxt, + }, }; fn has_destructor(db: &dyn HirDatabase, adt: AdtId) -> bool { @@ -43,23 +47,52 @@ pub enum DropGlue { HasDropGlue, } -pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment>) -> DropGlue { - match ty.kind(Interner) { - TyKind::Adt(adt, subst) => { - if has_destructor(db, adt.0) { +pub fn has_drop_glue<'db>( + infcx: &InferCtxt<'db>, + ty: Ty<'db>, + env: Arc<TraitEnvironment<'db>>, +) -> DropGlue { + has_drop_glue_impl(infcx, ty, env, &mut FxHashSet::default()) +} + +fn has_drop_glue_impl<'db>( + infcx: &InferCtxt<'db>, + ty: Ty<'db>, + env: Arc<TraitEnvironment<'db>>, + visited: &mut FxHashSet<Ty<'db>>, +) -> DropGlue { + let mut ocx = ObligationCtxt::new(infcx); + let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty); + + if !visited.insert(ty) { + // Recursive type. + return DropGlue::None; + } + + let db = infcx.interner.db; + match ty.kind() { + TyKind::Adt(adt_def, subst) => { + let adt_id = adt_def.def_id().0; + if has_destructor(db, adt_id) { return DropGlue::HasDropGlue; } - match adt.0 { + match adt_id { AdtId::StructId(id) => { - if db.struct_signature(id).flags.contains(StructFlags::IS_MANUALLY_DROP) { + if db + .struct_signature(id) + .flags + .intersects(StructFlags::IS_MANUALLY_DROP | StructFlags::IS_PHANTOM_DATA) + { return DropGlue::None; } db.field_types(id.into()) .iter() .map(|(_, field_ty)| { - db.has_drop_glue( - field_ty.clone().substitute(Interner, subst), + has_drop_glue_impl( + infcx, + field_ty.instantiate(infcx.interner, subst), env.clone(), + visited, ) }) .max() @@ -75,9 +108,11 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm db.field_types(variant.into()) .iter() .map(|(_, field_ty)| { - db.has_drop_glue( - field_ty.clone().substitute(Interner, subst), + has_drop_glue_impl( + infcx, + field_ty.instantiate(infcx.interner, subst), env.clone(), + visited, ) }) .max() @@ -87,113 +122,70 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm .unwrap_or(DropGlue::None), } } - TyKind::Tuple(_, subst) => subst - .iter(Interner) - .map(|ty| ty.assert_ty_ref(Interner)) - .map(|ty| db.has_drop_glue(ty.clone(), env.clone())) + TyKind::Tuple(tys) => tys + .iter() + .map(|ty| has_drop_glue_impl(infcx, ty, env.clone(), visited)) .max() .unwrap_or(DropGlue::None), TyKind::Array(ty, len) => { - if let ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Bytes(len, _) }) = - &len.data(Interner).value - { - match (&**len).try_into() { - Ok(len) => { - let len = usize::from_le_bytes(len); - if len == 0 { - // Arrays of size 0 don't have drop glue. - return DropGlue::None; - } - } - Err(_) => { - never!("const array size with non-usize len"); - } - } + if consteval::try_const_usize(db, len) == Some(0) { + // Arrays of size 0 don't have drop glue. + return DropGlue::None; } - db.has_drop_glue(ty.clone(), env) + has_drop_glue_impl(infcx, ty, env, visited) } - TyKind::Slice(ty) => db.has_drop_glue(ty.clone(), env), + TyKind::Slice(ty) => has_drop_glue_impl(infcx, ty, env, visited), TyKind::Closure(closure_id, subst) => { - let owner = db.lookup_intern_closure((*closure_id).into()).0; + let owner = db.lookup_intern_closure(closure_id.0).0; let infer = db.infer(owner); - let (captures, _) = infer.closure_info(closure_id); + let (captures, _) = infer.closure_info(closure_id.0); let env = db.trait_environment_for_body(owner); captures .iter() - .map(|capture| db.has_drop_glue(capture.ty(subst), env.clone())) + .map(|capture| { + has_drop_glue_impl(infcx, capture.ty(db, subst), env.clone(), visited) + }) .max() .unwrap_or(DropGlue::None) } // FIXME: Handle coroutines. - TyKind::Coroutine(..) | TyKind::CoroutineWitness(..) => DropGlue::None, + TyKind::Coroutine(..) | TyKind::CoroutineWitness(..) | TyKind::CoroutineClosure(..) => { + DropGlue::None + } TyKind::Ref(..) - | TyKind::Raw(..) + | TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::Str | TyKind::Never - | TyKind::Scalar(_) - | TyKind::Function(_) + | TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::FnPtr(..) | TyKind::Foreign(_) - | TyKind::Error => DropGlue::None, - TyKind::Dyn(_) => DropGlue::HasDropGlue, - TyKind::AssociatedType(assoc_type_id, subst) => projection_has_drop_glue( - db, - env, - ProjectionTy { associated_ty_id: *assoc_type_id, substitution: subst.clone() }, - ty, - ), - TyKind::Alias(AliasTy::Projection(projection)) => { - projection_has_drop_glue(db, env, projection.clone(), ty) - } - TyKind::OpaqueType(..) | TyKind::Alias(AliasTy::Opaque(_)) => { - if is_copy(db, ty, env) { + | TyKind::Error(_) + | TyKind::Bound(..) + | TyKind::Placeholder(..) => DropGlue::None, + TyKind::Dynamic(..) => DropGlue::HasDropGlue, + TyKind::Alias(..) => { + if infcx.type_is_copy_modulo_regions(env.env, ty) { DropGlue::None } else { DropGlue::HasDropGlue } } - TyKind::Placeholder(_) | TyKind::BoundVar(_) => { - if is_copy(db, ty, env) { + TyKind::Param(_) => { + if infcx.type_is_copy_modulo_regions(env.env, ty) { DropGlue::None } else { DropGlue::DependOnParams } } - TyKind::InferenceVar(..) => unreachable!("inference vars shouldn't exist out of inference"), - } -} - -fn projection_has_drop_glue( - db: &dyn HirDatabase, - env: Arc<TraitEnvironment>, - projection: ProjectionTy, - ty: Ty, -) -> DropGlue { - let normalized = db.normalize_projection(projection, env.clone()); - match normalized.kind(Interner) { - TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(..) => { - if is_copy(db, ty, env) { DropGlue::None } else { DropGlue::DependOnParams } + TyKind::Infer(..) => unreachable!("inference vars shouldn't exist out of inference"), + TyKind::Pat(..) | TyKind::UnsafeBinder(..) => { + never!("we do not handle pattern and unsafe binder types"); + DropGlue::None } - _ => db.has_drop_glue(normalized, env), } } - -fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment>) -> bool { - let Some(copy_trait) = LangItem::Copy.resolve_trait(db, env.krate) else { - return false; - }; - let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(ty).build(); - let goal = Canonical { - value: InEnvironment::new(&env.env, trait_ref.cast(Interner)), - binders: CanonicalVarKinds::empty(Interner), - }; - db.trait_solve(env.krate, env.block, goal).is_some() -} - -pub(crate) fn has_drop_glue_cycle_result( - _db: &dyn HirDatabase, - _ty: Ty, - _env: Arc<TraitEnvironment>, -) -> DropGlue { - DropGlue::None -} |