Skip to content

Commit 18ce182

Browse files
Haofeiclaude
andcommitted
test(testgen): deterministic cancellation concurrency primitives
Generate `CancellationSource`/`CancellationToken` usage: create a source, observe its token is not cancelled, cancel it, observe it is. Both observations are backend-deterministic (synchronous, no scheduler/timing), exercising the cancellation runtime objects' lowering across every backend. A safe slice of the concurrency surface; the scheduler-driven async subset (spawn/await/channels, needing a `features: async` header and determinism guards) remains future work. 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 a80f449 commit 18ce182

1 file changed

Lines changed: 26 additions & 2 deletions

File tree

crates/rss-testgen/src/generator.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ impl<'a> Generator<'a> {
377377
fn gen_stmt(&mut self, scope: &mut Scope) -> String {
378378
// Bias toward lets; sometimes assign, a `?`-unwrap, or a populated
379379
// collection.
380-
match self.seed.weighted(&[6, 2, 2, 3, 2]) {
380+
match self.seed.weighted(&[6, 2, 2, 3, 2, 1]) {
381381
0 => self.gen_let(scope),
382382
1 => self
383383
.gen_assign(scope)
@@ -387,10 +387,34 @@ impl<'a> Generator<'a> {
387387
.or_else(|| self.gen_assign(scope))
388388
.unwrap_or_else(|| self.gen_let(scope)),
389389
3 => self.gen_collection_stmt(scope),
390-
_ => self.gen_closure_stmt(scope),
390+
4 => self.gen_closure_stmt(scope),
391+
_ => self.gen_cancellation_stmt(),
391392
}
392393
}
393394

395+
/// Deterministic concurrency primitive: create a `CancellationSource`, observe
396+
/// its token is not cancelled, cancel it, observe it is. Both observations are
397+
/// backend-deterministic (no scheduler/timing), exercising the cancellation
398+
/// runtime objects' lowering across backends.
399+
fn gen_cancellation_stmt(&mut self) -> String {
400+
let source = self.fresh_var();
401+
let token = self.fresh_var();
402+
let observe = |token: &str| {
403+
format!(
404+
"Log.write(message: read String.from_bool(value: \
405+
CancellationToken.is_cancelled(token: read {token})))"
406+
)
407+
};
408+
[
409+
format!("let mut {source} = CancellationSource.new()"),
410+
format!("let {token} = CancellationSource.token(source: read {source})"),
411+
observe(&token),
412+
format!("CancellationSource.cancel(source: mut {source})"),
413+
observe(&token),
414+
]
415+
.join("\n ")
416+
}
417+
394418
/// Build a populated `List<T>` and `List.filter` it with a capture-free
395419
/// closure predicate, observing the filtered length. Exercises closure
396420
/// lowering (parameter, body, `noescape Fn(T) -> Bool`) without capturing

0 commit comments

Comments
 (0)