Skip to content

Commit bdf6d42

Browse files
committed
Defer cleanup of emptied and synthetic declarations during invalidation
1 parent a1a5972 commit bdf6d42

4 files changed

Lines changed: 488 additions & 50 deletions

File tree

rust/rubydex/src/model/built_in.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ pub static OBJECT_ID: LazyLock<DeclarationId> = LazyLock::new(|| DeclarationId::
1717
pub static MODULE_ID: LazyLock<DeclarationId> = LazyLock::new(|| DeclarationId::from("Module"));
1818
pub static CLASS_ID: LazyLock<DeclarationId> = LazyLock::new(|| DeclarationId::from("Class"));
1919

20+
/// Returns true if `decl_id` is a built-in declaration that should never be
21+
/// removed from the graph, even when it has no backing definitions.
22+
#[must_use]
23+
pub fn is_built_in(decl_id: &DeclarationId) -> bool {
24+
*decl_id == *KERNEL_ID
25+
|| *decl_id == *BASIC_OBJECT_ID
26+
|| *decl_id == *OBJECT_ID
27+
|| *decl_id == *MODULE_ID
28+
|| *decl_id == *CLASS_ID
29+
}
30+
2031
/// Adds core classes and modules data to the graph so that resolution can provide correct results even when not
2132
/// indexing the complete RBS core definitions
2233
///

rust/rubydex/src/model/declaration.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,14 @@ macro_rules! namespace_declaration {
162162
self.singleton_class_id = Some(declaration_id);
163163
}
164164

165+
/// Clears `singleton_class_id` only if it matches `expected`.
166+
/// Prevents accidentally clearing a pointer to a re-created singleton.
167+
pub fn clear_singleton_class_id(&mut self, expected: &DeclarationId) {
168+
if self.singleton_class_id.as_ref() == Some(expected) {
169+
self.singleton_class_id = None;
170+
}
171+
}
172+
165173
pub fn singleton_class_id(&self) -> Option<&DeclarationId> {
166174
self.singleton_class_id.as_ref()
167175
}
@@ -327,6 +335,14 @@ impl Declaration {
327335
}
328336
}
329337

338+
#[must_use]
339+
pub fn as_singleton_class(&self) -> Option<&Namespace> {
340+
match self {
341+
Declaration::Namespace(ns @ Namespace::SingletonClass(_)) => Some(ns),
342+
_ => None,
343+
}
344+
}
345+
330346
#[must_use]
331347
pub fn as_namespace_mut(&mut self) -> Option<&mut Namespace> {
332348
match self {
@@ -345,6 +361,24 @@ impl Declaration {
345361
all_declarations!(self, it => it.definition_ids.is_empty())
346362
}
347363

364+
/// Returns true if this declaration has no backing definitions and is eligible
365+
/// for removal. Built-in declarations are never removable. Singleton classes
366+
/// delegate to `Namespace::is_empty` — they are only removable when they
367+
/// have no definitions AND no members (populated singletons serve as
368+
/// namespace parents for class-level methods).
369+
#[must_use]
370+
pub fn has_no_backing_definitions(&self, decl_id: &DeclarationId) -> bool {
371+
if super::built_in::is_built_in(decl_id) {
372+
return false;
373+
}
374+
375+
if let Some(singleton_class) = self.as_singleton_class() {
376+
return singleton_class.is_empty();
377+
}
378+
379+
self.has_no_definitions()
380+
}
381+
348382
pub fn add_definition(&mut self, definition_id: DefinitionId) {
349383
all_declarations!(self, it => {
350384
debug_assert!(
@@ -466,6 +500,12 @@ impl Namespace {
466500
}
467501
}
468502

503+
/// Returns true if this namespace has no definitions and no members.
504+
#[must_use]
505+
pub fn is_empty(&self) -> bool {
506+
all_namespaces!(self, it => it.definition_ids.is_empty() && it.members.is_empty())
507+
}
508+
469509
#[must_use]
470510
pub fn references(&self) -> &IdentityHashSet<ConstantReferenceId> {
471511
all_namespaces!(self, it => &it.references)
@@ -578,6 +618,10 @@ impl Namespace {
578618
all_namespaces!(self, it => it.set_singleton_class_id(declaration_id));
579619
}
580620

621+
pub fn clear_singleton_class_id(&mut self, expected: &DeclarationId) {
622+
all_namespaces!(self, it => it.clear_singleton_class_id(expected));
623+
}
624+
581625
#[must_use]
582626
pub fn owner_id(&self) -> &DeclarationId {
583627
all_namespaces!(self, it => &it.owner_id)

0 commit comments

Comments
 (0)