Merge pull request #20785 from ChayimFriedman2/drop-glue

internal: Migrate drop glue handling to new solver
This commit is contained in:
Chayim Refael Friedman 2025-10-08 13:24:17 +00:00 committed by GitHub
commit 0580059e43
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 113 additions and 128 deletions

View file

@ -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<T: ?Sized>() -> bool;
}
@ -380,17 +381,19 @@ fn needs_drop() {
const fn opaque_copy() -> impl Sized + Copy {
|| {}
}
struct RecursiveType(RecursiveType);
trait Everything {}
impl<T> Everything for T {}
const GOAL: bool = !needs_drop::<i32>() && !needs_drop::<X>()
&& needs_drop::<NeedsDrop>() && !needs_drop::<ManuallyDrop<NeedsDrop>>()
&& needs_drop::<[NeedsDrop; 1]>() && !needs_drop::<[NeedsDrop; 0]>()
&& needs_drop::<(X, NeedsDrop)>()
&& needs_drop::<(X, NeedsDrop)>() && !needs_drop::<PhantomData<NeedsDrop>>()
&& needs_drop::<Enum<NeedsDrop>>() && !needs_drop::<Enum<X>>()
&& closure_needs_drop()
&& !val_needs_drop(opaque()) && !val_needs_drop(opaque_copy())
&& needs_drop::<[NeedsDrop]>() && needs_drop::<dyn Everything>()
&& !needs_drop::<&dyn Everything>() && !needs_drop::<str>();
&& !needs_drop::<&dyn Everything>() && !needs_drop::<str>()
&& !needs_drop::<RecursiveType>();
"#,
1,
);

View file

@ -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<crate::InEnvironment<crate::Goal>>,
) -> 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<TraitEnvironment<'_>>) -> DropGlue;
// next trait solver
#[salsa::invoke(crate::lower_nextsolver::const_param_ty_query)]

View file

@ -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<TraitEnvironment<'_>>,
pub fn has_drop_glue<'db>(
infcx: &InferCtxt<'db>,
ty: Ty<'db>,
env: Arc<TraitEnvironment<'db>>,
) -> 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<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())
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<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.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<TraitEnvironment<'_>>,
) -> DropGlue {
DropGlue::None
}

View file

@ -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,

View file

@ -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()),
})
}

View file

@ -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 => {

View file

@ -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())
}
}