match (ref s.field, b) with slice patterns, and name.to_string() of a view parameter, fail in rustcOpen and answer this issue on GitHub.
ready · opened 2026-10-27 · updated 2026-10-27 · 3 comments
I found these while compiling the rs2nika drafts of attributes and seeds (converter corpus). The checker accepts all of them, and the generated Rust fails.
struct A { args: Vec[i64] }
fn f(a: ref A, b: bool) -> String {
return match (ref a.args, b) {
([], true) => "none",
([x], true) => f"one {x}",
else => "more",
}
}
fn main() { println(f(A { args: [3] }, true)) }
nikaia run stops with Expected an array or slice, found Vec<i64>. The lowering writes &a.args where the slice pattern needs &a.args[..], or .as_slice().ref, the program gets NK2106: a.args is put into a tuple, but a is only borrowed. That is the right refusal.match (xs, b) with xs: ref Vec[i64]), it works.rs2nika now writes match (ref xs, b) for Rust’s match (&xs[..], b) (R187).
.to_string() of a String view parameter, stored in a structstruct B { name: String, held: Vec[String] }
fn add(mut bodies: Vec[B], name: String, args: ref Vec[String]) {
let held: Vec[String] = args.iter().filter(fn(a) { a.len() > 0 }).map(fn(a) { a.clone() }).collect()
if !held.is_empty() {
bodies.push(B { name: name.to_string(), held })
}
}
fn main() { let mut bs: Vec[B] = []; add(bs, "x", ["a"]); println(bs[0].name) }
name.clone() and plain name both compile. The to_string gives a view where an owned String is needed..to_string() on a String parameter (R183). The defect stays a compiler one.Seq::chainT?.iter() (an option as a sequence of zero or one)BTreeSet::clearref place matched by a slice pattern lowers to a slice (&x[..]), in a tuple and alone. Test tests/compiler/tests/ for probe 1..to_string() on a String value yields an owned String. Test for probe 2.chain, iter() on T?, BTreeSet::clear, each with a test.One more from the defaults draft: a filter_map closure is lowered without Some(..). The checker accepts each of these, and rustc refuses them:
let xs: Vec[i64?] = [1, null, 3]
let ys: Vec[i64] = xs.iter().filter_map(fn(x) { let v = x ?? return null; v * 2 }).collect()
// Mismatched types: expected Option<_>, found i64 (the same with `return v * 2`)
let zs: Vec[i64] = xs.iter().filter_map(fn(x) { x }).collect()
// expected Option<_>, found &Option<i64>
Seq::filter_map is in std.contracts, but no tools file uses it yet.
To build, step 4: a closure whose result is T? wraps its non-null results, both the tail and each return, in Some, and copies a borrowed T?. Test the probe above.
Generated by Claude Code
Two more from the emit_seeds draft (corpus case seeds), 2026-10-27:
collections::BTreeSet has no clear (NK1171), although maps.nika lists clear for maps. Rust’s self.private.clear() has no Nikaia spelling but = collections::BTreeSet().ref T? parameter or pattern binding is not narrowed by x != null (ADR-382): filed as #898. The converter’s R205 (A.chain(x.iter()).any(F) -> A.any(F) || (x != null && F(x))) depends on it.Seq::chain itself is now routed around by the converter only for any/all (R205); for x in a.chain(b) and .chain(..).collect() still need it.
Generated by Claude Code
One more std gap for step 3, found in the attributes draft: BTreeSet::iter(). self.places.iter().map(fn(x) { x.clone() }).collect().join(", ") on a collections::BTreeSet[String] stops with NK1171 (collections::BTreeSet has no method called iter). The std ledger knows contains, insert, remove, len, is_empty, first, last, union, difference, intersection and clone, but no iter and no clear.
So step 3 now covers: chain, iter() on T?, BTreeSet::clear and BTreeSet::iter (in order, like for x in set). Each needs a test.
Generated by Claude Code