fix(scala): walk type_definition right-hand sides for type references#2066
fix(scala): walk type_definition right-hand sides for type references#2066mdshzb04 wants to merge 2 commits into
Conversation
…Graphify-Labs#2049) type_definition (plain aliases, opaque type, match types) sits at the same template_body level as val_definition/var_definition, but the Scala dispatch only fired for the latter, so alias right-hand sides produced zero references edges. Two changes: - widen the dispatch to include type_definition; the RHS lives under the same 'type' field a val/var annotation uses, so the existing walk is reused as-is - teach _scala_collect_type_refs to recurse through match_type and type_case_clause nodes, which its whitelist did not know about, so match-type case patterns and results resolve too Fixture gains a TypeAliases class covering all three shapes; four new tests assert Map/HttpClient (alias), Long (opaque), and Option/ListBuffer (match type cases) each get references edges.
| @@ -969,7 +969,8 @@ def _scala_collect_type_refs(node, source: bytes, generic: bool, out: list[tuple | |||
| _scala_collect_type_refs(arg, source, True, out) | |||
| return | |||
There was a problem hiding this comment.
Looks good overall. Could you briefly explain why True is passed here instead of using the existing generic variable? It would help future readers understand the intent.
There was a problem hiding this comment.
This line is pre-existing and only appears as context in this diff. It’s where the walker descends into the children of a type_arguments node, so everything below that point is in generic-argument position regardless of the outer generic value. Wrapper nodes instead pass generic through unchanged since they don't change that context.
| @@ -3075,8 +3076,11 @@ def _emit_java_parent_type(type_node, rel: str, at_line: int) -> None: | |||
| return | |||
There was a problem hiding this comment.
This change seems reasonable. Would adding a short comment above this condition make the special handling for Scala type references easier to understand?
There was a problem hiding this comment.
Good point. There’s already a comment just inside the condition explaining the type_definition handling, but I agree it would be clearer above the condition. I’ll move it there.
| assert ("TypeAliases", "Option") in labels | ||
| assert ("TypeAliases", "ListBuffer") in labels | ||
|
|
||
|
|
There was a problem hiding this comment.
Nice improvement. Have you tested this against nested or more complex Scala type definitions to ensure there are no regressions?
There was a problem hiding this comment.
Yes. The committed fixture covers nested type arguments with Map[String, HttpClient] and match-type cases with type-variable binding. I also tested deeper nesting locally with Map[String, List[Option[HttpClient]]] and a match type over Either[Throwable, Vector[Int]]; references resolved correctly at each depth. The full relevant test suite also passes with 324 passed and 13 skipped. Happy to add the deeper-nesting case to the fixture if you'd like it covered explicitly.
Per review on Graphify-Labs#2066 — no logic change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per review on Graphify-Labs#2066 — no logic change.
1dfd279 to
1a4d371
Compare
Fixes #2049
type_definitionnodes (plain aliases,opaque type, match types) sit at the exact sametemplate_bodysibling level asval_definition/var_definition, but the Scala-specific dispatch in_extract_genericonly fired for the latter — so alias right-hand sides produced zeroreferencesedges of any kind, as reported.Changes
Two small edits in
graphify/extractors/engine.py:type_definition. Verified against tree-sitter-scala that the RHS lives under the sametypefield a val/var annotation uses (for plain aliases,opaque type, and match types alike), so the existing walk is reused verbatim — exactly the one-line widening the issue suggested._scala_collect_type_refsaboutmatch_type/type_case_clause. As the issue predicted, the dispatch alone isn't enough for match types: the walker's recursion whitelist didn't know these node types, so a correctly-dispatched match-type RHS still resolved nothing. Adding them to the existing recursion tuple lets case patterns and results resolve.Before / after
Before:
Repohas no outgoingreferencesedges.After:
referencesedges toList,Int,Long,String,Char,Array,t,X— matching what an equivalentvalannotation already produced.Tests
Extended
tests/fixtures/sample.scalawith aTypeAliasesclass covering all three shapes, plus four new tests asserting the alias (Map/HttpClient), opaque (Long), and match-type case (Option/ListBuffer) references. Full run:tests/test_languages.py+tests/test_builtin_global_type_refs.py→ 324 passed, 13 skipped.Out of scope (kept separate deliberately): file-scope/trait containers (#2042, #2054) and qualified
stable_type_identifiernames (#2055) — this PR only closes thetype_definitiondispatch gap so it composes cleanly with fixes for those.