diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs index c1ac7ae173b8..ee375d60deb8 100644 --- a/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -354,12 +354,43 @@ fn overflowing_add() { fn needs_drop() { check_number( r#" - //- minicore: copy, sized + //- minicore: drop, manually_drop, copy, sized + use core::mem::ManuallyDrop; extern "rust-intrinsic" { pub fn needs_drop() -> bool; } struct X; - const GOAL: bool = !needs_drop::() && needs_drop::(); + struct NeedsDrop; + impl Drop for NeedsDrop { + fn drop(&mut self) {} + } + enum Enum { + A(T), + B(X), + } + const fn val_needs_drop(_v: T) -> bool { needs_drop::() } + const fn closure_needs_drop() -> bool { + let a = NeedsDrop; + let b = X; + !val_needs_drop(|| &a) && val_needs_drop(move || &a) && !val_needs_drop(move || &b) + } + const fn opaque() -> impl Sized { + || {} + } + const fn opaque_copy() -> impl Sized + Copy { + || {} + } + 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::>() && !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::(); "#, 1, ); diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 6b0568266708..76031491d9a0 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -13,6 +13,7 @@ use hir_def::{ ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, TypeAliasId, TypeOrConstParamId, VariantId, }; +use hir_expand::name::Name; use la_arena::ArenaMap; use smallvec::SmallVec; use triomphe::Arc; @@ -20,6 +21,7 @@ use triomphe::Arc; use crate::{ chalk_db, consteval::ConstEvalError, + drop::DropGlue, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, lower::{Diagnostics, GenericDefaults, GenericPredicates}, @@ -28,7 +30,6 @@ use crate::{ Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner, PolyFnSig, Substitution, TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId, }; -use hir_expand::name::Name; #[ra_salsa::query_group(HirDatabaseStorage)] pub trait HirDatabase: DefDatabase + Upcast { @@ -305,6 +306,10 @@ pub trait HirDatabase: DefDatabase + Upcast { block: Option, env: chalk_ir::Environment, ) -> chalk_ir::ProgramClauses; + + #[ra_salsa::invoke(crate::drop::has_drop_glue)] + #[ra_salsa::cycle(crate::drop::has_drop_glue_recover)] + fn has_drop_glue(&self, ty: Ty, env: Arc) -> DropGlue {} } #[test] diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs new file mode 100644 index 000000000000..351926c86c47 --- /dev/null +++ b/crates/hir-ty/src/drop.rs @@ -0,0 +1,209 @@ +//! Utilities for computing drop info about types. + +use base_db::ra_salsa; +use chalk_ir::cast::Cast; +use hir_def::data::adt::StructFlags; +use hir_def::lang_item::LangItem; +use hir_def::AdtId; +use stdx::never; +use triomphe::Arc; + +use crate::{ + db::HirDatabase, method_resolution::TyFingerprint, AliasTy, Canonical, CanonicalVarKinds, + InEnvironment, Interner, ProjectionTy, TraitEnvironment, Ty, TyBuilder, TyKind, +}; +use crate::{ConcreteConst, ConstScalar, ConstValue}; + +fn has_destructor(db: &dyn HirDatabase, adt: AdtId) -> bool { + let module = match adt { + AdtId::EnumId(id) => db.lookup_intern_enum(id).container, + AdtId::StructId(id) => db.lookup_intern_struct(id).container, + AdtId::UnionId(id) => db.lookup_intern_union(id).container, + }; + let Some(drop_trait) = + db.lang_item(module.krate(), LangItem::Drop).and_then(|it| it.as_trait()) + else { + return false; + }; + let impls = match module.containing_block() { + Some(block) => match db.trait_impls_in_block(block) { + Some(it) => it, + None => return false, + }, + None => db.trait_impls_in_crate(module.krate()), + }; + let result = impls.for_trait_and_self_ty(drop_trait, TyFingerprint::Adt(adt)).next().is_some(); + result +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum DropGlue { + // Order of variants is important. + None, + /// May have a drop glue if some type parameter has it. + /// + /// For the compiler this is considered as a positive result, IDE distinguishes this from "yes". + DependOnParams, + HasDropGlue, +} + +pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc) -> DropGlue { + match ty.kind(Interner) { + TyKind::Adt(adt, subst) => { + if has_destructor(db, adt.0) { + return DropGlue::HasDropGlue; + } + match adt.0 { + AdtId::StructId(id) => { + if db.struct_data(id).flags.contains(StructFlags::IS_MANUALLY_DROP) { + return DropGlue::None; + } + db.field_types(id.into()) + .iter() + .map(|(_, field_ty)| { + db.has_drop_glue( + field_ty.clone().substitute(Interner, subst), + env.clone(), + ) + }) + .max() + .unwrap_or(DropGlue::None) + } + // Unions cannot have fields with destructors. + AdtId::UnionId(_) => DropGlue::None, + AdtId::EnumId(id) => db + .enum_data(id) + .variants + .iter() + .map(|&(variant, _)| { + db.field_types(variant.into()) + .iter() + .map(|(_, field_ty)| { + db.has_drop_glue( + field_ty.clone().substitute(Interner, subst), + env.clone(), + ) + }) + .max() + .unwrap_or(DropGlue::None) + }) + .max() + .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())) + .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"); + } + } + } + db.has_drop_glue(ty.clone(), env) + } + TyKind::Slice(ty) => db.has_drop_glue(ty.clone(), env), + TyKind::Closure(closure_id, subst) => { + let owner = db.lookup_intern_closure((*closure_id).into()).0; + let infer = db.infer(owner); + let (captures, _) = infer.closure_info(closure_id); + let env = db.trait_environment_for_body(owner); + captures + .iter() + .map(|capture| db.has_drop_glue(capture.ty(subst), env.clone())) + .max() + .unwrap_or(DropGlue::None) + } + // FIXME: Handle coroutines. + TyKind::Coroutine(..) | TyKind::CoroutineWitness(..) => DropGlue::None, + TyKind::Ref(..) + | TyKind::Raw(..) + | TyKind::FnDef(..) + | TyKind::Str + | TyKind::Never + | TyKind::Scalar(_) + | TyKind::Function(_) + | 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) { + DropGlue::None + } else { + DropGlue::HasDropGlue + } + } + TyKind::Placeholder(_) | TyKind::BoundVar(_) => { + if is_copy(db, ty, env) { + 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 + } + } + _ => db.has_drop_glue(normalized, env), + } +} + +fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc) -> bool { + let Some(copy_trait) = db.lang_item(env.krate, LangItem::Copy).and_then(|it| it.as_trait()) + 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_recover( + _db: &dyn HirDatabase, + _cycle: &ra_salsa::Cycle, + _ty: &Ty, + _env: &Arc, +) -> DropGlue { + DropGlue::None +} diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 3c18ea928165..b7f73deeceef 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -24,6 +24,7 @@ extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis; mod builder; mod chalk_db; mod chalk_ext; +mod drop; mod infer; mod inhabitedness; mod interner; @@ -81,6 +82,7 @@ use crate::{ pub use autoderef::autoderef; pub use builder::{ParamKind, TyBuilder}; pub use chalk_ext::*; +pub use drop::DropGlue; pub use infer::{ cast::CastError, closure::{CaptureKind, CapturedItem}, diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 0a78f4a5b24b..2659c79f203b 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -10,6 +10,7 @@ use hir_def::{ }; use hir_expand::name::Name; use intern::{sym, Symbol}; +use stdx::never; use crate::{ error_lifetime, @@ -19,6 +20,7 @@ use crate::{ LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, Result, Substitution, Ty, TyBuilder, TyExt, }, + DropGlue, }; mod simd; @@ -852,7 +854,14 @@ impl Evaluator<'_> { "size_of generic arg is not provided".into(), )); }; - let result = !ty.clone().is_copy(self.db, locals.body.owner); + let result = match self.db.has_drop_glue(ty.clone(), self.trait_env.clone()) { + DropGlue::HasDropGlue => true, + DropGlue::None => false, + DropGlue::DependOnParams => { + never!("should be fully monomorphized now"); + true + } + }; destination.write_from_bytes(self, &[u8::from(result)]) } "ptr_guaranteed_cmp" => { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index efa88d7c83ee..c880018d7790 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -152,7 +152,7 @@ pub use { layout::LayoutError, method_resolution::TyFingerprint, mir::{MirEvalError, MirLowerError}, - CastError, FnAbi, PointerCast, Safety, Variance, + CastError, DropGlue, FnAbi, PointerCast, Safety, Variance, }, // FIXME: Properly encapsulate mir hir_ty::{mir, Interner as ChalkTyInterner}, @@ -1404,6 +1404,10 @@ impl Struct { Type::from_def(db, self.id) } + pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type { + Type::from_def_placeholders(db, self.id) + } + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { Type::from_value_def(db, self.id) } @@ -1449,6 +1453,10 @@ impl Union { Type::from_def(db, self.id) } + pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type { + Type::from_def_placeholders(db, self.id) + } + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { Type::from_value_def(db, self.id) } @@ -1503,6 +1511,10 @@ impl Enum { Type::from_def(db, self.id) } + pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type { + Type::from_def_placeholders(db, self.id) + } + /// The type of the enum variant bodies. pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type { Type::new_for_crate( @@ -2871,6 +2883,10 @@ impl TypeAlias { Type::from_def(db, self.id) } + pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type { + Type::from_def_placeholders(db, self.id) + } + pub fn name(self, db: &dyn HirDatabase) -> Name { db.type_alias_data(self.id).name.clone() } @@ -4649,6 +4665,19 @@ impl Type { Type::new(db, def, ty.substitute(Interner, &substs)) } + fn from_def_placeholders(db: &dyn HirDatabase, def: impl Into + HasResolver) -> Type { + let ty = db.ty(def.into()); + let substs = TyBuilder::placeholder_subst( + db, + match def.into() { + TyDefId::AdtId(it) => GenericDefId::AdtId(it), + TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), + TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()), + }, + ); + Type::new(db, def, ty.substitute(Interner, &substs)) + } + fn from_value_def(db: &dyn HirDatabase, def: impl Into + HasResolver) -> Type { let Some(ty) = db.value_ty(def.into()) else { return Type::new(db, def, TyKind::Error.intern(Interner)); @@ -5663,6 +5692,10 @@ impl Type { db.layout_of_ty(self.ty.clone(), self.env.clone()) .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap())) } + + pub fn drop_glue(&self, db: &dyn HirDatabase) -> DropGlue { + db.has_drop_glue(self.ty.clone(), self.env.clone()) + } } #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 18a3fed07ece..ba8802f66653 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -38,6 +38,7 @@ pub struct HoverConfig { pub max_fields_count: Option, pub max_enum_variants_count: Option, pub max_subst_ty_len: SubstTyLen, + pub show_drop_glue: bool, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 46242b75dd0b..de2f281aa497 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -3,7 +3,7 @@ use std::{env, mem, ops::Not}; use either::Either; use hir::{ - db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, + db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, DropGlue, DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError, MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, VariantDef, }; @@ -628,6 +628,87 @@ pub(super) fn definition( _ => None, }; + let drop_info = || { + if !config.show_drop_glue { + return None; + } + let drop_info = match def { + Definition::Field(field) => { + DropInfo { drop_glue: field.ty(db).drop_glue(db), has_dtor: None } + } + Definition::Adt(Adt::Struct(strukt)) => { + let struct_drop_glue = strukt.ty_placeholders(db).drop_glue(db); + let mut fields_drop_glue = strukt + .fields(db) + .iter() + .map(|field| field.ty(db).drop_glue(db)) + .max() + .unwrap_or(DropGlue::None); + let has_dtor = match (fields_drop_glue, struct_drop_glue) { + (DropGlue::None, _) => struct_drop_glue != DropGlue::None, + (_, DropGlue::None) => { + // This is `ManuallyDrop`. + fields_drop_glue = DropGlue::None; + false + } + (_, _) => struct_drop_glue > fields_drop_glue, + }; + DropInfo { drop_glue: fields_drop_glue, has_dtor: Some(has_dtor) } + } + // Unions cannot have fields with drop glue. + Definition::Adt(Adt::Union(union)) => DropInfo { + drop_glue: DropGlue::None, + has_dtor: Some(union.ty_placeholders(db).drop_glue(db) != DropGlue::None), + }, + Definition::Adt(Adt::Enum(enum_)) => { + let enum_drop_glue = enum_.ty_placeholders(db).drop_glue(db); + let fields_drop_glue = enum_ + .variants(db) + .iter() + .map(|variant| { + variant + .fields(db) + .iter() + .map(|field| field.ty(db).drop_glue(db)) + .max() + .unwrap_or(DropGlue::None) + }) + .max() + .unwrap_or(DropGlue::None); + DropInfo { + drop_glue: fields_drop_glue, + has_dtor: Some(enum_drop_glue > fields_drop_glue), + } + } + Definition::Variant(variant) => { + let fields_drop_glue = variant + .fields(db) + .iter() + .map(|field| field.ty(db).drop_glue(db)) + .max() + .unwrap_or(DropGlue::None); + DropInfo { drop_glue: fields_drop_glue, has_dtor: None } + } + Definition::TypeAlias(type_alias) => { + DropInfo { drop_glue: type_alias.ty_placeholders(db).drop_glue(db), has_dtor: None } + } + Definition::Local(local) => { + DropInfo { drop_glue: local.ty(db).drop_glue(db), has_dtor: None } + } + _ => return None, + }; + let rendered_drop_glue = match drop_info.drop_glue { + DropGlue::None => "no drop glue", + DropGlue::DependOnParams => "may have drop glue depending on type parameters", + DropGlue::HasDropGlue => "has drop glue", + }; + Some(match drop_info.has_dtor { + Some(true) => format!("{}; has a destructor", rendered_drop_glue), + Some(false) => format!("{}; doesn't have a destructor", rendered_drop_glue), + None => rendered_drop_glue.to_owned(), + }) + }; + let dyn_compatibility_info = || match def { Definition::Trait(it) => { let mut dyn_compatibility_info = String::new(); @@ -660,6 +741,10 @@ pub(super) fn definition( extra.push_str("\n___\n"); extra.push_str(&dyn_compatibility_info); } + if let Some(drop_info) = drop_info() { + extra.push_str("\n___\n"); + extra.push_str(&drop_info); + } } let mut desc = String::new(); desc.push_str(&label); @@ -702,6 +787,12 @@ pub(super) fn definition( ) } +#[derive(Debug)] +struct DropInfo { + drop_glue: DropGlue, + has_dtor: Option, +} + pub(super) fn literal( sema: &Semantics<'_, RootDatabase>, token: SyntaxToken, diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 014b751f95b0..40110ba47b1e 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -21,6 +21,7 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { max_fields_count: Some(5), max_enum_variants_count: Some(5), max_subst_ty_len: super::SubstTyLen::Unlimited, + show_drop_glue: true, }; fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) { @@ -566,6 +567,10 @@ fn main() { --- size = 8, align = 4 + + --- + + no drop glue "#]], ); } @@ -811,6 +816,10 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 } --- size = 1, align = 1, offset = 6 + + --- + + no drop glue "#]], ); } @@ -862,6 +871,10 @@ fn main() { --- size = 4, align = 4, offset = 0 + + --- + + no drop glue "#]], ); } @@ -932,6 +945,10 @@ struct Foo$0(pub u32) where u32: Copy; --- size = 4, align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); } @@ -958,6 +975,10 @@ struct Foo$0 { field: u32 } --- size = 4, align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); check( @@ -983,6 +1004,10 @@ struct Foo$0 where u32: Copy { field: u32 } --- size = 4, align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); } @@ -1012,6 +1037,10 @@ fn hover_record_struct_limit() { --- size = 12 (0xC), align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1035,6 +1064,10 @@ fn hover_record_struct_limit() { --- size = 4, align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1061,6 +1094,10 @@ fn hover_record_struct_limit() { --- size = 16 (0x10), align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1082,6 +1119,10 @@ fn hover_record_struct_limit() { --- size = 12 (0xC), align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1103,6 +1144,10 @@ fn hover_record_struct_limit() { --- size = 12 (0xC), align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); @@ -1126,6 +1171,10 @@ fn hover_record_struct_limit() { --- size = 0, align = 1 + + --- + + no drop glue; doesn't have a destructor "#]], ); } @@ -1151,6 +1200,10 @@ fn hover_record_variant_limit() { --- size = 12 (0xC), align = 4 + + --- + + no drop glue "#]], ); check_hover_fields_limit( @@ -1172,6 +1225,10 @@ fn hover_record_variant_limit() { --- size = 4, align = 4 + + --- + + no drop glue "#]], ); check_hover_fields_limit( @@ -1193,6 +1250,10 @@ fn hover_record_variant_limit() { --- size = 16 (0x10), align = 4 + + --- + + no drop glue "#]], ); check_hover_fields_limit( @@ -1214,6 +1275,10 @@ fn hover_record_variant_limit() { --- size = 12 (0xC), align = 4 + + --- + + no drop glue "#]], ); check_hover_fields_limit( @@ -1235,6 +1300,10 @@ fn hover_record_variant_limit() { --- size = 12 (0xC), align = 4 + + --- + + no drop glue "#]], ); } @@ -1261,6 +1330,10 @@ fn hover_enum_limit() { --- size = 1, align = 1, niches = 254 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_enum_variants_limit( @@ -1283,6 +1356,10 @@ fn hover_enum_limit() { --- size = 1, align = 1, niches = 254 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_enum_variants_limit( @@ -1302,6 +1379,10 @@ fn hover_enum_limit() { --- size = 1, align = 1, niches = 254 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_enum_variants_limit( @@ -1321,6 +1402,10 @@ fn hover_enum_limit() { --- size = 1, align = 1, niches = 254 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_enum_variants_limit( @@ -1358,6 +1443,10 @@ fn hover_enum_limit() { --- size = 12 (0xC), align = 4, niches = 4294967288 + + --- + + no drop glue; doesn't have a destructor "#]], ); } @@ -1384,6 +1473,10 @@ fn hover_union_limit() { --- size = 4, align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1406,6 +1499,10 @@ fn hover_union_limit() { --- size = 4, align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1425,6 +1522,10 @@ fn hover_union_limit() { --- size = 4, align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1444,6 +1545,10 @@ fn hover_union_limit() { --- size = 4, align = 4 + + --- + + no drop glue; doesn't have a destructor "#]], ); } @@ -1470,6 +1575,10 @@ struct Foo$0 where u32: Copy; --- size = 0, align = 1 + + --- + + no drop glue; doesn't have a destructor "#]], ); } @@ -1492,6 +1601,10 @@ type Fo$0o: Trait = S where T: Trait; where T: Trait, ``` + + --- + + no drop glue "#]], ); } @@ -1641,6 +1754,10 @@ fn main() { --- size = 8, align = 4 + + --- + + no drop glue "#]], ); check_hover_range( @@ -1696,6 +1813,10 @@ fn main() { let b$0ar = Some(12); } --- size = 4, align = 4 + + --- + + no drop glue "#]], ); } @@ -1723,6 +1844,10 @@ enum Option { --- + no drop glue + + --- + The None variant "#]], ); @@ -1783,6 +1908,10 @@ fn hover_for_local_variable_pat() { --- size = 4, align = 4 + + --- + + no drop glue "#]], ) } @@ -1815,6 +1944,10 @@ fn hover_for_param_edge() { --- size = 4, align = 4 + + --- + + no drop glue "#]], ) } @@ -1837,6 +1970,10 @@ fn hover_for_param_with_multiple_traits() { ```rust _x: impl Deref + DerefMut ``` + + --- + + may have drop glue depending on type parameters "#]], ) } @@ -1863,6 +2000,10 @@ fn main() { let foo_$0test = Thing::new(); } --- size = 4, align = 4 + + --- + + no drop glue "#]], ) } @@ -2612,6 +2753,10 @@ fn test_hover_function_pointer_show_identifiers() { --- size = 8, align = 8, niches = 1 + + --- + + no drop glue "#]], ); } @@ -2634,6 +2779,10 @@ fn test_hover_function_pointer_no_identifier() { --- size = 8, align = 8, niches = 1 + + --- + + no drop glue "#]], ); } @@ -2880,6 +3029,10 @@ pub struct B$0ar --- + no drop glue; doesn't have a destructor + + --- + [external](https://www.google.com) "#]], ); @@ -2911,6 +3064,10 @@ pub struct B$0ar --- + no drop glue; doesn't have a destructor + + --- + [baz](Baz) "#]], ); @@ -3001,6 +3158,10 @@ fn test_hover_layout_of_variant() { --- size = 4, align = 2 + + --- + + no drop glue "#]], ); } @@ -3022,6 +3183,10 @@ fn test_hover_layout_of_variant_generic() { ```rust None ``` + + --- + + no drop glue "#]], ); } @@ -3047,6 +3212,10 @@ struct S$0(core::marker::PhantomData); --- size = 0, align = 1 + + --- + + no drop glue; doesn't have a destructor "#]], ); } @@ -3075,6 +3244,10 @@ fn test_hover_layout_of_enum() { --- size = 16 (0x10), align = 8, niches = 254 + + --- + + no drop glue; doesn't have a destructor "#]], ); } @@ -3093,6 +3266,10 @@ fn test_hover_no_memory_layout() { ```rust field_a: u8 ``` + + --- + + no drop glue "#]], ); @@ -4401,6 +4578,10 @@ fn main() { --- size = 8, align = 8, niches = 1 + + --- + + no drop glue --- ```rust @@ -4414,6 +4595,10 @@ fn main() { --- size = 4, align = 4, offset = 0 + + --- + + no drop glue "#]], ); } @@ -4439,6 +4624,10 @@ struct S$0T(T); --- size = 0, align = 1 + + --- + + may have drop glue depending on type parameters; doesn't have a destructor "#]], ); } @@ -4464,6 +4653,10 @@ struct S$0T(T); --- size = 0, align = 1 + + --- + + may have drop glue depending on type parameters; doesn't have a destructor "#]], ); } @@ -4490,6 +4683,10 @@ struct S$0T(T); --- size = 0, align = 1 + + --- + + may have drop glue depending on type parameters; doesn't have a destructor "#]], ); } @@ -4514,6 +4711,10 @@ fn main() { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -4538,6 +4739,10 @@ fn main() { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -4562,6 +4767,10 @@ fn main() { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -4586,6 +4795,10 @@ fn main() { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -4610,6 +4823,10 @@ fn main() { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -4633,6 +4850,10 @@ impl Foo { --- size = 8, align = 8, niches = 1 + + --- + + no drop glue "#]], ); } @@ -4657,6 +4878,10 @@ impl Foo { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -5147,6 +5372,10 @@ type Fo$0o2 = Foo<2>; --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -5200,6 +5429,10 @@ enum E { --- + no drop glue + + --- + This is a doc "#]], ); @@ -5229,6 +5462,10 @@ enum E { --- + no drop glue + + --- + This is a doc "#]], ); @@ -5259,6 +5496,10 @@ enum E { --- + no drop glue + + --- + This is a doc "#]], ); @@ -5289,6 +5530,10 @@ enum E { --- + no drop glue + + --- + This is a doc "#]], ); @@ -6217,6 +6462,10 @@ fn main() { --- size = 32 (0x20), align = 4 + + --- + + no drop glue "#]], ); } @@ -7516,6 +7765,10 @@ enum Enum { --- size = 4, align = 4 + + --- + + no drop glue "#]], ); } @@ -7542,6 +7795,10 @@ enum Enum { --- size = 4, align = 4 + + --- + + no drop glue "#]], ); } @@ -8212,6 +8469,10 @@ fn test() { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -8861,6 +9122,10 @@ fn main(notable$0: u32) {} --- size = 4, align = 4 + + --- + + no drop glue "#]], ); } @@ -8953,6 +9218,10 @@ extern "C" { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -9099,6 +9368,10 @@ struct Pedro$0<'a> { --- size = 16 (0x10), align = 8, niches = 1 + + --- + + no drop glue; doesn't have a destructor "#]], ) } @@ -9116,6 +9389,10 @@ fn main(a$0: impl T) {} ```rust a: impl T + ?Sized ``` + + --- + + may have drop glue depending on type parameters "#]], ); } @@ -9137,6 +9414,10 @@ fn main(a$0: T) {} --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -9190,6 +9471,10 @@ fn main() { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -9527,6 +9812,10 @@ type A$0 = B; --- + no drop glue + + --- + *This is the documentation for* `struct B` Docs for B @@ -9560,6 +9849,10 @@ type A$0 = B; --- + no drop glue + + --- + *This is the documentation for* `struct C` Docs for C @@ -9594,6 +9887,10 @@ type A$0 = B; --- + no drop glue + + --- + *This is the documentation for* `struct C` Docs for C @@ -9623,6 +9920,10 @@ type A$0 = B; --- size = 0, align = 1 + + --- + + no drop glue "#]], ); @@ -9747,6 +10048,10 @@ fn main() { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); @@ -9775,6 +10080,10 @@ fn main() { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); @@ -9810,6 +10119,10 @@ fn main() { --- size = 0, align = 1 + + --- + + no drop glue "#]], ); } @@ -10128,6 +10441,10 @@ fn bar() { --- size = 4, align = 4 + + --- + + no drop glue --- ```rust @@ -10140,6 +10457,10 @@ fn bar() { --- + may have drop glue depending on type parameters + + --- + `T` = `i32` "#]], ); @@ -10349,3 +10670,276 @@ macro_rules! str { "#]], ); } + +#[test] +fn drop_glue() { + check( + r#" +struct NoDrop$0; + "#, + expect![[r#" + *NoDrop* + + ```rust + ra_test_fixture + ``` + + ```rust + struct NoDrop + ``` + + --- + + size = 0, align = 1 + + --- + + no drop glue; doesn't have a destructor + "#]], + ); + check( + r#" +//- minicore: drop +struct NeedsDrop$0; +impl Drop for NeedsDrop { + fn drop(&mut self) {} +} + "#, + expect![[r#" + *NeedsDrop* + + ```rust + ra_test_fixture + ``` + + ```rust + struct NeedsDrop + ``` + + --- + + size = 0, align = 1 + + --- + + no drop glue; has a destructor + "#]], + ); + check( + r#" +//- minicore: manually_drop, drop +struct NeedsDrop; +impl Drop for NeedsDrop { + fn drop(&mut self) {} +} +type NoDrop$0 = core::mem::ManuallyDrop; + "#, + expect![[r#" + *NoDrop* + + ```rust + ra_test_fixture + ``` + + ```rust + type NoDrop = core::mem::ManuallyDrop + ``` + + --- + + size = 0, align = 1 + + --- + + no drop glue + "#]], + ); + check( + r#" +//- minicore: drop +struct NeedsDrop; +impl Drop for NeedsDrop { + fn drop(&mut self) {} +} +struct DropField$0 { + _x: i32, + _y: NeedsDrop, +} + "#, + expect![[r#" + *DropField* + + ```rust + ra_test_fixture + ``` + + ```rust + struct DropField { + _x: i32, + _y: NeedsDrop, + } + ``` + + --- + + size = 4, align = 4 + + --- + + has drop glue; doesn't have a destructor + "#]], + ); + check( + r#" +//- minicore: sized +type Foo$0 = impl Sized; + "#, + expect![[r#" + *Foo* + + ```rust + ra_test_fixture + ``` + + ```rust + type Foo = impl Sized + ``` + + --- + + has drop glue + "#]], + ); + check( + r#" +//- minicore: drop +struct NeedsDrop; +impl Drop for NeedsDrop { + fn drop(&mut self) {} +} +enum Enum { + A$0(&'static str), + B(NeedsDrop) +} + "#, + expect![[r#" + *A* + + ```rust + ra_test_fixture::Enum + ``` + + ```rust + A(&'static str) + ``` + + --- + + size = 16 (0x10), align = 8, niches = 1 + + --- + + no drop glue + "#]], + ); + check( + r#" +struct Foo$0(T); + "#, + expect![[r#" + *Foo* + + ```rust + ra_test_fixture + ``` + + ```rust + struct Foo(T) + ``` + + --- + + may have drop glue depending on type parameters; doesn't have a destructor + "#]], + ); + check( + r#" +//- minicore: copy +struct Foo$0(T); + "#, + expect![[r#" + *Foo* + + ```rust + ra_test_fixture + ``` + + ```rust + struct Foo(T) + where + T: Copy, + ``` + + --- + + no drop glue; doesn't have a destructor + "#]], + ); + check( + r#" +//- minicore: copy +trait Trait { + type Assoc: Copy; +} +struct Foo$0(T::Assoc); + "#, + expect![[r#" + *Foo* + + ```rust + ra_test_fixture + ``` + + ```rust + struct Foo(::Assoc) + where + T: Trait, + ``` + + --- + + no drop glue; doesn't have a destructor + "#]], + ); + check( + r#" +#[rustc_coherence_is_core] + +#[lang = "manually_drop"] +#[repr(transparent)] +pub struct ManuallyDrop$0 { + value: T, +} + "#, + expect![[r#" + *ManuallyDrop* + + ```rust + ra_test_fixture + ``` + + ```rust + pub struct ManuallyDrop + where + T: ?Sized, + { + value: T, + } + ``` + + --- + + no drop glue; doesn't have a destructor + "#]], + ); +} diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 8050a38b3ca1..be204563ccc0 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -186,6 +186,7 @@ impl StaticIndex<'_> { max_fields_count: Some(5), max_enum_variants_count: Some(5), max_subst_ty_len: SubstTyLen::Unlimited, + show_drop_glue: true, }; let tokens = tokens.filter(|token| { matches!( diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 3dc4379258fa..47186d4c9749 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -128,6 +128,8 @@ config_data! { /// Whether to show keyword hover popups. Only applies when /// `#rust-analyzer.hover.documentation.enable#` is set. hover_documentation_keywords_enable: bool = true, + /// Whether to show drop glue information on hover. + hover_dropGlue_enable: bool = true, /// Use markdown syntax for links on hover. hover_links_enable: bool = true, /// Whether to show what types are used as generic arguments in calls etc. on hover, and what is their max length to show such types, beyond it they will be shown with ellipsis. @@ -1622,6 +1624,7 @@ impl Config { Some(MaxSubstitutionLength::Limit(limit)) => ide::SubstTyLen::LimitTo(*limit), None => ide::SubstTyLen::Unlimited, }, + show_drop_glue: *self.hover_dropGlue_enable(), } } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index bd091db58d3f..5716cebbf859 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -546,6 +546,11 @@ Whether to show documentation on hover. Whether to show keyword hover popups. Only applies when `#rust-analyzer.hover.documentation.enable#` is set. -- +[[rust-analyzer.hover.dropGlue.enable]]rust-analyzer.hover.dropGlue.enable (default: `true`):: ++ +-- +Whether to show drop glue information on hover. +-- [[rust-analyzer.hover.links.enable]]rust-analyzer.hover.links.enable (default: `true`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index 8b066377f2b2..4e7f4fa87a44 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1617,6 +1617,16 @@ } } }, + { + "title": "hover", + "properties": { + "rust-analyzer.hover.dropGlue.enable": { + "markdownDescription": "Whether to show drop glue information on hover.", + "default": true, + "type": "boolean" + } + } + }, { "title": "hover", "properties": {