Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions crates/hir-ty/src/consteval/tests/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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,
);
Expand Down
5 changes: 0 additions & 5 deletions crates/hir-ty/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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)]
Expand Down
194 changes: 85 additions & 109 deletions crates/hir-ty/src/drop.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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
}
3 changes: 1 addition & 2 deletions crates/hir-ty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
10 changes: 7 additions & 3 deletions crates/hir-ty/src/mir/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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()),
})
}

Expand Down
Loading