Issue #851: lowering: .trim().to_string() stays ref String, process::run rejects it as Vec[String] (NK1102)

Open and answer this issue on GitHub.

decision · opened 2026-10-25 · updated 2026-10-29 · 1 comment

Part of #847 (found by step 2). Reproduced on 0.0.1222.

Probe.

use std::process
fn main() throws {
    let a = "  x ".trim().to_string()
    let o = process::run("echo", [a])
    println(o.stdout)
}

nikaia run gives NK1102: process::run expects args to be Vec[String], but you're passing Vec[ref String]. .trim().clone() is accepted.

Why it is a defect. to_string() names an owned String; its result must not stay a ref. Either to_string on a ref String returns ref String (wrong), or the list literal [a] takes the type of the view it came from.

To build.

  1. Find which of the two it is (nikaia check on a variant with let b: String = a).
  2. Fix in the compiler so to_string() yields String.
  3. Test tests/compiler/tests/to_string_owned.nika with the probe; delete any .clone() workaround in scripts/agent.nika that exists because of this.

Comments

keywan-ghadami, 2026-10-29

The same defect, reached through the checker: .to_string() of a view keeps the view’s type when it stands in a tuple literal, but not in a plain let or a list literal.

Probe (nikaia run p.nika):

comptime A: ref String = "a"
fn f(s: ref String) -> Vec[(String, String)] {
    return [(s.to_string(), "b")]      // NK1104: Vec[(ref String, String)]
}
fn h() -> (String, String) {
    return (A.to_string(), "b")        // NK1104: (ref String, String)
}
fn k() -> Vec[String] {
    return [A.to_string()]             // passes
}
fn g() -> Vec[(String, String)] {
    return [(A.clone(), "b")]          // passes
}
fn main() {}

The expected result is that all four pass, since to_string() gives text of its own. This comes up in rs2nika drafts: every (CONST.to_string(), ..) pair the converter writes is refused.

To build (in addition to the list above):


Generated by Claude Code

Back to Open Issues