Skip to content

Walk declaration initializers scoped to the declared symbol — Kotlin, Java, TS/JS, Scala, Rust, Python (#693 for the other six languages) - #1511

Closed
danusha2345 wants to merge 26 commits into
colbymchenry:mainfrom
danusha2345:fix/kotlin-property-initializer-walk
Closed

danusha2345 wants to merge 26 commits into
colbymchenry:mainfrom
danusha2345:fix/kotlin-property-initializer-walk

Conversation

@danusha2345

Copy link
Copy Markdown
Contributor

Closes #1510. Ports #693's fix (merged as #744 for Go) to Kotlin, Java, TypeScript/JavaScript, Scala, Rust and Python.

The shape is the same everywhere: after minting the declaration's node, walk its initializer through visitFunctionBody with that node pushed on the scope stack, so the calls inside it are attributed to the symbol that owns them instead of leaking to the file node — or, in most of these languages, vanishing outright.

Every language moves in both arms togethersrc/extraction/ and the matching codegraph-kernel/src/ walker — so kernel-*-parity stays byte-identical; that is asserted per language, and each torture fixture gains the new shapes.


Per language

Kotlin — three commits. The property_declaration hook consumed the whole subtree, so the dispatcher only fn-ref-scanned it.

  • The initializer (= …) and a property_delegate (by lazy { … }) are now walked under the property.
  • So is an accessor, on either line: a same-line val x: Int get() = f() nests under the declaration, an own-line one parses as a following sibling. The property claims its own-line accessors and the accessor branch skips what the property claimed — the skip re-derives the property's kind instead of remembering it across nodes, so a destructured or local declaration (which mints nothing and therefore claims nothing) keeps falling through. No cross-node state in either arm.
  • init { val cfg = load() } and val (a, b) = makePair() mint no symbol of their own, so they are walked at the enclosing scope — an init block's calls belong to the class, like its other statements. Both used to disappear completely.
  • The scope/kind decision moved into one function (kotlinPropertyKind / property_kind) now that two branches need it.

JavaextractField minted the node and stopped. The declarator's value is now walked under the field. The anonymous-class form lost more than edges: new LocationListener() { … } in a field initializer was never extracted at all, so the class and its overrides did not exist as symbols. extractField is shared, but the walk is keyed on the value field, which only Java's variable_declarator carries — C# (bare child), VB.NET (initializer) and PHP (default_value, separate branch) are untouched.

TypeScript / JavaScript — two defects in extractVariable's JS-family branch.

  1. The walk ran with only the FILE on nodeStack, so const cfg = loadConfig() recorded the file as loadConfig's caller. (This is the part CodeGraph does not index call edges from anonymous/lambda functions #693's closing note assumed JS/TS didn't have; it holds only for const f = () => …, where the arrow value delegates to extractFunction.)
  2. Object literals were excluded from the walk outright, on the grounds that their function-valued members are extracted individually below — but that only happens for exported consts. const obj = { handler: () => target() } therefore contributed nothing at all.

Both fixed by walking the initializer scoped to the declared symbol and skipping only the shapes whose members really are extracted one-by-one (exported object-of-functions, RTK endpoints, Pinia setup, Vue store collections) — walking those too would double-count each member arrow's calls.

Scala — the val/var hook returned true without walking; the grammar exposes value directly, so this is the closest analogue to the Go fix. Scala puts almost everything in a val, which is why it shows the largest per-file gain here.

Rustconst_item/static_item ride extractVariable's generic fallback. That fallback is shared, so the walk is gated to Rust; the declared symbol is identified by the name field, which leaves the fallback's phantom node for a bare-identifier initializer (const MAX: u32 = OTHER;MAX plus a spurious OTHER) exactly as it is. Separate defect, deliberately not folded in — noted in #1510.

Python — the assignment branch minted the node and stopped. right is now walked under the assigned name; a tuple target mints no symbol, so its RHS is walked at the enclosing scope rather than lost. Gated to Python — Ruby shares the branch. Class attributes are untouched: they never reach this branch (the dispatcher's class-scope gate excludes them), so their calls keep riding the class node; giving them symbols of their own is a separate question, since there are no nodes for them today at all.


Two follow-on repairs the change surfaced

Both are in this PR because the initializer walk is what exposed them.

CFML. <cfscript> bodies are delegated to a separate extractor as if they were a whole module, so a var x = helper() local inside a <cffunction> minted a top-level variable node and the walk attributed helper to it. Those snippet-top-level non-callables are locals of the enclosing function; their refs now redirect to it, exactly like the snippet's file-attributed refs already did.

codegraph_explore dynamic-dispatch links. The section stopped listing a synthesized edge once the same pair also had a static call edge: it asked getCallers/getCallees, which return one row per neighbour (the #1086 de-dup), so the static edge hid the heuristic one. It now asks the edges directly. This is the RTK thunk case — dispatch(innerThunk(n)) inside a thunk initializer is now a real static edge, which is the point, but the synthesized hop must still show up in the summary.


Validation

Each language was measured by diffing one extractor arm against upstream main over real trees, classifying every ref change as lost / re-attributed (same file+kind+name+line, different owner) / new:

language corpus lost re-attributed new kernel parity
Kotlin 113-file Android app 0 0 +368 99/113 (14 grammar-deferred — same set as upstream)
Java 409-file Android SDK sample tree 0 0 +651, +21 nodes 409/409
TS/JS 499 files, three projects 0 780 (file → constant) +228 324/326 (2 deferred)
Scala 32-file SpinalHDL project 0 0 +812 32/32
Rust 282 files, three projects 0 0 +86 226/230 (4 deferred)
Python 799 files, three projects 0 0 +3057 6221/6221 sweep

Node and edge counts are unchanged everywhere except Java (+21 nodes — the anonymous listener and Parcelable.Creator classes that were previously invisible).

End-to-end on a mixed 110-Kotlin / 100-JS / 37-Go project, full codegraph init both sides: 4311 → 4318 nodes, 12106 → 12254 edges, 0 edges lost. 13 edges changed identity — 9 JS initializer calls moving off the file node onto their declaring constant, and 4 Kotlin run(…) call sites that used to name-match a JavaScript test helper in desktop/test/ and now match a Kotlin run override.

The headline case that started this: an MSDK ICameraStreamManager.CameraFrameListener field now appears in callers of the method it invokes.

npm test2930 passing, on top of upstream main as of a7db24d.

Test coverage added

  • __tests__/extraction.test.ts — a regression test per language (Kotlin ×3 shapes, Java, TS/JS, Scala, Rust, Python), each asserting the exact set of owners for the calls in question, including the cases that deliberately still ride the enclosing scope.
  • Kernel-parity torture fixtures extended for all six languages, so the two arms are pinned on the new shapes (incl. CRLF variants).
  • __tests__/function-ref.test.ts — one expectation updated: a function-as-value in an initializer (REGISTRY = {"org": Serializer}) now produces a reference from both the assigned name and the file node, because the dispatcher's own scan runs either way. That is the shape fix(go): attribute calls inside top-level closures to the var, not the file (#693) #744 already ships — verified against the Go arm on the same input — so the two languages stay consistent.

Deliberately not in this PR

danusha2345 added 13 commits August 5, 2026 22:18
…lbymchenry#693 for Kotlin)

The Kotlin property hook consumes the whole `property_declaration` subtree,
so the dispatcher only scanned it for function-as-value candidates and never
walked it for calls. Every call inside a property initializer was therefore
dropped from the graph entirely — not misattributed, gone:

    private val fieldLambda: () -> Unit = { target() }   // no caller
    private val samField = Runnable { target() }         // no caller
    private val plain = compute()                        // no caller
    private val delegated by lazy { compute() }          // no caller

That is exactly how Android/MSDK callbacks are declared, so anything reached
only through such a callback looked like it had no callers and its blast
radius came back far too small.

Fix: after minting the property node, walk its RHS — the named child after
the `=` token plus a `property_delegate` — through visitFunctionBody with the
property pushed on the scope stack. This is Go's colbymchenry#693/colbymchenry#744 fix ported;
tree-sitter-kotlin exposes no fields at all, hence the `=` anchor instead of
Go's `child_by_field_name("value")`.

Not touched, by design: the `scope == "local"` early return, the
hook-declined destructuring branch, and the declaration's own children
(modifiers, `val`/`var`, name+type, extension receiver, `getter`/`setter`).

Both arms move together — the Rust kernel and the TS extractor — so
kernel-kotlin-parity stays byte-identical; the torture fixture gains the
lambda/SAM/anonymous-object initializer shapes.

Measured on a 113-file Android/Kotlin app: strictly additive, 0 lost nodes /
edges / refs, +7 nodes (anonymous-object overrides that were invisible),
+109 edges (+47 calls, +35 instantiates, +20 references), and the real case
that motivated this — a `CameraFrameListener` field — now shows up as a
caller of the method it invokes.
…ry#693 for Java)

`extractField` minted the field node and stopped; the dispatcher then only
scanned the `field_declaration` subtree for function-as-value candidates. So
a field initializer's code was never walked:

    private final Runnable fieldLambda = () -> target();          // no caller
    private final Runnable l = new LocationListener() { … };       // invisible
    private final int eager = compute();                           // no caller

The anonymous-class form lost more than edges — the class and its overrides
were never extracted at all, which is how `Parcelable.Creator` and every
Android listener field is written.

Fix: walk the declarator's `value` through visitFunctionBody with the field
pushed on the scope stack — Go's colbymchenry#693/colbymchenry#744 fix, and the same shape as the
TS/JS class-field walk already sitting in the methodTypes branch (colbymchenry#808).
`extractField` is shared, but the walk is keyed on the `value` FIELD, which
only Java's `variable_declarator` carries: C# (bare child), VB.NET
(`initializer`) and PHP (`default_value`, separate branch) are untouched and
stay for their own turn.

Kernel and TS extractor move together, so kernel parity stays byte-identical.

Measured on the 409-file DJI MSDK v5 UX SDK (Java): strictly additive, 0 lost
nodes / edges / refs, +21 nodes (anonymous listener and Creator classes with
their overrides), +21 edges, +651 refs, 409/409 files still byte-parity
between the two arms.
…ymchenry#693 for TS/JS)

Two defects in one place — extractVariable's JS-family branch.

1. The initializer walk ran with only the FILE on the node stack, so
   `const cfg = loadConfig()` recorded the FILE as loadConfig's caller. That is
   literally the leak colbymchenry#693 described and colbymchenry#744 fixed for Go; the closing note
   there said "JS/TS didn't have this gap", which holds only for the
   `const f = () => …` shape (an arrow value delegates to extractFunction and
   gets its own node).

2. Object literals were excluded from the walk outright, on the grounds that
   their function-valued members are extracted individually below — but that
   only happens for EXPORTED consts. `const obj = { handler: () => target() }`
   therefore contributed nothing at all: no member node, and no call edge to
   anything.

Fix: walk the initializer with the declared symbol pushed on the stack, and
skip only the shapes whose members really are extracted one-by-one (exported
object-of-functions, RTK endpoints, Pinia setup, Vue store collections) —
walking those too would double-count each member arrow's calls.

Two follow-on repairs the change surfaced:

- CFML `<cfscript>` bodies are delegated to a separate extractor as if they
  were a whole module, so a `var x = helper()` local inside a `<cffunction>`
  minted a top-level variable node and the walk attributed `helper` to it.
  Those snippet-top-level non-callables are locals of the enclosing function;
  their refs now redirect to it, like the snippet's file-attributed refs
  already did.
- codegraph_explore stopped listing a synthesized dynamic-dispatch link once
  the same pair also had a static call edge: it asked getCallers/getCallees,
  which return one row per NEIGHBOUR (the colbymchenry#1086 de-dup), so the static edge
  hid the heuristic one. It now asks the edges directly. This is exactly the
  RTK thunk case — `dispatch(innerThunk(n))` inside a thunk initializer is now
  a real static edge, which is the point, but the synthesized hop must still
  show up in the summary.

Measured on three independent TypeScript trees (codegraph's own src/, evcc-ng,
gv-grx — 499 files): 0 lost nodes/edges/refs, 780 refs re-attributed from the
file node to the declaring constant, 228 genuinely new refs from object
literals, node and edge counts unchanged. Kernel parity holds (324/324
non-deferred files byte-identical).
Follow-up to cf582f4. `val url: String get() = build(host)` nests the accessor
UNDER the property_declaration, so the hook consumed it and everything the
getter body called vanished — the initializer walk deliberately skipped
`getter`/`setter` on the theory that they are declaration, not code. They are
code.

Measured on the Android project this arc is validated against: 16 such
properties, whose accessor bodies contributed nothing at all.

An accessor written on its OWN line parses as a SIBLING of the property, not a
child, so it stays out of reach here and keeps attributing to the enclosing
class exactly as before. That asymmetry is the grammar's, and closing it means
looking backwards from a sibling accessor to the preceding declaration —
separate change, separate risk.

Whole-project re-measure (110 Kotlin + 100 JS + 37 Go files, both arms of the
extractor): 0 genuinely lost edges, +142 edges. The 13 edges that changed
identity are 9 JS initializer calls moving off the file node onto their
declaring constant, and 4 Kotlin `run(…)` call sites that used to name-match a
JavaScript test helper in desktop/test/ and now match a Kotlin `run` override.
…olbymchenry#693 for Scala)

The val/var hook minted the node and returned true, so the dispatcher only
scanned the subtree for function-as-value candidates and the initializer's
code was never walked:

    val fieldLambda: () => Unit = () => target()   // no caller
    val direct = target()                          // no caller
    lazy val lazily = compute()                    // no caller
    val anon = new Runnable { def run() = target() }  // no caller

Scala puts almost everything in a val, so this is not an edge case: on a
32-file SpinalHDL project the graph was missing 812 references.

Fix: walk the `value` field through visitFunctionBody with the declared symbol
pushed on the scope stack — the same shape as Go's colbymchenry#693/colbymchenry#744 fix, which the
grammar supports directly here (`val_definition` exposes `value`).

Kernel and TS extractor move together; kernel parity holds.

Measured on that SpinalHDL project: 0 lost refs, 0 re-attributed, +812 new,
node and edge counts unchanged (824/792), 32/32 files byte-parity between the
two arms.
…estructuring, own-line accessors

Three shapes the hook still swallowed after cf582f4/8b2e436. The first two are
outright losses: the code existed in the file and reached the graph nowhere.

    init { val cfg = load() }        // `load` vanished — only the block's
                                     // bare statements survived
    val (a, b) = makePair()          // `makePair` vanished, at class AND
                                     // file scope
    val x: Int                       // walked, but attributed to the
        get() = compute()            // enclosing CLASS, not to `x`

The first two mint no symbol of their own, so they are walked at the ENCLOSING
scope — an `init` block's calls belong to the class, exactly like the block's
other statements. The third is an accessor the grammar makes a following
SIBLING of the property rather than a child (same-line accessors nest, which
8b2e436 already covered); the property now claims its own-line accessors, and
the accessor branch skips what the property claimed. The skip re-derives the
property's kind instead of remembering it across nodes, so a destructured or
local declaration — which mints nothing and therefore claims nothing — keeps
falling through as before. No cross-node state in either arm.

The scope/kind decision moved into one function (`kotlinPropertyKind` /
`property_kind`) now that two branches need it.

Measured on the 113-file Android/Kotlin project, against upstream c65d56c:
0 lost refs, 0 re-attributed, +368 new. Kernel parity unchanged (99/113
byte-identical, same 14 grammar-deferred files as upstream).
…bol (colbymchenry#693 for Rust)

`const_item`/`static_item` ride extractVariable's generic fallback, which
minted the node and stopped — the initializer was never walked, so every call
inside it was missing from the graph:

    const LEN: usize = compute_len();                        // no caller
    static REGISTRY: Lazy<Cfg> = Lazy::new(|| build_cfg());  // no caller

That second shape is how once_cell/lazy_static singletons, handler tables and
static configs are written, so whatever they build looked unreferenced.

Fix: walk the `value` field through visitFunctionBody with the declared symbol
pushed on the scope stack. The fallback is shared, so the walk is gated to
Rust — the other languages on it spell their initializer differently and get
their own turn. The declared symbol is identified by the `name` FIELD, so the
phantom node the fallback also mints for a bare-identifier initializer
(`const MAX: u32 = OTHER;` → `MAX` plus a spurious `OTHER`) is left exactly as
it is: a separate defect, deliberately not folded in.

Measured on three Rust projects (gnss_rust, emmc-reader-gui,
bot_predlogka_rust — 282 files): 0 lost refs, 0 re-attributed, +86 new; node
and edge counts unchanged. Kernel parity holds (226/226 non-deferred files
byte-identical).
…he name (colbymchenry#693 for Python)

The assignment branch minted the node and stopped, so every call on the
right-hand side was missing from the graph:

    APP = compute()                    # no caller
    handler = lambda: target()         # no caller
    MAPPING = {"a": compute()}         # no caller
    first, second = compute(), f()     # no caller, and no symbol either

That is everything a module wires up at import time — `app = FastAPI()`,
`ENGINE = create_engine(url)`, `router = build_router()`, handler registries —
so whatever those build looked unreferenced.

Fix: walk the `right` field through visitFunctionBody with the assigned name
pushed on the scope stack. A tuple target mints no symbol, so its RHS is walked
at the enclosing scope rather than lost. Gated to Python — Ruby shares this
branch and gets its own turn.

Class attributes are untouched: they never reach this branch (the dispatcher's
class-scope gate excludes them), so their calls keep riding the class node.
Giving them symbols of their own is a separate question — there are no nodes
for them today at all.

A function-as-value in an initializer (`REGISTRY = {"org": Serializer}`) now
produces a reference from BOTH the assigned name and the file node, because the
dispatcher's own scan runs either way. That is the shape Go's colbymchenry#744 already
ships — verified against the Go arm on the same input — so the two languages
stay consistent; the function-ref test's expectation is updated to match.

Measured on three Python trees (libresdr, ADRC-betaflight,
bot_predlogka_big_project — 799 files): 0 lost refs, 0 re-attributed, +3057
new; node and edge counts unchanged. Kernel parity holds — 6221/6221 files
byte-identical across the sweep.
Port the raw-edge hasHeuristicEdge check into graph/named-symbol-flow.ts,
where upstream moved the token resolution explore shares with the viewer.
… code

Walking a declaration's initializer attributes its calls to the declared
name, so `const service = new Service()` no longer leaves a calls edge on
the FILE node — and the viewer's entry points ranking and the file screen's
top-level count, which read only the file node's edges, went blank on
exactly the files that run the most. Count a module-level variable or
constant's calls with the file in both places.
@bompus

bompus commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Verified on a real TypeScript repo (Chrome MV3 extension, 582 files, TS/JS/Vue/markdown, Windows 11, tree-sitter wasm walker, kernel off). Branch: this PR merged onto current main (b9ca4b7); control build indexed the same tree without the PR.

Merges clean onto main. On our tree: calls edges whose source is a variable/constant/property node 0 → 311, edges 33,927 → 34,133, nodes +4, no change to self-edge or import metrics. Samples look right: MESSAGE_HANDLERS -> getRecLock (handler map in a service worker), draftStateApplyLane -> createIdleLane, urgencyList -> ttdPriorityPctOf in a .vue <script setup>. PR test files: 652/652 pass.

danusha2345 added 2 commits September 8, 2026 11:18
…nitializer-walk

# Conflicts:
#	CHANGELOG.md
#	__tests__/fixtures/kernel-parity/torture.js
#	__tests__/fixtures/kernel-parity/torture.py
…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (3adf067, post-#1770) into this branch: head 752ddef. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
#	__tests__/fixtures/kernel-parity/torture.js
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (43271f3, post-#1771) into this branch: head fa69cbb. Conflicts were the CHANGELOG and the kernel-parity torture.js fixture (both fixture blocks kept). Kernel rebuilt; tsc clean; the branch's tests and the kernel parity suites pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (85550eb) into this branch: head f188330. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (8733c28) into this branch: head ff12a1f. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (8c04734) into this branch: head d7b657d. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (ee83636) into this branch: head 2997899. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (e720f6c) into this branch: head aaf9d4e. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (de5adba) into this branch: head 056f396. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (cece072) into this branch: head af098d9. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (040ba38) into this branch: head b26f888. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (374b3b4) into this branch: head c236fda. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

…nitializer-walk

# Conflicts:
#	CHANGELOG.md
@danusha2345

Copy link
Copy Markdown
Contributor Author

Merged current main (71d049c) into this branch: head d282f9e. The only conflict was the CHANGELOG entry; no source conflict. tsc clean, the branch's tests pass.

@colbymchenry

Copy link
Copy Markdown
Owner

Superseded by Forge land #1802, which squash-lands this branch (d282f9e8) onto current main as 9664bb7a (CHANGELOG condensed/credited; implementation, tests, fixtures and follow-ups retained).

Thanks @danusha2345 — Linux fail to pass verified across Kotlin, Java, TS/JS, Scala, Rust and Python (wasm + rebuilt native kernel) for #1510. Closing this PR as superseded.

@colbymchenry

Copy link
Copy Markdown
Owner

Superseded by #1802

colbymchenry added a commit that referenced this pull request Sep 8, 2026
…1802)

Squash danusha2345's PR #1511 at d282f9e onto main 8c9c476,
preserving its nine non-merge commits and main's existing Unreleased notes.
Calls in Kotlin, Java, TS/JS, Scala, Rust and Python declaration initializers
now retain the owner established by the upstream regression expectations.
Include the upstream CFML, dynamic-dispatch summary and viewer follow-ups.

Linux fail-to-pass validation (Node 22.19.0, rebuilt dist and native kernel):
- Before: TS load belonged to file:app.ts; Python/Kotlin/Scala/Rust calls
  vanished; Java lost the field-lambda, anonymous override and eager calls.
- After: all six languages PASS; 12 native/WASM LF/CRLF parity checks PASS.
- Focused initializer regressions: 10 passed with CODEGRAPH_KERNEL=0 and
  10 passed with the kernel enabled; Kotlin's grammar fallback is recorded.
- Related regression suites: 879 passed, 1 skipped across 15 test files.
- Evidence: /workspace/cg-1510-repro/before and /workspace/cg-1510-repro/after
  (combined test output: after/vitest.log).

Fixes #1510
Supersedes #1511

Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Declaration initializers are still unwalked (or unscoped) outside Go — #693 was fixed for Go only

3 participants