let mut c = a.clone() of a struct: assigning owned text to c.field is NK1105 (ref String)Open and answer this issue on GitHub.
ready · opened 2026-10-27 · updated 2026-10-27 · 0 comments
struct Ctx {
name: String,
n: i64,
}
fn main() {
let a = Ctx { name: "a", n: 1 }
let mut c = a.clone()
let t: String = f"x{a.n}"
c.name = t
println(f"{a.name} {c.name}")
}
nikaia run refuses it:
error[NK1105]: You're assigning `String` to something that holds `ref String`.
c.name = t
Expected: the program prints a x1.
let mut c: Ctx = a.clone() (with the type written): accepted, prints the right line.c.name = "b" (a literal): accepted.c.name = t, c.name = to.clone(), c.name = f"{to}!": all refused. It is the same when a is a ref Ctx parameter (fn f(given: ref Ctx, to: String) -> Ctx { let mut c = given.clone(); c.name = to; return c }).So the binding that let mut c = a.clone() makes, untyped, is typed as a view of Ctx, and its fields read as ref String. check_core_call_on_owned hands back the owned type for .clone() of a declared type (check_core_call_on.nika:168). The view must therefore come from the let (check_core_stmt.nika around 550-592: lent_lets, lent_arms_bound, views_meet_owned_text) or from a lent-clone analysis that does not count a write to a field of the binding as a write.
Found while splitting rs2nika_convert into a load step and a pure step, which runs under par_iter (crates/rs2nika/convert/src/main.nika, rs2nika_convert_in). There the binding is written with its type, as every binding in that file is.
tests/compiler/tests/a_field_of_an_untyped_clone_takes_owned_text.nika with the probe and its .stdout.let mut c = a.clone() becomes a view, and fix it there: a binding whose field is assigned owned text owns its value.