Skip to content

Commit 253f342

Browse files
Haofeiclaude
andcommitted
test(testgen): async channel pipeline (scheduler differential)
Generate a self-contained async program: a producer sends k values, a consumer receives exactly k (matched counts + buffered channel => no deadlock), counts them, and returns the count, which main prints. Exercises the cooperative scheduler, `task_group` / `async let`, `Channel`/`Sender`/`Receiver`, `await`, `take`, and `?` end-to-end across every backend — including the compiled-Rust lowering. Completion and the printed count are deterministic, so it is safe for the value differential (this is the determinism guard the plan called for). Smoke (>=95% accept, vm==jit) and full N-way incl. compiled (50 cases) green. Note: while building this, the framework surfaced a minor lowering bug — a source file named after a Rust keyword (e.g. `async.rss`) lowers to `async::main()`, invalid Rust. Not triggered by the generator (it uses non-keyword names); filed for a separate fix (sanitize keyword module names). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 4194c48 commit 253f342

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

crates/rss-testgen/src/generator.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ impl<'a> Generator<'a> {
9898
// -- top level -------------------------------------------------------
9999

100100
fn program(&mut self) -> GeneratedProgram {
101+
// Occasionally emit a self-contained async channel pipeline instead.
102+
if self.seed.choice(5) == 0 {
103+
return self.gen_async_program();
104+
}
105+
101106
// Always declare `features: local` so generated `local` bindings are
102107
// allowed; the feature is harmless when unused.
103108
let mut source = String::from("features: local\n\n");
@@ -139,6 +144,54 @@ impl<'a> Generator<'a> {
139144
}
140145
}
141146

147+
/// A self-contained async channel pipeline: a producer sends `k` values, a
148+
/// consumer receives exactly `k` (so there is no deadlock), counts them, and
149+
/// returns the count, which `main` prints. Exercises the cooperative
150+
/// scheduler, `task_group` / `async let`, channels, `await`, and `?` across
151+
/// every backend. Send/receive counts are matched and the channel is buffered
152+
/// (capacity >= k), so completion and the printed count are deterministic.
153+
fn gen_async_program(&mut self) -> GeneratedProgram {
154+
let k = 1 + self.seed.choice(4); // 1..=4 items
155+
156+
let mut produce = String::from(
157+
"async fn produce(sender: read Sender<Int>) -> Result<Unit, ChannelError> {\n",
158+
);
159+
for i in 0..k {
160+
let value = self.seed.range_i64(0, 1000);
161+
produce.push_str(&format!(" local s{i} = {value}\n"));
162+
produce.push_str(&format!(
163+
" await Sender.send(sender: read sender, value: take s{i})?\n"
164+
));
165+
}
166+
produce.push_str(" return Ok(Unit)\n}\n\n");
167+
168+
let mut consume = String::from(
169+
"async fn consume(receiver: read Receiver<Int>) -> Result<Int, ChannelError> {\n let mut n = 0\n",
170+
);
171+
for _ in 0..k {
172+
consume.push_str(" let _ = await Receiver.recv(receiver: read receiver)?\n");
173+
consume.push_str(" n = n + 1\n");
174+
}
175+
consume.push_str(" return Ok(n)\n}\n\n");
176+
177+
let main = "fn main() -> Result<Unit, ChannelError> {\n \
178+
let mut channel = Channel.bounded<Int>(capacity: 4)?\n \
179+
let sender = Channel.sender(channel: read channel)\n \
180+
let receiver = Channel.receiver(channel: mut channel)?\n \
181+
task_group {\n \
182+
async let producer = produce(sender: read sender)\n \
183+
async let consumer = consume(receiver: read receiver)\n \
184+
await producer?\n \
185+
let count = await consumer?\n \
186+
Log.write(message: read String.from_int(value: count))\n }\n \
187+
return Ok(Unit)\n}\n";
188+
189+
GeneratedProgram {
190+
source: format!("features: async, local\n\n{produce}{consume}{main}"),
191+
is_async: true,
192+
}
193+
}
194+
142195
// -- type declarations -----------------------------------------------
143196

144197
fn gen_struct_decl(&mut self, index: usize, out: &mut String) -> StructDef {

0 commit comments

Comments
 (0)