# XO0538: a variable written after a closure captured it

Reported by `xo vet`, not `xo check`. `let root = fn(k) { .. up[k] .. }` copies `up` when the closure is created. A later `up[i] = x`, `up = ..`, or `up.push(..)` in the enclosing function changes `up` but not the closure's copy, so every later call of `root` walks the old value. Found as the union find bug of the arm64 SLP pass (2026-10-21), where every pack stayed its own group. The check fires for a `let name = fn(..) { .. }` whose body reads a `var` local, a write to that local in a later statement of the same block, and a use of `name` after the write. Pass the variable as a parameter (`fn(k, up)`), or move the closure after the writes. See core 5.1.

## Example

```xo
fn groups(n: Int) -> Int {
  var up: List[Int] = [0, 1, 2]
  let root = fn(k: Int) -> Int { up[k] }
  up[0] = 2
  root(0)
}
```

## Fix

```xo
fn groups(n: Int) -> Int {
  var up: List[Int] = [0, 1, 2]
  up[0] = 2
  let root = fn(k: Int) -> Int { up[k] }
  root(0)
}
```

Run `xo explain XO0538` for this text in a terminal, or see
[section 10.6 of the specification](../../spec/core/#106-diagnostic-codes).

