Xo is experimental. The source is now public on GitHub, or try Xo in your browser.
Menu · XO1107

Docs

XO1107: List, Map or Set given to Go as any is a copy

warning · reported by the checker

Xo passes a List, Map or Set to Go by converting it to a Go slice or map: Go gets a copy. A Go function that changes its argument in place (json.unmarshal into the value, fmt.sscan, sort.slice, a decoder or a filler) changes that copy, and the Xo value stays as it was. xo check reports it where the value is given as Go’s any: go.any(xs) written for an any parameter, or an element of a list literal for a ...any parameter. It is not reported for a call of a Go function known only to read its argument, the reviewed list in compiler/check/goreads.xo: encoding/json and encoding/xml’s marshal and encoders, fmt’s print family, log and log/slog, zap’s field constructors (zap.any, zap.reflect, the sugared logger’s …w methods), database/sql’s query arguments, and text/template and html/template’s execute. For a function that changes the value, take the result Go returns, or pass go.out[T]()’s .any() and read .get() after the call. For another call that only reads, silence it with // xo:allow XO1107 <reason> on the line or the line above; a Go function that should join the list goes in goreads.xo with internal/gobind TestGoReadsList. See core 4.4 and decision 0491.

Example

use go "encoding/json"
use std/go

fn load(b: Bytes) -> List[Int] uses go {
  var xs: List[Int] = []
  json.unmarshal(b, go.any(xs)).ignore_err("example")
  xs
}

Fix

use go "encoding/json"
use std/go

fn load(b: Bytes) -> List[Int] uses go {
  let out = go.out[List[Int]]()
  json.unmarshal(b, out.any()).ignore_err("example")
  out.get()
}

Run xo explain XO1107 for this text in a terminal, or see section 10.6 of the specification.