fix(julia): port abstract-def / macro-def / signature-call WASM bugs#1130
fix(julia): port abstract-def / macro-def / signature-call WASM bugs#1130carlos-alm wants to merge 3 commits into
Conversation
The WASM Julia extractor diverged from the native Rust extractor in three ways that no existing WASM fixture exercised: - handleAbstractDef: `findChild(node, 'identifier')` only looks at direct children of `abstract_definition`, but tree-sitter-julia nests the identifier inside `type_head`. Result: no abstract type was ever recorded. Fall back to `findBaseName(typeHead)` like the native code. - handleMacroDef: `findChild(node, 'identifier')` resolves to the body's first identifier rather than the macro name (e.g. `macro mymac(x) x end` recorded `@x` instead of `@mymac`). Unwrap via `signatureCall` to reach the call_expression name. - handleCall: the guard `parent.type === 'function_definition'` never matched — the signature's call_expression is parented by `signature`, whose own parent is the function/macro definition. Result: every long-form `function greet(...) ... end` recorded `greet` as both a definition and a call. Match the native walk: skip when parent is `signature` and grandparent is `function_definition` or `macro_definition`. Adds WASM tests mirroring the native cases: extracts_abstract_type, extracts_parameterized_abstract_type_base_name, extracts_macro_def, and does_not_record_function_signature_as_call. Closes #1126
…gs' into fix/1126-julia-wasm-extractor-bugs
Greptile SummaryPorts three WASM-specific bugs in the Julia extractor that caused divergence from the native Rust extractor: abstract type names were never emitted, macro definitions were recording the wrong name, and function signatures were double-recorded as calls.
Confidence Score: 5/5Safe to merge — all three fixes are narrow, well-tested corrections to WASM extractor paths that were already broken. Each fix targets a clearly-documented regression, mirrors the already-working native extractor logic, and is guarded by a dedicated regression test that fails on the old code and passes after the fix. No existing test coverage was removed or weakened, and the changes are isolated to the Julia extractor. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[walkJuliaNode] --> B{node.type}
B -->|abstract_definition| C[handleAbstractDef]
C --> C1[findChild: type_head]
C1 -->|null| C2[return — skip]
C1 -->|found| C3[findBaseName typeHead]
C3 -->|null| C2
C3 -->|identifier node| C4[ctx.definitions.push kind=type]
B -->|macro_definition| D[handleMacroDef]
D --> D1[signatureCall node]
D1 -->|found| D2[callSig.child 0 = name identifier]
D1 -->|null| D3[fallback: childForFieldName OR findChild identifier]
D2 --> D4[ctx.definitions.push @name]
D3 --> D4
B -->|call_expression| E[handleCall]
E --> E1{parent.type === signature?}
E1 -->|yes| E2{grandparent.type?}
E2 -->|function_definition or macro_definition| E3[return — skip signature]
E2 -->|other| E4[record as call]
E1 -->|no| E5{parent = assignment LHS?}
E5 -->|yes| E3
E5 -->|no| E4
Reviews (3): Last reviewed commit: "fix(julia): align abstract-def name reso..." | Re-trigger Greptile |
| let nameNode = node.childForFieldName('name') || findChild(node, 'identifier'); | ||
| if (!nameNode) { | ||
| const typeHead = findChild(node, 'type_head'); | ||
| if (!typeHead) return; | ||
| nameNode = findBaseName(typeHead); | ||
| if (!nameNode) return; | ||
| } |
There was a problem hiding this comment.
The legacy
childForFieldName('name') || findChild(node, 'identifier') path is kept as the primary lookup before the type_head fallback. handleStructDef (which handles the identical type_head grammar shape) skips this step entirely and goes straight to findChild(node, 'type_head') + findBaseName. If a grammar revision ever makes childForFieldName('name') return the full type_head node rather than null, nameNode.text would emit the raw AbstractVector{T} <: AbstractArray{T,1} string and the parameterized-abstract-type test would silently break. Aligning with handleStructDef removes that fragility.
| let nameNode = node.childForFieldName('name') || findChild(node, 'identifier'); | |
| if (!nameNode) { | |
| const typeHead = findChild(node, 'type_head'); | |
| if (!typeHead) return; | |
| nameNode = findBaseName(typeHead); | |
| if (!nameNode) return; | |
| } | |
| const typeHead = findChild(node, 'type_head'); | |
| if (!typeHead) return; | |
| const nameNode = findBaseName(typeHead); | |
| if (!nameNode) return; |
There was a problem hiding this comment.
Fixed — dropped the legacy childForFieldName('name') lookup and aligned with handleStructDef's type_head + findBaseName pattern.
Codegraph Impact Analysis3 functions changed → 2 callers affected across 1 files
|
Summary
Ports three additional Julia WASM extractor bugs that diverged from the native Rust extractor. Surfaced while reviewing #1111 (#1128); filed and fixed separately per scope discipline.
handleAbstractDef—findChild(node, 'identifier')only inspects direct children ofabstract_definition, but tree-sitter-julia nests the name insidetype_head. Result: no abstract type was ever recorded on the WASM side. Falls back tofindBaseName(typeHead)like the native code.handleMacroDef—findChild(node, 'identifier')was resolving to the body's first identifier instead of the macro name (e.g.macro mymac(x) x endrecorded@xinstead of@mymac). Now unwraps viasignatureCallto reach the signature'scall_expressionname.handleCall— the guardparent.type === 'function_definition'never matched: the signature'scall_expressionis parented bysignature, whose own parent is the function/macro definition. Result: every long-formfunction greet(...) ... endwas recordinggreetas both a definition and a call. Now mirrors the native walk: skip when parent issignatureand grandparent isfunction_definitionormacro_definition.Test plan
Added WASM tests mirroring the native ones — each fails on
main's WASM extractor and passes after the fix:extracts abstract type—abstract type AbstractShape endextracts parameterized abstract type base name—abstract type AbstractVector{T} <: AbstractArray{T,1} endextracts macro definitions with correct name— guards against@xregressiondoes not record function signature as call— guards against duplicate-call regressiontests/parsers/julia.test.tspassNotes
Stacked on top of #1128 (which adds the
signatureCallandfindBaseNamehelpers this PR reuses). Will retarget tomainonce #1128 merges.Closes #1126