Skip to content

Commit 4194c48

Browse files
Haofeiclaude
andcommitted
test(testgen): local bindings + Counter resource (effects/resources slice)
Always emit a `features: local` header (harmless when unused) so the generator can use the `local` binding kind for immutable scalars, and add a `Counter` resource tier: create, `Counter.add` via `mut` receiver a few times, observe the final value. Both are backend-deterministic and exercise the local binding kind and runtime-backed mutable-resource lowering across every backend. Smoke (>=95% accept, vm==jit) and full N-way incl. compiled (40 cases) green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 18ce182 commit 4194c48

1 file changed

Lines changed: 30 additions & 3 deletions

File tree

crates/rss-testgen/src/generator.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ impl<'a> Generator<'a> {
9898
// -- top level -------------------------------------------------------
9999

100100
fn program(&mut self) -> GeneratedProgram {
101-
let mut source = String::new();
101+
// Always declare `features: local` so generated `local` bindings are
102+
// allowed; the feature is harmless when unused.
103+
let mut source = String::from("features: local\n\n");
102104

103105
let struct_count = self.seed.choice(3); // 0..=2
104106
for index in 0..struct_count {
@@ -377,7 +379,7 @@ impl<'a> Generator<'a> {
377379
fn gen_stmt(&mut self, scope: &mut Scope) -> String {
378380
// Bias toward lets; sometimes assign, a `?`-unwrap, or a populated
379381
// collection.
380-
match self.seed.weighted(&[6, 2, 2, 3, 2, 1]) {
382+
match self.seed.weighted(&[6, 2, 2, 3, 2, 1, 2]) {
381383
0 => self.gen_let(scope),
382384
1 => self
383385
.gen_assign(scope)
@@ -388,8 +390,29 @@ impl<'a> Generator<'a> {
388390
.unwrap_or_else(|| self.gen_let(scope)),
389391
3 => self.gen_collection_stmt(scope),
390392
4 => self.gen_closure_stmt(scope),
391-
_ => self.gen_cancellation_stmt(),
393+
5 => self.gen_cancellation_stmt(),
394+
_ => self.gen_counter_stmt(),
395+
}
396+
}
397+
398+
/// A `Counter` resource: create, add a few times, observe the value. A
399+
/// runtime-backed mutable resource whose final value is deterministic, so it
400+
/// exercises resource construction / `mut` receiver calls across backends.
401+
fn gen_counter_stmt(&mut self) -> String {
402+
let counter = self.fresh_var();
403+
let start = self.seed.range_i64(0, 1000);
404+
let mut lines = vec![format!("let {counter} = Counter.new(value: {start})")];
405+
let adds = self.seed.choice(3); // 0..=2
406+
for _ in 0..adds {
407+
let amount = self.seed.range_i64(0, 1000);
408+
lines.push(format!(
409+
"Counter.add(counter: mut {counter}, amount: {amount})"
410+
));
392411
}
412+
lines.push(format!(
413+
"Log.write(message: read String.from_int(value: Counter.value(counter: read {counter})))"
414+
));
415+
lines.join("\n ")
393416
}
394417

395418
/// Deterministic concurrency primitive: create a `CancellationSource`, observe
@@ -582,6 +605,10 @@ impl<'a> Generator<'a> {
582605
let mut_kw = if mutable { "mut " } else { "" };
583606
if annotate {
584607
format!("let {mut_kw}{name}: {} = {expr}", ty.render())
608+
} else if !mutable && ty.is_scalar() && self.seed.choice(3) == 0 {
609+
// Exercise the `local` binding kind for an immutable scalar (copyable,
610+
// so it can still be read/returned without escaping a resource).
611+
format!("local {name} = {expr}")
585612
} else {
586613
format!("let {mut_kw}{name} = {expr}")
587614
}

0 commit comments

Comments
 (0)