Skip to content

Commit 8c2e148

Browse files
committed
fix(julia): drop unused TYPE_HEAD_WRAPPERS entries, add simple-supertype test (#1128)
- Remove type_parameter_list / type_argument_list from TYPE_HEAD_WRAPPERS in both WASM and native engines. Julia grammar uses curly_expression for {T} constructs, so these were dead code. Removing them prevents findBaseName from ever recursing into a type-parameter list and returning a type variable (e.g. T) instead of the struct name. - Add WASM test for non-parameterized struct inheritance (struct Point <: AbstractPoint). The native engine already covers this case; the WASM side now has parity.
1 parent 796352b commit 8c2e148

3 files changed

Lines changed: 36 additions & 11 deletions

File tree

crates/codegraph-core/src/extractors/julia.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,17 @@ fn handle_abstract_def(node: &Node, source: &[u8], symbols: &mut FileSymbols) {
297297
///
298298
/// Handles plain identifiers, `Name <: Super` binary expressions, and
299299
/// parameterized forms like `Name{T}` / `Name{T} <: Super{T,1}` by recursing
300-
/// into common wrapper kinds (binary expressions, parametrized identifiers,
301-
/// type-parameter lists). Returns `None` when no identifier can be located —
300+
/// into wrapper kinds the Julia grammar actually emits for type heads
301+
/// (binary expressions, parametrized type expressions, parameterized
302+
/// identifiers). Returns `None` when no identifier can be located —
302303
/// callers should skip emitting a definition in that case.
304+
///
305+
/// Note: `type_parameter_list` / `type_argument_list` are intentionally
306+
/// excluded — Julia's grammar uses `curly_expression` for `{T}` constructs,
307+
/// not those node kinds. Including them would risk recursing into a
308+
/// type-parameter list and returning a type variable (e.g. `T`) instead of
309+
/// the struct name if `find_base_name` were ever called on a node lacking a
310+
/// direct `identifier` child.
303311
fn find_base_name<'a>(node: &Node<'a>) -> Option<Node<'a>> {
304312
// The node itself may already be the identifier (e.g. when called on a
305313
// direct side of a binary_expression like `Point <: AbstractPoint`).
@@ -317,9 +325,7 @@ fn find_base_name<'a>(node: &Node<'a>) -> Option<Node<'a>> {
317325
match child.kind() {
318326
"binary_expression"
319327
| "parametrized_type_expression"
320-
| "parameterized_identifier"
321-
| "type_parameter_list"
322-
| "type_argument_list" => {
328+
| "parameterized_identifier" => {
323329
if let Some(found) = find_base_name(&child) {
324330
return Some(found);
325331
}

src/extractors/julia.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,22 @@ function handleAssignment(
173173
*
174174
* Handles plain identifiers, `Name <: Super` binary expressions, and
175175
* parameterized forms like `Name{T}` / `Name{T} <: Super{T,1}` by recursing
176-
* into common wrapper kinds (binary expressions, parametrized type
177-
* expressions, parameterized identifiers, type-parameter / type-argument
178-
* lists). Returns `null` when no identifier can be located — callers should
179-
* skip emitting a definition in that case.
176+
* into wrapper kinds the Julia grammar actually emits for type heads
177+
* (binary expressions, parametrized type expressions, parameterized
178+
* identifiers). Returns `null` when no identifier can be located — callers
179+
* should skip emitting a definition in that case.
180+
*
181+
* Note: `type_parameter_list` / `type_argument_list` are intentionally
182+
* excluded — Julia's grammar uses `curly_expression` for `{T}` constructs,
183+
* not those node kinds. Including them would risk recursing into a
184+
* type-parameter list and returning a type variable (e.g. `T`) instead of
185+
* the struct name if `findBaseName` were ever called on a node lacking a
186+
* direct `identifier` child.
180187
*/
181188
const TYPE_HEAD_WRAPPERS: ReadonlySet<string> = new Set([
182189
'binary_expression',
183190
'parametrized_type_expression',
184191
'parameterized_identifier',
185-
'type_parameter_list',
186-
'type_argument_list',
187192
]);
188193

189194
function findBaseName(node: TreeSitterNode): TreeSitterNode | null {

tests/parsers/julia.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ end`);
6969
expect(symbols.classes[0]).toMatchObject({ name: 'Vec', extends: 'AbstractArray' });
7070
});
7171

72+
it('extracts non-parameterized struct inheritance', () => {
73+
// Simple `struct Name <: Super` must still record both the definition
74+
// and the `extends` relationship — the grammar wraps it in a
75+
// `binary_expression` just like the parameterized form.
76+
const symbols = parseJulia(`struct Point <: AbstractPoint
77+
x::Float64
78+
y::Float64
79+
end`);
80+
const names = symbols.definitions.map((d) => d.name);
81+
expect(names).toContain('Point');
82+
expect(symbols.classes).toHaveLength(1);
83+
expect(symbols.classes[0]).toMatchObject({ name: 'Point', extends: 'AbstractPoint' });
84+
});
85+
7286
it('qualified short-form method does not double-prefix', () => {
7387
// `Foo.bar(x, y) = x + y` inside `module Outer` must record `Foo.bar`,
7488
// not `Outer.Foo.bar` — the scoped_identifier already carries the qualifier.

0 commit comments

Comments
 (0)