fix(rust): index unit structs — bodiless is a definition, not a forward decl (#1800)
Land upstream PR #1514 for issue #1513 by cherry-picking
ctype_lab's a94c9dc94eee348bf63c7e2dd567c0b43577678a.
Keep allowBodilessStruct as a Rust-only opt-in, with matching behavior in
the wasm/TypeScript walker and native kernel. Create the node before
checking for a body and walk members only when present. Resolve against
main's shared struct/union walker while retaining its stack guard, kinds,
fields, and existing impl-receiver fixes.
Verified FAIL to PASS on Linux x64 with Node 22.19.0 after rebuilding via
tsc, copy-assets, and build:kernel. The identical fixture on main 7b339373
had two structs and two implements edges; fresh wasm (CODEGRAPH_KERNEL=0)
and native indexes now have three of each. UnitStruct and its Greet
implements edge are recovered; tuple and brace structs remain intact.
The native run loaded the rebuilt kernel and completed without fallback.
Focused extraction.test.ts and kernel-rustlang-parity.test.ts runs:
645 tests passed with the kernel disabled, and 645 with it enabled;
all three parity tests ran in each configuration, with no skips.
(cherry picked from commit a94c9dc94eee348bf63c7e2dd567c0b43577678a)
Co-authored-by: ctype_lab <cksgud1226@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
ctype_lab
Claude Opus 5
parent
7b339373b4
commit
71d049cd28
@@ -81,6 +81,9 @@ export const rustExtractor: LanguageExtractor = {
|
||||
methodTypes: ['function_item', 'function_signature_item'],
|
||||
interfaceTypes: ['trait_item'],
|
||||
structTypes: ['struct_item'],
|
||||
// `struct Unit;` is a unit struct — a complete definition with no body
|
||||
// field, not a forward declaration. Rust has no forward declarations.
|
||||
allowBodilessStruct: true,
|
||||
// Unions share struct member syntax and impl attachment, but retain their
|
||||
// distinct semantic kind in the graph.
|
||||
unionTypes: ['union_item'],
|
||||
|
||||
@@ -187,6 +187,19 @@ export interface LanguageExtractor {
|
||||
* bodiless class IS complete (Kotlin `class Empty`, Scala `case object`). (#1093)
|
||||
*/
|
||||
skipBodilessClass?: boolean;
|
||||
/**
|
||||
* Keep a bodiless struct node — it IS a complete definition, not a forward
|
||||
* declaration. Set only for languages where a bodiless `struct` is complete:
|
||||
* Rust's unit struct (`struct Unit;`). Leave unset for C/C++, where
|
||||
* `struct Foo;` is a forward declaration.
|
||||
*
|
||||
* Opposite polarity from `skipBodilessClass` (#1093) because the defaults
|
||||
* differ: a bodiless CLASS is kept unless a language opts into skipping,
|
||||
* a bodiless STRUCT is skipped unless a language opts into keeping. The
|
||||
* hardcoded C# `record_declaration` carve-out (#831) is the same situation
|
||||
* predating this flag.
|
||||
*/
|
||||
allowBodilessStruct?: boolean;
|
||||
/** NodeKind to use for interface-like declarations (Rust: 'trait'). Default: 'interface' */
|
||||
interfaceKind?: NodeKind;
|
||||
|
||||
|
||||
@@ -1974,8 +1974,16 @@ export class TreeSitterExtractor {
|
||||
// Skip forward declarations and type references (no body = not a definition)
|
||||
// — EXCEPT C# positional records (`record struct M(decimal Amount);`),
|
||||
// complete definitions with no body block. (#831)
|
||||
//
|
||||
// `allowBodilessStruct` is the per-language escape hatch for the same
|
||||
// situation: a bodiless struct that IS a complete definition (Rust's unit
|
||||
// struct `struct Unit;`). Opposite polarity from `skipBodilessClass`
|
||||
// (#1093) because the two defaults differ — a bodiless CLASS is kept
|
||||
// unless a language opts into skipping, a bodiless STRUCT is skipped
|
||||
// unless a language opts into keeping.
|
||||
const body = getChildByField(node, this.extractor.bodyField);
|
||||
if (!body && node.type !== 'record_declaration') return;
|
||||
if (!body && node.type !== 'record_declaration' && !this.extractor.allowBodilessStruct)
|
||||
return;
|
||||
|
||||
const name = extractName(node, this.source, this.extractor);
|
||||
const docstring = getPrecedingDocstring(node, this.source);
|
||||
|
||||
Reference in New Issue
Block a user