Issue #896: Lowering: match (ref s.field, b) with slice patterns, and name.to_string() of a view parameter, fail in rustc

Open 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.

1. A slice pattern over a borrowed field inside a tuple

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)) }

rs2nika now writes match (ref xs, b) for Rust’s match (&xs[..], b) (R187).

2. .to_string() of a String view parameter, stored in a struct

struct 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) }

3. std gaps the drafts hit

To build

  1. Lowering: a ref place matched by a slice pattern lowers to a slice (&x[..]), in a tuple and alone. Test tests/compiler/tests/ for probe 1.
  2. Lowering: .to_string() on a String value yields an owned String. Test for probe 2.
  3. std: chain, iter() on T?, BTreeSet::clear, each with a test.

Comments

keywan-ghadami, 2026-10-27

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

keywan-ghadami, 2026-10-27

Two more from the emit_seeds draft (corpus case seeds), 2026-10-27:

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

keywan-ghadami, 2026-10-27

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

Back to Open Issues