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.
This commit is contained in:
Chayim Refael Friedman 2025-01-20 19:48:55 +02:00
parent 2b485d7f23
commit 100e166bb1
13 changed files with 1002 additions and 6 deletions

View file

@ -38,6 +38,7 @@ pub struct HoverConfig {
pub max_fields_count: Option<usize>,
pub max_enum_variants_count: Option<usize>,
pub max_subst_ty_len: SubstTyLen,
pub show_drop_glue: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]

View file

@ -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<bool>,
}
pub(super) fn literal(
sema: &Semantics<'_, RootDatabase>,
token: SyntaxToken,

File diff suppressed because it is too large Load diff

View file

@ -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!(