Update code to use `set` for assignment

d3dd0b64dde55c9c77b6d2b9f4e8f1bed588b9cbbb88c10937cec60f3f98412f
Alexis Sellier committed ago 1 parent 3b92f411
compiler/radiance.rad +33 -33
197 197
    };
198 198
}
199 199
200 200
/// Consume the next argument, or print an error and throw.
201 201
fn nextArg(args: *[*[u8]], idx: *mut u32, msg: *[u8]) -> *[u8] throws (Error) {
202 -
    *idx += 1;
202 +
    set *idx += 1;
203 203
    if *idx >= args.len {
204 204
        io::printError(msg);
205 205
        throw Error::Other;
206 206
    }
207 207
    return args[*idx];
224 224
    let mut pkgNames: [*[u8]; MAX_PACKAGES] = undefined;
225 225
    let mut pkgCount: u32 = 0;
226 226
    let mut currentPkgIdx: ?u32 = nil;
227 227
228 228
    for i in 0..MAX_PACKAGES {
229 -
        moduleCounts[i] = 0;
229 +
        set moduleCounts[i] = 0;
230 230
    }
231 231
    if args.len == 0 {
232 232
        io::printError(USAGE);
233 233
        throw Error::Other;
234 234
    }
240 240
            try nextArg(args, &mut idx, "radiance: `-pkg` requires a package name\n");
241 241
            if pkgCount >= MAX_PACKAGES {
242 242
                io::printError("radiance: too many packages specified\n");
243 243
                throw Error::Other;
244 244
            }
245 -
            pkgNames[pkgCount] = args[idx];
246 -
            currentPkgIdx = pkgCount;
247 -
            pkgCount += 1;
245 +
            set pkgNames[pkgCount] = args[idx];
246 +
            set currentPkgIdx = pkgCount;
247 +
            set pkgCount += 1;
248 248
        } else if mem::eq(arg, "-mod") {
249 249
            try nextArg(args, &mut idx, "radiance: `-mod` requires a module path\n");
250 250
            let pkgIdx = currentPkgIdx else {
251 251
                io::printError("radiance: `-mod` must follow a `-pkg` argument\n");
252 252
                throw Error::Other;
253 253
            };
254 254
            if moduleCounts[pkgIdx] >= MAX_LOADED_MODULES {
255 255
                io::printError("radiance: too many modules specified for package\n");
256 256
                throw Error::Other;
257 257
            }
258 -
            modulePaths[pkgIdx][moduleCounts[pkgIdx]] = args[idx];
259 -
            moduleCounts[pkgIdx] += 1;
258 +
            set modulePaths[pkgIdx][moduleCounts[pkgIdx]] = args[idx];
259 +
            set moduleCounts[pkgIdx] += 1;
260 260
        } else if mem::eq(arg, "-entry") {
261 261
            try nextArg(args, &mut idx, "radiance: `-entry` requires a package name\n");
262 -
            entryPkgName = args[idx];
262 +
            set entryPkgName = args[idx];
263 263
        } else if mem::eq(arg, "-test") {
264 -
            buildTest = true;
264 +
            set buildTest = true;
265 265
        } else if mem::eq(arg, "-debug") {
266 -
            debugEnabled = true;
266 +
            set debugEnabled = true;
267 267
        } else if mem::eq(arg, "-o") {
268 268
            try nextArg(args, &mut idx, "radiance: `-o` requires an output path\n");
269 -
            outputPath = args[idx];
269 +
            set outputPath = args[idx];
270 270
        } else if mem::eq(arg, "-dump") {
271 271
            try nextArg(args, &mut idx, "radiance: `-dump` requires a mode (eg. ast)\n");
272 272
            let mode = args[idx];
273 273
            if mem::eq(mode, "ast") {
274 -
                dump = Dump::Ast;
274 +
                set dump = Dump::Ast;
275 275
            } else if mem::eq(mode, "graph") {
276 -
                dump = Dump::Graph;
276 +
                set dump = Dump::Graph;
277 277
            } else if mem::eq(mode, "il") {
278 -
                dump = Dump::Il;
278 +
                set dump = Dump::Il;
279 279
            } else if mem::eq(mode, "asm") {
280 -
                dump = Dump::Asm;
280 +
                set dump = Dump::Asm;
281 281
            } else {
282 282
                io::printError("radiance: unknown dump mode `");
283 283
                io::printError(mode);
284 284
                io::printError("` (expected: ast, graph, il, asm)\n");
285 285
                throw Error::Other;
288 288
            io::printError("radiance: unknown argument `");
289 289
            io::printError(arg);
290 290
            io::printError("`\n");
291 291
            throw Error::Other;
292 292
        }
293 -
        idx += 1;
293 +
        set idx += 1;
294 294
    }
295 295
    if pkgCount == 0 {
296 296
        io::printError("radiance: no package specified\n");
297 297
        throw Error::Other;
298 298
    }
299 299
300 300
    // Determine entry package index.
301 301
    let mut entryPkgIdx: ?u32 = nil;
302 302
    if pkgCount == 1 {
303 303
        // Single package: it is the entry.
304 -
        entryPkgIdx = 0;
304 +
        set entryPkgIdx = 0;
305 305
    } else {
306 306
        // Multiple packages: need -entry.
307 307
        let entryName = entryPkgName else {
308 308
            io::printError("radiance: `-entry` required when multiple packages specified\n");
309 309
            throw Error::Other;
310 310
        };
311 311
        for i in 0..pkgCount {
312 312
            if mem::eq(pkgNames[i], entryName) {
313 -
                entryPkgIdx = i;
313 +
                set entryPkgIdx = i;
314 314
                break;
315 315
            }
316 316
        }
317 317
        if entryPkgIdx == nil {
318 318
            io::printError("radiance: fatal: entry package `");
476 476
    for i in 1..path.len {
477 477
        let child = ast::synthNode(
478 478
            arena,
479 479
            ast::NodeValue::Ident(strings::intern(&mut STRING_POOL, path[i]))
480 480
        );
481 -
        result = ast::synthNode(arena, ast::NodeValue::ScopeAccess(ast::Access {
481 +
        set result = ast::synthNode(arena, ast::NodeValue::ScopeAccess(ast::Access {
482 482
            parent: result, child,
483 483
        }));
484 484
    }
485 485
    return result;
486 486
}
513 513
514 514
    for stmt in block.statements {
515 515
        if let case ast::NodeValue::FnDecl(decl) = stmt.value {
516 516
            if let fnName = getTestFnName(&decl) {
517 517
                if *testCount < tests.len {
518 -
                    tests[*testCount] = TestDesc { modPath, fnName };
519 -
                    *testCount += 1;
518 +
                    set tests[*testCount] = TestDesc { modPath, fnName };
519 +
                    set *testCount += 1;
520 520
                } else {
521 521
                    panic "collectModuleTests: too many tests";
522 522
                }
523 523
            }
524 524
        }
537 537
    let nameArg = ast::synthNode(arena, ast::NodeValue::String(desc.fnName));
538 538
539 539
    // Intra-package path: skip the package name prefix.
540 540
    let mut funcPath: [*[u8]; 16] = undefined;
541 541
    for j in 1..desc.modPath.len {
542 -
        funcPath[j - 1] = desc.modPath[j];
542 +
        set funcPath[j - 1] = desc.modPath[j];
543 543
    }
544 -
    funcPath[desc.modPath.len - 1] = desc.fnName;
544 +
    set funcPath[desc.modPath.len - 1] = desc.fnName;
545 545
    let funcArg = synthScopeAccess(arena, &funcPath[..desc.modPath.len]);
546 546
547 547
    let a = alloc::arenaAllocator(&mut arena.arena);
548 548
    let args = ast::nodeSlice(arena, 3)
549 549
        .append(modArg, a)
654 654
) {
655 655
    let case ast::NodeValue::Block(block) = blockNode.value else {
656 656
        panic "injectIntoBlock: expected Block node";
657 657
    };
658 658
    let stmts = block.statements.append(decl, alloc::arenaAllocator(&mut arena.arena));
659 -
    blockNode.value = ast::NodeValue::Block(ast::Block { statements: stmts });
659 +
    set blockNode.value = ast::NodeValue::Block(ast::Block { statements: stmts });
660 660
}
661 661
662 662
/// Write code buffer to file as raw bytes.
663 663
fn writeCode(code: *[u32], path: *[u8]) -> bool {
664 664
    // Convert `u32` slice to `u8` slice (little-endian).
680 680
        return;
681 681
    }
682 682
    let mut path: [u8; MAX_PATH_LEN] = undefined;
683 683
    let mut pos: u32 = 0;
684 684
685 -
    pos += try! mem::copy(&mut path[pos..], basePath);
686 -
    pos += try! mem::copy(&mut path[pos..], ext);
687 -
    path[pos] = 0; // Null-terminate for syscall.
685 +
    set pos += try! mem::copy(&mut path[pos..], basePath);
686 +
    set pos += try! mem::copy(&mut path[pos..], ext);
687 +
    set path[pos] = 0; // Null-terminate for syscall.
688 688
689 689
    if not unix::writeFile(&path[..pos], data) {
690 690
        io::printError("radiance: fatal: failed to write data file\n");
691 691
        throw Error::Other;
692 692
    }
711 711
    for i in 0..entries.len {
712 712
        let entry = &entries[i];
713 713
        let modEntry = module::get(graph, entry.moduleId) else {
714 714
            panic "writeDebugInfo: module not found for debug entry";
715 715
        };
716 -
        pos += try! mem::copy(&mut buf[pos..], @sliceOf(&entry.pc as *u8, 4));
717 -
        pos += try! mem::copy(&mut buf[pos..], @sliceOf(&entry.offset as *u8, 4));
718 -
        pos += try! mem::copy(&mut buf[pos..], modEntry.filePath);
716 +
        set pos += try! mem::copy(&mut buf[pos..], @sliceOf(&entry.pc as *u8, 4));
717 +
        set pos += try! mem::copy(&mut buf[pos..], @sliceOf(&entry.offset as *u8, 4));
718 +
        set pos += try! mem::copy(&mut buf[pos..], modEntry.filePath);
719 719
720 -
        buf[pos] = 0;
721 -
        pos += 1;
720 +
        set buf[pos] = 0;
721 +
        set pos += 1;
722 722
    }
723 723
    try writeDataWithExt(&buf[..pos], basePath, DEBUG_EXT);
724 724
}
725 725
726 726
/// Run the resolver on the parsed modules.
745 745
    let mut packages: [resolver::Pkg; MAX_PACKAGES] = undefined;
746 746
    for i in 0..ctx.packageCount {
747 747
        let pkg = &ctx.packages[i];
748 748
        let root = try getRootModule(pkg, &ctx.graph);
749 749
750 -
        packages[i] = resolver::Pkg {
750 +
        set packages[i] = resolver::Pkg {
751 751
            rootEntry: root.entry,
752 752
            rootAst: root.ast,
753 753
        };
754 754
    }
755 755
lib/std/arch/rv64.rad +1 -1
197 197
198 198
    // Emit placeholder entry jump to default function if there is one.
199 199
    // We'll patch this at the end once we know where the function is.
200 200
    let mut defaultName: ?*[u8] = nil;
201 201
    if let defIdx = program.defaultFnIdx {
202 -
        defaultName = program.fns[defIdx].name;
202 +
        set defaultName = program.fns[defIdx].name;
203 203
        emit::emit(&mut e, encode::nop()); // Placeholder for two-instruction jump.
204 204
        emit::emit(&mut e, encode::nop()); //
205 205
    }
206 206
207 207
    // Generate code for all functions.
lib/std/arch/rv64/emit.rad +20 -20
151 151
    let savedRegs = mem::popCount(usedCalleeSaved) + 2;
152 152
    let totalSize = mem::alignUpI32(
153 153
        localSize + savedRegs * super::DWORD_SIZE,
154 154
        super::STACK_ALIGNMENT
155 155
    );
156 -
    frame.totalSize = totalSize;
156 +
    set frame.totalSize = totalSize;
157 157
158 158
    // Build list of callee-saved registers with offsets.
159 159
    let mut offset = totalSize - (super::DWORD_SIZE * 3);
160 160
    for reg, i in super::CALLEE_SAVED {
161 161
        // Check if this register is in use.
162 162
        if (usedCalleeSaved & (1 << i)) <> 0 {
163 -
            frame.savedRegs[frame.savedRegsLen] = SavedReg {
163 +
            set frame.savedRegs[frame.savedRegsLen] = SavedReg {
164 164
                reg,
165 165
                offset,
166 166
            };
167 -
            frame.savedRegsLen += 1;
168 -
            offset -= super::DWORD_SIZE;
167 +
            set frame.savedRegsLen += 1;
168 +
            set offset -= super::DWORD_SIZE;
169 169
        }
170 170
    }
171 171
    return frame;
172 172
}
173 173
181 181
    let funcEntries = try alloc::allocSlice(arena, @sizeOf(dict::Entry), @alignOf(dict::Entry), labels::FUNC_TABLE_SIZE);
182 182
    let funcs = try alloc::allocSlice(arena, @sizeOf(types::FuncAddr), @alignOf(types::FuncAddr), MAX_FUNCS);
183 183
184 184
    let mut debugEntries: *mut [types::DebugEntry] = &mut [];
185 185
    if debug {
186 -
        debugEntries = try alloc::allocSlice(
186 +
        set debugEntries = try alloc::allocSlice(
187 187
            arena, @sizeOf(types::DebugEntry), @alignOf(types::DebugEntry), MAX_DEBUG_ENTRIES
188 188
        ) as *mut [types::DebugEntry];
189 189
    }
190 190
    return Emitter {
191 191
        code: code as *mut [u32],
209 209
///////////////////////
210 210
211 211
/// Emit a single instruction.
212 212
export fn emit(e: *mut Emitter, instr: u32) {
213 213
    assert e.codeLen < e.code.len, "emit: code buffer full";
214 -
    e.code[e.codeLen] = instr;
215 -
    e.codeLen += 1;
214 +
    set e.code[e.codeLen] = instr;
215 +
    set e.codeLen += 1;
216 216
}
217 217
218 218
/// Compute branch offset to a function by name.
219 219
export fn branchOffsetToFunc(e: *Emitter, srcIndex: u32, name: *[u8]) -> i32 {
220 220
    return labels::branchToFunc(&e.labels, srcIndex, name, super::INSTR_SIZE);
221 221
}
222 222
223 223
/// Patch an instruction at a given index.
224 224
export fn patch(e: *mut Emitter, index: u32, instr: u32) {
225 -
    e.code[index] = instr;
225 +
    set e.code[index] = instr;
226 226
}
227 227
228 228
/// Record a block's address for branch resolution.
229 229
export fn recordBlock(e: *mut Emitter, blockIdx: u32) {
230 230
    assert e.codeLen <= MAX_CODE_LEN;
238 238
}
239 239
240 240
/// Record a function's start position for printing.
241 241
export fn recordFunc(e: *mut Emitter, name: *[u8]) {
242 242
    assert e.funcsLen < e.funcs.len, "recordFunc: funcs buffer full";
243 -
    e.funcs[e.funcsLen] = types::FuncAddr { name, index: e.codeLen };
244 -
    e.funcsLen += 1;
243 +
    set e.funcs[e.funcsLen] = types::FuncAddr { name, index: e.codeLen };
244 +
    set e.funcsLen += 1;
245 245
}
246 246
247 247
/// Record a local branch needing later patching.
248 248
/// Unconditional jumps use a single slot (J-type, +-1MB range).
249 249
/// Conditional branches use two slots (B-type has only +-4KB range,
250 250
/// so large functions may need the inverted-branch + JAL fallback).
251 251
export fn recordBranch(e: *mut Emitter, targetBlock: u32, kind: BranchKind) {
252 252
    assert e.pendingBranchesLen < e.pendingBranches.len, "recordBranch: buffer full";
253 -
    e.pendingBranches[e.pendingBranchesLen] = PendingBranch {
253 +
    set e.pendingBranches[e.pendingBranchesLen] = PendingBranch {
254 254
        index: e.codeLen,
255 255
        target: targetBlock,
256 256
        kind: kind,
257 257
    };
258 -
    e.pendingBranchesLen += 1;
258 +
    set e.pendingBranchesLen += 1;
259 259
260 260
    emit(e, encode::nop()); // First slot, always needed.
261 261
262 262
    match kind {
263 263
        case BranchKind::Jump => {},
268 268
/// Record a function call needing later patching.
269 269
/// Emits placeholder instructions that will be patched later.
270 270
/// Uses two slots to support long-distance calls.
271 271
export fn recordCall(e: *mut Emitter, target: *[u8]) {
272 272
    assert e.pendingCallsLen < e.pendingCalls.len, "recordCall: buffer full";
273 -
    e.pendingCalls[e.pendingCallsLen] = PendingCall {
273 +
    set e.pendingCalls[e.pendingCallsLen] = PendingCall {
274 274
        index: e.codeLen,
275 275
        target,
276 276
    };
277 -
    e.pendingCallsLen += 1;
277 +
    set e.pendingCallsLen += 1;
278 278
279 279
    emit(e, encode::nop()); // Placeholder for AUIPC.
280 280
    emit(e, encode::nop()); // Placeholder for JALR.
281 281
}
282 282
283 283
/// Record a function address load needing later patching.
284 284
/// Emits placeholder instructions that will be patched to load the function's address.
285 285
/// Uses two slots to compute long-distance addresses.
286 286
export fn recordAddrLoad(e: *mut Emitter, target: *[u8], rd: gen::Reg) {
287 287
    assert e.pendingAddrLoadsLen < e.pendingAddrLoads.len, "recordAddrLoad: buffer full";
288 -
    e.pendingAddrLoads[e.pendingAddrLoadsLen] = PendingAddrLoad {
288 +
    set e.pendingAddrLoads[e.pendingAddrLoadsLen] = PendingAddrLoad {
289 289
        index: e.codeLen,
290 290
        target,
291 291
        rd: rd,
292 292
    };
293 -
    e.pendingAddrLoadsLen += 1;
293 +
    set e.pendingAddrLoadsLen += 1;
294 294
295 295
    emit(e, encode::nop()); // Placeholder for AUIPC.
296 296
    emit(e, encode::nop()); // Placeholder for ADDI.
297 297
}
298 298
332 332
                assert encode::isJumpImm(offset), "patchLocalBranches: jump offset too large";
333 333
                patch(e, p.index, encode::jal(super::ZERO, offset));
334 334
            },
335 335
        }
336 336
    }
337 -
    e.pendingBranchesLen = 0;
337 +
    set e.pendingBranchesLen = 0;
338 338
}
339 339
340 340
/// Encode a conditional branch instruction.
341 341
fn encodeCondBranch(op: il::CmpOp, rs1: gen::Reg, rs2: gen::Reg, offset: i32) -> u32 {
342 342
    match op {
406 406
    let lo = imm & 0xFFF;
407 407
    let mut hi = (imm >> 12) & 0xFFFFF;
408 408
    // If `lo`'s sign bit is set, it will be sign-extended to negative.
409 409
    // Compensate by incrementing `hi`.
410 410
    if (lo & 0x800) <> 0 {
411 -
        hi += 1;
411 +
        set hi += 1;
412 412
        return SplitImm { hi, lo: lo | 0xFFFFF000 as i32 };
413 413
    }
414 414
    return SplitImm { hi, lo };
415 415
}
416 416
664 664
        if prev.offset == loc.offset and prev.moduleId == loc.moduleId {
665 665
            return;
666 666
        }
667 667
    }
668 668
    assert e.debugEntriesLen < e.debugEntries.len, "recordSrcLoc: debug entry buffer full";
669 -
    e.debugEntries[e.debugEntriesLen] = types::DebugEntry {
669 +
    set e.debugEntries[e.debugEntriesLen] = types::DebugEntry {
670 670
        pc,
671 671
        moduleId: loc.moduleId,
672 672
        offset: loc.offset,
673 673
    };
674 -
    e.debugEntriesLen += 1;
674 +
    set e.debugEntriesLen += 1;
675 675
}
676 676
677 677
/// Get debug entries as a slice.
678 678
export fn getDebugEntries(e: *Emitter) -> *[types::DebugEntry] {
679 679
    return &e.debugEntries[..e.debugEntriesLen];
lib/std/arch/rv64/isel.rad +38 -38
144 144
/// If the register is spilled, records a pending spill and returns the scratch
145 145
/// register. The pending spill is auto-committed by [`selectBlock`] after each
146 146
/// instruction. If not spilled, returns the physical register.
147 147
fn getDstReg(s: *mut Selector, ssa: il::Reg, scratch: gen::Reg) -> gen::Reg {
148 148
    if let _ = regalloc::spill::spillSlot(&s.ralloc.spill, ssa) {
149 -
        s.pendingSpill = PendingSpill { ssa, rd: scratch };
149 +
        set s.pendingSpill = PendingSpill { ssa, rd: scratch };
150 150
        return scratch;
151 151
    }
152 152
    return getReg(s, ssa);
153 153
}
154 154
255 255
/// Resolve a value, trap if zero (unless known non-zero), and return the register.
256 256
fn resolveAndTrapIfZero(s: *mut Selector, b: il::Val) -> gen::Reg {
257 257
    let rs2 = resolveVal(s, super::SCRATCH2, b);
258 258
    let mut knownNonZero = false;
259 259
    if let case il::Val::Imm(imm) = b {
260 -
        knownNonZero = imm <> 0;
260 +
        set knownNonZero = imm <> 0;
261 261
    }
262 262
    if not knownNonZero {
263 263
        emit::emit(s.e, encode::bne(rs2, super::ZERO, super::INSTR_SIZE * 2));
264 264
        emit::emit(s.e, encode::ebreak());
265 265
    }
288 288
        let block = &func.blocks[b];
289 289
        for instr in block.instrs {
290 290
            match instr {
291 291
                case il::Instr::Reserve { size, alignment, .. } => {
292 292
                    if let case il::Val::Imm(sz) = size {
293 -
                        offset = mem::alignUpI32(offset, alignment as i32);
294 -
                        offset += sz as i32;
293 +
                        set offset = mem::alignUpI32(offset, alignment as i32);
294 +
                        set offset += sz as i32;
295 295
                    } else {
296 -
                        isDynamic = true;
296 +
                        set isDynamic = true;
297 297
                    }
298 298
                },
299 299
                else => {},
300 300
            }
301 301
        }
379 379
    for instr, i in block.instrs {
380 380
        // Record debug location before emitting machine instructions.
381 381
        if hasLocs {
382 382
            emit::recordSrcLoc(s.e, block.locs[i]);
383 383
        }
384 -
        s.pendingSpill = nil;
384 +
        set s.pendingSpill = nil;
385 385
        selectInstr(s, blockIdx, instr, frame, func);
386 386
387 387
        // Flush the pending spill store, if any.
388 388
        if let p = s.pendingSpill {
389 389
            if let slot = regalloc::spill::spillSlot(&s.ralloc.spill, p.ssa) {
390 390
                emit::emitSd(s.e, p.rd, spillBase(s), spillOffset(s, slot));
391 391
            }
392 -
            s.pendingSpill = nil;
392 +
            set s.pendingSpill = nil;
393 393
        }
394 394
    }
395 395
}
396 396
397 397
/// Select instructions for a single IL instruction.
436 436
                    let base = spillBase(s);
437 437
                    let offset = s.ralloc.spill.frameSize + aligned
438 438
                        - (s.frameSize if s.isDynamic else 0);
439 439
440 440
                    emit::emitAddImm(s.e, rd, base, offset);
441 -
                    s.reserveOffset = aligned + (sz as i32);
441 +
                    set s.reserveOffset = aligned + (sz as i32);
442 442
                },
443 443
                case il::Val::Reg(r) => {
444 444
                    // Dynamic-sized reserve: runtime SP adjustment.
445 445
                    let rd = getDstReg(s, dst, super::SCRATCH1);
446 446
                    let rs = getSrcReg(s, r, super::SCRATCH2);
482 482
                };
483 483
                let srcSlot = regalloc::spill::spillSlot(&s.ralloc.spill, src) else {
484 484
                    panic "selectInstr: blit src not spilled";
485 485
                };
486 486
                emit::emitLd(s.e, super::SCRATCH2, spillBase(s), spillOffset(s, dstSlot));
487 -
                srcReload = spillOffset(s, srcSlot);
487 +
                set srcReload = spillOffset(s, srcSlot);
488 488
            } else {
489 -
                rdst = getSrcReg(s, dst, super::SCRATCH2);
490 -
                rsrc = getSrcReg(s, src, super::SCRATCH2);
489 +
                set rdst = getSrcReg(s, dst, super::SCRATCH2);
490 +
                set rsrc = getSrcReg(s, src, super::SCRATCH2);
491 491
            }
492 492
            let mut offset: i32 = 0;
493 493
            let mut remaining = staticSize as i32;
494 494
495 495
            // For large blits where both pointers are in real registers,
512 512
                    emit::emit(s.e, encode::addi(rdst, rdst, super::DWORD_SIZE));
513 513
                }
514 514
                let brOff = (loopStart as i32 - s.e.codeLen as i32) * super::INSTR_SIZE;
515 515
516 516
                emit::emit(s.e, encode::bne(rsrc, super::SCRATCH1, brOff));
517 -
                remaining -= dwordBytes;
517 +
                set remaining -= dwordBytes;
518 518
            }
519 519
520 520
            // Copy remaining: 8 bytes, then 4 bytes, then 1 byte at a time.
521 521
            // Before each load/store pair, check whether the offset is
522 522
            // about to exceed the 12-bit signed immediate range. When
526 526
                if offset > super::MAX_IMM - super::DWORD_SIZE {
527 527
                    emit::emitAddImm(s.e, rsrc, rsrc, offset);
528 528
                    if *rdst <> *rsrc {
529 529
                        emit::emitAddImm(s.e, rdst, rdst, offset);
530 530
                    }
531 -
                    offset = 0;
531 +
                    set offset = 0;
532 532
                }
533 533
                if let off = srcReload {
534 534
                    emit::emitLd(s.e, super::SCRATCH1, spillBase(s), off);
535 535
                    emit::emitLd(s.e, super::SCRATCH1, super::SCRATCH1, offset);
536 536
                } else {
537 537
                    emit::emitLd(s.e, super::SCRATCH1, rsrc, offset);
538 538
                }
539 539
                emit::emitSd(s.e, super::SCRATCH1, rdst, offset);
540 -
                offset += super::DWORD_SIZE;
541 -
                remaining -= super::DWORD_SIZE;
540 +
                set offset += super::DWORD_SIZE;
541 +
                set remaining -= super::DWORD_SIZE;
542 542
            }
543 543
            if remaining >= super::WORD_SIZE {
544 544
                if offset > super::MAX_IMM - super::WORD_SIZE {
545 545
                    emit::emitAddImm(s.e, rsrc, rsrc, offset);
546 546
                    if *rdst <> *rsrc {
547 547
                        emit::emitAddImm(s.e, rdst, rdst, offset);
548 548
                    }
549 -
                    offset = 0;
549 +
                    set offset = 0;
550 550
                }
551 551
                if let off = srcReload {
552 552
                    emit::emitLd(s.e, super::SCRATCH1, spillBase(s), off);
553 553
                    emit::emitLw(s.e, super::SCRATCH1, super::SCRATCH1, offset);
554 554
                } else {
555 555
                    emit::emitLw(s.e, super::SCRATCH1, rsrc, offset);
556 556
                }
557 557
                emit::emitSw(s.e, super::SCRATCH1, rdst, offset);
558 -
                offset += super::WORD_SIZE;
559 -
                remaining -= super::WORD_SIZE;
558 +
                set offset += super::WORD_SIZE;
559 +
                set remaining -= super::WORD_SIZE;
560 560
            }
561 561
            while remaining > 0 {
562 562
                if offset > super::MAX_IMM - 1 {
563 563
                    emit::emitAddImm(s.e, rsrc, rsrc, offset);
564 564
                    if *rdst <> *rsrc {
565 565
                        emit::emitAddImm(s.e, rdst, rdst, offset);
566 566
                    }
567 -
                    offset = 0;
567 +
                    set offset = 0;
568 568
                }
569 569
                if let off = srcReload {
570 570
                    emit::emitLd(s.e, super::SCRATCH1, spillBase(s), off);
571 571
                    emit::emitLb(s.e, super::SCRATCH1, super::SCRATCH1, offset);
572 572
                } else {
573 573
                    emit::emitLb(s.e, super::SCRATCH1, rsrc, offset);
574 574
                }
575 575
                emit::emitSb(s.e, super::SCRATCH1, rdst, offset);
576 -
                offset += 1;
577 -
                remaining -= 1;
576 +
                set offset += 1;
577 +
                set remaining -= 1;
578 578
            }
579 579
            // Restore base registers if they were advanced (never happens
580 580
            // in the both-spilled case since size <= MAX_IMM).
581 581
            if not bothSpilled {
582 582
                let advanced = staticSize as i32 - offset;
639 639
            // Skip extension for zero register.
640 640
            // Determine extension mode: sign-extend for W32 or SLT,
641 641
            // zero-extend otherwise.
642 642
            let mut useSext: bool = undefined;
643 643
            if let case il::CmpOp::Slt = op {
644 -
                useSext = true;
644 +
                set useSext = true;
645 645
            } else {
646 -
                useSext = typ == il::Type::W32;
646 +
                set useSext = typ == il::Type::W32;
647 647
            }
648 648
            if useSext {
649 649
                if not aIsZero and not isExtendedImm(a, typ, true) {
650 650
                    emitSext(s.e, rs1, rs1, typ);
651 651
                }
697 697
            for c in cases {
698 698
                emit::loadImm(s.e, super::SCRATCH2, c.value);
699 699
700 700
                if c.args.len > 0 {
701 701
                    let skip = s.nextSynthBlock;
702 -
                    s.nextSynthBlock = skip + 1;
702 +
                    set s.nextSynthBlock = skip + 1;
703 703
704 704
                    emit::recordBranch(s.e, skip, emit::BranchKind::InvertedCond {
705 705
                        op: il::CmpOp::Eq, rs1, rs2: super::SCRATCH2,
706 706
                    });
707 707
                    emitBlockArgs(s, func, c.target, c.args);
1062 1062
        if dst <> super::ZERO { // Skip entries with no destination.
1063 1063
            match args[i] {
1064 1064
                case il::Val::Reg(r) => {
1065 1065
                    if let _ = regalloc::spill::spillSlot(&s.ralloc.spill, r) {
1066 1066
                        // Spilled value needs load, not a register move.
1067 -
                        pending[i] = true;
1068 -
                        numPending += 1;
1067 +
                        set pending[i] = true;
1068 +
                        set numPending += 1;
1069 1069
                    } else {
1070 1070
                        let src = getReg(s, r);
1071 1071
                        if src <> dst {
1072 1072
                            // Register-to-register move needed.
1073 -
                            srcRegs[i] = src;
1074 -
                            isRegMove[i] = true;
1075 -
                            pending[i] = true;
1076 -
                            numPending += 1;
1073 +
                            set srcRegs[i] = src;
1074 +
                            set isRegMove[i] = true;
1075 +
                            set pending[i] = true;
1076 +
                            set numPending += 1;
1077 1077
                        } else {
1078 1078
                            // No move needed.
1079 1079
                        }
1080 1080
                    }
1081 1081
                },
1082 1082
                case il::Val::Imm(_), il::Val::DataSym(_), il::Val::FnAddr(_) => {
1083 -
                    pending[i] = true;
1084 -
                    numPending += 1;
1083 +
                    set pending[i] = true;
1084 +
                    set numPending += 1;
1085 1085
                },
1086 1086
                case il::Val::Undef => {
1087 1087
                    // Undefined values don't need any move.
1088 1088
                }
1089 1089
            }
1104 1104
                let mut isReady = true;
1105 1105
1106 1106
                // Check if `dst` is used as source by any other pending register move.
1107 1107
                for j in 0..n {
1108 1108
                    if j <> i and pending[j] and isRegMove[j] and srcRegs[j] == dst {
1109 -
                        isReady = false;
1109 +
                        set isReady = false;
1110 1110
                        break;
1111 1111
                    }
1112 1112
                }
1113 1113
                if isReady {
1114 1114
                    // Execute this move.
1116 1116
                        emitMv(s, dst, srcRegs[i]);
1117 1117
                    } else {
1118 1118
                        // Load immediate, symbol, or spilled value.
1119 1119
                        loadVal(s, dst, args[i]);
1120 1120
                    }
1121 -
                    found = true;
1122 -
                    pending[i] = false;
1123 -
                    numPending -= 1;
1121 +
                    set found = true;
1122 +
                    set pending[i] = false;
1123 +
                    set numPending -= 1;
1124 1124
1125 1125
                    break;
1126 1126
                }
1127 1127
            }
1128 1128
        }
1136 1136
                    // Save this source to scratch.
1137 1137
                    emitMv(s, super::SCRATCH1, src);
1138 1138
                    // Update all pending moves that use this source.
1139 1139
                    for j in 0..n {
1140 1140
                        if pending[j] and isRegMove[j] and srcRegs[j] == src {
1141 -
                            srcRegs[j] = super::SCRATCH1;
1141 +
                            set srcRegs[j] = super::SCRATCH1;
1142 1142
                        }
1143 1143
                    }
1144 1144
                    break;
1145 1145
                }
1146 1146
            }
1175 1175
            } else {
1176 1176
                let rs = resolveVal(s, super::SCRATCH1, arg);
1177 1177
                emit::emitSd(s.e, rs, spillBase(s), spillOffset(s, slot));
1178 1178
            }
1179 1179
        } else {
1180 -
            dsts[i] = getReg(s, param);
1180 +
            set dsts[i] = getReg(s, param);
1181 1181
        }
1182 1182
    }
1183 1183
    emitParallelMoves(s, &dsts[..], args);
1184 1184
}
1185 1185
lib/std/arch/rv64/printer.rad +1 -1
91 91
fn writeMnem(out: *mut sexpr::Output, m: *[u8]) {
92 92
    write(out, m);
93 93
    let mut i = m.len;
94 94
    while i < MNEMONIC_WIDTH {
95 95
        write(out, " ");
96 -
        i += 1;
96 +
        set i += 1;
97 97
    }
98 98
}
99 99
100 100
////////////////////////////////
101 101
// Instruction Format Helpers //
lib/std/collections/dict.rad +7 -7
23 23
24 24
/// Create a dict backed by the given entry storage.
25 25
/// The storage length must be a power of two.
26 26
export fn init(entries: *mut [Entry]) -> Dict {
27 27
    for i in 0..entries.len {
28 -
        entries[i] = Entry { key: &[], value: 0 };
28 +
        set entries[i] = Entry { key: &[], value: 0 };
29 29
    }
30 30
    return Dict { entries, count: 0 };
31 31
}
32 32
33 33
/// Insert or update a key-value pair. Panics if the table exceeds 50% load.
37 37
38 38
    loop {
39 39
        let entry = m.entries[idx];
40 40
        if entry.key.len == 0 {
41 41
            assert m.count < m.entries.len / 2, "dict::insert: table full";
42 -
            m.entries[idx] = Entry { key, value };
43 -
            m.count += 1;
42 +
            set m.entries[idx] = Entry { key, value };
43 +
            set m.count += 1;
44 44
            return;
45 45
        }
46 46
        if mem::eq(entry.key, key) {
47 -
            m.entries[idx].value = value;
47 +
            set m.entries[idx].value = value;
48 48
            return;
49 49
        }
50 -
        idx = (idx + 1) & mask;
50 +
        set idx = (idx + 1) & mask;
51 51
    }
52 52
}
53 53
54 54
/// Look up a value by key. Returns `nil` if not found.
55 55
export fn get(m: *Dict, key: *[u8]) -> ?i32 {
62 62
            return nil;
63 63
        }
64 64
        if mem::eq(entry.key, key) {
65 65
            return entry.value;
66 66
        }
67 -
        idx = (idx + 1) & mask;
67 +
        set idx = (idx + 1) & mask;
68 68
    }
69 69
}
70 70
71 71
/// DJB2 hash function.
72 72
export fn hash(str: *[u8]) -> u32 {
73 73
    let mut h: u32 = 5381;
74 74
    for b in str {
75 -
        h = ((h << 5) + h) + b as u32;
75 +
        set h = ((h << 5) + h) + b as u32;
76 76
    }
77 77
    return h;
78 78
}
lib/std/fmt.rad +24 -24
19 19
    let mut x: u32 = val;
20 20
    let mut i: u32 = buffer.len;
21 21
22 22
    // Handle the zero case separately to ensure a single '0' is written.
23 23
    if x == 0 {
24 -
        i -= 1;
25 -
        buffer[i] = '0';
24 +
        set i -= 1;
25 +
        set buffer[i] = '0';
26 26
    } else {
27 27
        // Write digits backwards from the end of the buffer.
28 28
        while x <> 0 {
29 -
            i -= 1;
30 -
            buffer[i] = ('0' + (x % 10) as u8);
31 -
            x /= 10;
29 +
            set i -= 1;
30 +
            set buffer[i] = ('0' + (x % 10) as u8);
31 +
            set x /= 10;
32 32
        }
33 33
    }
34 34
    // Return the slice from the start of the written number to
35 35
    // the end of the buffer.
36 36
    return &buffer[i..];
43 43
    let neg: bool = val < 0;
44 44
    let mut x: u32 = -val as u32 if neg else val as u32;
45 45
    let mut i: u32 = buffer.len;
46 46
    // Handle the zero case separately to ensure a single '0' is written.
47 47
    if x == 0 {
48 -
        i -= 1;
49 -
        buffer[i] = '0';
48 +
        set i -= 1;
49 +
        set buffer[i] = '0';
50 50
    } else {
51 51
        // Write digits backwards from the end of the buffer.
52 52
        while x <> 0 {
53 -
            i -= 1;
54 -
            buffer[i] = '0' + (x % 10) as u8;
55 -
            x /= 10;
53 +
            set i -= 1;
54 +
            set buffer[i] = '0' + (x % 10) as u8;
55 +
            set x /= 10;
56 56
        }
57 57
        // Add the negative sign if needed.
58 58
        if neg {
59 -
            i -= 1;
60 -
            buffer[i] = '-';
59 +
            set i -= 1;
60 +
            set buffer[i] = '-';
61 61
        }
62 62
    }
63 63
    return &buffer[i..];
64 64
}
65 65
69 69
70 70
    let mut x: u64 = val;
71 71
    let mut i: u32 = buffer.len;
72 72
73 73
    if x == 0 {
74 -
        i -= 1;
75 -
        buffer[i] = '0';
74 +
        set i -= 1;
75 +
        set buffer[i] = '0';
76 76
    } else {
77 77
        while x <> 0 {
78 -
            i -= 1;
79 -
            buffer[i] = ('0' + (x % 10) as u8);
80 -
            x /= 10;
78 +
            set i -= 1;
79 +
            set buffer[i] = ('0' + (x % 10) as u8);
80 +
            set x /= 10;
81 81
        }
82 82
    }
83 83
    return &buffer[i..];
84 84
}
85 85
89 89
90 90
    let neg: bool = val < 0;
91 91
    let mut x: u64 = -val as u64 if neg else val as u64;
92 92
    let mut i: u32 = buffer.len;
93 93
    if x == 0 {
94 -
        i -= 1;
95 -
        buffer[i] = '0';
94 +
        set i -= 1;
95 +
        set buffer[i] = '0';
96 96
    } else {
97 97
        while x <> 0 {
98 -
            i -= 1;
99 -
            buffer[i] = '0' + (x % 10) as u8;
100 -
            x /= 10;
98 +
            set i -= 1;
99 +
            set buffer[i] = '0' + (x % 10) as u8;
100 +
            set x /= 10;
101 101
        }
102 102
        if neg {
103 -
            i -= 1;
104 -
            buffer[i] = '-';
103 +
            set i -= 1;
104 +
            set buffer[i] = '-';
105 105
        }
106 106
    }
107 107
    return &buffer[i..];
108 108
}
109 109
lib/std/io.rad +2 -2
46 46
47 47
        if n == 0 {
48 48
            break;
49 49
        }
50 50
        if n > chunk.len {
51 -
            total = buf.len;
51 +
            set total = buf.len;
52 52
            break;
53 53
        }
54 -
        total += n;
54 +
        set total += n;
55 55
    }
56 56
    return &buf[..total];
57 57
}
lib/std/lang/alloc.rad +4 -4
44 44
45 45
    if newOffset > arena.data.len as u32 {
46 46
        throw AllocError::OutOfMemory;
47 47
    }
48 48
    let base: *mut u8 = &mut arena.data[aligned];
49 -
    arena.offset = newOffset;
49 +
    set arena.offset = newOffset;
50 50
51 51
    return base as *mut opaque;
52 52
}
53 53
54 54
/// Reset the arena, allowing all memory to be reused.
55 55
///
56 56
/// Does not zero the memory.
57 57
export fn reset(arena: *mut Arena) {
58 -
    arena.offset = 0;
58 +
    set arena.offset = 0;
59 59
}
60 60
61 61
/// Save the current arena state for later restoration.
62 62
export fn save(arena: *Arena) -> u32 {
63 63
    return arena.offset;
64 64
}
65 65
66 66
/// Restore the arena to a previously saved state, reclaiming all
67 67
/// allocations made since that point.
68 68
export fn restore(arena: *mut Arena, savedOffset: u32) {
69 -
    arena.offset = savedOffset;
69 +
    set arena.offset = savedOffset;
70 70
}
71 71
72 72
/// Returns the number of bytes currently allocated.
73 73
export fn used(arena: *Arena) -> u32 {
74 74
    return arena.offset;
85 85
}
86 86
87 87
/// Commits `size` bytes of allocation, advancing the offset.
88 88
/// Use after writing to the buffer returned by [`remainingBuf`].
89 89
export fn commit(arena: *mut Arena, size: u32) {
90 -
    arena.offset += size;
90 +
    set arena.offset += size;
91 91
}
92 92
93 93
/// Allocate a slice of `count` elements, each of `size` bytes with given alignment.
94 94
///
95 95
/// Returns a type-erased slice that should be cast to the appropriate `*[T]`.
lib/std/lang/alloc/tests.rad +2 -2
50 50
    let p2 = try! super::alloc(&mut arena, 8, 4);
51 51
52 52
    // Arena is now full, this should fail.
53 53
    let mut failed = false;
54 54
    try super::alloc(&mut arena, 1, 1) catch {
55 -
        failed = true;
55 +
        set failed = true;
56 56
    };
57 57
    try testing::expect(failed);
58 58
}
59 59
60 60
/// Test that reset allows reuse of memory.
97 97
98 98
    // Try to allocate 16 bytes with 4-byte alignment.
99 99
    // Aligned offset would be 4, then 4 + 16 = 20 > 16, so should fail.
100 100
    let mut failed = false;
101 101
    try super::alloc(&mut arena, 16, 4) catch {
102 -
        failed = true;
102 +
        set failed = true;
103 103
    };
104 104
    try testing::expect(failed);
105 105
}
106 106
107 107
/// Test the Allocator interface backed by an arena.
lib/std/lang/ast.rad +3 -3
718 718
    ConstDecl(ConstDecl),
719 719
    /// Static storage declaration.
720 720
    StaticDecl(StaticDecl),
721 721
    /// Type signature node.
722 722
    TypeSig(TypeSig),
723 -
    /// Assignment expression.
723 +
    /// Assignment statement.
724 724
    Assign(Assign),
725 725
    /// Expression statement.
726 726
    ExprStmt(*Node),
727 727
    /// Module declaration (`mod`).
728 728
    Mod(Mod),
833 833
/// Allocate a new AST node from the arena with the given span and value.
834 834
export fn allocNode(arena: *mut NodeArena, span: Span, value: NodeValue) -> *mut Node {
835 835
    let p = try! alloc::alloc(&mut arena.arena, @sizeOf(Node), @alignOf(Node));
836 836
    let node = p as *mut Node;
837 837
    let nodeId = arena.nextId;
838 -
    arena.nextId = nodeId + 1;
838 +
    set arena.nextId = nodeId + 1;
839 839
840 -
    *node = Node { id: nodeId, span, value };
840 +
    set *node = Node { id: nodeId, span, value };
841 841
842 842
    return node;
843 843
}
844 844
845 845
/// Allocate a synthetic AST node with a zero-length span.
lib/std/lang/ast/printer.rad +21 -21
89 89
        case super::TypeSig::Record { fields, .. } =>
90 90
            return sexpr::list(a, "record", nodeListToExprs(a, &fields[..])),
91 91
        case super::TypeSig::Fn(sig) => {
92 92
            let mut ret = sexpr::sym("void");
93 93
            if let rt = sig.returnType {
94 -
                ret = toExpr(a, rt);
94 +
                set ret = toExpr(a, rt);
95 95
            }
96 96
            return sexpr::list(a, "fn", &[sexpr::list(a, "params", nodeListToExprs(a, &sig.params[..])), ret]);
97 97
        }
98 98
        case super::TypeSig::TraitObject { traitName, mutable } =>
99 99
            return sexpr::list(a, "obj", &[sexpr::sym("mut"), toExpr(a, traitName)]) if mutable
106 106
    if nodes.len == 0 {
107 107
        return &[];
108 108
    }
109 109
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
110 110
    for node, i in nodes {
111 -
        buf[i] = toExpr(a, node);
111 +
        set buf[i] = toExpr(a, node);
112 112
    }
113 113
    return buf;
114 114
}
115 115
116 116
/// Convert an optional node to an expression, or return placeholder.
144 144
    }
145 145
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
146 146
    for prong, i in nodes {
147 147
        match prong.value {
148 148
            case super::NodeValue::MatchProng(p) => {
149 -
                buf[i] = prongToExpr(a, p);
149 +
                set buf[i] = prongToExpr(a, p);
150 150
            }
151 151
            else => {
152 -
                buf[i] = sexpr::sym("<invalid>");
152 +
                set buf[i] = sexpr::sym("<invalid>");
153 153
            }
154 154
        }
155 155
    }
156 156
    return buf;
157 157
}
194 194
    }
195 195
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
196 196
    for node, i in nodes {
197 197
        match node.value {
198 198
            case super::NodeValue::RecordField { field, type, value } => {
199 -
                buf[i] = fieldToExpr(a, field, type, value);
199 +
                set buf[i] = fieldToExpr(a, field, type, value);
200 200
            }
201 201
            else => {
202 -
                buf[i] = sexpr::sym("<invalid>");
202 +
                set buf[i] = sexpr::sym("<invalid>");
203 203
            }
204 204
        }
205 205
    }
206 206
    return buf;
207 207
}
218 218
    }
219 219
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
220 220
    for node, i in nodes {
221 221
        match node.value {
222 222
            case super::NodeValue::UnionDeclVariant(v) => {
223 -
                buf[i] = variantToExpr(a, v.name, v.type);
223 +
                set buf[i] = variantToExpr(a, v.name, v.type);
224 224
            }
225 225
            else => {
226 -
                buf[i] = sexpr::sym("<invalid>");
226 +
                set buf[i] = sexpr::sym("<invalid>");
227 227
            }
228 228
        }
229 229
    }
230 230
    return buf;
231 231
}
255 255
            return sexpr::list(a, binOpName(b.op), &[toExpr(a, b.left), toExpr(a, b.right)]),
256 256
        case super::NodeValue::UnOp(u) =>
257 257
            return sexpr::list(a, unOpName(u.op), &[toExpr(a, u.value)]),
258 258
        case super::NodeValue::Call(c) => {
259 259
            let buf = try! sexpr::allocExprs(a, c.args.len as u32 + 1);
260 -
            buf[0] = toExpr(a, c.callee);
261 -
            for arg, i in c.args { buf[i + 1] = toExpr(a, arg); }
260 +
            set buf[0] = toExpr(a, c.callee);
261 +
            for arg, i in c.args { set buf[i + 1] = toExpr(a, arg); }
262 262
            return sexpr::Expr::List { head: "call", tail: buf, multiline: false };
263 263
        }
264 264
        case super::NodeValue::BuiltinCall { kind, args } =>
265 265
            return sexpr::list(a, builtinName(kind), nodeListToExprs(a, &args[..])),
266 266
        case super::NodeValue::Subscript { container, index } =>
281 281
        case super::NodeValue::ArrayRepeatLit(rep) =>
282 282
            return sexpr::list(a, "array-repeat", &[toExpr(a, rep.item), toExpr(a, rep.count)]),
283 283
        case super::NodeValue::RecordLit(lit) => {
284 284
            let mut total: u32 = lit.fields.len as u32;
285 285
            if let _ = lit.typeName {
286 -
                total += 1;
286 +
                set total += 1;
287 287
            }
288 288
            let buf = try! sexpr::allocExprs(a, total);
289 289
            let mut idx: u32 = 0;
290 290
            if let tn = lit.typeName {
291 -
                buf[idx] = toExpr(a, tn); idx = idx + 1;
291 +
                set buf[idx] = toExpr(a, tn); set idx = idx + 1;
292 292
            }
293 293
            for field, i in lit.fields {
294 -
                buf[idx + i] = toExpr(a, field);
294 +
                set buf[idx + i] = toExpr(a, field);
295 295
            }
296 296
            return sexpr::Expr::List { head: "record-lit", tail: buf, multiline: lit.fields.len > 2 };
297 297
        }
298 298
        case super::NodeValue::RecordLitField(f) =>
299 299
            return sexpr::list(a, "field", &[toExprOpt(a, f.label), toExpr(a, f.value)]),
309 309
                case super::Attribute::Intrinsic => return sexpr::sym("@intrinsic"),
310 310
            }
311 311
        }
312 312
        case super::NodeValue::Try(t) => {
313 313
            let mut head = "try";
314 -
            if t.shouldPanic { head = "try!"; }
314 +
            if t.shouldPanic { set head = "try!"; }
315 315
            if t.catches.len > 0 {
316 316
                let catches = nodeListToExprs(a, &t.catches[..]);
317 317
                return sexpr::list(a, head, &[toExpr(a, t.expr), sexpr::block(a, "catches", &[], catches)]);
318 318
            }
319 319
            return sexpr::list(a, head, &[toExpr(a, t.expr)]);
321 321
        case super::NodeValue::CatchClause(clause) => {
322 322
            let mut head = "catch";
323 323
            let mut children: [sexpr::Expr; 3] = undefined;
324 324
            let mut len: u32 = 0;
325 325
            if let b = clause.binding {
326 -
                children[len] = toExpr(a, b);
327 -
                len += 1;
326 +
                set children[len] = toExpr(a, b);
327 +
                set len += 1;
328 328
            }
329 329
            if let t = clause.typeNode {
330 -
                children[len] = toExpr(a, t);
331 -
                len += 1;
330 +
                set children[len] = toExpr(a, t);
331 +
                set len += 1;
332 332
            }
333 -
            children[len] = toExpr(a, clause.body);
334 -
            len += 1;
333 +
            set children[len] = toExpr(a, clause.body);
334 +
            set len += 1;
335 335
            return sexpr::list(a, head, &children[..len]);
336 336
        }
337 337
        case super::NodeValue::Block(blk) => {
338 338
            let children = nodeListToExprs(a, &blk.statements[..]);
339 339
            return sexpr::block(a, "block", &[], children);
340 340
        }
341 341
        case super::NodeValue::Let(decl) => {
342 342
            let mut head = "let";
343 -
            if decl.mutable { head = "let-mut"; }
343 +
            if decl.mutable { set head = "let-mut"; }
344 344
            return sexpr::list(a, head, &[
345 345
                toExpr(a, decl.ident),
346 346
                toExprOrNull(a, decl.type),
347 347
                toExpr(a, decl.value)
348 348
            ]);
lib/std/lang/gen/bitset.rad +17 -17
41 41
}
42 42
43 43
/// Create a new bitset backed by the given storage, zeroing it first.
44 44
export fn init(bits: *mut [u32]) -> Bitset {
45 45
    for i in 0..bits.len {
46 -
        bits[i] = 0;
46 +
        set bits[i] = 0;
47 47
    }
48 48
    return new(bits);
49 49
}
50 50
51 51
/// Create a bitset from arena allocation.
62 62
        return;
63 63
    }
64 64
    let word = n / 32;
65 65
    let b = n % 32;
66 66
67 -
    bs.bits[word] |= (1 << b);
67 +
    set bs.bits[word] |= (1 << b);
68 68
}
69 69
70 70
/// Clear bit `n` in the bitset.
71 71
export fn clear(bs: *mut Bitset, n: u32) {
72 72
    if n >= bs.len {
73 73
        return;
74 74
    }
75 75
    let word = n / 32;
76 76
    let b = n % 32;
77 77
78 -
    bs.bits[word] &= ~(1 << b);
78 +
    set bs.bits[word] &= ~(1 << b);
79 79
}
80 80
81 81
/// Check if bit `n` is set.
82 82
export fn contains(bs: *Bitset, n: u32) -> bool {
83 83
    if n >= bs.len {
94 94
    let mut total: u32 = 0;
95 95
    let numWords = bs.bits.len;
96 96
    for i in 0..numWords {
97 97
        let word = bs.bits[i];
98 98
        if word <> 0 {
99 -
            total += popCount(word);
99 +
            set total += popCount(word);
100 100
        }
101 101
    }
102 102
    return total;
103 103
}
104 104
105 105
/// Population count for a 32-bit word.
106 106
fn popCount(x: u32) -> u32 {
107 107
    let mut n = x;
108 -
    n -= ((n >> 1) & 0x55555555);
109 -
    n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
110 -
    n = (n + (n >> 4)) & 0x0F0F0F0F;
111 -
    n += (n >> 8);
112 -
    n += (n >> 16);
108 +
    set n -= ((n >> 1) & 0x55555555);
109 +
    set n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
110 +
    set n = (n + (n >> 4)) & 0x0F0F0F0F;
111 +
    set n += (n >> 8);
112 +
    set n += (n >> 16);
113 113
114 114
    return n & 0x3F;
115 115
}
116 116
117 117
/// Union: `dst = dst | src`.
118 118
export fn union_(dst: *mut Bitset, src: *Bitset) {
119 119
    let numWords = dst.bits.len;
120 120
    let srcWords = src.bits.len;
121 121
    let minWords = min(numWords, srcWords);
122 122
    for i in 0..minWords {
123 -
        dst.bits[i] |= src.bits[i];
123 +
        set dst.bits[i] |= src.bits[i];
124 124
    }
125 125
}
126 126
127 127
/// Subtract: `dst = dst - src`.
128 128
export fn subtract(dst: *mut Bitset, src: *Bitset) {
129 129
    let numWords = dst.bits.len;
130 130
    let srcWords = src.bits.len;
131 131
    let minWords = min(numWords, srcWords);
132 132
    for i in 0..minWords {
133 -
        dst.bits[i] &= ~src.bits[i];
133 +
        set dst.bits[i] &= ~src.bits[i];
134 134
    }
135 135
}
136 136
137 137
/// Check if two bitsets are equal.
138 138
export fn eq(a: *Bitset, b: *Bitset) -> bool {
155 155
    let numWords = dst.bits.len;
156 156
    let srcWords = src.bits.len;
157 157
    let minWords = min(numWords, srcWords);
158 158
159 159
    for i in 0..minWords {
160 -
        dst.bits[i] = src.bits[i];
160 +
        set dst.bits[i] = src.bits[i];
161 161
    }
162 162
    // Clear remaining words if destination is larger.
163 163
    for i in minWords..numWords {
164 -
        dst.bits[i] = 0;
164 +
        set dst.bits[i] = 0;
165 165
    }
166 166
}
167 167
168 168
/// Clear all bits.
169 169
export fn clearAll(bs: *mut Bitset) {
170 170
    let numWords = bs.bits.len;
171 171
    for i in 0..numWords {
172 -
        bs.bits[i] = 0;
172 +
        set bs.bits[i] = 0;
173 173
    }
174 174
}
175 175
176 176
/// Iterator state for iterating set bits.
177 177
export record BitIter {
192 192
/// Get the next set bit, or nil if none remain.
193 193
export fn iterNext(it: *mut BitIter) -> ?u32 {
194 194
    let numWords = it.bs.bits.len;
195 195
    // Skip to next non-zero word.
196 196
    while it.remaining == 0 {
197 -
        it.wordIdx += 1;
197 +
        set it.wordIdx += 1;
198 198
        if it.wordIdx >= numWords {
199 199
            return nil;
200 200
        }
201 -
        it.remaining = it.bs.bits[it.wordIdx];
201 +
        set it.remaining = it.bs.bits[it.wordIdx];
202 202
    }
203 203
    // Find lowest set bit position using de Bruijn sequence.
204 204
    let b = ctz(it.remaining);
205 205
    let n = it.wordIdx * 32 + b;
206 206
    if n >= it.bs.len {
207 207
        return nil;
208 208
    }
209 209
    // Clear the lowest set bit.
210 -
    it.remaining &= it.remaining - 1;
210 +
    set it.remaining &= it.remaining - 1;
211 211
212 212
    return n;
213 213
}
214 214
215 215
/// Count trailing zeros in a 32-bit value.
lib/std/lang/gen/bitset/tests.rad +2 -2
186 186
    let mut it = super::iter(&bs);
187 187
    let mut count: u32 = 0;
188 188
    let mut sum: u32 = 0;
189 189
190 190
    while let n = super::iterNext(&mut it) {
191 -
        count += 1;
192 -
        sum += n;
191 +
        set count += 1;
192 +
        set sum += n;
193 193
    }
194 194
195 195
    try testing::expect(count == 4);
196 196
    try testing::expect(sum == 3 + 31 + 32 + 50);
197 197
}
lib/std/lang/gen/data.rad +15 -15
46 46
47 47
    // Initialized data first.
48 48
    for i in 0..program.data.len {
49 49
        let data = &program.data[i];
50 50
        if data.readOnly == readOnly and not data.isUndefined {
51 -
            offset = mem::alignUp(offset, data.alignment);
52 -
            syms[*count] = DataSym { name: data.name, addr: base + offset };
53 -
            *count += 1;
54 -
            offset += data.size;
51 +
            set offset = mem::alignUp(offset, data.alignment);
52 +
            set syms[*count] = DataSym { name: data.name, addr: base + offset };
53 +
            set *count += 1;
54 +
            set offset += data.size;
55 55
        }
56 56
    }
57 57
    // Uninitialized data after.
58 58
    for i in 0..program.data.len {
59 59
        let data = &program.data[i];
60 60
        if data.readOnly == readOnly and data.isUndefined {
61 -
            offset = mem::alignUp(offset, data.alignment);
62 -
            syms[*count] = DataSym { name: data.name, addr: base + offset };
63 -
            *count += 1;
64 -
            offset += data.size;
61 +
            set offset = mem::alignUp(offset, data.alignment);
62 +
            set syms[*count] = DataSym { name: data.name, addr: base + offset };
63 +
            set *count += 1;
64 +
            set offset += data.size;
65 65
        }
66 66
    }
67 67
    return offset;
68 68
}
69 69
81 81
    let mut offset: u32 = 0;
82 82
83 83
    for i in 0..program.data.len {
84 84
        let data = &program.data[i];
85 85
        if data.readOnly == readOnly and not data.isUndefined {
86 -
            offset = mem::alignUp(offset, data.alignment);
86 +
            set offset = mem::alignUp(offset, data.alignment);
87 87
            assert offset + data.size <= buf.len, "emitSection: buffer overflow";
88 88
            for j in 0..data.values.len {
89 89
                let v = &data.values[j];
90 90
                for _ in 0..v.count {
91 91
                    match v.item {
92 92
                        case il::DataItem::Val { typ, val } => {
93 93
                            let size = il::typeSize(typ);
94 94
                            let valPtr = &val as *u8;
95 95
                            try! mem::copy(&mut buf[offset..], @sliceOf(valPtr, size));
96 -
                            offset += size;
96 +
                            set offset += size;
97 97
                        },
98 98
                        case il::DataItem::Sym(name) => {
99 99
                            let addr = lookupAddr(dataSymMap, name) else {
100 100
                                panic "emitSection: data symbol not found";
101 101
                            };
102 102
                            let addr64: u64 = addr as u64;
103 103
                            let addrPtr = &addr64 as *u8;
104 104
105 105
                            try! mem::copy(&mut buf[offset..], @sliceOf(addrPtr, 8));
106 106
107 -
                            offset += 8;
107 +
                            set offset += 8;
108 108
                        },
109 109
                        case il::DataItem::Fn(name) => {
110 110
                            let addr = codeBase + labels::funcOffset(fnLabels, name) as u32;
111 111
                            let addr64: u64 = addr as u64;
112 112
                            let addrPtr = &addr64 as *u8;
113 113
114 114
                            try! mem::copy(&mut buf[offset..], @sliceOf(addrPtr, 8));
115 115
116 -
                            offset += 8;
116 +
                            set offset += 8;
117 117
                        },
118 118
                        case il::DataItem::Str(s) => {
119 119
                            try! mem::copy(&mut buf[offset..], s);
120 -
                            offset += s.len;
120 +
                            set offset += s.len;
121 121
                        },
122 122
                        case il::DataItem::Undef => {
123 -
                            buf[offset] = 0;
124 -
                            offset += 1;
123 +
                            set buf[offset] = 0;
124 +
                            set offset += 1;
125 125
                        },
126 126
                    }
127 127
                }
128 128
            }
129 129
        }
lib/std/lang/gen/labels.rad +3 -3
31 31
    };
32 32
}
33 33
34 34
/// Reset block count for a new function.
35 35
export fn resetBlocks(l: *mut Labels) {
36 -
    l.blockCount = 0;
36 +
    set l.blockCount = 0;
37 37
}
38 38
39 39
/// Record a block's code offset by its index. O(1).
40 40
export fn recordBlock(l: *mut Labels, blockIdx: u32, offset: i32) {
41 41
    assert blockIdx < l.blockOffsets.len, "recordBlock: block index out of range";
42 -
    l.blockOffsets[blockIdx] = offset;
43 -
    l.blockCount += 1;
42 +
    set l.blockOffsets[blockIdx] = offset;
43 +
    set l.blockCount += 1;
44 44
}
45 45
46 46
/// Look up a block's byte offset by index. O(1).
47 47
export fn blockOffset(l: *Labels, blockIdx: u32) -> i32 {
48 48
    assert blockIdx < l.blockCount, "blockOffset: block not recorded";
lib/std/lang/gen/regalloc/assign.rad +21 -21
69 69
    }
70 70
71 71
    // Allocate output structures.
72 72
    let assignments = try alloc::allocSlice(arena, @sizeOf(?gen::Reg), @alignOf(?gen::Reg), maxReg) as *mut [?gen::Reg];
73 73
    for i in 0..maxReg {
74 -
        assignments[i] = nil;
74 +
        set assignments[i] = nil;
75 75
    }
76 76
    // Pre-assign function parameters to argument registers.
77 77
    // Cross-call params are NOT pre-assigned here; they will be allocated
78 78
    // to callee-saved registers by the normal path, and isel emits moves
79 79
    // from the arg register to the assigned register at function entry.
80 80
    for param, i in func.params {
81 81
        if i < config.argRegs.len {
82 82
            if not bitset::contains(&spillInfo.calleeClass, param.value.n) {
83 -
                assignments[param.value.n] = config.argRegs[i];
83 +
                set assignments[param.value.n] = config.argRegs[i];
84 84
            }
85 85
        }
86 86
    }
87 87
    let blkEnd = try alloc::allocSlice(arena, @sizeOf(RegMap), @alignOf(RegMap), blockCount) as *mut [RegMap];
88 88
    for i in 0..blockCount {
89 -
        blkEnd[i] = try createRegMap(arena);
89 +
        set blkEnd[i] = try createRegMap(arena);
90 90
    }
91 91
    // Allocate used registers bitset (32 physical registers per 32-bit word).
92 92
    let usedRegsBits = try alloc::allocSlice(arena, @sizeOf(u32), @alignOf(u32), 1) as *mut [u32];
93 93
    let mut usedRegs = bitset::init(usedRegsBits);
94 94
98 98
    // Phase 2: Linear scan allocation.
99 99
    for b in 0..blockCount {
100 100
        let block = &func.blocks[b];
101 101
102 102
        // Reset for new block.
103 -
        current.n = 0;
103 +
        set current.n = 0;
104 104
        bitset::clearAll(&mut usedRegs);
105 105
106 106
        // Initialize from predecessor if single predecessor.
107 107
        // Only copy values that are live-in to this block.
108 108
        if block.preds.len == 1 {
109 109
            let pred = &blkEnd[block.preds[0]];
110 110
            for k in 0..pred.n {
111 111
                if bitset::contains(&live.liveIn[b], pred.virtRegs[k]) {
112 -
                    current.virtRegs[current.n] = pred.virtRegs[k];
113 -
                    current.physRegs[current.n] = pred.physRegs[k];
114 -
                    current.n += 1;
112 +
                    set current.virtRegs[current.n] = pred.virtRegs[k];
113 +
                    set current.physRegs[current.n] = pred.physRegs[k];
114 +
                    set current.n += 1;
115 115
                    bitset::put(&mut usedRegs, *pred.physRegs[k] as u32);
116 116
                }
117 117
            }
118 118
        }
119 119
132 132
                    // Also track in current mapping for block-end state.
133 133
                    if rmapFind(&current, ssaReg) == nil {
134 134
                        rmapSet(&mut current, ssaReg, phys);
135 135
                    }
136 136
                } else {
137 -
                    assignments[ssaReg] = rallocReg(&mut current, &mut usedRegs, ssaReg, allocatable, config.calleeSaved, spillInfo);
137 +
                    set assignments[ssaReg] = rallocReg(&mut current, &mut usedRegs, ssaReg, allocatable, config.calleeSaved, spillInfo);
138 138
                }
139 139
            }
140 140
        }
141 141
142 142
        // Allocate block parameters.
143 143
        for p in block.params {
144 144
            if p.value.n < maxReg and not spill::isSpilled(spillInfo, p.value) {
145 -
                assignments[p.value.n] = rallocReg(&mut current, &mut usedRegs, p.value.n, allocatable, config.calleeSaved, spillInfo);
145 +
                set assignments[p.value.n] = rallocReg(&mut current, &mut usedRegs, p.value.n, allocatable, config.calleeSaved, spillInfo);
146 146
            }
147 147
        }
148 148
149 149
        // Process each instruction.
150 150
        for instr, i in block.instrs {
163 163
            il::forEachReg(instr, processInstrRegCb, &mut ctx as *mut opaque);
164 164
165 165
            // Allocate destination.
166 166
            if let dst = il::instrDst(instr) {
167 167
                if dst.n < maxReg and not spill::isSpilled(spillInfo, dst) {
168 -
                    assignments[dst.n] = rallocReg(&mut current, &mut usedRegs, dst.n, allocatable, config.calleeSaved, spillInfo);
168 +
                    set assignments[dst.n] = rallocReg(&mut current, &mut usedRegs, dst.n, allocatable, config.calleeSaved, spillInfo);
169 169
                }
170 170
            }
171 171
        }
172 172
        // Save block-end state.
173 -
        blkEnd[b].n = current.n;
173 +
        set blkEnd[b].n = current.n;
174 174
        for ri in 0..current.n {
175 -
            blkEnd[b].virtRegs[ri] = current.virtRegs[ri];
176 -
            blkEnd[b].physRegs[ri] = current.physRegs[ri];
175 +
            set blkEnd[b].virtRegs[ri] = current.virtRegs[ri];
176 +
            set blkEnd[b].physRegs[ri] = current.physRegs[ri];
177 177
        }
178 178
    }
179 179
    // Compute bitmask of used callee-saved registers.
180 180
    let mut usedCalleeSaved: u32 = 0;
181 181
    for i in 0..maxReg {
182 182
        if let phys = assignments[i] {
183 183
            for saved, j in config.calleeSaved {
184 184
                if *phys == *saved {
185 -
                    usedCalleeSaved |= (1 << j);
185 +
                    set usedCalleeSaved |= (1 << j);
186 186
                }
187 187
            }
188 188
        }
189 189
    }
190 190
213 213
}
214 214
215 215
/// Add a mapping to the register map.
216 216
fn rmapSet(rmap: *mut RegMap, virtReg: u32, physReg: gen::Reg) {
217 217
    assert rmap.n < MAX_ACTIVE, "rmapSet: register map overflow";
218 -
    rmap.virtRegs[rmap.n] = virtReg;
219 -
    rmap.physRegs[rmap.n] = physReg;
220 -
    rmap.n += 1;
218 +
    set rmap.virtRegs[rmap.n] = virtReg;
219 +
    set rmap.physRegs[rmap.n] = physReg;
220 +
    set rmap.n += 1;
221 221
}
222 222
223 223
/// Remove a mapping from register map.
224 224
fn rmapRemove(rmap: *mut RegMap, virtReg: u32) {
225 225
    for i in 0..rmap.n {
226 226
        if rmap.virtRegs[i] == virtReg {
227 227
            // Swap with last and decrement.
228 -
            rmap.n -= 1;
228 +
            set rmap.n -= 1;
229 229
            if i < rmap.n {
230 -
                rmap.virtRegs[i] = rmap.virtRegs[rmap.n];
231 -
                rmap.physRegs[i] = rmap.physRegs[rmap.n];
230 +
                set rmap.virtRegs[i] = rmap.virtRegs[rmap.n];
231 +
                set rmap.physRegs[i] = rmap.physRegs[rmap.n];
232 232
            }
233 233
            return;
234 234
        }
235 235
    }
236 236
    panic "rmapRemove: register not found";
290 290
    assert reg.n < ctx.assignments.len, "processInstrRegCb: register out of bounds";
291 291
    if spill::isSpilled(ctx.spillInfo, reg) {
292 292
        return; // Spilled values don't get physical registers.
293 293
    }
294 294
    if ctx.assignments[reg.n] == nil {
295 -
        ctx.assignments[reg.n] = rallocReg(
295 +
        set ctx.assignments[reg.n] = rallocReg(
296 296
            ctx.current, ctx.usedRegs, reg.n, ctx.allocatable,
297 297
            ctx.calleeSaved, ctx.spillInfo
298 298
        );
299 299
    }
300 300
}
lib/std/lang/gen/regalloc/liveness.rad +15 -15
74 74
    }
75 75
76 76
    // Find max register number.
77 77
    let mut maxReg: u32 = 0;
78 78
    for p in func.params {
79 -
        maxReg = maxRegNum(p.value.n, maxReg);
79 +
        set maxReg = maxRegNum(p.value.n, maxReg);
80 80
    }
81 81
    for b in 0..blockCount {
82 82
        let block = &func.blocks[b];
83 83
        for p in block.params {
84 -
            maxReg = maxRegNum(p.value.n, maxReg);
84 +
            set maxReg = maxRegNum(p.value.n, maxReg);
85 85
        }
86 86
        for i in 0..block.instrs.len {
87 87
            il::forEachReg(block.instrs[i], maxRegCallback, &mut maxReg as *mut opaque);
88 88
            if let dst = il::instrDst(block.instrs[i]) {
89 -
                maxReg = maxRegNum(dst.n, maxReg);
89 +
                set maxReg = maxRegNum(dst.n, maxReg);
90 90
            }
91 91
        }
92 92
    }
93 93
    assert maxReg <= MAX_SSA_REGS, "analyze: maximum SSA registers exceeded";
94 94
    // Allocate per-block bitsets.
96 96
    let liveOut = try alloc::allocSlice(arena, @sizeOf(bitset::Bitset), @alignOf(bitset::Bitset), blockCount) as *mut [bitset::Bitset];
97 97
    let defs = try alloc::allocSlice(arena, @sizeOf(bitset::Bitset), @alignOf(bitset::Bitset), blockCount) as *mut [bitset::Bitset];
98 98
    let uses = try alloc::allocSlice(arena, @sizeOf(bitset::Bitset), @alignOf(bitset::Bitset), blockCount) as *mut [bitset::Bitset];
99 99
100 100
    for b in 0..blockCount {
101 -
        liveIn[b] = try bitset::allocate(arena, maxReg);
102 -
        liveOut[b] = try bitset::allocate(arena, maxReg);
103 -
        defs[b] = try bitset::allocate(arena, maxReg);
104 -
        uses[b] = try bitset::allocate(arena, maxReg);
101 +
        set liveIn[b] = try bitset::allocate(arena, maxReg);
102 +
        set liveOut[b] = try bitset::allocate(arena, maxReg);
103 +
        set defs[b] = try bitset::allocate(arena, maxReg);
104 +
        set uses[b] = try bitset::allocate(arena, maxReg);
105 105
    }
106 106
107 107
    // Compute local defs and uses for each block.
108 108
    for b in 0..blockCount {
109 109
        computeLocalDefsUses(&func.blocks[b], &mut defs[b], &mut uses[b]);
111 111
    // Iterative dataflow analysis.
112 112
    let mut changed = true;
113 113
    let mut scratch = try bitset::allocate(arena, maxReg);
114 114
115 115
    while changed {
116 -
        changed = false;
116 +
        set changed = false;
117 117
118 118
        // Process blocks in reverse order (approximates post-order).
119 119
        let mut b = blockCount;
120 120
        while b > 0 {
121 -
            b -= 1;
121 +
            set b -= 1;
122 122
            let block = &func.blocks[b];
123 123
124 124
            // Compute new `liveOut` as union of successor `liveIn` sets.
125 125
            bitset::clearAll(&mut scratch);
126 126
            addSuccessorLiveIn(func, block, liveIn, &mut scratch);
127 127
128 128
            if not bitset::eq(&liveOut[b], &scratch) {
129 129
                bitset::copy(&mut liveOut[b], &scratch);
130 -
                changed = true;
130 +
                set changed = true;
131 131
            }
132 132
            if computeAndUpdateLiveIn(&mut liveIn[b], &liveOut[b], &defs[b], &uses[b]) {
133 -
                changed = true;
133 +
                set changed = true;
134 134
            }
135 135
        }
136 136
    }
137 137
    return LiveInfo { liveIn, liveOut, defs, uses, blockCount, maxReg };
138 138
}
148 148
    let numWords = dst.bits.len;
149 149
    let mut changed = false;
150 150
    for i in 0..numWords {
151 151
        let newWord = uses.bits[i] | (liveOut.bits[i] & ~defs.bits[i]);
152 152
        if dst.bits[i] <> newWord {
153 -
            dst.bits[i] = newWord;
154 -
            changed = true;
153 +
            set dst.bits[i] = newWord;
154 +
            set changed = true;
155 155
        }
156 156
    }
157 157
    return changed;
158 158
}
159 159
182 182
}
183 183
184 184
/// Callback for [`il::forEachReg`]: updates max register number.
185 185
fn maxRegCallback(reg: il::Reg, ctx: *mut opaque) {
186 186
    let max = ctx as *mut u32;
187 -
    *max = maxRegNum(reg.n, *max);
187 +
    set *max = maxRegNum(reg.n, *max);
188 188
}
189 189
190 190
/// Return the larger of n+1 and current.
191 191
fn maxRegNum(n: u32, current: u32) -> u32 {
192 192
    if n + 1 > current {
252 252
253 253
/// Callback for [`il::forEachReg`]: sets found if register matches target.
254 254
fn findRegCallback(reg: il::Reg, ctx: *mut opaque) {
255 255
    let c = ctx as *mut FindCtx;
256 256
    if reg.n == c.target {
257 -
        c.found = true;
257 +
        set c.found = true;
258 258
    }
259 259
}
lib/std/lang/gen/regalloc/spill.rad +15 -15
98 98
        };
99 99
    }
100 100
    // Allocate spill slots array.
101 101
    let slots = try alloc::allocSlice(arena, @sizeOf(i32), @alignOf(i32), maxReg) as *mut [i32];
102 102
    for i in 0..maxReg {
103 -
        slots[i] = -1;
103 +
        set slots[i] = -1;
104 104
    }
105 105
    // Allocate cost array.
106 106
    let costs = try alloc::allocSlice(arena, @sizeOf(SpillCost), @alignOf(SpillCost), maxReg) as *mut [SpillCost];
107 107
    for i in 0..maxReg {
108 -
        costs[i] = SpillCost { defs: 0, uses: 0 };
108 +
        set costs[i] = SpillCost { defs: 0, uses: 0 };
109 109
    }
110 110
    // Phase 1: Calculate spill costs.
111 111
    fillCosts(func, costs);
112 112
113 113
    // Phase 2: Find values that exceed register pressure.
122 122
        bitset::copy(&mut scratch, &live.liveOut[b]);
123 123
124 124
        // Walk instructions backwards.
125 125
        let mut i = block.instrs.len;
126 126
        while i > 0 {
127 -
            i -= 1;
127 +
            set i -= 1;
128 128
            let instr = block.instrs[i];
129 129
130 130
            // Limit register pressure before processing this instruction.
131 131
            limitPressure(&mut scratch, &mut spilled, costs, numRegs);
132 132
166 166
    // Phase 4: Assign stack slots to spilled values.
167 167
    let mut frameSize: i32 = 0;
168 168
    let mut it = bitset::iter(&spilled);
169 169
170 170
    while let n = bitset::iterNext(&mut it) {
171 -
        slots[n] = frameSize;
172 -
        frameSize += slotSize as i32;
171 +
        set slots[n] = frameSize;
172 +
        set frameSize += slotSize as i32;
173 173
    }
174 174
    return SpillInfo { slots, frameSize, calleeClass, maxReg };
175 175
}
176 176
177 177
/// Calculate spill costs for all registers, weighted by loop depth.
184 184
        let weight: u32 = 1 << depth;
185 185
186 186
        // Count block parameter definitions.
187 187
        for p in block.params {
188 188
            if p.value.n < costs.len {
189 -
                costs[p.value.n].defs = costs[p.value.n].defs + weight;
189 +
                set costs[p.value.n].defs = costs[p.value.n].defs + weight;
190 190
            }
191 191
        }
192 192
        // Count instruction defs and uses.
193 193
        for i in 0..block.instrs.len {
194 194
            let instr = block.instrs[i];
195 195
196 196
            // Count definition.
197 197
            if let dst = il::instrDst(instr) {
198 198
                if dst.n < costs.len {
199 -
                    costs[dst.n].defs = costs[dst.n].defs + weight;
199 +
                    set costs[dst.n].defs = costs[dst.n].defs + weight;
200 200
                }
201 201
            }
202 202
            // Count uses.
203 203
            let mut ctx = CountCtx { costs, weight };
204 204
            il::forEachReg(instr, countRegUseCallback, &mut ctx as *mut opaque);
217 217
    // Insertion sort ascending by cost.
218 218
    for i in 1..c.n {
219 219
        let key = c.entries[i];
220 220
        let mut j: u32 = i;
221 221
        while j > 0 and c.entries[j - 1].cost > key.cost {
222 -
            c.entries[j] = c.entries[j - 1];
223 -
            j -= 1;
222 +
            set c.entries[j] = c.entries[j - 1];
223 +
            set j -= 1;
224 224
        }
225 -
        c.entries[j] = key;
225 +
        set c.entries[j] = key;
226 226
    }
227 227
    let toSpill = c.n if excess > c.n else excess;
228 228
    for i in 0..toSpill {
229 229
        bitset::put(spilled, c.entries[i].reg);
230 230
        bitset::clear(source, c.entries[i].reg);
236 236
    let mut c = Candidates { entries: undefined, n: 0 };
237 237
    let mut it = bitset::iter(bs);
238 238
    while let reg = bitset::iterNext(&mut it) {
239 239
        assert c.n < MAX_CANDIDATES, "collectCandidates: too many live values";
240 240
        if reg < costs.len {
241 -
            c.entries[c.n] = CostEntry { reg, cost: costs[reg].defs + costs[reg].uses };
242 -
            c.n += 1;
241 +
            set c.entries[c.n] = CostEntry { reg, cost: costs[reg].defs + costs[reg].uses };
242 +
            set c.n += 1;
243 243
        }
244 244
    }
245 245
    return c;
246 246
}
247 247
285 285
    let mut candidates: [CostEntry; 256] = undefined;
286 286
    let mut numCandidates: u32 = 0;
287 287
    let mut it = bitset::iter(live);
288 288
    while let n = bitset::iterNext(&mut it) {
289 289
        if not isCallDst(callDst, n) and n < costs.len {
290 -
            candidates[numCandidates] = CostEntry {
290 +
            set candidates[numCandidates] = CostEntry {
291 291
                reg: n,
292 292
                cost: costs[n].defs + costs[n].uses,
293 293
            };
294 -
            numCandidates += 1;
294 +
            set numCandidates += 1;
295 295
        }
296 296
    }
297 297
    // Spill cheapest candidates if crossing count exceeds callee-saved capacity.
298 298
    if numCandidates > numCalleeSaved {
299 299
        let mut c = Candidates { entries: candidates, n: numCandidates };
310 310
311 311
/// Callback for [`il::forEachReg`]: increments use count for register.
312 312
fn countRegUseCallback(reg: il::Reg, ctxPtr: *mut opaque) {
313 313
    let ctx = ctxPtr as *mut CountCtx;
314 314
    assert reg.n < ctx.costs.len, "countRegUseCallback: register out of bounds";
315 -
    ctx.costs[reg.n].uses = ctx.costs[reg.n].uses + ctx.weight;
315 +
    set ctx.costs[reg.n].uses = ctx.costs[reg.n].uses + ctx.weight;
316 316
}
317 317
318 318
/// Callback for [`il::forEachReg`]: adds register to live set.
319 319
fn addRegToSetCallback(reg: il::Reg, ctx: *mut opaque) {
320 320
    bitset::put(ctx as *mut bitset::Bitset, reg.n);
lib/std/lang/il.rad +3 -3
83 83
84 84
/// Format a qualified symbol name: `pkg::mod::path::name`.
85 85
export fn formatQualifiedName(arena: *mut alloc::Arena, path: *[*[u8]], name: *[u8]) -> *[u8] {
86 86
    let mut totalLen: u32 = name.len;
87 87
    for segment in path {
88 -
        totalLen += segment.len + PATH_SEPARATOR.len;
88 +
        set totalLen += segment.len + PATH_SEPARATOR.len;
89 89
    }
90 90
    let buf = try! alloc::allocSlice(arena, 1, 1, totalLen) as *mut [u8];
91 91
    let mut pos: u32 = 0;
92 92
93 93
    for segment in path {
94 -
        pos += try! mem::copy(&mut buf[pos..], segment);
95 -
        pos += try! mem::copy(&mut buf[pos..], PATH_SEPARATOR);
94 +
        set pos += try! mem::copy(&mut buf[pos..], segment);
95 +
        set pos += try! mem::copy(&mut buf[pos..], PATH_SEPARATOR);
96 96
    }
97 97
    try! mem::copy(&mut buf[pos..], name);
98 98
99 99
    return &buf[..totalLen];
100 100
}
lib/std/lang/il/printer.rad +1 -1
37 37
/// Concatenate prefix and string in the arena.
38 38
fn prefixStr(a: *mut alloc::Arena, prefix: u8, str: *[u8]) -> *[u8] {
39 39
    let len = str.len + 1;
40 40
    let ptr = try! alloc::allocSlice(a, 1, 1, len);
41 41
    let slice = ptr as *mut [u8];
42 -
    slice[0] = prefix;
42 +
    set slice[0] = prefix;
43 43
    try! mem::copy(&mut slice[1..], str);
44 44
45 45
    return slice;
46 46
}
47 47
lib/std/lang/lower.rad +227 -236
305 305
fn maxErrSize(throwList: *[*resolver::Type]) -> u32 {
306 306
    let mut maxSize: u32 = 0;
307 307
    for ty in throwList {
308 308
        let size = resolver::getTypeLayout(*ty).size;
309 309
        if size > maxSize {
310 -
            maxSize = size;
310 +
            set maxSize = size;
311 311
        }
312 312
    }
313 313
    return maxSize;
314 314
}
315 315
321 321
            return entry.tag;
322 322
        }
323 323
    }
324 324
    let tag = self.errTagCounter;
325 325
326 -
    self.errTagCounter += 1;
326 +
    set self.errTagCounter += 1;
327 327
    self.errTags.append(ErrTagEntry { ty: errType, tag }, self.allocator);
328 328
329 329
    return tag;
330 330
}
331 331
351 351
/// Append a data value to the builder.
352 352
fn dataBuilderPush(b: *mut DataValueBuilder, value: il::DataValue) {
353 353
    b.values.append(value, b.allocator);
354 354
355 355
    if value.item <> il::DataItem::Undef {
356 -
        b.allUndef = false;
356 +
        set b.allUndef = false;
357 357
    }
358 358
}
359 359
360 360
/// Return the accumulated values.
361 361
fn dataBuilderFinish(b: *DataValueBuilder) -> ConstDataResult {
737 737
    low: *mut Lowerer,
738 738
    moduleId: u16,
739 739
    root: *ast::Node,
740 740
    isRoot: bool
741 741
) -> ?u32 throws (LowerError) {
742 -
    low.currentMod = moduleId;
742 +
    set low.currentMod = moduleId;
743 743
    return try lowerDecls(low, root, isRoot);
744 744
}
745 745
746 746
/// Lower all top-level declarations in a block.
747 747
fn lowerDecls(low: *mut Lowerer, root: *ast::Node, isRoot: bool) -> ?u32 throws (LowerError) {
754 754
    for node in stmtsList {
755 755
        match node.value {
756 756
            case ast::NodeValue::FnDecl(decl) => {
757 757
                if let f = try lowerFnDecl(low, node, decl) {
758 758
                    if isRoot and checkAttr(decl.attrs, ast::Attribute::Default) {
759 -
                        defaultFnIdx = low.fns.len;
759 +
                        set defaultFnIdx = low.fns.len;
760 760
                    }
761 761
                    low.fns.append(f, low.allocator);
762 762
                }
763 763
            }
764 764
            case ast::NodeValue::ConstDecl(decl) => {
800 800
    let graph = self.moduleGraph else {
801 801
        return &[];
802 802
    };
803 803
    let mut id = modId;
804 804
    if id == nil {
805 -
        id = self.currentMod;
805 +
        set id = self.currentMod;
806 806
    }
807 807
    let actualId = id else {
808 808
        return &[];
809 809
    };
810 810
    let entry = module::get(graph, actualId) else {
845 845
}
846 846
847 847
/// Set the package context for lowering.
848 848
/// Called before lowering each package.
849 849
export fn setPackage(self: *mut Lowerer, graph: *module::ModuleGraph, pkgName: *[u8]) {
850 -
    self.moduleGraph = graph;
851 -
    self.pkgName = pkgName;
852 -
    self.currentMod = nil;
850 +
    set self.moduleGraph = graph;
851 +
    set self.pkgName = pkgName;
852 +
    set self.currentMod = nil;
853 853
}
854 854
855 855
/// Create a new function lowerer for a given function type and name.
856 856
fn fnLowerer(
857 857
    self: *mut Lowerer,
882 882
    };
883 883
    if self.options.debug {
884 884
        let modId = self.currentMod else {
885 885
            panic "fnLowerer: debug enabled but no current module";
886 886
        };
887 -
        fnLow.srcLoc = il::SrcLoc {
887 +
        set fnLow.srcLoc = il::SrcLoc {
888 888
            moduleId: modId,
889 889
            offset: node.span.offset,
890 890
        };
891 891
    }
892 892
    return fnLow;
923 923
924 924
    // If the function returns an aggregate or is throwing, prepend a hidden
925 925
    // return parameter. The caller allocates the buffer and passes it
926 926
    // as the first argument; the callee writes the return value into it.
927 927
    if requiresReturnParam(fnType) and not isExtern {
928 -
        fnLow.returnReg = nextReg(&mut fnLow);
928 +
        set fnLow.returnReg = nextReg(&mut fnLow);
929 929
    }
930 930
    let lowParams = try lowerParams(&mut fnLow, *fnType, decl.sig.params, nil);
931 931
    let func = try! alloc::alloc(self.arena, @sizeOf(il::Fn), @alignOf(il::Fn)) as *mut il::Fn;
932 932
933 -
    *func = il::Fn {
933 +
    set *func = il::Fn {
934 934
        name: qualName,
935 935
        params: lowParams,
936 936
        returnType: undefined,
937 937
        isExtern,
938 938
        isLeaf: true,
941 941
    // Throwing functions return a result aggregate (word-sized pointer).
942 942
    // TODO: The resolver should set an appropriate type that takes into account
943 943
    //       the throws list. It shouldn't set the return type to the "success"
944 944
    //       value only.
945 945
    if fnType.throwList.len > 0 {
946 -
        func.returnType = il::Type::W64;
946 +
        set func.returnType = il::Type::W64;
947 947
    } else {
948 -
        func.returnType = ilType(self, *fnType.returnType);
948 +
        set func.returnType = ilType(self, *fnType.returnType);
949 949
    }
950 950
    let body = decl.body else {
951 951
        // Extern functions have no body.
952 952
        assert isExtern;
953 953
        return func;
954 954
    };
955 -
    func.blocks = try lowerFnBody(&mut fnLow, body);
956 -
    func.isLeaf = fnLow.isLeaf;
955 +
    set func.blocks = try lowerFnBody(&mut fnLow, body);
956 +
    set func.isLeaf = fnLow.isLeaf;
957 957
958 958
    return func;
959 959
}
960 960
961 961
/// Build a qualified name of the form "Type::method".
963 963
    let sepLen: u32 = 2; // "::"
964 964
    let totalLen = typeName.len + sepLen + methodName.len;
965 965
    let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8];
966 966
    let mut pos: u32 = 0;
967 967
968 -
    pos += try! mem::copy(&mut buf[pos..], typeName);
969 -
    pos += try! mem::copy(&mut buf[pos..], "::");
970 -
    pos += try! mem::copy(&mut buf[pos..], methodName);
968 +
    set pos += try! mem::copy(&mut buf[pos..], typeName);
969 +
    set pos += try! mem::copy(&mut buf[pos..], "::");
970 +
    set pos += try! mem::copy(&mut buf[pos..], methodName);
971 971
    assert pos == totalLen;
972 972
973 973
    return qualifyName(self, modId, &buf[..totalLen]);
974 974
}
975 975
979 979
    let sepLen: u32 = 2; // "::"
980 980
    let totalLen = prefix.len + typeName.len + sepLen + traitName.len;
981 981
    let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8];
982 982
    let mut pos: u32 = 0;
983 983
984 -
    pos += try! mem::copy(&mut buf[pos..], prefix);
985 -
    pos += try! mem::copy(&mut buf[pos..], typeName);
986 -
    pos += try! mem::copy(&mut buf[pos..], "::");
987 -
    pos += try! mem::copy(&mut buf[pos..], traitName);
984 +
    set pos += try! mem::copy(&mut buf[pos..], prefix);
985 +
    set pos += try! mem::copy(&mut buf[pos..], typeName);
986 +
    set pos += try! mem::copy(&mut buf[pos..], "::");
987 +
    set pos += try! mem::copy(&mut buf[pos..], traitName);
988 988
    assert pos == totalLen;
989 989
990 990
    return qualifyName(self, modId, &buf[..totalLen]);
991 991
}
992 992
1035 1035
        self.fns.append(func, self.allocator);
1036 1036
1037 1037
        let method = resolver::findTraitMethod(traitInfo, mName)
1038 1038
            else panic "lowerInstanceDecl: method not found in trait";
1039 1039
1040 -
        methodNames[method.index] = qualName;
1041 -
        methodNameSet[method.index] = true;
1040 +
        set methodNames[method.index] = qualName;
1041 +
        set methodNameSet[method.index] = true;
1042 1042
    }
1043 1043
1044 1044
    // Fill inherited method slots from supertraits.
1045 1045
    // These methods were already lowered as part of the supertrait instance
1046 1046
    // declarations and use the same `Type::method` qualified name.
1047 1047
    for method, i in traitInfo.methods {
1048 1048
        if not methodNameSet[i] {
1049 -
            methodNames[i] = instanceMethodName(self, nil, typeName, method.name);
1049 +
            set methodNames[i] = instanceMethodName(self, nil, typeName, method.name);
1050 1050
        }
1051 1051
    }
1052 1052
1053 1053
    // Create v-table in data section, used for dynamic dispatch.
1054 1054
    let vName = vtableName(self, nil, typeName, tName);
1055 1055
    let values = try! alloc::allocSlice(
1056 1056
        self.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue), traitInfo.methods.len as u32
1057 1057
    ) as *mut [il::DataValue];
1058 1058
1059 1059
    for i in 0..traitInfo.methods.len {
1060 -
        values[i] = il::DataValue {
1060 +
        set values[i] = il::DataValue {
1061 1061
            item: il::DataItem::Fn(methodNames[i]),
1062 1062
            count: 1,
1063 1063
        };
1064 1064
    }
1065 1065
    self.data.append(il::Data {
1089 1089
    let sym = data.sym else throw LowerError::MissingSymbol(node);
1090 1090
    registerFnSym(self, sym, qualName);
1091 1091
1092 1092
    let mut fnLow = fnLowerer(self, node, fnType, qualName);
1093 1093
    if requiresReturnParam(fnType) {
1094 -
        fnLow.returnReg = nextReg(&mut fnLow);
1094 +
        set fnLow.returnReg = nextReg(&mut fnLow);
1095 1095
    }
1096 1096
    let lowParams = try lowerParams(&mut fnLow, *fnType, sig.params, receiverName);
1097 1097
    let func = try! alloc::alloc(self.arena, @sizeOf(il::Fn), @alignOf(il::Fn)) as *mut il::Fn;
1098 1098
1099 -
    *func = il::Fn {
1099 +
    set *func = il::Fn {
1100 1100
        name: qualName,
1101 1101
        params: lowParams,
1102 1102
        returnType: ilType(self, *fnType.returnType),
1103 1103
        isExtern: false,
1104 1104
        isLeaf: true,
1105 1105
        blocks: &[],
1106 1106
    };
1107 1107
    if fnType.throwList.len > 0 {
1108 -
        func.returnType = il::Type::W64;
1108 +
        set func.returnType = il::Type::W64;
1109 1109
    }
1110 -
    func.blocks = try lowerFnBody(&mut fnLow, body);
1111 -
    func.isLeaf = fnLow.isLeaf;
1110 +
    set func.blocks = try lowerFnBody(&mut fnLow, body);
1111 +
    set func.isLeaf = fnLow.isLeaf;
1112 1112
1113 1113
    return func;
1114 1114
}
1115 1115
1116 1116
/// Lower a standalone method declaration.
1165 1165
}
1166 1166
1167 1167
/// Generate a unique label by appending the global counter to the base.
1168 1168
fn nextLabel(self: *mut FnLowerer, base: *[u8]) -> *[u8] throws (LowerError) {
1169 1169
    let idx = self.labelCounter;
1170 -
    self.labelCounter += 1;
1170 +
    set self.labelCounter += 1;
1171 1171
1172 1172
    return try labelWithSuffix(self, base, idx);
1173 1173
}
1174 1174
1175 1175
///////////////////////////////
1210 1210
        return il::DataItem::Str(s);
1211 1211
    }
1212 1212
    // Bool and char are byte-sized; integer uses the declared type.
1213 1213
    let mut irTyp = il::Type::W8;
1214 1214
    if let case resolver::ConstValue::Int(_) = val {
1215 -
        irTyp = ilType(self, typ);
1215 +
        set irTyp = ilType(self, typ);
1216 1216
    }
1217 1217
    return il::DataItem::Val { typ: irTyp, val: constToScalar(val) };
1218 1218
}
1219 1219
1220 1220
/// Lower a constant or static declaration to the data section.
1291 1291
    let backing = dataBuilderFinish(&nested);
1292 1292
    let readOnly = not mutable;
1293 1293
    let mut dataName: *[u8] = undefined;
1294 1294
    if readOnly {
1295 1295
        if let found = findConstData(self, backing.values, layout.alignment) {
1296 -
            dataName = found;
1296 +
            set dataName = found;
1297 1297
        } else {
1298 -
            dataName = try pushDeclData(self, layout.size, layout.alignment, readOnly, backing.values, dataPrefix);
1298 +
            set dataName = try pushDeclData(self, layout.size, layout.alignment, readOnly, backing.values, dataPrefix);
1299 1299
        }
1300 1300
    } else {
1301 -
        dataName = try pushDeclData(self, layout.size, layout.alignment, readOnly, backing.values, dataPrefix);
1301 +
        set dataName = try pushDeclData(self, layout.size, layout.alignment, readOnly, backing.values, dataPrefix);
1302 1302
    }
1303 1303
    dataSliceHeader(b, dataName, arrInfo.length);
1304 1304
}
1305 1305
1306 1306
/// Lower a constant expression into a builder, padding to slotSize.
1485 1485
) throws (LowerError) {
1486 1486
    let layout = recInfo.layout;
1487 1487
    for argNode, i in args {
1488 1488
        let mut valueNode = argNode;
1489 1489
        if let case ast::NodeValue::RecordLitField(fieldLit) = argNode.value {
1490 -
            valueNode = fieldLit.value;
1490 +
            set valueNode = fieldLit.value;
1491 1491
        }
1492 1492
        let fieldInfo = recInfo.fields[i];
1493 1493
        let fieldOffset = fieldInfo.offset as u32;
1494 1494
1495 1495
        // Slot extends to the next field's offset,
1582 1582
    let suffixStart = prefix.len + 1;
1583 1583
    let totalLen = suffixStart + suffix.len;
1584 1584
    let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8];
1585 1585
1586 1586
    try! mem::copy(&mut buf[..prefix.len], prefix);
1587 -
    buf[prefix.len] = '$';
1587 +
    set buf[prefix.len] = '$';
1588 1588
    try! mem::copy(&mut buf[suffixStart..], suffix);
1589 1589
1590 1590
    return &buf[..totalLen];
1591 1591
}
1592 1592
1616 1616
    }
1617 1617
    let values = try! alloc::allocSlice(
1618 1618
        self.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue), 1
1619 1619
    ) as *mut [il::DataValue];
1620 1620
1621 -
    values[0] = il::DataValue {
1621 +
    set values[0] = il::DataValue {
1622 1622
        item: il::DataItem::Str(s),
1623 1623
        count: 1
1624 1624
    };
1625 1625
    return try pushDeclData(self, s.len, 1, true, &values[..1], dataPrefix);
1626 1626
}
1716 1716
    let elemLayout = resolver::getTypeLayout(*elemTy);
1717 1717
    let size = elemLayout.size * length;
1718 1718
    let mut dataName: *[u8] = undefined;
1719 1719
    if readOnly {
1720 1720
        if let found = findConstData(self.low, values, alignment) {
1721 -
            dataName = found;
1721 +
            set dataName = found;
1722 1722
        } else {
1723 -
            dataName = try nextDataName(self);
1723 +
            set dataName = try nextDataName(self);
1724 1724
            self.low.data.append(il::Data { name: dataName, size, alignment, readOnly, isUndefined: false, values }, self.low.allocator);
1725 1725
        }
1726 1726
    } else {
1727 -
        dataName = try nextDataName(self);
1727 +
        set dataName = try nextDataName(self);
1728 1728
        self.low.data.append(il::Data { name: dataName, size, alignment, readOnly, isUndefined: false, values }, self.low.allocator);
1729 1729
    }
1730 1730
1731 1731
    // Get data address.
1732 1732
    let ptrReg = nextReg(self);
1738 1738
}
1739 1739
1740 1740
/// Generate a unique data name for inline literals, eg. `fnName/N`
1741 1741
fn nextDataName(self: *mut FnLowerer) -> *[u8] throws (LowerError) {
1742 1742
    let counter = self.dataCounter;
1743 -
    self.dataCounter += 1;
1743 +
    set self.dataCounter += 1;
1744 1744
    return try labelWithSuffix(self, self.fnName, counter);
1745 1745
}
1746 1746
1747 1747
/// Get the next available SSA register.
1748 1748
fn nextReg(self: *mut FnLowerer) -> il::Reg {
1749 1749
    let reg = il::Reg { n: self.regCounter };
1750 -
    self.regCounter += 1;
1750 +
    set self.regCounter += 1;
1751 1751
    return reg;
1752 1752
}
1753 1753
1754 1754
/// Look up the resolved type of an AST node, or throw `MissingType`.
1755 1755
fn typeOf(self: *mut FnLowerer, node: *ast::Node) -> resolver::Type throws (LowerError) {
1769 1769
/// Used when detecting a trivial phi that can be eliminated.
1770 1770
fn removeLastBlockParam(self: *mut FnLowerer, block: BlockId) {
1771 1771
    let blk = getBlockMut(self, block);
1772 1772
    if blk.params.len > 0 {
1773 1773
        // TODO: Use `pop`?
1774 -
        blk.params = @sliceOf(blk.params.ptr, blk.params.len - 1, blk.params.cap);
1774 +
        set blk.params = @sliceOf(blk.params.ptr, blk.params.len - 1, blk.params.cap);
1775 1775
    }
1776 1776
    if blk.paramVars.len > 0 {
1777 1777
        // TODO: Use `pop`?
1778 -
        blk.paramVars = @sliceOf(blk.paramVars.ptr, blk.paramVars.len - 1, blk.paramVars.cap);
1778 +
        set blk.paramVars = @sliceOf(blk.paramVars.ptr, blk.paramVars.len - 1, blk.paramVars.cap);
1779 1779
    }
1780 1780
}
1781 1781
1782 1782
/// Rewrite cached SSA values for a variable across all blocks, and also
1783 1783
/// rewrite any terminator arguments that reference the provisional register.
1786 1786
/// found to be trivial.
1787 1787
fn rewriteCachedVarValue(self: *mut FnLowerer, v: Var, from: il::Val, to: il::Val) {
1788 1788
    for i in 0..self.blockData.len {
1789 1789
        let blk = getBlockMut(self, BlockId(i));
1790 1790
        if blk.vars[*v] == from {
1791 -
            blk.vars[*v] = to;
1791 +
            set blk.vars[*v] = to;
1792 1792
        }
1793 1793
        if blk.instrs.len > 0 {
1794 1794
            let ix = blk.instrs.len - 1;
1795 1795
            match &mut blk.instrs[ix] {
1796 1796
                case il::Instr::Jmp { args, .. } =>
1813 1813
1814 1814
/// Replace all occurrences of `from` with `to` in an args slice.
1815 1815
fn rewriteValInSlice(args: *mut [il::Val], from: il::Val, to: il::Val) {
1816 1816
    for i in 0..args.len {
1817 1817
        if args[i] == from {
1818 -
            args[i] = to;
1818 +
            set args[i] = to;
1819 1819
        }
1820 1820
    }
1821 1821
}
1822 1822
1823 1823
////////////////////////////
1846 1846
    let id = BlockId(self.blockData.len);
1847 1847
    let varCount = self.fnType.localCount;
1848 1848
    let vars = try! alloc::allocSlice(self.low.arena, @sizeOf(?il::Val), @alignOf(?il::Val), varCount) as *mut [?il::Val];
1849 1849
1850 1850
    for i in 0..varCount {
1851 -
        vars[i] = nil;
1851 +
        set vars[i] = nil;
1852 1852
    }
1853 1853
    self.blockData.append(BlockData {
1854 1854
        label,
1855 1855
        params: &mut [],
1856 1856
        paramVars: &mut [],
1879 1879
}
1880 1880
1881 1881
/// Switch to building a different block.
1882 1882
/// All subsequent `emit` calls will add instructions to this block.
1883 1883
fn switchToBlock(self: *mut FnLowerer, block: BlockId) {
1884 -
    self.currentBlock = block;
1884 +
    set self.currentBlock = block;
1885 1885
}
1886 1886
1887 1887
/// Seal a block, indicating all predecessor edges are now known.
1888 1888
///
1889 1889
/// Sealing enables SSA construction to resolve variable uses by looking up
1892 1892
fn sealBlock(self: *mut FnLowerer, block: BlockId) throws (LowerError) {
1893 1893
    let blk = getBlockMut(self, block);
1894 1894
    let case Sealed::No { incompleteVars } = blk.sealState else {
1895 1895
        return; // Already sealed.
1896 1896
    };
1897 -
    blk.sealState = Sealed::Yes;
1897 +
    set blk.sealState = Sealed::Yes;
1898 1898
1899 1899
    // Complete all incomplete block parameters.
1900 1900
    for varId in incompleteVars {
1901 1901
        try resolveBlockArgs(self, block, Var(varId));
1902 1902
    }
1937 1937
1938 1938
    // Track whether this function is a leaf.
1939 1939
    if self.isLeaf {
1940 1940
        match instr {
1941 1941
            case il::Instr::Call { .. },
1942 -
                 il::Instr::Ecall { .. } => self.isLeaf = false,
1942 +
                 il::Instr::Ecall { .. } => set self.isLeaf = false,
1943 1943
            else => {},
1944 1944
        }
1945 1945
    }
1946 1946
    // Record source location alongside instruction when enabled.
1947 1947
    if self.low.options.debug {
2230 2230
            if unionInfo.isAllVoid {
2231 2231
                let mut tagVal = subject.val;
2232 2232
                match subject.by {
2233 2233
                    case resolver::MatchBy::Ref, resolver::MatchBy::MutRef => {
2234 2234
                        let base = emitValToReg(self, subject.val);
2235 -
                        tagVal = loadTag(self, base, 0, il::Type::W8);
2235 +
                        set tagVal = loadTag(self, base, 0, il::Type::W8);
2236 2236
                    }
2237 2237
                    case resolver::MatchBy::Value => {}
2238 2238
                }
2239 2239
                try emitBrCmp(self, il::CmpOp::Eq, il::Type::W8, tagVal, il::Val::Imm(variantTag as i64), matchBlock, fallthrough);
2240 2240
            } else {
2355 2355
/// In the above example, the merge block stays `nil`, and no code is generated
2356 2356
/// after the `if`. The merge block is created on first use.
2357 2357
fn emitMergeIfUnterminated(self: *mut FnLowerer, mergeBlock: *mut ?BlockId) throws (LowerError) {
2358 2358
    if not blockHasTerminator(self) {
2359 2359
        if *mergeBlock == nil {
2360 -
            *mergeBlock = try createBlock(self, "merge");
2360 +
            set *mergeBlock = try createBlock(self, "merge");
2361 2361
        }
2362 2362
        let target = *mergeBlock else { throw LowerError::MissingTarget; };
2363 2363
        try emitJmp(self, target);
2364 2364
    }
2365 2365
}
2389 2389
    ) as *mut [il::Block];
2390 2390
2391 2391
    for i in 0..self.blockData.len {
2392 2392
        let data = &self.blockData[i];
2393 2393
2394 -
        blocks[i] = il::Block {
2394 +
        set blocks[i] = il::Block {
2395 2395
            label: data.label,
2396 2396
            params: &data.params[..],
2397 2397
            instrs: data.instrs,
2398 2398
            locs: &data.locs[..],
2399 2399
            preds: &data.preds[..],
2411 2411
/// `continueBlock` is `nil` when the continue target is created lazily.
2412 2412
fn enterLoop(self: *mut FnLowerer, breakBlock: BlockId, continueBlock: ?BlockId) {
2413 2413
    assert self.loopDepth < self.loopStack.len, "enterLoop: loop depth overflow";
2414 2414
    let slot = &mut self.loopStack[self.loopDepth];
2415 2415
2416 -
    slot.breakTarget = breakBlock;
2417 -
    slot.continueTarget = continueBlock;
2418 -
    self.loopDepth += 1;
2416 +
    set slot.breakTarget = breakBlock;
2417 +
    set slot.continueTarget = continueBlock;
2418 +
    set self.loopDepth += 1;
2419 2419
}
2420 2420
2421 2421
/// Exit the current loop context.
2422 2422
fn exitLoop(self: *mut FnLowerer) {
2423 2423
    assert self.loopDepth <> 0, "exitLoop: loopDepth is zero";
2424 -
    self.loopDepth -= 1;
2424 +
    set self.loopDepth -= 1;
2425 2425
}
2426 2426
2427 2427
/// Get the current loop context.
2428 2428
fn currentLoop(self: *mut FnLowerer) -> ?*mut LoopCtx {
2429 2429
    if self.loopDepth == 0 {
2439 2439
    };
2440 2440
    if let block = ctx.continueTarget {
2441 2441
        return block;
2442 2442
    }
2443 2443
    let block = try createBlock(self, "step");
2444 -
    ctx.continueTarget = block;
2444 +
    set ctx.continueTarget = block;
2445 2445
    return block;
2446 2446
}
2447 2447
2448 2448
/// Allocate a slice of values in the lowering arena.
2449 2449
fn allocVals(self: *mut FnLowerer, len: u32) -> *mut [il::Val] throws (LowerError) {
2451 2451
}
2452 2452
2453 2453
/// Allocate a single-value slice in the lowering arena.
2454 2454
fn allocVal(self: *mut FnLowerer, val: il::Val) -> *mut [il::Val] throws (LowerError) {
2455 2455
    let args = try allocVals(self, 1);
2456 -
    args[0] = val;
2456 +
    set args[0] = val;
2457 2457
    return args;
2458 2458
}
2459 2459
2460 2460
////////////////////////
2461 2461
// SSA Var Management //
2568 2568
/// current block. Called when a variable is assigned or initialized (`let`
2569 2569
/// bindings, assignments, loop updates). When [`useVar`] is later called,
2570 2570
/// it will retrieve this value.
2571 2571
fn defVar(self: *mut FnLowerer, v: Var, val: il::Val) {
2572 2572
    assert *v < self.vars.len;
2573 -
    getBlockMut(self, currentBlock(self)).vars[*v] = val;
2573 +
    set getBlockMut(self, currentBlock(self)).vars[*v] = val;
2574 2574
}
2575 2575
2576 2576
/// Use (read) the current value of a variable in the current block.
2577 2577
/// May insert block parameters if the value must come from predecessors.
2578 2578
fn useVar(self: *mut FnLowerer, v: Var) -> il::Val throws (LowerError) {
2606 2606
        // available without a block parameter.
2607 2607
        if blk.preds.len == 1 {
2608 2608
            let pred = BlockId(blk.preds[0]);
2609 2609
            if *pred <> *block {
2610 2610
                let val = try useVarInBlock(self, pred, v);
2611 -
                blk.vars[*v] = val; // Cache.
2611 +
                set blk.vars[*v] = val; // Cache.
2612 2612
                return val;
2613 2613
            }
2614 2614
        }
2615 2615
    }
2616 2616
    // Multiple predecessors or unsealed block: need a block parameter to merge
2621 2621
/// Look up a variable by name in the current scope.
2622 2622
/// Searches from most recently declared to first, enabling shadowing.
2623 2623
fn lookupVarByName(self: *FnLowerer, name: *[u8]) -> ?Var {
2624 2624
    let mut id = self.vars.len;
2625 2625
    while id > 0 {
2626 -
        id -= 1;
2626 +
        set id -= 1;
2627 2627
        if let varName = self.vars[id].name {
2628 2628
            // Names are interned strings, so pointer comparison suffices.
2629 2629
            if varName == name {
2630 2630
                return Var(id);
2631 2631
            }
2647 2647
    return self.vars.len;
2648 2648
}
2649 2649
2650 2650
/// Restore lexical variable scope depth.
2651 2651
fn exitVarScope(self: *mut FnLowerer, savedVarsLen: u32) {
2652 -
    self.vars = @sliceOf(self.vars.ptr, savedVarsLen, self.vars.cap);
2652 +
    set self.vars = @sliceOf(self.vars.ptr, savedVarsLen, self.vars.cap);
2653 2653
}
2654 2654
2655 2655
/// Get the metadata for a variable.
2656 2656
fn getVar(self: *FnLowerer, v: Var) -> *VarData {
2657 2657
    assert *v < self.vars.len;
2687 2687
    blk.params.append(param, self.allocator);
2688 2688
    blk.paramVars.append(*v, self.allocator); // Associate variable with parameter.
2689 2689
2690 2690
    // Record that this variable's value in this block is now the parameter register.
2691 2691
    // This must happen before the predecessor loop to handle self-referential loops.
2692 -
    blk.vars[*v] = il::Val::Reg(reg);
2692 +
    set blk.vars[*v] = il::Val::Reg(reg);
2693 2693
2694 2694
    match &mut blk.sealState {
2695 2695
        case Sealed::No { incompleteVars } => {
2696 2696
            // Block unsealed: defer until sealing.
2697 2697
            incompleteVars.append(*v, self.allocator);
2702 2702
            // just created and use that value directly.
2703 2703
            if let trivial = try getTrivialPhiVal(self, block, v) {
2704 2704
                let provisional = il::Val::Reg(reg);
2705 2705
                removeLastBlockParam(self, block);
2706 2706
                rewriteCachedVarValue(self, v, provisional, trivial);
2707 -
                getBlockMut(self, block).vars[*v] = trivial;
2707 +
                set getBlockMut(self, block).vars[*v] = trivial;
2708 2708
                return trivial;
2709 2709
            }
2710 2710
            // Non-trivial phi: patch predecessors to pass their values.
2711 2711
            try resolveBlockArgs(self, block, v);
2712 2712
        },
2731 2731
    // Find the parameter index corresponding to this variable.
2732 2732
    // Each variable that needs merging gets its own block parameter slot.
2733 2733
    let mut paramIdx: u32 = 0;
2734 2734
    for i in 0..blk.paramVars.len {
2735 2735
        if blk.paramVars[i] == *v {
2736 -
            paramIdx = i;
2736 +
            set paramIdx = i;
2737 2737
            break;
2738 2738
        }
2739 2739
    }
2740 2740
2741 2741
    // For each predecessor, recursively look up the variable's reaching definition
2774 2774
                if val <> sv {
2775 2775
                    // Multiple different values, not trivial.
2776 2776
                    return nil;
2777 2777
                }
2778 2778
            } else {
2779 -
                sameVal = val;
2779 +
                set sameVal = val;
2780 2780
            }
2781 2781
        } else { // No param reg set yet, can't be trivial.
2782 2782
            return nil;
2783 2783
        }
2784 2784
    }
2799 2799
2800 2800
    // TODO: We shouldn't need to use a mutable subscript here, given that the
2801 2801
    // fields are already mutable.
2802 2802
    match &mut data.instrs[ix] {
2803 2803
        case il::Instr::Jmp { args, .. } => {
2804 -
            *args = growArgs(self, *args, paramIdx + 1);
2805 -
            args[paramIdx] = val;
2804 +
            set *args = growArgs(self, *args, paramIdx + 1);
2805 +
            set args[paramIdx] = val;
2806 2806
        }
2807 2807
        case il::Instr::Br { thenTarget, thenArgs, elseTarget, elseArgs, .. } => {
2808 2808
            // Nb. both branches could target the same block (e.g. `if cond { x } else { x }`).
2809 2809
            if *thenTarget == target {
2810 -
                *thenArgs = growArgs(self, *thenArgs, paramIdx + 1);
2811 -
                thenArgs[paramIdx] = val;
2810 +
                set *thenArgs = growArgs(self, *thenArgs, paramIdx + 1);
2811 +
                set thenArgs[paramIdx] = val;
2812 2812
            }
2813 2813
            if *elseTarget == target {
2814 -
                *elseArgs = growArgs(self, *elseArgs, paramIdx + 1);
2815 -
                elseArgs[paramIdx] = val;
2814 +
                set *elseArgs = growArgs(self, *elseArgs, paramIdx + 1);
2815 +
                set elseArgs[paramIdx] = val;
2816 2816
            }
2817 2817
        }
2818 2818
        case il::Instr::Switch { defaultTarget, defaultArgs, cases, .. } => {
2819 2819
            if *defaultTarget == target {
2820 -
                *defaultArgs = growArgs(self, *defaultArgs, paramIdx + 1);
2821 -
                defaultArgs[paramIdx] = val;
2820 +
                set *defaultArgs = growArgs(self, *defaultArgs, paramIdx + 1);
2821 +
                set defaultArgs[paramIdx] = val;
2822 2822
            }
2823 2823
            let idx = paramIdx + 1;
2824 2824
            for ci in 0..cases.len {
2825 2825
                if cases[ci].target == target {
2826 -
                    cases[ci].args = growArgs(self, cases[ci].args, idx);
2827 -
                    cases[ci].args[paramIdx] = val;
2826 +
                    set cases[ci].args = growArgs(self, cases[ci].args, idx);
2827 +
                    set cases[ci].args[paramIdx] = val;
2828 2828
                }
2829 2829
            }
2830 2830
        }
2831 2831
        else => {
2832 2832
            // Other terminators (e.g. `Ret`, `Unreachable`) don't have successor blocks.
2842 2842
    let newArgs = try! alloc::allocSlice(
2843 2843
        self.low.arena, @sizeOf(il::Val), @alignOf(il::Val), capacity
2844 2844
    ) as *mut [il::Val];
2845 2845
2846 2846
    for arg, i in args {
2847 -
        newArgs[i] = arg;
2847 +
        set newArgs[i] = arg;
2848 2848
    }
2849 2849
    for i in args.len..capacity {
2850 -
        newArgs[i] = il::Val::Undef;
2850 +
        set newArgs[i] = il::Val::Undef;
2851 2851
    }
2852 2852
    return newArgs;
2853 2853
}
2854 2854
2855 2855
/// Extract the parameter name from an [`FnParam`] AST node value.
2881 2881
    let params = try! alloc::allocSlice(
2882 2882
        self.low.arena, @sizeOf(il::Param), @alignOf(il::Param), totalLen
2883 2883
    ) as *mut [il::Param];
2884 2884
2885 2885
    if let reg = self.returnReg {
2886 -
        params[0] = il::Param { value: reg, type: il::Type::W64 };
2886 +
        set params[0] = il::Param { value: reg, type: il::Type::W64 };
2887 2887
    }
2888 2888
    for i in 0..fnType.paramTypes.len as u32 {
2889 2889
        let type = ilType(self.low, *fnType.paramTypes[i]);
2890 2890
        let reg = nextReg(self);
2891 2891
2892 -
        params[i + offset] = il::Param { value: reg, type };
2892 +
        set params[i + offset] = il::Param { value: reg, type };
2893 2893
2894 2894
        // Declare the parameter variable. For the receiver, the name comes
2895 2895
        // from the receiver node.
2896 2896
        // For all other parameters, the name comes from the AST params.
2897 2897
        let mut name: *[u8] = undefined;
2898 2898
        if let recNode = receiverName {
2899 2899
            if i == 0 {
2900 2900
                let case ast::NodeValue::Ident(recName) = recNode.value else {
2901 2901
                    throw LowerError::ExpectedIdentifier;
2902 2902
                };
2903 -
                name = recName;
2903 +
                set name = recName;
2904 2904
            } else {
2905 -
                name = try paramName(&astParams[i - 1].value);
2905 +
                set name = try paramName(&astParams[i - 1].value);
2906 2906
            }
2907 2907
        } else {
2908 -
            name = try paramName(&astParams[i].value);
2908 +
            set name = try paramName(&astParams[i].value);
2909 2909
        }
2910 2910
        let v = newVar(self, name, type, false, il::Val::Undef);
2911 2911
2912 2912
        self.params.append(FnParamBinding { var: v, reg }, self.allocator);
2913 2913
    }
2923 2923
    // When matching an aggregate by value, copy it to a fresh stack slot so
2924 2924
    // that bindings are independent of the original memory.  Without this,
2925 2925
    // the lowerer returns a pointer into the source and mutations to the
2926 2926
    // source silently corrupt the bound variables.
2927 2927
    if unwrapped.by == resolver::MatchBy::Value and isAggregateType(unwrapped.effectiveTy) {
2928 -
        val = try emitStackVal(self, unwrapped.effectiveTy, val);
2928 +
        set val = try emitStackVal(self, unwrapped.effectiveTy, val);
2929 2929
    }
2930 2930
2931 2931
    let mut bindType = unwrapped.effectiveTy;
2932 2932
    if let case resolver::Type::Optional(inner) = unwrapped.effectiveTy {
2933 -
        bindType = *inner;
2933 +
        set bindType = *inner;
2934 2934
    }
2935 2935
    let ilType = ilType(self.low, unwrapped.effectiveTy);
2936 2936
    let kind = matchSubjectKind(unwrapped.effectiveTy);
2937 2937
2938 2938
    return MatchSubject { val, type: unwrapped.effectiveTy, ilType, bindType, kind, by: unwrapped.by };
3030 3030
    let base = emitValToReg(self, subjectVal);
3031 3031
    let mut payload: il::Val = undefined;
3032 3032
3033 3033
    match matchBy {
3034 3034
        case resolver::MatchBy::Value =>
3035 -
            payload = tvalPayloadVal(self, base, bindType, valOffset),
3035 +
            set payload = tvalPayloadVal(self, base, bindType, valOffset),
3036 3036
        case resolver::MatchBy::Ref, resolver::MatchBy::MutRef =>
3037 -
            payload = tvalPayloadAddr(self, base, valOffset),
3037 +
            set payload = tvalPayloadAddr(self, base, valOffset),
3038 3038
    };
3039 3039
    return newVar(self, name, ilType(self.low, bindType), mutable, payload);
3040 3040
}
3041 3041
3042 3042
fn bindMatchVariable(
3198 3198
            let mut derefType = fieldInfo.fieldType;
3199 3199
            let mut nestedBase = emitPtrOffset(self, base, fieldInfo.offset);
3200 3200
            if let case resolver::Type::Pointer { target, .. } = fieldInfo.fieldType {
3201 3201
                let ptrReg = nextReg(self);
3202 3202
                emitLoadW64At(self, ptrReg, nestedBase, 0);
3203 -
                nestedBase = ptrReg;
3204 -
                derefType = *target;
3203 +
                set nestedBase = ptrReg;
3204 +
                set derefType = *target;
3205 3205
            }
3206 3206
            let recInfo = resolver::getRecord(derefType)
3207 3207
                else throw LowerError::ExpectedRecord;
3208 3208
3209 3209
            try bindNestedRecordFields(self, nestedBase, lit, recInfo, matchBy, failBlock);
3235 3235
    let mut derefBase: ?il::Reg = nil;
3236 3236
    if let case resolver::Type::Pointer { target, .. } = fieldType {
3237 3237
        if resolver::isDestructuringPattern(pattern) {
3238 3238
            let ptrReg = nextReg(self);
3239 3239
            emitLoadW64At(self, ptrReg, fieldPtr, 0);
3240 -
            derefBase = ptrReg;
3241 -
            fieldType = *target;
3240 +
            set derefBase = ptrReg;
3241 +
            set fieldType = *target;
3242 3242
        }
3243 3243
    }
3244 3244
    // Build a MatchSubject for the nested field.
3245 3245
    let ilTy = ilType(self.low, fieldType);
3246 3246
    let kind = matchSubjectKind(fieldType);
3247 3247
3248 3248
    // Determine the subject value.
3249 3249
    let mut val: il::Val = undefined;
3250 3250
    if let reg = derefBase {
3251 3251
        // Auto-deref: the loaded pointer is the address of the target value.
3252 -
        val = il::Val::Reg(reg);
3252 +
        set val = il::Val::Reg(reg);
3253 3253
    } else if isAggregateType(fieldType) {
3254 3254
        // Aggregate: use the pointer.
3255 -
        val = il::Val::Reg(fieldPtr);
3255 +
        set val = il::Val::Reg(fieldPtr);
3256 3256
    } else {
3257 3257
        // Scalar: load the value.
3258 -
        val = emitRead(self, base, fieldInfo.offset, fieldType);
3258 +
        set val = emitRead(self, base, fieldInfo.offset, fieldType);
3259 3259
    }
3260 3260
    let nestedSubject = MatchSubject {
3261 3261
        val,
3262 3262
        type: fieldType,
3263 3263
        ilType: ilTy,
3302 3302
3303 3303
/// Lower function body to a list of basic blocks.
3304 3304
fn lowerFnBody(self: *mut FnLowerer, body: *ast::Node) -> *[il::Block] throws (LowerError) {
3305 3305
    // Create and switch to entry block.
3306 3306
    let entry = try createBlock(self, "entry");
3307 -
    self.entryBlock = entry;
3307 +
    set self.entryBlock = entry;
3308 3308
    switchToBlock(self, entry);
3309 3309
3310 3310
    /// Bind parameter registers to variables in the entry block.
3311 3311
    for def in self.params {
3312 3312
        defVar(self, def.var, il::Val::Reg(def.reg));
3344 3344
        let case ast::NodeValue::MatchProng(prong) = p.value
3345 3345
            else throw LowerError::UnexpectedNodeValue(p);
3346 3346
3347 3347
        match prong.arm {
3348 3348
            case ast::ProngArm::Binding(_), ast::ProngArm::Else => {
3349 -
                blocks[i] = try createBlock(self, "default");
3350 -
                defaultIdx = i;
3349 +
                set blocks[i] = try createBlock(self, "default");
3350 +
                set defaultIdx = i;
3351 3351
            }
3352 3352
            case ast::ProngArm::Case(pats) => {
3353 -
                blocks[i] = try createBlock(self, "case");
3353 +
                set blocks[i] = try createBlock(self, "case");
3354 3354
                for pat in pats {
3355 3355
                    let cv = resolver::constValueEntry(self.low.resolver, pat)
3356 3356
                        else throw LowerError::MissingConst(pat);
3357 3357
3358 3358
                    cases.append(il::SwitchCase {
3469 3469
        // The guard block must be created before the body block so that
3470 3470
        // block indices are in reverse post-order (RPO), which the register
3471 3471
        // allocator requires.
3472 3472
        let mut entryBlock: BlockId = undefined;
3473 3473
        if hasGuard {
3474 -
            entryBlock = try createBlock(self, "guard");
3474 +
            set entryBlock = try createBlock(self, "guard");
3475 3475
        }
3476 3476
        // Body block: where the case body lives.
3477 3477
        let mut bodyLabel = "case";
3478 3478
        if prong.arm == ast::ProngArm::Else {
3479 -
            bodyLabel = "else";
3479 +
            set bodyLabel = "else";
3480 3480
        }
3481 3481
        let mut bodyBlock = try createBlock(self, bodyLabel);
3482 3482
        if not hasGuard {
3483 -
            entryBlock = bodyBlock;
3483 +
            set entryBlock = bodyBlock;
3484 3484
        }
3485 3485
        // Fallthrough block: jumped to when pattern or guard fails.
3486 3486
        let nextArm = try createBlock(self, "arm");
3487 3487
3488 3488
        // Emit pattern test: branch to entry block on match, next arm on fail.
3513 3513
        if let g = prong.guard {
3514 3514
            try emitCondBranch(self, g, bodyBlock, nextArm);
3515 3515
        } else if *currentBlock(self) <> *bodyBlock {
3516 3516
            // Nested tests changed the current block. Create a new body block
3517 3517
            // after the nest blocks to maintain RPO ordering, and jump to it.
3518 -
            bodyBlock = try createBlock(self, bodyLabel);
3518 +
            set bodyBlock = try createBlock(self, bodyLabel);
3519 3519
            try emitJmp(self, bodyBlock);
3520 3520
        }
3521 3521
        // Lower prong body and jump to merge if unterminated.
3522 3522
        try switchToAndSeal(self, bodyBlock);
3523 3523
        try lowerNode(self, prong.body);
3544 3544
fn lowerIfLet(self: *mut FnLowerer, cond: ast::IfLet) throws (LowerError) {
3545 3545
    let savedVarsLen = enterVarScope(self);
3546 3546
    let subject = try lowerMatchSubject(self, cond.pattern.scrutinee);
3547 3547
    let mut thenBlock: BlockId = undefined;
3548 3548
    if cond.pattern.guard == nil {
3549 -
        thenBlock = try createBlock(self, "then");
3549 +
        set thenBlock = try createBlock(self, "then");
3550 3550
    }
3551 3551
    let elseBlock = try createBlock(self, "else");
3552 3552
    let mut mergeBlock: ?BlockId = nil;
3553 3553
3554 3554
    // Pattern match: jump to @then on success, @else on failure.
3587 3587
    // If guard present, pattern match jumps to @guard, then guard evaluation
3588 3588
    // jumps to `successBlock` or `failBlock`. Otherwise, jump directly to
3589 3589
    // `successBlock`.
3590 3590
    let mut targetBlock: BlockId = undefined;
3591 3591
    if pat.guard <> nil {
3592 -
        targetBlock = try createBlock(self, "guard");
3593 -
        *successBlock = try createBlock(self, successLabel);
3592 +
        set targetBlock = try createBlock(self, "guard");
3593 +
        set *successBlock = try createBlock(self, successLabel);
3594 3594
    } else {
3595 -
        targetBlock = *successBlock;
3595 +
        set targetBlock = *successBlock;
3596 3596
    }
3597 3597
    match pat.kind {
3598 3598
        case ast::PatternKind::Case => {
3599 3599
            let patterns: *mut [*ast::Node] = &mut [pat.pattern];
3600 3600
            // Jump to `targetBlock` if the pattern matches, `failBlock` otherwise.
3618 3618
        try emitCondBranch(self, g, *successBlock, failBlock);
3619 3619
        try switchToAndSeal(self, *successBlock);
3620 3620
    } else if *currentBlock(self) <> *targetBlock {
3621 3621
        // Nested tests changed the current block. Create a new success block
3622 3622
        // after the nest blocks to maintain RPO ordering, and jump to it.
3623 -
        *successBlock = try createBlock(self, successLabel);
3623 +
        set *successBlock = try createBlock(self, successLabel);
3624 3624
3625 3625
        try emitJmp(self, *successBlock);
3626 3626
        try switchToAndSeal(self, *successBlock);
3627 3627
    }
3628 3628
}
3630 3630
/// Lower a `let-else` statement.
3631 3631
fn lowerLetElse(self: *mut FnLowerer, letElse: ast::LetElse) throws (LowerError) {
3632 3632
    let subject = try lowerMatchSubject(self, letElse.pattern.scrutinee);
3633 3633
    let mut mergeBlock: BlockId = undefined;
3634 3634
    if letElse.pattern.guard == nil {
3635 -
        mergeBlock = try createBlock(self, "merge");
3635 +
        set mergeBlock = try createBlock(self, "merge");
3636 3636
    }
3637 3637
    // Else branch executes when the pattern fails to match.
3638 3638
    let elseBlock = try createBlock(self, "else");
3639 3639
3640 3640
    // Evaluate pattern and jump to @end or @else.
3653 3653
    // Create control flow blocks: loop header, body (created lazily when
3654 3654
    // there's a guard), and exit.
3655 3655
    let whileBlock = try createBlock(self, "while");
3656 3656
    let mut bodyBlock: BlockId = undefined;
3657 3657
    if w.pattern.guard == nil {
3658 -
        bodyBlock = try createBlock(self, "body");
3658 +
        set bodyBlock = try createBlock(self, "body");
3659 3659
    }
3660 3660
    let endBlock = try createBlock(self, "merge");
3661 3661
3662 3662
    // Enter loop context and jump to loop header.
3663 3663
    enterLoop(self, endBlock, whileBlock);
3681 3681
///////////////////
3682 3682
3683 3683
/// Lower an AST node.
3684 3684
fn lowerNode(self: *mut FnLowerer, node: *ast::Node) throws (LowerError) {
3685 3685
    if self.low.options.debug {
3686 -
        self.srcLoc.offset = node.span.offset;
3686 +
        set self.srcLoc.offset = node.span.offset;
3687 3687
    }
3688 3688
    match node.value {
3689 3689
        case ast::NodeValue::Block(_) => {
3690 3690
            try lowerBlock(self, node);
3691 3691
        }
3885 3885
        return nil;
3886 3886
    }
3887 3887
    return index as i64;
3888 3888
}
3889 3889
3890 -
/// Check if an expression has persistent storage, ie. is an "lvalue".
3891 -
/// Such expressions need to be copied when used to initialize a variable,
3892 -
/// since their storage continues to exist independently. Temporaries (literals,
3893 -
/// call results) can be adopted directly without copying.
3894 -
fn hasStorage(node: *ast::Node) -> bool {
3895 -
    match node.value {
3896 -
        case ast::NodeValue::Ident(_),
3897 -
             ast::NodeValue::FieldAccess(_),
3898 -
             ast::NodeValue::Subscript { .. },
3899 -
             ast::NodeValue::Deref(_) => return true,
3900 -
        else => return false,
3901 -
    }
3902 -
}
3903 -
3904 3890
/// Reserve stack storage for a value of the given type.
3905 3891
fn emitReserve(self: *mut FnLowerer, typ: resolver::Type) -> il::Reg throws (LowerError) {
3906 3892
    let layout = resolver::getTypeLayout(typ);
3907 3893
    return emitReserveLayout(self, layout);
3908 3894
}
4159 4145
    let reg = emitValToReg(self, val);
4160 4146
4161 4147
    // For all-void unions, the value *is* the tag, not a pointer.
4162 4148
    let mut tag: il::Val = undefined;
4163 4149
    if resolver::isVoidUnion(valType) {
4164 -
        tag = il::Val::Reg(reg);
4150 +
        set tag = il::Val::Reg(reg);
4165 4151
    } else {
4166 -
        tag = loadTag(self, reg, TVAL_TAG_OFFSET, il::Type::W8);
4152 +
        set tag = loadTag(self, reg, TVAL_TAG_OFFSET, il::Type::W8);
4167 4153
    }
4168 4154
    let binOp = il::BinOp::Eq if op == ast::BinaryOp::Eq else il::BinOp::Ne;
4169 4155
    return emitTypedBinOp(self, binOp, il::Type::W8, tag, il::Val::Imm(tagIdx));
4170 4156
}
4171 4157
4213 4199
    let mut result: ?il::Val = nil;
4214 4200
4215 4201
    for field in recInfo.fields {
4216 4202
        let cmp = try emitEqAtOffset(self, a, b, offset + field.offset, field.fieldType);
4217 4203
4218 -
        result = emitLogicalAnd(self, result, cmp);
4204 +
        set result = emitLogicalAnd(self, result, cmp);
4219 4205
    }
4220 4206
    if let r = result {
4221 4207
        return r;
4222 4208
    }
4223 4209
    return il::Val::Imm(1);
4267 4253
    // Unions and nested optionals may contain uninitialized payload bytes
4268 4254
    // when nil, so they need a guarded comparison.
4269 4255
    let isUnion = unionInfoFromType(inner) <> nil;
4270 4256
    let mut isOptional = false;
4271 4257
    if let case resolver::Type::Optional(_) = inner {
4272 -
        isOptional = true;
4258 +
        set isOptional = true;
4273 4259
    }
4274 4260
    if not isUnion and not isOptional {
4275 4261
        let tagEq = emitTypedBinOp(self, il::BinOp::Eq, il::Type::W8, tagA, tagB);
4276 4262
        let tagNil = emitTypedBinOp(self, il::BinOp::Eq, il::Type::W8, tagA, il::Val::Imm(0));
4277 4263
        let payloadEq = try emitEqAtOffset(self, a, b, offset + valOffset, inner);
4390 4376
    ) as *mut [il::SwitchCase];
4391 4377
4392 4378
    let mut caseBlocks: [?BlockId; resolver::MAX_UNION_VARIANTS] = undefined;
4393 4379
    for variant, i in unionInfo.variants {
4394 4380
        if variant.valueType == resolver::Type::Void {
4395 -
            cases[i] = il::SwitchCase {
4381 +
            set cases[i] = il::SwitchCase {
4396 4382
                value: i as i64,
4397 4383
                target: *mergeBlock,
4398 4384
                args: trueArgs
4399 4385
            };
4400 -
            caseBlocks[i] = nil;
4386 +
            set caseBlocks[i] = nil;
4401 4387
        } else {
4402 4388
            let payloadBlock = try createBlock(self, "eq#payload");
4403 -
            cases[i] = il::SwitchCase {
4389 +
            set cases[i] = il::SwitchCase {
4404 4390
                value: i as i64,
4405 4391
                target: *payloadBlock,
4406 4392
                args: &mut []
4407 4393
            };
4408 -
            caseBlocks[i] = payloadBlock;
4394 +
            set caseBlocks[i] = payloadBlock;
4409 4395
        }
4410 4396
    }
4411 4397
4412 4398
    // Emit switch in @tag block. Default arm is unreachable since we cover all variants.
4413 4399
    let unreachableBlock = try createBlock(self, "eq#unreachable");
4461 4447
    let mut result: ?il::Val = nil;
4462 4448
4463 4449
    for i in 0..arr.length {
4464 4450
        let elemOffset = offset + (i as i32) * stride;
4465 4451
        let cmp = try emitEqAtOffset(self, a, b, elemOffset, *arr.item);
4466 -
        result = emitLogicalAnd(self, result, cmp);
4452 +
        set result = emitLogicalAnd(self, result, cmp);
4467 4453
    }
4468 4454
    if let r = result {
4469 4455
        return r;
4470 4456
    }
4471 4457
    // Empty arrays are always equal.
4558 4544
        let mut fieldIdx: u32 = i;
4559 4545
        if recInfo.labeled {
4560 4546
            let idx = resolver::recordFieldIndexFor(self.low.resolver, fieldNode) else {
4561 4547
                throw LowerError::MissingMetadata;
4562 4548
            };
4563 -
            fieldIdx = idx;
4549 +
            set fieldIdx = idx;
4564 4550
        }
4565 4551
        // Skip `undefined` fields, they need no initialization.
4566 4552
        // Emitting a blit from an uninitialised reserve produces a
4567 4553
        // phantom SSA source value that the backend cannot handle.
4568 4554
        if not isUndef(field.value) {
4654 4640
    let mut payloadVal: ?il::Val = nil;
4655 4641
    if payloadType <> resolver::Type::Void {
4656 4642
        let case resolver::Type::Nominal(payloadNominal) = payloadType else {
4657 4643
            throw LowerError::MissingMetadata;
4658 4644
        };
4659 -
        payloadVal = try lowerRecordCtor(self, payloadNominal, call.args);
4645 +
        set payloadVal = try lowerRecordCtor(self, payloadNominal, call.args);
4660 4646
    }
4661 4647
    return try buildTagged(self, resolver::getTypeLayout(unionTy), index as i64, payloadVal, payloadType, 1, valOffset);
4662 4648
}
4663 4649
4664 4650
/// Lower a field access into a pointer to the field.
4701 4687
4702 4688
    // Extract data pointer and container length.
4703 4689
    let mut dataReg = baseReg;
4704 4690
    let mut containerLen: il::Val = undefined;
4705 4691
    if let cap = info.capacity { // Slice from array.
4706 -
        containerLen = il::Val::Imm(cap as i64);
4692 +
        set containerLen = il::Val::Imm(cap as i64);
4707 4693
    } else { // Slice from slice.
4708 -
        dataReg = loadSlicePtr(self, baseReg);
4709 -
        containerLen = loadSliceLen(self, baseReg);
4694 +
        set dataReg = loadSlicePtr(self, baseReg);
4695 +
        set containerLen = loadSliceLen(self, baseReg);
4710 4696
    }
4711 4697
4712 4698
    // Compute range bounds.
4713 4699
    let mut startVal: il::Val = il::Val::Imm(0);
4714 4700
    if let start = range.start {
4715 -
        startVal = try lowerExpr(self, start);
4701 +
        set startVal = try lowerExpr(self, start);
4716 4702
    }
4717 4703
    let mut endVal = containerLen;
4718 4704
    if let end = range.end {
4719 -
        endVal = try lowerExpr(self, end);
4705 +
        set endVal = try lowerExpr(self, end);
4720 4706
    }
4721 4707
4722 4708
    // If the start value is known to be zero, the count is just the end
4723 4709
    // value. Otherwise, we have to compute it.
4724 4710
    let mut count = endVal;
4725 4711
4726 4712
    // Only compute range offset and count if the start value is not
4727 4713
    // statically known to be zero.
4728 4714
    if startVal <> il::Val::Imm(0) {
4729 4715
        // Offset the data pointer by the start value.
4730 -
        dataReg = emitElem(
4716 +
        set dataReg = emitElem(
4731 4717
            self, resolver::getTypeLayout(*info.itemType).size, dataReg, startVal
4732 4718
        );
4733 4719
        // Compute the count as `end - start`.
4734 4720
        let lenReg = nextReg(self);
4735 4721
        emit(self, il::Instr::BinOp {
4737 4723
            typ: il::Type::W32,
4738 4724
            dst: lenReg,
4739 4725
            a: endVal,
4740 4726
            b: startVal,
4741 4727
        });
4742 -
        count = il::Val::Reg(lenReg);
4728 +
        set count = il::Val::Reg(lenReg);
4743 4729
    }
4744 4730
    return SliceRangeResult { dataReg, count };
4745 4731
}
4746 4732
4747 4733
/// Lower a slice range expression into a slice header value.
4798 4784
            let layout = resolver::getLayout(self.low.resolver, addr.target, typ);
4799 4785
            let slot = emitReserveLayout(self, layout);
4800 4786
            try emitStore(self, slot, 0, typ, val);
4801 4787
            let stackVal = il::Val::Reg(slot);
4802 4788
4803 -
            self.vars[*v].addressTaken = true;
4789 +
            set self.vars[*v].addressTaken = true;
4804 4790
            defVar(self, v, stackVal);
4805 4791
4806 4792
            return stackVal;
4807 4793
        }
4808 4794
        // Fall back to symbol lookup for constants/statics.
4912 4898
    let mut dataReg = baseReg;
4913 4899
    let mut elemType: resolver::Type = undefined;
4914 4900
4915 4901
    match subjectTy {
4916 4902
        case resolver::Type::Slice { item, .. } => {
4917 -
            elemType = *item;
4903 +
            set elemType = *item;
4918 4904
            let sliceLen = loadSliceLen(self, baseReg);
4919 4905
            // Runtime safety check: index must be strictly less than slice length.
4920 4906
            try emitTrapUnlessCmp(self, il::CmpOp::Ult, il::Type::W32, indexVal, sliceLen);
4921 4907
4922 -
            dataReg = loadSlicePtr(self, baseReg);
4908 +
            set dataReg = loadSlicePtr(self, baseReg);
4923 4909
        }
4924 4910
        case resolver::Type::Array(arrInfo) => {
4925 -
            elemType = *arrInfo.item;
4911 +
            set elemType = *arrInfo.item;
4926 4912
            // Runtime safety check: index must be strictly less than array length.
4927 4913
            // Skip when the index is a compile-time constant, since we check
4928 4914
            // that in the resolver.
4929 4915
            if not resolver::isConstExpr(self.low.resolver, index) {
4930 4916
                let arrLen = il::Val::Imm(arrInfo.length as i64);
4981 4967
    // Temporaries such as literals or call results can be adopted directly.
4982 4968
    // This is because aggregates are represented as memory addresses
4983 4969
    // internally, even though they have value semantics, so without an explicit
4984 4970
    // copy, only the address is is written. Function calls on the other hand
4985 4971
    // reserve their own local stack space, so copying would be redundant.
4986 -
    if isAggregateType(typ) and hasStorage(l.value) {
4987 -
        varVal = try emitStackVal(self, typ, val);
4972 +
    // Void variant literals (e.g. `Option::None`) use scope access syntax and
4973 +
    // are flagged as place expressions, but they are freshly constructed
4974 +
    // temporaries with no persistent storage.
4975 +
    if isAggregateType(typ) and
4976 +
        ast::isPlaceExpr(l.value) and
4977 +
        voidVariantIndex(self.low.resolver, l.value) == nil {
4978 +
        set varVal = try emitStackVal(self, typ, val);
4988 4979
    }
4989 4980
4990 4981
    // If the resolver determined that this variable's address is taken
4991 4982
    // anywhere in the function, allocate a stack slot immediately so the
4992 4983
    // SSA value is always a pointer. This avoids mixing integer and pointer
4997 4988
                let layout = resolver::getLayout(self.low.resolver, node, typ);
4998 4989
                let slot = emitReserveLayout(self, layout);
4999 4990
                try emitStore(self, slot, 0, typ, varVal);
5000 4991
5001 4992
                let v = newVar(self, name, ilType, l.mutable, il::Val::Reg(slot));
5002 -
                self.vars[*v].addressTaken = true;
4993 +
                set self.vars[*v].addressTaken = true;
5003 4994
5004 4995
                return;
5005 4996
            }
5006 4997
        }
5007 4998
    }
5378 5369
            let endExpr = range.end else {
5379 5370
                throw LowerError::MissingMetadata;
5380 5371
            };
5381 5372
            let mut startVal = il::Val::Imm(0);
5382 5373
            if let start = range.start {
5383 -
                startVal = try lowerExpr(self, start);
5374 +
                set startVal = try lowerExpr(self, start);
5384 5375
            }
5385 5376
            let endVal = try lowerExpr(self, endExpr);
5386 5377
            let iterType = ilType(self.low, *valType);
5387 5378
            let valVar = newVar(self, bindingName, iterType, false, startVal);
5388 5379
5389 5380
            let mut indexVar: ?Var = nil;
5390 5381
            if indexName <> nil { // Optional index always starts at zero.
5391 -
                indexVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0));
5382 +
                set indexVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0));
5392 5383
            }
5393 5384
            let iter = ForIter::Range {
5394 5385
                valVar, indexVar, endVal, valType: iterType,
5395 5386
                unsigned: isUnsignedType(*valType),
5396 5387
            };
5402 5393
            let containerReg = emitValToReg(self, containerVal);
5403 5394
5404 5395
            let mut dataReg = containerReg;
5405 5396
            let mut lengthVal: il::Val = undefined;
5406 5397
            if let len = length { // Array (length is known).
5407 -
                lengthVal = il::Val::Imm(len as i64);
5398 +
                set lengthVal = il::Val::Imm(len as i64);
5408 5399
            } else { // Slice (length must be loaded).
5409 -
                lengthVal = loadSliceLen(self, containerReg);
5410 -
                dataReg = loadSlicePtr(self, containerReg);
5400 +
                set lengthVal = loadSliceLen(self, containerReg);
5401 +
                set dataReg = loadSlicePtr(self, containerReg);
5411 5402
            }
5412 5403
            // Declare index value binidng.
5413 5404
            let idxVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0));
5414 5405
5415 5406
            // Declare element value binding.
5416 5407
            let mut valVar: ?Var = nil;
5417 5408
            if bindingName <> nil {
5418 -
                valVar = newVar(
5409 +
                set valVar = newVar(
5419 5410
                    self,
5420 5411
                    bindingName,
5421 5412
                    ilType(self.low, *elemType),
5422 5413
                    false,
5423 5414
                    il::Val::Undef
5472 5463
5473 5464
/// Lower a return statement.
5474 5465
fn lowerReturnStmt(self: *mut FnLowerer, node: *ast::Node, value: ?*ast::Node) throws (LowerError) {
5475 5466
    let mut val = il::Val::Undef;
5476 5467
    if let expr = value {
5477 -
        val = try lowerExpr(self, expr);
5468 +
        set val = try lowerExpr(self, expr);
5478 5469
    }
5479 -
    val = try applyCoercion(self, node, val);
5470 +
    set val = try applyCoercion(self, node, val);
5480 5471
    try emitRetVal(self, val);
5481 5472
}
5482 5473
5483 5474
/// Lower a throw statement.
5484 5475
fn lowerThrowStmt(self: *mut FnLowerer, expr: *ast::Node) throws (LowerError) {
5570 5561
    // Result when short-circuiting (`0` or `1`).
5571 5562
    let mut shortCircuitVal: i64 = undefined;
5572 5563
5573 5564
    match op {
5574 5565
        case LogicalOp::And => {
5575 -
            shortCircuitBlock = elseBlock;
5576 -
            evalBlock = thenBlock;
5577 -
            shortCircuitVal = 0;
5566 +
            set shortCircuitBlock = elseBlock;
5567 +
            set evalBlock = thenBlock;
5568 +
            set shortCircuitVal = 0;
5578 5569
        }
5579 5570
        case LogicalOp::Or => {
5580 -
            shortCircuitBlock = thenBlock;
5581 -
            evalBlock = elseBlock;
5582 -
            shortCircuitVal = 1;
5571 +
            set shortCircuitBlock = thenBlock;
5572 +
            set evalBlock = elseBlock;
5573 +
            set shortCircuitVal = 1;
5583 5574
        }
5584 5575
    }
5585 5576
    // Emit short-circuit branch: jump to merge with constant result.
5586 5577
    try switchToAndSeal(self, shortCircuitBlock);
5587 5578
    try emitJmpWithArg(self, mergeBlock, il::Val::Imm(shortCircuitVal));
5700 5691
        // Aggregate types require element-wise comparison.
5701 5692
        // When comparing `?T` with `T`, wrap the scalar side.
5702 5693
        if isAggregateType(leftTy) {
5703 5694
            let mut rhs = b;
5704 5695
            if not isAggregateType(rightTy) {
5705 -
                rhs = try wrapInOptional(self, rhs, leftTy);
5696 +
                set rhs = try wrapInOptional(self, rhs, leftTy);
5706 5697
            }
5707 5698
            return try emitAggregateEqOp(self, binop.op, leftTy, a, rhs);
5708 5699
        }
5709 5700
        if isAggregateType(rightTy) {
5710 5701
            let lhs = try wrapInOptional(self, a, rightTy);
5711 5702
            return try emitAggregateEqOp(self, binop.op, rightTy, lhs, b);
5712 5703
        }
5713 -
        resultTy = leftTy;
5704 +
        set resultTy = leftTy;
5714 5705
    }
5715 5706
    return emitScalarBinOp(self, binop.op, ilType(self.low, resultTy), a, b, isUnsignedType(resultTy));
5716 5707
}
5717 5708
5718 5709
/// Emit an aggregate equality or inequality comparison.
5745 5736
    let dst = nextReg(self);
5746 5737
    let mut needsExt: bool = false;
5747 5738
    match op {
5748 5739
        case ast::BinaryOp::Add => {
5749 5740
            emit(self, il::Instr::BinOp { op: il::BinOp::Add, typ, dst, a, b });
5750 -
            needsExt = true;
5741 +
            set needsExt = true;
5751 5742
        }
5752 5743
        case ast::BinaryOp::Sub => {
5753 5744
            emit(self, il::Instr::BinOp { op: il::BinOp::Sub, typ, dst, a, b });
5754 -
            needsExt = true;
5745 +
            set needsExt = true;
5755 5746
        }
5756 5747
        case ast::BinaryOp::Mul => {
5757 5748
            emit(self, il::Instr::BinOp { op: il::BinOp::Mul, typ, dst, a, b });
5758 -
            needsExt = true;
5749 +
            set needsExt = true;
5759 5750
        }
5760 5751
        case ast::BinaryOp::Div => {
5761 5752
            let op = il::BinOp::Udiv if unsigned else il::BinOp::Sdiv;
5762 5753
            emit(self, il::Instr::BinOp { op, typ, dst, a, b });
5763 -
            needsExt = true;
5754 +
            set needsExt = true;
5764 5755
        }
5765 5756
        case ast::BinaryOp::Mod => {
5766 5757
            let op = il::BinOp::Urem if unsigned else il::BinOp::Srem;
5767 5758
            emit(self, il::Instr::BinOp { op, typ, dst, a, b });
5768 -
            needsExt = true;
5759 +
            set needsExt = true;
5769 5760
        }
5770 5761
        case ast::BinaryOp::BitAnd => emit(self, il::Instr::BinOp { op: il::BinOp::And, typ, dst, a, b }),
5771 5762
        case ast::BinaryOp::BitOr => emit(self, il::Instr::BinOp { op: il::BinOp::Or, typ, dst, a, b }),
5772 5763
        case ast::BinaryOp::BitXor => emit(self, il::Instr::BinOp { op: il::BinOp::Xor, typ, dst, a, b }),
5773 5764
        case ast::BinaryOp::Shl => {
5774 5765
            emit(self, il::Instr::BinOp { op: il::BinOp::Shl, typ, dst, a, b });
5775 -
            needsExt = true;
5766 +
            set needsExt = true;
5776 5767
        }
5777 5768
        case ast::BinaryOp::Shr => {
5778 5769
            let op = il::BinOp::Ushr if unsigned else il::BinOp::Sshr;
5779 5770
            emit(self, il::Instr::BinOp { op, typ, dst, a, b });
5780 5771
        }
5836 5827
        case ast::UnaryOp::Not => {
5837 5828
            emit(self, il::Instr::BinOp { op: il::BinOp::Eq, typ, dst, a: val, b: il::Val::Imm(0) });
5838 5829
        }
5839 5830
        case ast::UnaryOp::Neg => {
5840 5831
            emit(self, il::Instr::UnOp { op: il::UnOp::Neg, typ, dst, a: val });
5841 -
            needsExt = true;
5832 +
            set needsExt = true;
5842 5833
        }
5843 5834
        case ast::UnaryOp::BitNot => {
5844 5835
            emit(self, il::Instr::UnOp { op: il::UnOp::Not, typ, dst, a: val });
5845 -
            needsExt = true;
5836 +
            set needsExt = true;
5846 5837
        }
5847 5838
    }
5848 5839
    if needsExt {
5849 5840
        return normalizeSubword(self, typ, isUnsignedType(t), il::Val::Reg(dst));
5850 5841
    }
5893 5884
    // Build the string data value.
5894 5885
    let ptr = try! alloc::alloc(
5895 5886
        self.low.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue)
5896 5887
    ) as *mut il::DataValue;
5897 5888
5898 -
    *ptr = il::DataValue { item: il::DataItem::Str(s), count: 1 };
5889 +
    set *ptr = il::DataValue { item: il::DataItem::Str(s), count: 1 };
5899 5890
5900 5891
    return try lowerConstDataAsSlice(self, @sliceOf(ptr, 1), 1, true, item, mutable, s.len);
5901 5892
}
5902 5893
5903 5894
/// Lower a builtin call expression.
5924 5915
    };
5925 5916
    let ptrVal = try lowerExpr(self, args[0]);
5926 5917
    let lenVal = try lowerExpr(self, args[1]);
5927 5918
    let mut capVal = lenVal;
5928 5919
    if args.len == 3 {
5929 -
        capVal = try lowerExpr(self, args[2]);
5920 +
        set capVal = try lowerExpr(self, args[2]);
5930 5921
    }
5931 5922
    return try buildSliceValue(self, item, mutable, ptrVal, lenVal, capVal);
5932 5923
}
5933 5924
5934 5925
/// Lower a `try` expression.
5949 5940
    let mut resVal: il::Val = undefined;
5950 5941
    let callNodeExtra = resolver::nodeData(self.low.resolver, t.expr).extra;
5951 5942
    if let case resolver::NodeExtra::TraitMethodCall {
5952 5943
        traitInfo, methodIndex
5953 5944
    } = callNodeExtra {
5954 -
        resVal = try lowerTraitMethodCall(self, t.expr, callExpr, traitInfo, methodIndex);
5945 +
        set resVal = try lowerTraitMethodCall(self, t.expr, callExpr, traitInfo, methodIndex);
5955 5946
    } else if let case resolver::NodeExtra::MethodCall { method } = callNodeExtra {
5956 -
        resVal = try lowerMethodCall(self, t.expr, callExpr, method);
5947 +
        set resVal = try lowerMethodCall(self, t.expr, callExpr, method);
5957 5948
    } else {
5958 -
        resVal = try lowerCall(self, t.expr, callExpr);
5949 +
        set resVal = try lowerCall(self, t.expr, callExpr);
5959 5950
    }
5960 5951
    let base = emitValToReg(self, resVal); // The result value.
5961 5952
    let tagReg = resultTagReg(self, base); // The result tag.
5962 5953
5963 5954
    let okBlock = try createBlock(self, "ok"); // Block if success.
5968 5959
5969 5960
    // Check if the `try` returns a success value or not. If so, reserve
5970 5961
    // space for it.
5971 5962
    let isVoid = tryExprTy == resolver::Type::Void;
5972 5963
    if not isVoid {
5973 -
        resultSlot = try emitReserve(self, tryExprTy);
5964 +
        set resultSlot = try emitReserve(self, tryExprTy);
5974 5965
    }
5975 5966
    // Branch on tag: zero means ok, non-zero means error.
5976 5967
    try emitBr(self, tagReg, errBlock, okBlock);
5977 5968
5978 5969
    // We can now seal the blocks since all predecessors are known.
5988 5979
        // type (e.g. `try?` wrapping `T` into `?T`), wrap the value.
5989 5980
        let payloadVal = tvalPayloadVal(self, base, okValueTy, RESULT_VAL_OFFSET);
5990 5981
        let mut okVal = payloadVal;
5991 5982
5992 5983
        if t.returnsOptional and tryExprTy <> okValueTy {
5993 -
            okVal = try wrapInOptional(self, payloadVal, tryExprTy);
5984 +
            set okVal = try wrapInOptional(self, payloadVal, tryExprTy);
5994 5985
        }
5995 5986
        try emitStore(self, slot, 0, tryExprTy, okVal);
5996 5987
    }
5997 5988
    // Jump to merge block if unterminated.
5998 5989
    try emitMergeIfUnterminated(self, &mut mergeBlock);
6094 6085
6095 6086
    for clauseNode, i in catches {
6096 6087
        let case ast::NodeValue::CatchClause(clause) = clauseNode.value
6097 6088
            else panic "lowerMultiCatch: expected CatchClause";
6098 6089
6099 -
        blocks[i] = try createBlock(self, "catch");
6090 +
        set blocks[i] = try createBlock(self, "catch");
6100 6091
        addPredecessor(self, blocks[i], entry);
6101 6092
6102 6093
        if let typeNode = clause.typeNode {
6103 6094
            let errTy = try typeOf(self, typeNode);
6104 -
            errTypes[i] = errTy;
6095 +
            set errTypes[i] = errTy;
6105 6096
6106 6097
            cases.append(il::SwitchCase {
6107 6098
                value: getOrAssignErrorTag(self.low, errTy) as i64,
6108 6099
                target: *blocks[i],
6109 6100
                args: &mut []
6110 6101
            }, self.allocator);
6111 6102
        } else {
6112 -
            errTypes[i] = nil;
6113 -
            defaultIdx = i;
6103 +
            set errTypes[i] = nil;
6104 +
            set defaultIdx = i;
6114 6105
        }
6115 6106
    }
6116 6107
6117 6108
    // Emit switch. Default target is the catch-all block, or an unreachable block.
6118 6109
    let mut defaultTarget: BlockId = undefined;
6119 6110
    if let idx = defaultIdx {
6120 -
        defaultTarget = blocks[idx];
6111 +
        set defaultTarget = blocks[idx];
6121 6112
    } else {
6122 -
        defaultTarget = try createBlock(self, "unreachable");
6113 +
        set defaultTarget = try createBlock(self, "unreachable");
6123 6114
        addPredecessor(self, defaultTarget, entry);
6124 6115
    }
6125 6116
    emit(self, il::Instr::Switch {
6126 6117
        val: il::Val::Reg(tagReg),
6127 6118
        defaultTarget: *defaultTarget,
6265 6256
    emitLoadW64At(self, allocCtxReg, allocReg, 8);
6266 6257
6267 6258
    let byteSize = emitTypedBinOp(self, il::BinOp::Mul, il::Type::W32, newCapVal, il::Val::Imm(stride as i64));
6268 6259
    let args = try allocVals(self, 3);
6269 6260
6270 -
    args[0] = il::Val::Reg(allocCtxReg);
6271 -
    args[1] = byteSize;
6272 -
    args[2] = il::Val::Imm(alignment as i64);
6261 +
    set args[0] = il::Val::Reg(allocCtxReg);
6262 +
    set args[1] = byteSize;
6263 +
    set args[2] = il::Val::Imm(alignment as i64);
6273 6264
6274 6265
    let newPtrReg = nextReg(self);
6275 6266
    emit(self, il::Instr::Call {
6276 6267
        retTy: il::Type::W64,
6277 6268
        dst: newPtrReg,
6437 6428
    let methodFnType = traitInfo.methods[methodIndex].fnType;
6438 6429
6439 6430
    // Build args: optional return param slot + data pointer (receiver) + user args.
6440 6431
    let argOffset: u32 = 1 if requiresReturnParam(methodFnType) else 0;
6441 6432
    let args = try allocVals(self, call.args.len + 1 + argOffset);
6442 -
    args[argOffset] = il::Val::Reg(dataReg);
6433 +
    set args[argOffset] = il::Val::Reg(dataReg);
6443 6434
6444 6435
    for arg, i in call.args {
6445 -
        args[i + 1 + argOffset] = try lowerExpr(self, arg);
6436 +
        set args[i + 1 + argOffset] = try lowerExpr(self, arg);
6446 6437
    }
6447 6438
    return try emitCallValue(self, il::Val::Reg(fnPtrReg), methodFnType, args);
6448 6439
}
6449 6440
6450 6441
/// Emit a function call with return-parameter and small-aggregate handling.
6462 6453
    let retTy = *fnInfo.returnType;
6463 6454
6464 6455
    if requiresReturnParam(fnInfo) {
6465 6456
        if fnInfo.throwList.len > 0 {
6466 6457
            let layout = resolver::getResultLayout(retTy, fnInfo.throwList);
6467 -
            args[0] = il::Val::Reg(emitReserveLayout(self, layout));
6458 +
            set args[0] = il::Val::Reg(emitReserveLayout(self, layout));
6468 6459
        } else {
6469 -
            args[0] = il::Val::Reg(try emitReserve(self, retTy));
6460 +
            set args[0] = il::Val::Reg(try emitReserve(self, retTy));
6470 6461
        }
6471 6462
        let dst = nextReg(self);
6472 6463
6473 6464
        emit(self, il::Instr::Call {
6474 6465
            retTy: il::Type::W64,
6478 6469
        });
6479 6470
        return il::Val::Reg(dst);
6480 6471
    }
6481 6472
    let mut dst: ?il::Reg = nil;
6482 6473
    if retTy <> resolver::Type::Void {
6483 -
        dst = nextReg(self);
6474 +
        set dst = nextReg(self);
6484 6475
    }
6485 6476
    emit(self, il::Instr::Call {
6486 6477
        retTy: ilType(self.low, retTy),
6487 6478
        dst,
6488 6479
        func: callee,
6558 6549
        else panic "lowerMethodCall: expected Fn type on method symbol";
6559 6550
6560 6551
    // Build args: optional return param slot + receiver + user args.
6561 6552
    let argOffset: u32 = 1 if requiresReturnParam(fnInfo) else 0;
6562 6553
    let args = try allocVals(self, call.args.len + 1 + argOffset);
6563 -
    args[argOffset] = receiverVal;
6554 +
    set args[argOffset] = receiverVal;
6564 6555
    for arg, i in call.args {
6565 -
        args[i + 1 + argOffset] = try lowerExpr(self, arg);
6556 +
        set args[i + 1 + argOffset] = try lowerExpr(self, arg);
6566 6557
    }
6567 6558
    return try emitCallValue(self, il::Val::FnAddr(qualName), fnInfo, args);
6568 6559
}
6569 6560
6570 6561
/// Check if a call is to a compiler intrinsic and lower it directly.
6649 6640
    };
6650 6641
    let callee = try lowerCallee(self, call.callee);
6651 6642
    let offset: u32 = 1 if requiresReturnParam(fnInfo) else 0;
6652 6643
    let args = try allocVals(self, call.args.len + offset);
6653 6644
    for arg, i in call.args {
6654 -
        args[i + offset] = try lowerExpr(self, arg);
6645 +
        set args[i + offset] = try lowerExpr(self, arg);
6655 6646
    }
6656 6647
6657 6648
    return try emitCallValue(self, callee, fnInfo, args);
6658 6649
}
6659 6650
6809 6800
6810 6801
/// Lower an expression AST node to an IL value.
6811 6802
/// This is the main expression dispatch, all expression nodes go through here.
6812 6803
fn lowerExpr(self: *mut FnLowerer, node: *ast::Node) -> il::Val throws (LowerError) {
6813 6804
    if self.low.options.debug {
6814 -
        self.srcLoc.offset = node.span.offset;
6805 +
        set self.srcLoc.offset = node.span.offset;
6815 6806
    }
6816 6807
    let mut val: il::Val = undefined;
6817 6808
6818 6809
    match node.value {
6819 6810
        case ast::NodeValue::Ident(_) => {
6820 6811
            // First try local variable lookup.
6821 6812
            // Otherwise fall back to global symbol lookup.
6822 6813
            if let v = lookupLocalVar(self, node) {
6823 -
                val = try useVar(self, v);
6814 +
                set val = try useVar(self, v);
6824 6815
                if self.vars[*v].addressTaken {
6825 6816
                    let typ = try typeOf(self, node);
6826 6817
                    let ptr = emitValToReg(self, val);
6827 -
                    val = emitRead(self, ptr, 0, typ);
6818 +
                    set val = emitRead(self, ptr, 0, typ);
6828 6819
                }
6829 6820
            } else {
6830 -
                val = try lowerGlobalSymbol(self, node);
6821 +
                set val = try lowerGlobalSymbol(self, node);
6831 6822
            }
6832 6823
        }
6833 6824
        case ast::NodeValue::ScopeAccess(_) => {
6834 -
            val = try lowerScopeAccess(self, node);
6825 +
            set val = try lowerScopeAccess(self, node);
6835 6826
        }
6836 6827
        case ast::NodeValue::Number(lit) => {
6837 6828
            let mag = -(lit.magnitude as i64) if lit.negative else lit.magnitude as i64;
6838 -
            val = il::Val::Imm(mag);
6829 +
            set val = il::Val::Imm(mag);
6839 6830
        }
6840 6831
        case ast::NodeValue::Bool(b) => {
6841 -
            val = il::Val::Imm(1) if b else il::Val::Imm(0);
6832 +
            set val = il::Val::Imm(1) if b else il::Val::Imm(0);
6842 6833
        }
6843 6834
        case ast::NodeValue::Char(c) => {
6844 -
            val = il::Val::Imm(c as i64);
6835 +
            set val = il::Val::Imm(c as i64);
6845 6836
        }
6846 6837
        case ast::NodeValue::Nil => {
6847 6838
            let typ = try typeOf(self, node);
6848 6839
            if let case resolver::Type::Optional(_) = typ {
6849 -
                val = try buildNilOptional(self, typ);
6840 +
                set val = try buildNilOptional(self, typ);
6850 6841
            } else if let case resolver::Type::Nil = typ {
6851 6842
                // Standalone `nil` without a concrete optional type. We can't
6852 6843
                // generate a proper value representation.
6853 6844
                throw LowerError::MissingType(node);
6854 6845
            } else {
6855 6846
                throw LowerError::NilInNonOptional;
6856 6847
            }
6857 6848
        }
6858 6849
        case ast::NodeValue::RecordLit(lit) => {
6859 -
            val = try lowerRecordLit(self, node, lit);
6850 +
            set val = try lowerRecordLit(self, node, lit);
6860 6851
        }
6861 6852
        case ast::NodeValue::AddressOf(addr) => {
6862 -
            val = try lowerAddressOf(self, node, addr);
6853 +
            set val = try lowerAddressOf(self, node, addr);
6863 6854
        }
6864 6855
        case ast::NodeValue::Deref(target) => {
6865 -
            val = try lowerDeref(self, node, target);
6856 +
            set val = try lowerDeref(self, node, target);
6866 6857
        }
6867 6858
        case ast::NodeValue::BinOp(binop) => {
6868 -
            val = try lowerBinOp(self, node, binop);
6859 +
            set val = try lowerBinOp(self, node, binop);
6869 6860
        }
6870 6861
        case ast::NodeValue::UnOp(unop) => {
6871 -
            val = try lowerUnOp(self, node, unop);
6862 +
            set val = try lowerUnOp(self, node, unop);
6872 6863
        }
6873 6864
        case ast::NodeValue::Subscript { container, index } => {
6874 -
            val = try lowerSubscript(self, node, container, index);
6865 +
            set val = try lowerSubscript(self, node, container, index);
6875 6866
        }
6876 6867
        case ast::NodeValue::BuiltinCall { kind, args } => {
6877 -
            val = try lowerBuiltinCall(self, node, kind, args);
6868 +
            set val = try lowerBuiltinCall(self, node, kind, args);
6878 6869
        }
6879 6870
        case ast::NodeValue::Call(call) => {
6880 -
            val = try lowerCallOrCtor(self, node, call);
6871 +
            set val = try lowerCallOrCtor(self, node, call);
6881 6872
        }
6882 6873
        case ast::NodeValue::Try(t) => {
6883 -
            val = try lowerTry(self, node, t);
6874 +
            set val = try lowerTry(self, node, t);
6884 6875
        }
6885 6876
        case ast::NodeValue::FieldAccess(access) => {
6886 6877
            // Check for compile-time constant (e.g., `arr.len` on fixed-size arrays).
6887 6878
            if let constVal = resolver::constValueEntry(self.low.resolver, node) {
6888 6879
                match constVal {
6889 6880
                    // TODO: Handle `u32` values that don't fit in an `i32`.
6890 6881
                    //       Perhaps just store the `ConstInt`.
6891 -
                    case resolver::ConstValue::Int(i) => val = il::Val::Imm(constIntToI64(i)),
6892 -
                    else => val = try lowerFieldAccess(self, access),
6882 +
                    case resolver::ConstValue::Int(i) => set val = il::Val::Imm(constIntToI64(i)),
6883 +
                    else => set val = try lowerFieldAccess(self, access),
6893 6884
                }
6894 6885
            } else {
6895 -
                val = try lowerFieldAccess(self, access);
6886 +
                set val = try lowerFieldAccess(self, access);
6896 6887
            }
6897 6888
        }
6898 6889
        case ast::NodeValue::ArrayLit(elements) => {
6899 -
            val = try lowerArrayLit(self, node, elements);
6890 +
            set val = try lowerArrayLit(self, node, elements);
6900 6891
        }
6901 6892
        case ast::NodeValue::ArrayRepeatLit(repeat) => {
6902 -
            val = try lowerArrayRepeatLit(self, node, repeat);
6893 +
            set val = try lowerArrayRepeatLit(self, node, repeat);
6903 6894
        }
6904 6895
        case ast::NodeValue::As(cast) => {
6905 -
            val = try lowerCast(self, node, cast);
6896 +
            set val = try lowerCast(self, node, cast);
6906 6897
        }
6907 6898
        case ast::NodeValue::CondExpr(cond) => {
6908 -
            val = try lowerCondExpr(self, node, cond);
6899 +
            set val = try lowerCondExpr(self, node, cond);
6909 6900
        }
6910 6901
        case ast::NodeValue::String(s) => {
6911 -
            val = try lowerStringLit(self, node, s);
6902 +
            set val = try lowerStringLit(self, node, s);
6912 6903
        }
6913 6904
        case ast::NodeValue::Undef => {
6914 6905
            let typ = try typeOf(self, node);
6915 6906
            if isAggregateType(typ) {
6916 6907
                // When `undefined` appears as a stand-alone expression,
6917 6908
                /// we need a stack slot for reads and writes.
6918 6909
                let slot = try emitReserve(self, typ);
6919 -
                val = il::Val::Reg(slot);
6910 +
                set val = il::Val::Reg(slot);
6920 6911
            } else {
6921 -
                val = il::Val::Undef;
6912 +
                set val = il::Val::Undef;
6922 6913
            }
6923 6914
        }
6924 6915
        case ast::NodeValue::Panic { .. } => {
6925 6916
            // Panic in expression context (e.g. match arm). Emit unreachable
6926 6917
            // and return a dummy value since control won't continue.
6927 6918
            emit(self, il::Instr::Unreachable);
6928 -
            val = il::Val::Undef;
6919 +
            set val = il::Val::Undef;
6929 6920
        }
6930 6921
        case ast::NodeValue::Assert { .. } => {
6931 6922
            // Assert in expression context. Lower as statement, return `void`.
6932 6923
            try lowerNode(self, node);
6933 -
            val = il::Val::Undef;
6924 +
            set val = il::Val::Undef;
6934 6925
        }
6935 6926
        case ast::NodeValue::Block(_) => {
6936 6927
            try lowerBlock(self, node);
6937 -
            val = il::Val::Undef;
6928 +
            set val = il::Val::Undef;
6938 6929
        }
6939 6930
        case ast::NodeValue::ExprStmt(expr) => {
6940 6931
            let _ = expr;
6941 -
            val = il::Val::Undef;
6932 +
            set val = il::Val::Undef;
6942 6933
        }
6943 6934
        // Lower these as statements.
6944 6935
        case ast::NodeValue::ConstDecl(decl) => {
6945 6936
            try lowerDataDecl(self.low, node, decl.value, true);
6946 -
            val = il::Val::Undef;
6937 +
            set val = il::Val::Undef;
6947 6938
        }
6948 6939
        case ast::NodeValue::StaticDecl(decl) => {
6949 6940
            try lowerDataDecl(self.low, node, decl.value, false);
6950 -
            val = il::Val::Undef;
6941 +
            set val = il::Val::Undef;
6951 6942
        }
6952 6943
        case ast::NodeValue::Throw { .. },
6953 6944
             ast::NodeValue::Return { .. },
6954 6945
             ast::NodeValue::Continue,
6955 6946
             ast::NodeValue::Break => {
6956 6947
            try lowerNode(self, node);
6957 -
            val = il::Val::Undef;
6948 +
            set val = il::Val::Undef;
6958 6949
        }
6959 6950
        else => {
6960 6951
            panic "lowerExpr: node is not an expression";
6961 6952
        }
6962 6953
    }
lib/std/lang/module.rad +22 -22
121 121
    filePath: *[u8]
122 122
) -> u16 throws (ModuleError) {
123 123
    let m = try allocModule(graph, packageId, name, filePath);
124 124
    try appendPathSegment(m, m.name);
125 125
126 -
    m.state = ModuleState::Registered;
126 +
    set m.state = ModuleState::Registered;
127 127
128 128
    return m.id;
129 129
}
130 130
131 131
/// Register a child module.
147 147
        return child.id;
148 148
    }
149 149
    // Inherit packageId from parent.
150 150
    let m = try allocModule(graph, parent.packageId, name, filePath);
151 151
152 -
    m.dirLen = dirLength(m.filePath);
153 -
    m.state = ModuleState::Registered;
154 -
    m.parent = parentId;
152 +
    set m.dirLen = dirLength(m.filePath);
153 +
    set m.state = ModuleState::Registered;
154 +
    set m.parent = parentId;
155 155
156 156
    // Inherit path prefix from parent.
157 157
    for p in moduleQualifiedPath(parent) {
158 158
        try appendPathSegment(m, p);
159 159
    }
204 204
}
205 205
206 206
/// Record the parsed AST root for `id`.
207 207
export fn setAst(graph: *mut ModuleGraph, id: u16, root: *mut ast::Node) throws (ModuleError) {
208 208
    let m = getMut(graph, id) else throw ModuleError::NotFound(id);
209 -
    m.ast = root;
210 -
    m.state = ModuleState::Parsed;
209 +
    set m.ast = root;
210 +
    set m.state = ModuleState::Parsed;
211 211
}
212 212
213 213
/// Set the source text for a module.
214 214
export fn setSource(graph: *mut ModuleGraph, id: u16, source: *[u8]) throws (ModuleError) {
215 215
    let m = getMut(graph, id) else throw ModuleError::NotFound(id);
216 -
    m.source = source;
216 +
    set m.source = source;
217 217
}
218 218
219 219
/// Look up a child module by name under the given parent.
220 220
export fn findChild(graph: *ModuleGraph, name: *[u8], parentId: u16) -> ?*ModuleEntry {
221 221
    assert isValidId(graph, parentId), "findChild: parent identifier is valid";
241 241
    // Split on '/' to extract all but the last component.
242 242
    for i in 0..filePath.len {
243 243
        if filePath[i] == PATH_SEP {
244 244
            if i > last {
245 245
                assert count < components.len, "parsePath: output slice is large enough";
246 -
                components[count] = &filePath[last..i];
247 -
                count += 1;
246 +
                set components[count] = &filePath[last..i];
247 +
                set count += 1;
248 248
            }
249 -
            last = i + 1;
249 +
            set last = i + 1;
250 250
        }
251 251
    }
252 252
    if last >= filePath.len {
253 253
        return nil; // Path ends with separator or is empty.
254 254
    }
255 255
256 256
    // Handle the last component by removing extension.
257 257
    assert count < components.len, "parsePath: output slice is large enough";
258 258
    if let name = trimExtension(&filePath[last..]) {
259 -
        components[count] = name;
259 +
        set components[count] = name;
260 260
    } else {
261 261
        return nil;
262 262
    };
263 -
    count += 1;
263 +
    set count += 1;
264 264
265 265
    return count;
266 266
}
267 267
268 268
/// Register a module from a file path, creating the full hierarchy as needed.
306 306
    let mut parentId = root;
307 307
    for part in &childPath[..childPath.len - 1] {
308 308
        let child = findChild(graph, part, parentId) else {
309 309
            throw ModuleError::MissingParent;
310 310
        };
311 -
        parentId = child.id;
311 +
        set parentId = child.id;
312 312
    }
313 313
    return try registerChild(graph, parentId, childName, filePath);
314 314
}
315 315
316 316
/// Allocate a fresh entry in the graph.
317 317
fn allocModule(graph: *mut ModuleGraph, packageId: u16, name: *[u8], filePath: *[u8]) -> *mut ModuleEntry throws (ModuleError) {
318 318
    if graph.entriesLen >= graph.entries.len {
319 319
        throw ModuleError::CapacityExceeded;
320 320
    }
321 321
    let idx = graph.entriesLen;
322 -
    graph.entriesLen += 1;
322 +
    set graph.entriesLen += 1;
323 323
324 324
    // TODO: This is a common pattern that needs better syntax.
325 325
    let m = &mut graph.entries[idx];
326 -
    *m = ModuleEntry {
326 +
    set *m = ModuleEntry {
327 327
        id: idx as u16,
328 328
        packageId,
329 329
        parent: nil,
330 330
        filePath,
331 331
        dirLen: 0,
336 336
        children: undefined,
337 337
        childrenLen: 0,
338 338
        ast: nil,
339 339
        source: nil,
340 340
    };
341 -
    m.dirLen = dirLength(m.filePath);
341 +
    set m.dirLen = dirLength(m.filePath);
342 342
343 343
    return m;
344 344
}
345 345
346 346
/// Append a logical path segment (module identifier) to the entry.
347 347
fn appendPathSegment(entry: *mut ModuleEntry, segment: *[u8]) throws (ModuleError) {
348 348
    if entry.pathDepth >= entry.path.len {
349 349
        throw ModuleError::PathTooDeep;
350 350
    }
351 -
    entry.path[entry.pathDepth] = segment;
352 -
    entry.pathDepth += 1;
351 +
    set entry.path[entry.pathDepth] = segment;
352 +
    set entry.pathDepth += 1;
353 353
}
354 354
355 355
/// Append a child identifier to the parent's child list.
356 356
fn addChild(parent: *mut ModuleEntry, childId: u16) -> u16 throws (ModuleError) {
357 357
    if parent.childrenLen >= parent.children.len {
358 358
        throw ModuleError::CapacityExceeded;
359 359
    }
360 -
    parent.children[parent.childrenLen] = childId;
361 -
    parent.childrenLen += 1;
360 +
    set parent.children[parent.childrenLen] = childId;
361 +
    set parent.childrenLen += 1;
362 362
363 363
    return childId;
364 364
}
365 365
366 366
/// Check if `id` points at an allocated entry.
374 374
        return 0;
375 375
    }
376 376
    let mut last: i32 = -1;
377 377
    for i in 0..path.len {
378 378
        if path[i] == PATH_SEP {
379 -
            last = i as i32;
379 +
            set last = i as i32;
380 380
        }
381 381
    }
382 382
    if last < 0 {
383 383
        return 0;
384 384
    }
397 397
/// Find the byte offset immediately following the last separator.
398 398
fn basenameStart(path: *[u8]) -> u32 {
399 399
    let mut start: u32 = 0;
400 400
    for i in 0..path.len {
401 401
        if path[i] == PATH_SEP {
402 -
            start = i + 1;
402 +
            set start = i + 1;
403 403
        }
404 404
    }
405 405
    return start;
406 406
}
407 407
lib/std/lang/module/printer.rad +4 -4
37 37
    let idText = formatId(a, entry.id as u32);
38 38
    let path = super::moduleQualifiedPath(entry);
39 39
    let mut pathBuf: *[sexpr::Expr] = &[];
40 40
    if path.len > 0 {
41 41
        let buf = try! sexpr::allocExprs(a, path.len);
42 -
        for seg, i in path { buf[i] = sexpr::sym(seg); }
43 -
        pathBuf = buf;
42 +
        for seg, i in path { set buf[i] = sexpr::sym(seg); }
43 +
        set pathBuf = buf;
44 44
    }
45 45
46 46
    let mut childBuf: *[sexpr::Expr] = &[];
47 47
    if entry.childrenLen > 0 {
48 48
        let buf = try! sexpr::allocExprs(a, entry.childrenLen);
49 49
        for i in 0..entry.childrenLen {
50 50
            if let child = super::get(graph, entry.children[i]) {
51 -
                buf[i] = subtreeToExpr(a, graph, child);
51 +
                set buf[i] = subtreeToExpr(a, graph, child);
52 52
            }
53 53
        }
54 -
        childBuf = buf;
54 +
        set childBuf = buf;
55 55
    }
56 56
57 57
    return sexpr::block(a, "module", &[
58 58
        sexpr::sym(entry.name),
59 59
        sexpr::list(a, "id", &[sexpr::sym(idText)]),
lib/std/lang/package.rad +4 -4
24 24
    pkg: *mut Package,
25 25
    id: u16,
26 26
    name: *[u8],
27 27
    pool: *mut strings::Pool
28 28
) -> *mut Package {
29 -
    pkg.id = id;
30 -
    pkg.name = strings::intern(pool, name);
31 -
    pkg.rootModuleId = nil;
29 +
    set pkg.id = id;
30 +
    set pkg.name = strings::intern(pool, name);
31 +
    set pkg.rootModuleId = nil;
32 32
33 33
    return pkg;
34 34
}
35 35
36 36
/// Register a module described by the file path.
38 38
    throws (module::ModuleError)
39 39
{
40 40
    let modId = try module::registerFromPath(graph, pkg.id, pkg.rootModuleId, filePath);
41 41
    // First registered module becomes the root.
42 42
    if pkg.rootModuleId == nil {
43 -
        pkg.rootModuleId = modId;
43 +
        set pkg.rootModuleId = modId;
44 44
    }
45 45
    return modId;
46 46
}
lib/std/lang/parser.rad +124 -129
177 177
178 178
    // Default to an out-of-range value so non-digits fall through to `nil`.
179 179
    let mut value: u32 = 36;
180 180
181 181
    if ch >= '0' and ch <= '9' {
182 -
        value = (ch - '0') as u32;
182 +
        set value = (ch - '0') as u32;
183 183
    } else if radix > 10 {
184 184
        // Mask to convert ASCII letters to uppercase.
185 185
        let upper = ch & 0xDF;
186 186
        if upper >= 'A' and upper <= 'Z' {
187 -
            value = (upper - 'A') as u32 + 10;
187 +
            set value = (upper - 'A') as u32 + 10;
188 188
        }
189 189
    }
190 190
    if value < radix {
191 191
        return value;
192 192
    }
207 207
    let mut start: u32 = 0;
208 208
    let mut radix: u32 = 10;
209 209
    let mut radixType = ast::Radix::Decimal;
210 210
211 211
    if signed {
212 -
        start = 1;
212 +
        set start = 1;
213 213
        if start >= text.len {
214 214
            throw failParsing(p, "integer literal requires digits after sign");
215 215
        }
216 216
    }
217 217
    if start + 1 < text.len and text[start] == '0' {
218 218
        let prefix = text[start + 1];
219 219
        if prefix == 'x' or prefix == 'X' {
220 -
            radix = 16;
221 -
            radixType = ast::Radix::Hex;
222 -
            start += 2;
220 +
            set radix = 16;
221 +
            set radixType = ast::Radix::Hex;
222 +
            set start += 2;
223 223
        } else if prefix == 'b' or prefix == 'B' {
224 -
            radix = 2;
225 -
            radixType = ast::Radix::Binary;
226 -
            start += 2;
224 +
            set radix = 2;
225 +
            set radixType = ast::Radix::Binary;
226 +
            set start += 2;
227 227
        }
228 228
        if start >= text.len {
229 229
            throw failParsing(p, "integer literal prefix must be followed by digits");
230 230
        }
231 231
    }
237 237
            throw failParsing(p, "invalid digit in integer literal");
238 238
        };
239 239
        if value > (U64_MAX / radix64) {
240 240
            throw failParsing(p, "integer literal overflow");
241 241
        }
242 -
        value *= radix64;
242 +
        set value *= radix64;
243 243
244 244
        if value > U64_MAX - (digit as u64) {
245 245
            throw failParsing(p, "integer literal overflow");
246 246
        }
247 -
        value += (digit as u64);
247 +
        set value += (digit as u64);
248 248
    }
249 249
    return ast::IntLiteral {
250 250
        text, magnitude: value, radix: radixType, signed, negative,
251 251
    };
252 252
}
275 275
    let mut j: u32 = 0;
276 276
277 277
    while i < raw.len {
278 278
        if raw[i] == '\\' and i + 1 < raw.len {
279 279
            match raw[i + 1] {
280 -
                case 'n'  => dst[j] = '\n',
281 -
                case 't'  => dst[j] = '\t',
282 -
                case 'r'  => dst[j] = '\r',
283 -
                case '\\' => dst[j] = '\\',
284 -
                case '"'  => dst[j] = '"',
285 -
                case '0'  => dst[j] = 0,
286 -
                else      => dst[j] = raw[i + 1],
280 +
                case 'n'  => set dst[j] = '\n',
281 +
                case 't'  => set dst[j] = '\t',
282 +
                case 'r'  => set dst[j] = '\r',
283 +
                case '\\' => set dst[j] = '\\',
284 +
                case '"'  => set dst[j] = '"',
285 +
                case '0'  => set dst[j] = 0,
286 +
                else      => set dst[j] = raw[i + 1],
287 287
            }
288 -
            i += 2;
288 +
            set i += 2;
289 289
        } else {
290 -
            dst[j] = raw[i];
291 -
            i += 1;
290 +
            set dst[j] = raw[i];
291 +
            set i += 1;
292 292
        }
293 -
        j += 1;
293 +
        set j += 1;
294 294
    }
295 295
    return j;
296 296
}
297 297
298 298
/// Emit a single attribute node.
310 310
    throws (ParseError)
311 311
{
312 312
    try expect(p, scanner::TokenKind::LParen, "expected `(`");
313 313
314 314
    let saved = p.context;
315 -
    p.context = Context::Normal;
315 +
    set p.context = Context::Normal;
316 316
    let expr = try parseExpr(p);
317 -
    p.context = saved;
317 +
    set p.context = saved;
318 318
319 319
    try expect(p, scanner::TokenKind::RParen, "expected `)`");
320 320
321 321
    return expr;
322 322
}
375 375
    let mut result = expr;
376 376
377 377
    while consume(p, scanner::TokenKind::As) {
378 378
        let target = try parseType(p);
379 379
380 -
        result = node(p, ast::NodeValue::As(
380 +
        set result = node(p, ast::NodeValue::As(
381 381
            ast::As { value: result, type: target }
382 382
        ));
383 383
    }
384 384
    return result;
385 385
}
419 419
420 420
    if consume(p, scanner::TokenKind::DotDot) {
421 421
        // Either `..` or `..end`.
422 422
        let mut endExpr: ?*ast::Node = nil;
423 423
        if not check(p, scanner::TokenKind::RBracket) {
424 -
            endExpr = try parseExpr(p);
424 +
            set endExpr = try parseExpr(p);
425 425
        }
426 -
        index = node(p, ast::NodeValue::Range(
426 +
        set index = node(p, ast::NodeValue::Range(
427 427
            ast::Range { start: nil, end: endExpr }
428 428
        ));
429 429
    } else {
430 430
        // Either `n`, `n..` or `n..end`.
431 431
        let startExpr = try parseExpr(p);
432 432
433 433
        if consume(p, scanner::TokenKind::DotDot) {
434 434
            // Either `n..` or `n..end`.
435 435
            let mut endExpr: ?*ast::Node = nil;
436 436
            if not check(p, scanner::TokenKind::RBracket) {
437 -
                endExpr = try parseExpr(p);
437 +
                set endExpr = try parseExpr(p);
438 438
            }
439 -
            index = node(p, ast::NodeValue::Range(
439 +
            set index = node(p, ast::NodeValue::Range(
440 440
                ast::Range { start: startExpr, end: endExpr }
441 441
            ));
442 442
        } else {
443 443
            // Just `n` - regular indexing.
444 -
            index = startExpr;
444 +
            set index = startExpr;
445 445
        }
446 446
    }
447 447
    try expect(p, scanner::TokenKind::RBracket, "expected `]` after array index");
448 448
449 449
    return node(p, ast::NodeValue::Subscript { container, index });
459 459
        match p.current.kind {
460 460
            case scanner::TokenKind::Dot => {
461 461
                advance(p);
462 462
463 463
                let field = try parseIdent(p, "expected field name after `.`");
464 -
                result = node(p, ast::NodeValue::FieldAccess(
464 +
                set result = node(p, ast::NodeValue::FieldAccess(
465 465
                    ast::Access { parent: result, child: field }
466 466
                ));
467 467
            }
468 468
            case scanner::TokenKind::ColonColon => {
469 469
                advance(p);
470 470
471 471
                let ident = try parseIdent(p, "expected identifier after `::`");
472 -
                result = node(p, ast::NodeValue::ScopeAccess(
472 +
                set result = node(p, ast::NodeValue::ScopeAccess(
473 473
                    ast::Access { parent: result, child: ident }
474 474
                ));
475 475
            }
476 476
            case scanner::TokenKind::LBracket => {
477 -
                result = try parseSubscriptOrSlice(p, result);
477 +
                set result = try parseSubscriptOrSlice(p, result);
478 478
            }
479 479
            case scanner::TokenKind::LParen => {
480 -
                result = try parseCall(p, result);
480 +
                set result = try parseCall(p, result);
481 481
            }
482 482
            case scanner::TokenKind::LBrace if p.context <> Context::Condition => {
483 -
                result = try parseRecordLit(p, result);
483 +
                set result = try parseRecordLit(p, result);
484 484
            }
485 485
            else => {
486 486
                break;
487 487
            }
488 488
        }
491 491
}
492 492
493 493
/// Parse a conditional expression.
494 494
export fn parseCond(p: *mut Parser) -> *ast::Node throws (ParseError) {
495 495
    let saved = p.context;
496 -
    p.context = Context::Condition;
496 +
    set p.context = Context::Condition;
497 497
    let expr = try parseExpr(p);
498 -
    p.context = saved;
498 +
    set p.context = saved;
499 499
500 500
    return expr;
501 501
}
502 502
503 503
/// Parse unary expression followed by optional `as` cast.
579 579
{
580 580
    let mut endExpr: ?*ast::Node = nil;
581 581
582 582
    if not isRangeTerminator(p.current.kind) {
583 583
        let right = try parseUnary(p);
584 -
        endExpr = try parseBinary(p, right, -1);
584 +
        set endExpr = try parseBinary(p, right, -1);
585 585
    }
586 586
    return node(p, ast::NodeValue::Range(
587 587
        ast::Range { start, end: endExpr }
588 588
    ));
589 589
}
595 595
    let mut result = left;
596 596
597 597
    loop {
598 598
        if p.current.kind == scanner::TokenKind::DotDot {
599 599
            advance(p);
600 -
            result = try parseRangeExpr(p, result);
600 +
            set result = try parseRangeExpr(p, result);
601 601
        } else {
602 602
            let opInfo = findNextOp(p.current.kind, minPrec) else break;
603 603
            advance(p);
604 604
605 605
            let mut right = try parseUnary(p);
606 606
607 607
            while let _ = findNextOp(p.current.kind, opInfo.prec)  {
608 -
                right = try parseBinary(p, right, opInfo.prec);
608 +
                set right = try parseBinary(p, right, opInfo.prec);
609 609
            }
610 -
            result = node(p, ast::NodeValue::BinOp(ast::BinOp {
610 +
            set result = node(p, ast::NodeValue::BinOp(ast::BinOp {
611 611
                op: opInfo.op, left: result, right,
612 612
            }));
613 613
        }
614 614
    }
615 615
    return result;
630 630
            return true,
631 631
        else =>
632 632
            return false,
633 633
    }
634 634
}
635 -
636 635
/// Check if a statement requires a semicolon after it.
637 636
///
638 637
/// Statements that end with blocks don't require semicolons.
639 638
/// All other statements do.
640 639
fn expectsSemicolon(stmt: *ast::Node) -> bool {
702 701
            let src = p.previous.source;
703 702
            let mut ch: u8 = 0;
704 703
705 704
            if src[1] == '\\' { // Handle escape sequences.
706 705
                match src[2] {
707 -
                    case 'n'  => { ch = '\n'; }
708 -
                    case 't'  => { ch = '\t'; }
709 -
                    case 'r'  => { ch = '\r'; }
710 -
                    case '\'' => { ch = '\''; }
711 -
                    case '\\' => { ch = '\\'; }
712 -
                    else      => { ch = src[2]; }
706 +
                    case 'n'  => { set ch = '\n'; }
707 +
                    case 't'  => { set ch = '\t'; }
708 +
                    case 'r'  => { set ch = '\r'; }
709 +
                    case '\'' => { set ch = '\''; }
710 +
                    case '\\' => { set ch = '\\'; }
711 +
                    else      => { set ch = src[2]; }
713 712
                }
714 713
            } else {
715 -
                ch = src[1];
714 +
                set ch = src[1];
716 715
            }
717 716
            return node(p, ast::NodeValue::Char(ch));
718 717
        }
719 718
        case scanner::TokenKind::String => {
720 719
            advance(p);
773 772
    advance(p);
774 773
775 774
    let mut kind: ast::Builtin = undefined;
776 775
    // TODO: Use `match`.
777 776
    if ident == "@sizeOf" {
778 -
        kind = ast::Builtin::SizeOf;
777 +
        set kind = ast::Builtin::SizeOf;
779 778
    } else if ident == "@alignOf" {
780 -
        kind = ast::Builtin::AlignOf;
779 +
        set kind = ast::Builtin::AlignOf;
781 780
    } else if ident == "@sliceOf" {
782 -
        kind = ast::Builtin::SliceOf;
781 +
        set kind = ast::Builtin::SliceOf;
783 782
    } else {
784 783
        throw failParsing(p, "unknown builtin");
785 784
    }
786 785
    try expect(p, scanner::TokenKind::LParen, "expected `(` after builtin name");
787 786
838 837
/// Parse an expression statement.
839 838
export fn parseExprStmt(p: *mut Parser) -> *ast::Node
840 839
    throws (ParseError)
841 840
{
842 841
    let expr = try parseExpr(p);
842 +
    return node(p, ast::NodeValue::ExprStmt(expr));
843 +
}
843 844
845 +
/// Parse a `set` statement assignment.
846 +
fn parseSetStmt(p: *mut Parser) -> *ast::Node
847 +
    throws (ParseError)
848 +
{
849 +
    let target = try parseUnary(p);
850 +
    if not ast::isPlaceExpr(target) {
851 +
        throw failParsing(p, "invalid assignment target");
852 +
    }
844 853
    if consume(p, scanner::TokenKind::Equal) {
845 -
        if not isAssignableTarget(expr) {
846 -
            throw failParsing(p, "invalid assignment target");
847 -
        }
848 854
        let value = try parseExpr(p);
849 -
850 855
        return node(p, ast::NodeValue::Assign(
851 -
            ast::Assign { left: expr, right: value }
856 +
            ast::Assign { left: target, right: value }
852 857
        ));
853 858
    }
854 -
    // Compound assignment: desugar `x <op>= y` into `x = x <op> y`.
855 -
    // The left-hand side node is shared between the assignment target and the
856 -
    // binary operand. This is safe because the resolver caches results by node
857 -
    // and returns the same type on repeated visits.
859 +
    // Compound assignment: desugar `set x <op>= y` into `set x = x <op> y`.
860 +
    // The target node is shared with the binary operand.
858 861
    if let op = tryCompoundAssignOp(p) {
859 -
        if not isAssignableTarget(expr) {
860 -
            throw failParsing(p, "invalid compound assignment target");
861 -
        }
862 862
        let rhs = try parseExpr(p);
863 863
        let binop = node(p, ast::NodeValue::BinOp(
864 -
            ast::BinOp { op, left: expr, right: rhs }
864 +
            ast::BinOp { op, left: target, right: rhs }
865 865
        ));
866 -
867 866
        return node(p, ast::NodeValue::Assign(
868 -
            ast::Assign { left: expr, right: binop }
867 +
            ast::Assign { left: target, right: binop }
869 868
        ));
870 869
    }
871 -
    return node(p, ast::NodeValue::ExprStmt(expr));
870 +
    throw failParsing(p, "expected assignment after `set`");
872 871
}
873 872
874 873
/// Parse leading attributes attached to the next declaration statement.
875 874
fn parseAttributes(p: *mut Parser) -> ?ast::Attributes {
876 875
    let mut attrs = ast::nodeSlice(p.arena, 4);
988 987
            }
989 988
            return try parseLet(p, false);
990 989
        }
991 990
        case scanner::TokenKind::Set => {
992 991
            advance(p);
993 -
            let stmt = try parseExprStmt(p);
994 -
            if let case ast::NodeValue::Assign(_) = stmt.value {
995 -
                return stmt;
996 -
            }
997 -
            throw failParsing(p, "expected assignment after `set`");
992 +
            return try parseSetStmt(p);
998 993
        }
999 994
        case scanner::TokenKind::Constant => {
1000 995
            return try parseConst(p, attrs);
1001 996
        }
1002 997
        case scanner::TokenKind::Static => {
1112 1107
fn finishSpan(p: *mut Parser, node: *mut ast::Node) {
1113 1108
    let start: u32 = node.span.offset;
1114 1109
    let mut end: u32 = p.previous.offset + p.previous.source.len;
1115 1110
1116 1111
    if end >= start {
1117 -
        node.span.length = end - start;
1112 +
        set node.span.length = end - start;
1118 1113
    } else {
1119 -
        node.span.length = 0;
1114 +
        set node.span.length = 0;
1120 1115
    }
1121 1116
}
1122 1117
1123 1118
/// Save parser state for speculative parsing.
1124 1119
fn saveState(p: *Parser) -> SavedState {
1130 1125
}
1131 1126
1132 1127
/// Restore parser state from a snapshot, fully undoing any
1133 1128
/// side effects of a failed speculative parse.
1134 1129
fn restoreState(p: *mut Parser, s: *SavedState) {
1135 -
    *p = s.parser;
1130 +
    set *p = s.parser;
1136 1131
    alloc::restore(&mut p.arena.arena, s.arena);
1137 -
    p.arena.nextId = s.nextId;
1132 +
    set p.arena.nextId = s.nextId;
1138 1133
}
1139 1134
1140 1135
/// Report a parser error.
1141 1136
fn reportError(p: *mut Parser, token: scanner::Token, message: *[u8]) {
1142 1137
    assert message.len > 0;
1143 1138
1144 1139
    // Ignore errors once the error list is full.
1145 1140
    if p.errors.count < p.errors.list.len {
1146 -
        p.errors.list[p.errors.count] = Error { message, token };
1147 -
        p.errors.count += 1;
1141 +
        set p.errors.list[p.errors.count] = Error { message, token };
1142 +
        set p.errors.count += 1;
1148 1143
    }
1149 1144
}
1150 1145
1151 1146
/// Fail the parsing process with the given error.
1152 1147
fn failParsing(p: *mut Parser, err: *[u8]) -> ParseError {
1190 1185
    return p.current.kind == kind;
1191 1186
}
1192 1187
1193 1188
/// Advance the parser by one token.
1194 1189
export fn advance(p: *mut Parser) {
1195 -
    p.previous = p.current;
1196 -
    p.current = scanner::next(&mut p.scanner);
1190 +
    set p.previous = p.current;
1191 +
    set p.current = scanner::next(&mut p.scanner);
1197 1192
}
1198 1193
1199 1194
/// Parse an `if let` pattern matching statement.
1200 1195
///
1201 1196
/// Syntax: `if let binding = scrutinee { ... }`
1207 1202
    let mut pattern: *ast::Node = undefined;
1208 1203
    let mut kind = ast::PatternKind::Binding;
1209 1204
    let mut mutable = false;
1210 1205
1211 1206
    if consume(p, scanner::TokenKind::Case) {
1212 -
        pattern = try parseMatchPattern(p);
1213 -
        kind = ast::PatternKind::Case;
1207 +
        set pattern = try parseMatchPattern(p);
1208 +
        set kind = ast::PatternKind::Case;
1214 1209
    } else {
1215 -
        mutable = consume(p, scanner::TokenKind::Mut);
1216 -
        pattern = try parseIdentOrPlaceholder(p, "expected `case`, `mut`, or identifier after `let`");
1210 +
        set mutable = consume(p, scanner::TokenKind::Mut);
1211 +
        set pattern = try parseIdentOrPlaceholder(p, "expected `case`, `mut`, or identifier after `let`");
1217 1212
    }
1218 1213
    try expect(p, scanner::TokenKind::Equal, "expected `=` after pattern");
1219 1214
1220 1215
    let scrutinee = try parseCond(p);
1221 1216
    let mut guard: ?*ast::Node = nil;
1222 1217
1223 1218
    if consume(p, scanner::TokenKind::Semicolon) {
1224 -
        guard = try parseCond(p);
1219 +
        set guard = try parseCond(p);
1225 1220
    }
1226 1221
    let thenBranch = try parseBlock(p);
1227 1222
    let mut elseBranch: ?*ast::Node = nil;
1228 1223
1229 1224
    if consume(p, scanner::TokenKind::Else) {
1230 1225
        if check(p, scanner::TokenKind::If) {
1231 -
            elseBranch = node(p, ast::NodeValue::Block(
1226 +
            set elseBranch = node(p, ast::NodeValue::Block(
1232 1227
                mkBlockWith(p, try parseIf(p))
1233 1228
            ));
1234 1229
        } else {
1235 -
            elseBranch = try parseBlock(p);
1230 +
            set elseBranch = try parseBlock(p);
1236 1231
        }
1237 1232
    }
1238 1233
1239 1234
    return node(p, ast::NodeValue::IfLet(ast::IfLet {
1240 1235
        pattern: ast::PatternMatch { pattern, scrutinee, guard, kind, mutable },
1252 1247
    // Parse pattern: either `case <pattern>`, `mut <ident>`, or simple `<ident>`.
1253 1248
    let mut pattern: *ast::Node = undefined;
1254 1249
    let mut kind = ast::PatternKind::Binding;
1255 1250
    let mut mutable = false;
1256 1251
    if consume(p, scanner::TokenKind::Case) {
1257 -
        pattern = try parseMatchPattern(p);
1258 -
        kind = ast::PatternKind::Case;
1252 +
        set pattern = try parseMatchPattern(p);
1253 +
        set kind = ast::PatternKind::Case;
1259 1254
    } else {
1260 -
        mutable = consume(p, scanner::TokenKind::Mut);
1261 -
        pattern = try parseIdentOrPlaceholder(p, "expected `case`, `mut`, or identifier after `let`");
1255 +
        set mutable = consume(p, scanner::TokenKind::Mut);
1256 +
        set pattern = try parseIdentOrPlaceholder(p, "expected `case`, `mut`, or identifier after `let`");
1262 1257
    }
1263 1258
    try expect(p, scanner::TokenKind::Equal, "expected `=` after pattern");
1264 1259
1265 1260
    let scrutinee = try parseCond(p);
1266 1261
    let mut guard: ?*ast::Node = nil;
1267 1262
1268 1263
    if consume(p, scanner::TokenKind::Semicolon) {
1269 -
        guard = try parseCond(p);
1264 +
        set guard = try parseCond(p);
1270 1265
    }
1271 1266
    let body = try parseBlock(p);
1272 1267
    let mut elseBranch: ?*ast::Node = nil;
1273 1268
1274 1269
    if consume(p, scanner::TokenKind::Else) {
1275 -
        elseBranch = try parseBlock(p);
1270 +
        set elseBranch = try parseBlock(p);
1276 1271
    }
1277 1272
    return node(p, ast::NodeValue::WhileLet(ast::WhileLet {
1278 1273
        pattern: ast::PatternMatch { pattern, scrutinee, guard, kind, mutable },
1279 1274
        body,
1280 1275
        elseBranch,
1294 1289
    let condition = try parseCond(p);
1295 1290
    let body = try parseBlock(p);
1296 1291
    let mut elseBranch: ?*ast::Node = nil;
1297 1292
1298 1293
    if consume(p, scanner::TokenKind::Else) {
1299 -
        elseBranch = try parseBlock(p);
1294 +
        set elseBranch = try parseBlock(p);
1300 1295
    }
1301 1296
    return node(p, ast::NodeValue::While(ast::While {
1302 1297
        condition, body, elseBranch,
1303 1298
    }));
1304 1299
}
1321 1316
1322 1317
    let binding = try parseIdentOrPlaceholder(p, "expected identifier or `_`");
1323 1318
    let mut index: ?*ast::Node = nil;
1324 1319
1325 1320
    if consume(p, scanner::TokenKind::Comma) {
1326 -
        index = try parseIdentOrPlaceholder(p, "expected index identifier or `_` after `,`");
1321 +
        set index = try parseIdentOrPlaceholder(p, "expected index identifier or `_` after `,`");
1327 1322
    }
1328 1323
    try expect(p, scanner::TokenKind::In, "expected `in`");
1329 1324
1330 1325
    let iterable = try parseCond(p);
1331 1326
    let body = try parseBlock(p);
1332 1327
    let mut elseBranch: ?*ast::Node = nil;
1333 1328
1334 1329
    if consume(p, scanner::TokenKind::Else) {
1335 -
        elseBranch = try parseBlock(p);
1330 +
        set elseBranch = try parseBlock(p);
1336 1331
    }
1337 1332
    return node(p, ast::NodeValue::For(ast::For {
1338 1333
        binding, index, iterable, body, elseBranch,
1339 1334
    }));
1340 1335
}
1397 1392
    try expect(p, scanner::TokenKind::Assert, "expected `assert`");
1398 1393
1399 1394
    // `assert { expr }` block form or `assert <expr>`.
1400 1395
    let mut condition: *ast::Node = undefined;
1401 1396
    if consume(p, scanner::TokenKind::LBrace) {
1402 -
        condition = try parseExpr(p);
1397 +
        set condition = try parseExpr(p);
1403 1398
        try expect(p, scanner::TokenKind::RBrace, "expected closing `}` after expression");
1404 1399
    } else {
1405 -
        condition = try parseExpr(p);
1400 +
        set condition = try parseExpr(p);
1406 1401
    }
1407 1402
    let mut message: ?*ast::Node = nil;
1408 1403
    if consume(p, scanner::TokenKind::Comma) {
1409 -
        message = try parseExpr(p);
1404 +
        set message = try parseExpr(p);
1410 1405
    }
1411 1406
    return node(p, ast::NodeValue::Assert { condition, message });
1412 1407
}
1413 1408
1414 1409
/// Parse a `try` expression with optional `catch` clause(s).
1427 1422
        let mut typeNode: ?*ast::Node = nil;
1428 1423
1429 1424
        // Check for optional error binding: `catch ident { ... }` or
1430 1425
        // `catch ident as Type { ... }`.
1431 1426
        if check(p, scanner::TokenKind::Ident) {
1432 -
            binding = try parseIdent(p, "expected identifier after `catch`");
1427 +
            set binding = try parseIdent(p, "expected identifier after `catch`");
1433 1428
            if consume(p, scanner::TokenKind::As) {
1434 -
                typeNode = try parseType(p);
1429 +
                set typeNode = try parseType(p);
1435 1430
            }
1436 1431
        }
1437 1432
        if not check(p, scanner::TokenKind::LBrace) {
1438 1433
            throw failParsing(p, "expected `{` after `catch`");
1439 1434
        }
1499 1494
1500 1495
    if consume(p, scanner::TokenKind::Else) {
1501 1496
        // Check for `else if` construct.
1502 1497
        if check(p, scanner::TokenKind::If) {
1503 1498
            // Set the else branch to a block containing the nested if.
1504 -
            elseBranch = node(p, ast::NodeValue::Block(
1499 +
            set elseBranch = node(p, ast::NodeValue::Block(
1505 1500
                mkBlockWith(p, try parseIf(p))
1506 1501
            ));
1507 1502
        } else {
1508 1503
            // Regular else clause.
1509 -
            elseBranch = try parseBlock(p);
1504 +
            set elseBranch = try parseBlock(p);
1510 1505
        }
1511 1506
    }
1512 1507
    return node(p, ast::NodeValue::If(ast::If {
1513 1508
        condition: cond, thenBranch, elseBranch,
1514 1509
    }));
1559 1554
            if check(p, scanner::TokenKind::Case) or check(p, scanner::TokenKind::Else) {
1560 1555
                throw failParsing(p, "unexpected keyword after `,` in case pattern list");
1561 1556
            }
1562 1557
        }
1563 1558
        if consume(p, scanner::TokenKind::If) {
1564 -
            guard = try parseCond(p);
1559 +
            set guard = try parseCond(p);
1565 1560
        }
1566 1561
        try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after case pattern");
1567 1562
        let body = try parseStmt(p);
1568 1563
1569 1564
        return node(p, ast::NodeValue::MatchProng(
1571 1566
        ));
1572 1567
    }
1573 1568
    // Else prong: `else if <guard> => <body>`.
1574 1569
    if consume(p, scanner::TokenKind::Else) {
1575 1570
        if consume(p, scanner::TokenKind::If) {
1576 -
            guard = try parseCond(p);
1571 +
            set guard = try parseCond(p);
1577 1572
        }
1578 1573
        try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after else");
1579 1574
        let body = try parseStmt(p);
1580 1575
1581 1576
        return node(p, ast::NodeValue::MatchProng(
1584 1579
    }
1585 1580
    // Binding prong: `<ident> if <guard> => <body>` or `_ if <guard> => <body>`.
1586 1581
    let binding = try parseIdentOrPlaceholder(p, "expected `case`, `else`, or identifier");
1587 1582
1588 1583
    if consume(p, scanner::TokenKind::If) {
1589 -
        guard = try parseCond(p);
1584 +
        set guard = try parseCond(p);
1590 1585
    }
1591 1586
    try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after binding");
1592 1587
    let body = try parseStmt(p);
1593 1588
1594 1589
    return node(p, ast::NodeValue::MatchProng(
1600 1595
/// Uses `Pattern` context to allow record literals but not conditional expressions.
1601 1596
fn parseMatchPattern(p: *mut Parser) -> *ast::Node
1602 1597
    throws (ParseError)
1603 1598
{
1604 1599
    let saved = p.context;
1605 -
    p.context = Context::Pattern;
1600 +
    set p.context = Context::Pattern;
1606 1601
    let pattern = try parseExpr(p);
1607 -
    p.context = saved;
1602 +
    set p.context = saved;
1608 1603
1609 1604
    return pattern;
1610 1605
}
1611 1606
1612 1607
/// Parse an identifier.
1666 1661
                    throw failParsing(p, "record fields cannot specify alignment");
1667 1662
                }
1668 1663
                if field.value <> nil and mode <> RecordFieldMode::Labeled {
1669 1664
                    throw failParsing(p, "record fields cannot have initializers");
1670 1665
                }
1671 -
                recordField = ast::NodeValue::RecordField {
1666 +
                set recordField = ast::NodeValue::RecordField {
1672 1667
                    field: field.name, type, value: field.value,
1673 1668
                };
1674 1669
            }
1675 1670
            case RecordFieldMode::Unlabeled => {
1676 1671
                let type = try parseType(p);
1677 -
                recordField = ast::NodeValue::RecordField {
1672 +
                set recordField = ast::NodeValue::RecordField {
1678 1673
                    field: nil, type, value: nil,
1679 1674
                };
1680 1675
            }
1681 1676
        }
1682 1677
        fields.append(node(p, recordField), p.allocator);
1738 1733
    try expect(p, scanner::TokenKind::LBrace, "expected `{` to begin record literal");
1739 1734
1740 1735
    while not check(p, scanner::TokenKind::RBrace) {
1741 1736
        // Check for `..` to ignore remaining fields.
1742 1737
        if consume(p, scanner::TokenKind::DotDot) {
1743 -
            ignoreRest = true;
1738 +
            set ignoreRest = true;
1744 1739
            break;
1745 1740
        }
1746 1741
        let field = try parseRecordLitField(p);
1747 1742
        fields.append(field, p.allocator);
1748 1743
1803 1798
        let mut payloadType: ?*ast::Node = nil;
1804 1799
        let mut explicitValue: ?*ast::Node = nil;
1805 1800
1806 1801
        if consume(p, scanner::TokenKind::LParen) { // `Variant(T, U)`.
1807 1802
            let fields = try parseRecordFields(p, RecordFieldMode::Unlabeled);
1808 -
            payloadType = node(p, ast::NodeValue::TypeSig(
1803 +
            set payloadType = node(p, ast::NodeValue::TypeSig(
1809 1804
                ast::TypeSig::Record { fields, labeled: false }
1810 1805
            ));
1811 1806
        } else if consume(p, scanner::TokenKind::LBrace) { // `Variant { x: T, y: T }`.
1812 1807
            let fields = try parseRecordFields(p, RecordFieldMode::Labeled);
1813 -
            payloadType = node(p, ast::NodeValue::TypeSig(
1808 +
            set payloadType = node(p, ast::NodeValue::TypeSig(
1814 1809
                ast::TypeSig::Record { fields, labeled: true }
1815 1810
            ));
1816 1811
        } else if consume(p, scanner::TokenKind::Equal) {
1817 1812
            // TODO: Support constant expressions.
1818 1813
            try expect(p, scanner::TokenKind::Number, "expected integer literal after `=`");
1819 1814
            let literal = try parseIntLiteral(p, p.previous.source);
1820 -
            explicitValue = nodeNumber(p, literal);
1815 +
            set explicitValue = nodeNumber(p, literal);
1821 1816
        }
1822 1817
1823 1818
        let variant = node(p, ast::NodeValue::UnionDeclVariant(
1824 1819
            ast::UnionDeclVariant {
1825 1820
                name: variantName, index: variants.len as u32, value: explicitValue, type: payloadType,
1878 1873
        parseType
1879 1874
    );
1880 1875
    let mut returnType: ?*ast::Node = nil;
1881 1876
1882 1877
    if consume(p, scanner::TokenKind::Arrow) {
1883 -
        returnType = try parseType(p);
1878 +
        set returnType = try parseType(p);
1884 1879
    }
1885 1880
    let throwList = try parseThrowList(p);
1886 1881
    let sig = ast::FnSig { params, returnType, throwList };
1887 1882
    return node(p, ast::NodeValue::TypeSig(
1888 1883
        ast::TypeSig::Fn(sig)
1906 1901
    }
1907 1902
    try expect(p, scanner::TokenKind::RParen, "expected `)` after function parameters");
1908 1903
1909 1904
    let mut returnType: ?*ast::Node = nil;
1910 1905
    if consume(p, scanner::TokenKind::Arrow) {
1911 -
        returnType = try parseType(p);
1906 +
        set returnType = try parseType(p);
1912 1907
    }
1913 1908
    let throwList = try parseThrowList(p);
1914 1909
1915 1910
    return ast::FnSig { params, returnType, throwList };
1916 1911
}
1940 1935
                    list.append(a.list[i], p.allocator);
1941 1936
                }
1942 1937
            }
1943 1938
            let attrNode = nodeAttribute(p, ast::Attribute::Extern);
1944 1939
            list.append(attrNode, p.allocator);
1945 -
            fnAttrs = ast::Attributes { list };
1940 +
            set fnAttrs = ast::Attributes { list };
1946 1941
        }
1947 1942
    } else {
1948 -
        body = try parseBlock(p);
1943 +
        set body = try parseBlock(p);
1949 1944
    }
1950 1945
    return node(p, ast::NodeValue::FnDecl(
1951 1946
        ast::FnDecl { name, sig, body, attrs: fnAttrs }
1952 1947
    ));
1953 1948
}
2012 2007
    throws (ParseError)
2013 2008
{
2014 2009
    let mut path: *ast::Node = undefined;
2015 2010
    if p.current.kind == scanner::TokenKind::Super {
2016 2011
        advance(p);
2017 -
        path = nodeSuper(p);
2012 +
        set path = nodeSuper(p);
2018 2013
    } else {
2019 -
        path = try parseIdent(p, "expected type identifier");
2014 +
        set path = try parseIdent(p, "expected type identifier");
2020 2015
    }
2021 2016
    while consume(p, scanner::TokenKind::ColonColon) {
2022 2017
        let part = try parseIdent(p, "expected identifier after `::`");
2023 -
        path = node(p, ast::NodeValue::ScopeAccess(
2018 +
        set path = node(p, ast::NodeValue::ScopeAccess(
2024 2019
            ast::Access { parent: path, child: part }
2025 2020
        ));
2026 2021
    }
2027 2022
    return path;
2028 2023
}
2113 2108
    let mut type: ?*ast::Node = nil;
2114 2109
    let mut alignment: ?*ast::Node = nil;
2115 2110
    let mut value: ?*ast::Node = nil;
2116 2111
2117 2112
    if consume(p, scanner::TokenKind::Colon) {
2118 -
        type = try parseType(p);
2113 +
        set type = try parseType(p);
2119 2114
2120 2115
        if check(p, scanner::TokenKind::Align) {
2121 -
            alignment = try parseAlign(p);
2116 +
            set alignment = try parseAlign(p);
2122 2117
        }
2123 2118
    }
2124 2119
    if consume(p, scanner::TokenKind::Equal) {
2125 -
        value = try parseExpr(p);
2120 +
        set value = try parseExpr(p);
2126 2121
    }
2127 2122
    return NameTypeValue { name, type, value, alignment };
2128 2123
}
2129 2124
2130 2125
/// Parse a constant declaration.
2172 2167
    try expect(p, scanner::TokenKind::Use, "expected `use`");
2173 2168
2174 2169
    // Allow `super` or identifier as the first part of the path.
2175 2170
    let mut path: *ast::Node = undefined;
2176 2171
    if consume(p, scanner::TokenKind::Super) {
2177 -
        path = nodeSuper(p);
2172 +
        set path = nodeSuper(p);
2178 2173
    } else {
2179 -
        path = try parseIdent(p, "expected module name or `super` after `use`");
2174 +
        set path = try parseIdent(p, "expected module name or `super` after `use`");
2180 2175
    }
2181 2176
    while consume(p, scanner::TokenKind::ColonColon) {
2182 2177
        // Check for wildcard import (e.g., `use parser::*`)
2183 2178
        if consume(p, scanner::TokenKind::Star) {
2184 2179
            return node(p, ast::NodeValue::Use(
2185 2180
                ast::Use { path, wildcard: true, attrs }
2186 2181
            ));
2187 2182
        }
2188 2183
        let part = try parseIdent(p, "expected identifier or `*` after `::`");
2189 -
        path = node(p, ast::NodeValue::ScopeAccess(
2184 +
        set path = node(p, ast::NodeValue::ScopeAccess(
2190 2185
            ast::Access { parent: path, child: part }
2191 2186
        ));
2192 2187
    }
2193 2188
    return node(p, ast::NodeValue::Use(
2194 2189
        ast::Use { path, wildcard: false, attrs }
2219 2214
    try expect(p, scanner::TokenKind::Equal, "expected `=` after pattern");
2220 2215
    let expr = try parseCond(p);
2221 2216
2222 2217
    let mut guard: ?*ast::Node = nil;
2223 2218
    if consume(p, scanner::TokenKind::If) {
2224 -
        guard = try parseCond(p);
2219 +
        set guard = try parseCond(p);
2225 2220
    }
2226 2221
2227 2222
    try expect(p, scanner::TokenKind::Else, "expected `else` after pattern");
2228 2223
    let elseBranch = try parseLetElseBranch(p);
2229 2224
lib/std/lang/parser/tests.rad +22 -4
2186 2186
}
2187 2187
2188 2188
/// Test parsing assignment expressions.
2189 2189
@test fn testParseAssignment() throws (testing::TestError) {
2190 2190
    {
2191 -
        let assign = try! parseStmtStr("x = 1;");
2191 +
        let assign = try! parseStmtStr("set x = 1;");
2192 2192
        let case ast::NodeValue::Assign(node) = assign.value
2193 2193
            else throw testing::TestError::Failed;
2194 2194
        try expectIdent(node.left, "x");
2195 2195
        let case ast::NodeValue::Number(_) = node.right.value
2196 2196
            else throw testing::TestError::Failed;
2197 2197
    }
2198 2198
    {
2199 -
        let assign = try! parseStmtStr("obj.field = value;");
2199 +
        let assign = try! parseStmtStr("set obj.field = value;");
2200 2200
        let case ast::NodeValue::Assign(node) = assign.value
2201 2201
            else throw testing::TestError::Failed;
2202 2202
        let case ast::NodeValue::FieldAccess(access) = node.left.value
2203 2203
            else throw testing::TestError::Failed;
2204 2204
        try expectIdent(access.parent, "obj");
2205 2205
        try expectIdent(access.child, "field");
2206 2206
        try expectIdent(node.right, "value");
2207 2207
    }
2208 2208
    {
2209 -
        let assign = try! parseStmtStr("*ptr = rhs;");
2209 +
        let assign = try! parseStmtStr("set *ptr = rhs;");
2210 2210
        let case ast::NodeValue::Assign(node) = assign.value
2211 2211
            else throw testing::TestError::Failed;
2212 2212
        let case ast::NodeValue::Deref(target) = node.left.value
2213 2213
            else throw testing::TestError::Failed;
2214 2214
        try expectIdent(target, "ptr");
2215 2215
        try expectIdent(node.right, "rhs");
2216 2216
    }
2217 2217
    {
2218 -
        let assign = try! parseStmtStr("x = 1 + 2;");
2218 +
        let assign = try! parseStmtStr("set x = 1 + 2;");
2219 2219
        let case ast::NodeValue::Assign(node) = assign.value
2220 2220
            else throw testing::TestError::Failed;
2221 2221
        let case ast::NodeValue::BinOp(bin) = node.right.value
2222 2222
            else throw testing::TestError::Failed;
2223 2223
        try testing::expect(bin.op == ast::BinaryOp::Add);
2231 2231
        try expectIdent(access.parent, "module");
2232 2232
        try expectIdent(access.child, "VAR");
2233 2233
    }
2234 2234
}
2235 2235
2236 +
/// Test that assignment syntax requires the `set` statement.
2237 +
@test fn testAssignmentRequiresSetKeyword() throws (testing::TestError) {
2238 +
    let assign: ?*ast::Node = try? parseStmtStr("x = 1;");
2239 +
    try testing::expect(assign == nil);
2240 +
2241 +
    let compoundAssign: ?*ast::Node = try? parseStmtStr("x += 1;");
2242 +
    try testing::expect(compoundAssign == nil);
2243 +
}
2244 +
2245 +
/// Test that `set` requires an assignable target.
2246 +
@test fn testSetRequiresAssignableTarget() throws (testing::TestError) {
2247 +
    let binTarget: ?*ast::Node = try? parseStmtStr("set x + y = 1;");
2248 +
    try testing::expect(binTarget == nil);
2249 +
2250 +
    let condTarget: ?*ast::Node = try? parseStmtStr("set x if ok else y = 1;");
2251 +
    try testing::expect(condTarget == nil);
2252 +
}
2253 +
2236 2254
/// Test parsing basic arithmetic binary operators (+, -, *, /, %).
2237 2255
@test fn testParseBinOpArithmetic() throws (testing::TestError) {
2238 2256
    let add = try! parseExprStr("a + b");
2239 2257
    let case ast::NodeValue::BinOp(op1) = add.value
2240 2258
        else throw testing::TestError::Failed;
lib/std/lang/resolver.rad +176 -176
789 789
    let mut cursor = self.types;
790 790
    while let node = cursor {
791 791
        if node.ty == ty {
792 792
            return &node.ty;
793 793
        }
794 -
        cursor = node.next;
794 +
        set cursor = node.next;
795 795
    }
796 796
    // Allocate a new type node from the arena.
797 797
    let node = try! alloc::alloc(
798 798
        &mut self.arena, @sizeOf(TypeNode), @alignOf(TypeNode)
799 799
    ) as *mut TypeNode;
800 800
801 -
    *node = TypeNode { ty, next: self.types };
802 -
    self.types = node;
801 +
    set *node = TypeNode { ty, next: self.types };
802 +
    set self.types = node;
803 803
804 804
    return &node.ty;
805 805
}
806 806
807 807
/// Allocate a nominal type descriptor and return a pointer to it.
811 811
    // placeholder entries when binding symbols.
812 812
    let entry = try! alloc::alloc(
813 813
        &mut self.arena, @sizeOf(NominalType), @alignOf(NominalType)
814 814
    ) as *mut NominalType;
815 815
816 -
    *entry = info;
816 +
    set *entry = info;
817 817
818 818
    return entry;
819 819
}
820 820
821 821
/// Allocate a function type descriptor and return a pointer to it.
822 822
fn allocFnType(self: *mut Resolver, info: FnType) -> *FnType {
823 823
    let entry = try! alloc::alloc(
824 824
        &mut self.arena, @sizeOf(FnType), @alignOf(FnType)
825 825
    ) as *mut FnType;
826 826
827 -
    *entry = info;
827 +
    set *entry = info;
828 828
829 829
    return entry;
830 830
}
831 831
832 832
/// Returns an error, if any, associated with the given node.
870 870
        &mut arena, @sizeOf(*mut Symbol), @alignOf(*mut Symbol), MAX_MODULE_SYMBOLS
871 871
    ) as *mut [*mut Symbol];
872 872
873 873
    // Initialize the root scope.
874 874
    // TODO: Set this up when declaring `PKG_SCOPE`, not here.
875 -
    *storage.pkgScope = Scope {
875 +
    set *storage.pkgScope = Scope {
876 876
        owner: nil,
877 877
        parent: nil,
878 878
        moduleId: nil,
879 879
        symbols,
880 880
        symbolsLen: 0,
881 881
    };
882 882
883 883
    // Clear all node semantic metadata to sentinel values.
884 884
    // TODO: Use array repeat literal?
885 885
    for i in 0..storage.nodeData.len {
886 -
        storage.nodeData[i] = NodeData {
886 +
        set storage.nodeData[i] = NodeData {
887 887
            ty: Type::Unknown,
888 888
            coercion: Coercion::Identity,
889 889
            sym: nil,
890 890
            constValue: nil,
891 891
            scope: nil,
894 894
    }
895 895
896 896
    let mut moduleScopes: [?*mut Scope; module::MAX_MODULES] = undefined;
897 897
    // TODO: Simplify.
898 898
    for i in 0..moduleScopes.len {
899 -
        moduleScopes[i] = nil;
899 +
        set moduleScopes[i] = nil;
900 900
    }
901 901
    return Resolver {
902 902
        scope: storage.pkgScope,
903 903
        pkgScope: storage.pkgScope,
904 904
        loopStack: undefined,
942 942
    // Don't record more than one error per node.
943 943
    if let n = node; errorForNode(self, n) <> nil {
944 944
        return ResolveError::Failure;
945 945
    }
946 946
    let idx = self.errors.len;
947 -
    self.errors = @sliceOf(self.errors.ptr, idx + 1, self.errors.cap);
948 -
    self.errors[idx] = Error { kind, node, moduleId: self.currentMod };
947 +
    set self.errors = @sliceOf(self.errors.ptr, idx + 1, self.errors.cap);
948 +
    set self.errors[idx] = Error { kind, node, moduleId: self.currentMod };
949 949
950 950
    return ResolveError::Failure;
951 951
}
952 952
953 953
/// Like [`emitError`], but for type mismatches specifically.
969 969
    // Allocate symbols from the arena.
970 970
    let symbols = try! alloc::allocSlice(
971 971
        &mut self.arena, @sizeOf(*mut Symbol), @alignOf(*mut Symbol), capacity
972 972
    ) as *mut [*mut Symbol];
973 973
974 -
    *entry = Scope { owner, parent: nil, moduleId: nil, symbols, symbolsLen: 0 };
975 -
    self.nodeData.entries[owner.id].scope = entry;
974 +
    set *entry = Scope { owner, parent: nil, moduleId: nil, symbols, symbolsLen: 0 };
975 +
    set self.nodeData.entries[owner.id].scope = entry;
976 976
977 977
    return entry;
978 978
}
979 979
980 980
/// Enter a new local scope that is the child of the current scope.
981 981
/// This creates a parent/child relationship that means that lookups in the
982 982
/// child scope can recurse upwards.
983 983
export fn enterScope(self: *mut Resolver, owner: *ast::Node) -> *Scope {
984 984
    let scope = allocScope(self, owner, MAX_LOCAL_SYMBOLS);
985 -
    scope.parent = self.scope;
986 -
    self.scope = scope;
985 +
    set scope.parent = self.scope;
986 +
    set self.scope = scope;
987 987
    return scope;
988 988
}
989 989
990 990
/// Enter a module scope. Returns an object that can be used to exit the scope.
991 991
export fn enterModuleScope(self: *mut Resolver, owner: *ast::Node, module: *module::ModuleEntry) -> ModuleScope {
992 992
    let prevScope = self.scope;
993 993
    let prevMod = self.currentMod;
994 994
    let scope = allocScope(self, owner, MAX_MODULE_SYMBOLS);
995 995
996 -
    self.scope = scope;
997 -
    self.scope.moduleId = module.id;
998 -
    self.currentMod = module.id;
996 +
    set self.scope = scope;
997 +
    set self.scope.moduleId = module.id;
998 +
    set self.currentMod = module.id;
999 999
    // TODO: Allow any unsigned integer to index an array.
1000 -
    self.moduleScopes[module.id as u32] = scope;
1000 +
    set self.moduleScopes[module.id as u32] = scope;
1001 1001
1002 1002
    return ModuleScope { root: owner, entry: module, newScope: scope, prevScope, prevMod };
1003 1003
}
1004 1004
1005 1005
/// Enter a sub-module. Changes the current scope into that of the sub-module.
1012 1012
    return enterModuleScope(self, modRoot, modEntry);
1013 1013
}
1014 1014
1015 1015
/// Exit a module scope, given the object returned by `enterModuleScope`.
1016 1016
export fn exitModuleScope(self: *mut Resolver, entry: ModuleScope) {
1017 -
    self.scope = entry.prevScope;
1018 -
    self.currentMod = entry.prevMod;
1017 +
    set self.scope = entry.prevScope;
1018 +
    set self.currentMod = entry.prevMod;
1019 1019
}
1020 1020
1021 1021
/// Exit the most recent scope.
1022 1022
export fn exitScope(self: *mut Resolver) {
1023 1023
    let parent = self.scope.parent else {
1024 1024
        // TODO: This should be a panic, but one of the tests hits this
1025 1025
        // clause, which might be a bug in the generator.
1026 1026
        return;
1027 1027
    };
1028 -
    self.scope = parent;
1028 +
    set self.scope = parent;
1029 1029
}
1030 1030
1031 1031
/// Visit the body of a loop while tracking nesting depth.
1032 1032
fn visitLoop(self: *mut Resolver, body: *ast::Node) -> Type
1033 1033
    throws (ResolveError)
1034 1034
{
1035 1035
    assert self.loopDepth < MAX_LOOP_DEPTH, "visitLoop: loop nesting depth exceeded";
1036 -
    self.loopStack[self.loopDepth] = LoopCtx { hasBreak: false };
1037 -
    self.loopDepth += 1;
1036 +
    set self.loopStack[self.loopDepth] = LoopCtx { hasBreak: false };
1037 +
    set self.loopDepth += 1;
1038 1038
1039 1039
    let ty = try infer(self, body) catch {
1040 1040
        assert self.loopDepth <> 0, "visitLoop: loop depth underflow";
1041 -
        self.loopDepth -= 1;
1041 +
        set self.loopDepth -= 1;
1042 1042
        throw ResolveError::Failure;
1043 1043
    };
1044 1044
    // Pop and check if break was encountered.
1045 -
    self.loopDepth -= 1;
1045 +
    set self.loopDepth -= 1;
1046 1046
1047 1047
    if self.loopStack[self.loopDepth].hasBreak {
1048 1048
        return Type::Void;
1049 1049
    }
1050 1050
    return Type::Never;
1073 1073
}
1074 1074
1075 1075
/// Set the expected return type for a new function body.
1076 1076
fn enterFn(self: *mut Resolver, node: *ast::Node, ty: *FnType) {
1077 1077
    assert self.currentFn == nil, "enterFn: already in a function";
1078 -
    self.currentFn = ty;
1078 +
    set self.currentFn = ty;
1079 1079
    enterScope(self, node);
1080 1080
}
1081 1081
1082 1082
/// Clear the expected return type when leaving a function body.
1083 1083
fn exitFn(self: *mut Resolver) {
1084 1084
    if self.currentFn == nil {
1085 1085
        // TODO: This should be a panic, but one of the tests hits this
1086 1086
        // clause, which might be a bug in the generator.
1087 1087
        return;
1088 1088
    }
1089 -
    self.currentFn = nil;
1089 +
    set self.currentFn = nil;
1090 1090
    exitScope(self);
1091 1091
}
1092 1092
1093 1093
/// Extract the identifier text from a node.
1094 1094
fn nodeName(self: *mut Resolver, node: *ast::Node) -> *[u8]
1102 1102
/// Associate a resolved symbol with an AST node.
1103 1103
fn setNodeSymbol(self: *mut Resolver, node: *ast::Node, symbol: *mut Symbol) {
1104 1104
    if let existingSym = self.nodeData.entries[node.id].sym {
1105 1105
        panic "setNodeSymbol: a symbol is already associated with this node";
1106 1106
    }
1107 -
    self.nodeData.entries[node.id].sym = symbol;
1107 +
    set self.nodeData.entries[node.id].sym = symbol;
1108 1108
}
1109 1109
1110 1110
/// Associate a resolved type with an AST node and return it.
1111 1111
fn setNodeType(self: *mut Resolver, node: *ast::Node, ty: Type) -> Type {
1112 1112
    if ty == Type::Unknown {
1113 1113
        // In this case, we simply don't associate a type.
1114 1114
        return ty;
1115 1115
    }
1116 -
    self.nodeData.entries[node.id].ty = ty;
1116 +
    set self.nodeData.entries[node.id].ty = ty;
1117 1117
1118 1118
    return ty;
1119 1119
}
1120 1120
1121 1121
/// Unify the types of two branches for control flow. Returns `never` only if
1133 1133
/// Associate a coercion plan with an AST node.
1134 1134
fn setNodeCoercion(self: *mut Resolver, node: *ast::Node, coercion: Coercion) -> Coercion {
1135 1135
    if coercion == Coercion::Identity {
1136 1136
        return coercion;
1137 1137
    }
1138 -
    self.nodeData.entries[node.id].coercion = coercion;
1138 +
    set self.nodeData.entries[node.id].coercion = coercion;
1139 1139
1140 1140
    return coercion;
1141 1141
}
1142 1142
1143 1143
/// Associate a constant value with an AST node.
1144 1144
fn setNodeConstValue(self: *mut Resolver, node: *ast::Node, value: ConstValue) {
1145 -
    self.nodeData.entries[node.id].constValue = value;
1145 +
    set self.nodeData.entries[node.id].constValue = value;
1146 1146
}
1147 1147
1148 1148
/// Associate a record field index with a record literal field node.
1149 1149
fn setRecordFieldIndex(self: *mut Resolver, node: *ast::Node, index: u32) {
1150 -
    self.nodeData.entries[node.id].extra = NodeExtra::RecordField { index };
1150 +
    set self.nodeData.entries[node.id].extra = NodeExtra::RecordField { index };
1151 1151
}
1152 1152
1153 1153
/// Associate slice range metadata with a subscript expression.
1154 1154
fn setSliceRangeInfo(self: *mut Resolver, node: *ast::Node, info: SliceRangeInfo) {
1155 -
    self.nodeData.entries[node.id].extra = NodeExtra::SliceRange(info);
1155 +
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceRange(info);
1156 1156
}
1157 1157
1158 1158
/// Associate union variant metadata with a pattern or constructor node.
1159 1159
fn setVariantInfo(self: *mut Resolver, node: *ast::Node, ordinal: u32, tag: u32) {
1160 -
    self.nodeData.entries[node.id].extra = NodeExtra::UnionVariant { ordinal, tag };
1160 +
    set self.nodeData.entries[node.id].extra = NodeExtra::UnionVariant { ordinal, tag };
1161 1161
}
1162 1162
1163 1163
/// Associate trait method call metadata with a call node.
1164 1164
fn setTraitMethodCall(self: *mut Resolver, node: *ast::Node, traitInfo: *TraitType, methodIndex: u32) {
1165 -
    self.nodeData.entries[node.id].extra = NodeExtra::TraitMethodCall { traitInfo, methodIndex };
1165 +
    set self.nodeData.entries[node.id].extra = NodeExtra::TraitMethodCall { traitInfo, methodIndex };
1166 1166
}
1167 1167
1168 1168
/// Associate for-loop metadata with a for-loop node.
1169 1169
fn setForLoopInfo(self: *mut Resolver, node: *ast::Node, info: ForLoopInfo) {
1170 -
    self.nodeData.entries[node.id].extra = NodeExtra::ForLoop(info);
1170 +
    set self.nodeData.entries[node.id].extra = NodeExtra::ForLoop(info);
1171 1171
}
1172 1172
1173 1173
/// Retrieve the constant value associated with a node, if any.
1174 1174
export fn constValueEntry(self: *Resolver, node: *ast::Node) -> ?ConstValue {
1175 1175
    return self.nodeData.entries[node.id].constValue;
1199 1199
    return nil;
1200 1200
}
1201 1201
1202 1202
/// Associate match prong metadata with a match prong node.
1203 1203
fn setProngCatchAll(self: *mut Resolver, node: *ast::Node, catchAll: bool) {
1204 -
    self.nodeData.entries[node.id].extra = NodeExtra::MatchProng { catchAll };
1204 +
    set self.nodeData.entries[node.id].extra = NodeExtra::MatchProng { catchAll };
1205 1205
}
1206 1206
1207 1207
/// Check if a prong is catch-all.
1208 1208
export fn isProngCatchAll(self: *Resolver, node: *ast::Node) -> bool {
1209 1209
    if let case NodeExtra::MatchProng { catchAll } = self.nodeData.entries[node.id].extra {
1212 1212
    return false;
1213 1213
}
1214 1214
1215 1215
/// Set match metadata.
1216 1216
fn setMatchConst(self: *mut Resolver, node: *ast::Node, isConst: bool) {
1217 -
    self.nodeData.entries[node.id].extra = NodeExtra::Match { isConst };
1217 +
    set self.nodeData.entries[node.id].extra = NodeExtra::Match { isConst };
1218 1218
}
1219 1219
1220 1220
/// Check if a match has all constant patterns.
1221 1221
export fn isMatchConst(self: *Resolver, node: *ast::Node) -> bool {
1222 1222
    if let case NodeExtra::Match { isConst } = self.nodeData.entries[node.id].extra {
1297 1297
}
1298 1298
1299 1299
/// Allocate a new symbol, and return a reference to it.
1300 1300
fn allocSymbol(self: *mut Resolver, data: SymbolData, name: *[u8], node: *ast::Node, attrs: u32) -> *mut Symbol {
1301 1301
    let sym = try! alloc::alloc(&mut self.arena, @sizeOf(Symbol), @alignOf(Symbol)) as *mut Symbol;
1302 -
    *sym = Symbol { name, data, attrs, node, moduleId: nil };
1302 +
    set *sym = Symbol { name, data, attrs, node, moduleId: nil };
1303 1303
1304 1304
    return sym;
1305 1305
}
1306 1306
1307 1307
/// Check that a type is boolean, otherwise throw an error.
1371 1371
    let mut layout = getTypeLayout(ty);
1372 1372
    // Check for symbol-specific alignment override.
1373 1373
    if let sym = symbolFor(self, node) {
1374 1374
        if let case SymbolData::Value { alignment, .. } = sym.data {
1375 1375
            if alignment > 0 {
1376 -
                layout.alignment = alignment;
1376 +
                set layout.alignment = alignment;
1377 1377
            }
1378 1378
        }
1379 1379
    }
1380 1380
    return layout;
1381 1381
}
1468 1468
    let mut maxSize = payloadLayout.size;
1469 1469
    let mut maxAlign = payloadLayout.alignment;
1470 1470
1471 1471
    for errType in throwList {
1472 1472
        let errLayout = getTypeLayout(*errType);
1473 -
        maxSize = max(maxSize, errLayout.size);
1474 -
        maxAlign = max(maxAlign, errLayout.alignment);
1473 +
        set maxSize = max(maxSize, errLayout.size);
1474 +
        set maxAlign = max(maxAlign, errLayout.alignment);
1475 1475
    }
1476 1476
    return Layout {
1477 1477
        size: PTR_SIZE + maxSize,
1478 1478
        alignment: max(PTR_SIZE, maxAlign),
1479 1479
    };
1486 1486
    let mut maxVarAlign: u32 = 1;
1487 1487
    let mut isAllVoid: bool = true;
1488 1488
1489 1489
    for variant in variants {
1490 1490
        if variant.valueType <> Type::Void {
1491 -
            isAllVoid = false;
1491 +
            set isAllVoid = false;
1492 1492
            let payloadLayout = getTypeLayout(variant.valueType);
1493 -
            maxVarSize = max(maxVarSize, payloadLayout.size);
1494 -
            maxVarAlign = max(maxVarAlign, payloadLayout.alignment);
1493 +
            set maxVarSize = max(maxVarSize, payloadLayout.size);
1494 +
            set maxVarAlign = max(maxVarAlign, payloadLayout.alignment);
1495 1495
        }
1496 1496
    }
1497 1497
    let unionAlignment: u32 = max(1, maxVarAlign);
1498 1498
    let unionValOffset: u32 = mem::alignUp(tagSize, maxVarAlign);
1499 1499
    let unionLayout = Layout {
1508 1508
fn variantTag(variantDecl: ast::UnionDeclVariant, iota: *mut u32) -> u32 {
1509 1509
    let mut tag: u32 = *iota;
1510 1510
    if let valueNode = variantDecl.value {
1511 1511
        let case ast::NodeValue::Number(lit) = valueNode.value
1512 1512
            else panic "variantTag: expected number literal";
1513 -
        tag = lit.magnitude as u32;
1513 +
        set tag = lit.magnitude as u32;
1514 1514
    }
1515 -
    *iota = tag + 1;
1515 +
    set *iota = tag + 1;
1516 1516
    return tag;
1517 1517
}
1518 1518
1519 1519
/// Check if a type is a union without payloads.
1520 1520
export fn isVoidUnion(ty: Type) -> bool {
1619 1619
1620 1620
        if let sym = symbolFor(self, declNode) {
1621 1621
            if let mid = sym.moduleId {
1622 1622
                if (mid as u32) < self.moduleScopes.len {
1623 1623
                    if let ms = self.moduleScopes[mid as u32] {
1624 -
                        self.scope = ms;
1625 -
                        self.currentMod = mid;
1624 +
                        set self.scope = ms;
1625 +
                        set self.currentMod = mid;
1626 1626
                    }
1627 1627
                }
1628 1628
            }
1629 1629
        }
1630 1630
1635 1635
            case ast::NodeValue::UnionDecl(decl) => {
1636 1636
                try resolveUnionBody(self, declNode, decl);
1637 1637
            }
1638 1638
            else => {},
1639 1639
        }
1640 -
        self.scope = prevScope;
1641 -
        self.currentMod = prevMod;
1640 +
        set self.scope = prevScope;
1641 +
        set self.currentMod = prevMod;
1642 1642
    }
1643 1643
}
1644 1644
1645 1645
/// Check if all elements in a node list are assignable to the target type.
1646 1646
fn isListAssignable(self: *mut Resolver, targetType: Type, items: *mut [*ast::Node]) -> bool {
2012 2012
    if scope.symbolsLen >= scope.symbols.len {
2013 2013
        throw emitError(self, site, ErrorKind::SymbolOverflow);
2014 2014
    }
2015 2015
    // Propagate module ID to the symbol for fast lookup.
2016 2016
    if let modId = scope.moduleId {
2017 -
        sym.moduleId = modId;
2017 +
        set sym.moduleId = modId;
2018 2018
    }
2019 -
    scope.symbols[scope.symbolsLen] = sym;
2020 -
    scope.symbolsLen += 1;
2019 +
    set scope.symbols[scope.symbolsLen] = sym;
2020 +
    set scope.symbolsLen += 1;
2021 2021
}
2022 2022
2023 2023
/// Bind a value identifier in the current scope.
2024 2024
/// Returns `nil` if the identifier is a placeholder (`_`).
2025 2025
fn bindValueIdent(
2041 2041
    setNodeType(self, owner, type);
2042 2042
    setNodeType(self, ident, type);
2043 2043
2044 2044
    // Track number of local bindings for lowering stage.
2045 2045
    if let mut fnType = self.currentFn {
2046 -
        fnType.localCount += 1;
2046 +
        set fnType.localCount += 1;
2047 2047
    }
2048 2048
    return sym;
2049 2049
}
2050 2050
2051 2051
/// Bind a constant identifier in the current scope.
2137 2137
    loop {
2138 2138
        if let sym = findInScope(curr, name, predicate) {
2139 2139
            return sym;
2140 2140
        }
2141 2141
        if let parent = curr.parent {
2142 -
            curr = parent;
2142 +
            set curr = parent;
2143 2143
        } else {
2144 2144
            break;
2145 2145
        }
2146 2146
    }
2147 2147
    return nil;
2178 2178
    let mut out: *[*[u8]] = &[];
2179 2179
2180 2180
    match node.value {
2181 2181
        case ast::NodeValue::Ident(name) if name.len > 0 => {
2182 2182
            assert buf.len >= 1, "flattenPath: invalid output buffer size";
2183 -
            buf[0] = name;
2184 -
            out = &buf[..1];
2183 +
            set buf[0] = name;
2184 +
            set out = &buf[..1];
2185 2185
        }
2186 2186
        case ast::NodeValue::ScopeAccess(access) => {
2187 2187
            // Recursively flatten parent path.
2188 2188
            let parent = try flattenPath(self, access.parent, buf);
2189 2189
            assert parent.len < buf.len, "flattenPath: invalid output buffer size";
2190 2190
            let child = try nodeName(self, access.child);
2191 -
            buf[parent.len] = child;
2192 -
            out = &buf[..parent.len + 1];
2191 +
            set buf[parent.len] = child;
2192 +
            set out = &buf[..parent.len + 1];
2193 2193
        }
2194 2194
        case ast::NodeValue::Super => {
2195 2195
            // `super` is handled by scope adjustment in `checkSuperAccess`.
2196 2196
            // Return empty prefix so the path continues from the next segment.
2197 -
            out = &buf[..0];
2197 +
            set out = &buf[..0];
2198 2198
            return out;
2199 2199
        }
2200 2200
        else => {
2201 2201
            // Fallthrough to error.
2202 2202
        }
2214 2214
    loop {
2215 2215
        if let id = s.moduleId {
2216 2216
            return id;
2217 2217
        }
2218 2218
        if let parent = s.parent {
2219 -
            s = parent;
2219 +
            set s = parent;
2220 2220
        } else {
2221 2221
            return nil;
2222 2222
        }
2223 2223
    }
2224 2224
}
2289 2289
) -> *mut Symbol throws (ResolveError) {
2290 2290
    // Handle `super` access by adjusting scope and node.
2291 2291
    let mut startScope = scope;
2292 2292
    let mut pathNode = node;
2293 2293
    if let superAccess = try checkSuperAccess(self, node) {
2294 -
        startScope = superAccess.scope;
2295 -
        pathNode = superAccess.child;
2294 +
        set startScope = superAccess.scope;
2295 +
        set pathNode = superAccess.child;
2296 2296
    }
2297 2297
    // TODO: It doesn't make sense that `flattenPath` handles identifiers and scope access,
2298 2298
    // while this function requires a scope access.
2299 2299
    let mut buffer: [*[u8]; 32] = undefined;
2300 2300
    let path = try flattenPath(self, pathNode, &mut buffer[..]);
2363 2363
    let mut startScope = self.scope;
2364 2364
    let mut pathNode = module;
2365 2365
2366 2366
    // Handle `super` access.
2367 2367
    if let superAccess = try checkSuperAccess(self, module) {
2368 -
        startScope = superAccess.scope;
2369 -
        pathNode = superAccess.child;
2368 +
        set startScope = superAccess.scope;
2369 +
        set pathNode = superAccess.child;
2370 2370
    }
2371 2371
    let mut pathBuf: [*[u8]; 16] = undefined;
2372 2372
    let path = try flattenPath(self, pathNode, &mut pathBuf[..]);
2373 2373
    if path.len == 0 {
2374 2374
        throw emitError(self, module, ErrorKind::UnresolvedSymbol(""));
2589 2589
            return setNodeType(self, node, loopType);
2590 2590
        },
2591 2591
        case ast::NodeValue::Break => {
2592 2592
            try ensureInsideLoop(self, node);
2593 2593
            // Mark that the current loop has a reachable break.
2594 -
            self.loopStack[self.loopDepth - 1].hasBreak = true;
2594 +
            set self.loopStack[self.loopDepth - 1].hasBreak = true;
2595 2595
2596 2596
            return setNodeType(self, node, Type::Never);
2597 2597
        },
2598 2598
        case ast::NodeValue::Continue => {
2599 2599
            try ensureInsideLoop(self, node);
2702 2702
    throws (ResolveError)
2703 2703
{
2704 2704
    let mut diverges = false;
2705 2705
    for item in list {
2706 2706
        if try infer(self, item) == Type::Never {
2707 -
            diverges = true;
2707 +
            set diverges = true;
2708 2708
        }
2709 2709
    }
2710 2710
    if diverges {
2711 2711
        return Type::Never;
2712 2712
    }
2720 2720
    let mut mask: u32 = 0;
2721 2721
2722 2722
    for node in attrNodes {
2723 2723
        let case ast::NodeValue::Attribute(attr) = node.value
2724 2724
            else panic "resolveAttributes: invalid attribute node";
2725 -
        mask |= (attr as u32);
2725 +
        set mask |= (attr as u32);
2726 2726
    }
2727 2727
    return mask;
2728 2728
}
2729 2729
2730 2730
/// Ensure the `default` attribute is only applied to functions.
2762 2762
    let mut bindingTy = Type::Unknown;
2763 2763
2764 2764
    // Check type.
2765 2765
    if let declTy = try visitOptional(self, decl.type, Type::Unknown) {
2766 2766
        let _coercion = try checkAssignable(self, decl.value, declTy);
2767 -
        bindingTy = declTy;
2767 +
        set bindingTy = declTy;
2768 2768
    } else {
2769 -
        bindingTy = try infer(self, decl.value);
2769 +
        set bindingTy = try infer(self, decl.value);
2770 2770
2771 2771
        if not isTypeInferrable(bindingTy) {
2772 2772
            throw emitError(self, decl.value, ErrorKind::CannotInferType);
2773 2773
        }
2774 2774
    }
2782 2782
    }
2783 2783
    // Check alignment.
2784 2784
    if let a = decl.alignment {
2785 2785
        let case ast::NodeValue::Align { value } = a.value
2786 2786
            else panic "resolveLet: expected Align node";
2787 -
        alignment = try checkSizeInt(self, value);
2787 +
        set alignment = try checkSizeInt(self, value);
2788 2788
    }
2789 2789
    assert bindingTy <> Type::Unknown;
2790 2790
2791 2791
    // Alignment must be zero or a power of two.
2792 2792
    if alignment <> 0 and (alignment & (alignment - 1)) <> 0 {
3013 3013
    throws (ResolveError)
3014 3014
{
3015 3015
    let attrMask = resolveAttributes(self, decl.attrs);
3016 3016
    let mut retTy = Type::Void;
3017 3017
    if let retNode = decl.sig.returnType {
3018 -
        retTy = try infer(self, retNode);
3018 +
        set retTy = try infer(self, retNode);
3019 3019
    }
3020 3020
    let a = alloc::arenaAllocator(&mut self.arena);
3021 3021
    let mut paramTypes: *mut [*Type] = &mut [];
3022 3022
    let mut throwList: *mut [*Type] = &mut [];
3023 3023
    let mut fnType = FnType {
3057 3057
            throw e;
3058 3058
        };
3059 3059
        throwList.append(allocType(self, throwTy), a);
3060 3060
    }
3061 3061
    exitFn(self);
3062 -
    fnType.paramTypes = &paramTypes[..];
3063 -
    fnType.throwList = &throwList[..];
3062 +
    set fnType.paramTypes = &paramTypes[..];
3063 +
    set fnType.throwList = &throwList[..];
3064 3064
3065 3065
    // Bind the function name.
3066 3066
    let ty = Type::Fn(allocFnType(self, fnType));
3067 3067
    let sym = try bindValueIdent(self, decl.name, node, ty, false, 0, attrMask)
3068 3068
        else throw emitError(self, node, ErrorKind::ExpectedIdentifier);
3144 3144
        // Get field name for labeled records.
3145 3145
        let mut fieldName: ?*[u8] = nil;
3146 3146
        if labeled {
3147 3147
            let n = fieldNode
3148 3148
                else panic "resolveRecordFields: labeled record field missing name";
3149 -
            fieldName = try nodeName(self, n);
3149 +
            set fieldName = try nodeName(self, n);
3150 3150
        }
3151 3151
        let fieldType = typeFor(self, typeNode)
3152 3152
            else throw emitError(self, typeNode, ErrorKind::CannotInferType);
3153 3153
3154 3154
        // Ensure field type is fully resolved before computing layout.
3155 3155
        try ensureTypeResolved(self, fieldType, typeNode);
3156 3156
3157 3157
        // Compute field offset by aligning to field's alignment.
3158 3158
        let fieldLayout = getTypeLayout(fieldType);
3159 -
        currentOffset = mem::alignUp(currentOffset, fieldLayout.alignment);
3159 +
        set currentOffset = mem::alignUp(currentOffset, fieldLayout.alignment);
3160 3160
3161 3161
        result.append(RecordField { name: fieldName, fieldType, offset: currentOffset as i32 }, a);
3162 3162
3163 3163
        // Advance offset past this field.
3164 -
        currentOffset += fieldLayout.size;
3164 +
        set currentOffset += fieldLayout.size;
3165 3165
3166 3166
        // Track max alignment for record layout.
3167 -
        maxAlignment = max(maxAlignment, fieldLayout.alignment);
3167 +
        set maxAlignment = max(maxAlignment, fieldLayout.alignment);
3168 3168
    }
3169 3169
    // Compute cached layout.
3170 3170
    let recordLayout = Layout {
3171 3171
        size: mem::alignUp(currentOffset, maxAlignment),
3172 3172
        alignment: maxAlignment
3190 3190
        return;
3191 3191
    }
3192 3192
    try visitList(self, decl.derives);
3193 3193
    let recordType = try resolveRecordFields(self, node, decl.fields, decl.labeled);
3194 3194
3195 -
    *nominalTy = NominalType::Record(recordType);
3195 +
    set *nominalTy = NominalType::Record(recordType);
3196 3196
}
3197 3197
3198 3198
/// Bind a type name.
3199 3199
fn bindTypeName(self: *mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol
3200 3200
    throws (ResolveError)
3211 3211
3212 3212
/// Allocate a trait type descriptor and return a pointer to it.
3213 3213
fn allocTraitType(self: *mut Resolver, name: *[u8]) -> *mut TraitType {
3214 3214
    let p = try! alloc::alloc(&mut self.arena, @sizeOf(TraitType), @alignOf(TraitType));
3215 3215
    let entry = p as *mut TraitType;
3216 -
    *entry = TraitType { name, methods: &mut [], supertraits: &mut [] };
3216 +
    set *entry = TraitType { name, methods: &mut [], supertraits: &mut [] };
3217 3217
3218 3218
    return entry;
3219 3219
}
3220 3220
3221 3221
/// Bind a trait name in the current scope.
3331 3331
        for paramNode in sig.params {
3332 3332
            let paramTy = try infer(self, paramNode);
3333 3333
            paramTypes.append(allocType(self, paramTy), a);
3334 3334
        }
3335 3335
        if let ret = sig.returnType {
3336 -
            retType = allocType(self, try infer(self, ret));
3336 +
            set retType = allocType(self, try infer(self, ret));
3337 3337
        }
3338 3338
        // Resolve throws list.
3339 3339
        if sig.throwList.len > MAX_FN_THROWS {
3340 3340
            throw emitError(self, methodNode, ErrorKind::FnThrowOverflow(CountMismatch {
3341 3341
                expected: MAX_FN_THROWS,
3494 3494
                });
3495 3495
            }
3496 3496
        }
3497 3497
        let mut instanceRetTy = Type::Void;
3498 3498
        if let retNode = sig.returnType {
3499 -
            instanceRetTy = try resolveValueType(self, retNode);
3499 +
            set instanceRetTy = try resolveValueType(self, retNode);
3500 3500
        }
3501 3501
        if not typesEqual(instanceRetTy, *tm.fnType.returnType) {
3502 3502
            throw emitTypeMismatch(self, methodNode, TypeMismatch {
3503 3503
                expected: *tm.fnType.returnType,
3504 3504
                actual: instanceRetTy,
3548 3548
        setNodeSymbol(self, methodNode, sym);
3549 3549
        setNodeType(self, methodNode, fnTy);
3550 3550
        setNodeType(self, name, fnTy);
3551 3551
3552 3552
        // Store in instance entry at the matching v-table slot.
3553 -
        entry.methods[tm.index] = sym;
3554 -
        covered[tm.index] = true;
3553 +
        set entry.methods[tm.index] = sym;
3554 +
        set covered[tm.index] = true;
3555 3555
    }
3556 3556
3557 3557
    // Fill inherited method slots from supertrait instances.
3558 3558
    for superTrait in traitInfo.supertraits {
3559 3559
        let superInst = findInstance(self, superTrait, concreteType)
3560 3560
            else throw emitError(self, node, ErrorKind::MissingSupertraitInstance(superTrait.name));
3561 3561
        for superMethod, mi in superTrait.methods {
3562 3562
            let merged = findTraitMethod(traitInfo, superMethod.name)
3563 3563
                else panic "resolveInstanceDecl: inherited method not found";
3564 3564
            if not covered[merged.index] {
3565 -
                entry.methods[merged.index] = superInst.methods[mi];
3566 -
                covered[merged.index] = true;
3565 +
                set entry.methods[merged.index] = superInst.methods[mi];
3566 +
                set covered[merged.index] = true;
3567 3567
            }
3568 3568
        }
3569 3569
    }
3570 3570
3571 3571
    // Check that all trait methods are implemented.
3572 3572
    for method, i in traitInfo.methods {
3573 3573
        if not covered[i] {
3574 3574
            throw emitError(self, node, ErrorKind::MissingTraitMethod(method.name));
3575 3575
        }
3576 3576
    }
3577 -
    self.instances[self.instancesLen] = entry;
3578 -
    self.instancesLen += 1;
3577 +
    set self.instances[self.instancesLen] = entry;
3578 +
    set self.instancesLen += 1;
3579 3579
3580 3580
    setNodeType(self, node, Type::Void);
3581 3581
}
3582 3582
3583 3583
/// Resolve instance method bodies.
3703 3703
    }
3704 3704
3705 3705
    // Resolve return type.
3706 3706
    let mut returnType = Type::Void;
3707 3707
    if let retNode = sig.returnType {
3708 -
        returnType = try resolveValueType(self, retNode);
3708 +
        set returnType = try resolveValueType(self, retNode);
3709 3709
    }
3710 3710
3711 3711
    // Resolve throw list.
3712 3712
    let mut throwTypes: *mut [*Type] = &mut [];
3713 3713
    for throwNode in sig.throwList {
3732 3732
    // Compute attribute mask.
3733 3733
    let mut attrMask: u32 = 0;
3734 3734
    if let a = attrs {
3735 3735
        for attrNode in a.list {
3736 3736
            if let case ast::NodeValue::Attribute(attr) = attrNode.value {
3737 -
                attrMask = attrMask | (attr as u32);
3737 +
                set attrMask = attrMask | (attr as u32);
3738 3738
            }
3739 3739
        }
3740 3740
    }
3741 3741
3742 3742
    // Create a symbol for the method without binding it into the module scope.
3750 3750
3751 3751
    // Register in the method table.
3752 3752
    if self.methodsLen >= MAX_METHODS {
3753 3753
        throw emitError(self, node, ErrorKind::Internal);
3754 3754
    }
3755 -
    self.methods[self.methodsLen] = MethodEntry {
3755 +
    set self.methods[self.methodsLen] = MethodEntry {
3756 3756
        concreteType,
3757 3757
        concreteTypeName: typeName,
3758 3758
        name: methodName,
3759 3759
        fnType: allocFnType(self, checkFnType),
3760 3760
        mutable: receiverMut,
3761 3761
        symbol: sym,
3762 3762
    };
3763 -
    self.methodsLen += 1;
3763 +
    set self.methodsLen += 1;
3764 3764
}
3765 3765
3766 3766
/// Look up an instance entry by trait and concrete type.
3767 3767
fn findInstance(self: *Resolver, traitInfo: *TraitType, concreteType: Type) -> ?*InstanceEntry {
3768 3768
    for i in 0..self.instancesLen {
3816 3816
    let mut variants: *mut [UnionVariant] = &mut [];
3817 3817
3818 3818
    // Create a temporary nominal type to replace the placeholder.This prevents infinite recursion
3819 3819
    // when a variant references this union type (e.g. record payloads with `*[Self]`).
3820 3820
    // TODO: It would be best to have a resolving state eg. `Visiting` for this situation.
3821 -
    *nominalTy = NominalType::Union(UnionType {
3821 +
    set *nominalTy = NominalType::Union(UnionType {
3822 3822
        variants: &[],
3823 3823
        layout: Layout { size: 0, alignment: 0 },
3824 3824
        valOffset: 0,
3825 3825
        isAllVoid: true
3826 3826
    });
3834 3834
            else panic "resolveUnionBody: invalid union variant";
3835 3835
        let variantName = try nodeName(self, variantDecl.name);
3836 3836
        // Resolve the variant's payload type if present.
3837 3837
        let mut variantType = Type::Void;
3838 3838
        if let ty = try visitOptional(self, variantDecl.type, Type::Unknown) {
3839 -
            variantType = ty;
3839 +
            set variantType = ty;
3840 3840
        }
3841 3841
        // Process the variant's explicit discriminant value if present.
3842 3842
        try visitOptional(self, variantDecl.value, variantType);
3843 3843
        let tag = variantTag(variantDecl, &mut iota);
3844 3844
        // Create a symbol for this variant.
3852 3852
        }, a);
3853 3853
    }
3854 3854
    let info = computeUnionLayout(&variants[..]);
3855 3855
3856 3856
    // Update the nominal type with the resolved variants.
3857 -
    *nominalTy = NominalType::Union(UnionType {
3857 +
    set *nominalTy = NominalType::Union(UnionType {
3858 3858
        variants: &variants[..],
3859 3859
        layout: info.layout,
3860 3860
        valOffset: info.valOffset,
3861 3861
        isAllVoid: info.isAllVoid,
3862 3862
    });
4121 4121
    let iterableTy = try infer(self, forStmt.iterable);
4122 4122
4123 4123
    // Extract binding names for the lowerer.
4124 4124
    let mut bindingName: ?*[u8] = nil;
4125 4125
    if let case ast::NodeValue::Ident(name) = forStmt.binding.value {
4126 -
        bindingName = name;
4126 +
        set bindingName = name;
4127 4127
    }
4128 4128
    let mut indexName: ?*[u8] = nil;
4129 4129
    if let idx = forStmt.index {
4130 4130
        if let case ast::NodeValue::Ident(name) = idx.value {
4131 -
            indexName = name;
4131 +
            set indexName = name;
4132 4132
        }
4133 4133
    }
4134 4134
    // Extract item type and store pre-computed loop metadata for the lowerer.
4135 4135
    let mut itemTy: Type = undefined;
4136 4136
    match iterableTy {
4141 4141
                throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable);
4142 4142
            };
4143 4143
            let case ast::NodeValue::Range(range) = forStmt.iterable.value else {
4144 4144
                throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable);
4145 4145
            };
4146 -
            itemTy = *valType;
4146 +
            set itemTy = *valType;
4147 4147
4148 4148
            setForLoopInfo(self, node, ForLoopInfo::Range {
4149 4149
                valType, range, bindingName, indexName
4150 4150
            });
4151 4151
        }
4152 4152
        case Type::Array(arrayInfo) => {
4153 -
            itemTy = *arrayInfo.item;
4153 +
            set itemTy = *arrayInfo.item;
4154 4154
            setForLoopInfo(self, node, ForLoopInfo::Collection {
4155 4155
                elemType: arrayInfo.item,
4156 4156
                length: arrayInfo.length,
4157 4157
                bindingName,
4158 4158
                indexName,
4159 4159
            });
4160 4160
        }
4161 4161
        case Type::Slice { item, .. } => {
4162 -
            itemTy = *item;
4162 +
            set itemTy = *item;
4163 4163
            setForLoopInfo(self, node, ForLoopInfo::Collection {
4164 4164
                elemType: item, length: nil, bindingName, indexName
4165 4165
            });
4166 4166
        }
4167 4167
        else => throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable),
4173 4173
        try bindForLoopPattern(self, pat, Type::U32, false);
4174 4174
    }
4175 4175
    // The lowerer always creates at least one internal variable for iteration,
4176 4176
    // even when the binding is a placeholder or no explicit index is given.
4177 4177
    if let mut fnType = self.currentFn {
4178 -
        fnType.localCount += 1;
4178 +
        set fnType.localCount += 1;
4179 4179
    }
4180 4180
    try visitLoop(self, forStmt.body);
4181 4181
    exitScope(self);
4182 4182
4183 4183
    try visitOptional(self, forStmt.elseBranch, Type::Void);
4325 4325
) -> Type throws (ResolveError) {
4326 4326
    // Whether this prong is catch-all.
4327 4327
    let mut isCatchAll = false;
4328 4328
4329 4329
    if prong.guard <> nil {
4330 -
        state.isConst = false;
4330 +
        set state.isConst = false;
4331 4331
    } else {
4332 4332
        match prong.arm {
4333 4333
            case ast::ProngArm::Binding(_),
4334 -
                 ast::ProngArm::Else => isCatchAll = true,
4335 -
            case ast::ProngArm::Case(patterns) => isCatchAll = hasWildcardPattern(patterns),
4334 +
                 ast::ProngArm::Else => set isCatchAll = true,
4335 +
            case ast::ProngArm::Case(patterns) => set isCatchAll = hasWildcardPattern(patterns),
4336 4336
        }
4337 4337
    }
4338 4338
    if isCatchAll {
4339 4339
        if state.catchAll {
4340 4340
            throw emitError(self, prongNode, ErrorKind::DuplicateCatchAll);
4341 4341
        }
4342 -
        state.catchAll = true;
4342 +
        set state.catchAll = true;
4343 4343
    }
4344 4344
    setProngCatchAll(self, prongNode, isCatchAll);
4345 4345
4346 4346
    return try visitMatchProng(self, prongNode, prong, subjectTy, matchType, matchBy);
4347 4347
}
4394 4394
        // Only `else` without a guard is a true catch-all.
4395 4395
        if prong.arm == ast::ProngArm::Else and prong.guard == nil {
4396 4396
            if catchAll {
4397 4397
                throw emitError(self, prongNode, ErrorKind::DuplicateCatchAll);
4398 4398
            }
4399 -
            catchAll = true;
4399 +
            set catchAll = true;
4400 4400
        }
4401 4401
4402 4402
        let mut isCatchAll = false;
4403 4403
        if prong.guard == nil {
4404 4404
            match prong.arm {
4405 -
                case ast::ProngArm::Else => isCatchAll = true,
4406 -
                case ast::ProngArm::Case(patterns) => isCatchAll = hasWildcardPattern(patterns),
4405 +
                case ast::ProngArm::Else => set isCatchAll = true,
4406 +
                case ast::ProngArm::Case(patterns) => set isCatchAll = hasWildcardPattern(patterns),
4407 4407
                case ast::ProngArm::Binding(_) => {
4408 4408
                    // For optionals, a binding does *not* always match.
4409 4409
                }
4410 4410
            }
4411 4411
        }
4412 4412
        setProngCatchAll(self, prongNode, isCatchAll);
4413 -
        matchType = try visitMatchProng(self, prongNode, prong, subjectTy, matchType, MatchBy::Value);
4413 +
        set matchType = try visitMatchProng(self, prongNode, prong, subjectTy, matchType, MatchBy::Value);
4414 4414
4415 4415
        // Track coverage. Guarded prongs don't count as covering a case.
4416 4416
        if prong.guard == nil {
4417 4417
            if let case ast::ProngArm::Binding(_) = prong.arm {
4418 4418
                if hasValue {
4419 4419
                    throw emitError(self, prongNode, ErrorKind::DuplicateMatchPattern);
4420 4420
                }
4421 -
                hasValue = true;
4421 +
                set hasValue = true;
4422 4422
            } else if let case ast::ProngArm::Case(patterns) = prong.arm {
4423 4423
                for pat in patterns {
4424 4424
                    if let case ast::NodeValue::Nil = pat.value {
4425 4425
                        if hasNil {
4426 4426
                            throw emitError(self, pat, ErrorKind::DuplicateMatchPattern);
4427 4427
                        }
4428 -
                        hasNil = true;
4428 +
                        set hasNil = true;
4429 4429
                    }
4430 4430
                }
4431 4431
            }
4432 4432
        }
4433 4433
    }
4463 4463
4464 4464
    for prongNode in prongs {
4465 4465
        let case ast::NodeValue::MatchProng(prong) = prongNode.value
4466 4466
            else panic "resolveMatchUnion: expected match prong";
4467 4467
4468 -
        matchType = try resolveMatchProng(self, prongNode, prong, subjectTy, &mut state, matchType, matchBy);
4468 +
        set matchType = try resolveMatchProng(self, prongNode, prong, subjectTy, &mut state, matchType, matchBy);
4469 4469
4470 4470
        // Guarded prongs don't count as covering. Patterns with nested
4471 4471
        // refining sub-patterns (e.g. matching different inner union variants)
4472 4472
        // don't count as duplicates or as fully covering.
4473 4473
        if prong.guard == nil {
4476 4476
                    if let case NodeExtra::UnionVariant { ordinal: ix, .. } = self.nodeData.entries[pattern.id].extra {
4477 4477
                        if not hasNestedRefiningPattern(self, pattern) {
4478 4478
                            if covered[ix] {
4479 4479
                                throw emitError(self, pattern, ErrorKind::DuplicateMatchPattern);
4480 4480
                            }
4481 -
                            covered[ix] = true;
4482 -
                            coveredCount += 1;
4481 +
                            set covered[ix] = true;
4482 +
                            set coveredCount += 1;
4483 4483
                        }
4484 4484
                    }
4485 4485
                }
4486 4486
            }
4487 4487
        }
4515 4515
4516 4516
    for prongNode in prongs {
4517 4517
        let case ast::NodeValue::MatchProng(prong) = prongNode.value
4518 4518
            else panic "resolveMatchGeneric: expected match prong";
4519 4519
4520 -
        matchType = try resolveMatchProng(
4520 +
        set matchType = try resolveMatchProng(
4521 4521
            self, prongNode, prong, subjectTy, &mut state, matchType, MatchBy::Value
4522 4522
        );
4523 4523
        // Track boolean coverage. Guarded prongs don't count as covering.
4524 4524
        if let case ast::ProngArm::Case(patterns) = prong.arm {
4525 4525
            for p in patterns {
4527 4527
                    if let case ast::NodeValue::Bool(val) = p.value {
4528 4528
                        if (val and hasTrue) or (not val and hasFalse) {
4529 4529
                            throw emitError(self, p, ErrorKind::DuplicateMatchPattern);
4530 4530
                        }
4531 4531
                        if val {
4532 -
                            hasTrue = true;
4532 +
                            set hasTrue = true;
4533 4533
                        } else {
4534 -
                            hasFalse = true;
4534 +
                            set hasFalse = true;
4535 4535
                        }
4536 4536
                    }
4537 4537
                }
4538 4538
                // Scalar constant patterns allow the match to be lowered
4539 4539
                // to a switch instruction.
4540 4540
                if let c = constValueEntry(self, p) {
4541 4541
                    match c {
4542 4542
                        case ConstValue::Bool(_), ConstValue::Char(_), ConstValue::Int(_) =>
4543 -
                            hasConstCase = true,
4543 +
                            set hasConstCase = true,
4544 4544
                        else =>
4545 -
                            state.isConst = false,
4545 +
                            set state.isConst = false,
4546 4546
                    }
4547 4547
                }
4548 4548
            }
4549 4549
        }
4550 4550
    }
4601 4601
    match prong.arm {
4602 4602
        case ast::ProngArm::Binding(pat) => {
4603 4603
            // For optionals, bind the unwrapped inner type.
4604 4604
            let mut bindTy = subjectTy;
4605 4605
            if let case Type::Optional(inner) = subjectTy {
4606 -
                bindTy = *inner;
4606 +
                set bindTy = *inner;
4607 4607
            }
4608 4608
            try bindPatternVar(self, pat, bindTy, matchBy);
4609 4609
        }
4610 4610
        case ast::ProngArm::Case(patterns) => {
4611 4611
            for pattern in patterns {
4696 4696
    throws (ResolveError)
4697 4697
{
4698 4698
    let mut bindTy = ty;
4699 4699
    match matchBy {
4700 4700
        case MatchBy::Value => {}
4701 -
        case MatchBy::Ref => bindTy = Type::Pointer { target: allocType(self, ty), mutable: false },
4702 -
        case MatchBy::MutRef => bindTy = Type::Pointer { target: allocType(self, ty), mutable: true },
4701 +
        case MatchBy::Ref => set bindTy = Type::Pointer { target: allocType(self, ty), mutable: false },
4702 +
        case MatchBy::MutRef => set bindTy = Type::Pointer { target: allocType(self, ty), mutable: true },
4703 4703
    }
4704 4704
    match binding.value {
4705 4705
        case ast::NodeValue::Placeholder => {
4706 4706
            // Nothing to do.
4707 4707
        }
4896 4896
4897 4897
    // Evaluate the built-in.
4898 4898
    let mut value: u32 = undefined;
4899 4899
    match kind {
4900 4900
        case ast::Builtin::SizeOf => {
4901 -
            value = layout.size;
4901 +
            set value = layout.size;
4902 4902
        },
4903 4903
        case ast::Builtin::AlignOf => {
4904 -
            value = layout.alignment;
4904 +
            set value = layout.alignment;
4905 4905
        },
4906 4906
        case ast::Builtin::SliceOf => {
4907 4907
            panic "unreachable: @sliceOf handled above";
4908 4908
        }
4909 4909
    }
4984 4984
4985 4985
    // Check if we have a trait method call, ie. callee is a trait object.
4986 4986
    if let case ast::NodeValue::FieldAccess(access) = call.callee.value {
4987 4987
        let mut parentTy = Type::Unknown;
4988 4988
        if let t = typeFor(self, access.parent) {
4989 -
            parentTy = t;
4989 +
            set parentTy = t;
4990 4990
        }
4991 4991
        let subjectTy = autoDeref(parentTy);
4992 4992
4993 4993
        if let case Type::TraitObject { traitInfo, mutable: objMutable } = subjectTy {
4994 4994
            let methodName = try nodeName(self, access.child);
5013 5013
                // If the parent is already a mutable pointer, the receiver is fine.
5014 5014
                // Otherwise, check that the parent can yield a mutable borrow.
5015 5015
                if method.mutable {
5016 5016
                    let mut isMutPtr = false;
5017 5017
                    if let case Type::Pointer { mutable, .. } = parentTy {
5018 -
                        isMutPtr = mutable;
5018 +
                        set isMutPtr = mutable;
5019 5019
                    }
5020 5020
                    if not isMutPtr and not (try canBorrowMutFrom(self, access.parent)) {
5021 5021
                        throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
5022 5022
                    }
5023 5023
                }
5024 5024
                // Check arguments (excluding receiver).
5025 5025
                try checkCallArgs(self, node, call, method.fnType, ctx);
5026 -
                self.nodeData.entries[node.id].extra = NodeExtra::MethodCall { method };
5026 +
                set self.nodeData.entries[node.id].extra = NodeExtra::MethodCall { method };
5027 5027
5028 5028
                return setNodeType(self, node, *method.fnType.returnType);
5029 5029
            }
5030 5030
        }
5031 5031
    }
5065 5065
    // First argument must be assignable to the element type.
5066 5066
    try checkAssignable(self, args[0], *elemType);
5067 5067
    // Second argument: the allocator. We accept any type -- the lowerer
5068 5068
    // reads `.func` and `.ctx` at fixed offsets.
5069 5069
    try visit(self, args[1], Type::Unknown);
5070 -
    self.nodeData.entries[node.id].extra = NodeExtra::SliceAppend { elemType };
5070 +
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceAppend { elemType };
5071 5071
5072 5072
    // Return the parent's type so the caller can rebind:
5073 5073
    return setNodeType(self, node, parentType);
5074 5074
}
5075 5075
5090 5090
            expected: 1,
5091 5091
            actual: args.len as u32,
5092 5092
        }));
5093 5093
    }
5094 5094
    try checkAssignable(self, args[0], Type::U32);
5095 -
    self.nodeData.entries[node.id].extra = NodeExtra::SliceDelete { elemType };
5095 +
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceDelete { elemType };
5096 5096
5097 5097
    return setNodeType(self, node, Type::Void);
5098 5098
}
5099 5099
5100 5100
/// Analyze an assignment expression.
5116 5116
            let mut capacity: ?u32 = nil;
5117 5117
5118 5118
            match subjectTy {
5119 5119
                case Type::Array(a) => {
5120 5120
                    try validateArraySliceBounds(self, range, a.length, node);
5121 -
                    item = a.item;
5122 -
                    capacity = a.length;
5121 +
                    set item = a.item;
5122 +
                    set capacity = a.length;
5123 5123
                }
5124 5124
                case Type::Slice { item: i, mutable } => {
5125 5125
                    if not mutable { throw emitError(self, container, ErrorKind::ImmutableBinding); }
5126 -
                    item = i;
5126 +
                    set item = i;
5127 5127
                }
5128 5128
                else => throw emitError(self, container, ErrorKind::ExpectedIndexable),
5129 5129
            }
5130 5130
            // RHS is either a fill value or a source slice.
5131 5131
            let rhsTy = try infer(self, assign.right);
5168 5168
    let mut startVal: ?u32 = nil;
5169 5169
    let mut endVal: ?u32 = length;
5170 5170
5171 5171
    if let startNode = range.start {
5172 5172
        if let val = constSliceIndex(self, startNode) {
5173 -
            startVal = val;
5173 +
            set startVal = val;
5174 5174
        }
5175 5175
    }
5176 5176
    if let endNode = range.end {
5177 5177
        if let val = constSliceIndex(self, endNode) {
5178 -
            endVal = val;
5178 +
            set endVal = val;
5179 5179
        }
5180 5180
    }
5181 5181
    if let val = startVal; val >= length {
5182 5182
        throw emitError(self, site, ErrorKind::SliceRangeOutOfBounds);
5183 5183
    }
5410 5410
    throws (ResolveError)
5411 5411
{
5412 5412
    // Unwrap optional hint to get the inner record type.
5413 5413
    let mut innerHint = hint;
5414 5414
    if let case Type::Optional(inner) = hint {
5415 -
        innerHint = *inner;
5415 +
        set innerHint = *inner;
5416 5416
    }
5417 5417
    let mut hintInfo: ?RecordType = nil;
5418 5418
    if let case Type::Nominal(info) = innerHint {
5419 5419
        try ensureNominalResolved(self, info, node);
5420 5420
        if let case NominalType::Record(s) = *info {
5421 -
            hintInfo = s;
5421 +
            set hintInfo = s;
5422 5422
        }
5423 5423
    }
5424 5424
    let targetInfo = hintInfo else {
5425 5425
        throw emitError(self, node, ErrorKind::CannotInferType);
5426 5426
    };
5469 5469
{
5470 5470
    let length = items.len;
5471 5471
    let mut expectedTy: Type = Type::Unknown;
5472 5472
5473 5473
    if let case Type::Array(ary) = hint {
5474 -
        expectedTy = *ary.item;
5474 +
        set expectedTy = *ary.item;
5475 5475
    } else if let case Type::Optional(inner) = hint {
5476 5476
        if let case Type::Array(ary) = *inner {
5477 -
            expectedTy = *ary.item;
5477 +
            set expectedTy = *ary.item;
5478 5478
        }
5479 5479
    };
5480 5480
    for itemNode in items {
5481 5481
        let itemTy = try visit(self, itemNode, expectedTy);
5482 5482
        assert itemTy <> Type::Unknown;
5483 5483
5484 5484
        // Set the expected type to the first type we encounter.
5485 5485
        if expectedTy == Type::Unknown {
5486 -
            expectedTy = itemTy;
5486 +
            set expectedTy = itemTy;
5487 5487
        } else {
5488 5488
            try expectAssignable(self, expectedTy, itemTy, itemNode);
5489 5489
        }
5490 5490
    }
5491 5491
    if expectedTy == Type::Unknown {
5499 5499
fn resolveArrayRepeat(self: *mut Resolver, node: *ast::Node, lit: ast::ArrayRepeatLit, hint: Type) -> Type
5500 5500
    throws (ResolveError)
5501 5501
{
5502 5502
    let mut itemHint = hint;
5503 5503
    if let case Type::Array(ary) = hint {
5504 -
        itemHint = *ary.item;
5504 +
        set itemHint = *ary.item;
5505 5505
    } else if let case Type::Optional(inner) = hint {
5506 5506
        if let case Type::Array(ary) = *inner {
5507 -
            itemHint = *ary.item;
5507 +
            set itemHint = *ary.item;
5508 5508
        }
5509 5509
    }
5510 5510
    let valueTy = try visit(self, lit.item, itemHint);
5511 5511
    let count = try checkSizeInt(self, lit.count);
5512 5512
    let arrayTy = Type::Array(ArrayType {
5552 5552
    let mut ty: Type = undefined;
5553 5553
5554 5554
    match sym.data {
5555 5555
        case SymbolData::Value { type, .. } => {
5556 5556
            setNodeSymbol(self, node, sym);
5557 -
            ty = type;
5557 +
            set ty = type;
5558 5558
        }
5559 5559
        case SymbolData::Constant { type, value } => {
5560 5560
            // Propagate the constant value.
5561 5561
            if let val = value {
5562 5562
                setNodeConstValue(self, node, val);
5563 5563
            }
5564 5564
            setNodeSymbol(self, node, sym);
5565 -
            ty = type;
5565 +
            set ty = type;
5566 5566
        }
5567 5567
        case SymbolData::Type(t) => {
5568 5568
            setNodeSymbol(self, node, sym);
5569 -
            ty = Type::Nominal(t);
5569 +
            set ty = Type::Nominal(t);
5570 5570
        }
5571 5571
        case SymbolData::Variant { index, .. } => {
5572 5572
            let ty = typeFor(self, node)
5573 5573
                else throw emitError(self, node, ErrorKind::Internal);
5574 5574
            // For unions without payload, store the variant index as a constant.
5781 5781
            let mut capacity: ?u32 = nil;
5782 5782
5783 5783
            match subjectTy {
5784 5784
                case Type::Array(arrayInfo) => {
5785 5785
                    try validateArraySliceBounds(self, range, arrayInfo.length, node);
5786 -
                    item = arrayInfo.item;
5787 -
                    capacity = arrayInfo.length;
5786 +
                    set item = arrayInfo.item;
5787 +
                    set capacity = arrayInfo.length;
5788 5788
                }
5789 5789
                case Type::Slice { item: sliceItem, mutable } => {
5790 5790
                    if addr.mutable and not mutable {
5791 5791
                        throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
5792 5792
                    }
5793 -
                    item = sliceItem;
5793 +
                    set item = sliceItem;
5794 5794
                }
5795 5795
                else => {
5796 5796
                    throw emitError(self, container, ErrorKind::ExpectedIndexable);
5797 5797
                }
5798 5798
            }
5808 5808
        }
5809 5809
    }
5810 5810
    // Derive a hint for the target type from the slice hint.
5811 5811
    let mut targetHint: Type = Type::Unknown;
5812 5812
    if let case Type::Slice { item, .. } = hint {
5813 -
        targetHint = Type::Array(ArrayType { item, length: 0 });
5813 +
        set targetHint = Type::Array(ArrayType { item, length: 0 });
5814 5814
    }
5815 5815
    let targetTy = try visit(self, addr.target, targetHint);
5816 5816
5817 5817
    // Mark local variable symbols as address-taken so the lowerer
5818 5818
    // allocates a stack slot eagerly.
5819 5819
    if let case ast::NodeValue::Ident(name) = addr.target.value {
5820 5820
        if let sym = findValueSymbol(self.scope, name) {
5821 5821
            match &mut sym.data {
5822 5822
                case SymbolData::Value { addressTaken, .. } => {
5823 -
                    *addressTaken = true;
5823 +
                    set *addressTaken = true;
5824 5824
                }
5825 5825
                else => {}
5826 5826
            }
5827 5827
        }
5828 5828
    }
5981 5981
            let mut resolvedTy = startTy;
5982 5982
5983 5983
            // Infer unsuffixed integer literals from the opposite bound.
5984 5984
            if startTy == Type::Int and endTy <> Type::Int {
5985 5985
                let _ = try checkAssignable(self, s, endTy);
5986 -
                resolvedTy = endTy;
5986 +
                set resolvedTy = endTy;
5987 5987
            } else if endTy == Type::Int and startTy <> Type::Int {
5988 5988
                let _ = try checkAssignable(self, e, startTy);
5989 -
                resolvedTy = startTy;
5989 +
                set resolvedTy = startTy;
5990 5990
            } else {
5991 5991
                let _ = try checkAssignable(self, e, startTy);
5992 5992
            }
5993 -
            start = allocType(self, resolvedTy);
5994 -
            end = allocType(self, resolvedTy);
5993 +
            set start = allocType(self, resolvedTy);
5994 +
            set end = allocType(self, resolvedTy);
5995 5995
        } else {
5996 -
            start = allocType(self, startTy);
5996 +
            set start = allocType(self, startTy);
5997 5997
        }
5998 5998
    } else if let e = range.end {
5999 -
        end = allocType(self, try checkNumeric(self, e));
5999 +
        set end = allocType(self, try checkNumeric(self, e));
6000 6000
    }
6001 6001
    return setNodeType(self, node, Type::Range { start, end });
6002 6002
}
6003 6003
6004 6004
/// Analyze a `try` expression and its handlers.
6028 6028
    if tryExpr.returnsOptional {
6029 6029
        // `try?` converts errors to `nil` and wraps the result in an optional.
6030 6030
        if let case Type::Optional(_) = resultTy {
6031 6031
            // Already optional, no wrapping needed.
6032 6032
        } else {
6033 -
            tryResultTy = Type::Optional(allocType(self, resultTy));
6033 +
            set tryResultTy = Type::Optional(allocType(self, resultTy));
6034 6034
        }
6035 6035
    } else if tryExpr.catches.len > 0 {
6036 6036
        // `try ... catch` -- one or more catch clauses.
6037 -
        tryResultTy = try resolveTryCatches(self, node, tryExpr.catches, calleeInfo, resultTy, hint);
6037 +
        set tryResultTy = try resolveTryCatches(self, node, tryExpr.catches, calleeInfo, resultTy, hint);
6038 6038
    } else if not tryExpr.shouldPanic {
6039 6039
        let fnInfo = self.currentFn
6040 6040
            else throw emitError(self, node, ErrorKind::TryRequiresThrows);
6041 6041
        if fnInfo.throwList.len == 0 {
6042 6042
            throw emitError(self, node, ErrorKind::TryRequiresThrows);
6046 6046
        for throwTy in calleeInfo.throwList {
6047 6047
            let mut found = false;
6048 6048
6049 6049
            for callerThrowTy in fnInfo.throwList {
6050 6050
                if callerThrowTy == throwTy {
6051 -
                    found = true;
6051 +
                    set found = true;
6052 6052
                    break;
6053 6053
                }
6054 6054
            }
6055 6055
            if not found {
6056 6056
                throw emitError(self, node, ErrorKind::TryIncompatibleError);
6136 6136
            let errTy = try infer(self, typeNode);
6137 6137
            let mut foundIdx: ?u32 = nil;
6138 6138
6139 6139
            for throwType, j in calleeInfo.throwList {
6140 6140
                if errTy == *throwType {
6141 -
                    foundIdx = j;
6141 +
                    set foundIdx = j;
6142 6142
                    break;
6143 6143
                }
6144 6144
            }
6145 6145
            let idx = foundIdx else {
6146 6146
                throw emitError(self, typeNode, ErrorKind::TryIncompatibleError);
6147 6147
            };
6148 6148
            if covered[idx] {
6149 6149
                throw emitError(self, typeNode, ErrorKind::TryCatchDuplicateType);
6150 6150
            }
6151 -
            covered[idx] = true;
6151 +
            set covered[idx] = true;
6152 6152
6153 6153
            // Bind the error variable if present.
6154 6154
            if let binding = clause.binding {
6155 6155
                enterScope(self, clauseNode);
6156 6156
                try bindValueIdent(self, binding, binding, errTy, false, 0, 0);
6157 6157
            }
6158 6158
        } else {
6159 6159
            // Catch-all clause with no type annotation or binding.
6160 -
            hasCatchAll = true;
6160 +
            set hasCatchAll = true;
6161 6161
        }
6162 6162
        // Resolve the catch body and check assignability.
6163 6163
        try visit(self, clause.body, resultTy);
6164 6164
        // Only typed clauses can have bindings.
6165 6165
        if let _ = clause.binding {
6250 6250
/// Returns the resulting constant value if successful.
6251 6251
fn foldIntBinOp(op: ast::BinaryOp, left: ConstInt, right: ConstInt) -> ?ConstValue {
6252 6252
    // Use the wider bit width and propagate signedness.
6253 6253
    let mut bits = left.bits;
6254 6254
    if right.bits > bits {
6255 -
        bits = right.bits;
6255 +
        set bits = right.bits;
6256 6256
    }
6257 6257
    let signed = left.signed or right.signed;
6258 6258
    let l = constIntToSigned(left);
6259 6259
    let r = constIntToSigned(right);
6260 6260
6343 6343
             ast::BinaryOp::Xor =>
6344 6344
        {
6345 6345
            try checkBoolean(self, binop.left);
6346 6346
            try checkBoolean(self, binop.right);
6347 6347
6348 -
            resultTy = Type::Bool;
6348 +
            set resultTy = Type::Bool;
6349 6349
        },
6350 6350
        case ast::BinaryOp::Eq,
6351 6351
             ast::BinaryOp::Ne =>
6352 6352
        {
6353 6353
            let leftTy = try infer(self, binop.left);
6371 6371
                    setNodeCoercion(self, binop.right, Coercion::OptionalLift(leftTy));
6372 6372
                }
6373 6373
            } else if let case Type::Optional(_) = rightTy {
6374 6374
                setNodeCoercion(self, binop.left, Coercion::OptionalLift(rightTy));
6375 6375
            }
6376 -
            resultTy = Type::Bool;
6376 +
            set resultTy = Type::Bool;
6377 6377
        },
6378 6378
        else => {
6379 6379
            // Check for pointer arithmetic before numeric check.
6380 6380
            if binop.op == ast::BinaryOp::Add or binop.op == ast::BinaryOp::Sub {
6381 6381
                let leftTy = try infer(self, binop.left);
6403 6403
6404 6404
            // Ordering comparisons return `bool`, not the operand type.
6405 6405
            match binop.op {
6406 6406
                case ast::BinaryOp::Lt, ast::BinaryOp::Gt,
6407 6407
                     ast::BinaryOp::Lte, ast::BinaryOp::Gte => {
6408 -
                    resultTy = Type::Bool;
6408 +
                    set resultTy = Type::Bool;
6409 6409
                } else => {
6410 6410
                    if leftTy == rightTy {
6411 -
                        resultTy = leftTy;
6411 +
                        set resultTy = leftTy;
6412 6412
                    } else if leftTy == Type::Int {
6413 -
                        resultTy = rightTy;
6413 +
                        set resultTy = rightTy;
6414 6414
                    } else if rightTy == Type::Int {
6415 -
                        resultTy = leftTy;
6415 +
                        set resultTy = leftTy;
6416 6416
                    } else {
6417 6417
                        throw emitTypeMismatch(self, binop.right, TypeMismatch {
6418 6418
                            expected: leftTy,
6419 6419
                            actual: rightTy,
6420 6420
                        });
6436 6436
{
6437 6437
    let mut resultTy = Type::Unknown;
6438 6438
6439 6439
    match unop.op {
6440 6440
        case ast::UnaryOp::Not => {
6441 -
            resultTy = try checkBoolean(self, unop.value);
6441 +
            set resultTy = try checkBoolean(self, unop.value);
6442 6442
            if let value = constValueEntry(self, unop.value) {
6443 6443
                if let case ConstValue::Bool(val) = value {
6444 6444
                    setNodeConstValue(self, node, ConstValue::Bool(not val));
6445 6445
                }
6446 6446
            }
6447 6447
        },
6448 6448
        case ast::UnaryOp::Neg => {
6449 6449
            // TODO: Check that we're allowed to use `-` here? Should negation
6450 6450
            // only be valid for signed integers?
6451 -
            resultTy = try checkNumeric(self, unop.value);
6451 +
            set resultTy = try checkNumeric(self, unop.value);
6452 6452
            if let value = constValueEntry(self, unop.value) {
6453 6453
                // Get the constant expression for the value, flip the sign,
6454 6454
                // and store that new expression on the unary op node.
6455 6455
                if let case ConstValue::Int(intVal) = value {
6456 6456
                    setNodeConstValue(
6460 6460
                    );
6461 6461
                }
6462 6462
            }
6463 6463
        },
6464 6464
        case ast::UnaryOp::BitNot => {
6465 -
            resultTy = try checkNumeric(self, unop.value);
6465 +
            set resultTy = try checkNumeric(self, unop.value);
6466 6466
            if let value = constValueEntry(self, unop.value) {
6467 6467
                if let case ConstValue::Int(intVal) = value {
6468 6468
                    let signed = constIntToSigned(intVal);
6469 6469
                    let inverted = constIntFromSigned(-(signed + 1), intVal.bits, intVal.signed);
6470 6470
                    setNodeConstValue(self, node, ConstValue::Int(inverted));
6569 6569
                let throwTy = try infer(self, tyNode);
6570 6570
                throwList.append(allocType(self, throwTy), a);
6571 6571
            }
6572 6572
            let mut retType = allocType(self, Type::Void);
6573 6573
            if let ret = t.returnType {
6574 -
                retType = allocType(self, try infer(self, ret));
6574 +
                set retType = allocType(self, try infer(self, ret));
6575 6575
            }
6576 6576
            let fnType = FnType {
6577 6577
                paramTypes: &paramTypes[..],
6578 6578
                returnType: retType,
6579 6579
                throwList: &throwList[..],
6775 6775
    }
6776 6776
}
6777 6777
6778 6778
/// Resolve all packages.
6779 6779
export fn resolve(self: *mut Resolver, graph: *module::ModuleGraph, packages: *[Pkg]) -> Diagnostics throws (ResolveError) {
6780 -
    self.moduleGraph = graph;
6780 +
    set self.moduleGraph = graph;
6781 6781
6782 6782
    // 1. Bind all package roots to enable cross-package references.
6783 6783
    for i in 0..packages.len {
6784 6784
        let pkg = &packages[i];
6785 6785
        // Enter a new scope for the module.
6805 6805
    let rootId = rootEntry.id;
6806 6806
    let scope = self.moduleScopes[rootId as u32]
6807 6807
        else panic "resolvePackage: module scope not found";
6808 6808
6809 6809
    // Set up the module scope for this package.
6810 -
    self.scope = scope;
6811 -
    self.currentMod = rootId;
6810 +
    set self.scope = scope;
6811 +
    set self.currentMod = rootId;
6812 6812
6813 6813
    let case ast::NodeValue::Block(block) = node.value
6814 6814
        else panic "resolvePackage: expected block for module root";
6815 6815
6816 6816
    // Module graph analysis phase: bind all module name symbols and scopes.
lib/std/lang/resolver/tests.rad +41 -41
54 54
    for i in 0..LITERALS.len {
55 55
        strings::intern(&mut STRING_POOL, LITERALS[i]);
56 56
    }
57 57
    // TODO: Use local static for this.
58 58
    // Reset the module graph for each test.
59 -
    MODULE_ARENA = ast::nodeArena(&mut MODULE_ARENA_STORAGE[..]);
60 -
    MODULE_GRAPH = module::moduleGraph(&mut MODULE_ENTRIES[..], &mut STRING_POOL, &mut MODULE_ARENA);
59 +
    set MODULE_ARENA = ast::nodeArena(&mut MODULE_ARENA_STORAGE[..]);
60 +
    set MODULE_GRAPH = module::moduleGraph(&mut MODULE_ENTRIES[..], &mut STRING_POOL, &mut MODULE_ARENA);
61 61
    let config = super::Config { buildTest: true };
62 62
    let res = super::resolver(testStorage(), config);
63 63
64 64
    return res;
65 65
}
151 151
    arena: *mut ast::NodeArena
152 152
) -> u16 throws (testing::TestError) {
153 153
    let filePath = "<test>";
154 154
    let mut modId: u16 = undefined;
155 155
    if let parent = parentId {
156 -
        modId = try module::registerChild(graph, parent, name, filePath) catch {
156 +
        set modId = try module::registerChild(graph, parent, name, filePath) catch {
157 157
            throw testing::TestError::Failed;
158 158
        };
159 159
    } else {
160 -
        modId = try module::registerRootWithName(graph, 0, name, filePath) catch {
160 +
        set modId = try module::registerRootWithName(graph, 0, name, filePath) catch {
161 161
            throw testing::TestError::Failed;
162 162
        };
163 163
    }
164 164
    let root = try parser::parse(scanner::SourceLoc::String, code, arena, &mut STRING_POOL) catch {
165 165
        panic "registerModule: parsing failed";
1719 1719
}
1720 1720
1721 1721
@test fn testResolveAssign() throws (testing::TestError) {
1722 1722
    {
1723 1723
        let mut a = testResolver();
1724 -
        let result = try resolveProgramStr(&mut a, "let mut x: i32 = 0; x = 1;");
1724 +
        let result = try resolveProgramStr(&mut a, "let mut x: i32 = 0; set x = 1;");
1725 1725
        try expectNoErrors(&result);
1726 1726
    } {
1727 1727
        let mut a = testResolver();
1728 -
        let result = try resolveProgramStr(&mut a, "let x: i32 = 0; x = 1;");
1728 +
        let result = try resolveProgramStr(&mut a, "let x: i32 = 0; set x = 1;");
1729 1729
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1730 1730
    } {
1731 1731
        let mut a = testResolver();
1732 -
        let result = try resolveProgramStr(&mut a, "let mut x: bool = false; x = 1;");
1732 +
        let result = try resolveProgramStr(&mut a, "let mut x: bool = false; set x = 1;");
1733 1733
        let err = try expectError(&result);
1734 1734
        try expectTypeMismatch(err, super::Type::Bool, super::Type::Int);
1735 1735
    } {
1736 1736
        let mut a = testResolver();
1737 -
        let result = try resolveProgramStr(&mut a, "x = 1;");
1737 +
        let result = try resolveProgramStr(&mut a, "set x = 1;");
1738 1738
        try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x"));
1739 1739
    } {
1740 1740
        let mut a = testResolver();
1741 -
        let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; x = 1;");
1741 +
        let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; set x = 1;");
1742 1742
        try expectNoErrors(&result);
1743 1743
    } {
1744 1744
        let mut a = testResolver();
1745 -
        let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; x = nil;");
1745 +
        let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; set x = nil;");
1746 1746
        try expectNoErrors(&result);
1747 1747
    }
1748 1748
}
1749 1749
1750 1750
@test fn testResolveAssignSubscript() throws (testing::TestError) {
1751 1751
    {
1752 1752
        let mut a = testResolver();
1753 -
        let program = "let mut xs: [u8; 2] = [0, 1]; xs[0] = 9;";
1753 +
        let program = "let mut xs: [u8; 2] = [0, 1]; set xs[0] = 9;";
1754 1754
        let result = try resolveProgramStr(&mut a, program);
1755 1755
        try expectNoErrors(&result);
1756 1756
    }
1757 1757
    {
1758 1758
        let mut a = testResolver();
1759 -
        let program = "let mut xs: [u8; 2] = [0, 1]; let slice: *mut [u8] = &mut xs[..]; slice[0] = 1;";
1759 +
        let program = "let mut xs: [u8; 2] = [0, 1]; let slice: *mut [u8] = &mut xs[..]; set slice[0] = 1;";
1760 1760
        let result = try resolveProgramStr(&mut a, program);
1761 1761
        try expectNoErrors(&result);
1762 1762
    }
1763 1763
    {
1764 1764
        let mut a = testResolver();
1765 -
        let program = "let mut xs: [u8; 2] = [0, 1]; let mut slice: *[u8] = &xs[..]; slice[0] = 1;";
1765 +
        let program = "let mut xs: [u8; 2] = [0, 1]; let mut slice: *[u8] = &xs[..]; set slice[0] = 1;";
1766 1766
        let result = try resolveProgramStr(&mut a, program);
1767 1767
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1768 1768
    }
1769 1769
    {
1770 1770
        let mut a = testResolver();
1771 -
        let program = "let xs: [u8; 2] = [0, 1]; xs[0] = 9;";
1771 +
        let program = "let xs: [u8; 2] = [0, 1]; set xs[0] = 9;";
1772 1772
        let result = try resolveProgramStr(&mut a, program);
1773 1773
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1774 1774
    }
1775 1775
    {
1776 1776
        let mut a = testResolver();
1777 -
        let program = "let mut xs: [u8; 2] = [0, 1]; let slice: *[u8] = &xs[..]; slice[0] = 1;";
1777 +
        let program = "let mut xs: [u8; 2] = [0, 1]; let slice: *[u8] = &xs[..]; set slice[0] = 1;";
1778 1778
        let result = try resolveProgramStr(&mut a, program);
1779 1779
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
1780 1780
    }
1781 1781
}
1782 1782
2096 2096
        let mut a = testResolver();
2097 2097
        let result = try resolveBlockStr(&mut a, "let count: i32 = undefined;");
2098 2098
        try expectNoErrors(&result);
2099 2099
    } {
2100 2100
        let mut a = testResolver();
2101 -
        let program = "let mut value: i32 = 0; value = undefined;";
2101 +
        let program = "let mut value: i32 = 0; set value = undefined;";
2102 2102
        let result = try resolveProgramStr(&mut a, program);
2103 2103
        try expectNoErrors(&result);
2104 2104
    } {
2105 2105
        let mut a = testResolver();
2106 2106
        let program = "fn f(x: i32) {} fn g() { f(undefined); }";
2200 2200
}
2201 2201
2202 2202
/// Test that `if let mut` produces a mutable binding.
2203 2203
@test fn testResolveIfLetMut() throws (testing::TestError) {
2204 2204
    let mut a = testResolver();
2205 -
    let program = "let opt: ?i32 = 42; if let mut v = opt { v = v + 1; }";
2205 +
    let program = "let opt: ?i32 = 42; if let mut v = opt { set v = v + 1; }";
2206 2206
    let result = try resolveProgramStr(&mut a, program);
2207 2207
    try expectNoErrors(&result);
2208 2208
}
2209 2209
2210 2210
/// Test that `if let` (without mut) rejects assignment.
2211 2211
@test fn testResolveIfLetImmutable() throws (testing::TestError) {
2212 2212
    let mut a = testResolver();
2213 -
    let program = "let opt: ?i32 = 42; if let v = opt { v = 1; }";
2213 +
    let program = "let opt: ?i32 = 42; if let v = opt { set v = 1; }";
2214 2214
    let result = try resolveProgramStr(&mut a, program);
2215 2215
    let err = try expectError(&result);
2216 2216
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2217 2217
}
2218 2218
2219 2219
/// Test that `let mut ... else` produces a mutable binding.
2220 2220
@test fn testResolveLetMutElse() throws (testing::TestError) {
2221 2221
    let mut a = testResolver();
2222 -
    let program = "let opt: ?i32 = 42; let mut v = opt else panic; v = v + 1;";
2222 +
    let program = "let opt: ?i32 = 42; let mut v = opt else panic; set v = v + 1;";
2223 2223
    let result = try resolveProgramStr(&mut a, program);
2224 2224
    try expectNoErrors(&result);
2225 2225
}
2226 2226
2227 2227
/// Test that `let ... else` (without mut) rejects assignment.
2228 2228
@test fn testResolveLetElseImmutable() throws (testing::TestError) {
2229 2229
    let mut a = testResolver();
2230 -
    let program = "let opt: ?i32 = 42; let v = opt else panic; v = 1;";
2230 +
    let program = "let opt: ?i32 = 42; let v = opt else panic; set v = 1;";
2231 2231
    let result = try resolveProgramStr(&mut a, program);
2232 2232
    let err = try expectError(&result);
2233 2233
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2234 2234
}
2235 2235
2703 2703
}
2704 2704
2705 2705
@test fn testResolveAssignDeref() throws (testing::TestError) {
2706 2706
    {
2707 2707
        let mut a = testResolver();
2708 -
        let program = "let mut x: i32 = 0; let ptr: *mut i32 = &mut x; *ptr = 42;";
2708 +
        let program = "let mut x: i32 = 0; let ptr: *mut i32 = &mut x; set *ptr = 42;";
2709 2709
        let result = try resolveProgramStr(&mut a, program);
2710 2710
        try expectNoErrors(&result);
2711 2711
    } {
2712 2712
        let mut a = testResolver();
2713 -
        let program = "let mut x: i32 = 0; let ptr: *i32 = &x; *ptr = 42;";
2713 +
        let program = "let mut x: i32 = 0; let ptr: *i32 = &x; set *ptr = 42;";
2714 2714
        let result = try resolveProgramStr(&mut a, program);
2715 2715
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2716 2716
    } {
2717 2717
        let mut a = testResolver();
2718 -
        let program = "let mut x: i32 = 0; let mut ptr: *i32 = &x; *ptr = 42;";
2718 +
        let program = "let mut x: i32 = 0; let mut ptr: *i32 = &x; set *ptr = 42;";
2719 2719
        let result = try resolveProgramStr(&mut a, program);
2720 2720
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
2721 2721
    } {
2722 2722
        let mut a = testResolver();
2723 -
        let program = "let mut x: u8 = 0; let mut ptr: *mut u8 = &mut x; *ptr = 255;";
2723 +
        let program = "let mut x: u8 = 0; let mut ptr: *mut u8 = &mut x; set *ptr = 255;";
2724 2724
        let result = try resolveProgramStr(&mut a, program);
2725 2725
        try expectNoErrors(&result);
2726 2726
    }
2727 2727
}
2728 2728
3422 3422
    let mut a = testResolver();
3423 3423
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3424 3424
3425 3425
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena);
3426 3426
    let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "export static COUNTER: i32 = 0;", &mut arena);
3427 -
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() { let p: *mut i32 = &mut statics::COUNTER; *p = 7; }", &mut arena);
3427 +
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() { let p: *mut i32 = &mut statics::COUNTER; set *p = 7; }", &mut arena);
3428 3428
3429 3429
    let result = try resolveModuleTree(&mut a, rootId);
3430 3430
    try expectNoErrors(&result);
3431 3431
}
3432 3432
3435 3435
    let mut a = testResolver();
3436 3436
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3437 3437
3438 3438
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
3439 3439
    let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant LIMIT: i32 = 7;", &mut arena);
3440 -
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; fn main() { let p: *mut i32 = &mut consts::LIMIT; *p = 9; }", &mut arena);
3440 +
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; fn main() { let p: *mut i32 = &mut consts::LIMIT; set *p = 9; }", &mut arena);
3441 3441
3442 3442
    let result = try resolveModuleTree(&mut a, rootId);
3443 3443
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3444 3444
}
3445 3445
3455 3455
/// Test that mutable pointer to immutable slice cannot be assigned through index.
3456 3456
/// This tests the case where we have `*mut *[T]`; the outer pointer is mutable but
3457 3457
/// the inner slice is immutable, so we shouldn't be able to mutate the elements.
3458 3458
@test fn testAssignThroughMutablePointerToImmutableSlice() throws (testing::TestError) {
3459 3459
    let mut a = testResolver();
3460 -
    let program = "fn f(slice: *[i32]) { let p: *mut *[i32] = &mut slice; p[0] = 1; }";
3460 +
    let program = "fn f(slice: *[i32]) { let p: *mut *[i32] = &mut slice; set p[0] = 1; }";
3461 3461
    let result = try resolveProgramStr(&mut a, program);
3462 3462
3463 3463
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3464 3464
}
3465 3465
3466 3466
/// Test that mutable slice parameters can be assigned through index.
3467 3467
@test fn testAssignThroughMutableSliceParam() throws (testing::TestError) {
3468 3468
    {
3469 3469
        // Mutable slice param: direct assignment should work
3470 3470
        let mut a = testResolver();
3471 -
        let program = "fn f(slice: *mut [i32]) { slice[0] = 1; }";
3471 +
        let program = "fn f(slice: *mut [i32]) { set slice[0] = 1; }";
3472 3472
        let result = try resolveProgramStr(&mut a, program);
3473 3473
        try expectNoErrors(&result);
3474 3474
    } {
3475 3475
        // Immutable slice param: direct assignment should fail
3476 3476
        let mut a = testResolver();
3477 -
        let program = "fn f(slice: *[i32]) { slice[0] = 1; }";
3477 +
        let program = "fn f(slice: *[i32]) { set slice[0] = 1; }";
3478 3478
        let result = try resolveProgramStr(&mut a, program);
3479 3479
        try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3480 3480
    }
3481 3481
}
3482 3482
3545 3545
}
3546 3546
3547 3547
/// Test that record fields can be assigned if the record binding is mutable.
3548 3548
@test fn testMutableAssignToMutableRecordBinding() throws (testing::TestError) {
3549 3549
    let mut a = testResolver();
3550 -
    let program = "record S { x: i32 } fn f() { let mut s = S { x: 1 }; s.x = 2; }";
3550 +
    let program = "record S { x: i32 } fn f() { let mut s = S { x: 1 }; set s.x = 2; }";
3551 3551
    let result = try resolveProgramStr(&mut a, program);
3552 3552
    try expectNoErrors(&result);
3553 3553
}
3554 3554
3555 3555
/// Test that record fields cannot be assigned if the record binding is immutable.
3556 3556
@test fn testMutableAssignToImmutableRecordBinding() throws (testing::TestError) {
3557 3557
    let mut a = testResolver();
3558 -
    let program = "record S { x: i32 } fn f() { let s = S { x: 1 }; s.x = 2; }";
3558 +
    let program = "record S { x: i32 } fn f() { let s = S { x: 1 }; set s.x = 2; }";
3559 3559
    let result = try resolveProgramStr(&mut a, program);
3560 3560
    let err = try expectError(&result);
3561 3561
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3562 3562
}
3563 3563
3564 3564
/// Test that record fields can be assigned through a mutable pointer.
3565 3565
@test fn testMutableAssignToMutablePointerToRecord() throws (testing::TestError) {
3566 3566
    let mut a = testResolver();
3567 -
    let program = "record S { x: i32 } fn f(p: *mut S) { p.x = 2; }";
3567 +
    let program = "record S { x: i32 } fn f(p: *mut S) { set p.x = 2; }";
3568 3568
    let result = try resolveProgramStr(&mut a, program);
3569 3569
    try expectNoErrors(&result);
3570 3570
}
3571 3571
3572 3572
/// Test that record fields cannot be assigned through an immutable pointer.
3573 3573
@test fn testMutableAssignToImmutablePointerToRecord() throws (testing::TestError) {
3574 3574
    let mut a = testResolver();
3575 -
    let program = "record S { x: i32 } fn f(p: *S) { p.x = 2; }";
3575 +
    let program = "record S { x: i32 } fn f(p: *S) { set p.x = 2; }";
3576 3576
    let result = try resolveProgramStr(&mut a, program);
3577 3577
    let err = try expectError(&result);
3578 3578
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
3579 3579
}
3580 3580
3581 3581
// Opaque pointer tests.
3582 3582
3583 3583
/// You can assign any pointer (*T) to an opaque pointer (*opaque) without a cast.
3584 3584
@test fn testOpaquePointerAutoCoercion() throws (testing::TestError) {
3585 3585
    let mut a = testResolver();
3586 -
    let result = try resolveProgramStr(&mut a, "fn f(x: i32) { let mut ptr: *i32 = &x; let o: *opaque = ptr; ptr = o as *i32; }");
3586 +
    let result = try resolveProgramStr(&mut a, "fn f(x: i32) { let mut ptr: *i32 = &x; let o: *opaque = ptr; set ptr = o as *i32; }");
3587 3587
    try expectNoErrors(&result);
3588 3588
}
3589 3589
3590 3590
/// You cannot assign an opaque pointer to a non-opaque pointer without a cast.
3591 3591
@test fn testOpaquePointerNoReverseCoercion() throws (testing::TestError) {
4766 4766
4767 4767
/// Trait declares immutable receiver (*Trait) but instance uses mutable (*mut Type).
4768 4768
/// The instance method could mutate through what was originally an immutable pointer.
4769 4769
@test fn testResolveInstanceMutReceiverOnImmutableTrait() throws (testing::TestError) {
4770 4770
    let mut a = testResolver();
4771 -
    let program = "record Counter { value: i32 } trait Reader { fn (*Reader) read() -> i32; } instance Reader for Counter { fn (c: *mut Counter) read() -> i32 { c.value = c.value + 1; return c.value; } }";
4771 +
    let program = "record Counter { value: i32 } trait Reader { fn (*Reader) read() -> i32; } instance Reader for Counter { fn (c: *mut Counter) read() -> i32 { set c.value = c.value + 1; return c.value; } }";
4772 4772
    let result = try resolveProgramStr(&mut a, program);
4773 4773
    // Should reject: instance declares *mut receiver but trait only requires immutable.
4774 4774
    try expectErrorKind(&result, super::ErrorKind::ReceiverMutabilityMismatch);
4775 4775
}
4776 4776
4777 4777
/// Instance method declares different parameter types than the trait.
4778 4778
/// The resolver should reject the mismatch rather than silently using the trait's types.
4779 4779
@test fn testResolveInstanceParamTypeMismatch() throws (testing::TestError) {
4780 4780
    let mut a = testResolver();
4781 -
    let program = "record Acc { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Acc { fn (a: *mut Acc) add(n: u8) -> i32 { a.value = a.value + n as i32; return a.value; } }";
4781 +
    let program = "record Acc { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Acc { fn (a: *mut Acc) add(n: u8) -> i32 { set a.value = a.value + n as i32; return a.value; } }";
4782 4782
    let result = try resolveProgramStr(&mut a, program);
4783 4783
    // Should reject: instance param type u8 doesn't match trait param type i32.
4784 4784
    let err = try expectError(&result);
4785 4785
    let case super::ErrorKind::TypeMismatch(_) = err.kind
4786 4786
        else throw testing::TestError::Failed;
4787 4787
}
4788 4788
4789 4789
/// Duplicate instance declarations for the same (trait, type) pair should be rejected.
4790 4790
@test fn testResolveInstanceDuplicateRejected() throws (testing::TestError) {
4791 4791
    let mut a = testResolver();
4792 -
    let program = "record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { c.value = c.value + n; return c.value; } } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { c.value = c.value + n + 100; return c.value; } }";
4792 +
    let program = "record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n + 100; return c.value; } }";
4793 4793
    let result = try resolveProgramStr(&mut a, program);
4794 4794
    // Should reject: duplicate instance for (Adder, Counter).
4795 4795
    try expectErrorKind(&result, super::ErrorKind::DuplicateInstance);
4796 4796
}
4797 4797
4815 4815
@test fn testResolveTraitCrossModuleCoercion() throws (testing::TestError) {
4816 4816
    let mut a = testResolver();
4817 4817
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4818 4818
4819 4819
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod defs; mod app;", &mut arena);
4820 -
    let defsId = try registerModule(&mut MODULE_GRAPH, rootId, "defs", "export record Counter { value: i32 } export trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { c.value = c.value + n; return c.value; } }", &mut arena);
4820 +
    let defsId = try registerModule(&mut MODULE_GRAPH, rootId, "defs", "export record Counter { value: i32 } export trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } }", &mut arena);
4821 4821
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::defs; fn test() -> i32 { let mut c = defs::Counter { value: 10 }; let a: *mut opaque defs::Adder = &mut c; return a.add(5); }", &mut arena);
4822 4822
4823 4823
    let result = try resolveModuleTree(&mut a, rootId);
4824 4824
    try expectNoErrors(&result);
4825 4825
}
4829 4829
    let mut a = testResolver();
4830 4830
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4831 4831
4832 4832
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod defs; export mod impls; mod app;", &mut arena);
4833 4833
    let defsId = try registerModule(&mut MODULE_GRAPH, rootId, "defs", "export record Counter { value: i32 } export trait Adder { fn (*mut Adder) add(n: i32) -> i32; }", &mut arena);
4834 -
    let implsId = try registerModule(&mut MODULE_GRAPH, rootId, "impls", "use root::defs; instance defs::Adder for defs::Counter { fn (c: *mut defs::Counter) add(n: i32) -> i32 { c.value = c.value + n; return c.value; } }", &mut arena);
4834 +
    let implsId = try registerModule(&mut MODULE_GRAPH, rootId, "impls", "use root::defs; instance defs::Adder for defs::Counter { fn (c: *mut defs::Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } }", &mut arena);
4835 4835
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::defs; fn test() -> i32 { let mut c = defs::Counter { value: 10 }; let a: *mut opaque defs::Adder = &mut c; return a.add(5); }", &mut arena);
4836 4836
4837 4837
    let result = try resolveModuleTree(&mut a, rootId);
4838 4838
    try expectNoErrors(&result);
4839 4839
}
4840 4840
4841 4841
/// Calling a mutable-receiver trait method on an immutable trait object
4842 4842
/// must be rejected.
4843 4843
@test fn testResolveTraitMutMethodOnImmutableObject() throws (testing::TestError) {
4844 4844
    let mut a = testResolver();
4845 -
    let program = "record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { c.value = c.value + n; return c.value; } } fn caller(a: *opaque Adder) -> i32 { return a.add(1); }";
4845 +
    let program = "record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } } fn caller(a: *opaque Adder) -> i32 { return a.add(1); }";
4846 4846
    let result = try resolveProgramStr(&mut a, program);
4847 4847
    try expectErrorKind(&result, super::ErrorKind::ImmutableBinding);
4848 4848
}
4849 4849
4850 4850
/// Immutable methods on an immutable trait object should be accepted.
4856 4856
}
4857 4857
4858 4858
/// Both mutable and immutable methods on a mutable trait object should work.
4859 4859
@test fn testResolveTraitMixedMethodsOnMutableObject() throws (testing::TestError) {
4860 4860
    let mut a = testResolver();
4861 -
    let program = "record Counter { value: i32 } trait Ops { fn (*mut Ops) inc(); fn (*Ops) get() -> i32; } instance Ops for Counter { fn (c: *mut Counter) inc() { c.value = c.value + 1; } fn (c: *Counter) get() -> i32 { return c.value; } } fn caller(o: *mut opaque Ops) -> i32 { o.inc(); return o.get(); }";
4861 +
    let program = "record Counter { value: i32 } trait Ops { fn (*mut Ops) inc(); fn (*Ops) get() -> i32; } instance Ops for Counter { fn (c: *mut Counter) inc() { set c.value = c.value + 1; } fn (c: *Counter) get() -> i32 { return c.value; } } fn caller(o: *mut opaque Ops) -> i32 { o.inc(); return o.get(); }";
4862 4862
    let result = try resolveProgramStr(&mut a, program);
4863 4863
    try expectNoErrors(&result);
4864 4864
}
4865 4865
4866 4866
/// Instance method body type must match the trait return type.
lib/std/lang/scanner.rad +7 -7
256 256
    return s.source[s.cursor + 1];
257 257
}
258 258
259 259
/// Advance scanner and return the character that was consumed.
260 260
fn advance(s: *mut Scanner) -> u8 {
261 -
    s.cursor += 1;
261 +
    set s.cursor += 1;
262 262
    return s.source[s.cursor - 1];
263 263
}
264 264
265 265
/// Consume the expected character if it matches the current position.
266 266
fn consume(s: *mut Scanner, expected: u8) -> bool {
417 417
        let mid = left + ((right - left) / 2);
418 418
        let kw = KEYWORDS[mid];
419 419
        let cmp = mem::cmp(src, kw.name);
420 420
421 421
        match cmp {
422 -
            case -1 => right = mid,
423 -
            case 1 => left = mid + 1,
422 +
            case -1 => set right = mid,
423 +
            case 1 => set left = mid + 1,
424 424
            else => return kw.tok,
425 425
        }
426 426
    }
427 427
    return TokenKind::Ident;
428 428
}
443 443
}
444 444
445 445
/// Scan the next token.
446 446
export fn next(s: *mut Scanner) -> Token {
447 447
    skipWhitespace(s);  // Skip any whitespace between tokens.
448 -
    s.token = s.cursor; // Token starts at current position.
448 +
    set s.token = s.cursor; // Token starts at current position.
449 449
450 450
    if isEof(s) {
451 451
        return tok(s, TokenKind::Eof);
452 452
    }
453 453
    let c: u8 = advance(s);
613 613
    if offset >= source.len {
614 614
        return nil;
615 615
    }
616 616
    for ch in &source[..offset] {
617 617
        if ch == '\n' {
618 -
            c = 1;
619 -
            l += 1;
618 +
            set c = 1;
619 +
            set l += 1;
620 620
        } else {
621 -
            c += 1;
621 +
            set c += 1;
622 622
        }
623 623
    }
624 624
    return Location { source: sourceLoc, line: l, col: c };
625 625
}
lib/std/lang/scanner/tests.rad +11 -11
84 84
    let mut t: super::Token = super::next(&mut s);
85 85
    try testing::expect(t.kind == super::TokenKind::String);
86 86
    try testing::expect(t.source.len == 14); // Includes quotes.
87 87
    try testing::expect(mem::eq(t.source, "\"Hello World!\""));
88 88
89 -
    t = super::next(&mut s);
89 +
    set t = super::next(&mut s);
90 90
    try testing::expect(t.kind == super::TokenKind::String);
91 91
    try testing::expect(t.source.len == 4);
92 92
    try testing::expect(mem::eq(t.source, "\"\\\"\""));
93 93
}
94 94
104 104
        try testing::expect(loc.line == 1);
105 105
        try testing::expect(loc.col == 1);
106 106
    } else {
107 107
        try testing::expect(false);
108 108
    }
109 -
    tok = super::next(&mut s);
109 +
    set tok = super::next(&mut s);
110 110
    try testing::expect(tok.kind == super::TokenKind::Ident);
111 111
    try testing::expect(tok.source.len == 3);
112 112
113 113
    if let loc = super::getLocation(s.sourceLoc, s.source, tok.offset) {
114 114
        try testing::expect(loc.line == 2);
115 115
        try testing::expect(loc.col == 3);
116 116
    } else {
117 117
        try testing::expect(false);
118 118
    }
119 -
    tok = super::next(&mut s);
119 +
    set tok = super::next(&mut s);
120 120
    try testing::expect(tok.kind == super::TokenKind::Ident);
121 121
    try testing::expect(tok.source.len == 3);
122 122
123 123
    if let loc = super::getLocation(s.sourceLoc, s.source, tok.offset) {
124 124
        try testing::expect(loc.line == 3);
187 187
    );
188 188
    let mut tok: super::Token = super::next(&mut s);
189 189
    try testing::expect(tok.kind == super::TokenKind::Ident);
190 190
    try testing::expect(tok.source.len == 3);
191 191
192 -
    tok = super::next(&mut s);
192 +
    set tok = super::next(&mut s);
193 193
    try testing::expect(tok.kind == super::TokenKind::Ident);
194 194
    try testing::expect(tok.source.len == 6);
195 195
196 -
    tok = super::next(&mut s);
196 +
    set tok = super::next(&mut s);
197 197
    try testing::expect(tok.kind == super::TokenKind::Ident);
198 198
    try testing::expect(tok.source.len == 7);
199 199
}
200 200
201 201
@test fn testScanNumbers() throws (testing::TestError) {
205 205
    let mut tok: super::Token = super::next(&mut s);
206 206
    try testing::expect(tok.kind == super::TokenKind::Number);
207 207
    try testing::expect(mem::eq(tok.source, "9841029"));
208 208
    try testing::expect(tok.source.len == 7);
209 209
210 -
    tok = super::next(&mut s);
210 +
    set tok = super::next(&mut s);
211 211
    try testing::expect(tok.kind == super::TokenKind::Number);
212 212
    try testing::expect(tok.source.len == 5);
213 213
214 -
    tok = super::next(&mut s);
214 +
    set tok = super::next(&mut s);
215 215
    try testing::expect(tok.kind == super::TokenKind::Number);
216 216
    try testing::expect(mem::eq(tok.source, "-128"));
217 217
    try testing::expect(tok.source.len == 4);
218 218
219 -
    tok = super::next(&mut s);
219 +
    set tok = super::next(&mut s);
220 220
    try testing::expect(tok.kind == super::TokenKind::Number);
221 221
    try testing::expect(mem::eq(tok.source, "+0x2A"));
222 222
    try testing::expect(tok.source.len == 5);
223 223
224 -
    tok = super::next(&mut s);
224 +
    set tok = super::next(&mut s);
225 225
    try testing::expect(tok.kind == super::TokenKind::Number);
226 226
    try testing::expect(mem::eq(tok.source, "+0b11"));
227 227
    try testing::expect(tok.source.len == 5);
228 228
}
229 229
271 271
    );
272 272
    let mut tok: super::Token = super::next(&mut s);
273 273
    try testing::expect(tok.kind == super::TokenKind::Invalid);
274 274
    try testing::expect(tok.offset == 0);
275 275
276 -
    tok = super::next(&mut s);
276 +
    set tok = super::next(&mut s);
277 277
    try testing::expect(tok.kind == super::TokenKind::Invalid);
278 278
    try testing::expect(tok.offset == 1);
279 279
280 -
    tok = super::next(&mut s);
280 +
    set tok = super::next(&mut s);
281 281
    try testing::expect(tok.kind == super::TokenKind::Invalid);
282 282
    try testing::expect(tok.offset == 2);
283 283
}
284 284
285 285
@test fn testScanUnterminatedString() throws (testing::TestError) {
lib/std/lang/sexpr.rad +4 -4
46 46
    if items.len == 0 {
47 47
        return &[];
48 48
    }
49 49
    let buf = try! allocExprs(a, items.len);
50 50
    for item, i in items {
51 -
        buf[i] = item;
51 +
        set buf[i] = item;
52 52
    }
53 53
    return buf;
54 54
}
55 55
56 56
/// Shorthand for creating a symbol.
84 84
        case Output::Stdout => io::print(s),
85 85
        case Output::Buffer { buf, pos } => {
86 86
            let remaining = buf.len - *pos;
87 87
            let toWrite = remaining if s.len > remaining else s.len;
88 88
            for i in 0..toWrite {
89 -
                buf[*pos] = s[i];
90 -
                *pos += 1;
89 +
                set buf[*pos] = s[i];
90 +
                set *pos += 1;
91 91
            }
92 92
        }
93 93
    }
94 94
}
95 95
149 149
            } else {
150 150
                let mut first = head.len == 0;
151 151
                for i in 0..tail.len {
152 152
                    if tail[i] <> Expr::Null {
153 153
                        if first {
154 -
                            first = false;
154 +
                            set first = false;
155 155
                        } else {
156 156
                            write(out, " ");
157 157
                        }
158 158
                        printTo(tail[i], depth, out);
159 159
                    }
lib/std/lang/strings.rad +3 -3
39 39
        let entry = sp.table[idx];
40 40
        if entry.len > 0 {
41 41
            if mem::eq(entry, str) {
42 42
                return Lookup::Found(entry);
43 43
            }
44 -
            idx = (idx + 1) & (TABLE_SIZE - 1);
44 +
            set idx = (idx + 1) & (TABLE_SIZE - 1);
45 45
        } else {
46 46
            return Lookup::Empty(idx);
47 47
        }
48 48
    }
49 49
}
64 64
export fn intern(sp: *mut Pool, str: *[u8]) -> *[u8] {
65 65
    match lookup(sp, str) {
66 66
        case Lookup::Found(entry) => return entry,
67 67
        case Lookup::Empty(idx) => {
68 68
            assert sp.count < TABLE_SIZE / 2, "intern: string pool is full";
69 -
            sp.table[idx] = str;
70 -
            sp.count += 1;
69 +
            set sp.table[idx] = str;
70 +
            set sp.count += 1;
71 71
72 72
            return str;
73 73
        }
74 74
    }
75 75
}
lib/std/mem.rad +3 -3
8 8
export fn copy(into: *mut [u8], from: *[u8]) -> u32 throws (MemoryError) {
9 9
    if into.len < from.len {
10 10
        throw MemoryError::BufferTooSmall;
11 11
    }
12 12
    for x, i in from {
13 -
        into[i] = x;
13 +
        set into[i] = x;
14 14
    }
15 15
    return from.len;
16 16
}
17 17
18 18
/// Strip a byte-level prefix from the input, and return the suffix.
45 45
/// Count number of set bits in a 32-bit value.
46 46
export fn popCount(x: u32) -> i32 {
47 47
    let mut n = x;
48 48
    let mut count: i32 = 0;
49 49
    while n <> 0 {
50 -
        count += (n & 1) as i32;
51 -
        n >>= 1;
50 +
        set count += (n & 1) as i32;
51 +
        set n >>= 1;
52 52
    }
53 53
    return count;
54 54
}
55 55
56 56
/// Check whether two byte slices have the same length and contents.
lib/std/sys/unix.rad +2 -2
60 60
            return n;
61 61
        }
62 62
        if n == 0 {
63 63
            break;
64 64
        }
65 -
        total += n as u32;
65 +
        set total += n as u32;
66 66
    }
67 67
    return total as i64;
68 68
}
69 69
70 70
/// Writes to a file descriptor from the provided buffer.
117 117
        let n = write(fd, chunk);
118 118
        if n <= 0 {
119 119
            close(fd);
120 120
            return false;
121 121
        }
122 -
        written += n as u32;
122 +
        set written += n as u32;
123 123
    }
124 124
    close(fd);
125 125
126 126
    return true;
127 127
}
lib/std/testing.rad +3 -3
57 57
    io::print(name);
58 58
    io::print(" ... ");
59 59
60 60
    let mut success = true;
61 61
    try testFn() catch {
62 -
        success = false;
62 +
        set success = false;
63 63
    };
64 64
    if success {
65 65
        io::printLn("ok");
66 -
        ctx.passed += 1;
66 +
        set ctx.passed += 1;
67 67
    } else {
68 68
        io::printLn("FAILED");
69 -
        ctx.failed += 1;
69 +
        set ctx.failed += 1;
70 70
    }
71 71
}
72 72
73 73
fn printTestSummary(ctx: *Ctx) {
74 74
    if (ctx.failed > 0) {
lib/std/tests.rad +1 -1
134 134
    let mut xs: [u8; 2] = [1, 2];
135 135
    let ys: [u8; 3] = [4, 5, 6];
136 136
137 137
    let mut threw = false;
138 138
    try mem::copy(&mut xs[..], &ys[..]) catch {
139 -
        threw = true;
139 +
        set threw = true;
140 140
    };
141 141
    try testing::expect(threw);
142 142
}
143 143
144 144
@test fn testStripPrefixMatch() throws (testing::TestError) {
lib/std/vec.rad +4 -4
42 42
    return vec.data.len / vec.stride;
43 43
}
44 44
45 45
/// Reset the vector to empty (does not clear memory).
46 46
export fn reset(vec: *mut RawVec) {
47 -
    vec.len = 0;
47 +
    set vec.len = 0;
48 48
}
49 49
50 50
/// Get a pointer to the element at the given index.
51 51
///
52 52
/// Returns nil if index is out of bounds.
70 70
    let off: u32 = vec.len * vec.stride;
71 71
    let dst: *mut u8 = &mut vec.data[off];
72 72
    let src: *u8 = elem as *u8;
73 73
74 74
    copyBytes(dst, src, vec.stride);
75 -
    vec.len += 1;
75 +
    set vec.len += 1;
76 76
77 77
    return true;
78 78
}
79 79
80 80
/// Pop an element from the end of the vector.
83 83
/// Returns false if the vector is empty.
84 84
export fn pop(vec: *mut RawVec, out: *mut opaque) -> bool {
85 85
    if vec.len == 0 {
86 86
        return false;
87 87
    }
88 -
    vec.len -= 1;
88 +
    set vec.len -= 1;
89 89
90 90
    let off: u32 = vec.len * vec.stride;
91 91
    let src: *u8 = &vec.data[off];
92 92
    let dst: *mut u8 = out as *mut u8;
93 93
113 113
}
114 114
115 115
/// Copy bytes from source to destination.
116 116
fn copyBytes(dst: *mut u8, src: *u8, count: u32) {
117 117
    for i in 0..count {
118 -
        *(dst + i) = *(src + i);
118 +
        set *(dst + i) = *(src + i);
119 119
    }
120 120
}
test/runner.rad +11 -11
53 53
    let mut end: u32 = 0;
54 54
    let mut i: u32 = 0;
55 55
56 56
    while i < line.len and line[i] <> ';' {
57 57
        if line[i] <> ' ' and line[i] <> '\t' {
58 -
            end = i + 1;
58 +
            set end = i + 1;
59 59
        }
60 -
        i += 1;
60 +
        set i += 1;
61 61
    }
62 62
    return &line[..end];
63 63
}
64 64
65 65
/// Get next line from string at offset. Returns the line and updates offset past newline.
66 66
fn nextLine(s: *[u8], offset: *mut u32) -> *[u8] {
67 67
    let start = *offset;
68 68
    let mut i = start;
69 69
70 70
    while i < s.len and s[i] <> '\n' {
71 -
        i += 1;
71 +
        set i += 1;
72 72
    }
73 73
    let line = &s[start..i];
74 74
    if i < s.len {
75 -
        *offset = i + 1;
75 +
        set *offset = i + 1;
76 76
    } else {
77 -
        *offset = i;
77 +
        set *offset = i;
78 78
    }
79 79
    return line;
80 80
}
81 81
82 82
/// Compare two strings ignoring comments, line by line.
85 85
    let mut bi: u32 = 0;
86 86
87 87
    while ai < a.len or bi < b.len {
88 88
        let mut aLine = "";
89 89
        while ai < a.len and aLine.len == 0 {
90 -
            aLine = stripLine(nextLine(a, &mut ai));
90 +
            set aLine = stripLine(nextLine(a, &mut ai));
91 91
        }
92 92
        let mut bLine = "";
93 93
        while bi < b.len and bLine.len == 0 {
94 -
            bLine = stripLine(nextLine(b, &mut bi));
94 +
            set bLine = stripLine(nextLine(b, &mut bi));
95 95
        }
96 96
        if not mem::eq(aLine, bLine) {
97 97
            return false;
98 98
        }
99 99
    }
130 130
    try mem::copy(buf, sourcePath) catch {
131 131
        return nil;
132 132
    };
133 133
    // TODO: Rewrite this once we fix the compiler bug and add support for
134 134
    // additions in ranges.
135 -
    buf[len - 3] = 'r';
136 -
    buf[len - 2] = 'i';
137 -
    buf[len - 1] = 'l';
138 -
    buf[len] = 0;
135 +
    set buf[len - 3] = 'r';
136 +
    set buf[len - 2] = 'i';
137 +
    set buf[len - 1] = 'l';
138 +
    set buf[len] = 0;
139 139
140 140
    return &buf[..len];
141 141
}
142 142
143 143
/// Run a single IL snapshot test case. Returns `true` on success.
test/tests/aggregate.return.rad +4 -4
61 61
fn testMutateReturnedAggregate() -> i32 {
62 62
    let before: u32 = 42;
63 63
    let mut p: Pair = makePair(10, 20);
64 64
    let after: u32 = 99;
65 65
66 -
    p.a = 100;
67 -
    p.b = 200;
66 +
    set p.a = 100;
67 +
    set p.b = 200;
68 68
69 69
    assert before == 42;
70 70
    assert after == 99;
71 71
    assert p.a == 100;
72 72
    assert p.b == 200;
77 77
fn testAggregateReturnInLoop() -> i32 {
78 78
    let mut total: u32 = 0;
79 79
    let mut idx: u32 = 0;
80 80
    while idx < 5 {
81 81
        let p: Pair = makePair(idx, idx + 10);
82 -
        total += p.a + p.b;
83 -
        idx += 1;
82 +
        set total += p.a + p.b;
83 +
        set idx += 1;
84 84
    }
85 85
    // total = sum(i + i+10 for i in 0..5) = sum(2i+10) = 2*(0+1+2+3+4) + 50 = 20 + 50 = 70
86 86
    assert total == 70;
87 87
    return 0;
88 88
}
test/tests/arith.assignment.rad +9 -9
4 4
    let mut b: i32 = 3;
5 5
    let mut c: i32 = 0;
6 6
    let mut d: i32 = 0;
7 7
8 8
    // Test addition.
9 -
    c = a + b; // c = 9
9 +
    set c = a + b; // c = 9
10 10
11 11
    // Test subtraction.
12 -
    c -= b; // c = 6
12 +
    set c -= b; // c = 6
13 13
14 14
    // Test multiplication.
15 -
    c *= b; // c = 18
15 +
    set c *= b; // c = 18
16 16
17 17
    // Test division.
18 -
    c /= b; // c = 6
18 +
    set c /= b; // c = 6
19 19
20 20
    // Test mixed operations.
21 -
    d = a * b + c / b;   // d = 18 + 2 = 20
22 -
    d += a * b / a;   // d = 20 + 3 = 23
23 -
    d += (b * a - c); // d = 23 + (18 - 6) = 35
24 -
    d += (c - a / b); // d = 35 + (6 - 2) = 39
25 -
    d += 3;           // d = 42
21 +
    set d = a * b + c / b;   // d = 18 + 2 = 20
22 +
    set d += a * b / a;   // d = 20 + 3 = 23
23 +
    set d += (b * a - c); // d = 23 + (18 - 6) = 35
24 +
    set d += (c - a / b); // d = 35 + (6 - 2) = 39
25 +
    set d += 3;           // d = 42
26 26
27 27
    return (d) - 42;
28 28
}
test/tests/array.assign.rad +1 -1
3 3
4 4
@default fn main() -> i32 {
5 5
    let mut a: [i32; 5] = [1, 2, 3, 4, 5];
6 6
    let mut b: [i32; 5] = [8, 9, 7, 6, 0];
7 7
8 -
    b = a;
8 +
    set b = a;
9 9
10 10
    return b[0] + b[3] - b[2];
11 11
}
test/tests/array.index.assign.rad +10 -10
2 2
//! Test array index assignment and reading.
3 3
4 4
@default fn main() -> i32 {
5 5
    let mut arr: [i32; 5] = [1, 2, 3, 4, 5];
6 6
7 -
    arr[0] = 10;
8 -
    arr[1] = 20;
9 -
    arr[2] = 30;
10 -
    arr[3] = 40;
11 -
    arr[4] = 50;
7 +
    set arr[0] = 10;
8 +
    set arr[1] = 20;
9 +
    set arr[2] = 30;
10 +
    set arr[3] = 40;
11 +
    set arr[4] = 50;
12 12
13 13
    let mut sum: i32 = 0;
14 14
15 -
    sum += arr[0];
16 -
    sum += arr[1];
17 -
    sum += arr[2];
18 -
    sum += arr[3];
19 -
    sum -= arr[4];
15 +
    set sum += arr[0];
16 +
    set sum += arr[1];
17 +
    set sum += arr[2];
18 +
    set sum += arr[3];
19 +
    set sum -= arr[4];
20 20
21 21
    assert sum == 50;
22 22
    return 0;
23 23
}
test/tests/array.index.rad +4 -4
3 3
4 4
@default fn main() -> i32 {
5 5
    let mut arr: [i32; 4] = [10, 20, 30, 40];
6 6
    let mut sum: i32 = 0;
7 7
8 -
    sum += arr[0];
9 -
    sum += arr[1];
10 -
    sum += arr[2];
11 -
    sum += arr[3];
8 +
    set sum += arr[0];
9 +
    set sum += arr[1];
10 +
    set sum += arr[2];
11 +
    set sum += arr[3];
12 12
13 13
    return (sum) - 100;
14 14
}
test/tests/array.length.rad +2 -2
5 5
    let mut ary: [i32; 7] = [1, 2, 3, 4, 5, 6, 7];
6 6
    let mut sum: i32 = 0;
7 7
    let mut i: u32 = 0;
8 8
9 9
    while (i < ary.len) {
10 -
        sum += ary[i];
11 -
        i += 1;
10 +
        set sum += ary[i];
11 +
        set i += 1;
12 12
    }
13 13
    return (sum) - 28;
14 14
}
test/tests/array.math.rad +5 -5
3 3
4 4
fn sumMatrix(mat: [[i32; 3]; 2]) -> i32 {
5 5
    let mut sum: i32 = 0;
6 6
    for vec in mat {
7 7
        for x in vec {
8 -
            sum += x;
8 +
            set sum += x;
9 9
        }
10 10
    }
11 11
    return sum;
12 12
}
13 13
14 14
fn sumMatrixTransposed(mat: [[i32; 2]; 3]) -> i32 {
15 15
    let mut sum: i32 = 0;
16 16
    for vec in (mat) {
17 17
        for x in (vec) {
18 -
            sum += x;
18 +
            set sum += x;
19 19
        }
20 20
    }
21 21
    return sum;
22 22
}
23 23
26 26
    let mut i: u32 = 0;
27 27
28 28
    while (i < matrix.len) {
29 29
        let mut j: u32 = 0;
30 30
        while (j < matrix[i].len) {
31 -
            result[j][i] = matrix[i][j];
32 -
            j += 1;
31 +
            set result[j][i] = matrix[i][j];
32 +
            set j += 1;
33 33
        }
34 -
        i += 1;
34 +
        set i += 1;
35 35
    }
36 36
    return result;
37 37
}
38 38
39 39
@default fn main() -> i32 {
test/tests/array.nested.assign.rad +2 -2
4 4
@default fn main() -> i32 {
5 5
    let mut m: [[i32; 3]; 2] = [
6 6
        [1, 2, 3],
7 7
        [4, 5, 6]
8 8
    ];
9 -
    m[1][1] = 7;
10 -
    m[0][2] = 4;
9 +
    set m[1][1] = 7;
10 +
    set m[0][2] = 4;
11 11
12 12
    return
13 13
        m[0][0] +
14 14
        m[0][1] +
15 15
        m[0][2] +
test/tests/array.record.elements.rad +8 -8
8 8
9 9
fn calculateDistance(p1: Point, p2: Point) -> i32 {
10 10
    // Simple Manhattan distance
11 11
    let mut dx: i32 = p2.x - p1.x;
12 12
    if (dx < 0) {
13 -
        dx = -dx;
13 +
        set dx = -dx;
14 14
    }
15 15
    let mut dy: i32 = p2.y - p1.y;
16 16
    if (dy < 0) {
17 -
        dy = -dy;
17 +
        set dy = -dy;
18 18
    }
19 19
    return dx + dy;
20 20
}
21 21
22 22
fn sumPoints(points: [Point; 4]) -> i32 {
23 23
    let mut sum: i32 = 0;
24 24
    let mut i: u32 = 0;
25 25
26 26
    while (i < 4) {
27 -
        sum += points[i].x + points[i].y;
28 -
        i += 1;
27 +
        set sum += points[i].x + points[i].y;
28 +
        set i += 1;
29 29
    }
30 30
    return sum;
31 31
}
32 32
33 33
fn shiftPoints(points: [Point; 4], dx: i32, dy: i32) -> [Point; 4] {
37 37
        Point { x: 0, y: 0 },
38 38
        Point { x: 0, y: 0 }
39 39
    ];
40 40
    let mut i: u32 = 0;
41 41
    while (i < 4) {
42 -
        result[i] = Point {
42 +
        set result[i] = Point {
43 43
            x: points[i].x + dx,
44 44
            y: points[i].y + dy
45 45
        };
46 -
        i += 1;
46 +
        set i += 1;
47 47
    }
48 48
    return result;
49 49
}
50 50
51 51
@default fn main() -> i32 {
63 63
    let mut shifted: [Point; 4] = shiftPoints(points, 1, 1);
64 64
    // Calculate distance between original and shifted array elements.
65 65
    let mut distance: i32 = 0;
66 66
    let mut i: u32 = 0;
67 67
    while (i < points.len) {
68 -
        distance += calculateDistance(points[i], shifted[i]);
69 -
        i += 1;
68 +
        set distance += calculateDistance(points[i], shifted[i]);
69 +
        set i += 1;
70 70
    }
71 71
    return total + distance + shifted[3].x - points[0].y;
72 72
}
test/tests/assign.loop.rad +2 -2
1 1
/// Assignment in a loop, accumulating a value.
2 2
fn assignLoop(n: i32) -> i32 {
3 3
    let mut sum: i32 = 0;
4 4
    let mut i: i32 = 0;
5 5
    while i < n {
6 -
        sum += i;
7 -
        i += 1;
6 +
        set sum += i;
7 +
        set i += 1;
8 8
    }
9 9
    return sum;
10 10
}
test/tests/assign.multi.var.rad +3 -3
1 1
/// Multiple variables with interleaved assignments.
2 2
fn assignMultiVar() -> i32 {
3 3
    let mut a: i32 = 1;
4 4
    let mut b: i32 = 2;
5 -
    a = 10;
6 -
    b = 20;
7 -
    a += b;
5 +
    set a = 10;
6 +
    set b = 20;
7 +
    set a += b;
8 8
    return a;
9 9
}
test/tests/assign.mutable.rad +46 -46
15 15
/// Basic variable aliasing and mutation.
16 16
fn testBasicAliasing() -> i32 {
17 17
    let mut x: i32 = 10;
18 18
    let mut y: i32 = x;  // y aliases x's value
19 19
20 -
    x = 20;          // Modify x
21 -
    y += 5;       // Modify y independently
20 +
    set x = 20;          // Modify x
21 +
    set y += 5;       // Modify y independently
22 22
23 23
    return x + y;    // Should be 20 + 15 = 35
24 24
}
25 25
26 26
/// Struct aliasing and field mutation.
27 27
fn testStructAliasing() -> i32 {
28 28
    let mut p1: Person = Person { age: 25, score: 100 };
29 29
    let mut p2: Person = p1;     // Copy record
30 30
31 -
    p1.age = 30;             // Modify original
32 -
    p2.score = 0;            // Modify copy
31 +
    set p1.age = 30;             // Modify original
32 +
    set p2.score = 0;            // Modify copy
33 33
34 34
    return p1.age + p1.score + p2.age + p2.score; // 30+100+25+0 = 155
35 35
}
36 36
37 37
/// Array aliasing and element mutation.
38 38
fn testArrayAliasing() -> i32 {
39 39
    let mut arr1: [i32; 3] = [1, 2, 3];
40 40
    let mut arr2: [i32; 3] = arr1;  // Copy array
41 -
    arr1[0] = 10;               // Modify original
42 -
    arr2[1] = 20;               // Modify copy
41 +
    set arr1[0] = 10;               // Modify original
42 +
    set arr2[1] = 20;               // Modify copy
43 43
    // Arrays should be independent
44 44
    return arr1[0] + arr1[1] + arr2[0] + arr2[1]; // 10+2+1+20 = 33
45 45
}
46 46
47 47
/// Test 4: Nested record with array mutation.
50 50
        values: [1, 2, 3],
51 51
        count: 3
52 52
    };
53 53
    let mut container2: Container = container1;  // Copy entire record
54 54
55 -
    container1.values[0] = 50;              // Modify nested array in original
56 -
    container1.count = 5;                   // Modify field in original
55 +
    set container1.values[0] = 50;              // Modify nested array in original
56 +
    set container1.count = 5;                   // Modify field in original
57 57
58 -
    container2.values[2] = 60;              // Modify nested array in copy
59 -
    container2.count = 7;                   // Modify field in copy
58 +
    set container2.values[2] = 60;              // Modify nested array in copy
59 +
    set container2.count = 7;                   // Modify field in copy
60 60
61 61
    return container1.values[0] + container1.count +
62 62
           container2.values[2] + container2.count; // 50+5+60+7 = 122
63 63
}
64 64
65 65
/// Variable overwriting with different types/scopes.
66 66
fn testVariableOverwriting() -> i32 {
67 67
    let mut result: i32 = 0;
68 68
    let mut temp: i32 = 10;
69 -
    result = temp;      // First assignment
69 +
    set result = temp;      // First assignment
70 70
71 -
    temp = 20;          // Overwrite temp
72 -
    result += temp; // result = 10 + 20 = 30
71 +
    set temp = 20;          // Overwrite temp
72 +
    set result += temp; // result = 10 + 20 = 30
73 73
74 74
    // Create new scope with same variable name
75 75
    if true {
76 76
        let mut temp: i32 = 50;   // Shadow outer temp
77 -
        result += temp; // result = 30 + 50 = 80
78 -
        temp = 60;        // Modify inner temp
79 -
        result += temp; // result = 80 + 60 = 140
77 +
        set result += temp; // result = 30 + 50 = 80
78 +
        set temp = 60;        // Modify inner temp
79 +
        set result += temp; // result = 80 + 60 = 140
80 80
    }
81 -
    result += temp;   // Should use outer temp (20)
81 +
    set result += temp;   // Should use outer temp (20)
82 82
83 83
    return result;            // 140 + 20 = 160
84 84
}
85 85
86 86
/// Array of structs with aliasing.
89 89
        Person { age: 10, score: 20 },
90 90
        Person { age: 15, score: 25 }
91 91
    ];
92 92
    let mut backup: [Person; 2] = people;  // Copy array of structs
93 93
94 -
    people[0].age = 12;        // Modify original
95 -
    people[1].score = 30;      // Modify original
94 +
    set people[0].age = 12;        // Modify original
95 +
    set people[1].score = 30;      // Modify original
96 96
97 -
    backup[0].score = 22;      // Modify copy
98 -
    backup[1].age = 18;        // Modify copy
97 +
    set backup[0].score = 22;      // Modify copy
98 +
    set backup[1].age = 18;        // Modify copy
99 99
100 100
    return people[0].age + people[0].score + people[1].age + people[1].score +
101 101
           backup[0].age + backup[0].score + backup[1].age + backup[1].score;
102 102
}
103 103
105 105
fn testMutationChain() -> i32 {
106 106
    let mut a: i32 = 1;
107 107
    let mut b: i32 = 2;
108 108
    let mut c: i32 = 3;
109 109
110 -
    a = b;          // a = 2
111 -
    b = c;          // b = 3
112 -
    c = a + b;      // c = 2 + 3 = 5
113 -
    a = c - b;      // a = 5 - 3 = 2
114 -
    b = a * c;      // b = 2 * 5 = 10
110 +
    set a = b;          // a = 2
111 +
    set b = c;          // b = 3
112 +
    set c = a + b;      // c = 2 + 3 = 5
113 +
    set a = c - b;      // a = 5 - 3 = 2
114 +
    set b = a * c;      // b = 2 * 5 = 10
115 115
116 116
    return a + b + c; // 2 + 10 + 5 = 17
117 117
}
118 118
119 119
/// Struct field reassignment with aliasing.
121 121
    let mut original: Person = Person { age: 30, score: 40 };
122 122
    let mut copied: Person = original;
123 123
124 124
    // Swap fields in original
125 125
    let mut temp: i32 = original.age;
126 -
    original.age = original.score;
127 -
    original.score = temp;
126 +
    set original.age = original.score;
127 +
    set original.score = temp;
128 128
129 129
    // Different swap in copy
130 -
    temp = copied.score;
131 -
    copied.score = copied.age;
132 -
    copied.age = temp;
130 +
    set temp = copied.score;
131 +
    set copied.score = copied.age;
132 +
    set copied.age = temp;
133 133
134 134
    return original.age + original.score + copied.age + copied.score;
135 135
    // 40+30 + 40+30 = 140
136 136
}
137 137
140 140
    let mut indices: [u32; 3] = [0, 1, 2];
141 141
    let mut values: [i32; 3] = [10, 20, 30];
142 142
    let mut backup: [i32; 3] = values;
143 143
144 144
    // Use indices to modify values
145 -
    values[indices[0]] = 25;     // values[0] = 25
146 -
    values[indices[1]] = 35;     // values[1] = 35
145 +
    set values[indices[0]] = 25;     // values[0] = 25
146 +
    set values[indices[1]] = 35;     // values[1] = 35
147 147
148 148
    // Modify indices
149 -
    indices[0] = 2;
150 -
    indices[2] = 0;
149 +
    set indices[0] = 2;
150 +
    set indices[2] = 0;
151 151
152 152
    // Use new indices on backup
153 -
    backup[indices[0]] = 40;   // backup[2] = 40
154 -
    backup[indices[2]] = 45;   // backup[0] = 45
153 +
    set backup[indices[0]] = 40;   // backup[2] = 40
154 +
    set backup[indices[2]] = 45;   // backup[0] = 45
155 155
156 156
    return values[0] + values[1] + values[2] +
157 157
           backup[0] + backup[1] + backup[2];
158 158
    // 25+35+30 + 45+20+40 = 195
159 159
}
164 164
    let mut level2: Person = level1;
165 165
    let mut level3: Person = level2;
166 166
    let mut level4: Person = level3;
167 167
168 168
    // Modify each level
169 -
    level1.age = 11;
170 -
    level2.age = 12;
171 -
    level3.age = 13;
172 -
    level4.age = 14;
173 -
174 -
    level1.score = 21;
175 -
    level2.score = 22;
176 -
    level3.score = 23;
177 -
    level4.score = 24;
169 +
    set level1.age = 11;
170 +
    set level2.age = 12;
171 +
    set level3.age = 13;
172 +
    set level4.age = 14;
173 +
174 +
    set level1.score = 21;
175 +
    set level2.score = 22;
176 +
    set level3.score = 23;
177 +
    set level4.score = 24;
178 178
179 179
    return (level1.age + level1.score) +
180 180
           (level2.age + level2.score) +
181 181
           (level3.age + level3.score) +
182 182
           (level4.age + level4.score);
test/tests/assign.param.rad +2 -2
1 1
/// Assignment overwriting a parameter value.
2 2
fn assignParam(x: i32) -> i32 {
3 3
    let mut y: i32 = x;
4 -
    y += 1;
5 -
    y *= 2;
4 +
    set y += 1;
5 +
    set y *= 2;
6 6
    return y;
7 7
}
test/tests/assign.rad +3 -3
1 1
//! returns: 0
2 2
@default fn main() -> i32 {
3 3
    let mut i: i32 = 36;
4 -
    i += 1; // 37
5 -
    i += 2; // 39
6 -
    i += 3; // 42
4 +
    set i += 1; // 37
5 +
    set i += 2; // 39
6 +
    set i += 3; // 42
7 7
8 8
    return i - 42;
9 9
}
test/tests/assign.self.ref.rad +2 -2
1 1
/// Assignment where the new value depends on the old value.
2 2
fn assignSelfRef() -> i32 {
3 3
    let mut x: i32 = 1;
4 -
    x += x;
5 -
    x *= x;
4 +
    set x += x;
5 +
    set x *= x;
6 6
    return x;
7 7
}
test/tests/assign.sequential.rad +2 -2
1 1
/// Sequential assignments where the final value is returned.
2 2
fn assignSequential() -> i32 {
3 3
    let mut x: i32 = 1;
4 -
    x = 2;
5 -
    x = 3;
4 +
    set x = 2;
5 +
    set x = 3;
6 6
    return x;
7 7
}
test/tests/assign.shadow.mutable.rad +7 -7
1 1
//! returns: 0
2 2
3 3
fn shadowedMutation() -> i32 {
4 4
    let mut result: i32 = 0;
5 5
    let mut temp: i32 = 10;
6 -
    result = temp;
6 +
    set result = temp;
7 7
8 -
    temp = 20;
9 -
    result += temp;
8 +
    set temp = 20;
9 +
    set result += temp;
10 10
11 11
    if true {
12 12
        let mut temp: i32 = 50;
13 -
        result += temp;
14 -
        temp = 60;
15 -
        result += temp;
13 +
        set result += temp;
14 +
        set temp = 60;
15 +
        set result += temp;
16 16
    }
17 17
    // Must refer to outer `temp` (20), not inner shadowed `temp` (60).
18 -
    result += temp;
18 +
    set result += temp;
19 19
20 20
    return result;
21 21
}
22 22
23 23
@default fn main() -> i32 {
test/tests/assign.use.intermediate.rad +1 -1
1 1
/// Sequential assignments with intermediate value used in computation.
2 2
fn assignUseIntermediate() -> i32 {
3 3
    let mut x: i32 = 1;
4 4
    let y: i32 = x + 1;
5 -
    x = 5;
5 +
    set x = 5;
6 6
    return x + y;
7 7
}
test/tests/average.rad +1 -1
1 1
/// Compute the sum of a list of numbers.
2 2
fn average(numbers: *[u32]) -> u32 {
3 3
    let mut sum: u32 = 0;
4 4
5 5
    for i in numbers {
6 -
        sum += i;
6 +
        set sum += i;
7 7
    }
8 8
    return sum / numbers.len;
9 9
}
test/tests/bool.short.circuit.rad +1 -1
1 1
//! returns: 0
2 2
//! Test short-circuiting behavior of 'and' and 'or' operators.
3 3
fn modify(counter: *mut i32, ret: bool) -> bool {
4 -
    *counter += 1;
4 +
    set *counter += 1;
5 5
    return ret;
6 6
}
7 7
8 8
@default fn main() -> i32 {
9 9
    // Test 'and' short-circuits when first operand is false.
test/tests/builtin.sliceof.mut.rad +8 -8
9 9
10 10
    // Create a mutable slice from the pointer and length
11 11
    let slice: *mut [i32] = @sliceOf(ptr, 4);
12 12
13 13
    // Double each element via the slice
14 -
    slice[0] *= 2;
15 -
    slice[1] *= 2;
16 -
    slice[2] *= 2;
17 -
    slice[3] *= 2;
14 +
    set slice[0] *= 2;
15 +
    set slice[1] *= 2;
16 +
    set slice[2] *= 2;
17 +
    set slice[3] *= 2;
18 18
19 19
    // Sum the modified elements
20 20
    let mut sum: i32 = 0;
21 -
    sum += slice[0];
22 -
    sum += slice[1];
23 -
    sum += slice[2];
24 -
    sum += slice[3];
21 +
    set sum += slice[0];
22 +
    set sum += slice[1];
23 +
    set sum += slice[2];
24 +
    set sum += slice[3];
25 25
26 26
    return (sum) - 200;
27 27
}
test/tests/builtin.sliceof.rad +4 -4
10 10
    // Create a slice from the pointer and length
11 11
    let slice: *[i32] = @sliceOf(ptr, 4);
12 12
13 13
    // Access elements via the slice and sum them
14 14
    let mut sum: i32 = 0;
15 -
    sum += slice[0];
16 -
    sum += slice[1];
17 -
    sum += slice[2];
18 -
    sum += slice[3];
15 +
    set sum += slice[0];
16 +
    set sum += slice[1];
17 +
    set sum += slice[2];
18 +
    set sum += slice[3];
19 19
20 20
    return sum;
21 21
}
test/tests/byte.load.store.rad +2 -2
3 3
fn loadByte(ptr: *u8) -> u8 {
4 4
    return *ptr;
5 5
}
6 6
7 7
fn storeByte(ptr: *mut u8, val: u8) {
8 -
    *ptr = val;
8 +
    set *ptr = val;
9 9
}
10 10
11 11
fn loadStoreByte(src: *u8, dst: *mut u8) {
12 -
    *dst = *src;
12 +
    set *dst = *src;
13 13
}
14 14
15 15
fn byteArrayAccess(arr: [u8; 4], idx: u32) -> u8 {
16 16
    return arr[idx];
17 17
}
test/tests/call.clobber.rad +1 -1
1 1
//! returns: 0
2 2
//! Test that values live across function calls are not clobbered.
3 3
fn modify(counter: *mut i32, ret: bool) -> bool {
4 -
    *counter += 1;
4 +
    set *counter += 1;
5 5
    return ret;
6 6
}
7 7
8 8
@default fn main() -> i32 {
9 9
    let mut x: i32 = 0;
test/tests/casting.numbers.rad +2 -2
2 2
//! Test integer casting: zero-extension, sign-extension, truncation.
3 3
4 4
fn zeroExtension() -> bool {
5 5
    let x: u8 = 9;
6 6
    let mut y: i32 = 42424242;
7 -
    y = x as i32;
7 +
    set y = x as i32;
8 8
    let z: u8 = y as u8;
9 9
10 10
    return y == 9 and z == 9;
11 11
}
12 12
13 13
fn casting() -> bool {
14 14
    let x: u8 = 5;
15 15
    let y: i16 = 10;
16 16
    let mut z: i32 = y as i32;
17 17
18 -
    z = 11 as i32 + z;
18 +
    set z = 11 as i32 + z;
19 19
20 20
    return ((x as i32) + z) == 26;
21 21
}
22 22
23 23
fn signedCasting() -> bool {
test/tests/compound.assign.field.rad +3 -3
6 6
}
7 7
8 8
@default fn main() -> i32 {
9 9
    let mut p = Point { x: 10, y: 20 };
10 10
11 -
    p.x += 5;
11 +
    set p.x += 5;
12 12
    assert p.x == 15;
13 13
14 -
    p.y -= 3;
14 +
    set p.y -= 3;
15 15
    assert p.y == 17;
16 16
17 -
    p.x *= 2;
17 +
    set p.x *= 2;
18 18
    assert p.x == 30;
19 19
20 20
    return 0;
21 21
}
test/tests/compound.assign.rad +15 -15
2 2
/// Test compound assignment operators (+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=).
3 3
@default fn main() -> i32 {
4 4
    let mut a: i32 = 10;
5 5
6 6
    // Test +=
7 -
    a += 5;
7 +
    set a += 5;
8 8
    assert a == 15;
9 9
10 10
    // Test -=
11 -
    a -= 3;
11 +
    set a -= 3;
12 12
    assert a == 12;
13 13
14 14
    // Test *=
15 -
    a *= 2;
15 +
    set a *= 2;
16 16
    assert a == 24;
17 17
18 18
    // Test /=
19 -
    a /= 4;
19 +
    set a /= 4;
20 20
    assert a == 6;
21 21
22 22
    // Test %=
23 -
    a %= 4;
23 +
    set a %= 4;
24 24
    assert a == 2;
25 25
26 26
    // Test &=
27 27
    let mut b: i32 = 0xFF;
28 -
    b &= 0x0F;
28 +
    set b &= 0x0F;
29 29
    assert b == 0x0F;
30 30
31 31
    // Test |=
32 -
    b |= 0xF0;
32 +
    set b |= 0xF0;
33 33
    assert b == 0xFF;
34 34
35 35
    // Test ^=
36 -
    b ^= 0x0F;
36 +
    set b ^= 0x0F;
37 37
    assert b == 0xF0;
38 38
39 39
    // Test <<=
40 40
    let mut c: i32 = 1;
41 -
    c <<= 4;
41 +
    set c <<= 4;
42 42
    assert c == 16;
43 43
44 44
    // Test >>=
45 -
    c >>= 2;
45 +
    set c >>= 2;
46 46
    assert c == 4;
47 47
48 48
    // Test compound assignment with array subscript.
49 49
    let mut arr: [i32; 3] = [10, 20, 30];
50 -
    arr[1] += 5;
50 +
    set arr[1] += 5;
51 51
    assert arr[1] == 25;
52 52
53 53
    // Test compound assignment with pointer dereference.
54 54
    let mut val: i32 = 100;
55 55
    let p: *mut i32 = &mut val;
56 -
    *p += 50;
56 +
    set *p += 50;
57 57
    assert val == 150;
58 58
59 59
    // Test chained compound assignments.
60 60
    let mut x: i32 = 1;
61 -
    x += 2;
62 -
    x *= 3;
63 -
    x -= 1;
61 +
    set x += 2;
62 +
    set x *= 3;
63 +
    set x -= 1;
64 64
    assert x == 8;
65 65
66 66
    return 0;
67 67
}
test/tests/cond.assign.merge.basic.rad +2 -2
1 1
/// Return a value assigned from either branch of a conditional.
2 2
fn condAssignMergeBasic(flag: bool) -> i32 {
3 3
    let mut x: i32 = 0;
4 4
    if flag {
5 -
        x = 1;
5 +
        set x = 1;
6 6
    } else {
7 -
        x = 2;
7 +
        set x = 2;
8 8
    }
9 9
    return x;
10 10
}
test/tests/cond.assign.merge.rad +2 -2
1 1
/// Returns a value assigned from either branch of a conditional.
2 2
fn condAssignMerge(x: i32) -> i32 {
3 3
    let mut y: i32 = 0;
4 4
    if x > 0 {
5 -
        y = 1;
5 +
        set y = 1;
6 6
    } else {
7 -
        y = 2;
7 +
        set y = 2;
8 8
    }
9 9
    return y;
10 10
}
test/tests/cond.assign.rad +7 -7
6 6
@default fn main() -> i32 {
7 7
    // Simple `if-else` with variable assignment.
8 8
    let t: bool = true;
9 9
    let mut x: i32 = 0;
10 10
    if t {
11 -
        x = 1;
11 +
        set x = 1;
12 12
    } else {
13 -
        x = 2;
13 +
        set x = 2;
14 14
    }
15 15
    assert x == 1;
16 16
17 17
    // `if-else` with `false` condition.
18 18
    let f: bool = false;
19 19
    if f {
20 -
        x = 10;
20 +
        set x = 10;
21 21
    } else {
22 -
        x = 20;
22 +
        set x = 20;
23 23
    }
24 24
    assert x == 20;
25 25
26 26
    // `if-else` chain.
27 27
    let a: i32 = 5;
28 28
    if a == 3 {
29 -
        x = 100;
29 +
        set x = 100;
30 30
    } else if a == 5 {
31 -
        x = 200;
31 +
        set x = 200;
32 32
    } else {
33 -
        x = 300;
33 +
        set x = 300;
34 34
    }
35 35
    assert x == 200;
36 36
    return 0;
37 37
}
test/tests/cond.for.else.break.rad +2 -2
3 3
@default fn main() -> i32 {
4 4
    let mut i: i32 = 0;
5 5
    let xs: [i32; 7] = [1, 2, 3, 4, 5, 6, 7];
6 6
7 7
    for x in (xs) {
8 -
        i += x;
8 +
        set i += x;
9 9
        if (i >= 10) {
10 10
            break; // This should skip the else clause.
11 11
        }
12 12
    } else {
13 -
        i += 100; // This should NOT run because we break.
13 +
        set i += 100; // This should NOT run because we break.
14 14
    }
15 15
    return (i) - 10;
16 16
}
test/tests/cond.for.indexed.rad +1 -1
3 3
@default fn main() -> u32 {
4 4
    let arr: [u32; 3] = [10, 20, 30];
5 5
    let mut sum: u32 = 0;
6 6
7 7
    for value, index in arr {
8 -
        sum += value + index;
8 +
        set sum += value + index;
9 9
    }
10 10
    return (sum) - 63;
11 11
    //  (10+0) + (20+1) + (30+2) = 10 + 21 + 32 = 63
12 12
}
test/tests/cond.for.rad +1 -1
3 3
@default fn main() -> i32 {
4 4
    let mut i: i32 = 0;
5 5
    let xs: [i32; 7] = [1, 2, 3, 4, 5, 6, 7];
6 6
7 7
    for x in (xs) {
8 -
        i += x;
8 +
        set i += x;
9 9
    }
10 10
    return (i) - 28;
11 11
}
test/tests/cond.for.range.indexed.rad +2 -2
6 6
    // Test range iteration with index.
7 7
    // val: 5, 6, 7, 8
8 8
    // idx: 0, 1, 2, 3
9 9
    // sum: (5+0) + (6+1) + (7+2) + (8+3) = 5 + 7 + 9 + 11 = 32
10 10
    for val, idx in 5..9 {
11 -
        sum += val + idx as i32;
11 +
        set sum += val + idx as i32;
12 12
    }
13 13
14 14
    // Test that value starts from a non-zero offset while index starts at 0.
15 15
    // val: 10, 11
16 16
    // idx: 0, 1
17 17
    // sum: 32 + (10-0) + (11-1) = 32 + 10 + 10 = 52
18 18
    for v, i in 10..12 {
19 -
        sum += v - i as i32;
19 +
        set sum += v - i as i32;
20 20
    }
21 21
22 22
    return (sum) - 52;
23 23
}
test/tests/cond.for.range.rad +1 -1
3 3
@default fn main() -> i32 {
4 4
    let xs: [i32; 4] = [3, 4, 5, 6];
5 5
    let mut sum: i32 = 0;
6 6
7 7
    for i in 0..xs.len {
8 -
        sum += xs[i];
8 +
        set sum += xs[i];
9 9
    }
10 10
    return (sum) - 18;
11 11
}
test/tests/cond.for.unsigned.range.rad +3 -3
4 4
    let start: u32 = 2147483647;
5 5
    let end: u32 = 2147483648;
6 6
    let mut count: i32 = 0;
7 7
8 8
    for i in start..end {
9 -
        count += 1;
9 +
        set count += 1;
10 10
    }
11 11
    assert count == 1;
12 12
13 13
    // Unsigned range above signed boundary.
14 14
    let start2: u32 = 2147483648;
15 15
    let end2: u32 = 2147483651;
16 16
    let mut count2: i32 = 0;
17 17
18 18
    for i in start2..end2 {
19 -
        count2 += 1;
19 +
        set count2 += 1;
20 20
    }
21 21
    assert count2 == 3;
22 22
23 23
    // Signed range still uses signed ordering.
24 24
    let mut sum: i32 = 0;
25 25
    for i in -2..2 {
26 -
        sum += i;
26 +
        set sum += i;
27 27
    }
28 28
    assert sum == -2;
29 29
30 30
    return 0;
31 31
}
test/tests/cond.forever.break.continue.rad +1 -1
2 2
@default fn main() -> i32 {
3 3
    let mut i: i32 = 0;
4 4
5 5
    loop {
6 6
        if (i < 42) {
7 -
            i += 1;
7 +
            set i += 1;
8 8
            continue;
9 9
        }
10 10
        break;
11 11
    }
12 12
    return (i) - 42;
test/tests/cond.forever.break.rad +2 -2
5 5
    loop {
6 6
        loop {
7 7
            if (i > 39) {
8 8
                break;
9 9
            }
10 -
            i += 1;
10 +
            set i += 1;
11 11
        }
12 -
        i += 2;
12 +
        set i += 2;
13 13
        break;
14 14
    }
15 15
    return (i) - 42;
16 16
}
test/tests/cond.if.else.rad +1 -1
3 3
    let mut i: i32 = 41;
4 4
5 5
    if (i == 42) {
6 6
        return (1) - 42;
7 7
    } else {
8 -
        i += 1;
8 +
        set i += 1;
9 9
    }
10 10
11 11
    if (i == 42) {
12 12
        return (42) - 42;
13 13
    } else {
test/tests/cond.if.elseif.rad +2 -2
5 5
    if (i == 42) {
6 6
        return (1) - 42;
7 7
    } else if (i == 41) {
8 8
        return (1) - 42;
9 9
    } else if (i == 40) {
10 -
        i += 2;
10 +
        set i += 2;
11 11
    } else {
12 -
        i += 1;
12 +
        set i += 1;
13 13
    }
14 14
15 15
    if (i == 42) {
16 16
        return (42) - 42;
17 17
    } else if (i == 41) {
test/tests/cond.if.noelse.rad +1 -1
2 2
3 3
@default fn main() -> i32 {
4 4
    let mut x: i32 = 10;
5 5
6 6
    if (x == 11) {
7 -
        x = 20;
7 +
        set x = 20;
8 8
    }
9 9
10 10
    return (x) - 10;
11 11
}
test/tests/cond.iflet.mut.rad +1 -1
1 1
//! `if let mut` binding with mutation of the bound variable.
2 2
fn ifLetMut(p: ?i32) -> i32 {
3 3
    if let mut x = p {
4 -
        x = x + 1;
4 +
        set x = x + 1;
5 5
        return x;
6 6
    } else {
7 7
        return 0;
8 8
    }
9 9
}
test/tests/cond.letelse.mut.rad +1 -1
1 1
//! `let mut ... else` binding with mutation of the bound variable.
2 2
fn letMutElse(p: ?i32) -> i32 {
3 3
    let mut x = p else {
4 4
        return 0;
5 5
    };
6 -
    x = x + 1;
6 +
    set x = x + 1;
7 7
    return x;
8 8
}
test/tests/cond.match.fallthrough.rad +1 -1
4 4
    let mut x: i32 = 1;
5 5
6 6
    match (x) {
7 7
        case 1 => {
8 8
            // This case matches, changes x to 2 and should jump to end.
9 -
            x = 2;
9 +
            set x = 2;
10 10
        },
11 11
        case 2 => { return (2) - 42; },
12 12
        else => { return (0) - 42; }
13 13
    }
14 14
    return (42) - 42;
test/tests/cond.match.guard.rad +4 -4
8 8
9 9
fn checkStmt(value: OptionNum) -> i32 {
10 10
    let mut result: i32 = -100;
11 11
    match value {
12 12
        case OptionNum::Some(payload) if payload == 5 => {
13 -
            result = payload;
13 +
            set result = payload;
14 14
        }
15 15
        case OptionNum::Some(payload) => {
16 -
            result = -payload;
16 +
            set result = -payload;
17 17
        }
18 18
        case OptionNum::Other(payload) if payload == 7 => {
19 -
            result = payload * 2;
19 +
            set result = payload * 2;
20 20
        }
21 21
        else => {
22 -
            result = 0;
22 +
            set result = 0;
23 23
        }
24 24
    }
25 25
    return result;
26 26
}
27 27
test/tests/cond.match.guard.regalloc.rad +3 -3
23 23
fn getPath(node: *Node, buf: *mut [*[u8]]) -> *[*[u8]] {
24 24
    let mut out: *[*[u8]] = &[];
25 25
26 26
    match node.kind {
27 27
        case Kind::Name(name) if name.len > 0 => {
28 -
            buf[0] = name;
29 -
            out = &buf[..1];
28 +
            set buf[0] = name;
29 +
            set out = &buf[..1];
30 30
        }
31 31
        case Kind::Pair { a, b } => {
32 -
            out = &buf[..1];
32 +
            set out = &buf[..1];
33 33
        }
34 34
        else => {}
35 35
    }
36 36
    return out;
37 37
}
test/tests/cond.while.else.break.rad +2 -2
2 2
3 3
@default fn main() -> i32 {
4 4
    let mut i: i32 = 0;
5 5
6 6
    while (i < 100) {
7 -
        i += 1;
7 +
        set i += 1;
8 8
        if (i == 42) {
9 9
            break; // This should skip the else clause.
10 10
        }
11 11
    } else {
12 -
        i += 100; // This should NOT run because we break.
12 +
        set i += 100; // This should NOT run because we break.
13 13
    }
14 14
    return (i) - 42;
15 15
}
test/tests/cond.while.rad +1 -1
1 1
//! returns: 0
2 2
@default fn main() -> i32 {
3 3
    let mut i: i32 = 0;
4 4
5 5
    while (i < 42) {
6 -
        i += 1;
6 +
        set i += 1;
7 7
    }
8 8
    return (i) - 42;
9 9
}
test/tests/const.array.copy.mutate.rad +2 -2
4 4
constant SEED: [i32; 4] = [1, 2, 3, 4];
5 5
6 6
fn crunch() -> i32 {
7 7
    let mut working: [i32; 4] = SEED;
8 8
9 -
    working[0] += 5;
10 -
    working[3] = working[1] + working[2];
9 +
    set working[0] += 5;
10 +
    set working[3] = working[1] + working[2];
11 11
12 12
    return working[0] + working[3];
13 13
}
14 14
15 15
@default fn main() -> i32 {
test/tests/const.array.rad +1 -1
4 4
constant NUMBERS: [i32; 4] = [1, 2, 3, 4];
5 5
6 6
@default fn main() -> i32 {
7 7
    let mut sum: i32 = 0;
8 8
    for n in (NUMBERS) {
9 -
        sum += n;
9 +
        set sum += n;
10 10
    }
11 11
    return (sum) - 10;
12 12
}
test/tests/const.record.array.rad +1 -1
15 15
16 16
fn sumPoints(points: [Point; 3]) -> i32 {
17 17
    let mut sum: i32 = 0;
18 18
19 19
    for p in (points) {
20 -
        sum += p.x + p.y;
20 +
        set sum += p.x + p.y;
21 21
    }
22 22
    return sum;
23 23
}
24 24
25 25
// Array of structs as a function parameter
test/tests/const.record.array.simple.rad +3 -3
15 15
16 16
@default fn main() -> i32 {
17 17
    let mut sum: i32 = 0;
18 18
19 19
    // Add all points' x and y values
20 -
    sum += POINTS[0].x + POINTS[0].y;  // 1 + 2 = 3
21 -
    sum += POINTS[1].x + POINTS[1].y;  // 3 + 4 = 7
22 -
    sum += POINTS[2].x + POINTS[2].y;  // 5 + 6 = 11
20 +
    set sum += POINTS[0].x + POINTS[0].y;  // 1 + 2 = 3
21 +
    set sum += POINTS[1].x + POINTS[1].y;  // 3 + 4 = 7
22 +
    set sum += POINTS[2].x + POINTS[2].y;  // 5 + 6 = 11
23 23
24 24
    return (sum) - 21;  // 3 + 7 + 11 = 21
25 25
}
test/tests/const.record.mutcopy.rad +1 -1
8 8
9 9
/// Returns a scratch register, avoiding the one already used by `rs`.
10 10
fn test(rs: Reg) -> Reg {
11 11
    let mut scratch = SCRATCH1;
12 12
    if rs.n == SCRATCH1.n {
13 -
        scratch = SCRATCH2;
13 +
        set scratch = SCRATCH2;
14 14
    }
15 15
    return scratch;
16 16
}
test/tests/edge.cases.4.rad +2 -2
21 21
}
22 22
23 23
fn node(nodes: *mut Node, count: *mut u32, value: NodeValue) -> *Node {
24 24
    let index = *count;
25 25
    let slot = nodes + index;
26 -
    *slot = Node { value };
27 -
    *count = index + 1;
26 +
    set *slot = Node { value };
27 +
    set *count = index + 1;
28 28
    return slot;
29 29
}
30 30
31 31
fn nodeTypeInt(nodes: *mut Node, count: *mut u32, width: u8, sign: Signedness) -> *Node {
32 32
    return node(nodes, count, NodeValue::TypeSig(
test/tests/edge.cases.6.rad +4 -4
58 58
    t: 0x1234560F,
59 59
};
60 60
static ANALYZER: Analyzer = undefined;
61 61
62 62
fn fillEntry(out: *mut Entry) {
63 -
    *out = DEFAULT_ENTRY;
63 +
    set *out = DEFAULT_ENTRY;
64 64
}
65 65
66 66
fn mkEntry() -> Entry {
67 67
    return DEFAULT_ENTRY;
68 68
}
73 73
    }
74 74
    return mkEntry();
75 75
}
76 76
77 77
fn init(entries: *mut [Entry]) {
78 -
    ANALYZER = Analyzer {
78 +
    set ANALYZER = Analyzer {
79 79
        pad0: 0xDEADAAA0,
80 80
        pad1: 0xDEADAAA1,
81 81
        entries,
82 82
        len: 0,
83 83
    };
86 86
fn add() {
87 87
    let idx = ANALYZER.len;
88 88
    let entry = mkOptEntry(true) else {
89 89
        return;
90 90
    };
91 -
    ANALYZER.entries[idx] = entry;
92 -
    ANALYZER.len = idx + 1;
91 +
    set ANALYZER.entries[idx] = entry;
92 +
    set ANALYZER.len = idx + 1;
93 93
}
94 94
95 95
fn checkHeader(expected: *[Entry]) -> i32 {
96 96
    if ANALYZER.entries.ptr <> expected.ptr or ANALYZER.entries.len <> expected.len {
97 97
        // Slice header got clobbered instead of the backing storage.
test/tests/edge.cases.7.addr.bug.rad +2 -2
6 6
7 7
static target: i32 = 10;
8 8
static holder: PtrHolder = undefined;
9 9
10 10
@default fn main() -> i32 {
11 -
    holder.ptr = &mut target;
12 -
    *holder.ptr = 42;
11 +
    set holder.ptr = &mut target;
12 +
    set *holder.ptr = 42;
13 13
14 14
    return target;
15 15
}
test/tests/edge.cases.8.bug.rad +1 -1
17 17
fn readInner(i: Inner) -> i32 {
18 18
    return i.value;
19 19
}
20 20
21 21
@default fn main() -> i32 {
22 -
    global = Outer { padding: 0, inner: Inner { value: 42 } };
22 +
    set global = Outer { padding: 0, inner: Inner { value: 42 } };
23 23
24 24
    assert readInner(global.inner) == 42;
25 25
    return 0;
26 26
}
test/tests/error.catch.rad +1 -1
13 13
    assert val2 == 21;
14 14
15 15
    // Catch block that discards error
16 16
    let mut flag: u32 = 0;
17 17
    try returnsErr() catch {};
18 -
    flag = 1;
18 +
    set flag = 1;
19 19
    assert flag == 1;
20 20
21 21
    // Catch block with return in function
22 22
    let val3: u32 = returnsEarly();
23 23
    assert val3 == 42;
test/tests/error.multi.basic.rad +3 -3
18 18
19 19
@default fn main() -> i32 {
20 20
    // Test throwing ErrA.
21 21
    let mut caught: i32 = 0;
22 22
    try failA() catch {
23 -
        caught = 1;
23 +
        set caught = 1;
24 24
    };
25 25
    assert caught == 1;
26 26
27 27
    // Test throwing ErrB.
28 -
    caught = 0;
28 +
    set caught = 0;
29 29
    try failB() catch {
30 -
        caught = 2;
30 +
        set caught = 2;
31 31
    };
32 32
    assert caught == 2;
33 33
34 34
    // Test success path.
35 35
    let val = try succeed() catch {
test/tests/error.multi.catch.rad +5 -5
18 18
19 19
@default fn main() -> i32 {
20 20
    // Catch ErrA without binding.
21 21
    let mut handled: i32 = 0;
22 22
    try failA() catch {
23 -
        handled = 1;
23 +
        set handled = 1;
24 24
    };
25 25
    assert handled == 1;
26 26
27 27
    // Catch ErrB without binding.
28 -
    handled = 0;
28 +
    set handled = 0;
29 29
    try failB() catch {
30 -
        handled = 2;
30 +
        set handled = 2;
31 31
    };
32 32
    assert handled == 2;
33 33
34 34
    // Success path should not trigger catch.
35 -
    handled = 0;
35 +
    set handled = 0;
36 36
    let val = try succeed() catch {
37 -
        handled = 99;
37 +
        set handled = 99;
38 38
    };
39 39
    assert handled == 0;
40 40
    assert val == 99;
41 41
    return 0;
42 42
}
test/tests/error.multi.catch.typed.binding.rad +3 -3
17 17
    let mut got: i32 = 0;
18 18
    try failA(100) catch e as ErrA {
19 19
        let case ErrA::A(v) = e else {
20 20
            return 1;
21 21
        };
22 -
        got = v;
22 +
        set got = v;
23 23
    } catch e as ErrB {
24 24
        return 2;
25 25
    };
26 26
    assert got == 100;
27 27
28 28
    // Extract ErrB payload.
29 -
    got = 0;
29 +
    set got = 0;
30 30
    try failB(200) catch e as ErrA {
31 31
        return 4;
32 32
    } catch e as ErrB {
33 33
        let case ErrB::B(v) = e else {
34 34
            return 5;
35 35
        };
36 -
        got = v;
36 +
        set got = v;
37 37
    };
38 38
    assert got == 200;
39 39
    return 0;
40 40
}
test/tests/error.multi.catch.typed.catchall.rad +4 -4
22 22
    let mut result: i32 = 0;
23 23
    try failA() catch e as ErrA {
24 24
        let case ErrA::A(v) = e else {
25 25
            return 10;
26 26
        };
27 -
        result = v;
27 +
        set result = v;
28 28
    } catch {
29 29
        return 1;
30 30
    };
31 31
    assert result == 10;
32 32
33 33
    // ErrB should fall into catch-all.
34 34
    let mut caughtAll: i32 = 0;
35 35
    try failB() catch e as ErrA {
36 36
        return 3;
37 37
    } catch {
38 -
        caughtAll = 1;
38 +
        set caughtAll = 1;
39 39
    };
40 40
    assert caughtAll == 1;
41 41
42 42
    // ErrC should also fall into catch-all.
43 -
    caughtAll = 0;
43 +
    set caughtAll = 0;
44 44
    try failC() catch e as ErrA {
45 45
        return 5;
46 46
    } catch {
47 -
        caughtAll = 1;
47 +
        set caughtAll = 1;
48 48
    };
49 49
    assert caughtAll == 1;
50 50
    return 0;
51 51
}
test/tests/error.multi.catch.typed.rad +3 -3
21 21
    let mut result: i32 = 0;
22 22
    let val1 = try failA() catch e as ErrA {
23 23
        let case ErrA::A(v) = e else {
24 24
            return 10;
25 25
        };
26 -
        result = v;
26 +
        set result = v;
27 27
        0
28 28
    } catch e as ErrB {
29 29
        return 1;
30 30
    };
31 31
    assert result == 10;
32 32
33 33
    // Catch ErrB specifically with typed binding.
34 -
    result = 0;
34 +
    set result = 0;
35 35
    let val2 = try failB() catch e as ErrA {
36 36
        return 3;
37 37
    } catch e as ErrB {
38 38
        let case ErrB::B(v) = e else {
39 39
            return 11;
40 40
        };
41 -
        result = v;
41 +
        set result = v;
42 42
        0
43 43
    };
44 44
    assert result == 20;
45 45
46 46
    // Success path should skip all catches.
test/tests/error.multi.propagate.multi.rad +5 -5
21 21
22 22
@default fn main() -> i32 {
23 23
    // Propagate ErrA through outer.
24 24
    let mut result: i32 = 0;
25 25
    try outer(1) catch e as ErrA {
26 -
        result = 10;
26 +
        set result = 10;
27 27
    } catch e as ErrB {
28 -
        result = 20;
28 +
        set result = 20;
29 29
    };
30 30
    assert result == 10;
31 31
32 32
    // Propagate ErrB through outer.
33 -
    result = 0;
33 +
    set result = 0;
34 34
    try outer(2) catch e as ErrA {
35 -
        result = 10;
35 +
        set result = 10;
36 36
    } catch e as ErrB {
37 -
        result = 20;
37 +
        set result = 20;
38 38
    };
39 39
    assert result == 20;
40 40
41 41
    // Success path.
42 42
    let val = try outer(0) catch e as ErrA {
test/tests/error.multi.propagate.rad +3 -3
24 24
25 25
@default fn main() -> i32 {
26 26
    // Propagate ErrA through middle.
27 27
    let mut caught: i32 = 0;
28 28
    try middle(1) catch {
29 -
        caught = 1;
29 +
        set caught = 1;
30 30
    };
31 31
    assert caught == 1;
32 32
33 33
    // Propagate ErrB through middle.
34 -
    caught = 0;
34 +
    set caught = 0;
35 35
    try middle(2) catch {
36 -
        caught = 2;
36 +
        set caught = 2;
37 37
    };
38 38
    assert caught == 2;
39 39
40 40
    // Success path.
41 41
    let val = try middle(0) catch {
test/tests/error.try.catch.binding.rad +7 -7
5 5
@default fn main() -> u32 {
6 6
    // Test catching and using the error value.
7 7
    let mut caught: u32 = 0;
8 8
    try failWithBoom() catch e {
9 9
        if (e == TestError::Boom) {
10 -
            caught = 1;
10 +
            set caught = 1;
11 11
        } else {
12 -
            caught = 2;
12 +
            set caught = 2;
13 13
        }
14 14
    };
15 15
    assert caught == 1;
16 16
17 17
    // Test catching a different error variant.
18 -
    caught = 0;
18 +
    set caught = 0;
19 19
    try failWithBust() catch e {
20 20
        if (e == TestError::Bust) {
21 -
            caught = 10;
21 +
            set caught = 10;
22 22
        } else {
23 -
            caught = 20;
23 +
            set caught = 20;
24 24
        }
25 25
    };
26 26
    assert caught == 10;
27 27
28 28
    // Test that success path doesn't execute catch block.
29 -
    caught = 0;
29 +
    set caught = 0;
30 30
    try succeed() catch e {
31 -
        caught = 99;
31 +
        set caught = 99;
32 32
    };
33 33
    assert caught == 0;
34 34
35 35
    // Test catch block that returns early from function.
36 36
    let early: u32 = testCatchReturn();
test/tests/error.try.optional.rad +2 -2
79 79
80 80
    // Test 7: try? in while-let loop
81 81
    let mut count: u32 = 0;
82 82
    let mut iter: u32 = 0;
83 83
    while let value = try? maybeValue(iter) {
84 -
        count += value;
85 -
        iter += 1;
84 +
        set count += value;
85 +
        set iter += 1;
86 86
    }
87 87
    assert count == 6;
88 88
89 89
    return 0;
90 90
}
test/tests/error.try.rad +13 -13
38 38
39 39
fn shortCircuit(flag: bool) -> u32 throws (TestError) {
40 40
    let mut counter: u32 = 1;
41 41
42 42
    if flag {
43 -
        counter += try returnsErr(2);
43 +
        set counter += try returnsErr(2);
44 44
    } else {
45 45
        try returnsErr(0);
46 -
        counter += 100;
46 +
        set counter += 100;
47 47
    }
48 48
    return counter;
49 49
}
50 50
51 51
fn aggregateTwo() -> u32 throws (TestError) {
74 74
75 75
fn catchReturn(flag: *mut u32, fail: bool) -> bool {
76 76
    let value: u32 = try maybeReturn(fail) catch {
77 77
        return true;
78 78
    };
79 -
    *flag = value;
79 +
    set *flag = value;
80 80
    return false;
81 81
}
82 82
83 83
fn accumulateSteps(failMid: bool) -> u32 throws (TestError) {
84 84
    let mut total: u32 = 0;
85 85
    let mut idx: u32 = 0;
86 86
    while idx < 3 {
87 87
        if failMid {
88 88
            if idx == 1 {
89 -
                total += try returnsErr(0);
89 +
                set total += try returnsErr(0);
90 90
            } else {
91 -
                total += try returnsErr(2);
91 +
                set total += try returnsErr(2);
92 92
            }
93 93
        } else {
94 -
            total += try returnsErr(2);
94 +
            set total += try returnsErr(2);
95 95
        }
96 -
        idx += 1;
96 +
        set idx += 1;
97 97
    }
98 98
    return total;
99 99
}
100 100
101 101
fn structSuccess(state: *mut ResultSink) -> u32 throws (TestError) {
102 102
    let value: u32 = try returnsOk();
103 -
    state.last = value;
104 -
    state.count += 1;
103 +
    set state.last = value;
104 +
    set state.count += 1;
105 105
    return value;
106 106
}
107 107
108 108
fn structFailure(state: *mut ResultSink) -> u32 throws (TestError) {
109 109
    try returnsErr(1);
110 -
    state.last = 999;
110 +
    set state.last = 999;
111 111
    return 999;
112 112
}
113 113
114 114
@default fn main() -> i32 {
115 115
    let mut sumFlag: u32 = 0;
116 116
    let total: u32 = try! sumThree();
117 117
    assert total == 39;
118 -
    sumFlag = total;
118 +
    set sumFlag = total;
119 119
120 120
    let mut scOkFlag: u32 = 0;
121 121
    let scVal: u32 = try! shortCircuit(true);
122 122
    assert scVal == 10;
123 -
    scOkFlag = scVal;
123 +
    set scOkFlag = scVal;
124 124
125 125
    let mut scErrFlag: u32 = 0;
126 126
    try shortCircuit(false) catch {};
127 127
    assert scErrFlag == 0;
128 128
156 156
    try structFailure(&mut sink) catch {};
157 157
    assert sink.count == 2;
158 158
159 159
    let mut voidOkFlag: u32 = 0;
160 160
    try! returnsOkVoid();
161 -
    voidOkFlag = 77;
161 +
    set voidOkFlag = 77;
162 162
    assert voidOkFlag == 77;
163 163
164 164
    let mut voidErrFlag: u32 = 0;
165 165
    try returnsErrVoid() catch {};
166 166
    assert voidErrFlag == 0;
test/tests/fn.callback.nested.rad +1 -1
17 17
    return current;
18 18
}
19 19
20 20
fn maxRegCallback(reg: Reg, ctx: *mut opaque) {
21 21
    let max = ctx as *mut u32;
22 -
    *max = maxRegNum(reg.n, *max);
22 +
    set *max = maxRegNum(reg.n, *max);
23 23
}
24 24
25 25
fn withReg(val: Val, callback: fn(Reg, *mut opaque), ctx: *mut opaque) {
26 26
    if let case Val::Reg(r) = val {
27 27
        callback(r, ctx);
test/tests/for.else.continue.rad +5 -5
12 12
            else continue;
13 13
        if name.len == target.len {
14 14
            let mut eq = true;
15 15
            for j in 0..name.len {
16 16
                if name[j] <> target[j] {
17 -
                    eq = false;
17 +
                    set eq = false;
18 18
                }
19 19
            }
20 20
            if eq {
21 21
                return fields[i].value;
22 22
            }
25 25
    return nil;
26 26
}
27 27
28 28
@default fn main() -> i32 {
29 29
    let mut fields: [Field; 4] = undefined;
30 -
    fields[0] = Field { name: nil, value: 10 };
31 -
    fields[1] = Field { name: "foo", value: 20 };
32 -
    fields[2] = Field { name: nil, value: 30 };
33 -
    fields[3] = Field { name: "bar", value: 40 };
30 +
    set fields[0] = Field { name: nil, value: 10 };
31 +
    set fields[1] = Field { name: "foo", value: 20 };
32 +
    set fields[2] = Field { name: nil, value: 30 };
33 +
    set fields[3] = Field { name: "bar", value: 40 };
34 34
35 35
    let v1 = findField(&fields[..], "foo") else {
36 36
        return 1;
37 37
    };
38 38
    assert v1 == 20;
test/tests/frame.large.rad +1 -1
14 14
    return arr[0] + arr[1] + arr[3];
15 15
}
16 16
17 17
fn bigFrame3() -> i32 {
18 18
    let mut ary: [u8; 4096] = undefined;
19 -
    ary[4091] = 192;
19 +
    set ary[4091] = 192;
20 20
21 21
    return ary[4091] as i32;
22 22
}
23 23
24 24
@default fn main() -> i32 {
test/tests/if-let-mut.rad +4 -4
10 10
11 11
fn testIfLetMut() -> i32 {
12 12
    let opt = getOptional(10);
13 13
14 14
    if let mut v = opt {
15 -
        v = v + 5;
15 +
        set v = v + 5;
16 16
        if v <> 15 {
17 17
            return 1;
18 18
        }
19 19
    } else {
20 20
        return 2;
24 24
25 25
fn testIfLetMutNil() -> i32 {
26 26
    let opt = getOptional(0);
27 27
28 28
    if let mut v = opt {
29 -
        v = v + 1;
29 +
        set v = v + 1;
30 30
        return 3;
31 31
    }
32 32
    return 0;
33 33
}
34 34
36 36
    let opt = getOptional(42);
37 37
38 38
    let mut v = opt else {
39 39
        return 4;
40 40
    };
41 -
    v = v + 8;
41 +
    set v = v + 8;
42 42
    if v <> 50 {
43 43
        return 5;
44 44
    }
45 45
    return 0;
46 46
}
49 49
    let opt = getOptional(0);
50 50
51 51
    let mut v = opt else {
52 52
        return 0;
53 53
    };
54 -
    v = v + 1;
54 +
    set v = v + 1;
55 55
    return 6;
56 56
}
57 57
58 58
@default fn main() -> i32 {
59 59
    let r1 = testIfLetMut();
test/tests/large.blit.store.rad +11 -11
21 21
/// Store at offset 2200 (> MAX_IMM) into a record field.
22 22
/// Generates `store w32 <imm> %0 2200` in IL, which triggers the
23 23
/// SCRATCH1 aliasing bug when adjustOffset clobbers the value.
24 24
fn storeLargeOffset() -> i32 {
25 25
    let mut b: Big = undefined;
26 -
    b.tag = 42;
26 +
    set b.tag = 42;
27 27
    assert b.tag == 42;
28 -
    b.tag = 99;
28 +
    set b.tag = 99;
29 29
    assert b.tag == 99;
30 30
    return 0;
31 31
}
32 32
33 33
/// Copy a >2047 byte struct (triggers blit offset overflow).
34 34
fn copyBig() -> i32 {
35 35
    let mut src: Big = undefined;
36 -
    src.a[0] = 10;
37 -
    src.a[1000] = 20;
38 -
    src.a[2199] = 30;
39 -
    src.tag = 77;
36 +
    set src.a[0] = 10;
37 +
    set src.a[1000] = 20;
38 +
    set src.a[2199] = 30;
39 +
    set src.tag = 77;
40 40
41 41
    let mut dst: Big = src;
42 42
43 43
    assert dst.a[0] == 10;
44 44
    assert dst.a[1000] == 20;
48 48
}
49 49
50 50
/// Mutate a copy to ensure the blit produced an independent copy.
51 51
fn copyIndependence() -> i32 {
52 52
    let mut a: Big = undefined;
53 -
    a.a[0] = 1;
54 -
    a.a[2199] = 2;
55 -
    a.tag = 100;
53 +
    set a.a[0] = 1;
54 +
    set a.a[2199] = 2;
55 +
    set a.tag = 100;
56 56
57 57
    let mut b: Big = a;
58 -
    b.a[0] = 99;
59 -
    b.tag = 200;
58 +
    set b.a[0] = 99;
59 +
    set b.tag = 200;
60 60
61 61
    assert a.a[0] == 1;
62 62
    assert a.tag == 100;
63 63
    assert b.a[0] == 99;
64 64
    assert b.a[2199] == 2;
test/tests/loc.addr.offset.bug.rad +1 -1
12 12
}
13 13
14 14
static outer: Outer = undefined;
15 15
16 16
@default fn main() -> i32 {
17 -
    outer.inner.value = 42;
17 +
    set outer.inner.value = 42;
18 18
19 19
    let ptr: *Inner = &outer.inner;
20 20
21 21
    assert (*ptr).value == 42;
22 22
    return 0;
test/tests/loc.addr.opt.to.opt.rad +1 -1
10 10
static container: Container = undefined;
11 11
12 12
@default fn main() -> i32 {
13 13
    let sourceOpt: ?i32 = 42;
14 14
15 -
    container.opt = sourceOpt;
15 +
    set container.opt = sourceOpt;
16 16
17 17
    if let val = container.opt {
18 18
        assert val == 42;
19 19
        return 0;
20 20
    } else {
test/tests/loc.addr.optional.assign.rad +1 -1
7 7
}
8 8
9 9
static container: Container = undefined;
10 10
11 11
@default fn main() -> i32 {
12 -
    container.opt = 42;
12 +
    set container.opt = 42;
13 13
14 14
    if let val = container.opt {
15 15
        assert val == 42;
16 16
        return 0;
17 17
    } else {
test/tests/loc.addr.record.assign.rad +2 -2
13 13
14 14
static outer: Outer = undefined;
15 15
static source: Inner = undefined;
16 16
17 17
@default fn main() -> i32 {
18 -
    source.value = 42;
18 +
    set source.value = 42;
19 19
20 -
    outer.inner = source;
20 +
    set outer.inner = source;
21 21
22 22
    assert outer.inner.value == 42;
23 23
    return 0;
24 24
}
test/tests/local.mut.rad +1 -1
1 1
fn localMut() -> i32 {
2 2
    let mut x: i32 = 5;
3 -
    x = 10;
3 +
    set x = 10;
4 4
    return x;
5 5
}
test/tests/loop.break.rad +1 -1
2 2
    let mut i: i32 = 0;
3 3
    loop {
4 4
        if i >= n {
5 5
            break;
6 6
        }
7 -
        i += 1;
7 +
        set i += 1;
8 8
    }
9 9
    return i;
10 10
}
test/tests/loop.complex.flow.rad +3 -3
25 25
        let val = i - 2;  // -2, -1, 0, 1, 2, 3
26 26
        let result = maybeAdd(sum, val);
27 27
28 28
        match result {
29 29
            case Result::Ok(v) => {
30 -
                sum = v;
30 +
                set sum = v;
31 31
            },
32 32
            case Result::Err(e) => {
33 -
                errCount += 1;
33 +
                set errCount += 1;
34 34
            },
35 35
        }
36 -
        i += 1;
36 +
        set i += 1;
37 37
    }
38 38
39 39
    // val sequence: -2, -1, 0, 1, 2, 3
40 40
    // Err for val <= 0: errCount = 3 (for -2, -1, 0)
41 41
    // Ok for val > 0: sum = 0 + 1 + 2 + 3 = 6
test/tests/loop.continue.rad +2 -2
1 1
fn loopContinue(n: i32) -> i32 {
2 2
    let mut i: i32 = 0;
3 3
    let mut sum: i32 = 0;
4 4
    while i < n {
5 -
        i += 1;
5 +
        set i += 1;
6 6
        if i == 3 {
7 7
            continue;
8 8
        }
9 -
        sum += i;
9 +
        set sum += i;
10 10
    }
11 11
    return sum;
12 12
}
test/tests/loop.for.array.rad +1 -1
1 1
/// Iterates over an array with index binding and sums elements.
2 2
fn forArrayIndexed(arr: [i32; 3]) -> i32 {
3 3
    let mut sum: i32 = 0;
4 4
    for elem, idx in arr {
5 -
        sum += elem + idx as i32;
5 +
        set sum += elem + idx as i32;
6 6
    }
7 7
    return sum;
8 8
}
test/tests/loop.for.continue.rad +2 -2
4 4
    let mut sum: u32 = 0;
5 5
    for i in 0..n {
6 6
        if i == 2 {
7 7
            continue;
8 8
        }
9 -
        sum += i;
9 +
        set sum += i;
10 10
    }
11 11
    return sum;
12 12
}
13 13
14 14
fn forContinueArray(arr: [i32; 4]) -> i32 {
15 15
    let mut sum: i32 = 0;
16 16
    for elem in arr {
17 17
        if elem == 0 {
18 18
            continue;
19 19
        }
20 -
        sum += elem;
20 +
        set sum += elem;
21 21
    }
22 22
    return sum;
23 23
}
test/tests/loop.for.indexed.rad +1 -1
1 1
fn loopForIndexed(n: i32) -> i32 {
2 2
    let mut sum: i32 = 0;
3 3
    for val, idx in 0..n {
4 -
        sum += val + idx as i32;
4 +
        set sum += val + idx as i32;
5 5
    }
6 6
    return sum;
7 7
}
test/tests/loop.for.placeholder.rad +2 -2
1 1
// Test for loop with placeholder binding
2 2
3 3
fn forPlaceholder(n: u32) -> u32 {
4 4
    let mut count: u32 = 0;
5 5
    for _ in 0..n {
6 -
        count += 1;
6 +
        set count += 1;
7 7
    }
8 8
    return count;
9 9
}
10 10
11 11
fn forPlaceholderArray(arr: [i32; 4]) -> i32 {
12 12
    let mut count: i32 = 0;
13 13
    for _ in arr {
14 -
        count += 1;
14 +
        set count += 1;
15 15
    }
16 16
    return count;
17 17
}
test/tests/loop.for.rad +1 -1
1 1
fn loopFor(n: i32) -> i32 {
2 2
    let mut sum: i32 = 0;
3 3
    for i in 0..n {
4 -
        sum += i;
4 +
        set sum += i;
5 5
    }
6 6
    return sum;
7 7
}
test/tests/loop.for.slice.rad +1 -1
1 1
/// Iterates over a slice with index binding and sums elements.
2 2
fn forSliceIndexed(s: *[i32]) -> i32 {
3 3
    let mut sum: i32 = 0;
4 4
    for elem, idx in s {
5 -
        sum += elem + idx as i32;
5 +
        set sum += elem + idx as i32;
6 6
    }
7 7
    return sum;
8 8
}
test/tests/loop.for.unsigned.range.rad +2 -2
1 1
fn loopForUnsignedRange(start: u32, end: u32) -> u32 {
2 2
    let mut count: u32 = 0;
3 3
    for _ in start..end {
4 -
        count += 1;
4 +
        set count += 1;
5 5
    }
6 6
    return count;
7 7
}
8 8
9 9
fn loopForSignedRange(start: i32, end: i32) -> i32 {
10 10
    let mut count: i32 = 0;
11 11
    for _ in start..end {
12 -
        count += 1;
12 +
        set count += 1;
13 13
    }
14 14
    return count;
15 15
}
test/tests/loop.mutable.rad +1 -1
8 8
9 9
/// Computes the maximum alignment from a slice of alignment values.
10 10
fn computeMaxAlign(items: *[u32]) -> u32 {
11 11
    let mut maxAlign: u32 = 1;
12 12
    for i in 0..items.len {
13 -
        maxAlign = max(maxAlign, items[i]);
13 +
        set maxAlign = max(maxAlign, items[i]);
14 14
    }
15 15
    return maxAlign;
16 16
}
test/tests/loop.nested.break.rad +3 -3
5 5
    let mut i: i32 = 0;
6 6
7 7
    loop {
8 8
        let mut j: i32 = 0;
9 9
        loop {
10 -
            result += 1;
11 -
            j += 1;
10 +
            set result += 1;
11 +
            set j += 1;
12 12
            if j >= n {
13 13
                break;
14 14
            }
15 15
        }
16 -
        i += 1;
16 +
        set i += 1;
17 17
        if i >= n {
18 18
            break;
19 19
        }
20 20
    }
21 21
    return result;
test/tests/loop.nested.continue.rad +3 -3
3 3
fn nestedContinue(n: i32) -> i32 {
4 4
    let mut result: i32 = 0;
5 5
    let mut i: i32 = 0;
6 6
7 7
    while i < n {
8 -
        i += 1;
8 +
        set i += 1;
9 9
        if i == 2 {
10 10
            continue;
11 11
        }
12 12
        let mut j: i32 = 0;
13 13
        while j < n {
14 -
            j += 1;
14 +
            set j += 1;
15 15
            if j == 1 {
16 16
                continue;
17 17
            }
18 -
            result += 1;
18 +
            set result += 1;
19 19
        }
20 20
    }
21 21
    return result;
22 22
}
test/tests/loop.return.rad +1 -1
1 1
fn loopReturn() -> i32 {
2 2
    let mut i: i32 = 0;
3 3
    loop {
4 -
        i += 1;
4 +
        set i += 1;
5 5
        if i == 10 {
6 6
            return i;
7 7
        }
8 8
    }
9 9
}
test/tests/loop.sealblock.rad +4 -4
7 7
@default fn main() -> i32 {
8 8
    // Simple loop with mutable variable.
9 9
    let mut sum: i32 = 0;
10 10
    let mut i: i32 = 0;
11 11
    while i < 5 {
12 -
        sum += i;
13 -
        i += 1;
12 +
        set sum += i;
13 +
        set i += 1;
14 14
    }
15 15
    // sum = 0 + 1 + 2 + 3 + 4 = 10
16 16
    assert sum == 10;
17 17
18 18
    // For loop with mutable variable.
19 19
    let mut count: i32 = 0;
20 20
    for j in 0..4 {
21 -
        count += 1;
21 +
        set count += 1;
22 22
    }
23 23
    assert count == 4;
24 24
25 25
    // Nested pattern: mutable var with function call in loop.
26 26
    let mut total: i32 = 0;
27 27
    for k in 0..3 {
28 -
        total += addOne(k);
28 +
        set total += addOne(k);
29 29
    }
30 30
    // total = 1 + 2 + 3 = 6
31 31
    assert total == 6;
32 32
33 33
    return 0;
test/tests/loop.while.nested.shortcircuit.rad +3 -3
11 11
    let mut outer: i32 = 0;
12 12
    let mut total: i32 = 0;
13 13
    while outer < n {
14 14
        let mut inner: i32 = outer;
15 15
        while inner > 0 and inner < 100 {
16 -
            inner -= 1;
16 +
            set inner -= 1;
17 17
        }
18 -
        total += outer;
19 -
        outer += 1;
18 +
        set total += outer;
19 +
        set outer += 1;
20 20
    }
21 21
    return total;
22 22
}
test/tests/loop.while.rad +2 -2
1 1
fn loopWhile(n: i32) -> i32 {
2 2
    let mut i: i32 = 0;
3 3
    let mut sum: i32 = 0;
4 4
    while i < n {
5 -
        sum += i;
6 -
        i += 1;
5 +
        set sum += i;
6 +
        set i += 1;
7 7
    }
8 8
    return sum;
9 9
}
test/tests/loop.whilelet.case.rad +2 -2
1 1
// Returns the number of loop iterations when the input starts at zero.
2 2
fn whileLetCase(x: i32) -> i32 {
3 3
    let mut cur: i32 = x;
4 4
    let mut steps: i32 = 0;
5 5
    while let case 0 = cur {
6 -
        cur = 1;
7 -
        steps += 1;
6 +
        set cur = 1;
7 +
        set steps += 1;
8 8
    }
9 9
    return steps;
10 10
}
test/tests/loop.whilelet.guard.rad +2 -2
1 1
// Loops while the input matches case 0 and passes the guard.
2 2
fn whileLetCaseGuard(x: i32) -> i32 {
3 3
    let mut cur: i32 = x;
4 4
    let mut steps: i32 = 0;
5 5
    while let case 0 = cur; steps < 3 {
6 -
        cur = 0;
7 -
        steps += 1;
6 +
        set cur = 0;
7 +
        set steps += 1;
8 8
    }
9 9
    return steps;
10 10
}
test/tests/loop.whilelet.optional.rad +1 -1
1 1
// Returns the iteration count for a single guarded loop.
2 2
fn whileLetOptional(p: ?*i32) -> i32 {
3 3
    let mut steps: i32 = 0;
4 4
    while let _ = p {
5 -
        steps += 1;
5 +
        set steps += 1;
6 6
        break;
7 7
    }
8 8
    return steps;
9 9
}
test/tests/loop.whilelet.union.rad +2 -2
4 4
/// Sum values from a linked iteration using while-let case with binding.
5 5
fn sumWhileLet(x: Option) -> u32 {
6 6
    let mut opt = x;
7 7
    let mut sum: u32 = 0;
8 8
    while let case Option::Some(val) = opt {
9 -
        sum += val;
10 -
        opt = Option::None;
9 +
        set sum += val;
10 +
        set opt = Option::None;
11 11
    }
12 12
    return sum;
13 13
}
test/tests/match.more.rad +1 -1
23 23
24 24
// Returns 1 when the input matches, otherwise returns 0.
25 25
fn matchNoElse(x: i32) -> i32 {
26 26
    let mut y: i32 = 0;
27 27
    match x {
28 -
       case 1 => y = 1,
28 +
       case 1 => set y = 1,
29 29
       else => {},
30 30
    }
31 31
    return y;
32 32
}
test/tests/match.mutref.push.rad +3 -3
10 10
    No { items: U32List },
11 11
    Yes,
12 12
}
13 13
14 14
fn pushItem(list: *mut U32List, value: u32) {
15 -
    list.data[list.len] = value;
16 -
    list.len += 1;
15 +
    set list.data[list.len] = value;
16 +
    set list.len += 1;
17 17
}
18 18
19 19
fn addToUnsealedBlock(state: *mut Sealed, value: u32) -> bool {
20 20
    match state {
21 21
        case Sealed::No { items } => {
28 28
    }
29 29
}
30 30
31 31
@default fn main() -> i32 {
32 32
    let mut buf: [u32; 8] = undefined;
33 -
    buf[0] = 0;
33 +
    set buf[0] = 0;
34 34
    let mut state = Sealed::No { items: U32List { data: &mut buf[0..8], len: 0 } };
35 35
36 36
    assert addToUnsealedBlock(&mut state, 42);
37 37
    assert addToUnsealedBlock(&mut state, 99);
38 38
test/tests/match.mutref.union.rad +1 -1
14 14
15 15
fn process(d: *mut Data) -> u32 {
16 16
    match &mut d.state {
17 17
        case State::A { count } => {
18 18
            let c = *count;
19 -
            *count = c + 1;
19 +
            set *count = c + 1;
20 20
            return c;
21 21
        },
22 22
        case State::B => {
23 23
            return 0;
24 24
        },
test/tests/match.nested.whilelet.rad +6 -6
21 21
/// While-let with nested record destructuring.
22 22
fn sumPairs(items: *[Opt]) -> i32 {
23 23
    let mut sum: i32 = 0;
24 24
    let mut i: u32 = 0;
25 25
    while let case Opt::Some { pair: Pair { a, b } } = get(items, i) {
26 -
        sum = sum + a + b;
27 -
        i = i + 1;
26 +
        set sum = sum + a + b;
27 +
        set i = i + 1;
28 28
    }
29 29
    return sum;
30 30
}
31 31
32 32
/// While-let with nested record and guard.
33 33
fn sumPositive(items: *[Opt]) -> i32 {
34 34
    let mut sum: i32 = 0;
35 35
    let mut i: u32 = 0;
36 36
    while let case Opt::Some { pair: Pair { a, b } } = get(items, i); a > 0 {
37 -
        sum = sum + a + b;
38 -
        i = i + 1;
37 +
        set sum = sum + a + b;
38 +
        set i = i + 1;
39 39
    }
40 40
    return sum;
41 41
}
42 42
43 43
union Dir { North, South }
57 57
/// While-let with nested union variant pattern.
58 58
fn sumNorthSpeeds(items: *[Command]) -> i32 {
59 59
    let mut sum: i32 = 0;
60 60
    let mut i: u32 = 0;
61 61
    while let case Command::Move { dir: Dir::North, speed } = getCmd(items, i) {
62 -
        sum = sum + speed;
63 -
        i = i + 1;
62 +
        set sum = sum + speed;
63 +
        set i = i + 1;
64 64
    }
65 65
    return sum;
66 66
}
67 67
68 68
@default fn main() -> i32 {
test/tests/match.value.copy.rad +3 -3
31 31
32 32
    let case Data::Some { pair } = b.data else {
33 33
        return 1;
34 34
    };
35 35
    // Overwrite the source - binding should be unaffected.
36 -
    b.data = Data::None;
36 +
    set b.data = Data::None;
37 37
38 38
    assert pair.a == 10;
39 39
    assert pair.b == 20;
40 40
    return 0;
41 41
}
45 45
    let mut b = Box {
46 46
        data: Data::Some { pair: Pair { a: 30, b: 40 } },
47 47
    };
48 48
49 49
    if let case Data::Some { pair } = b.data {
50 -
        b.data = Data::None;
50 +
        set b.data = Data::None;
51 51
        assert pair.a == 30;
52 52
        assert pair.b == 40;
53 53
    } else {
54 54
        return 4;
55 55
    }
62 62
        data: Data::Some { pair: Pair { a: 50, b: 60 } },
63 63
    };
64 64
65 65
    match b.data {
66 66
        case Data::Some { pair } => {
67 -
            b.data = Data::None;
67 +
            set b.data = Data::None;
68 68
            assert pair.a == 50;
69 69
            assert pair.b == 60;
70 70
        }
71 71
        case Data::None => {
72 72
            return 7;
test/tests/memzero.result.bug.rad +2 -2
17 17
    // Place the return slot and a guard back-to-back on the stack.
18 18
    let mut guard: u32 = 0;
19 19
20 20
    // Success return should write only the small payload.
21 21
    try fallible(false) catch {
22 -
        guard = 0xDEAD;
22 +
        set guard = 0xDEAD;
23 23
    };
24 -
    guard = 0xDEADBEEF;
24 +
    set guard = 0xDEADBEEF;
25 25
26 26
    if guard <> 0xDEADBEEF {
27 27
        return 1; // Guard was clobbered by an overzealous memzero.
28 28
    }
29 29
    return 0;
test/tests/memzero.union.bug.rad +2 -2
13 13
}
14 14
15 15
@default fn main() -> i32 {
16 16
    let mut f: Frame = Frame { guard1: 0xDEAD, val: undefined, guard2: 0xDEADBEEF };
17 17
18 -
    f.val = Payload::Small(7);
19 -
    f.val = Payload::Big([1, 2, 3]);
18 +
    set f.val = Payload::Small(7);
19 +
    set f.val = Payload::Big([1, 2, 3]);
20 20
21 21
    if f.guard1 == 0xDEAD and f.guard2 == 0xDEADBEEF {
22 22
        return 0;
23 23
    } else {
24 24
        return 1;
test/tests/method.basic.rad +2 -2
9 9
fn (p: *Point) sum() -> i32 {
10 10
    return p.x + p.y;
11 11
}
12 12
13 13
fn (p: *mut Point) translate(dx: i32, dy: i32) {
14 -
    p.x = p.x + dx;
15 -
    p.y = p.y + dy;
14 +
    set p.x = p.x + dx;
15 +
    set p.y = p.y + dy;
16 16
}
17 17
18 18
@default fn main() -> i32 {
19 19
    let mut pt = Point { x: 3, y: 4 };
20 20
test/tests/method.chain.rad +2 -2
5 5
    x: i32,
6 6
    y: i32,
7 7
}
8 8
9 9
fn (b: *mut Builder) setX(x: i32) -> *mut Builder {
10 -
    b.x = x;
10 +
    set b.x = x;
11 11
    return b;
12 12
}
13 13
14 14
fn (b: *mut Builder) setY(y: i32) -> *mut Builder {
15 -
    b.y = y;
15 +
    set b.y = y;
16 16
    return b;
17 17
}
18 18
19 19
fn (b: *Builder) sum() -> i32 {
20 20
    return b.x + b.y;
test/tests/method.multiple.rad +4 -4
13 13
fn (v: *Vec2) dot(other: *Vec2) -> i32 {
14 14
    return v.x * other.x + v.y * other.y;
15 15
}
16 16
17 17
fn (v: *mut Vec2) add(other: *Vec2) {
18 -
    v.x = v.x + other.x;
19 -
    v.y = v.y + other.y;
18 +
    set v.x = v.x + other.x;
19 +
    set v.y = v.y + other.y;
20 20
}
21 21
22 22
fn (v: *mut Vec2) scale(factor: i32) {
23 -
    v.x = v.x * factor;
24 -
    v.y = v.y * factor;
23 +
    set v.x = v.x * factor;
24 +
    set v.y = v.y * factor;
25 25
}
26 26
27 27
@default fn main() -> i32 {
28 28
    let mut a = Vec2 { x: 3, y: 4 };
29 29
    let b = Vec2 { x: 1, y: 2 };
test/tests/method.ptr.rad +1 -1
8 8
fn (c: *Counter) get() -> i32 {
9 9
    return c.value;
10 10
}
11 11
12 12
fn (c: *mut Counter) inc() {
13 -
    c.value = c.value + 1;
13 +
    set c.value = c.value + 1;
14 14
}
15 15
16 16
@default fn main() -> i32 {
17 17
    let mut c = Counter { value: 0 };
18 18
test/tests/method.throws.rad +2 -2
12 12
13 13
fn (p: *mut Parser) advance() throws (ParseError) {
14 14
    if p.pos >= p.len {
15 15
        throw ParseError::Invalid;
16 16
    }
17 -
    p.pos = p.pos + 1;
17 +
    set p.pos = p.pos + 1;
18 18
}
19 19
20 20
fn (p: *Parser) remaining() -> i32 {
21 21
    return p.len - p.pos;
22 22
}
37 37
    assert parser.remaining() == 0;
38 38
39 39
    // Advance past end -- should throw.
40 40
    let mut threw = false;
41 41
    try parser.advance() catch {
42 -
        threw = true;
42 +
        set threw = true;
43 43
    };
44 44
    assert threw;
45 45
46 46
    return 0;
47 47
}
test/tests/multi.throw.catch.typed.rad +2 -2
13 13
}
14 14
15 15
fn caller(flag: i32) -> i32 {
16 16
    let mut r: i32 = 0;
17 17
    try fallible(flag) catch e as ErrA {
18 -
        r = 1;
18 +
        set r = 1;
19 19
    } catch e as ErrB {
20 -
        r = 2;
20 +
        set r = 2;
21 21
    };
22 22
    return r;
23 23
}
test/tests/mutref.call.result.rad added +20 -0
1 +
//! returns: 0
2 +
//! Mutable borrow through a field access on a call result.
3 +
4 +
record Box {
5 +
    x: i32,
6 +
}
7 +
8 +
fn idBox(b: *mut Box) -> *mut Box {
9 +
    return b;
10 +
}
11 +
12 +
@default fn main() -> i32 {
13 +
    let mut b = Box { x: 1 };
14 +
15 +
    let px: *mut i32 = &mut idBox(&mut b).x;
16 +
    set *px = 9;
17 +
18 +
    assert b.x == 9;
19 +
    return 0;
20 +
}
test/tests/mutref.loop.bug.rad +4 -4
9 9
//! The critical case is when the loop executes zero iterations: the merge
10 10
//! block tries to `load` through the initial integer value (not a valid
11 11
//! pointer), crashing the program.
12 12
13 13
fn store(ptr: *mut u32, val: u32) {
14 -
    *ptr = val;
14 +
    set *ptr = val;
15 15
}
16 16
17 17
/// Zero-iteration loop with &mut inside the body.
18 18
/// Without the fix, `val` starts as integer 42 in SSA, but the post-loop
19 19
/// merge tries to `load` through it as if it were a pointer.
20 20
fn testZeroIter(n: u32) -> u32 {
21 21
    let mut val: u32 = 42;
22 22
    let mut i: u32 = 0;
23 23
    while i < n {
24 24
        store(&mut val, val + 1);
25 -
        i += 1;
25 +
        set i += 1;
26 26
    }
27 27
    return val;
28 28
}
29 29
30 30
/// Multiple iterations: accumulate via &mut pointer in a loop.
31 31
fn testMultiIter() -> u32 {
32 32
    let mut acc: u32 = 0;
33 33
    let mut i: u32 = 0;
34 34
    while i < 5 {
35 35
        store(&mut acc, acc + i);
36 -
        i += 1;
36 +
        set i += 1;
37 37
    }
38 38
    return acc;
39 39
}
40 40
41 41
/// Multiple address-taken variables in the same loop.
44 44
    let mut b: u32 = 100;
45 45
    let mut i: u32 = 0;
46 46
    while i < 3 {
47 47
        store(&mut a, a + 1);
48 48
        store(&mut b, b - 1);
49 -
        i += 1;
49 +
        set i += 1;
50 50
    }
51 51
    return a + b;
52 52
}
53 53
54 54
@default fn main() -> i32 {
test/tests/mutref.loop.rad +2 -2
1 1
fn callback(val: u32, ctx: *mut opaque) {
2 2
    let max = ctx as *mut u32;
3 -
    *max = val;
3 +
    set *max = val;
4 4
}
5 5
6 6
fn test() -> i32 {
7 7
    let mut maxReg: u32 = 0;
8 8
    let mut i: u32 = 0;
9 9
    while i < 3 {
10 10
        callback(i, &mut maxReg as *mut opaque);
11 -
        i += 1;
11 +
        set i += 1;
12 12
    }
13 13
    return maxReg as i32;
14 14
}
test/tests/mutref.scalar.rad +1 -1
1 1
fn modify(counter: *mut i32, ret: bool) -> bool {
2 -
    *counter += 1;
2 +
    set *counter += 1;
3 3
    return ret;
4 4
}
5 5
6 6
fn test() -> i32 {
7 7
    let mut x: i32 = 0;
test/tests/opt.assignment.bug.rad +4 -4
12 12
/// Test assigning via if-let pattern.
13 13
fn testIfLetPattern() -> bool {
14 14
    let mut result: ?i32 = nil;
15 15
16 16
    if let val = returnOptional(true) {
17 -
        result = val;
17 +
        set result = val;
18 18
    }
19 19
    if let r = result {
20 20
        return r == 99;
21 21
    }
22 22
    return false;
24 24
25 25
/// Test direct assignment from function.
26 26
fn testDirectAssignment() -> bool {
27 27
    let mut result: ?i32 = nil;
28 28
29 -
    result = returnOptional(true);
29 +
    set result = returnOptional(true);
30 30
31 31
    if let r = result {
32 32
        return r == 99;
33 33
    }
34 34
    return false;
37 37
/// Test if-let pattern with nil return.
38 38
fn testIfLetPatternNil() -> bool {
39 39
    let mut result: ?i32 = nil;
40 40
41 41
    if let val = returnOptional(false) {
42 -
        result = val;
42 +
        set result = val;
43 43
    }
44 44
    if let r = result {
45 45
        return false;
46 46
    }
47 47
    return true;
49 49
50 50
/// Test direct assignment with nil return.
51 51
fn testDirectAssignmentNil() -> bool {
52 52
    let mut result: ?i32 = nil;
53 53
54 -
    result = returnOptional(false);
54 +
    set result = returnOptional(false);
55 55
56 56
    if let r = result {
57 57
        return false;
58 58
    }
59 59
    return true;
test/tests/opt.bug.test.rad +2 -2
16 16
fn testManualPattern() -> bool {
17 17
    let mut result: ?i32 = nil;
18 18
    let opt: ?i32 = 42;
19 19
20 20
    if let val = opt {
21 -
        result = inner(val);
21 +
        set result = inner(val);
22 22
    }
23 23
24 24
    if let r = result {
25 25
        return r == 43;
26 26
    }
42 42
fn testManualPatternNil() -> bool {
43 43
    let mut result: ?i32 = nil;
44 44
    let opt: ?i32 = nil;
45 45
46 46
    if let val = opt {
47 -
        result = inner(val);
47 +
        set result = inner(val);
48 48
    }
49 49
50 50
    if let r = result {
51 51
        return false; // Should be nil
52 52
    }
test/tests/opt.if.let.complex.rad +5 -5
113 113
fn testMultipleNilAssignments() -> bool {
114 114
    let mut opt: ?i32 = 42;
115 115
116 116
    if let x = opt {
117 117
        if x == 42 {
118 -
            opt = nil;
118 +
            set opt = nil;
119 119
            if let y = opt {
120 120
                return false; // Should not reach here after nil assignment
121 121
            } else {
122 -
                opt = 100;
122 +
                set opt = 100;
123 123
                if let z = opt {
124 124
                    return z == 100;
125 125
                } else {
126 126
                    return false;
127 127
                }
242 242
243 243
    if let x = opt {
244 244
        return false;
245 245
    }
246 246
247 -
    opt = 10;
247 +
    set opt = 10;
248 248
    if let x = opt; x == 10 {
249 -
        opt = 20;
249 +
        set opt = 20;
250 250
        if let y = opt; y == 20 {
251 -
            opt = nil;
251 +
            set opt = nil;
252 252
            if let z = opt {
253 253
                return false;
254 254
            } else {
255 255
                return true;
256 256
            }
test/tests/opt.record.eq.rad +3 -3
26 26
    let mut optA: ?Outer = nil;
27 27
    let mut optB: ?Outer = nil;
28 28
    let mut optDiff: ?Outer = nil;
29 29
    let mut optNil: ?Outer = nil;
30 30
31 -
    optA = outerA;
32 -
    optB = outerB;
33 -
    optDiff = outerC;
31 +
    set optA = outerA;
32 +
    set optB = outerB;
33 +
    set optDiff = outerC;
34 34
35 35
    if optA <> optB {
36 36
        return false;
37 37
    }
38 38
    if optA == optDiff {
test/tests/opt.record.rad +3 -3
18 18
    return 0;
19 19
}
20 20
21 21
@default fn main() -> i32 {
22 22
    let mut v: ?Vector = nil;
23 -
    v = Vector { x: 3, y: 4, z: 5 };
23 +
    set v = Vector { x: 3, y: 4, z: 5 };
24 24
25 25
    let mut total: i32 = 0;
26 26
27 27
    if let w = v {
28 -
        total = w.x + w.y + w.z;
28 +
        set total = w.x + w.y + w.z;
29 29
    } else {
30 30
        return 0;
31 31
    }
32 32
33 33
    let wrapper = Wrapper { opt: 7 };
34 34
    if let value = wrapper.opt {
35 -
        total += value;
35 +
        set total += value;
36 36
    } else {
37 37
        return 0;
38 38
    }
39 39
40 40
    let call = takeOptional(9);
test/tests/opt.type.rad +3 -3
2 2
@default fn main() -> i32 {
3 3
    let optSome: ?i32 = 42;
4 4
    let optNone: ?i32 = nil;
5 5
6 6
    let mut optMaybe: ?i32 = nil;
7 -
    optMaybe = optSome;
8 -
    optMaybe = 42;
9 -
    optMaybe = nil;
7 +
    set optMaybe = optSome;
8 +
    set optMaybe = 42;
9 +
    set optMaybe = nil;
10 10
11 11
    return 0;
12 12
}
test/tests/opt.while.let.complex.rad +2 -2
12 12
@default fn main() -> i32 {
13 13
    let mut cur: u32 = 7;
14 14
    let mut sum: u32 = 0;
15 15
16 16
    while let x = decr(cur); x > 1 {
17 -
        sum += x;
18 -
        cur = x;
17 +
        set sum += x;
18 +
        set cur = x;
19 19
    }
20 20
21 21
    // sum should be 6 + 5 + 4 + 3 + 2 = 20
22 22
    assert sum == 20;
23 23
    return 0;
test/tests/placeholder.comprehensive.rad +1 -1
20 20
21 21
    // Test 4: for loop with placeholder for value
22 22
    let arr: [i32; 3] = [1, 2, 3];
23 23
    let mut count: i32 = 0;
24 24
    for _ in &arr[..] {
25 -
        count += 1;
25 +
        set count += 1;
26 26
    }
27 27
    assert count == 3;
28 28
    return 0;
29 29
}
test/tests/pointer.copy.edge.case.rad +5 -5
19 19
    count: u32,
20 20
}
21 21
22 22
fn makeNode(p: *mut Parser, kind: NodeKind) -> *mut Node {
23 23
    let idx: u32 = p.count;
24 -
    p.nodes[idx] = Node {
24 +
    set p.nodes[idx] = Node {
25 25
        span: Span { length: 0 },
26 26
        kind,
27 27
    };
28 -
    p.count = idx + 1;
28 +
    set p.count = idx + 1;
29 29
    return &mut p.nodes[idx];
30 30
}
31 31
32 32
fn setLen(n: *mut Node, len: u32) {
33 -
    n.span.length = len;
33 +
    set n.span.length = len;
34 34
}
35 35
36 36
@default fn main() -> i32 {
37 37
    let mut parser: Parser = Parser {
38 38
        nodes: [Node {
40 40
            kind: NodeKind::Placeholder,
41 41
        }; 1],
42 42
        count: 0,
43 43
    };
44 44
45 -
    parser.count = 0;
46 -
    parser.nodes[0] = Node {
45 +
    set parser.count = 0;
46 +
    set parser.nodes[0] = Node {
47 47
        span: Span { length: 0 },
48 48
        kind: NodeKind::Placeholder,
49 49
    };
50 50
51 51
    let node: *mut Node = makeNode(&mut parser, NodeKind::Bool(true));
test/tests/pointer.slice.store.rad +5 -5
21 21
static STORAGE: [Entry; 2] = undefined;
22 22
static TABLE: Table = undefined;
23 23
static HOLDER: PtrBox = undefined;
24 24
25 25
@default fn main() -> i32 {
26 -
    TABLE.entries = &mut STORAGE[..];
27 -
    TABLE.len     = 0;
26 +
    set TABLE.entries = &mut STORAGE[..];
27 +
    set TABLE.len     = 0;
28 28
29 -
    HOLDER.ptr = &mut TABLE.entries;
29 +
    set HOLDER.ptr = &mut TABLE.entries;
30 30
31 -
    HOLDER.ptr[0] = Entry { a: 1, b: 2, c: 3, d: 4, e: 5 };
31 +
    set HOLDER.ptr[0] = Entry { a: 1, b: 2, c: 3, d: 4, e: 5 };
32 32
33 33
    assert TABLE.entries.len == 2 and TABLE.entries.ptr == &STORAGE[0];
34 34
    assert STORAGE[0].a == 1 and STORAGE[0].e == 5;
35 35
36 -
    HOLDER.ptr[1] = Entry { a: 10, b: 20, c: 30, d: 40, e: 50 };
36 +
    set HOLDER.ptr[1] = Entry { a: 10, b: 20, c: 30, d: 40, e: 50 };
37 37
38 38
    assert TABLE.entries.len == 2 and TABLE.entries.ptr == &STORAGE[0];
39 39
    assert STORAGE[1].c == 30 and STORAGE[1].d == 40;
40 40
    return 0;
41 41
}
test/tests/prog.ackermann.rad +16 -16
40 40
    if m == 3 {
41 41
        // 2^(n+3) - 3
42 42
        let mut power: i32 = 1;
43 43
        let mut i: u32 = 0;
44 44
        while i < n + 3 {
45 -
            power *= 2;
46 -
            i += 1;
45 +
            set power *= 2;
46 +
            set i += 1;
47 47
        }
48 48
        return power - 3;
49 49
    }
50 50
    // For m >= 4, fall back to recursion (only safe for very small n).
51 51
    if n == 0 {
57 57
/// Power of 2 helper.
58 58
fn pow2(exp: u32) -> i32 {
59 59
    let mut result: i32 = 1;
60 60
    let mut i: u32 = 0;
61 61
    while i < exp {
62 -
        result *= 2;
63 -
        i += 1;
62 +
        set result *= 2;
63 +
        set i += 1;
64 64
    }
65 65
    return result;
66 66
}
67 67
68 68
/// Test known small values using the recursive implementation.
99 99
    // Verify m=0 row.
100 100
    let mut n: u32 = 0;
101 101
    while n < 50 {
102 102
        let expected: i32 = n as i32 + 1;
103 103
        assert ackMemo(0, n) == expected;
104 -
        n += 1;
104 +
        set n += 1;
105 105
    }
106 106
107 107
    // Verify m=1 row.
108 -
    n = 0;
108 +
    set n = 0;
109 109
    while n < 50 {
110 110
        let expected: i32 = n as i32 + 2;
111 111
        assert ackMemo(1, n) == expected;
112 -
        n += 1;
112 +
        set n += 1;
113 113
    }
114 114
115 115
    // Verify m=2 row.
116 -
    n = 0;
116 +
    set n = 0;
117 117
    while n < 50 {
118 118
        let expected: i32 = (2 * n + 3) as i32;
119 119
        assert ackMemo(2, n) == expected;
120 -
        n += 1;
120 +
        set n += 1;
121 121
    }
122 122
123 123
    // Verify m=3 row for small n.
124 124
    // A(3,0)=5, A(3,1)=13, A(3,2)=29, A(3,3)=61, A(3,4)=125
125 125
    assert ackMemo(3, 0) == 5;
141 141
    while m <= 3 {
142 142
        let mut n: u32 = 0;
143 143
        // Limit n to keep recursion tractable.
144 144
        let mut limit: u32 = 4;
145 145
        if m <= 2 {
146 -
            limit = 8;
146 +
            set limit = 8;
147 147
        }
148 148
        while n <= limit {
149 149
            let r: i32 = ack(m, n);
150 150
            let memoR: i32 = ackMemo(m, n);
151 151
            if r <> memoR {
152 152
                return (m * 20 + n) as i32 + 1;
153 153
            }
154 -
            n += 1;
154 +
            set n += 1;
155 155
        }
156 -
        m += 1;
156 +
        set m += 1;
157 157
    }
158 158
    return 0;
159 159
}
160 160
161 161
/// Test the Ackermann inverse property: A(m, n) > n for all m, n.
167 167
            let val: i32 = ackMemo(m, n);
168 168
            assert val > n as i32;
169 169
            // A(m, n) < A(m, n+1) (strictly increasing in n).
170 170
            let valNext: i32 = ackMemo(m, n + 1);
171 171
            assert valNext > val;
172 -
            n += 1;
172 +
            set n += 1;
173 173
        }
174 -
        m += 1;
174 +
        set m += 1;
175 175
    }
176 176
177 177
    // A(m, n) < A(m+1, n) (strictly increasing in m).
178 178
    let mut m2: u32 = 0;
179 179
    while m2 < 3 {
180 180
        let mut n2: u32 = 0;
181 181
        while n2 < 10 {
182 182
            let lower: i32 = ackMemo(m2, n2);
183 183
            let upper: i32 = ackMemo(m2 + 1, n2);
184 184
            assert upper > lower;
185 -
            n2 += 1;
185 +
            set n2 += 1;
186 186
        }
187 -
        m2 += 1;
187 +
        set m2 += 1;
188 188
    }
189 189
190 190
    return 0;
191 191
}
192 192
test/tests/prog.bignum.rad +62 -62
7 7
/// Number of limbs per big number (128 bits = 4 x 32-bit words).
8 8
constant LIMBS: u32 = 4;
9 9
10 10
/// Set a big number to a u32 value.
11 11
fn bnFromU32(dst: *mut [u32], val: u32) {
12 -
    dst[0] = val;
12 +
    set dst[0] = val;
13 13
    let mut i: u32 = 1;
14 14
    while i < LIMBS {
15 -
        dst[i] = 0;
16 -
        i += 1;
15 +
        set dst[i] = 0;
16 +
        set i += 1;
17 17
    }
18 18
}
19 19
20 20
/// Set a big number to zero.
21 21
fn bnZero(dst: *mut [u32]) {
22 22
    let mut i: u32 = 0;
23 23
    while i < LIMBS {
24 -
        dst[i] = 0;
25 -
        i += 1;
24 +
        set dst[i] = 0;
25 +
        set i += 1;
26 26
    }
27 27
}
28 28
29 29
/// Copy src to dst.
30 30
fn bnCopy(dst: *mut [u32], src: *[u32]) {
31 31
    let mut i: u32 = 0;
32 32
    while i < LIMBS {
33 -
        dst[i] = src[i];
34 -
        i += 1;
33 +
        set dst[i] = src[i];
34 +
        set i += 1;
35 35
    }
36 36
}
37 37
38 38
/// Compare two big numbers. Returns 0 if equal, 1 if a > b, -1 if a < b.
39 39
fn bnCmp(a: *[u32], b: *[u32]) -> i32 {
46 46
            return -1;
47 47
        }
48 48
        if i == 0 {
49 49
            break;
50 50
        }
51 -
        i -= 1;
51 +
        set i -= 1;
52 52
    }
53 53
    return 0;
54 54
}
55 55
56 56
/// Add two big numbers: dst = a + b. Returns carry (0 or 1).
59 59
    let mut i: u32 = 0;
60 60
    while i < LIMBS {
61 61
        let sumLo: u32 = a[i] + b[i];
62 62
        let mut carry1: u32 = 0;
63 63
        if sumLo < a[i] {
64 -
            carry1 = 1;
64 +
            set carry1 = 1;
65 65
        }
66 66
        let sum: u32 = sumLo + carry;
67 67
        let mut carry2: u32 = 0;
68 68
        if sum < sumLo {
69 -
            carry2 = 1;
69 +
            set carry2 = 1;
70 70
        }
71 -
        dst[i] = sum;
72 -
        carry = carry1 + carry2;
73 -
        i += 1;
71 +
        set dst[i] = sum;
72 +
        set carry = carry1 + carry2;
73 +
        set i += 1;
74 74
    }
75 75
    return carry;
76 76
}
77 77
78 78
/// Subtract two big numbers: dst = a - b. Returns borrow (0 or 1).
81 81
    let mut i: u32 = 0;
82 82
    while i < LIMBS {
83 83
        let diff: u32 = a[i] - b[i];
84 84
        let mut borrow1: u32 = 0;
85 85
        if diff > a[i] {
86 -
            borrow1 = 1;
86 +
            set borrow1 = 1;
87 87
        }
88 88
        let result: u32 = diff - borrow;
89 89
        let mut borrow2: u32 = 0;
90 90
        if result > diff {
91 -
            borrow2 = 1;
91 +
            set borrow2 = 1;
92 92
        }
93 -
        dst[i] = result;
94 -
        borrow = borrow1 + borrow2;
95 -
        i += 1;
93 +
        set dst[i] = result;
94 +
        set borrow = borrow1 + borrow2;
95 +
        set i += 1;
96 96
    }
97 97
    return borrow;
98 98
}
99 99
100 100
/// Multiply two LIMBS-word numbers, producing a 2*LIMBS-word result in wide.
101 101
fn bnMul(wide: *mut [u32], a: *[u32], b: *[u32]) {
102 102
    let mut i: u32 = 0;
103 103
    while i < LIMBS * 2 {
104 -
        wide[i] = 0;
105 -
        i += 1;
104 +
        set wide[i] = 0;
105 +
        set i += 1;
106 106
    }
107 107
108 -
    i = 0;
108 +
    set i = 0;
109 109
    while i < LIMBS {
110 110
        let mut carry: u32 = 0;
111 111
        let mut j: u32 = 0;
112 112
        while j < LIMBS {
113 113
            let al: u32 = a[i] & 0xFFFF;
121 121
            let hh: u32 = ah * bh;
122 122
123 123
            let mid: u32 = lh + hl;
124 124
            let mut midCarry: u32 = 0;
125 125
            if mid < lh {
126 -
                midCarry = 1;
126 +
                set midCarry = 1;
127 127
            }
128 128
129 129
            let lo: u32 = ll + (mid << 16);
130 130
            let mut loCarry: u32 = 0;
131 131
            if lo < ll {
132 -
                loCarry = 1;
132 +
                set loCarry = 1;
133 133
            }
134 134
            let hi: u32 = hh + (mid >> 16) + (midCarry << 16) + loCarry;
135 135
136 136
            let sum1: u32 = wide[i + j] + lo;
137 137
            let mut c1: u32 = 0;
138 138
            if sum1 < wide[i + j] {
139 -
                c1 = 1;
139 +
                set c1 = 1;
140 140
            }
141 141
            let sum2: u32 = sum1 + carry;
142 142
            let mut c2: u32 = 0;
143 143
            if sum2 < sum1 {
144 -
                c2 = 1;
144 +
                set c2 = 1;
145 145
            }
146 -
            wide[i + j] = sum2;
147 -
            carry = hi + c1 + c2;
146 +
            set wide[i + j] = sum2;
147 +
            set carry = hi + c1 + c2;
148 148
149 -
            j += 1;
149 +
            set j += 1;
150 150
        }
151 -
        wide[i + LIMBS] += carry;
152 -
        i += 1;
151 +
        set wide[i + LIMBS] += carry;
152 +
        set i += 1;
153 153
    }
154 154
}
155 155
156 156
/// Left shift a big number by 1 bit.
157 157
fn bnShl1(dst: *mut [u32], src: *[u32]) {
158 158
    let mut carry: u32 = 0;
159 159
    let mut i: u32 = 0;
160 160
    while i < LIMBS {
161 161
        let newCarry: u32 = src[i] >> 31;
162 -
        dst[i] = (src[i] << 1) | carry;
163 -
        carry = newCarry;
164 -
        i += 1;
162 +
        set dst[i] = (src[i] << 1) | carry;
163 +
        set carry = newCarry;
164 +
        set i += 1;
165 165
    }
166 166
}
167 167
168 168
/// Right shift a big number by 1 bit.
169 169
fn bnShr1(dst: *mut [u32], src: *[u32]) {
170 170
    let mut carry: u32 = 0;
171 171
    let mut i: u32 = LIMBS;
172 172
    while i > 0 {
173 -
        i -= 1;
173 +
        set i -= 1;
174 174
        let newCarry: u32 = src[i] & 1;
175 -
        dst[i] = (src[i] >> 1) | (carry << 31);
176 -
        carry = newCarry;
175 +
        set dst[i] = (src[i] >> 1) | (carry << 31);
176 +
        set carry = newCarry;
177 177
    }
178 178
}
179 179
180 180
/// Test basic addition.
181 181
fn testAdd() -> i32 {
206 206
    let mut a: [u32; 4] = [0; 4];
207 207
    let mut b: [u32; 4] = [0; 4];
208 208
    let mut c: [u32; 4] = [0; 4];
209 209
210 210
    bnZero(&mut a[..]);
211 -
    a[1] = 1;
211 +
    set a[1] = 1;
212 212
    bnFromU32(&mut b[..], 1);
213 213
    let borrow: u32 = bnSub(&mut c[..], &a[..], &b[..]);
214 214
215 215
    assert borrow == 0;
216 216
    assert c[0] == 0xFFFFFFFF;
247 247
    let mut a: [u32; 4] = [0; 4];
248 248
    let mut b: [u32; 4] = [0; 4];
249 249
    let mut c: [u32; 4] = [0; 4];
250 250
    let mut d: [u32; 4] = [0; 4];
251 251
252 -
    a[0] = 0x12345678;
253 -
    a[1] = 0xABCDEF01;
254 -
    a[2] = 0x9876FEDC;
255 -
    a[3] = 0x01020304;
252 +
    set a[0] = 0x12345678;
253 +
    set a[1] = 0xABCDEF01;
254 +
    set a[2] = 0x9876FEDC;
255 +
    set a[3] = 0x01020304;
256 256
257 -
    b[0] = 0xFEDCBA98;
258 -
    b[1] = 0x76543210;
259 -
    b[2] = 0x11223344;
260 -
    b[3] = 0x00AABB00;
257 +
    set b[0] = 0xFEDCBA98;
258 +
    set b[1] = 0x76543210;
259 +
    set b[2] = 0x11223344;
260 +
    set b[3] = 0x00AABB00;
261 261
262 262
    bnAdd(&mut c[..], &a[..], &b[..]);
263 263
    bnSub(&mut d[..], &c[..], &b[..]);
264 264
265 265
    assert bnCmp(&d[..], &a[..]) == 0;
296 296
fn testLargeMultiply() -> i32 {
297 297
    let mut a: [u32; 4] = [0; 4];
298 298
    let mut b: [u32; 4] = [0; 4];
299 299
    let mut wide: [u32; 8] = [0; 8];
300 300
301 -
    a[0] = 0xFFFFFFFF;
302 -
    a[1] = 0xFFFFFFFF;
303 -
    a[2] = 0;
304 -
    a[3] = 0;
301 +
    set a[0] = 0xFFFFFFFF;
302 +
    set a[1] = 0xFFFFFFFF;
303 +
    set a[2] = 0;
304 +
    set a[3] = 0;
305 305
306 306
    bnFromU32(&mut b[..], 1);
307 307
    bnMul(&mut wide[..], &a[..], &b[..]);
308 308
    assert wide[0] == 0xFFFFFFFF;
309 309
    assert wide[1] == 0xFFFFFFFF;
310 310
    assert wide[2] == 0;
311 311
312 312
    bnZero(&mut a[..]);
313 -
    a[1] = 1;
313 +
    set a[1] = 1;
314 314
    bnZero(&mut b[..]);
315 -
    b[1] = 1;
315 +
    set b[1] = 1;
316 316
    bnMul(&mut wide[..], &a[..], &b[..]);
317 317
    assert wide[0] == 0;
318 318
    assert wide[1] == 0;
319 319
    assert wide[2] == 1;
320 320
    assert wide[3] == 0;
326 326
fn testFibonacci() -> i32 {
327 327
    let mut fibA: [u32; 4] = [0; 4];
328 328
    let mut fibB: [u32; 4] = [0; 4];
329 329
    let mut fibC: [u32; 4] = [0; 4];
330 330
331 -
    fibA[0] = 0;
332 -
    fibB[0] = 1;
331 +
    set fibA[0] = 0;
332 +
    set fibB[0] = 1;
333 333
334 334
    let mut i: u32 = 2;
335 335
    while i <= 48 {
336 336
        bnAdd(&mut fibC[..], &fibA[..], &fibB[..]);
337 337
        bnCopy(&mut fibA[..], &fibB[..]);
338 338
        bnCopy(&mut fibB[..], &fibC[..]);
339 -
        i += 1;
339 +
        set i += 1;
340 340
    }
341 341
342 342
    assert fibB[0] == 0x1E8D0A40;
343 343
    assert fibB[1] == 0x01;
344 344
345 345
    let mut fa: [u32; 4] = [0; 4];
346 346
    let mut fb: [u32; 4] = [0; 4];
347 347
    let mut fc: [u32; 4] = [0; 4];
348 -
    fa[0] = 0;
349 -
    fb[0] = 1;
350 -
    i = 2;
348 +
    set fa[0] = 0;
349 +
    set fb[0] = 1;
350 +
    set i = 2;
351 351
    while i <= 47 {
352 352
        bnAdd(&mut fc[..], &fa[..], &fb[..]);
353 353
        bnCopy(&mut fa[..], &fb[..]);
354 354
        bnCopy(&mut fb[..], &fc[..]);
355 -
        i += 1;
355 +
        set i += 1;
356 356
    }
357 357
    bnAdd(&mut fc[..], &fa[..], &fb[..]);
358 358
    assert bnCmp(&fc[..], &fibB[..]) == 0;
359 359
360 360
    return 0;
372 372
    assert bnCmp(&b[..], &a[..]) == 1;
373 373
    assert bnCmp(&a[..], &a[..]) == 0;
374 374
375 375
    bnZero(&mut a[..]);
376 376
    bnZero(&mut b[..]);
377 -
    a[3] = 1;
378 -
    b[0] = 0xFFFFFFFF;
379 -
    b[1] = 0xFFFFFFFF;
380 -
    b[2] = 0xFFFFFFFF;
377 +
    set a[3] = 1;
378 +
    set b[0] = 0xFFFFFFFF;
379 +
    set b[1] = 0xFFFFFFFF;
380 +
    set b[2] = 0xFFFFFFFF;
381 381
    assert bnCmp(&a[..], &b[..]) == 1;
382 382
383 383
    return 0;
384 384
}
385 385
test/tests/prog.binsearch.rad +2 -2
12 12
        let val: i32 = data[mid as u32];
13 13
14 14
        if val == target {
15 15
            return mid as u32;
16 16
        } else if val < target {
17 -
            lo = mid + 1;
17 +
            set lo = mid + 1;
18 18
        } else {
19 -
            hi = mid - 1;
19 +
            set hi = mid - 1;
20 20
        }
21 21
    }
22 22
    return nil;
23 23
}
24 24
test/tests/prog.bubblesort.rad +7 -7
9 9
        let mut swapped: bool = false;
10 10
        let mut i: u32 = 0;
11 11
        while i < n - 1 {
12 12
            if data[i] > data[i + 1] {
13 13
                let tmp: i32 = data[i];
14 -
                data[i] = data[i + 1];
15 -
                data[i + 1] = tmp;
16 -
                swapped = true;
14 +
                set data[i] = data[i + 1];
15 +
                set data[i + 1] = tmp;
16 +
                set swapped = true;
17 17
            }
18 -
            i += 1;
18 +
            set i += 1;
19 19
        }
20 20
        if not swapped {
21 21
            // Already sorted, early exit.
22 22
            return;
23 23
        }
24 -
        n -= 1;
24 +
        set n -= 1;
25 25
    }
26 26
}
27 27
28 28
/// Verify the array is sorted in ascending order.
29 29
fn isSorted(data: *[i32]) -> bool {
32 32
        if let p = prev {
33 33
            if p > val {
34 34
                return false;
35 35
            }
36 36
        }
37 -
        prev = val;
37 +
        set prev = val;
38 38
    }
39 39
    return true;
40 40
}
41 41
42 42
/// Compute the sum of all elements.
43 43
fn sum(data: *[i32]) -> i32 {
44 44
    let mut total: i32 = 0;
45 45
    for val in data {
46 -
        total += val;
46 +
        set total += val;
47 47
    }
48 48
    return total;
49 49
}
50 50
51 51
/// Verify specific positions in the sorted output.
test/tests/prog.cordic.rad +13 -13
38 38
    while i < ITERATIONS {
39 39
        let dx: i32 = x >> i as i32;
40 40
        let dy: i32 = y >> i as i32;
41 41
42 42
        if z >= 0 {
43 -
            x -= dy;
44 -
            y += dx;
45 -
            z -= atanTable[i];
43 +
            set x -= dy;
44 +
            set y += dx;
45 +
            set z -= atanTable[i];
46 46
        } else {
47 -
            x += dy;
48 -
            y -= dx;
49 -
            z += atanTable[i];
47 +
            set x += dy;
48 +
            set y -= dx;
49 +
            set z += atanTable[i];
50 50
        }
51 -
        i += 1;
51 +
        set i += 1;
52 52
    }
53 53
54 54
    return CosSin { cos: x, sin: y };
55 55
}
56 56
58 58
fn cosSin(angle: i32, atanTable: *[i32]) -> CosSin {
59 59
    let mut a: i32 = angle;
60 60
61 61
    // Reduce to [-pi, pi].
62 62
    while a > PI {
63 -
        a -= 2 * PI;
63 +
        set a -= 2 * PI;
64 64
    }
65 65
    while a < 0 - PI {
66 -
        a += 2 * PI;
66 +
        set a += 2 * PI;
67 67
    }
68 68
69 69
    // If in [pi/2, pi], use cos(a) = -cos(pi-a), sin(a) = sin(pi-a).
70 70
    if a > HALF_PI {
71 71
        let r: CosSin = cordicRotate(PI - a, atanTable);
92 92
fn fpmul(a: i32, b: i32) -> i32 {
93 93
    // Determine sign and work with magnitudes.
94 94
    let neg: bool = (a < 0) <> (b < 0);
95 95
    let mut ua: u32 = a as u32;
96 96
    if a < 0 {
97 -
        ua = (0 - a) as u32;
97 +
        set ua = (0 - a) as u32;
98 98
    }
99 99
    let mut ub: u32 = b as u32;
100 100
    if b < 0 {
101 -
        ub = (0 - b) as u32;
101 +
        set ub = (0 - b) as u32;
102 102
    }
103 103
104 104
    // Split into 16-bit halves: ua = ah:al, ub = bh:bl.
105 105
    let al: u32 = ua & 0xFFFF;
106 106
    let ah: u32 = ua >> 16;
170 170
        let sum: i32 = sin2 + cos2;
171 171
        let err: i32 = abs(sum - SCALE);
172 172
173 173
        // Allow ~2% error due to fixed-point precision.
174 174
        assert err <= 1311;
175 -
        i += step;
175 +
        set i += step;
176 176
    }
177 177
    return 0;
178 178
}
179 179
180 180
/// Test symmetry: sin(-x) = -sin(x), cos(-x) = cos(x).
190 190
191 191
        // cos(-x) should equal cos(x).
192 192
        assert abs(rPos.cos - rNeg.cos) <= 655;
193 193
        // sin(-x) should equal -sin(x).
194 194
        assert abs(rPos.sin + rNeg.sin) <= 655;
195 -
        i += 1;
195 +
        set i += 1;
196 196
    }
197 197
    return 0;
198 198
}
199 199
200 200
/// Test specific known value: cos(pi/3) = 0.5, sin(pi/3) = 0.866.
test/tests/prog.crc32.rad +9 -9
9 9
    while i < 256 {
10 10
        let mut crc: u32 = i;
11 11
        let mut j: u32 = 0;
12 12
        while j < 8 {
13 13
            if crc & 1 == 1 {
14 -
                crc = (crc >> 1) ^ 0xEDB88320;
14 +
                set crc = (crc >> 1) ^ 0xEDB88320;
15 15
            } else {
16 -
                crc >>= 1;
16 +
                set crc >>= 1;
17 17
            }
18 -
            j += 1;
18 +
            set j += 1;
19 19
        }
20 -
        table[i] = crc;
21 -
        i += 1;
20 +
        set table[i] = crc;
21 +
        set i += 1;
22 22
    }
23 23
}
24 24
25 25
/// Compute CRC-32 of a byte slice.
26 26
fn crc32(table: *[u32], data: *[u8]) -> u32 {
27 27
    let mut crc: u32 = 0xFFFFFFFF;
28 28
    let mut i: u32 = 0;
29 29
    while i < data.len {
30 30
        let byte: u8 = data[i];
31 31
        let index: u32 = (crc ^ byte as u32) & 0xFF;
32 -
        crc = (crc >> 8) ^ table[index];
33 -
        i += 1;
32 +
        set crc = (crc >> 8) ^ table[index];
33 +
        set i += 1;
34 34
    }
35 35
    return crc ^ 0xFFFFFFFF;
36 36
}
37 37
38 38
/// Test the lookup table has been built correctly.
65 65
fn testIncremental(table: *[u32]) -> i32 {
66 66
    // Build a 32-byte buffer with values 0..31.
67 67
    let mut buf: [u8; 32] = [0; 32];
68 68
    let mut i: u32 = 0;
69 69
    while i < 32 {
70 -
        buf[i] = i as u8;
71 -
        i += 1;
70 +
        set buf[i] = i as u8;
71 +
        set i += 1;
72 72
    }
73 73
    let crcFull = crc32(table, &buf[..]);
74 74
75 75
    // CRC should be non-zero and deterministic.
76 76
    assert crcFull <> 0;
test/tests/prog.dijkstra.rad +39 -39
21 21
    heapSize: u32,
22 22
}
23 23
24 24
fn heapSwap(g: *mut Graph, i: u32, j: u32) {
25 25
    let tmp: HeapEntry = g.heap[i];
26 -
    g.heap[i] = g.heap[j];
27 -
    g.heap[j] = tmp;
26 +
    set g.heap[i] = g.heap[j];
27 +
    set g.heap[j] = tmp;
28 28
}
29 29
30 30
fn siftUp(g: *mut Graph, pos: u32) {
31 31
    let mut i: u32 = pos;
32 32
    while i > 0 {
33 33
        let parent: u32 = (i - 1) / 2;
34 34
        if g.heap[i].dist < g.heap[parent].dist {
35 35
            heapSwap(g, i, parent);
36 -
            i = parent;
36 +
            set i = parent;
37 37
        } else {
38 38
            return;
39 39
        }
40 40
    }
41 41
}
46 46
        let left: u32 = 2 * i + 1;
47 47
        let right: u32 = 2 * i + 2;
48 48
        let mut smallest: u32 = i;
49 49
50 50
        if left < g.heapSize and g.heap[left].dist < g.heap[smallest].dist {
51 -
            smallest = left;
51 +
            set smallest = left;
52 52
        }
53 53
        if right < g.heapSize and g.heap[right].dist < g.heap[smallest].dist {
54 -
            smallest = right;
54 +
            set smallest = right;
55 55
        }
56 56
        if smallest == i {
57 57
            return;
58 58
        }
59 59
        heapSwap(g, i, smallest);
60 -
        i = smallest;
60 +
        set i = smallest;
61 61
    }
62 62
}
63 63
64 64
fn heapPush(g: *mut Graph, dist: u32, node: u32) {
65 -
    g.heap[g.heapSize] = HeapEntry { dist, node };
66 -
    g.heapSize += 1;
65 +
    set g.heap[g.heapSize] = HeapEntry { dist, node };
66 +
    set g.heapSize += 1;
67 67
    siftUp(g, g.heapSize - 1);
68 68
}
69 69
70 70
/// Pop from the heap. Returns nil if the heap is empty.
71 71
fn heapPop(g: *mut Graph) -> ?HeapEntry {
72 72
    if g.heapSize == 0 {
73 73
        return nil;
74 74
    }
75 75
    let result: HeapEntry = g.heap[0];
76 -
    g.heapSize -= 1;
77 -
    g.heap[0] = g.heap[g.heapSize];
76 +
    set g.heapSize -= 1;
77 +
    set g.heap[0] = g.heap[g.heapSize];
78 78
    if g.heapSize > 0 {
79 79
        siftDown(g, 0);
80 80
    }
81 81
    return result;
82 82
}
83 83
84 84
fn addEdge(g: *mut Graph, from: u32, to: u32, weight: u32) {
85 -
    g.adj[from][to] = weight;
85 +
    set g.adj[from][to] = weight;
86 86
}
87 87
88 88
fn addBidiEdge(g: *mut Graph, from: u32, to: u32, weight: u32) {
89 -
    g.adj[from][to] = weight;
90 -
    g.adj[to][from] = weight;
89 +
    set g.adj[from][to] = weight;
90 +
    set g.adj[to][from] = weight;
91 91
}
92 92
93 93
fn resetGraph(g: *mut Graph, n: u32) {
94 -
    g.numNodes = n;
94 +
    set g.numNodes = n;
95 95
    let mut i: u32 = 0;
96 96
    while i < MAX_NODES {
97 97
        let mut j: u32 = 0;
98 98
        while j < MAX_NODES {
99 -
            g.adj[i][j] = INF;
100 -
            j += 1;
99 +
            set g.adj[i][j] = INF;
100 +
            set j += 1;
101 101
        }
102 -
        g.dist[i] = INF;
103 -
        g.prev[i] = -1;
104 -
        g.visited[i] = false;
105 -
        i += 1;
102 +
        set g.dist[i] = INF;
103 +
        set g.prev[i] = -1;
104 +
        set g.visited[i] = false;
105 +
        set i += 1;
106 106
    }
107 -
    g.heapSize = 0;
107 +
    set g.heapSize = 0;
108 108
}
109 109
110 110
/// Get the predecessor as an optional; -1 means no predecessor.
111 111
fn getPrev(g: *Graph, node: u32) -> ?u32 {
112 112
    let p = g.prev[node];
115 115
    }
116 116
    return p as u32;
117 117
}
118 118
119 119
fn dijkstra(g: *mut Graph, source: u32) {
120 -
    g.dist[source] = 0;
120 +
    set g.dist[source] = 0;
121 121
    heapPush(g, 0, source);
122 122
123 123
    while let entry = heapPop(g) {
124 124
        let u: u32 = entry.node;
125 125
126 126
        if g.visited[u] {
127 127
            continue;
128 128
        }
129 -
        g.visited[u] = true;
129 +
        set g.visited[u] = true;
130 130
131 131
        let mut v: u32 = 0;
132 132
        while v < g.numNodes {
133 133
            if g.adj[u][v] <> INF and not g.visited[v] {
134 134
                let newDist: u32 = g.dist[u] + g.adj[u][v];
135 135
                if newDist < g.dist[v] {
136 -
                    g.dist[v] = newDist;
137 -
                    g.prev[v] = u as i32;
136 +
                    set g.dist[v] = newDist;
137 +
                    set g.prev[v] = u as i32;
138 138
                    heapPush(g, newDist, v);
139 139
                }
140 140
            }
141 -
            v += 1;
141 +
            set v += 1;
142 142
        }
143 143
    }
144 144
}
145 145
146 146
/// Reconstruct the shortest path from source to target.
147 147
fn reconstructPath(g: *Graph, target: u32, path: *mut [u32]) -> u32 {
148 148
    let mut len: u32 = 0;
149 149
150 -
    path[len] = target;
151 -
    len += 1;
150 +
    set path[len] = target;
151 +
    set len += 1;
152 152
153 153
    let mut cur: ?u32 = getPrev(g, target);
154 154
    while let node = cur {
155 -
        path[len] = node;
156 -
        len += 1;
157 -
        cur = getPrev(g, node);
155 +
        set path[len] = node;
156 +
        set len += 1;
157 +
        set cur = getPrev(g, node);
158 158
    }
159 159
160 160
    // Reverse the path.
161 161
    let mut a: u32 = 0;
162 162
    let mut b: u32 = len - 1;
163 163
    while a < b {
164 164
        let tmp: u32 = path[a];
165 -
        path[a] = path[b];
166 -
        path[b] = tmp;
167 -
        a += 1;
168 -
        b -= 1;
165 +
        set path[a] = path[b];
166 +
        set path[b] = tmp;
167 +
        set a += 1;
168 +
        set b -= 1;
169 169
    }
170 170
    return len;
171 171
}
172 172
173 173
fn testLinear(g: *mut Graph) -> i32 {
244 244
        let mut j: u32 = 0;
245 245
        while j < 8 {
246 246
            if i <> j {
247 247
                let mut diff: u32 = j - i;
248 248
                if i > j {
249 -
                    diff = i - j;
249 +
                    set diff = i - j;
250 250
                }
251 251
                addEdge(g, i, j, diff * 3 + 1);
252 252
            }
253 -
            j += 1;
253 +
            set j += 1;
254 254
        }
255 -
        i += 1;
255 +
        set i += 1;
256 256
    }
257 257
258 258
    dijkstra(g, 0);
259 259
260 260
    let mut k: u32 = 1;
261 261
    while k < 8 {
262 262
        let expected: u32 = k * 3 + 1;
263 263
        if g.dist[k] <> expected {
264 264
            return k as i32;
265 265
        }
266 -
        k += 1;
266 +
        set k += 1;
267 267
    }
268 268
269 269
    return 0;
270 270
}
271 271
test/tests/prog.eval.rad +4 -4
33 33
}
34 34
35 35
/// Allocate a new node, returning its index.
36 36
fn newNode(pool: *mut Pool, expr: Expr) -> u32 {
37 37
    let idx = pool.count;
38 -
    pool.nodes[idx] = expr;
39 -
    pool.count += 1;
38 +
    set pool.nodes[idx] = expr;
39 +
    set pool.count += 1;
40 40
    return idx;
41 41
}
42 42
43 43
/// Convenience constructors.
44 44
fn num(pool: *mut Pool, n: i32) -> u32 {
120 120
    }
121 121
}
122 122
123 123
/// Reset the node pool.
124 124
fn reset(pool: *mut Pool) {
125 -
    pool.count = 0;
125 +
    set pool.count = 0;
126 126
}
127 127
128 128
/// Test 1: Simple addition: 3 + 4 = 7
129 129
fn testSimpleAdd(pool: *mut Pool) -> i32 {
130 130
    reset(pool);
167 167
fn testDeep(pool: *mut Pool) -> i32 {
168 168
    reset(pool);
169 169
    let mut root = num(pool, 1);
170 170
    let values: [i32; 7] = [2, 3, 4, 5, 6, 7, 8];
171 171
    for v in values {
172 -
        root = add(pool, root, num(pool, v));
172 +
        set root = add(pool, root, num(pool, v));
173 173
    }
174 174
    assert try! eval(&pool.nodes[..], root) == 36;
175 175
    assert countNodes(&pool.nodes[..], root) == 15;
176 176
    return 0;
177 177
}
test/tests/prog.hanoi.rad +7 -7
21 21
}
22 22
23 23
/// Record a move.
24 24
fn recordMove(ml: *mut MoveLog, disk: u32, from: u32, to: u32) {
25 25
    if ml.count < MAX_MOVES {
26 -
        ml.moves[ml.count] = Move { disk, from, to };
27 -
        ml.count += 1;
26 +
        set ml.moves[ml.count] = Move { disk, from, to };
27 +
        set ml.count += 1;
28 28
    }
29 29
}
30 30
31 31
/// Solve Tower of Hanoi recursively.
32 32
/// Move `n` disks from peg `from` to peg `to` using `aux` as auxiliary.
78 78
        // Check that the top disk is larger than the one being placed.
79 79
        if pegs.stacks[peg][t - 1] < disk {
80 80
            return false;
81 81
        }
82 82
    }
83 -
    pegs.stacks[peg][t] = disk;
84 -
    pegs.top[peg] = t + 1;
83 +
    set pegs.stacks[peg][t] = disk;
84 +
    set pegs.top[peg] = t + 1;
85 85
    return true;
86 86
}
87 87
88 88
fn pegPop(pegs: *mut Pegs, peg: u32) -> u32 {
89 89
    let t = pegs.top[peg];
90 90
    if t == 0 {
91 91
        // Should not happen in a valid solution.
92 92
        return 0;
93 93
    }
94 -
    pegs.top[peg] = t - 1;
94 +
    set pegs.top[peg] = t - 1;
95 95
    return pegs.stacks[peg][t - 1];
96 96
}
97 97
98 98
/// Simulate the peg state to verify correctness.
99 99
/// Replay all moves and check:
110 110
    while d >= 1 {
111 111
        assert pegPush(&mut pegs, 0, d);
112 112
        if d == 0 {
113 113
            break;
114 114
        }
115 -
        d -= 1;
115 +
        set d -= 1;
116 116
    }
117 117
118 118
    // Replay all moves.
119 119
    let mut i: u32 = 0;
120 120
    while i < ml.count {
121 121
        let m = ml.moves[i];
122 122
        let disk = pegPop(&mut pegs, m.from);
123 123
        assert disk == m.disk;
124 124
        assert pegPush(&mut pegs, m.to, disk);
125 -
        i += 1;
125 +
        set i += 1;
126 126
    }
127 127
128 128
    // All disks should be on peg 1.
129 129
    assert pegs.top[0] == 0;
130 130
    assert pegs.top[1] == NUM_DISKS;
test/tests/prog.huffman.rad +39 -39
35 35
    bitCount: u32,
36 36
}
37 37
38 38
fn newLeaf(s: *mut HuffState, freq: u32, symbol: u32) -> u32 {
39 39
    let idx: u32 = s.nodeCount;
40 -
    s.nodes[idx] = HNode { freq, kind: HNodeKind::Leaf(symbol), left: NIL, right: NIL };
41 -
    s.nodeCount += 1;
40 +
    set s.nodes[idx] = HNode { freq, kind: HNodeKind::Leaf(symbol), left: NIL, right: NIL };
41 +
    set s.nodeCount += 1;
42 42
    return idx;
43 43
}
44 44
45 45
fn newInterior(s: *mut HuffState, freq: u32, left: u32, right: u32) -> u32 {
46 46
    let idx: u32 = s.nodeCount;
47 -
    s.nodes[idx] = HNode { freq, kind: HNodeKind::Interior, left, right };
48 -
    s.nodeCount += 1;
47 +
    set s.nodes[idx] = HNode { freq, kind: HNodeKind::Interior, left, right };
48 +
    set s.nodeCount += 1;
49 49
    return idx;
50 50
}
51 51
52 52
/// Get the symbol from a node, or nil if it's an interior node.
53 53
fn nodeSymbol(node: *HNode) -> ?u32 {
61 61
    }
62 62
}
63 63
64 64
fn heapSwap(s: *mut HuffState, i: u32, j: u32) {
65 65
    let tmp: u32 = s.heap[i];
66 -
    s.heap[i] = s.heap[j];
67 -
    s.heap[j] = tmp;
66 +
    set s.heap[i] = s.heap[j];
67 +
    set s.heap[j] = tmp;
68 68
}
69 69
70 70
fn heapFreq(s: *HuffState, i: u32) -> u32 {
71 71
    return s.nodes[s.heap[i]].freq;
72 72
}
75 75
    let mut i: u32 = pos;
76 76
    while i > 0 {
77 77
        let parent: u32 = (i - 1) / 2;
78 78
        if heapFreq(s, i) < heapFreq(s, parent) {
79 79
            heapSwap(s, i, parent);
80 -
            i = parent;
80 +
            set i = parent;
81 81
        } else {
82 82
            return;
83 83
        }
84 84
    }
85 85
}
90 90
        let left: u32 = 2 * i + 1;
91 91
        let right: u32 = 2 * i + 2;
92 92
        let mut smallest: u32 = i;
93 93
94 94
        if left < s.heapSize and heapFreq(s, left) < heapFreq(s, smallest) {
95 -
            smallest = left;
95 +
            set smallest = left;
96 96
        }
97 97
        if right < s.heapSize and heapFreq(s, right) < heapFreq(s, smallest) {
98 -
            smallest = right;
98 +
            set smallest = right;
99 99
        }
100 100
        if smallest == i {
101 101
            return;
102 102
        }
103 103
        heapSwap(s, i, smallest);
104 -
        i = smallest;
104 +
        set i = smallest;
105 105
    }
106 106
}
107 107
108 108
fn heapPush(s: *mut HuffState, nodeIdx: u32) {
109 -
    s.heap[s.heapSize] = nodeIdx;
110 -
    s.heapSize += 1;
109 +
    set s.heap[s.heapSize] = nodeIdx;
110 +
    set s.heapSize += 1;
111 111
    siftUp(s, s.heapSize - 1);
112 112
}
113 113
114 114
fn heapPop(s: *mut HuffState) -> u32 {
115 115
    let result: u32 = s.heap[0];
116 -
    s.heapSize -= 1;
117 -
    s.heap[0] = s.heap[s.heapSize];
116 +
    set s.heapSize -= 1;
117 +
    set s.heap[0] = s.heap[s.heapSize];
118 118
    if s.heapSize > 0 {
119 119
        siftDown(s, 0);
120 120
    }
121 121
    return result;
122 122
}
123 123
124 124
fn buildTree(s: *mut HuffState, freqs: *[u32]) -> u32 {
125 -
    s.nodeCount = 0;
126 -
    s.heapSize = 0;
125 +
    set s.nodeCount = 0;
126 +
    set s.heapSize = 0;
127 127
128 128
    for freq, sym in freqs {
129 129
        if freq > 0 {
130 130
            let idx: u32 = newLeaf(s, freq, sym);
131 131
            heapPush(s, idx);
144 144
}
145 145
146 146
fn generateCodes(s: *mut HuffState, nodeIdx: u32, code: u32, depth: u32) {
147 147
    match s.nodes[nodeIdx].kind {
148 148
        case HNodeKind::Leaf(sym) => {
149 -
            s.codeBits[sym] = code;
150 -
            s.codeLen[sym] = depth;
149 +
            set s.codeBits[sym] = code;
150 +
            set s.codeLen[sym] = depth;
151 151
        }
152 152
        case HNodeKind::Interior => {
153 153
            if s.nodes[nodeIdx].left <> NIL {
154 154
                generateCodes(s, s.nodes[nodeIdx].left, code << 1, depth + 1);
155 155
            }
162 162
163 163
fn writeBit(s: *mut HuffState, bit: u32) {
164 164
    let byteIdx: u32 = s.bitCount / 8;
165 165
    let bitIdx: u32 = 7 - (s.bitCount % 8);
166 166
    if bit == 1 {
167 -
        s.bitstream[byteIdx] |= (1 as u8 << bitIdx as u8);
167 +
        set s.bitstream[byteIdx] |= (1 as u8 << bitIdx as u8);
168 168
    }
169 -
    s.bitCount += 1;
169 +
    set s.bitCount += 1;
170 170
}
171 171
172 172
fn readBit(s: *HuffState, pos: u32) -> u32 {
173 173
    let byteIdx: u32 = pos / 8;
174 174
    let bitIdx: u32 = 7 - (pos % 8);
175 175
    return (s.bitstream[byteIdx] >> bitIdx as u8) as u32 & 1;
176 176
}
177 177
178 178
fn encode(s: *mut HuffState, msg: *[u32]) {
179 -
    s.bitCount = 0;
179 +
    set s.bitCount = 0;
180 180
    let mut i: u32 = 0;
181 181
    while i < MAX_BITS {
182 -
        s.bitstream[i] = 0;
183 -
        i += 1;
182 +
        set s.bitstream[i] = 0;
183 +
        set i += 1;
184 184
    }
185 185
186 186
    for sym in msg {
187 187
        let bits: u32 = s.codeBits[sym];
188 188
        let len: u32 = s.codeLen[sym];
189 189
        let mut b: u32 = 0;
190 190
        while b < len {
191 191
            let bit: u32 = (bits >> (len - 1 - b)) & 1;
192 192
            writeBit(s, bit);
193 -
            b += 1;
193 +
            set b += 1;
194 194
        }
195 195
    }
196 196
}
197 197
198 198
fn decode(s: *HuffState, root: u32, numSymbols: u32, out: *mut [u32]) -> u32 {
202 202
    while decoded < numSymbols {
203 203
        let mut cur: u32 = root;
204 204
        // Walk the tree until we find a leaf.
205 205
        while nodeSymbol(&s.nodes[cur]) == nil {
206 206
            let bit: u32 = readBit(s, bitPos);
207 -
            bitPos += 1;
207 +
            set bitPos += 1;
208 208
            if bit == 0 {
209 -
                cur = s.nodes[cur].left;
209 +
                set cur = s.nodes[cur].left;
210 210
            } else {
211 -
                cur = s.nodes[cur].right;
211 +
                set cur = s.nodes[cur].right;
212 212
            }
213 213
        }
214 214
        let sym = nodeSymbol(&s.nodes[cur]) else {
215 215
            return decoded;
216 216
        };
217 -
        out[decoded] = sym;
218 -
        decoded += 1;
217 +
        set out[decoded] = sym;
218 +
        set decoded += 1;
219 219
    }
220 220
    return decoded;
221 221
}
222 222
223 223
fn resetCodes(s: *mut HuffState) {
224 224
    let mut i: u32 = 0;
225 225
    while i < MAX_SYMBOLS {
226 -
        s.codeBits[i] = 0;
227 -
        s.codeLen[i] = 0;
228 -
        i += 1;
226 +
        set s.codeBits[i] = 0;
227 +
        set s.codeLen[i] = 0;
228 +
        set i += 1;
229 229
    }
230 230
}
231 231
232 232
fn testBasic(s: *mut HuffState) -> i32 {
233 233
    let freqs: [u32; 5] = [5, 9, 12, 13, 16];
240 240
241 241
    // All symbols should have non-zero code lengths.
242 242
    let mut i: u32 = 0;
243 243
    while i < 5 {
244 244
        assert s.codeLen[i] <> 0;
245 -
        i += 1;
245 +
        set i += 1;
246 246
    }
247 247
248 248
    // No two symbols at the same depth should have the same code.
249 249
    let mut a: u32 = 0;
250 250
    while a < 5 {
251 251
        let mut b: u32 = a + 1;
252 252
        while b < 5 {
253 253
            if s.codeLen[a] == s.codeLen[b] {
254 254
                assert s.codeBits[a] <> s.codeBits[b];
255 255
            }
256 -
            b += 1;
256 +
            set b += 1;
257 257
        }
258 -
        a += 1;
258 +
        set a += 1;
259 259
    }
260 260
261 261
    return 0;
262 262
}
263 263
297 297
    let mut shortestLen: u32 = 100;
298 298
    let mut shortestSym: u32 = 0;
299 299
    let mut i: u32 = 0;
300 300
    while i < 6 {
301 301
        if s.codeLen[i] > 0 and s.codeLen[i] < shortestLen {
302 -
            shortestLen = s.codeLen[i];
303 -
            shortestSym = i;
302 +
            set shortestLen = s.codeLen[i];
303 +
            set shortestSym = i;
304 304
        }
305 -
        i += 1;
305 +
        set i += 1;
306 306
    }
307 307
    assert shortestSym == 0;
308 308
309 309
    let msg: [u32; 12] = [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2];
310 310
    encode(s, &msg[..]);
331 331
332 332
    // All 8 symbols should have code length 3 (8 = 2^3).
333 333
    let mut i: u32 = 0;
334 334
    while i < 8 {
335 335
        assert s.codeLen[i] == 3;
336 -
        i += 1;
336 +
        set i += 1;
337 337
    }
338 338
339 339
    let msg: [u32; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
340 340
    encode(s, &msg[..]);
341 341
test/tests/prog.hybridsort.rad +12 -12
4 4
//! both produce identical sorted output.
5 5
6 6
/// Copy `src` into `dst`.
7 7
fn copy(dst: *mut [i32], src: *[i32]) {
8 8
    for val, i in src {
9 -
        dst[i] = val;
9 +
        set dst[i] = val;
10 10
    }
11 11
}
12 12
13 13
/// Insertion sort on the given array.
14 14
fn insertionSort(data: *mut [i32]) {
15 15
    let mut i: u32 = 1;
16 16
    while i < data.len {
17 17
        let key = data[i];
18 18
        let mut j: i32 = i as i32 - 1;
19 19
        while j >= 0 and data[j as u32] > key {
20 -
            data[(j + 1) as u32] = data[j as u32];
21 -
            j -= 1;
20 +
            set data[(j + 1) as u32] = data[j as u32];
21 +
            set j -= 1;
22 22
        }
23 -
        data[(j + 1) as u32] = key;
24 -
        i += 1;
23 +
        set data[(j + 1) as u32] = key;
24 +
        set i += 1;
25 25
    }
26 26
}
27 27
28 28
/// Selection sort on the given array.
29 29
fn selectionSort(data: *mut [i32]) {
31 31
    while i < data.len - 1 {
32 32
        let mut minIdx: u32 = i;
33 33
        let mut j: u32 = i + 1;
34 34
        while j < data.len {
35 35
            if data[j] < data[minIdx] {
36 -
                minIdx = j;
36 +
                set minIdx = j;
37 37
            }
38 -
            j += 1;
38 +
            set j += 1;
39 39
        }
40 40
        if minIdx <> i {
41 41
            let tmp = data[i];
42 -
            data[i] = data[minIdx];
43 -
            data[minIdx] = tmp;
42 +
            set data[i] = data[minIdx];
43 +
            set data[minIdx] = tmp;
44 44
        }
45 -
        i += 1;
45 +
        set i += 1;
46 46
    }
47 47
}
48 48
49 49
/// Check that an array is sorted in ascending order.
50 50
fn isSorted(data: *[i32]) -> bool {
53 53
        if let p = prev {
54 54
            if p > val {
55 55
                return false;
56 56
            }
57 57
        }
58 -
        prev = val;
58 +
        set prev = val;
59 59
    }
60 60
    return true;
61 61
}
62 62
63 63
/// Compute sum of all elements.
64 64
fn sum(data: *[i32]) -> i32 {
65 65
    let mut total: i32 = 0;
66 66
    for val in data {
67 -
        total += val;
67 +
        set total += val;
68 68
    }
69 69
    return total;
70 70
}
71 71
72 72
/// Compare two arrays element by element.
test/tests/prog.linkedlist.rad +20 -20
17 17
}
18 18
19 19
/// Allocate a node from the pool. Returns its index.
20 20
fn alloc(list: *mut List, value: i32) -> u32 {
21 21
    let idx = list.free;
22 -
    list.free += 1;
23 -
    list.pool[idx] = Node { value, next: nil };
22 +
    set list.free += 1;
23 +
    set list.pool[idx] = Node { value, next: nil };
24 24
    return idx;
25 25
}
26 26
27 27
/// Push a value onto the front of the list.
28 28
fn push(list: *mut List, value: i32) {
29 29
    let idx = alloc(list, value);
30 -
    list.pool[idx].next = list.head;
31 -
    list.head = idx;
30 +
    set list.pool[idx].next = list.head;
31 +
    set list.head = idx;
32 32
}
33 33
34 34
/// Pop a value from the front of the list. Returns nil if empty.
35 35
fn pop(list: *mut List) -> ?i32 {
36 36
    let idx = list.head else {
37 37
        return nil;
38 38
    };
39 39
    let value = list.pool[idx].value;
40 -
    list.head = list.pool[idx].next;
40 +
    set list.head = list.pool[idx].next;
41 41
    return value;
42 42
}
43 43
44 44
/// Get the length of the list.
45 45
fn length(list: *List) -> u32 {
46 46
    let mut count: u32 = 0;
47 47
    let mut cur = list.head;
48 48
    while let idx = cur {
49 -
        count += 1;
50 -
        cur = list.pool[idx].next;
49 +
        set count += 1;
50 +
        set cur = list.pool[idx].next;
51 51
    }
52 52
    return count;
53 53
}
54 54
55 55
/// Find a value in the list. Returns the node index if found, or nil.
57 57
    let mut cur = list.head;
58 58
    while let idx = cur {
59 59
        if list.pool[idx].value == value {
60 60
            return idx;
61 61
        }
62 -
        cur = list.pool[idx].next;
62 +
        set cur = list.pool[idx].next;
63 63
    }
64 64
    return nil;
65 65
}
66 66
67 67
/// Get the value at a given index (0-based from head).
70 70
    let mut i: u32 = 0;
71 71
    while let idx = cur {
72 72
        if i == index {
73 73
            return list.pool[idx].value;
74 74
        }
75 -
        cur = list.pool[idx].next;
76 -
        i += 1;
75 +
        set cur = list.pool[idx].next;
76 +
        set i += 1;
77 77
    }
78 78
    return nil;
79 79
}
80 80
81 81
/// Reverse the linked list in-place.
82 82
fn reverse(list: *mut List) {
83 83
    let mut prev: ?u32 = nil;
84 84
    let mut cur = list.head;
85 85
    while let idx = cur {
86 86
        let next = list.pool[idx].next;
87 -
        list.pool[idx].next = prev;
88 -
        prev = idx;
89 -
        cur = next;
87 +
        set list.pool[idx].next = prev;
88 +
        set prev = idx;
89 +
        set cur = next;
90 90
    }
91 -
    list.head = prev;
91 +
    set list.head = prev;
92 92
}
93 93
94 94
/// Compute the sum of all values in the list.
95 95
fn sum(list: *List) -> i32 {
96 96
    let mut total: i32 = 0;
97 97
    let mut cur = list.head;
98 98
    while let idx = cur {
99 -
        total += list.pool[idx].value;
100 -
        cur = list.pool[idx].next;
99 +
        set total += list.pool[idx].value;
100 +
        set cur = list.pool[idx].next;
101 101
    }
102 102
    return total;
103 103
}
104 104
105 105
/// Reset the list to empty.
106 106
fn reset(list: *mut List) {
107 -
    list.head = nil;
108 -
    list.free = 0;
107 +
    set list.head = nil;
108 +
    set list.free = 0;
109 109
}
110 110
111 111
/// Test basic push and length.
112 112
fn testPushLength(list: *mut List) -> i32 {
113 113
    push(list, 10);
200 200
201 201
    // Push 32 elements.
202 202
    let mut i: u32 = 0;
203 203
    while i < 32 {
204 204
        push(list, i as i32 * 3);
205 -
        i += 1;
205 +
        set i += 1;
206 206
    }
207 207
208 208
    assert length(list) == 32;
209 209
210 210
    // Sum should be 3 * (0 + 1 + ... + 31) = 3 * 496 = 1488
230 230
        let v = pop(list) else {
231 231
            return 6;
232 232
        };
233 233
        let expected = j as i32 * 3;
234 234
        assert v == expected;
235 -
        j += 1;
235 +
        set j += 1;
236 236
    }
237 237
238 238
    assert length(list) == 0;
239 239
240 240
    // Pop from empty list should return nil.
test/tests/prog.lzw.rad +38 -38
24 24
    decLen: u32,
25 25
    temp: *mut [u8],
26 26
}
27 27
28 28
fn initEncDict(s: *mut LzwState) {
29 -
    s.encDictSize = INIT_DICT;
29 +
    set s.encDictSize = INIT_DICT;
30 30
    let mut i: u32 = 0;
31 31
    while i < 256 {
32 -
        s.encDict[i] = DictEntry { prefix: 0xFFFF, suffix: i as u8 };
33 -
        i += 1;
32 +
        set s.encDict[i] = DictEntry { prefix: 0xFFFF, suffix: i as u8 };
33 +
        set i += 1;
34 34
    }
35 35
}
36 36
37 37
fn initDecDict(s: *mut LzwState) {
38 -
    s.decDictSize = INIT_DICT;
38 +
    set s.decDictSize = INIT_DICT;
39 39
    let mut i: u32 = 0;
40 40
    while i < 256 {
41 -
        s.decDict[i] = DictEntry { prefix: 0xFFFF, suffix: i as u8 };
42 -
        i += 1;
41 +
        set s.decDict[i] = DictEntry { prefix: 0xFFFF, suffix: i as u8 };
42 +
        set i += 1;
43 43
    }
44 44
}
45 45
46 46
fn dictLookup(s: *LzwState, prefix: u32, suffix: u8) -> u32 {
47 47
    let mut i: u32 = 0;
48 48
    while i < s.encDictSize {
49 49
        if s.encDict[i].prefix == prefix and s.encDict[i].suffix == suffix {
50 50
            return i;
51 51
        }
52 -
        i += 1;
52 +
        set i += 1;
53 53
    }
54 54
    return 0xFFFFFFFF;
55 55
}
56 56
57 57
fn dictAdd(s: *mut LzwState, prefix: u32, suffix: u8) {
58 58
    if s.encDictSize < MAX_DICT {
59 -
        s.encDict[s.encDictSize] = DictEntry { prefix, suffix };
60 -
        s.encDictSize += 1;
59 +
        set s.encDict[s.encDictSize] = DictEntry { prefix, suffix };
60 +
        set s.encDictSize += 1;
61 61
    }
62 62
}
63 63
64 64
fn emitCode(s: *mut LzwState, code: u32) {
65 -
    s.encoded[s.encLen] = code;
66 -
    s.encLen += 1;
65 +
    set s.encoded[s.encLen] = code;
66 +
    set s.encLen += 1;
67 67
}
68 68
69 69
fn encode(s: *mut LzwState, data: *[u8]) {
70 70
    initEncDict(s);
71 -
    s.encLen = 0;
71 +
    set s.encLen = 0;
72 72
73 73
    if data.len == 0 {
74 74
        emitCode(s, EOI_CODE);
75 75
        return;
76 76
    }
80 80
81 81
    while i < data.len {
82 82
        let c: u8 = data[i];
83 83
        let wc: u32 = dictLookup(s, w, c);
84 84
        if wc <> 0xFFFFFFFF {
85 -
            w = wc;
85 +
            set w = wc;
86 86
        } else {
87 87
            emitCode(s, w);
88 88
            dictAdd(s, w, c);
89 -
            w = c as u32;
89 +
            set w = c as u32;
90 90
        }
91 -
        i += 1;
91 +
        set i += 1;
92 92
    }
93 93
    emitCode(s, w);
94 94
    emitCode(s, EOI_CODE);
95 95
}
96 96
97 97
fn decodeString(s: *mut LzwState, code: u32) -> u32 {
98 98
    let mut len: u32 = 0;
99 99
    let mut c: u32 = code;
100 100
    while c <> 0xFFFF and c < s.decDictSize {
101 -
        s.temp[len] = s.decDict[c].suffix;
102 -
        len += 1;
103 -
        c = s.decDict[c].prefix;
101 +
        set s.temp[len] = s.decDict[c].suffix;
102 +
        set len += 1;
103 +
        set c = s.decDict[c].prefix;
104 104
    }
105 105
    let mut a: u32 = 0;
106 106
    let mut b: u32 = len - 1;
107 107
    while a < b {
108 108
        let tmp: u8 = s.temp[a];
109 -
        s.temp[a] = s.temp[b];
110 -
        s.temp[b] = tmp;
111 -
        a += 1;
112 -
        b -= 1;
109 +
        set s.temp[a] = s.temp[b];
110 +
        set s.temp[b] = tmp;
111 +
        set a += 1;
112 +
        set b -= 1;
113 113
    }
114 114
    return len;
115 115
}
116 116
117 117
fn firstByte(s: *LzwState, code: u32) -> u8 {
118 118
    let mut c: u32 = code;
119 119
    while s.decDict[c].prefix <> 0xFFFF and s.decDict[c].prefix < s.decDictSize {
120 -
        c = s.decDict[c].prefix;
120 +
        set c = s.decDict[c].prefix;
121 121
    }
122 122
    return s.decDict[c].suffix;
123 123
}
124 124
125 125
fn decDictAdd(s: *mut LzwState, prefix: u32, suffix: u8) {
126 126
    if s.decDictSize < MAX_DICT {
127 -
        s.decDict[s.decDictSize] = DictEntry { prefix, suffix };
128 -
        s.decDictSize += 1;
127 +
        set s.decDict[s.decDictSize] = DictEntry { prefix, suffix };
128 +
        set s.decDictSize += 1;
129 129
    }
130 130
}
131 131
132 132
fn outputByte(s: *mut LzwState, b: u8) {
133 -
    s.decoded[s.decLen] = b;
134 -
    s.decLen += 1;
133 +
    set s.decoded[s.decLen] = b;
134 +
    set s.decLen += 1;
135 135
}
136 136
137 137
fn decode(s: *mut LzwState) {
138 138
    initDecDict(s);
139 -
    s.decLen = 0;
139 +
    set s.decLen = 0;
140 140
141 141
    if s.encLen == 0 {
142 142
        return;
143 143
    }
144 144
145 145
    let mut pos: u32 = 0;
146 146
    let mut code: u32 = s.encoded[pos];
147 -
    pos += 1;
147 +
    set pos += 1;
148 148
149 149
    if code == EOI_CODE {
150 150
        return;
151 151
    }
152 152
153 153
    outputByte(s, code as u8);
154 154
    let mut prevCode: u32 = code;
155 155
156 156
    while pos < s.encLen {
157 -
        code = s.encoded[pos];
158 -
        pos += 1;
157 +
        set code = s.encoded[pos];
158 +
        set pos += 1;
159 159
160 160
        if code == EOI_CODE {
161 161
            return;
162 162
        }
163 163
164 164
        if code < s.decDictSize {
165 165
            let len: u32 = decodeString(s, code);
166 166
            let mut i: u32 = 0;
167 167
            while i < len {
168 168
                outputByte(s, s.temp[i]);
169 -
                i += 1;
169 +
                set i += 1;
170 170
            }
171 171
            decDictAdd(s, prevCode, s.temp[0]);
172 172
        } else {
173 173
            let fb: u8 = firstByte(s, prevCode);
174 174
            let len: u32 = decodeString(s, prevCode);
175 175
            let mut i: u32 = 0;
176 176
            while i < len {
177 177
                outputByte(s, s.temp[i]);
178 -
                i += 1;
178 +
                set i += 1;
179 179
            }
180 180
            outputByte(s, fb);
181 181
            decDictAdd(s, prevCode, fb);
182 182
        }
183 -
        prevCode = code;
183 +
        set prevCode = code;
184 184
    }
185 185
}
186 186
187 187
fn testSimple(s: *mut LzwState) -> i32 {
188 188
    let data: *[u8] = "ABABABABAB";
193 193
    decode(s);
194 194
    assert s.decLen == 10;
195 195
    let mut i: u32 = 0;
196 196
    while i < 10 {
197 197
        assert s.decoded[i] == data[i];
198 -
        i += 1;
198 +
        set i += 1;
199 199
    }
200 200
    return 0;
201 201
}
202 202
203 203
fn testDistinct(s: *mut LzwState) -> i32 {
207 207
    decode(s);
208 208
    assert s.decLen == 16;
209 209
    let mut i: u32 = 0;
210 210
    while i < 16 {
211 211
        assert s.decoded[i] == data[i];
212 -
        i += 1;
212 +
        set i += 1;
213 213
    }
214 214
    return 0;
215 215
}
216 216
217 217
fn testRepetitive(s: *mut LzwState) -> i32 {
223 223
    decode(s);
224 224
    assert s.decLen == 64;
225 225
    let mut i: u32 = 0;
226 226
    while i < 64 {
227 227
        assert s.decoded[i] == 65;
228 -
        i += 1;
228 +
        set i += 1;
229 229
    }
230 230
    return 0;
231 231
}
232 232
233 233
fn testMixed(s: *mut LzwState) -> i32 {
237 237
    decode(s);
238 238
    assert s.decLen == 24;
239 239
    let mut i: u32 = 0;
240 240
    while i < 24 {
241 241
        assert s.decoded[i] == data[i];
242 -
        i += 1;
242 +
        set i += 1;
243 243
    }
244 244
245 245
    assert s.encLen - 1 < 24;
246 246
247 247
    return 0;
test/tests/prog.matmul.rad +12 -12
17 17
        let mut j: u32 = 0;
18 18
        while j < N {
19 19
            let mut sum: i32 = 0;
20 20
            let mut k: u32 = 0;
21 21
            while k < N {
22 -
                sum += a.rows[i][k] * b.rows[k][j];
23 -
                k += 1;
22 +
                set sum += a.rows[i][k] * b.rows[k][j];
23 +
                set k += 1;
24 24
            }
25 -
            c.rows[i][j] = sum;
26 -
            j += 1;
25 +
            set c.rows[i][j] = sum;
26 +
            set j += 1;
27 27
        }
28 -
        i += 1;
28 +
        set i += 1;
29 29
    }
30 30
}
31 31
32 32
/// Verify c matches expected.
33 33
fn verifyResult(c: *Mat4, expected: *Mat4) -> i32 {
36 36
        let mut j: u32 = 0;
37 37
        while j < N {
38 38
            if c.rows[i][j] <> expected.rows[i][j] {
39 39
                return (i * N + j) as i32 + 1;
40 40
            }
41 -
            j += 1;
41 +
            set j += 1;
42 42
        }
43 -
        i += 1;
43 +
        set i += 1;
44 44
    }
45 45
    return 0;
46 46
}
47 47
48 48
/// Compute the trace (sum of diagonal) of a matrix.
49 49
fn trace(m: *Mat4) -> i32 {
50 50
    let mut sum: i32 = 0;
51 51
    let mut i: u32 = 0;
52 52
    while i < N {
53 -
        sum += m.rows[i][i];
54 -
        i += 1;
53 +
        set sum += m.rows[i][i];
54 +
        set i += 1;
55 55
    }
56 56
    return sum;
57 57
}
58 58
59 59
/// Zero out a matrix.
60 60
fn zero(m: *mut Mat4) {
61 61
    let mut i: u32 = 0;
62 62
    while i < N {
63 63
        let mut j: u32 = 0;
64 64
        while j < N {
65 -
            m.rows[i][j] = 0;
66 -
            j += 1;
65 +
            set m.rows[i][j] = 0;
66 +
            set j += 1;
67 67
        }
68 -
        i += 1;
68 +
        set i += 1;
69 69
    }
70 70
}
71 71
72 72
/// Multiply matrices multiple times to test repeated computation.
73 73
fn testRepeatedMultiply(c: *mut Mat4, a: *Mat4, b: *Mat4) -> i32 {
test/tests/prog.mersenne.rad +41 -41
11 11
    mt: *mut [u32],
12 12
    mti: u32,
13 13
}
14 14
15 15
fn mtInit(s: *mut MtState, seed: u32) {
16 -
    s.mt[0] = seed;
16 +
    set s.mt[0] = seed;
17 17
    let mut i: u32 = 1;
18 18
    while i < N {
19 19
        let prev: u32 = s.mt[i - 1];
20 20
        let xored: u32 = prev ^ (prev >> 30);
21 21
28 28
        let ll: u32 = clo * lo;
29 29
        let lh: u32 = clo * hi;
30 30
        let hl: u32 = chi * lo;
31 31
32 32
        let result: u32 = ll + ((lh + hl) << 16) + i;
33 -
        s.mt[i] = result;
34 -
        i += 1;
33 +
        set s.mt[i] = result;
34 +
        set i += 1;
35 35
    }
36 -
    s.mti = N;
36 +
    set s.mti = N;
37 37
}
38 38
39 39
fn generateNumbers(s: *mut MtState) {
40 40
    let mut i: u32 = 0;
41 41
42 42
    while i < N - M {
43 43
        let y: u32 = (s.mt[i] & UPPER_MASK) | (s.mt[i + 1] & LOWER_MASK);
44 44
        let mut mag: u32 = 0;
45 45
        if y & 1 == 1 {
46 -
            mag = MATRIX_A;
46 +
            set mag = MATRIX_A;
47 47
        }
48 -
        s.mt[i] = s.mt[i + M] ^ (y >> 1) ^ mag;
49 -
        i += 1;
48 +
        set s.mt[i] = s.mt[i + M] ^ (y >> 1) ^ mag;
49 +
        set i += 1;
50 50
    }
51 51
52 52
    while i < N - 1 {
53 53
        let y: u32 = (s.mt[i] & UPPER_MASK) | (s.mt[i + 1] & LOWER_MASK);
54 54
        let mut mag: u32 = 0;
55 55
        if y & 1 == 1 {
56 -
            mag = MATRIX_A;
56 +
            set mag = MATRIX_A;
57 57
        }
58 -
        s.mt[i] = s.mt[i + M - N] ^ (y >> 1) ^ mag;
59 -
        i += 1;
58 +
        set s.mt[i] = s.mt[i + M - N] ^ (y >> 1) ^ mag;
59 +
        set i += 1;
60 60
    }
61 61
62 62
    let y: u32 = (s.mt[N - 1] & UPPER_MASK) | (s.mt[0] & LOWER_MASK);
63 63
    let mut mag: u32 = 0;
64 64
    if y & 1 == 1 {
65 -
        mag = MATRIX_A;
65 +
        set mag = MATRIX_A;
66 66
    }
67 -
    s.mt[N - 1] = s.mt[M - 1] ^ (y >> 1) ^ mag;
67 +
    set s.mt[N - 1] = s.mt[M - 1] ^ (y >> 1) ^ mag;
68 68
69 -
    s.mti = 0;
69 +
    set s.mti = 0;
70 70
}
71 71
72 72
fn mtNext(s: *mut MtState) -> u32 {
73 73
    if s.mti >= N {
74 74
        generateNumbers(s);
75 75
    }
76 76
77 77
    let mut y: u32 = s.mt[s.mti];
78 -
    s.mti += 1;
78 +
    set s.mti += 1;
79 79
80 -
    y ^= (y >> 11);
81 -
    y ^= ((y << 7) & 0x9D2C5680);
82 -
    y ^= ((y << 15) & 0xEFC60000);
83 -
    y ^= (y >> 18);
80 +
    set y ^= (y >> 11);
81 +
    set y ^= ((y << 7) & 0x9D2C5680);
82 +
    set y ^= ((y << 15) & 0xEFC60000);
83 +
    set y ^= (y >> 18);
84 84
85 85
    return y;
86 86
}
87 87
88 88
fn testKnownSequence(s: *mut MtState) -> i32 {
110 110
    mtInit(s, 42);
111 111
112 112
    let mut first: [u32; 10] = [0; 10];
113 113
    let mut i: u32 = 0;
114 114
    while i < 10 {
115 -
        first[i] = mtNext(s);
116 -
        i += 1;
115 +
        set first[i] = mtNext(s);
116 +
        set i += 1;
117 117
    }
118 118
119 119
    mtInit(s, 42);
120 120
121 -
    i = 0;
121 +
    set i = 0;
122 122
    while i < 10 {
123 123
        let v: u32 = mtNext(s);
124 124
        if v <> first[i] { return i as i32 + 1; }
125 -
        i += 1;
125 +
        set i += 1;
126 126
    }
127 127
128 128
    return 0;
129 129
}
130 130
156 156
157 157
    let mut i: u32 = 0;
158 158
    while i < NUM_SAMPLES {
159 159
        let val: u32 = mtNext(s);
160 160
        let bin: u32 = val >> 28;
161 -
        bins[bin] += 1;
162 -
        i += 1;
161 +
        set bins[bin] += 1;
162 +
        set i += 1;
163 163
    }
164 164
165 165
    let mut chi2Scaled: u32 = 0;
166 166
    let mut b: u32 = 0;
167 167
    while b < NUM_BINS {
168 168
        let obs: i32 = bins[b] as i32;
169 169
        let exp: i32 = EXPECTED as i32;
170 170
        let diff: i32 = obs - exp;
171 -
        chi2Scaled += (diff * diff) as u32;
172 -
        b += 1;
171 +
        set chi2Scaled += (diff * diff) as u32;
172 +
        set b += 1;
173 173
    }
174 174
175 175
    assert chi2Scaled <= 5000;
176 176
177 -
    b = 0;
177 +
    set b = 0;
178 178
    while b < NUM_BINS {
179 179
        assert bins[b] <> 0;
180 -
        b += 1;
180 +
        set b += 1;
181 181
    }
182 182
183 -
    b = 0;
183 +
    set b = 0;
184 184
    while b < NUM_BINS {
185 185
        assert bins[b] <= NUM_SAMPLES / 2;
186 -
        b += 1;
186 +
        set b += 1;
187 187
    }
188 188
189 189
    return 0;
190 190
}
191 191
193 193
    mtInit(s, 7);
194 194
195 195
    let mut last: u32 = 0;
196 196
    let mut i: u32 = 0;
197 197
    while i < 700 {
198 -
        last = mtNext(s);
199 -
        i += 1;
198 +
        set last = mtNext(s);
199 +
        set i += 1;
200 200
    }
201 201
202 202
    mtInit(s, 7);
203 203
    let mut last2: u32 = 0;
204 -
    i = 0;
204 +
    set i = 0;
205 205
    while i < 700 {
206 -
        last2 = mtNext(s);
207 -
        i += 1;
206 +
        set last2 = mtNext(s);
207 +
        set i += 1;
208 208
    }
209 209
210 210
    assert last == last2;
211 211
212 212
    let mut more: u32 = 0;
213 -
    i = 0;
213 +
    set i = 0;
214 214
    while i < 700 {
215 -
        more = mtNext(s);
216 -
        i += 1;
215 +
        set more = mtNext(s);
216 +
        set i += 1;
217 217
    }
218 218
    assert more <> 0;
219 219
220 220
    return 0;
221 221
}
227 227
    let mut andAll: u32 = 0xFFFFFFFF;
228 228
229 229
    let mut i: u32 = 0;
230 230
    while i < 200 {
231 231
        let v: u32 = mtNext(s);
232 -
        orAll |= v;
233 -
        andAll &= v;
234 -
        i += 1;
232 +
        set orAll |= v;
233 +
        set andAll &= v;
234 +
        set i += 1;
235 235
    }
236 236
237 237
    assert orAll == 0xFFFFFFFF;
238 238
    assert andAll <> 0xFFFFFFFF;
239 239
    assert andAll == 0;
test/tests/prog.nqueens.rad +15 -15
21 21
        let rowDiff: i32 = row as i32 - i as i32;
22 22
        let colDiff: i32 = col as i32 - qcol;
23 23
        if colDiff == rowDiff or colDiff == 0 - rowDiff {
24 24
            return false;
25 25
        }
26 -
        i += 1;
26 +
        set i += 1;
27 27
    }
28 28
    return true;
29 29
}
30 30
31 31
fn solve(b: *mut Board, row: u32) {
32 32
    if row == b.boardSize {
33 -
        b.solutionCount += 1;
33 +
        set b.solutionCount += 1;
34 34
        return;
35 35
    }
36 36
    let mut col: u32 = 0;
37 37
    while col < b.boardSize {
38 38
        if isSafe(b, row, col) {
39 -
            b.queens[row] = col as i32;
39 +
            set b.queens[row] = col as i32;
40 40
            solve(b, row + 1);
41 -
            b.queens[row] = -1;
41 +
            set b.queens[row] = -1;
42 42
        }
43 -
        col += 1;
43 +
        set col += 1;
44 44
    }
45 45
}
46 46
47 47
fn resetBoard(b: *mut Board) {
48 48
    let mut i: u32 = 0;
49 49
    while i < MAX_N {
50 -
        b.queens[i] = -1;
51 -
        i += 1;
50 +
        set b.queens[i] = -1;
51 +
        set i += 1;
52 52
    }
53 -
    b.solutionCount = 0;
53 +
    set b.solutionCount = 0;
54 54
}
55 55
56 56
fn solveNQueens(b: *mut Board, n: u32) -> u32 {
57 57
    resetBoard(b);
58 -
    b.boardSize = n;
58 +
    set b.boardSize = n;
59 59
    solve(b, 0);
60 60
    return b.solutionCount;
61 61
}
62 62
63 63
fn testAllSizes(b: *mut Board) -> i32 {
66 66
    while n <= 8 {
67 67
        let count: u32 = solveNQueens(b, n);
68 68
        if count <> expected[n] {
69 69
            return n as i32;
70 70
        }
71 -
        n += 1;
71 +
        set n += 1;
72 72
    }
73 73
    return 0;
74 74
}
75 75
76 76
fn testKnownSolution() -> i32 {
82 82
        while j < 8 {
83 83
            assert solution[i] <> solution[j];
84 84
            let rowDiff: i32 = j as i32 - i as i32;
85 85
            let colDiff: i32 = solution[j] - solution[i];
86 86
            assert colDiff <> rowDiff and colDiff <> 0 - rowDiff;
87 -
            j += 1;
87 +
            set j += 1;
88 88
        }
89 -
        i += 1;
89 +
        set i += 1;
90 90
    }
91 91
92 92
    let mut used: [bool; 8] = [false; 8];
93 93
    let mut k: u32 = 0;
94 94
    while k < 8 {
95 95
        let col: u32 = solution[k] as u32;
96 96
        if used[col] {
97 97
            return 3;
98 98
        }
99 -
        used[col] = true;
100 -
        k += 1;
99 +
        set used[col] = true;
100 +
        set k += 1;
101 101
    }
102 102
103 103
    return 0;
104 104
}
105 105
118 118
    let expected: [u32; 9] = [0, 1, 0, 0, 2, 10, 4, 40, 92];
119 119
120 120
    let mut n: u32 = 4;
121 121
    while n <= 8 {
122 122
        assert expected[n] <> 0;
123 -
        n += 1;
123 +
        set n += 1;
124 124
    }
125 125
126 126
    assert expected[2] == 0;
127 127
    assert expected[3] == 0;
128 128
    assert expected[7] > expected[6];
test/tests/prog.rbtree.rad +62 -62
24 24
    inorderCount: u32,
25 25
}
26 26
27 27
fn allocNode(t: *mut RBTree, key: i32) -> u32 {
28 28
    let idx: u32 = t.poolNext;
29 -
    t.poolNext += 1;
30 -
    t.pool[idx] = RBNode { key, color: RED, left: NIL, right: NIL, parent: NIL };
29 +
    set t.poolNext += 1;
30 +
    set t.pool[idx] = RBNode { key, color: RED, left: NIL, right: NIL, parent: NIL };
31 31
    return idx;
32 32
}
33 33
34 34
fn rotateLeft(t: *mut RBTree, x: u32) {
35 35
    let y: u32 = t.pool[x].right;
36 -
    t.pool[x].right = t.pool[y].left;
36 +
    set t.pool[x].right = t.pool[y].left;
37 37
    if t.pool[y].left <> NIL {
38 -
        t.pool[t.pool[y].left].parent = x;
38 +
        set t.pool[t.pool[y].left].parent = x;
39 39
    }
40 -
    t.pool[y].parent = t.pool[x].parent;
40 +
    set t.pool[y].parent = t.pool[x].parent;
41 41
    if t.pool[x].parent == NIL {
42 -
        t.root = y;
42 +
        set t.root = y;
43 43
    } else if x == t.pool[t.pool[x].parent].left {
44 -
        t.pool[t.pool[x].parent].left = y;
44 +
        set t.pool[t.pool[x].parent].left = y;
45 45
    } else {
46 -
        t.pool[t.pool[x].parent].right = y;
46 +
        set t.pool[t.pool[x].parent].right = y;
47 47
    }
48 -
    t.pool[y].left = x;
49 -
    t.pool[x].parent = y;
48 +
    set t.pool[y].left = x;
49 +
    set t.pool[x].parent = y;
50 50
}
51 51
52 52
fn rotateRight(t: *mut RBTree, x: u32) {
53 53
    let y: u32 = t.pool[x].left;
54 -
    t.pool[x].left = t.pool[y].right;
54 +
    set t.pool[x].left = t.pool[y].right;
55 55
    if t.pool[y].right <> NIL {
56 -
        t.pool[t.pool[y].right].parent = x;
56 +
        set t.pool[t.pool[y].right].parent = x;
57 57
    }
58 -
    t.pool[y].parent = t.pool[x].parent;
58 +
    set t.pool[y].parent = t.pool[x].parent;
59 59
    if t.pool[x].parent == NIL {
60 -
        t.root = y;
60 +
        set t.root = y;
61 61
    } else if x == t.pool[t.pool[x].parent].right {
62 -
        t.pool[t.pool[x].parent].right = y;
62 +
        set t.pool[t.pool[x].parent].right = y;
63 63
    } else {
64 -
        t.pool[t.pool[x].parent].left = y;
64 +
        set t.pool[t.pool[x].parent].left = y;
65 65
    }
66 -
    t.pool[y].right = x;
67 -
    t.pool[x].parent = y;
66 +
    set t.pool[y].right = x;
67 +
    set t.pool[x].parent = y;
68 68
}
69 69
70 70
fn insertFixup(t: *mut RBTree, zArg: u32) {
71 71
    let mut z: u32 = zArg;
72 72
    while t.pool[t.pool[z].parent].color == RED {
73 73
        if t.pool[z].parent == t.pool[t.pool[t.pool[z].parent].parent].left {
74 74
            let y: u32 = t.pool[t.pool[t.pool[z].parent].parent].right;
75 75
            if t.pool[y].color == RED {
76 -
                t.pool[t.pool[z].parent].color = BLACK;
77 -
                t.pool[y].color = BLACK;
78 -
                t.pool[t.pool[t.pool[z].parent].parent].color = RED;
79 -
                z = t.pool[t.pool[z].parent].parent;
76 +
                set t.pool[t.pool[z].parent].color = BLACK;
77 +
                set t.pool[y].color = BLACK;
78 +
                set t.pool[t.pool[t.pool[z].parent].parent].color = RED;
79 +
                set z = t.pool[t.pool[z].parent].parent;
80 80
            } else {
81 81
                if z == t.pool[t.pool[z].parent].right {
82 -
                    z = t.pool[z].parent;
82 +
                    set z = t.pool[z].parent;
83 83
                    rotateLeft(t, z);
84 84
                }
85 -
                t.pool[t.pool[z].parent].color = BLACK;
86 -
                t.pool[t.pool[t.pool[z].parent].parent].color = RED;
85 +
                set t.pool[t.pool[z].parent].color = BLACK;
86 +
                set t.pool[t.pool[t.pool[z].parent].parent].color = RED;
87 87
                rotateRight(t, t.pool[t.pool[z].parent].parent);
88 88
            }
89 89
        } else {
90 90
            let y: u32 = t.pool[t.pool[t.pool[z].parent].parent].left;
91 91
            if t.pool[y].color == RED {
92 -
                t.pool[t.pool[z].parent].color = BLACK;
93 -
                t.pool[y].color = BLACK;
94 -
                t.pool[t.pool[t.pool[z].parent].parent].color = RED;
95 -
                z = t.pool[t.pool[z].parent].parent;
92 +
                set t.pool[t.pool[z].parent].color = BLACK;
93 +
                set t.pool[y].color = BLACK;
94 +
                set t.pool[t.pool[t.pool[z].parent].parent].color = RED;
95 +
                set z = t.pool[t.pool[z].parent].parent;
96 96
            } else {
97 97
                if z == t.pool[t.pool[z].parent].left {
98 -
                    z = t.pool[z].parent;
98 +
                    set z = t.pool[z].parent;
99 99
                    rotateRight(t, z);
100 100
                }
101 -
                t.pool[t.pool[z].parent].color = BLACK;
102 -
                t.pool[t.pool[t.pool[z].parent].parent].color = RED;
101 +
                set t.pool[t.pool[z].parent].color = BLACK;
102 +
                set t.pool[t.pool[t.pool[z].parent].parent].color = RED;
103 103
                rotateLeft(t, t.pool[t.pool[z].parent].parent);
104 104
            }
105 105
        }
106 106
    }
107 -
    t.pool[t.root].color = BLACK;
107 +
    set t.pool[t.root].color = BLACK;
108 108
}
109 109
110 110
fn insert(t: *mut RBTree, key: i32) {
111 111
    let z: u32 = allocNode(t, key);
112 112
    let mut y: u32 = NIL;
113 113
    let mut x: u32 = t.root;
114 114
115 115
    while x <> NIL {
116 -
        y = x;
116 +
        set y = x;
117 117
        if key < t.pool[x].key {
118 -
            x = t.pool[x].left;
118 +
            set x = t.pool[x].left;
119 119
        } else {
120 -
            x = t.pool[x].right;
120 +
            set x = t.pool[x].right;
121 121
        }
122 122
    }
123 123
124 -
    t.pool[z].parent = y;
124 +
    set t.pool[z].parent = y;
125 125
    if y == NIL {
126 -
        t.root = z;
126 +
        set t.root = z;
127 127
    } else if key < t.pool[y].key {
128 -
        t.pool[y].left = z;
128 +
        set t.pool[y].left = z;
129 129
    } else {
130 -
        t.pool[y].right = z;
130 +
        set t.pool[y].right = z;
131 131
    }
132 132
133 133
    insertFixup(t, z);
134 134
}
135 135
137 137
    let mut x: u32 = t.root;
138 138
    while x <> NIL {
139 139
        if key == t.pool[x].key {
140 140
            return true;
141 141
        } else if key < t.pool[x].key {
142 -
            x = t.pool[x].left;
142 +
            set x = t.pool[x].left;
143 143
        } else {
144 -
            x = t.pool[x].right;
144 +
            set x = t.pool[x].right;
145 145
        }
146 146
    }
147 147
    return false;
148 148
}
149 149
150 150
fn inorderWalk(t: *mut RBTree, x: u32) {
151 151
    if x == NIL {
152 152
        return;
153 153
    }
154 154
    inorderWalk(t, t.pool[x].left);
155 -
    t.inorder[t.inorderCount] = t.pool[x].key;
156 -
    t.inorderCount += 1;
155 +
    set t.inorder[t.inorderCount] = t.pool[x].key;
156 +
    set t.inorderCount += 1;
157 157
    inorderWalk(t, t.pool[x].right);
158 158
}
159 159
160 160
fn countNodes(t: *RBTree, x: u32) -> u32 {
161 161
    if x == NIL {
203 203
}
204 204
205 205
fn resetTree(t: *mut RBTree) {
206 206
    let mut i: u32 = 0;
207 207
    while i < POOL_SIZE {
208 -
        t.pool[i] = RBNode { key: 0, color: BLACK, left: NIL, right: NIL, parent: NIL };
209 -
        i += 1;
208 +
        set t.pool[i] = RBNode { key: 0, color: BLACK, left: NIL, right: NIL, parent: NIL };
209 +
        set i += 1;
210 210
    }
211 -
    t.poolNext = 1;
212 -
    t.root = NIL;
213 -
    t.inorderCount = 0;
211 +
    set t.poolNext = 1;
212 +
    set t.root = NIL;
213 +
    set t.inorderCount = 0;
214 214
}
215 215
216 216
fn testAscending(t: *mut RBTree) -> i32 {
217 217
    resetTree(t);
218 218
219 219
    let mut i: i32 = 0;
220 220
    while i < 32 {
221 221
        insert(t, i);
222 -
        i += 1;
222 +
        set i += 1;
223 223
    }
224 224
225 225
    assert countNodes(t, t.root) == 32;
226 226
    assert t.pool[t.root].color == BLACK;
227 227
228 228
    let bh: i32 = blackHeight(t, t.root);
229 229
    assert bh <> -1;
230 230
231 231
    assert noRedRed(t, t.root);
232 232
233 -
    t.inorderCount = 0;
233 +
    set t.inorderCount = 0;
234 234
    inorderWalk(t, t.root);
235 235
    assert t.inorderCount == 32;
236 236
    let mut j: u32 = 0;
237 237
    while j < 32 {
238 238
        assert t.inorder[j] == j as i32;
239 -
        j += 1;
239 +
        set j += 1;
240 240
    }
241 241
242 242
    return 0;
243 243
}
244 244
249 249
    while i >= 0 {
250 250
        insert(t, i);
251 251
        if i == 0 {
252 252
            break;
253 253
        }
254 -
        i -= 1;
254 +
        set i -= 1;
255 255
    }
256 256
257 257
    assert countNodes(t, t.root) == 32;
258 258
    assert blackHeight(t, t.root) <> -1;
259 259
    assert noRedRed(t, t.root);
260 260
261 -
    t.inorderCount = 0;
261 +
    set t.inorderCount = 0;
262 262
    inorderWalk(t, t.root);
263 263
    let mut j: u32 = 0;
264 264
    while j < 32 {
265 265
        assert t.inorder[j] == j as i32;
266 -
        j += 1;
266 +
        set j += 1;
267 267
    }
268 268
269 269
    return 0;
270 270
}
271 271
275 275
    let mut inserted: [bool; 48] = [false; 48];
276 276
    let mut seed: u32 = 42;
277 277
    let mut count: u32 = 0;
278 278
279 279
    while count < 48 {
280 -
        seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF;
280 +
        set seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF;
281 281
        let val: u32 = seed % 48;
282 282
        if not inserted[val] {
283 283
            insert(t, val as i32);
284 -
            inserted[val] = true;
285 -
            count += 1;
284 +
            set inserted[val] = true;
285 +
            set count += 1;
286 286
        }
287 287
    }
288 288
289 289
    assert countNodes(t, t.root) == 48;
290 290
    assert blackHeight(t, t.root) <> -1;
291 291
    assert noRedRed(t, t.root);
292 292
293 293
    let mut i: i32 = 0;
294 294
    while i < 48 {
295 295
        assert search(t, i);
296 -
        i += 1;
296 +
        set i += 1;
297 297
    }
298 298
299 299
    assert not search(t, -1);
300 300
    assert not search(t, 48);
301 301
    assert not search(t, 100);
302 302
303 -
    t.inorderCount = 0;
303 +
    set t.inorderCount = 0;
304 304
    inorderWalk(t, t.root);
305 305
    assert t.inorderCount == 48;
306 306
    let mut j: u32 = 0;
307 307
    while j < 48 {
308 308
        assert t.inorder[j] == j as i32;
309 -
        j += 1;
309 +
        set j += 1;
310 310
    }
311 311
312 312
    return 0;
313 313
}
314 314
316 316
    resetTree(t);
317 317
318 318
    let mut i: i32 = 0;
319 319
    while i < 63 {
320 320
        insert(t, i);
321 -
        i += 1;
321 +
        set i += 1;
322 322
    }
323 323
324 324
    let bh: i32 = blackHeight(t, t.root);
325 325
    assert bh >= 3;
326 326
    assert bh <= 7;
test/tests/prog.regex.rad +42 -42
37 37
    fragTop: u32,
38 38
}
39 39
40 40
fn newState(nfa: *mut NfaState) -> u32 {
41 41
    let s: u32 = nfa.stateCount;
42 -
    nfa.stateFirst[s] = NIL;
43 -
    nfa.stateCount += 1;
42 +
    set nfa.stateFirst[s] = NIL;
43 +
    set nfa.stateCount += 1;
44 44
    return s;
45 45
}
46 46
47 47
fn addTrans(nfa: *mut NfaState, from: u32, kind: u32, ch: u8, to: u32) {
48 48
    let idx: u32 = nfa.transCount;
49 -
    nfa.trans[idx] = Trans { kind, ch, to };
50 -
    nfa.transNext[idx] = nfa.stateFirst[from];
51 -
    nfa.stateFirst[from] = idx;
52 -
    nfa.transCount += 1;
49 +
    set nfa.trans[idx] = Trans { kind, ch, to };
50 +
    set nfa.transNext[idx] = nfa.stateFirst[from];
51 +
    set nfa.stateFirst[from] = idx;
52 +
    set nfa.transCount += 1;
53 53
}
54 54
55 55
fn pushFrag(nfa: *mut NfaState, f: Frag) {
56 -
    nfa.fragStack[nfa.fragTop] = f;
57 -
    nfa.fragTop += 1;
56 +
    set nfa.fragStack[nfa.fragTop] = f;
57 +
    set nfa.fragTop += 1;
58 58
}
59 59
60 60
fn popFrag(nfa: *mut NfaState) -> Frag {
61 -
    nfa.fragTop -= 1;
61 +
    set nfa.fragTop -= 1;
62 62
    return nfa.fragStack[nfa.fragTop];
63 63
}
64 64
65 65
fn setEmpty(s: *mut [u32]) {
66 -
    s[0] = 0;
67 -
    s[1] = 0;
68 -
    s[2] = 0;
69 -
    s[3] = 0;
66 +
    set s[0] = 0;
67 +
    set s[1] = 0;
68 +
    set s[2] = 0;
69 +
    set s[3] = 0;
70 70
}
71 71
72 72
fn setAdd(s: *mut [u32], bit: u32) {
73 73
    let word: u32 = bit / 32;
74 74
    let pos: u32 = bit % 32;
75 -
    s[word] |= (1 << pos);
75 +
    set s[word] |= (1 << pos);
76 76
}
77 77
78 78
fn setHas(s: *[u32], bit: u32) -> bool {
79 79
    let word: u32 = bit / 32;
80 80
    let pos: u32 = bit % 32;
84 84
fn setIsEmpty(s: *[u32]) -> bool {
85 85
    return s[0] == 0 and s[1] == 0 and s[2] == 0 and s[3] == 0;
86 86
}
87 87
88 88
fn setCopy(dst: *mut [u32], src: *[u32]) {
89 -
    dst[0] = src[0];
90 -
    dst[1] = src[1];
91 -
    dst[2] = src[2];
92 -
    dst[3] = src[3];
89 +
    set dst[0] = src[0];
90 +
    set dst[1] = src[1];
91 +
    set dst[2] = src[2];
92 +
    set dst[3] = src[3];
93 93
}
94 94
95 95
fn epsilonClosure(nfa: *mut NfaState, states: *mut [u32]) {
96 96
    setCopy(nfa.closure, states);
97 97
98 98
    let mut changed: bool = true;
99 99
    while changed {
100 -
        changed = false;
100 +
        set changed = false;
101 101
        let mut s: u32 = 0;
102 102
        while s < nfa.stateCount {
103 103
            if setHas(nfa.closure, s) {
104 104
                let mut t: u32 = nfa.stateFirst[s];
105 105
                while t <> NIL {
106 106
                    if nfa.trans[t].kind == TRANS_EPSILON {
107 107
                        if not setHas(nfa.closure, nfa.trans[t].to) {
108 108
                            setAdd(nfa.closure, nfa.trans[t].to);
109 -
                            changed = true;
109 +
                            set changed = true;
110 110
                        }
111 111
                    }
112 -
                    t = nfa.transNext[t];
112 +
                    set t = nfa.transNext[t];
113 113
                }
114 114
            }
115 -
            s += 1;
115 +
            set s += 1;
116 116
        }
117 117
    }
118 118
119 119
    setCopy(states, nfa.closure);
120 120
}
121 121
122 122
fn resetNFA(nfa: *mut NfaState) {
123 -
    nfa.stateCount = 0;
124 -
    nfa.transCount = 0;
125 -
    nfa.fragTop = 0;
123 +
    set nfa.stateCount = 0;
124 +
    set nfa.transCount = 0;
125 +
    set nfa.fragTop = 0;
126 126
    let mut i: u32 = 0;
127 127
    while i < MAX_STATES {
128 -
        nfa.stateFirst[i] = NIL;
129 -
        i += 1;
128 +
        set nfa.stateFirst[i] = NIL;
129 +
        set i += 1;
130 130
    }
131 -
    i = 0;
131 +
    set i = 0;
132 132
    while i < MAX_TRANSITIONS {
133 -
        nfa.transNext[i] = NIL;
134 -
        i += 1;
133 +
        set nfa.transNext[i] = NIL;
134 +
        set i += 1;
135 135
    }
136 136
}
137 137
138 138
fn compile(nfa: *mut NfaState, pattern: *[u8]) -> u32 {
139 139
    resetNFA(nfa);
158 158
                addTrans(nfa, s, TRANS_EPSILON, 0, body);
159 159
                addTrans(nfa, s, TRANS_EPSILON, 0, e);
160 160
                addTrans(nfa, body, TRANS_EPSILON, 0, e);
161 161
162 162
                pushFrag(nfa, Frag { start: s, endState: e });
163 -
                i += 2;
163 +
                set i += 2;
164 164
                continue;
165 165
            }
166 166
            if nextCh == 43 {
167 167
                let s: u32 = newState(nfa);
168 168
                let m: u32 = newState(nfa);
176 176
                    addTrans(nfa, m, TRANS_CHAR, ch, m);
177 177
                }
178 178
                addTrans(nfa, m, TRANS_EPSILON, 0, e);
179 179
180 180
                pushFrag(nfa, Frag { start: s, endState: e });
181 -
                i += 2;
181 +
                set i += 2;
182 182
                continue;
183 183
            }
184 184
            if nextCh == 63 {
185 185
                let s: u32 = newState(nfa);
186 186
                let m: u32 = newState(nfa);
193 193
                }
194 194
                addTrans(nfa, s, TRANS_EPSILON, 0, e);
195 195
                addTrans(nfa, m, TRANS_EPSILON, 0, e);
196 196
197 197
                pushFrag(nfa, Frag { start: s, endState: e });
198 -
                i += 2;
198 +
                set i += 2;
199 199
                continue;
200 200
            }
201 201
        }
202 202
203 203
        let s: u32 = newState(nfa);
206 206
            addTrans(nfa, s, TRANS_DOT, 0, e);
207 207
        } else {
208 208
            addTrans(nfa, s, TRANS_CHAR, ch, e);
209 209
        }
210 210
        pushFrag(nfa, Frag { start: s, endState: e });
211 -
        i += 1;
211 +
        set i += 1;
212 212
    }
213 213
214 214
    if nfa.fragTop == 0 {
215 215
        let s: u32 = newState(nfa);
216 -
        nfa.acceptState = s;
216 +
        set nfa.acceptState = s;
217 217
        return s;
218 218
    }
219 219
220 220
    let numFrags: u32 = nfa.fragTop;
221 221
    let mut frags: [Frag; 64] = [Frag { start: 0, endState: 0 }; 64];
222 222
    let mut k: u32 = 0;
223 223
    while k < numFrags {
224 -
        frags[numFrags - 1 - k] = popFrag(nfa);
225 -
        k += 1;
224 +
        set frags[numFrags - 1 - k] = popFrag(nfa);
225 +
        set k += 1;
226 226
    }
227 227
228 228
    let mut j: u32 = 0;
229 229
    while j < numFrags - 1 {
230 230
        addTrans(nfa, frags[j].endState, TRANS_EPSILON, 0, frags[j + 1].start);
231 -
        j += 1;
231 +
        set j += 1;
232 232
    }
233 233
234 -
    nfa.acceptState = frags[numFrags - 1].endState;
234 +
    set nfa.acceptState = frags[numFrags - 1].endState;
235 235
    return frags[0].start;
236 236
}
237 237
238 238
fn nfaMatches(nfa: *mut NfaState, start: u32, input: *[u8]) -> bool {
239 239
    setEmpty(nfa.current);
253 253
                    if nfa.trans[t].kind == TRANS_CHAR and nfa.trans[t].ch == ch {
254 254
                        setAdd(nfa.nextSet, nfa.trans[t].to);
255 255
                    } else if nfa.trans[t].kind == TRANS_DOT {
256 256
                        setAdd(nfa.nextSet, nfa.trans[t].to);
257 257
                    }
258 -
                    t = nfa.transNext[t];
258 +
                    set t = nfa.transNext[t];
259 259
                }
260 260
            }
261 -
            s += 1;
261 +
            set s += 1;
262 262
        }
263 263
264 264
        epsilonClosure(nfa, nfa.nextSet);
265 265
        setCopy(nfa.current, nfa.nextSet);
266 266
267 267
        if setIsEmpty(nfa.current) {
268 268
            return false;
269 269
        }
270 -
        i += 1;
270 +
        set i += 1;
271 271
    }
272 272
273 273
    return setHas(nfa.current, nfa.acceptState);
274 274
}
275 275
test/tests/prog.sha256.rad +35 -35
54 54
/// Prepare the message schedule from a 16-word (512-bit) block.
55 55
fn prepareSchedule(s: *mut Sha256, block: *[u32]) {
56 56
    // Copy the first 16 words directly.
57 57
    let mut i: u32 = 0;
58 58
    while i < 16 {
59 -
        s.w[i] = block[i];
60 -
        i += 1;
59 +
        set s.w[i] = block[i];
60 +
        set i += 1;
61 61
    }
62 62
    // Extend to 64 words.
63 63
    while i < 64 {
64 -
        s.w[i] = ssig1(s.w[i - 2]) + s.w[i - 7] + ssig0(s.w[i - 15]) + s.w[i - 16];
65 -
        i += 1;
64 +
        set s.w[i] = ssig1(s.w[i - 2]) + s.w[i - 7] + ssig0(s.w[i - 15]) + s.w[i - 16];
65 +
        set i += 1;
66 66
    }
67 67
}
68 68
69 69
/// Run the 64-round compression function.
70 70
fn compress(s: *mut Sha256, k: *[u32]) {
79 79
80 80
    let mut i: u32 = 0;
81 81
    while i < 64 {
82 82
        let t1 = hh + bsig1(e) + ch(e, f, g) + k[i] + s.w[i];
83 83
        let t2 = bsig0(a) + maj(a, b, c);
84 -
        hh = g;
85 -
        g = f;
86 -
        f = e;
87 -
        e = d + t1;
88 -
        d = c;
89 -
        c = b;
90 -
        b = a;
91 -
        a = t1 + t2;
92 -
        i += 1;
84 +
        set hh = g;
85 +
        set g = f;
86 +
        set f = e;
87 +
        set e = d + t1;
88 +
        set d = c;
89 +
        set c = b;
90 +
        set b = a;
91 +
        set a = t1 + t2;
92 +
        set i += 1;
93 93
    }
94 94
95 -
    s.h[0] += a;
96 -
    s.h[1] += b;
97 -
    s.h[2] += c;
98 -
    s.h[3] += d;
99 -
    s.h[4] += e;
100 -
    s.h[5] += f;
101 -
    s.h[6] += g;
102 -
    s.h[7] += hh;
95 +
    set s.h[0] += a;
96 +
    set s.h[1] += b;
97 +
    set s.h[2] += c;
98 +
    set s.h[3] += d;
99 +
    set s.h[4] += e;
100 +
    set s.h[5] += f;
101 +
    set s.h[6] += g;
102 +
    set s.h[7] += hh;
103 103
}
104 104
105 105
/// Reset hash state to initial values.
106 106
fn resetHash(s: *mut Sha256) {
107 107
    let mut i: u32 = 0;
108 108
    while i < 8 {
109 -
        s.h[i] = INIT_H[i];
110 -
        i += 1;
109 +
        set s.h[i] = INIT_H[i];
110 +
        set i += 1;
111 111
    }
112 112
}
113 113
114 114
/// Pad and hash a short message (up to 55 bytes, fits in one 512-bit block).
115 115
fn hashMessage(s: *mut Sha256, k: *[u32], msg: *[u8]) -> i32 {
122 122
    let mut blockBytes: [u8; 64] = [0; 64];
123 123
124 124
    // Copy message.
125 125
    let mut i: u32 = 0;
126 126
    while i < msg.len {
127 -
        blockBytes[i] = msg[i];
128 -
        i += 1;
127 +
        set blockBytes[i] = msg[i];
128 +
        set i += 1;
129 129
    }
130 130
131 131
    // Append the 1-bit (0x80).
132 -
    blockBytes[msg.len] = 0x80;
132 +
    set blockBytes[msg.len] = 0x80;
133 133
134 134
    // Append length in bits as big-endian 64-bit integer at the end.
135 135
    let bitLen: u32 = msg.len * 8;
136 -
    blockBytes[60] = (bitLen >> 24) as u8;
137 -
    blockBytes[61] = (bitLen >> 16) as u8;
138 -
    blockBytes[62] = (bitLen >> 8) as u8;
139 -
    blockBytes[63] = bitLen as u8;
136 +
    set blockBytes[60] = (bitLen >> 24) as u8;
137 +
    set blockBytes[61] = (bitLen >> 16) as u8;
138 +
    set blockBytes[62] = (bitLen >> 8) as u8;
139 +
    set blockBytes[63] = bitLen as u8;
140 140
141 141
    // Convert bytes to 16 big-endian 32-bit words.
142 142
    let mut block: [u32; 16] = [0; 16];
143 143
    let mut w: u32 = 0;
144 144
    while w < 16 {
145 145
        let base = w * 4;
146 -
        block[w] = (blockBytes[base] as u32 << 24)
147 -
                  | (blockBytes[base + 1] as u32 << 16)
148 -
                  | (blockBytes[base + 2] as u32 << 8)
149 -
                  | (blockBytes[base + 3] as u32);
150 -
        w += 1;
146 +
        set block[w] = (blockBytes[base] as u32 << 24)
147 +
                     | (blockBytes[base + 1] as u32 << 16)
148 +
                     | (blockBytes[base + 2] as u32 << 8)
149 +
                     | (blockBytes[base + 3] as u32);
150 +
        set w += 1;
151 151
    }
152 152
153 153
    resetHash(s);
154 154
    prepareSchedule(s, &block[..]);
155 155
    compress(s, k);
test/tests/prog.sieve.rad +9 -9
5 5
6 6
/// Mark all multiples of p as composite.
7 7
fn markMultiples(sieve: *mut [bool], p: u32) {
8 8
    let mut i: u32 = p * p;
9 9
    while i < sieve.len {
10 -
        sieve[i] = true;
11 -
        i += p;
10 +
        set sieve[i] = true;
11 +
        set i += p;
12 12
    }
13 13
}
14 14
15 15
/// Run the sieve algorithm.
16 16
fn runSieve(sieve: *mut [bool]) {
17 17
    // 0 and 1 are not prime.
18 -
    sieve[0] = true;
19 -
    sieve[1] = true;
18 +
    set sieve[0] = true;
19 +
    set sieve[1] = true;
20 20
21 21
    let mut p: u32 = 2;
22 22
    while p * p < sieve.len {
23 23
        if not sieve[p] {
24 24
            markMultiples(sieve, p);
25 25
        }
26 -
        p += 1;
26 +
        set p += 1;
27 27
    }
28 28
}
29 29
30 30
/// Count the number of primes found.
31 31
fn countPrimes(sieve: *[bool]) -> u32 {
32 32
    let mut count: u32 = 0;
33 33
    for composite in sieve {
34 34
        if not composite {
35 -
            count += 1;
35 +
            set count += 1;
36 36
        }
37 37
    }
38 38
    return count;
39 39
}
40 40
42 42
fn collectPrimes(sieve: *[bool], primes: *mut [u32]) -> u32 {
43 43
    let mut count: u32 = 0;
44 44
    for composite, idx in sieve {
45 45
        if not composite {
46 46
            if count < primes.len {
47 -
                primes[count] = idx;
48 -
                count += 1;
47 +
                set primes[count] = idx;
48 +
                set count += 1;
49 49
            }
50 50
        }
51 51
    }
52 52
    return count;
53 53
}
96 96
    let mut prev: ?u32 = nil;
97 97
    for p in collected {
98 98
        if let prevVal = prev {
99 99
            assert prevVal < p;
100 100
        }
101 -
        prev = p;
101 +
        set prev = p;
102 102
    }
103 103
    return 0;
104 104
}
105 105
106 106
@default fn main() -> i32 {
test/tests/prog.symtab.rad +28 -28
41 41
42 42
/// Simple string hash function.
43 43
fn hashName(name: *[u8]) -> u32 {
44 44
    let mut h: u32 = 5381;
45 45
    for ch in name {
46 -
        h = ((h << 5) + h) + ch as u32;
46 +
        set h = ((h << 5) + h) + ch as u32;
47 47
    }
48 48
    return h;
49 49
}
50 50
51 51
/// Initialize the symbol table.
52 52
fn init(tab: *mut SymTab) {
53 -
    tab.symbolCount = 0;
54 -
    tab.scopeDepth = 0;
53 +
    set tab.symbolCount = 0;
54 +
    set tab.scopeDepth = 0;
55 55
56 56
    for i in 0..HASH_SIZE {
57 -
        tab.buckets[i] = NIL;
57 +
        set tab.buckets[i] = NIL;
58 58
    }
59 59
}
60 60
61 61
/// Push a new scope.
62 62
fn pushScope(tab: *mut SymTab) {
63 -
    tab.scopes[tab.scopeDepth] = ScopeMarker { symbolCount: tab.symbolCount };
64 -
    tab.scopeDepth += 1;
63 +
    set tab.scopes[tab.scopeDepth] = ScopeMarker { symbolCount: tab.symbolCount };
64 +
    set tab.scopeDepth += 1;
65 65
}
66 66
67 67
/// Pop the current scope, removing all symbols defined in it.
68 68
fn popScope(tab: *mut SymTab) {
69 69
    if tab.scopeDepth == 0 {
70 70
        return;
71 71
    }
72 -
    tab.scopeDepth -= 1;
72 +
    set tab.scopeDepth -= 1;
73 73
    let marker = tab.scopes[tab.scopeDepth];
74 74
75 75
    // Remove symbols added in this scope (in reverse order).
76 76
    while tab.symbolCount > marker.symbolCount {
77 -
        tab.symbolCount -= 1;
77 +
        set tab.symbolCount -= 1;
78 78
        let sym = tab.symbols[tab.symbolCount];
79 79
        let bucket = sym.nameHash % HASH_SIZE;
80 80
81 81
        // Remove from hash chain.
82 -
        tab.buckets[bucket] = sym.next;
82 +
        set tab.buckets[bucket] = sym.next;
83 83
84 84
        // Restore shadowed symbol if any.
85 85
        if sym.shadow <> NIL {
86 86
            // The shadowed symbol is still in the symbols array;
87 87
            // re-link it into the hash chain.
88 88
            let shadowIdx = sym.shadow;
89 -
            tab.symbols[shadowIdx].next = tab.buckets[bucket];
90 -
            tab.buckets[bucket] = shadowIdx;
89 +
            set tab.symbols[shadowIdx].next = tab.buckets[bucket];
90 +
            set tab.buckets[bucket] = shadowIdx;
91 91
        }
92 92
    }
93 93
}
94 94
95 95
/// Define a symbol in the current scope.
102 102
    let mut cur = tab.buckets[bucket];
103 103
    while cur <> NIL {
104 104
        if tab.symbols[cur].nameHash == h {
105 105
            // Found existing symbol with same hash - shadow it.
106 106
            // Remove it from hash chain first.
107 -
            shadowIdx = cur;
107 +
            set shadowIdx = cur;
108 108
            // Remove the shadowed symbol from the bucket chain.
109 109
            if tab.buckets[bucket] == cur {
110 -
                tab.buckets[bucket] = tab.symbols[cur].next;
110 +
                set tab.buckets[bucket] = tab.symbols[cur].next;
111 111
            }
112 112
            break;
113 113
        }
114 -
        cur = tab.symbols[cur].next;
114 +
        set cur = tab.symbols[cur].next;
115 115
    }
116 116
117 117
    let idx = tab.symbolCount;
118 -
    tab.symbols[idx] = Symbol {
118 +
    set tab.symbols[idx] = Symbol {
119 119
        nameHash: h,
120 120
        value,
121 121
        depth: tab.scopeDepth,
122 122
        next: tab.buckets[bucket],
123 123
        shadow: shadowIdx,
124 124
    };
125 -
    tab.buckets[bucket] = idx;
126 -
    tab.symbolCount += 1;
125 +
    set tab.buckets[bucket] = idx;
126 +
    set tab.symbolCount += 1;
127 127
    return idx;
128 128
}
129 129
130 130
/// Look up a symbol by name. Returns the value if found.
131 131
fn lookup(tab: *SymTab, name: *[u8]) -> ?i32 {
135 135
136 136
    while cur <> NIL {
137 137
        if tab.symbols[cur].nameHash == h {
138 138
            return tab.symbols[cur].value;
139 139
        }
140 -
        cur = tab.symbols[cur].next;
140 +
        set cur = tab.symbols[cur].next;
141 141
    }
142 142
    return nil;
143 143
}
144 144
145 145
/// Update a symbol's value. Returns true if the symbol was found.
148 148
    let bucket = h % HASH_SIZE;
149 149
    let mut cur = tab.buckets[bucket];
150 150
151 151
    while cur <> NIL {
152 152
        if tab.symbols[cur].nameHash == h {
153 -
            tab.symbols[cur].value = newValue;
153 +
            set tab.symbols[cur].value = newValue;
154 154
            return true;
155 155
        }
156 -
        cur = tab.symbols[cur].next;
156 +
        set cur = tab.symbols[cur].next;
157 157
    }
158 158
    return false;
159 159
}
160 160
161 161
/// Test basic define and lookup.
231 231
    // Define x at each of 8 scope levels.
232 232
    let mut i: u32 = 0;
233 233
    while i < 8 {
234 234
        pushScope(tab);
235 235
        define(tab, "x", i as i32 * 10);
236 -
        i += 1;
236 +
        set i += 1;
237 237
    }
238 238
239 239
    // x should be the innermost value.
240 240
    let x = lookup(tab, "x") else {
241 241
        return 1;
242 242
    };
243 243
    assert x == 70;
244 244
245 245
    // Pop scopes one by one and check.
246 -
    i = 7;
246 +
    set i = 7;
247 247
    while i > 0 {
248 248
        popScope(tab);
249 249
        let val = lookup(tab, "x") else {
250 250
            return 3;
251 251
        };
252 252
        let expected = (i - 1) as i32 * 10;
253 253
        assert val == expected;
254 -
        i -= 1;
254 +
        set i -= 1;
255 255
    }
256 256
257 257
    popScope(tab);
258 258
    return 0;
259 259
}
273 273
274 274
    // Verify all of them.
275 275
    let mut sum: i32 = 0;
276 276
    for name, i in names {
277 277
        if let val = lookup(tab, name) {
278 -
            sum += val;
278 +
            set sum += val;
279 279
        } else {
280 280
            return 1;
281 281
        }
282 282
    }
283 283
300 300
    while i < 10 {
301 301
        let cur = lookup(tab, "counter") else {
302 302
            return 1;
303 303
        };
304 304
        assert update(tab, "counter", cur + 1);
305 -
        i += 1;
305 +
        set i += 1;
306 306
    }
307 307
308 308
    let finalVal = lookup(tab, "counter") else {
309 309
        return 3;
310 310
    };
378 378
        let result = lookup(tab, name);
379 379
        if let exp = expected[i] {
380 380
            // We expect a value.
381 381
            if let r = result {
382 382
                if r <> exp {
383 -
                    failures += 1;
383 +
                    set failures += 1;
384 384
                }
385 385
            } else {
386 -
                failures += 1;
386 +
                set failures += 1;
387 387
            }
388 388
        } else {
389 389
            // We expect nil.
390 390
            if let _ = result {
391 -
                failures += 1;
391 +
                set failures += 1;
392 392
            }
393 393
        }
394 394
    }
395 395
396 396
    if failures <> 0 {
test/tests/prog.tokenizer.rad +21 -21
86 86
}
87 87
88 88
/// Advance the lexer by one character.
89 89
fn advance(lex: *mut Lexer) {
90 90
    if lex.pos < lex.source.len {
91 -
        lex.pos += 1;
91 +
        set lex.pos += 1;
92 92
    }
93 93
}
94 94
95 95
/// Skip whitespace characters.
96 96
fn skipWhitespace(lex: *mut Lexer) {
101 101
102 102
/// Scan a number literal.
103 103
fn scanNumber(lex: *mut Lexer) -> i32 {
104 104
    let mut value: i32 = 0;
105 105
    while let ch = peek(lex); isDigit(ch) {
106 -
        value = value * 10 + (ch - 48) as i32;
106 +
        set value = value * 10 + (ch - 48) as i32;
107 107
        advance(lex);
108 108
    }
109 109
    return value;
110 110
}
111 111
140 140
        match tok {
141 141
            case Token::Invalid(_) => {
142 142
                return false;
143 143
            }
144 144
            case Token::Eof => {
145 -
                list.tokens[list.count] = tok;
146 -
                list.count += 1;
147 -
                done = true;
145 +
                set list.tokens[list.count] = tok;
146 +
                set list.count += 1;
147 +
                set done = true;
148 148
            }
149 149
            else => {
150 150
                if list.count >= list.tokens.len - 1 {
151 151
                    return false;
152 152
                }
153 -
                list.tokens[list.count] = tok;
154 -
                list.count += 1;
153 +
                set list.tokens[list.count] = tok;
154 +
                set list.count += 1;
155 155
            }
156 156
        }
157 157
    }
158 158
    return true;
159 159
}
160 160
161 161
/// Allocate a new expression node.
162 162
fn newExpr(pool: *mut ExprPool, expr: Expr) -> u32 {
163 163
    let idx = pool.count;
164 -
    pool.nodes[idx] = expr;
165 -
    pool.count += 1;
164 +
    set pool.nodes[idx] = expr;
165 +
    set pool.count += 1;
166 166
    return idx;
167 167
}
168 168
169 169
/// Get the current token in the parser.
170 170
fn currentToken(p: *Parser) -> Token {
175 175
}
176 176
177 177
/// Advance the parser to the next token.
178 178
fn advanceParser(p: *mut Parser) {
179 179
    if p.pos < p.tokenCount {
180 -
        p.pos += 1;
180 +
        set p.pos += 1;
181 181
    }
182 182
}
183 183
184 184
/// Parse a primary expression (number, parenthesized expression, or unary minus).
185 185
fn parsePrimary(p: *mut Parser) -> ?u32 {
230 230
        let tok = currentToken(p);
231 231
        match tok {
232 232
            case Token::Star => {
233 233
                advanceParser(p);
234 234
                if let right = parsePrimary(p) {
235 -
                    result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 42, left: result, right }));
235 +
                    set result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 42, left: result, right }));
236 236
                } else {
237 -
                    cont = false;
237 +
                    set cont = false;
238 238
                }
239 239
            }
240 240
            case Token::Slash => {
241 241
                advanceParser(p);
242 242
                if let right = parsePrimary(p) {
243 -
                    result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 47, left: result, right }));
243 +
                    set result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 47, left: result, right }));
244 244
                } else {
245 -
                    cont = false;
245 +
                    set cont = false;
246 246
                }
247 247
            }
248 248
            else => {
249 -
                cont = false;
249 +
                set cont = false;
250 250
            }
251 251
        }
252 252
    }
253 253
    return result;
254 254
}
263 263
        match tok {
264 264
            case Token::Plus => {
265 265
                advanceParser(p);
266 266
                if let right = parsePrimary(p) {
267 267
                    let rhs = parseMulDiv(p, right);
268 -
                    result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 43, left: result, right: rhs }));
268 +
                    set result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 43, left: result, right: rhs }));
269 269
                } else {
270 -
                    cont = false;
270 +
                    set cont = false;
271 271
                }
272 272
            }
273 273
            case Token::Minus => {
274 274
                advanceParser(p);
275 275
                if let right = parsePrimary(p) {
276 276
                    let rhs = parseMulDiv(p, right);
277 -
                    result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 45, left: result, right: rhs }));
277 +
                    set result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 45, left: result, right: rhs }));
278 278
                } else {
279 -
                    cont = false;
279 +
                    set cont = false;
280 280
                }
281 281
            }
282 282
            else => {
283 -
                cont = false;
283 +
                set cont = false;
284 284
            }
285 285
        }
286 286
    }
287 287
    return result;
288 288
}
444 444
    let mut numCount: u32 = 0;
445 445
    let slice = &tokenBuf[0..list.count];
446 446
    for tok in slice {
447 447
        match tok {
448 448
            case Token::Number(_) => {
449 -
                numCount += 1;
449 +
                set numCount += 1;
450 450
            }
451 451
            else => {}
452 452
        }
453 453
    }
454 454
    assert numCount == 3;
test/tests/prog.vm.rad +117 -117
85 85
/// Push a value onto the stack.
86 86
fn push(vm: *mut VM, value: i32) throws (VmError) {
87 87
    if vm.sp >= MAX_STACK {
88 88
        throw VmError::StackOverflow;
89 89
    }
90 -
    vm.stack[vm.sp] = value;
91 -
    vm.sp += 1;
90 +
    set vm.stack[vm.sp] = value;
91 +
    set vm.sp += 1;
92 92
}
93 93
94 94
/// Pop a value from the stack.
95 95
fn pop(vm: *mut VM) -> i32 throws (VmError) {
96 96
    if vm.sp == 0 {
97 97
        throw VmError::StackUnderflow;
98 98
    }
99 -
    vm.sp -= 1;
99 +
    set vm.sp -= 1;
100 100
    return vm.stack[vm.sp];
101 101
}
102 102
103 103
/// Peek at the top of the stack without removing.
104 104
fn peek(vm: *VM) -> i32 throws (VmError) {
110 110
111 111
/// Execute the bytecode program.
112 112
fn execute(vm: *mut VM) -> i32 throws (VmError) {
113 113
    while vm.pc < vm.codeLen {
114 114
        let instr = vm.code[vm.pc];
115 -
        vm.pc += 1;
115 +
        set vm.pc += 1;
116 116
117 117
        match instr {
118 118
            case Op::Push(val) => {
119 119
                try push(vm, val);
120 120
            }
144 144
            case Op::Eq => {
145 145
                let b = try pop(vm);
146 146
                let a = try pop(vm);
147 147
                let mut result: i32 = 0;
148 148
                if a == b {
149 -
                    result = 1;
149 +
                    set result = 1;
150 150
                }
151 151
                try push(vm, result);
152 152
            }
153 153
            case Op::Lt => {
154 154
                let b = try pop(vm);
155 155
                let a = try pop(vm);
156 156
                let mut result: i32 = 0;
157 157
                if a < b {
158 -
                    result = 1;
158 +
                    set result = 1;
159 159
                }
160 160
                try push(vm, result);
161 161
            }
162 162
            case Op::Gt => {
163 163
                let b = try pop(vm);
164 164
                let a = try pop(vm);
165 165
                let mut result: i32 = 0;
166 166
                if a > b {
167 -
                    result = 1;
167 +
                    set result = 1;
168 168
                }
169 169
                try push(vm, result);
170 170
            }
171 171
            case Op::Neg => {
172 172
                let a = try pop(vm);
181 181
            }
182 182
            case Op::Store(idx) => {
183 183
                let val = try pop(vm);
184 184
                let mut base: u32 = 0;
185 185
                if vm.frameCount > 0 {
186 -
                    base = vm.frames[vm.frameCount - 1].localBase;
186 +
                    set base = vm.frames[vm.frameCount - 1].localBase;
187 187
                }
188 -
                vm.locals[base + idx] = val;
188 +
                set vm.locals[base + idx] = val;
189 189
            }
190 190
            case Op::Load(idx) => {
191 191
                let mut base: u32 = 0;
192 192
                if vm.frameCount > 0 {
193 -
                    base = vm.frames[vm.frameCount - 1].localBase;
193 +
                    set base = vm.frames[vm.frameCount - 1].localBase;
194 194
                }
195 195
                let val = vm.locals[base + idx];
196 196
                try push(vm, val);
197 197
            }
198 198
            case Op::Jump(target) => {
199 -
                vm.pc = target;
199 +
                set vm.pc = target;
200 200
            }
201 201
            case Op::JumpIfZero(target) => {
202 202
                let cond = try pop(vm);
203 203
                if cond == 0 {
204 -
                    vm.pc = target;
204 +
                    set vm.pc = target;
205 205
                }
206 206
            }
207 207
            case Op::Call(target) => {
208 208
                if vm.frameCount >= MAX_FRAMES {
209 209
                    throw VmError::CallOverflow;
210 210
                }
211 211
                let mut base: u32 = 0;
212 212
                if vm.frameCount > 0 {
213 -
                    base = vm.frames[vm.frameCount - 1].localBase + MAX_LOCALS;
213 +
                    set base = vm.frames[vm.frameCount - 1].localBase + MAX_LOCALS;
214 214
                }
215 -
                vm.frames[vm.frameCount] = Frame { returnAddr: vm.pc, localBase: base };
216 -
                vm.frameCount += 1;
217 -
                vm.pc = target;
215 +
                set vm.frames[vm.frameCount] = Frame { returnAddr: vm.pc, localBase: base };
216 +
                set vm.frameCount += 1;
217 +
                set vm.pc = target;
218 218
            }
219 219
            case Op::Ret => {
220 220
                if vm.frameCount == 0 {
221 221
                    throw VmError::InvalidPC;
222 222
                }
223 -
                vm.frameCount -= 1;
224 -
                vm.pc = vm.frames[vm.frameCount].returnAddr;
223 +
                set vm.frameCount -= 1;
224 +
                set vm.pc = vm.frames[vm.frameCount].returnAddr;
225 225
            }
226 226
            case Op::Halt => {
227 227
                return try pop(vm);
228 228
            }
229 229
        }
257 257
}
258 258
259 259
/// Test basic arithmetic: 3 + 4 * 2 = 11
260 260
fn testArith(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
261 261
    let mut code: [Op; 8] = [Op::Halt; 8];
262 -
    code[0] = Op::Push(3);
263 -
    code[1] = Op::Push(4);
264 -
    code[2] = Op::Push(2);
265 -
    code[3] = Op::Mul;
266 -
    code[4] = Op::Add;
267 -
    code[5] = Op::Halt;
262 +
    set code[0] = Op::Push(3);
263 +
    set code[1] = Op::Push(4);
264 +
    set code[2] = Op::Push(2);
265 +
    set code[3] = Op::Mul;
266 +
    set code[4] = Op::Add;
267 +
    set code[5] = Op::Halt;
268 268
269 269
    let result: i32 = try! runProgram(&code[..], 6, stackBuf, localsBuf, framesBuf);
270 270
    assert result == 11;
271 271
    return 0;
272 272
}
273 273
274 274
/// Test local variables: x = 5, y = 7, push x + y.
275 275
fn testLocals(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
276 276
    let mut code: [Op; 16] = [Op::Halt; 16];
277 -
    code[0] = Op::Push(5);
278 -
    code[1] = Op::Store(0);   // x = 5
279 -
    code[2] = Op::Push(7);
280 -
    code[3] = Op::Store(1);   // y = 7
281 -
    code[4] = Op::Load(0);    // push x
282 -
    code[5] = Op::Load(1);    // push y
283 -
    code[6] = Op::Add;        // x + y
284 -
    code[7] = Op::Halt;
277 +
    set code[0] = Op::Push(5);
278 +
    set code[1] = Op::Store(0);   // x = 5
279 +
    set code[2] = Op::Push(7);
280 +
    set code[3] = Op::Store(1);   // y = 7
281 +
    set code[4] = Op::Load(0);    // push x
282 +
    set code[5] = Op::Load(1);    // push y
283 +
    set code[6] = Op::Add;        // x + y
284 +
    set code[7] = Op::Halt;
285 285
286 286
    let result: i32 = try! runProgram(&code[..], 8, stackBuf, localsBuf, framesBuf);
287 287
    assert result == 12;
288 288
    return 0;
289 289
}
290 290
291 291
/// Test conditional jump: if 3 > 2 then push 42 else push 99.
292 292
fn testConditional(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
293 293
    let mut code: [Op; 16] = [Op::Halt; 16];
294 -
    code[0] = Op::Push(3);
295 -
    code[1] = Op::Push(2);
296 -
    code[2] = Op::Gt;            // 3 > 2 => 1
297 -
    code[3] = Op::JumpIfZero(6); // if false, jump to 6
298 -
    code[4] = Op::Push(42);      // true branch
299 -
    code[5] = Op::Jump(7);       // skip false branch
300 -
    code[6] = Op::Push(99);      // false branch
301 -
    code[7] = Op::Halt;
294 +
    set code[0] = Op::Push(3);
295 +
    set code[1] = Op::Push(2);
296 +
    set code[2] = Op::Gt;            // 3 > 2 => 1
297 +
    set code[3] = Op::JumpIfZero(6); // if false, jump to 6
298 +
    set code[4] = Op::Push(42);      // true branch
299 +
    set code[5] = Op::Jump(7);       // skip false branch
300 +
    set code[6] = Op::Push(99);      // false branch
301 +
    set code[7] = Op::Halt;
302 302
303 303
    let result: i32 = try! runProgram(&code[..], 8, stackBuf, localsBuf, framesBuf);
304 304
    assert result == 42;
305 305
    return 0;
306 306
}
307 307
308 308
/// Test loop: sum 1..5 using jumps.
309 309
/// local[0] = counter (starts at 1), local[1] = sum (starts at 0).
310 310
fn testLoop(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
311 311
    let mut code: [Op; 32] = [Op::Halt; 32];
312 -
    code[0] = Op::Push(1);
313 -
    code[1] = Op::Store(0);      // counter = 1
314 -
    code[2] = Op::Push(0);
315 -
    code[3] = Op::Store(1);      // sum = 0
312 +
    set code[0] = Op::Push(1);
313 +
    set code[1] = Op::Store(0);      // counter = 1
314 +
    set code[2] = Op::Push(0);
315 +
    set code[3] = Op::Store(1);      // sum = 0
316 316
    // Loop start (pc = 4):
317 -
    code[4] = Op::Load(0);       // push counter
318 -
    code[5] = Op::Push(6);
319 -
    code[6] = Op::Lt;            // counter < 6
320 -
    code[7] = Op::JumpIfZero(17); // if false, exit loop
321 -
    code[8] = Op::Load(1);       // push sum
322 -
    code[9] = Op::Load(0);       // push counter
323 -
    code[10] = Op::Add;          // sum + counter
324 -
    code[11] = Op::Store(1);     // sum = sum + counter
325 -
    code[12] = Op::Load(0);      // push counter
326 -
    code[13] = Op::Push(1);
327 -
    code[14] = Op::Add;          // counter + 1
328 -
    code[15] = Op::Store(0);     // counter = counter + 1
329 -
    code[16] = Op::Jump(4);      // back to loop start
330 -
    code[17] = Op::Load(1);      // push sum
331 -
    code[18] = Op::Halt;
317 +
    set code[4] = Op::Load(0);       // push counter
318 +
    set code[5] = Op::Push(6);
319 +
    set code[6] = Op::Lt;            // counter < 6
320 +
    set code[7] = Op::JumpIfZero(17); // if false, exit loop
321 +
    set code[8] = Op::Load(1);       // push sum
322 +
    set code[9] = Op::Load(0);       // push counter
323 +
    set code[10] = Op::Add;          // sum + counter
324 +
    set code[11] = Op::Store(1);     // sum = sum + counter
325 +
    set code[12] = Op::Load(0);      // push counter
326 +
    set code[13] = Op::Push(1);
327 +
    set code[14] = Op::Add;          // counter + 1
328 +
    set code[15] = Op::Store(0);     // counter = counter + 1
329 +
    set code[16] = Op::Jump(4);      // back to loop start
330 +
    set code[17] = Op::Load(1);      // push sum
331 +
    set code[18] = Op::Halt;
332 332
333 333
    let result: i32 = try! runProgram(&code[..], 19, stackBuf, localsBuf, framesBuf);
334 334
    // sum = 1+2+3+4+5 = 15
335 335
    assert result == 15;
336 336
    return 0;
339 339
/// Test function call: call a function that computes n*2+1 for n=10.
340 340
fn testCall(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
341 341
    let mut code: [Op; 32] = [Op::Halt; 32];
342 342
343 343
    // Main: push argument on stack, call function, halt.
344 -
    code[0] = Op::Push(10);      // push argument
345 -
    code[1] = Op::Call(5);       // call function at 5
344 +
    set code[0] = Op::Push(10);      // push argument
345 +
    set code[1] = Op::Call(5);       // call function at 5
346 346
    // After return, result is on stack.
347 -
    code[2] = Op::Halt;
348 -
    code[3] = Op::Halt;          // padding
349 -
    code[4] = Op::Halt;          // padding
347 +
    set code[2] = Op::Halt;
348 +
    set code[3] = Op::Halt;          // padding
349 +
    set code[4] = Op::Halt;          // padding
350 350
351 351
    // Function at pc 5:
352 -
    code[5] = Op::Store(0);      // pop arg into local[0]
353 -
    code[6] = Op::Load(0);       // push local[0]
354 -
    code[7] = Op::Push(2);
355 -
    code[8] = Op::Mul;           // n * 2
356 -
    code[9] = Op::Push(1);
357 -
    code[10] = Op::Add;          // n * 2 + 1
358 -
    code[11] = Op::Ret;          // return (result on stack)
352 +
    set code[5] = Op::Store(0);      // pop arg into local[0]
353 +
    set code[6] = Op::Load(0);       // push local[0]
354 +
    set code[7] = Op::Push(2);
355 +
    set code[8] = Op::Mul;           // n * 2
356 +
    set code[9] = Op::Push(1);
357 +
    set code[10] = Op::Add;          // n * 2 + 1
358 +
    set code[11] = Op::Ret;          // return (result on stack)
359 359
360 360
    let result: i32 = try! runProgram(&code[..], 12, stackBuf, localsBuf, framesBuf);
361 361
    // 10 * 2 + 1 = 21
362 362
    assert result == 21;
363 363
    return 0;
364 364
}
365 365
366 366
/// Test division by zero detection using try...catch with error binding.
367 367
fn testDivByZero(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
368 368
    let mut code: [Op; 8] = [Op::Halt; 8];
369 -
    code[0] = Op::Push(42);
370 -
    code[1] = Op::Push(0);
371 -
    code[2] = Op::Div;
372 -
    code[3] = Op::Halt;
369 +
    set code[0] = Op::Push(42);
370 +
    set code[1] = Op::Push(0);
371 +
    set code[2] = Op::Div;
372 +
    set code[3] = Op::Halt;
373 373
374 374
    let mut caught: i32 = 0;
375 375
    try runProgram(&code[..], 4, stackBuf, localsBuf, framesBuf) catch e {
376 376
        if e == VmError::DivByZero {
377 -
            caught = 1;
377 +
            set caught = 1;
378 378
        } else {
379 -
            caught = 2;
379 +
            set caught = 2;
380 380
        }
381 381
    };
382 382
    assert caught == 1;
383 383
    return 0;
384 384
}
385 385
386 386
/// Test negation and equality.
387 387
fn testNegAndEq(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
388 388
    let mut code: [Op; 16] = [Op::Halt; 16];
389 -
    code[0] = Op::Push(5);
390 -
    code[1] = Op::Neg;           // -5
391 -
    code[2] = Op::Push(-5);
392 -
    code[3] = Op::Eq;            // -5 == -5 => 1
393 -
    code[4] = Op::Halt;
389 +
    set code[0] = Op::Push(5);
390 +
    set code[1] = Op::Neg;           // -5
391 +
    set code[2] = Op::Push(-5);
392 +
    set code[3] = Op::Eq;            // -5 == -5 => 1
393 +
    set code[4] = Op::Halt;
394 394
395 395
    let result: i32 = try! runProgram(&code[..], 5, stackBuf, localsBuf, framesBuf);
396 396
    assert result == 1;
397 397
    return 0;
398 398
}
400 400
/// Test factorial using recursive calls: fact(6) = 720.
401 401
fn testFactorial(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
402 402
    let mut code: [Op; 32] = [Op::Halt; 32];
403 403
404 404
    // Main: push 6, call fact, halt.
405 -
    code[0] = Op::Push(6);
406 -
    code[1] = Op::Call(4);       // call fact at 4
407 -
    code[2] = Op::Halt;
408 -
    code[3] = Op::Halt;          // padding
405 +
    set code[0] = Op::Push(6);
406 +
    set code[1] = Op::Call(4);       // call fact at 4
407 +
    set code[2] = Op::Halt;
408 +
    set code[3] = Op::Halt;          // padding
409 409
410 410
    // fact(n) at pc 4:
411 411
    //   Store arg to local[0]
412 412
    //   If n <= 1, push 1, return
413 413
    //   Else push n, push fact(n-1), multiply, return
414 -
    code[4] = Op::Store(0);      // local[0] = n
415 -
    code[5] = Op::Load(0);       // push n
416 -
    code[6] = Op::Push(2);
417 -
    code[7] = Op::Lt;            // n < 2
418 -
    code[8] = Op::JumpIfZero(11); // if n >= 2, skip
419 -
    code[9] = Op::Push(1);       // base case: push 1
420 -
    code[10] = Op::Ret;
414 +
    set code[4] = Op::Store(0);      // local[0] = n
415 +
    set code[5] = Op::Load(0);       // push n
416 +
    set code[6] = Op::Push(2);
417 +
    set code[7] = Op::Lt;            // n < 2
418 +
    set code[8] = Op::JumpIfZero(11); // if n >= 2, skip
419 +
    set code[9] = Op::Push(1);       // base case: push 1
420 +
    set code[10] = Op::Ret;
421 421
422 422
    // Recursive case:
423 -
    code[11] = Op::Load(0);      // push n
424 -
    code[12] = Op::Push(1);
425 -
    code[13] = Op::Sub;          // n - 1
426 -
    code[14] = Op::Call(4);      // fact(n-1)
427 -
    code[15] = Op::Load(0);      // push n
428 -
    code[16] = Op::Mul;          // fact(n-1) * n
429 -
    code[17] = Op::Ret;
423 +
    set code[11] = Op::Load(0);      // push n
424 +
    set code[12] = Op::Push(1);
425 +
    set code[13] = Op::Sub;          // n - 1
426 +
    set code[14] = Op::Call(4);      // fact(n-1)
427 +
    set code[15] = Op::Load(0);      // push n
428 +
    set code[16] = Op::Mul;          // fact(n-1) * n
429 +
    set code[17] = Op::Ret;
430 430
431 431
    let result: i32 = try! runProgram(&code[..], 18, stackBuf, localsBuf, framesBuf);
432 432
    assert result == 720;
433 433
    return 0;
434 434
}
435 435
436 436
/// Test dup instruction.
437 437
fn testDup(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
438 438
    let mut code: [Op; 8] = [Op::Halt; 8];
439 -
    code[0] = Op::Push(7);
440 -
    code[1] = Op::Dup;
441 -
    code[2] = Op::Add;           // 7 + 7 = 14
442 -
    code[3] = Op::Halt;
439 +
    set code[0] = Op::Push(7);
440 +
    set code[1] = Op::Dup;
441 +
    set code[2] = Op::Add;           // 7 + 7 = 14
442 +
    set code[3] = Op::Halt;
443 443
444 444
    let result: i32 = try! runProgram(&code[..], 4, stackBuf, localsBuf, framesBuf);
445 445
    assert result == 14;
446 446
    return 0;
447 447
}
448 448
449 449
/// Test stack underflow detection using try...catch with error binding.
450 450
fn testStackUnderflow(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
451 451
    let mut code: [Op; 4] = [Op::Halt; 4];
452 -
    code[0] = Op::Add;  // nothing on stack
453 -
    code[1] = Op::Halt;
452 +
    set code[0] = Op::Add;  // nothing on stack
453 +
    set code[1] = Op::Halt;
454 454
455 455
    let mut caught: i32 = 0;
456 456
    try runProgram(&code[..], 2, stackBuf, localsBuf, framesBuf) catch e {
457 457
        if e == VmError::StackUnderflow {
458 -
            caught = 1;
458 +
            set caught = 1;
459 459
        } else {
460 -
            caught = 2;
460 +
            set caught = 2;
461 461
        }
462 462
    };
463 463
    assert caught == 1;
464 464
    return 0;
465 465
}
466 466
467 467
/// Test that try...catch on success path does not execute catch block.
468 468
fn testSuccessNoCatch(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
469 469
    let mut code: [Op; 4] = [Op::Halt; 4];
470 -
    code[0] = Op::Push(99);
471 -
    code[1] = Op::Halt;
470 +
    set code[0] = Op::Push(99);
471 +
    set code[1] = Op::Halt;
472 472
473 473
    let mut caught: i32 = 0;
474 474
    let result: i32 = try runProgram(&code[..], 2, stackBuf, localsBuf, framesBuf) catch e {
475 -
        caught = 1;
475 +
        set caught = 1;
476 476
        return 1;
477 477
    };
478 478
    // Catch block should not have run.
479 479
    assert caught == 0;
480 480
    // Should have the success value.
484 484
485 485
/// Test call overflow detection by exhausting frames.
486 486
fn testCallOverflow(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
487 487
    let mut code: [Op; 4] = [Op::Halt; 4];
488 488
    // Infinite recursion: function calls itself.
489 -
    code[0] = Op::Call(0);
490 -
    code[1] = Op::Halt;
489 +
    set code[0] = Op::Call(0);
490 +
    set code[1] = Op::Halt;
491 491
492 492
    let mut caught: i32 = 0;
493 493
    try runProgram(&code[..], 2, stackBuf, localsBuf, framesBuf) catch e {
494 494
        if e == VmError::CallOverflow {
495 -
            caught = 1;
495 +
            set caught = 1;
496 496
        } else {
497 -
            caught = 2;
497 +
            set caught = 2;
498 498
        }
499 499
    };
500 500
    assert caught == 1;
501 501
    return 0;
502 502
}
503 503
504 504
/// Test that catch with no binding works (discard the error).
505 505
fn testCatchNoBinding(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 {
506 506
    let mut code: [Op; 4] = [Op::Halt; 4];
507 -
    code[0] = Op::Pop;  // underflow
508 -
    code[1] = Op::Halt;
507 +
    set code[0] = Op::Pop;  // underflow
508 +
    set code[1] = Op::Halt;
509 509
510 510
    // Catch without binding - just swallow the error.
511 511
    try runProgram(&code[..], 2, stackBuf, localsBuf, framesBuf) catch {};
512 512
    return 0;
513 513
}
test/tests/ptr.assign.rad +1 -1
1 1
//! returns: 42
2 2
@default fn main() -> i32 {
3 3
    let mut x: i32 = 1;
4 4
    let mut ptr: *mut i32 = &mut x;
5 5
6 -
    *ptr = 42;
6 +
    set *ptr = 42;
7 7
8 8
    return x;
9 9
}
test/tests/ptr.mutate.rad +3 -3
1 1
//! returns: 42
2 2
3 3
fn mutate1(ptr: *mut i32) {
4 -
    *ptr = 39;
4 +
    set *ptr = 39;
5 5
}
6 6
7 7
fn mutate2(ptr: *mut i32) {
8 -
    *ptr += 2;
9 -
    *ptr += 1;
8 +
    set *ptr += 2;
9 +
    set *ptr += 1;
10 10
}
11 11
12 12
@default fn main() -> i32 {
13 13
    let mut ptr: i32 = 0;
14 14
test/tests/ptr.opaque.rad +1 -1
37 37
fn testNullableOpaque() -> bool {
38 38
    let mut opt: ?*opaque = nil;
39 39
    if opt == nil {
40 40
        let x: u32 = 42;
41 41
        let ptr: *u8 = &x as *u8;
42 -
        opt = ptr;  // Automatic coercion in assignment.
42 +
        set opt = ptr;  // Automatic coercion in assignment.
43 43
44 44
        if let p = opt {
45 45
            return p as *u8 == ptr;
46 46
        }
47 47
    }
test/tests/ptr.subscript.assign.rad +1 -1
1 1
/// Writes to a slice element through subscript.
2 2
fn subscriptAssign(arr: *mut [i32], idx: u32, val: i32) {
3 -
    arr[idx] = val;
3 +
    set arr[idx] = val;
4 4
}
test/tests/record.array.elements.rad +7 -7
12 12
fn vectorSum(vec: Vector) -> i32 {
13 13
    let mut sum: i32 = 0;
14 14
    let mut i: u32 = 0;
15 15
16 16
    while (i < vec.data.len) {
17 -
        sum += vec.data[i];
18 -
        i += 1;
17 +
        set sum += vec.data[i];
18 +
        set i += 1;
19 19
    }
20 20
    return sum;
21 21
}
22 22
23 23
fn vectorScale(vec: Vector, scale: i32) -> Vector {
24 24
    let mut result: Vector = Vector { data: [0, 0, 0, 0] };
25 25
    let mut i: u32 = 0;
26 26
27 27
    while (i < vec.data.len) {
28 -
        result.data[i] = vec.data[i] * scale;
29 -
        i += 1;
28 +
        set result.data[i] = vec.data[i] * scale;
29 +
        set i += 1;
30 30
    }
31 31
    return result;
32 32
}
33 33
34 34
// Sum of the diagonal elements.
35 35
fn matrixTrace(mat: Matrix) -> i32 {
36 36
    let mut sum: i32 = 0;
37 37
    let mut i: u32 = 0;
38 38
39 39
    while (i < mat.rows.len) {
40 -
        sum += mat.rows[i].data[i];
41 -
        i += 1;
40 +
        set sum += mat.rows[i].data[i];
41 +
        set i += 1;
42 42
    }
43 43
    return sum;
44 44
}
45 45
46 46
@default fn main() -> i32 {
60 60
    // Sum of v2: 2 + 4 + 6 + 8 = 20.
61 61
    let mut sumV2: i32 = vectorSum(v2);
62 62
    // Trace of matrix: 10 + 15 + 20 = 45.
63 63
    let mut trace: i32 = matrixTrace(m1);
64 64
    // Modify element in the matrix.
65 -
    m1.rows[0].data[0] = m1.rows[0].data[0] - 5; // 10 - 5 = 5
65 +
    set m1.rows[0].data[0] = m1.rows[0].data[0] - 5; // 10 - 5 = 5
66 66
    // Calculate new trace: 5 + 15 + 20 = 40.
67 67
    let mut newTrace: i32 = matrixTrace(m1);
68 68
69 69
    // Return combined results: 10 + 20 + 45 + 40 = 115.
70 70
    return sumV1 + sumV2 + trace + newTrace;
test/tests/record.assign.blit.rad +1 -1
1 1
record Point { x: i32, y: i32 }
2 2
3 3
fn copy() {
4 4
    let p = Point { x: 1, y: 2 };
5 5
    let mut q = p;
6 -
    q = p;
6 +
    set q = p;
7 7
}
test/tests/record.copy.rad +16 -16
15 15
    return s;
16 16
}
17 17
18 18
fn func1(s: S) -> i32 {
19 19
    let mut m: S = s;
20 -
    m.x = 112;
21 -
    m.y = 582;
22 -
    m.z = 281;
20 +
    set m.x = 112;
21 +
    set m.y = 582;
22 +
    set m.z = 281;
23 23
24 24
    assert m.x == 112;
25 25
    assert m.y == 582;
26 26
    assert m.z == 281;
27 27
    return 0;
31 31
    let p: i32 = 0;
32 32
    let mut t: S = s;
33 33
    let q: i32 = 0;
34 34
    let mut u: S = s;
35 35
36 -
    t.x = 12;
37 -
    u.x = 13;
38 -
    t.y = 52;
39 -
    u.y = 54;
40 -
    t.z = 21;
41 -
    u.z = 25;
36 +
    set t.x = 12;
37 +
    set u.x = 13;
38 +
    set t.y = 52;
39 +
    set u.y = 54;
40 +
    set t.z = 21;
41 +
    set u.z = 25;
42 42
43 43
    assert t.x == 12;
44 44
    assert t.y == 52;
45 45
    assert t.z == 21;
46 46
    assert u.x == 13;
51 51
52 52
fn func3(s: S) -> i32 {
53 53
    let mut a: [S; 4] = [s; 4];
54 54
    let mut t: S = s;
55 55
56 -
    t.x = 12;
57 -
    t.y = 13;
58 -
    t.z = 52;
56 +
    set t.x = 12;
57 +
    set t.y = 13;
58 +
    set t.z = 52;
59 59
60 -
    a[1] = t;
61 -
    a[3] = a[1];
60 +
    set a[1] = t;
61 +
    set a[3] = a[1];
62 62
63 63
    assert a[0].x == 561;
64 64
    assert a[0].y == 938;
65 65
    assert a[0].z == 102;
66 66
    assert a[1].x == 12;
71 71
    return 0;
72 72
}
73 73
74 74
fn func4(s: S) -> i32 {
75 75
    let mut a: [S; 2] = undefined;
76 -
    a[0] = s;
76 +
    set a[0] = s;
77 77
78 78
    assert a[0].x == 561;
79 79
    assert a[0].y == 938;
80 80
    assert a[0].z == 102;
81 81
    return 0;
82 82
}
83 83
84 84
fn func5(s: S) -> i32 {
85 85
    let mut a: [S; 2] = undefined;
86 86
    let t: S = makeS(s.x, s.y, s.z);
87 -
    a[0] = t;
87 +
    set a[0] = t;
88 88
89 89
    assert a[0].x == 561;
90 90
    assert a[0].y == 938;
91 91
    assert a[0].z == 102;
92 92
    return 0;
test/tests/record.field.assign.rad +3 -3
3 3
record Vector { x: i32, y: i32 }
4 4
5 5
@default fn main() -> i32 {
6 6
    let mut v: Vector = Vector { x: 3, y: 2 };
7 7
8 -
    v.x = 40;
9 -
    v.y = 1;
10 -
    v.y *= 2;
8 +
    set v.x = 40;
9 +
    set v.y = 1;
10 +
    set v.y *= 2;
11 11
12 12
    return (v.x + v.y) - 42;
13 13
}
test/tests/record.nested.calls.2.rad +1 -1
16 16
17 17
@default fn main() -> i32 {
18 18
    let mut p: Point = Point { x: 3, y: 4 };
19 19
    let mut q: Point = Point { x: 5, y: 6 };
20 20
21 -
    p = add(
21 +
    set p = add(
22 22
        scale(p, 2), // (6, 8)
23 23
        scale(q, 2)  // (10, 12)
24 24
    ); // (16, 20)
25 25
26 26
    // p.x + p.y = 16 + 20 = 36
test/tests/record.ptr.mutate.rad +2 -2
4 4
    x: i32,
5 5
    y: i32,
6 6
}
7 7
8 8
fn mutate(p: *mut Point) {
9 -
    p.x = 4;
10 -
    p.y = 38;
9 +
    set p.x = 4;
10 +
    set p.y = 38;
11 11
}
12 12
13 13
@default fn main() -> i32 {
14 14
    let mut p: Point = Point { x: 0, y: 0 };
15 15
test/tests/record.unlabeled.deref.rad +1 -1
71 71
        return 9;
72 72
    }
73 73
74 74
    // Assignment through deref on mutable binding.
75 75
    let mut m: Wrap = Wrap(0);
76 -
    *m = 77;
76 +
    set *m = 77;
77 77
    if *m <> 77 {
78 78
        return 10;
79 79
    }
80 80
81 81
    return 0;
test/tests/ref.if.bug.rad +1 -1
3 3
//!
4 4
//! When `&mut var` appears in only one branch of an if/else, the merge
5 5
//! block's phi merges the original integer value with a stack pointer.
6 6
7 7
fn store(ptr: *mut u32, val: u32) {
8 -
    *ptr = val;
8 +
    set *ptr = val;
9 9
}
10 10
11 11
fn testIfBranch(cond: bool) -> u32 {
12 12
    let mut val: u32 = 42;
13 13
    if cond {
test/tests/ref.immut.loop.bug.rad +1 -1
13 13
fn testZeroIter(n: u32) -> u32 {
14 14
    let val: u32 = 42;
15 15
    let mut i: u32 = 0;
16 16
    while i < n {
17 17
        let _ = read(&val);
18 -
        i += 1;
18 +
        set i += 1;
19 19
    }
20 20
    return val;
21 21
}
22 22
23 23
@default fn main() -> i32 {
test/tests/ref.mut.ptr.rad +1 -1
1 1
//! returns: 84
2 2
//! Test mutable pointer references.
3 3
4 4
fn store(ptr: *mut i32) {
5 -
    *ptr = 42;
5 +
    set *ptr = 42;
6 6
}
7 7
8 8
@default fn main() -> i32 {
9 9
    let mut a: i32 = 0;
10 10
    let p: *mut i32 = &mut a;
test/tests/reserve.loop.rad +2 -2
4 4
@default fn main() -> i32 {
5 5
    let mut total: i32 = 0;
6 6
    let mut i: i32 = 0;
7 7
    while i < 10000 {
8 8
        let p: Pair = Pair { a: i, b: i + 1 };
9 -
        total += p.a + p.b;
10 -
        i += 1;
9 +
        set total += p.a + p.b;
10 +
        set i += 1;
11 11
    }
12 12
    // Expected: sum(i) + sum(i+1) for i=0..9999
13 13
    // = 2 * 9999*10000/2 + 10000 = 99990000 + 10000 = 100000000
14 14
    assert total == 100000000;
15 15
    return 0;
test/tests/result.void.success.rad +1 -1
27 27
        return (2) - 42;
28 28
    }
29 29
30 30
    // Try the error path too.
31 31
    try voidError() catch {
32 -
        guard = 99;
32 +
        set guard = 99;
33 33
    };
34 34
35 35
    if guard <> 99 {
36 36
        return (3) - 42;
37 37
    }
test/tests/slice.alloc.loop.rad +1 -1
13 13
fn initSlice(buf: *mut [u8], count: u32) -> i32 {
14 14
    let s = makeSlice(buf, count);
15 15
16 16
    // This loop pattern matches createBlock's vars initialization.
17 17
    for i in 0..s.len {
18 -
        s[i] = 0;
18 +
        set s[i] = 0;
19 19
    }
20 20
21 21
    return s.len as i32;
22 22
}
23 23
test/tests/slice.append.rad +5 -5
16 16
    let newOffset = aligned + size;
17 17
18 18
    assert newOffset <= arena.data.len as u32;
19 19
20 20
    let base: *mut u8 = &mut arena.data[aligned];
21 -
    arena.offset = newOffset;
21 +
    set arena.offset = newOffset;
22 22
23 23
    return base as *mut opaque;
24 24
}
25 25
26 26
/// Allocator record matching the compiler's expected layout.
119 119
    }
120 120
121 121
    // Sum all elements in nums.
122 122
    let mut sum: i32 = 0;
123 123
    for n in nums {
124 -
        sum += n;
124 +
        set sum += n;
125 125
    }
126 126
    if sum <> 150 {
127 127
        return 16;
128 128
    }
129 129
163 163
    // Test that .append() returns the slice, allowing rebinding.
164 164
    let ptr2 = arenaAlloc(&mut arena, @sizeOf(i32) * 2, @alignOf(i32));
165 165
    let mut vals = @sliceOf(ptr2 as *mut i32, 0, 2);
166 166
167 167
    // Append within capacity, rebind via return value.
168 -
    vals = vals.append(42, a);
168 +
    set vals = vals.append(42, a);
169 169
    assert vals.len == 1;
170 170
    assert vals[0] == 42;
171 171
172 -
    vals = vals.append(43, a);
172 +
    set vals = vals.append(43, a);
173 173
    assert vals.len == 2;
174 174
175 175
    // Append past capacity -- triggers growth and returns updated slice.
176 176
    let oldPtr = &vals[0] as *opaque;
177 -
    vals = vals.append(44, a);
177 +
    set vals = vals.append(44, a);
178 178
    assert vals.len == 3;
179 179
    assert vals.cap == 5;
180 180
181 181
    // After growth, the data pointer should have changed.
182 182
    let newPtr = &vals[0] as *opaque;
test/tests/slice.assign.mismatch.rad +1 -1
2 2
//! Test that slice copy with mismatched lengths traps.
3 3
4 4
@default fn main() -> i32 {
5 5
    let mut dst: [i32; 4] = [0, 0, 0, 0];
6 6
    let src: [i32; 2] = [1, 2];
7 -
    dst[..] = &src[..];
7 +
    set dst[..] = &src[..];
8 8
    return 0;
9 9
}
test/tests/slice.assign.rad +9 -9
1 1
//! returns: 0
2 2
3 3
@default fn main() -> i32 {
4 4
    // Fill entire array.
5 5
    let mut a: [i32; 4] = [1, 2, 3, 4];
6 -
    a[..] = 0;
6 +
    set a[..] = 0;
7 7
    assert a == [0, 0, 0, 0];
8 8
9 9
    // Fill sub-range of array.
10 10
    let mut b: [i32; 4] = [1, 2, 3, 4];
11 -
    b[1..3] = 99;
11 +
    set b[1..3] = 99;
12 12
    assert b == [1, 99, 99, 4];
13 13
14 14
    // Fill mutable slice.
15 15
    let mut c: [i32; 4] = [10, 20, 30, 40];
16 16
    let cs: *mut [i32] = &mut c[..];
17 -
    cs[..] = 7;
17 +
    set cs[..] = 7;
18 18
    assert c == [7, 7, 7, 7];
19 19
20 20
    // Fill sub-range of mutable slice.
21 21
    let mut d: [i32; 5] = [1, 2, 3, 4, 5];
22 22
    let ds: *mut [i32] = &mut d[..];
23 -
    ds[1..4] = 0;
23 +
    set ds[1..4] = 0;
24 24
    assert d == [1, 0, 0, 0, 5];
25 25
26 26
    // Copy slice into array.
27 27
    let mut e: [i32; 3] = [0, 0, 0];
28 28
    let src: [i32; 3] = [10, 20, 30];
29 -
    e[..] = &src[..];
29 +
    set e[..] = &src[..];
30 30
    assert e == [10, 20, 30];
31 31
32 32
    // Copy into sub-range.
33 33
    let mut f: [i32; 5] = [1, 2, 3, 4, 5];
34 34
    let src2: [i32; 2] = [88, 99];
35 -
    f[1..3] = &src2[..];
35 +
    set f[1..3] = &src2[..];
36 36
    assert f == [1, 88, 99, 4, 5];
37 37
38 38
    // Empty range is a no-op.
39 39
    let mut g: [i32; 3] = [1, 2, 3];
40 -
    g[1..1] = 99;
40 +
    set g[1..1] = 99;
41 41
    assert g == [1, 2, 3];
42 42
43 43
    // Copy between sub-ranges.
44 44
    let mut i: [i32; 10] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
45 45
    let s: *mut [i32] = &mut i[..];
46 -
    s[1..4] = &s[7..10];
46 +
    set s[1..4] = &s[7..10];
47 47
    assert i[1] == 80 and i[2] == 90 and i[3] == 100;
48 48
49 49
    // Fill u8 array.
50 50
    let mut h: [u8; 4] = [65, 66, 67, 68];
51 -
    h[..] = 0;
51 +
    set h[..] = 0;
52 52
    assert h == [0, 0, 0, 0];
53 53
54 54
    return 0;
55 55
}
test/tests/slice.mutable.rad +4 -4
1 1
// Test mutable slice operations
2 2
3 3
fn mutSliceStore(s: *mut [i32], idx: u32, val: i32) {
4 -
    s[idx] = val;
4 +
    set s[idx] = val;
5 5
}
6 6
7 7
fn mutSliceIncrement(s: *mut [i32], idx: u32) {
8 -
    s[idx] += 1;
8 +
    set s[idx] += 1;
9 9
}
10 10
11 11
fn mutSliceSwap(s: *mut [i32], i: u32, j: u32) {
12 12
    let tmp = s[i];
13 -
    s[i] = s[j];
14 -
    s[j] = tmp;
13 +
    set s[i] = s[j];
14 +
    set s[j] = tmp;
15 15
}
test/tests/spill.blockarg.clobber.rad +22 -22
39 39
}
40 40
41 41
fn prepareSchedule(s: *mut State, block: *[u32]) {
42 42
    let mut i: u32 = 0;
43 43
    while i < 16 {
44 -
        s.w[i] = block[i];
45 -
        i += 1;
44 +
        set s.w[i] = block[i];
45 +
        set i += 1;
46 46
    }
47 47
    while i < 64 {
48 -
        s.w[i] = ssig1(s.w[i - 2]) + s.w[i - 7] + ssig0(s.w[i - 15]) + s.w[i - 16];
49 -
        i += 1;
48 +
        set s.w[i] = ssig1(s.w[i - 2]) + s.w[i - 7] + ssig0(s.w[i - 15]) + s.w[i - 16];
49 +
        set i += 1;
50 50
    }
51 51
}
52 52
53 53
/// SHA-256 compression: 64 rounds with 8 rotating working variables.
54 54
/// Exercises heavy register pressure and spilled block-argument shuffles.
64 64
65 65
    let mut i: u32 = 0;
66 66
    while i < 64 {
67 67
        let t1 = hh + bsig1(e) + ch(e, f, g) + k[i] + s.w[i];
68 68
        let t2 = bsig0(a) + maj(a, b, c);
69 -
        hh = g;
70 -
        g = f;
71 -
        f = e;
72 -
        e = d + t1;
73 -
        d = c;
74 -
        c = b;
75 -
        b = a;
76 -
        a = t1 + t2;
77 -
        i += 1;
69 +
        set hh = g;
70 +
        set g = f;
71 +
        set f = e;
72 +
        set e = d + t1;
73 +
        set d = c;
74 +
        set c = b;
75 +
        set b = a;
76 +
        set a = t1 + t2;
77 +
        set i += 1;
78 78
    }
79 79
80 -
    s.h[0] += a;
81 -
    s.h[1] += b;
82 -
    s.h[2] += c;
83 -
    s.h[3] += d;
84 -
    s.h[4] += e;
85 -
    s.h[5] += f;
86 -
    s.h[6] += g;
87 -
    s.h[7] += hh;
80 +
    set s.h[0] += a;
81 +
    set s.h[1] += b;
82 +
    set s.h[2] += c;
83 +
    set s.h[3] += d;
84 +
    set s.h[4] += e;
85 +
    set s.h[5] += f;
86 +
    set s.h[6] += g;
87 +
    set s.h[7] += hh;
88 88
}
89 89
90 90
@default fn main() -> i32 {
91 91
    let k: [u32; 64] = [
92 92
        0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
113 113
        w: [0; 64]
114 114
    };
115 115
116 116
    // Padded empty-message block.
117 117
    let mut block: [u32; 16] = [0; 16];
118 -
    block[0] = 0x80000000;
118 +
    set block[0] = 0x80000000;
119 119
120 120
    prepareSchedule(&mut s, &block[..]);
121 121
    compress(&mut s, &k[..]);
122 122
123 123
    // SHA-256("") = e3b0c442 98fc1c14 ...
test/tests/spill.loop.rad +3 -3
34 34
fn computeRecordLayout(tags: *[u8]) -> Layout {
35 35
    let mut currentOffset: u32 = 0;
36 36
    let mut maxAlignment: u32 = 1;
37 37
    for i in 0..tags.len {
38 38
        let layout = getLayout(tags[i]);
39 -
        currentOffset = alignUp(currentOffset, layout.alignment);
40 -
        currentOffset += layout.size;
41 -
        maxAlignment = max(maxAlignment, layout.alignment);
39 +
        set currentOffset = alignUp(currentOffset, layout.alignment);
40 +
        set currentOffset += layout.size;
41 +
        set maxAlignment = max(maxAlignment, layout.alignment);
42 42
    }
43 43
    return Layout {
44 44
        size: alignUp(currentOffset, maxAlignment),
45 45
        alignment: maxAlignment,
46 46
    };
test/tests/static.array.mutate.rad +1 -1
2 2
//! Test mutating a static array.
3 3
4 4
static BUFFER: [i32; 3] = [1, 2, 3];
5 5
6 6
fn bump(slot: u32, amount: i32) -> i32 {
7 -
    BUFFER[slot] += amount;
7 +
    set BUFFER[slot] += amount;
8 8
    return BUFFER[0] + BUFFER[1] + BUFFER[2];
9 9
}
10 10
11 11
@default fn main() -> i32 {
12 12
    let a: i32 = bump(0, 4);
test/tests/static.assign.rad +1 -1
1 1
/// Test static variable assignment.
2 2
static COUNTER: i32 = 0;
3 3
4 4
fn increment() -> i32 {
5 -
    COUNTER += 1;
5 +
    set COUNTER += 1;
6 6
    return COUNTER;
7 7
}
test/tests/static.basic.rad +5 -5
3 3
static GLOBAL: i32 = 0;
4 4
5 5
fn updateCounter(i: i32) -> i32 {
6 6
    static counter: i32 = 0;
7 7
8 -
    counter += i;
9 -
    GLOBAL += i * 10;
8 +
    set counter += i;
9 +
    set GLOBAL += i * 10;
10 10
11 11
    return counter;
12 12
}
13 13
14 14
@default fn main() -> i32 {
15 15
    let mut n: i32 = 0;
16 16
17 -
    n = updateCounter(1);
18 -
    n = updateCounter(2);
19 -
    n = updateCounter(3);
17 +
    set n = updateCounter(1);
18 +
    set n = updateCounter(2);
19 +
    set n = updateCounter(3);
20 20
21 21
    return n + GLOBAL;
22 22
}
test/tests/static.local.decl.rad +1 -1
1 1
/// Test lowering of function-local static and constant declarations.
2 2
fn localStaticAndConst() -> i32 {
3 3
    static LOCAL: i32 = 7;
4 4
    constant ADD: i32 = 5;
5 5
6 -
    LOCAL += ADD;
6 +
    set LOCAL += ADD;
7 7
    return LOCAL;
8 8
}
test/tests/static.record.array.rad +2 -2
10 10
    values: [5, 1, 9, 2],
11 11
    bias: 4,
12 12
};
13 13
14 14
fn rebalance() -> i32 {
15 -
    TABLE.values[0] += TABLE.bias;
16 -
    TABLE.values[3] += 1;
15 +
    set TABLE.values[0] += TABLE.bias;
16 +
    set TABLE.values[3] += 1;
17 17
    return TABLE.values[0] + TABLE.values[3] + TABLE.bias;
18 18
}
19 19
20 20
@default fn main() -> i32 {
21 21
    let first: i32 = rebalance();
test/tests/static.slice.index.assign.rad +4 -4
10 10
}
11 11
12 12
static container: Container = undefined;
13 13
14 14
@default fn main() -> i32 {
15 -
    container.items[0].value = 10;
16 -
    container.items[1].value = 20;
17 -
    container.items[2].value = 30;
15 +
    set container.items[0].value = 10;
16 +
    set container.items[1].value = 20;
17 +
    set container.items[2].value = 30;
18 18
19 19
    let slice: *mut [Inner] = &mut container.items[..];
20 20
21 -
    slice[1].value = 42;
21 +
    set slice[1].value = 42;
22 22
23 23
    return container.items[1].value;
24 24
}
test/tests/static.slice.offset.rad +5 -5
18 18
    Entry { a: 0, b: 0 },
19 19
];
20 20
static TBL: Table = undefined;
21 21
22 22
@default fn main() -> i32 {
23 -
    TBL.scratch = &mut SCRATCH[..];
24 -
    TBL.entries = &mut STORAGE[..];
25 -
    TBL.len     = 0;
23 +
    set TBL.scratch = &mut SCRATCH[..];
24 +
    set TBL.entries = &mut STORAGE[..];
25 +
    set TBL.len     = 0;
26 26
27 -
    TBL.entries[TBL.len] = Entry { a: 7, b: 9 };
28 -
    TBL.len += 1;
27 +
    set TBL.entries[TBL.len] = Entry { a: 7, b: 9 };
28 +
    set TBL.len += 1;
29 29
30 30
    assert STORAGE[0].a == 7 and STORAGE[0].b == 9;
31 31
    assert SCRATCH[0].a == 0 and SCRATCH[0].b == 0;
32 32
    return 0;
33 33
}
test/tests/trait.array.optional.rad +1 -1
30 30
31 31
/// Apply a chain of transforms to a value.
32 32
fn applyAll(transforms: *[*opaque Transform], value: i32) -> i32 {
33 33
    let mut result = value;
34 34
    for i in 0..transforms.len {
35 -
        result = transforms[i].apply(result);
35 +
        set result = transforms[i].apply(result);
36 36
    }
37 37
    return result;
38 38
}
39 39
40 40
/// Apply an optional transform, returning the original value if nil.
test/tests/trait.basic.rad +1 -1
8 8
    fn (*mut Adder) add(n: i32) -> i32;
9 9
}
10 10
11 11
instance Adder for Counter {
12 12
    fn (c: *mut Counter) add(n: i32) -> i32 {
13 -
        c.value = c.value + n;
13 +
        set c.value = c.value + n;
14 14
        return c.value;
15 15
    }
16 16
}
17 17
18 18
@default fn main() -> i32 {
test/tests/trait.control.flow.rad +2 -2
14 14
    fn (*Stepper) current() -> i32;
15 15
}
16 16
17 17
instance Stepper for Counter {
18 18
    fn (c: *mut Counter) step() -> i32 {
19 -
        c.value = c.value + 1;
19 +
        set c.value = c.value + 1;
20 20
        return c.value;
21 21
    }
22 22
23 23
    fn (c: *Counter) current() -> i32 {
24 24
        return c.value;
31 31
32 32
    // Dispatch in a while loop.
33 33
    let mut i: i32 = 0;
34 34
    while i < 5 {
35 35
        s.step();
36 -
        i = i + 1;
36 +
        set i = i + 1;
37 37
    }
38 38
    assert s.current() == 5;
39 39
40 40
    // Dispatch in a conditional.
41 41
    if s.current() > 3 {
test/tests/trait.dispatch.rad +1 -1
11 11
    fn (a: *Acc) get() -> i32 {
12 12
        return a.n;
13 13
    }
14 14
15 15
    fn (a: *mut Acc) put(n: i32) {
16 -
        a.n = n;
16 +
        set a.n = n;
17 17
    }
18 18
}
19 19
20 20
fn dispatch(o: *mut opaque Ops) -> i32 {
21 21
    o.put(42);
test/tests/trait.fn.param.rad +1 -1
32 32
    }
33 33
}
34 34
35 35
instance Scalable for Circle {
36 36
    fn (c: *mut Circle) scale(factor: i32) {
37 -
        c.radius = c.radius * factor;
37 +
        set c.radius = c.radius * factor;
38 38
    }
39 39
}
40 40
41 41
/// Accept an immutable trait object parameter.
42 42
fn getArea(s: *opaque Shape) -> i32 {
test/tests/trait.multiple.methods.rad +2 -2
15 15
    fn (*mut Collector) isEmpty() -> bool;
16 16
}
17 17
18 18
instance Collector for Accumulator {
19 19
    fn (a: *mut Accumulator) add(n: i32) -> i32 {
20 -
        a.total = a.total + n;
20 +
        set a.total = a.total + n;
21 21
        return a.total;
22 22
    }
23 23
24 24
    fn (a: *mut Accumulator) clear() {
25 -
        a.total = 0;
25 +
        set a.total = 0;
26 26
    }
27 27
28 28
    fn (a: *mut Accumulator) isEmpty() -> bool {
29 29
        return a.total == 0;
30 30
    }
test/tests/trait.multiple.traits.rad +2 -2
18 18
    fn (*mut Resettable) isZero() -> bool;
19 19
}
20 20
21 21
instance Incrementable for Counter {
22 22
    fn (c: *mut Counter) inc() -> i32 {
23 -
        c.value = c.value + 1;
23 +
        set c.value = c.value + 1;
24 24
        return c.value;
25 25
    }
26 26
}
27 27
28 28
instance Resettable for Counter {
29 29
    fn (c: *mut Counter) reset() {
30 -
        c.value = 0;
30 +
        set c.value = 0;
31 31
    }
32 32
33 33
    fn (c: *mut Counter) isZero() -> bool {
34 34
        return c.value == 0;
35 35
    }
test/tests/trait.object.rad +1 -1
6 6
    fn (*mut Adder) add(n: i32) -> i32;
7 7
}
8 8
9 9
instance Adder for Counter {
10 10
    fn (c: *mut Counter) add(n: i32) -> i32 {
11 -
        c.value = c.value + n;
11 +
        set c.value = c.value + n;
12 12
        return c.value;
13 13
    }
14 14
}
15 15
16 16
fn use_adder() -> i32 {
test/tests/trait.supertrait.rad +12 -12
30 30
31 31
instance Reader for Socket {
32 32
    fn (s: *mut Socket) read(buf: *mut [u8]) -> i32 {
33 33
        let mut i: u32 = 0;
34 34
        while i < buf.len and s.rpos < s.rlen {
35 -
            buf[i] = s.rbuf[s.rpos as u32];
36 -
            s.rpos = s.rpos + 1;
37 -
            i = i + 1;
35 +
            set buf[i] = s.rbuf[s.rpos as u32];
36 +
            set s.rpos = s.rpos + 1;
37 +
            set i = i + 1;
38 38
        }
39 39
        return i as i32;
40 40
    }
41 41
}
42 42
45 45
        let mut i: u32 = 0;
46 46
        while i < data.len {
47 47
            if s.wpos >= 32 {
48 48
                return s.wpos;
49 49
            }
50 -
            s.wbuf[s.wpos as u32] = data[i];
51 -
            s.wpos = s.wpos + 1;
52 -
            i = i + 1;
50 +
            set s.wbuf[s.wpos as u32] = data[i];
51 +
            set s.wpos = s.wpos + 1;
52 +
            set i = i + 1;
53 53
        }
54 54
        return s.wpos;
55 55
    }
56 56
}
57 57
58 58
instance ReadWriter for Socket {
59 59
    fn (s: *mut Socket) flush() -> i32 {
60 60
        let pos = s.wpos;
61 -
        s.wpos = 0;
61 +
        set s.wpos = 0;
62 62
        return pos;
63 63
    }
64 64
}
65 65
66 66
@default fn main() -> i32 {
70 70
        rlen: 5,
71 71
        wbuf: undefined,
72 72
        wpos: 0,
73 73
    };
74 74
    // Pre-fill the read buffer with "hello".
75 -
    sock.rbuf[0] = 'h' as u8;
76 -
    sock.rbuf[1] = 'e' as u8;
77 -
    sock.rbuf[2] = 'l' as u8;
78 -
    sock.rbuf[3] = 'l' as u8;
79 -
    sock.rbuf[4] = 'o' as u8;
75 +
    set sock.rbuf[0] = 'h' as u8;
76 +
    set sock.rbuf[1] = 'e' as u8;
77 +
    set sock.rbuf[2] = 'l' as u8;
78 +
    set sock.rbuf[3] = 'l' as u8;
79 +
    set sock.rbuf[4] = 'o' as u8;
80 80
81 81
    // Test 1: Use as ReadWriter trait object.
82 82
    let rw: *mut opaque ReadWriter = &mut sock;
83 83
84 84
    // Test 2: Write through the ReadWriter (dispatches via Writer supertrait).
test/tests/trait.throws.rad +3 -3
37 37
    assert r1 == 10;
38 38
39 39
    // Error path: negative input.
40 40
    let mut caught = false;
41 41
    let r2 = try p.parse(-1) catch {
42 -
        caught = true;
42 +
        set caught = true;
43 43
        0
44 44
    };
45 45
    assert caught;
46 46
47 47
    // Error path: overflow.
48 -
    caught = false;
48 +
    set caught = false;
49 49
    let r3 = try p.parse(200) catch {
50 -
        caught = true;
50 +
        set caught = true;
51 51
        0
52 52
    };
53 53
    assert caught;
54 54
55 55
    return 0;
test/tests/trait.writer.rad +4 -4
22 22
        let mut i: u32 = 0;
23 23
        while i < data.len {
24 24
            if w.pos >= 64 {
25 25
                return w.pos;
26 26
            }
27 -
            w.buf[w.pos as u32] = data[i];
28 -
            w.pos = w.pos + 1;
29 -
            i = i + 1;
27 +
            set w.buf[w.pos as u32] = data[i];
28 +
            set w.pos = w.pos + 1;
29 +
            set i = i + 1;
30 30
        }
31 31
        return w.pos;
32 32
    }
33 33
34 34
    fn (w: *BufferWriter) total() -> i32 {
42 42
    count: i32,
43 43
}
44 44
45 45
instance Writer for CountingWriter {
46 46
    fn (w: *mut CountingWriter) write(data: *[u8]) -> i32 {
47 -
        w.count = w.count + data.len as i32;
47 +
        set w.count = w.count + data.len as i32;
48 48
        return w.inner.write(data);
49 49
    }
50 50
51 51
    fn (w: *CountingWriter) total() -> i32 {
52 52
        return w.count;
test/tests/trivial.phi.rad +2 -2
33 33
/// If-else with assignments that both assign the same param value.
34 34
/// The merge uses %1 (val param) directly - no block param.
35 35
fn condSameParam(cond: bool, val: i32) -> i32 {
36 36
    let mut result: i32 = 0;
37 37
    if cond {
38 -
        result = val;
38 +
        set result = val;
39 39
    } else {
40 -
        result = val;
40 +
        set result = val;
41 41
    }
42 42
    return result;
43 43
}
test/tests/type.unify.rad +9 -9
24 24
    let optComplex: ?i32 = (10 * 2) - 5;
25 25
26 26
    let opt1: ?i32 = 10;
27 27
    let opt2: ?i32 = 20;
28 28
    let mut optResult: ?i32 = opt1;
29 -
    optResult = opt2;
29 +
    set optResult = opt2;
30 30
31 31
    if let a = optExpr {
32 32
        if let b = optComplex {
33 33
            return a + b == 20;
34 34
        }
39 39
/// Verifies assignment compatibility for arrays with identical element types and lengths.
40 40
fn testArrayUnification() -> bool {
41 41
    let arr1: [i32; 3] = [1, 2, 3];
42 42
    let arr2: [i32; 3] = [4, 5, 6];
43 43
    let mut arrResult: [i32; 3] = arr1;
44 -
    arrResult = arr2;
44 +
    set arrResult = arr2;
45 45
46 46
    return true;
47 47
}
48 48
49 49
/// Verifies assignment compatibility for pointers with identical target types.
51 51
    let x: i32 = 42;
52 52
    let y: i32 = 24;
53 53
    let ptr1: *i32 = &x;
54 54
    let ptr2: *i32 = &y;
55 55
    let mut ptrResult: *i32 = ptr1;
56 -
    ptrResult = ptr2;
56 +
    set ptrResult = ptr2;
57 57
58 58
    return true;
59 59
}
60 60
61 61
/// Verifies conversion from array references to slices.
91 91
/// Verifies basic optional assignments between values of the same optional type.
92 92
fn testSimpleOptionalValues() -> bool {
93 93
    let opt1: ?i32 = 10;
94 94
    let opt2: ?i32 = 20;
95 95
    let mut result: ?i32 = opt1;
96 -
    result = opt2;
96 +
    set result = opt2;
97 97
98 98
    return true;
99 99
}
100 100
101 101
/// Verifies coercion from pointer values to optional pointer values.
121 121
/// Verifies optional assignments involving `nil` and concrete values.
122 122
fn testNilUnification() -> bool {
123 123
    let opt1: ?i32 = nil;
124 124
    let opt2: ?i32 = 42;
125 125
    let mut result: ?i32 = opt1;
126 -
    result = opt2;
127 -
    result = nil;
126 +
    set result = opt2;
127 +
    set result = nil;
128 128
129 129
    return true;
130 130
}
131 131
132 132
/// Verifies that arrays of different lengths remain distinct types.
146 146
    let ptr1: *i32 = &value1;
147 147
    let ptr2: *i32 = &value2;
148 148
    let ptr3: *i32 = &value3;
149 149
150 150
    let mut result: *i32 = ptr1;
151 -
    result = ptr2;
152 -
    result = ptr3;
151 +
    set result = ptr2;
152 +
    set result = ptr3;
153 153
154 154
    return true;
155 155
}
156 156
157 157
/// Verifies assignment compatibility for boolean values.
158 158
fn testBoolUnification() -> bool {
159 159
    let b1: bool = true;
160 160
    let b2: bool = false;
161 161
    let mut result: bool = b1;
162 -
    result = b2;
162 +
    set result = b2;
163 163
164 164
    return true;
165 165
}
166 166
167 167
@default fn main() -> i32 {
test/tests/undefined.rad +5 -5
3 3
@default fn main() -> i32 {
4 4
    let mut ary: [u16; 32] = undefined;
5 5
    let x: u32 = 8;
6 6
    let y: u32 = 9;
7 7
8 -
    ary[0] = 1;
9 -
    ary[1] = 2;
10 -
    ary[2] = 3;
11 -
    ary[3] = 4;
12 -
    ary[4] = 5;
8 +
    set ary[0] = 1;
9 +
    set ary[1] = 2;
10 +
    set ary[2] = 3;
11 +
    set ary[3] = 4;
12 +
    set ary[4] = 5;
13 13
14 14
    assert x == 8;
15 15
    assert y == 9;
16 16
    assert ary[0] == 1;
17 17
    assert ary[1] == 2;
test/tests/union.edge.case.3.rad +1 -1
10 10
record Parser {
11 11
    root: Node,
12 12
}
13 13
14 14
fn node(p: *mut Parser, value: Node) -> *Node {
15 -
    p.root = value;
15 +
    set p.root = value;
16 16
    return &p.root;
17 17
}
18 18
19 19
fn nodeBool(p: *mut Parser, value: bool) -> *Node {
20 20
    return node(p, Node::Bool(value));
test/tests/union.match.ref.rad +2 -2
31 31
32 32
/// While-let on a mutable union reference.
33 33
fn whileLetRef(ptr: *mut Option) -> u32 {
34 34
    let mut sum: u32 = 0;
35 35
    while let case Option::Some(val) = ptr {
36 -
        sum += *val;
37 -
        *ptr = Option::None;
36 +
        set sum += *val;
37 +
        set *ptr = Option::None;
38 38
    }
39 39
    return sum;
40 40
}
41 41
42 42
/// Match on an optional reference with binding pattern.
test/tests/union.mixed.assign.rad +2 -2
11 11
record Holder {
12 12
    value: Mixed,
13 13
}
14 14
15 15
fn storePayload(holder: *mut Holder, value: i32) {
16 -
    holder.value = Mixed::Payload(value);
16 +
    set holder.value = Mixed::Payload(value);
17 17
}
18 18
19 19
fn storeFinal(holder: *mut Holder) {
20 -
    holder.value = Mixed::Final;
20 +
    set holder.value = Mixed::Final;
21 21
}
22 22
23 23
fn checkIfLet(value: Mixed) -> i32 {
24 24
    if let case Mixed::Payload(v) = value {
25 25
        return v;
test/tests/union.payload.mutref.rad +2 -2
20 20
}
21 21
22 22
fn addItemViaMatchRef(blk: *mut Block, val: u32) -> bool {
23 23
    match &mut blk.state {
24 24
        case Sealed::No { items } => {
25 -
            items.data[items.len] = val;
26 -
            items.len += 1;
25 +
            set items.data[items.len] = val;
26 +
            set items.len += 1;
27 27
            return true;
28 28
        },
29 29
        case Sealed::Yes => {
30 30
            return false;
31 31
        },
test/tests/union.record.forward.rad +1 -1
60 60
    ];
61 61
62 62
    let mut result: u32 = 0;
63 63
    match wrappers[7] {
64 64
        case Wrapper::Data(payload) => {
65 -
            result = payload.f0 + payload.f15;
65 +
            set result = payload.f0 + payload.f15;
66 66
        }
67 67
    }
68 68
    return result;
69 69
}
70 70
test/tests/var.infer.rad +1 -1
20 20
@default fn main() -> i32 {
21 21
    let inferredFlag = alwaysTrue();
22 22
    assert inferredFlag;
23 23
24 24
    let mut counter = returnsCount();
25 -
    counter += 1;
25 +
    set counter += 1;
26 26
    assert counter == 6;
27 27
28 28
    let pair = loadPair();
29 29
    let left = pair.left;
30 30
test/tests/var.shadow.rad +2 -2
1 1
// Test variable reuse (not true shadowing)
2 2
3 3
fn reuseVar() -> i32 {
4 4
    let mut x: i32 = 1;
5 -
    x = 2;
5 +
    set x = 2;
6 6
    return x;
7 7
}
8 8
9 9
fn reuseWithComputation() -> i32 {
10 10
    let mut x: i32 = 10;
11 11
    let y: i32 = x + 5;
12 -
    x = 20;
12 +
    set x = 20;
13 13
    return x + y;
14 14
}