Skip to content

fix(scala): walk type_definition right-hand sides for type references#2066

Open
mdshzb04 wants to merge 2 commits into
Graphify-Labs:v8from
mdshzb04:fix/scala-type-definition-refs
Open

fix(scala): walk type_definition right-hand sides for type references#2066
mdshzb04 wants to merge 2 commits into
Graphify-Labs:v8from
mdshzb04:fix/scala-type-definition-refs

Conversation

@mdshzb04

Copy link
Copy Markdown
Contributor

Fixes #2049

type_definition nodes (plain aliases, opaque type, match types) sit at the exact same template_body sibling level as val_definition/var_definition, but the Scala-specific dispatch in _extract_generic only fired for the latter — so alias right-hand sides produced zero references edges of any kind, as reported.

Changes

Two small edits in graphify/extractors/engine.py:

  1. Widen the dispatch to include type_definition. Verified against tree-sitter-scala that the RHS lives under the same type field 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.
  2. Teach _scala_collect_type_refs about match_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

class Repo {
  type Alias = List[Int]
  opaque type Id = Long
  type Elem[X] = X match { case String => Char; case Array[t] => t }
}

Before: Repo has no outgoing references edges.
After: references edges to List, Int, Long, String, Char, Array, t, X — matching what an equivalent val annotation already produced.

Tests

Extended tests/fixtures/sample.scala with a TypeAliases class 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.py324 passed, 13 skipped.

Out of scope (kept separate deliberately): file-scope/trait containers (#2042, #2054) and qualified stable_type_identifier names (#2055) — this PR only closes the type_definition dispatch gap so it composes cleanly with fixes for those.

…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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems reasonable. Would adding a short comment above this condition make the special handling for Scala type references easier to understand?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread tests/test_languages.py
assert ("TypeAliases", "Option") in labels
assert ("TypeAliases", "ListBuffer") in labels


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice improvement. Have you tested this against nested or more complex Scala type definitions to ensure there are no regressions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

mdshzb04 added a commit to mdshzb04/graphify that referenced this pull request Jul 21, 2026
Per review on Graphify-Labs#2066 — no logic change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mdshzb04
mdshzb04 force-pushed the fix/scala-type-definition-refs branch from 1dfd279 to 1a4d371 Compare July 21, 2026 02:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants