From 100e166bb16d1e8c2a2aaff243c56a5cecbf884c Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 20 Jan 2025 19:48:55 +0200 Subject: [PATCH] Calculate drop glue and show it on hover Also fix the `needs_drop()` intrinsic. Unions also need this information (to err if they have a drop-needing field), but this will come in a follow-up PR. --- .../hir-ty/src/consteval/tests/intrinsics.rs | 35 +- crates/hir-ty/src/db.rs | 7 +- crates/hir-ty/src/drop.rs | 209 ++++++ crates/hir-ty/src/lib.rs | 2 + crates/hir-ty/src/mir/eval/shim.rs | 11 +- crates/hir/src/lib.rs | 35 +- crates/ide/src/hover.rs | 1 + crates/ide/src/hover/render.rs | 95 ++- crates/ide/src/hover/tests.rs | 594 ++++++++++++++++++ crates/ide/src/static_index.rs | 1 + crates/rust-analyzer/src/config.rs | 3 + docs/book/src/configuration_generated.md | 5 + editors/code/package.json | 10 + 13 files changed, 1002 insertions(+), 6 deletions(-) create mode 100644 crates/hir-ty/src/drop.rs 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 55d81875a2be..748016f7ceda 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 38b189a517f2..7d3376f56be1 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -11,6 +11,7 @@ use hir_def::{ }; use hir_expand::name::Name; use intern::{sym, Symbol}; +use stdx::never; use crate::{ error_lifetime, @@ -20,6 +21,7 @@ use crate::{ LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, Result, Substitution, Ty, TyBuilder, TyExt, }, + DropGlue, }; mod simd; @@ -853,7 +855,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 5923a1bc30ea..727d31cffb51 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}, @@ -1391,6 +1391,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) } @@ -1436,6 +1440,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) } @@ -1490,6 +1498,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( @@ -2929,6 +2941,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() } @@ -4708,6 +4724,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)); @@ -5737,6 +5766,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 95a720e7e452..9a3e77f3a932 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 c996230c3a1f..c5a83e58cea1 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, }; @@ -629,6 +629,89 @@ 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 => "does not contain types with destructors (drop glue)", + DropGlue::DependOnParams => { + "may contain types with destructors (drop glue) depending on type parameters" + } + DropGlue::HasDropGlue => "contain types with destructors (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(); @@ -661,6 +744,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); @@ -703,6 +790,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 8c32cc9720af..7c720d97cb6d 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) { @@ -567,6 +568,10 @@ fn main() { --- size = 8, align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -812,6 +817,10 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 } --- size = 1, align = 1, offset = 6 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -863,6 +872,10 @@ fn main() { --- size = 4, align = 4, offset = 0 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -933,6 +946,10 @@ struct Foo$0(pub u32) where u32: Copy; --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); } @@ -959,6 +976,10 @@ struct Foo$0 { field: u32 } --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check( @@ -984,6 +1005,10 @@ struct Foo$0 where u32: Copy { field: u32 } --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); } @@ -1013,6 +1038,10 @@ fn hover_record_struct_limit() { --- size = 12 (0xC), align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1036,6 +1065,10 @@ fn hover_record_struct_limit() { --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1062,6 +1095,10 @@ fn hover_record_struct_limit() { --- size = 16 (0x10), align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1083,6 +1120,10 @@ fn hover_record_struct_limit() { --- size = 12 (0xC), align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1104,6 +1145,10 @@ fn hover_record_struct_limit() { --- size = 12 (0xC), align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); @@ -1127,6 +1172,10 @@ fn hover_record_struct_limit() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); } @@ -1152,6 +1201,10 @@ fn hover_record_variant_limit() { --- size = 12 (0xC), align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); check_hover_fields_limit( @@ -1173,6 +1226,10 @@ fn hover_record_variant_limit() { --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); check_hover_fields_limit( @@ -1194,6 +1251,10 @@ fn hover_record_variant_limit() { --- size = 16 (0x10), align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); check_hover_fields_limit( @@ -1215,6 +1276,10 @@ fn hover_record_variant_limit() { --- size = 12 (0xC), align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); check_hover_fields_limit( @@ -1236,6 +1301,10 @@ fn hover_record_variant_limit() { --- size = 12 (0xC), align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -1262,6 +1331,10 @@ fn hover_enum_limit() { --- size = 1, align = 1, niches = 254 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_enum_variants_limit( @@ -1284,6 +1357,10 @@ fn hover_enum_limit() { --- size = 1, align = 1, niches = 254 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_enum_variants_limit( @@ -1303,6 +1380,10 @@ fn hover_enum_limit() { --- size = 1, align = 1, niches = 254 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_enum_variants_limit( @@ -1322,6 +1403,10 @@ fn hover_enum_limit() { --- size = 1, align = 1, niches = 254 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_enum_variants_limit( @@ -1359,6 +1444,10 @@ fn hover_enum_limit() { --- size = 12 (0xC), align = 4, niches = a lot + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); } @@ -1385,6 +1474,10 @@ fn hover_union_limit() { --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1407,6 +1500,10 @@ fn hover_union_limit() { --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1426,6 +1523,10 @@ fn hover_union_limit() { --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); check_hover_fields_limit( @@ -1445,6 +1546,10 @@ fn hover_union_limit() { --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); } @@ -1471,6 +1576,10 @@ struct Foo$0 where u32: Copy; --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); } @@ -1493,6 +1602,10 @@ type Fo$0o: Trait = S where T: Trait; where T: Trait, ``` + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -1642,6 +1755,10 @@ fn main() { --- size = 8, align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); check_hover_range( @@ -1697,6 +1814,10 @@ fn main() { let b$0ar = Some(12); } --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -1724,6 +1845,10 @@ enum Option { --- + does not contain types with destructors (drop glue) + + --- + The None variant "#]], ); @@ -1784,6 +1909,10 @@ fn hover_for_local_variable_pat() { --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ) } @@ -1816,6 +1945,10 @@ fn hover_for_param_edge() { --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ) } @@ -1838,6 +1971,10 @@ fn hover_for_param_with_multiple_traits() { ```rust _x: impl Deref + DerefMut ``` + + --- + + may contain types with destructors (drop glue) depending on type parameters "#]], ) } @@ -1864,6 +2001,10 @@ fn main() { let foo_$0test = Thing::new(); } --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ) } @@ -2613,6 +2754,10 @@ fn test_hover_function_pointer_show_identifiers() { --- size = 8, align = 8, niches = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -2635,6 +2780,10 @@ fn test_hover_function_pointer_no_identifier() { --- size = 8, align = 8, niches = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -2881,6 +3030,10 @@ pub struct B$0ar --- + does not contain types with destructors (drop glue); doesn't have a destructor + + --- + [external](https://www.google.com) "#]], ); @@ -2912,6 +3065,10 @@ pub struct B$0ar --- + does not contain types with destructors (drop glue); doesn't have a destructor + + --- + [baz](Baz) "#]], ); @@ -3002,6 +3159,10 @@ fn test_hover_layout_of_variant() { --- size = 4, align = 2 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -3023,6 +3184,10 @@ fn test_hover_layout_of_variant_generic() { ```rust None ``` + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -3048,6 +3213,10 @@ struct S$0(core::marker::PhantomData); --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); } @@ -3076,6 +3245,10 @@ fn test_hover_layout_of_enum() { --- size = 16 (0x10), align = 8, niches = 254 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ); } @@ -3094,6 +3267,10 @@ fn test_hover_no_memory_layout() { ```rust field_a: u8 ``` + + --- + + does not contain types with destructors (drop glue) "#]], ); @@ -4405,6 +4582,10 @@ fn main() { --- + does not contain types with destructors (drop glue) + + --- + ```rust ra_test_fixture::S ``` @@ -4416,6 +4597,10 @@ fn main() { --- size = 4, align = 4, offset = 0 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -4441,6 +4626,10 @@ struct S$0T(T); --- size = 0, align = 1 + + --- + + may contain types with destructors (drop glue) depending on type parameters; doesn't have a destructor "#]], ); } @@ -4466,6 +4655,10 @@ struct S$0T(T); --- size = 0, align = 1 + + --- + + may contain types with destructors (drop glue) depending on type parameters; doesn't have a destructor "#]], ); } @@ -4492,6 +4685,10 @@ struct S$0T(T); --- size = 0, align = 1 + + --- + + may contain types with destructors (drop glue) depending on type parameters; doesn't have a destructor "#]], ); } @@ -4516,6 +4713,10 @@ fn main() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -4540,6 +4741,10 @@ fn main() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -4564,6 +4769,10 @@ fn main() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -4588,6 +4797,10 @@ fn main() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -4612,6 +4825,10 @@ fn main() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -4635,6 +4852,10 @@ impl Foo { --- size = 8, align = 8, niches = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -4659,6 +4880,10 @@ impl Foo { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -5149,6 +5374,10 @@ type Fo$0o2 = Foo<2>; --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -5202,6 +5431,10 @@ enum E { --- + does not contain types with destructors (drop glue) + + --- + This is a doc "#]], ); @@ -5231,6 +5464,10 @@ enum E { --- + does not contain types with destructors (drop glue) + + --- + This is a doc "#]], ); @@ -5261,6 +5498,10 @@ enum E { --- + does not contain types with destructors (drop glue) + + --- + This is a doc "#]], ); @@ -5291,6 +5532,10 @@ enum E { --- + does not contain types with destructors (drop glue) + + --- + This is a doc "#]], ); @@ -6219,6 +6464,10 @@ fn main() { --- size = 32 (0x20), align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -7518,6 +7767,10 @@ enum Enum { --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -7544,6 +7797,10 @@ enum Enum { --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -8214,6 +8471,10 @@ fn test() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -8863,6 +9124,10 @@ fn main(notable$0: u32) {} --- size = 4, align = 4 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -8955,6 +9220,10 @@ extern "C" { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -9101,6 +9370,10 @@ struct Pedro$0<'a> { --- size = 16 (0x10), align = 8, niches = 1 + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor "#]], ) } @@ -9118,6 +9391,10 @@ fn main(a$0: impl T) {} ```rust a: impl T + ?Sized ``` + + --- + + may contain types with destructors (drop glue) depending on type parameters "#]], ); } @@ -9139,6 +9416,10 @@ fn main(a$0: T) {} --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -9192,6 +9473,10 @@ fn main() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -9529,6 +9814,10 @@ type A$0 = B; --- + does not contain types with destructors (drop glue) + + --- + *This is the documentation for* `struct B` Docs for B @@ -9562,6 +9851,10 @@ type A$0 = B; --- + does not contain types with destructors (drop glue) + + --- + *This is the documentation for* `struct C` Docs for C @@ -9596,6 +9889,10 @@ type A$0 = B; --- + does not contain types with destructors (drop glue) + + --- + *This is the documentation for* `struct C` Docs for C @@ -9625,6 +9922,10 @@ type A$0 = B; --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); @@ -9749,6 +10050,10 @@ fn main() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); @@ -9777,6 +10082,10 @@ fn main() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); @@ -9812,6 +10121,10 @@ fn main() { --- size = 0, align = 1 + + --- + + does not contain types with destructors (drop glue) "#]], ); } @@ -10134,6 +10447,10 @@ fn bar() { --- + does not contain types with destructors (drop glue) + + --- + ```rust ra_test_fixture::Foo ``` @@ -10144,6 +10461,10 @@ fn bar() { --- + may contain types with destructors (drop glue) depending on type parameters + + --- + `T` = `i32` "#]], ); @@ -10353,3 +10674,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 + + --- + + does not contain types with destructors (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 + + --- + + does not contain types with destructors (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 + + --- + + does not contain types with destructors (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 + + --- + + contain types with destructors (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 + ``` + + --- + + contain types with destructors (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 + + --- + + does not contain types with destructors (drop glue) + "#]], + ); + check( + r#" +struct Foo$0(T); + "#, + expect![[r#" + *Foo* + + ```rust + ra_test_fixture + ``` + + ```rust + struct Foo(T) + ``` + + --- + + may contain types with destructors (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, + ``` + + --- + + does not contain types with destructors (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, + ``` + + --- + + does not contain types with destructors (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, + } + ``` + + --- + + does not contain types with destructors (drop glue); doesn't have a destructor + "#]], + ); +} diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 07553a87d28f..41957bad7e07 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -187,6 +187,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 d7e9a5c586c9..5c7b088e680d 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. @@ -1630,6 +1632,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/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md index 0c6674b1408e..1cbe51836f47 100644 --- a/docs/book/src/configuration_generated.md +++ b/docs/book/src/configuration_generated.md @@ -559,6 +559,11 @@ also need to add the folders to Code's `files.watcherExclude`. `#rust-analyzer.hover.documentation.enable#` is set. +**rust-analyzer.hover.dropGlue.enable** (default: true) + + Whether to show drop glue information on hover. + + **rust-analyzer.hover.links.enable** (default: true) Use markdown syntax for links on hover. diff --git a/editors/code/package.json b/editors/code/package.json index 3f09033051ba..a7c8506a45e6 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1641,6 +1641,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": {