diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs index 5e85978e2990..10282d21168a 100644 --- a/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -354,8 +354,9 @@ fn overflowing_add() { fn needs_drop() { check_number( r#" - //- minicore: drop, manually_drop, copy, sized + //- minicore: drop, manually_drop, copy, sized, phantom_data use core::mem::ManuallyDrop; + use core::marker::PhantomData; extern "rust-intrinsic" { pub fn needs_drop() -> bool; } @@ -380,17 +381,19 @@ fn needs_drop() { const fn opaque_copy() -> impl Sized + Copy { || {} } + struct RecursiveType(RecursiveType); trait Everything {} impl Everything for T {} const GOAL: bool = !needs_drop::() && !needs_drop::() && needs_drop::() && !needs_drop::>() && needs_drop::<[NeedsDrop; 1]>() && !needs_drop::<[NeedsDrop; 0]>() - && needs_drop::<(X, NeedsDrop)>() + && needs_drop::<(X, NeedsDrop)>() && !needs_drop::>() && needs_drop::>() && !needs_drop::>() && closure_needs_drop() && !val_needs_drop(opaque()) && !val_needs_drop(opaque_copy()) && needs_drop::<[NeedsDrop]>() && needs_drop::() - && !needs_drop::<&dyn Everything>() && !needs_drop::(); + && !needs_drop::<&dyn Everything>() && !needs_drop::() + && !needs_drop::(); "#, 1, ); diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 82d17cc618cd..11d3be5c3c48 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -19,7 +19,6 @@ use crate::{ Binders, Const, ImplTraitId, ImplTraits, InferenceResult, Substitution, TraitEnvironment, Ty, TyDefId, ValueTyDefId, chalk_db, consteval::ConstEvalError, - drop::DropGlue, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, lower::{Diagnostics, GenericDefaults, GenericPredicates}, @@ -334,10 +333,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { goal: crate::Canonical>, ) -> NextTraitSolveResult; - #[salsa::invoke(crate::drop::has_drop_glue)] - #[salsa::cycle(cycle_result = crate::drop::has_drop_glue_cycle_result)] - fn has_drop_glue(&self, ty: Ty, env: Arc>) -> DropGlue; - // next trait solver #[salsa::invoke(crate::lower_nextsolver::const_param_ty_query)] diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs index 0618fd17d55d..4bd9691ea079 100644 --- a/crates/hir-ty/src/drop.rs +++ b/crates/hir-ty/src/drop.rs @@ -1,18 +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::next_solver::DbInterner; -use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; use crate::{ - AliasTy, Canonical, CanonicalVarKinds, ConcreteConst, ConstScalar, ConstValue, InEnvironment, - Interner, ProjectionTy, TraitEnvironment, Ty, TyBuilder, TyKind, db::HirDatabase, + TraitEnvironment, consteval_nextsolver, + 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 { @@ -45,27 +47,52 @@ pub enum DropGlue { HasDropGlue, } -pub(crate) fn has_drop_glue( - db: &dyn HirDatabase, - ty: Ty, - env: Arc>, +pub fn has_drop_glue<'db>( + infcx: &InferCtxt<'db>, + ty: Ty<'db>, + env: Arc>, ) -> DropGlue { - match ty.kind(Interner) { - TyKind::Adt(adt, subst) => { - if has_destructor(db, adt.0) { + has_drop_glue_impl(infcx, ty, env, &mut FxHashSet::default()) +} + +fn has_drop_glue_impl<'db>( + infcx: &InferCtxt<'db>, + ty: Ty<'db>, + env: Arc>, + visited: &mut FxHashSet>, +) -> 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()) + db.field_types_ns(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() @@ -78,12 +105,14 @@ pub(crate) fn has_drop_glue( .variants .iter() .map(|&(variant, _, _)| { - db.field_types(variant.into()) + db.field_types_ns(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() @@ -93,123 +122,70 @@ pub(crate) fn has_drop_glue( .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_nextsolver::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 closure_id = (*closure_id).into(); - let owner = db.lookup_intern_closure(closure_id).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); - let interner = DbInterner::conjure(); captures .iter() .map(|capture| { - db.has_drop_glue( - capture.ty(db, subst.to_nextsolver(interner)).to_chalk(interner), - env.clone(), - ) + 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>, - 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>) -> 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.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), - trait_ref.cast(Interner), - ), - binders: CanonicalVarKinds::empty(Interner), - }; - db.trait_solve(env.krate, env.block, goal).certain() -} - -pub(crate) fn has_drop_glue_cycle_result( - _db: &dyn HirDatabase, - _ty: Ty, - _env: Arc>, -) -> DropGlue { - DropGlue::None -} diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 2add66d02d23..4ff5cc5588bf 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -24,7 +24,6 @@ extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; mod builder; mod chalk_db; mod chalk_ext; -mod drop; mod infer; mod inhabitedness; mod interner; @@ -42,6 +41,7 @@ pub mod consteval_nextsolver; pub mod db; pub mod diagnostics; pub mod display; +pub mod drop; pub mod dyn_compatibility; pub mod generics; pub mod lang_items; @@ -94,7 +94,6 @@ use crate::{ pub use autoderef::autoderef; pub use builder::{ParamKind, TyBuilder}; pub use chalk_ext::*; -pub use drop::DropGlue; pub use infer::{ Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult, InferenceTyDiagnosticSource, OverloadedDeref, PointerCast, diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index e1983b37472c..6e09cf9aeb88 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -32,7 +32,6 @@ use stdx::never; use syntax::{SyntaxNodePtr, TextRange}; use triomphe::Arc; -use crate::next_solver::mapping::NextSolverToChalk; use crate::{ AliasTy, CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, Interner, MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, @@ -44,8 +43,11 @@ use crate::{ layout::{Layout, LayoutError, RustcEnumVariantIdx}, method_resolution::{is_dyn_method, lookup_impl_const}, next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, convert_args_for_result, convert_ty_for_result}, + DbInterner, TypingMode, + infer::{DbInternerInferExt, InferCtxt}, + mapping::{ + ChalkToNextSolver, NextSolverToChalk, convert_args_for_result, convert_ty_for_result, + }, }, static_lifetime, traits::FnTrait, @@ -204,6 +206,7 @@ pub struct Evaluator<'a> { /// Maximum count of bytes that heap and stack can grow memory_limit: usize, interner: DbInterner<'a>, + infcx: InferCtxt<'a>, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -690,6 +693,7 @@ impl<'db> Evaluator<'db> { x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call_once)) }), interner, + infcx: interner.infer_ctxt().build(TypingMode::non_body_analysis()), }) } diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 54d13a8d3d73..9ef0012a89c1 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -16,8 +16,8 @@ use stdx::never; use crate::next_solver::mapping::NextSolverToChalk; use crate::{ - DropGlue, display::DisplayTarget, + drop::{DropGlue, has_drop_glue}, error_lifetime, mir::eval::{ Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, HasModule, HirDisplay, @@ -855,7 +855,11 @@ impl<'db> Evaluator<'db> { "size_of generic arg is not provided".into(), )); }; - let result = match self.db.has_drop_glue(ty.clone(), self.trait_env.clone()) { + let result = match has_drop_glue( + &self.infcx, + ty.to_nextsolver(self.interner), + self.trait_env.clone(), + ) { DropGlue::HasDropGlue => true, DropGlue::None => false, DropGlue::DependOnParams => { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index ae52986008f1..cce2564a9e6d 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -82,8 +82,8 @@ use hir_ty::{ method_resolution, mir::{MutBorrowKind, interpret_mir}, next_solver::{ - ClauseKind, DbInterner, GenericArgs, - infer::InferCtxt, + ClauseKind, DbInterner, GenericArgs, TypingMode, + infer::{DbInternerInferExt, InferCtxt}, mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result}, }, primitive::UintTy, @@ -157,10 +157,11 @@ pub use { tt, }, hir_ty::{ - CastError, DropGlue, FnAbi, PointerCast, Variance, attach_db, attach_db_allow_change, + CastError, FnAbi, PointerCast, Variance, attach_db, attach_db_allow_change, consteval::ConstEvalError, diagnostics::UnsafetyReason, display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite}, + drop::DropGlue, dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode}, layout::LayoutError, method_resolution::TyFingerprint, @@ -6043,7 +6044,10 @@ impl<'db> Type<'db> { } pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue { - db.has_drop_glue(self.ty.clone(), self.env.clone()) + let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block); + // FIXME: This should be `PostAnalysis` I believe. + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + hir_ty::drop::has_drop_glue(&infcx, self.ty.to_nextsolver(interner), self.env.clone()) } }