Use `assert` instead of `panic`
3df5cf97acb5200ec1fb8c76bcc47d98c125e461c2b401369bd6ca0ef0ce7cdc
1 parent
4579515f
lib/std/arch/rv64/emit.rad
+7 -21
| 208 | 208 | // Emission Helpers // |
|
| 209 | 209 | /////////////////////// |
|
| 210 | 210 | ||
| 211 | 211 | /// Emit a single instruction. |
|
| 212 | 212 | pub fn emit(e: *mut Emitter, instr: u32) { |
|
| 213 | - | if e.codeLen >= e.code.len { |
|
| 214 | - | panic "emit: code buffer full"; |
|
| 215 | - | } |
|
| 213 | + | assert e.codeLen < e.code.len, "emit: code buffer full"; |
|
| 216 | 214 | e.code[e.codeLen] = instr; |
|
| 217 | 215 | e.codeLen += 1; |
|
| 218 | 216 | } |
|
| 219 | 217 | ||
| 220 | 218 | /// Compute branch offset to a function by name. |
| 239 | 237 | dict::insert(&mut e.labels.funcs, name, e.codeLen as i32 * super::INSTR_SIZE); |
|
| 240 | 238 | } |
|
| 241 | 239 | ||
| 242 | 240 | /// Record a function's start position for printing. |
|
| 243 | 241 | pub fn recordFunc(e: *mut Emitter, name: *[u8]) { |
|
| 244 | - | if e.funcsLen >= e.funcs.len { |
|
| 245 | - | panic "recordFunc: funcs buffer full"; |
|
| 246 | - | } |
|
| 242 | + | assert e.funcsLen < e.funcs.len, "recordFunc: funcs buffer full"; |
|
| 247 | 243 | e.funcs[e.funcsLen] = types::FuncAddr { name, index: e.codeLen }; |
|
| 248 | 244 | e.funcsLen += 1; |
|
| 249 | 245 | } |
|
| 250 | 246 | ||
| 251 | 247 | /// Record a local branch needing later patching. |
|
| 252 | 248 | /// Unconditional jumps use a single slot (J-type, +-1MB range). |
|
| 253 | 249 | /// Conditional branches use two slots (B-type has only +-4KB range, |
|
| 254 | 250 | /// so large functions may need the inverted-branch + JAL fallback). |
|
| 255 | 251 | pub fn recordBranch(e: *mut Emitter, targetBlock: u32, kind: BranchKind) { |
|
| 256 | - | if e.pendingBranchesLen >= e.pendingBranches.len { |
|
| 257 | - | panic "recordBranch: buffer full"; |
|
| 258 | - | } |
|
| 252 | + | assert e.pendingBranchesLen < e.pendingBranches.len, "recordBranch: buffer full"; |
|
| 259 | 253 | e.pendingBranches[e.pendingBranchesLen] = PendingBranch { |
|
| 260 | 254 | index: e.codeLen, |
|
| 261 | 255 | target: targetBlock, |
|
| 262 | 256 | kind: kind, |
|
| 263 | 257 | }; |
| 273 | 267 | ||
| 274 | 268 | /// Record a function call needing later patching. |
|
| 275 | 269 | /// Emits placeholder instructions that will be patched later. |
|
| 276 | 270 | /// Uses two slots to support long-distance calls. |
|
| 277 | 271 | pub fn recordCall(e: *mut Emitter, target: *[u8]) { |
|
| 278 | - | if e.pendingCallsLen >= e.pendingCalls.len { |
|
| 279 | - | panic "recordCall: buffer full"; |
|
| 280 | - | } |
|
| 272 | + | assert e.pendingCallsLen < e.pendingCalls.len, "recordCall: buffer full"; |
|
| 281 | 273 | e.pendingCalls[e.pendingCallsLen] = PendingCall { |
|
| 282 | 274 | index: e.codeLen, |
|
| 283 | 275 | target, |
|
| 284 | 276 | }; |
|
| 285 | 277 | e.pendingCallsLen += 1; |
| 290 | 282 | ||
| 291 | 283 | /// Record a function address load needing later patching. |
|
| 292 | 284 | /// Emits placeholder instructions that will be patched to load the function's address. |
|
| 293 | 285 | /// Uses two slots to compute long-distance addresses. |
|
| 294 | 286 | pub fn recordAddrLoad(e: *mut Emitter, target: *[u8], rd: super::Reg) { |
|
| 295 | - | if e.pendingAddrLoadsLen >= e.pendingAddrLoads.len { |
|
| 296 | - | panic "recordAddrLoad: buffer full"; |
|
| 297 | - | } |
|
| 287 | + | assert e.pendingAddrLoadsLen < e.pendingAddrLoads.len, "recordAddrLoad: buffer full"; |
|
| 298 | 288 | e.pendingAddrLoads[e.pendingAddrLoadsLen] = PendingAddrLoad { |
|
| 299 | 289 | index: e.codeLen, |
|
| 300 | 290 | target, |
|
| 301 | 291 | rd: rd, |
|
| 302 | 292 | }; |
| 337 | 327 | patch(e, p.index + 1, encode::jal(super::ZERO, adj)); |
|
| 338 | 328 | } |
|
| 339 | 329 | }, |
|
| 340 | 330 | case BranchKind::Jump => { |
|
| 341 | 331 | // Single-slot jump (J-type, +-1MB range). |
|
| 342 | - | if not encode::isJumpImm(offset) { |
|
| 343 | - | panic "patchLocalBranches: jump offset too large"; |
|
| 344 | - | } |
|
| 332 | + | assert encode::isJumpImm(offset), "patchLocalBranches: jump offset too large"; |
|
| 345 | 333 | patch(e, p.index, encode::jal(super::ZERO, offset)); |
|
| 346 | 334 | }, |
|
| 347 | 335 | } |
|
| 348 | 336 | } |
|
| 349 | 337 | e.pendingBranchesLen = 0; |
| 675 | 663 | let prev = &e.debugEntries[e.debugEntriesLen - 1]; |
|
| 676 | 664 | if prev.offset == loc.offset and prev.moduleId == loc.moduleId { |
|
| 677 | 665 | return; |
|
| 678 | 666 | } |
|
| 679 | 667 | } |
|
| 680 | - | if e.debugEntriesLen >= e.debugEntries.len { |
|
| 681 | - | panic "recordSrcLoc: debug entry buffer full"; |
|
| 682 | - | } |
|
| 668 | + | assert e.debugEntriesLen < e.debugEntries.len, "recordSrcLoc: debug entry buffer full"; |
|
| 683 | 669 | e.debugEntries[e.debugEntriesLen] = types::DebugEntry { |
|
| 684 | 670 | pc, |
|
| 685 | 671 | moduleId: loc.moduleId, |
|
| 686 | 672 | offset: loc.offset, |
|
| 687 | 673 | }; |
lib/std/arch/rv64/isel.rad
+5 -15
| 439 | 439 | and regalloc::spill::isSpilled(&s.ralloc.spill, src); |
|
| 440 | 440 | ||
| 441 | 441 | // When both are spilled, offsets must fit 12-bit immediates |
|
| 442 | 442 | // since we can't advance base registers (they live in spill |
|
| 443 | 443 | // slots, not real registers we can mutate). |
|
| 444 | - | if bothSpilled and staticSize as i32 > super::MAX_IMM { |
|
| 445 | - | panic "selectInstr: blit both-spilled with large size"; |
|
| 446 | - | } |
|
| 444 | + | assert not (bothSpilled and staticSize as i32 > super::MAX_IMM), "selectInstr: blit both-spilled with large size"; |
|
| 447 | 445 | ||
| 448 | 446 | // Resolve dst/src base registers. |
|
| 449 | 447 | let mut rdst = super::SCRATCH2; |
|
| 450 | 448 | let mut rsrc = super::SCRATCH1; |
|
| 451 | 449 | let mut srcReload: ?i32 = nil; |
| 662 | 660 | if let case il::Val::Reg(r) = func { |
|
| 663 | 661 | let target = getSrcReg(s, r, super::SCRATCH2); |
|
| 664 | 662 | emitMv(s, super::SCRATCH2, target); |
|
| 665 | 663 | } |
|
| 666 | 664 | // Move arguments to A0-A7 using parallel move resolution. |
|
| 667 | - | if args.len > super::ARG_REGS.len { |
|
| 668 | - | panic "selectInstr: too many call arguments"; |
|
| 669 | - | } |
|
| 665 | + | assert args.len <= super::ARG_REGS.len, "selectInstr: too many call arguments"; |
|
| 670 | 666 | emitParallelMoves(s, &super::ARG_REGS[..], args); |
|
| 671 | 667 | ||
| 672 | 668 | // Emit call. |
|
| 673 | 669 | match func { |
|
| 674 | 670 | case il::Val::FnAddr(name) => { |
| 995 | 991 | fn emitParallelMoves(s: *mut Selector, dsts: *[super::Reg], args: *[il::Val]) { |
|
| 996 | 992 | let n: u32 = args.len; |
|
| 997 | 993 | if n == 0 { |
|
| 998 | 994 | return; |
|
| 999 | 995 | } |
|
| 1000 | - | if n > MAX_BLOCK_ARGS { |
|
| 1001 | - | panic "emitParallelMoves: too many arguments"; |
|
| 1002 | - | } |
|
| 996 | + | assert n <= MAX_BLOCK_ARGS, "emitParallelMoves: too many arguments"; |
|
| 1003 | 997 | // Source registers for each arg. |
|
| 1004 | 998 | let mut srcRegs: [super::Reg; MAX_BLOCK_ARGS] = [super::ZERO; MAX_BLOCK_ARGS]; |
|
| 1005 | 999 | // If this is a register-to-register move. |
|
| 1006 | 1000 | let mut isRegMove: [bool; MAX_BLOCK_ARGS] = [false; MAX_BLOCK_ARGS]; |
|
| 1007 | 1001 | // If this move still needs to be executed. |
| 1107 | 1101 | fn emitBlockArgs(s: *mut Selector, func: *il::Fn, target: u32, args: *mut [il::Val]) { |
|
| 1108 | 1102 | if args.len == 0 { |
|
| 1109 | 1103 | return; |
|
| 1110 | 1104 | } |
|
| 1111 | 1105 | let block = &func.blocks[target]; |
|
| 1112 | - | if args.len != block.params.len { |
|
| 1113 | - | panic "emitBlockArgs: argument/parameter count mismatch"; |
|
| 1114 | - | } |
|
| 1115 | - | if args.len > MAX_BLOCK_ARGS { |
|
| 1116 | - | panic "emitBlockArgs: too many block arguments"; |
|
| 1117 | - | } |
|
| 1106 | + | assert args.len == block.params.len, "emitBlockArgs: argument/parameter count mismatch"; |
|
| 1107 | + | assert args.len <= MAX_BLOCK_ARGS, "emitBlockArgs: too many block arguments"; |
|
| 1118 | 1108 | ||
| 1119 | 1109 | // Destination registers for each arg. |
|
| 1120 | 1110 | // Zero means the destination is spilled or skipped. |
|
| 1121 | 1111 | let mut dsts: [super::Reg; MAX_BLOCK_ARGS] = [super::ZERO; MAX_BLOCK_ARGS]; |
|
| 1122 | 1112 |
lib/std/collections/dict.rad
+1 -3
| 36 | 36 | let mut idx = hash(key) & mask; |
|
| 37 | 37 | ||
| 38 | 38 | loop { |
|
| 39 | 39 | let entry = m.entries[idx]; |
|
| 40 | 40 | if entry.key.len == 0 { |
|
| 41 | - | if m.count >= m.entries.len / 2 { |
|
| 42 | - | panic "dict::insert: table full"; |
|
| 43 | - | } |
|
| 41 | + | assert m.count < m.entries.len / 2, "dict::insert: table full"; |
|
| 44 | 42 | m.entries[idx] = Entry { key, value }; |
|
| 45 | 43 | m.count += 1; |
|
| 46 | 44 | return; |
|
| 47 | 45 | } |
|
| 48 | 46 | if mem::eq(entry.key, key) { |
lib/std/lang/gen/data.rad
+1 -3
| 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 | 86 | offset = mem::alignUp(offset, data.alignment); |
|
| 87 | - | if offset + data.size > buf.len { |
|
| 88 | - | panic "emitSection: buffer overflow"; |
|
| 89 | - | } |
|
| 87 | + | assert offset + data.size <= buf.len, "emitSection: buffer overflow"; |
|
| 90 | 88 | for j in 0..data.values.len { |
|
| 91 | 89 | let v = &data.values[j]; |
|
| 92 | 90 | for _ in 0..v.count { |
|
| 93 | 91 | match v.item { |
|
| 94 | 92 | case il::DataItem::Val { typ, val } => { |
lib/std/lang/gen/labels.rad
+2 -6
| 36 | 36 | l.blockCount = 0; |
|
| 37 | 37 | } |
|
| 38 | 38 | ||
| 39 | 39 | /// Record a block's code offset by its index. O(1). |
|
| 40 | 40 | pub fn recordBlock(l: *mut Labels, blockIdx: u32, offset: i32) { |
|
| 41 | - | if blockIdx >= l.blockOffsets.len { |
|
| 42 | - | panic "recordBlock: block index out of range"; |
|
| 43 | - | } |
|
| 41 | + | assert blockIdx < l.blockOffsets.len, "recordBlock: block index out of range"; |
|
| 44 | 42 | l.blockOffsets[blockIdx] = offset; |
|
| 45 | 43 | l.blockCount += 1; |
|
| 46 | 44 | } |
|
| 47 | 45 | ||
| 48 | 46 | /// Look up a block's byte offset by index. O(1). |
|
| 49 | 47 | pub fn blockOffset(l: *Labels, blockIdx: u32) -> i32 { |
|
| 50 | - | if blockIdx >= l.blockCount { |
|
| 51 | - | panic "blockOffset: block not recorded"; |
|
| 52 | - | } |
|
| 48 | + | assert blockIdx < l.blockCount, "blockOffset: block not recorded"; |
|
| 53 | 49 | return l.blockOffsets[blockIdx]; |
|
| 54 | 50 | } |
|
| 55 | 51 | ||
| 56 | 52 | /// Look up a function's byte offset by name. |
|
| 57 | 53 | pub fn funcOffset(l: *Labels, name: *[u8]) -> i32 { |
lib/std/lang/gen/regalloc/assign.rad
+2 -6
| 216 | 216 | return nil; |
|
| 217 | 217 | } |
|
| 218 | 218 | ||
| 219 | 219 | /// Add a mapping to the register map. |
|
| 220 | 220 | fn rmapSet(rmap: *mut RegMap, virtReg: u32, physReg: u8) { |
|
| 221 | - | if rmap.n >= MAX_ACTIVE { |
|
| 222 | - | panic "rmapSet: register map overflow"; |
|
| 223 | - | } |
|
| 221 | + | assert rmap.n < MAX_ACTIVE, "rmapSet: register map overflow"; |
|
| 224 | 222 | rmap.virtRegs[rmap.n] = virtReg; |
|
| 225 | 223 | rmap.physRegs[rmap.n] = physReg; |
|
| 226 | 224 | rmap.n += 1; |
|
| 227 | 225 | } |
|
| 228 | 226 |
| 291 | 289 | if let phys = rmapFind(ctx.current, reg.n) { |
|
| 292 | 290 | bitset::clear(ctx.usedRegs, phys as u32); |
|
| 293 | 291 | rmapRemove(ctx.current, reg.n); |
|
| 294 | 292 | } |
|
| 295 | 293 | } |
|
| 296 | - | if reg.n >= ctx.assignments.len { |
|
| 297 | - | panic "processInstrRegCb: register out of bounds"; |
|
| 298 | - | } |
|
| 294 | + | assert reg.n < ctx.assignments.len, "processInstrRegCb: register out of bounds"; |
|
| 299 | 295 | if spill::isSpilled(ctx.spillInfo, reg) { |
|
| 300 | 296 | return; // Spilled values don't get physical registers. |
|
| 301 | 297 | } |
|
| 302 | 298 | if ctx.assignments[reg.n] == nil { |
|
| 303 | 299 | ctx.assignments[reg.n] = rallocReg( |
lib/std/lang/gen/regalloc/liveness.rad
+1 -3
| 89 | 89 | if let dst = il::instrDst(block.instrs[i]) { |
|
| 90 | 90 | maxReg = maxRegNum(dst.n, maxReg); |
|
| 91 | 91 | } |
|
| 92 | 92 | } |
|
| 93 | 93 | } |
|
| 94 | - | if maxReg > MAX_SSA_REGS { |
|
| 95 | - | panic "analyze: maximum SSA registers exceeded"; |
|
| 96 | - | } |
|
| 94 | + | assert maxReg <= MAX_SSA_REGS, "analyze: maximum SSA registers exceeded"; |
|
| 97 | 95 | // Allocate per-block bitsets. |
|
| 98 | 96 | let liveIn = try alloc::allocSlice(arena, @sizeOf(bitset::Bitset), @alignOf(bitset::Bitset), blockCount) as *mut [bitset::Bitset]; |
|
| 99 | 97 | let liveOut = try alloc::allocSlice(arena, @sizeOf(bitset::Bitset), @alignOf(bitset::Bitset), blockCount) as *mut [bitset::Bitset]; |
|
| 100 | 98 | let defs = try alloc::allocSlice(arena, @sizeOf(bitset::Bitset), @alignOf(bitset::Bitset), blockCount) as *mut [bitset::Bitset]; |
|
| 101 | 99 | let uses = try alloc::allocSlice(arena, @sizeOf(bitset::Bitset), @alignOf(bitset::Bitset), blockCount) as *mut [bitset::Bitset]; |
lib/std/lang/gen/regalloc/spill.rad
+2 -6
| 234 | 234 | /// Collect all values from a bitset into a candidates buffer with their costs. |
|
| 235 | 235 | fn collectCandidates(set: *bitset::Bitset, costs: *[SpillCost]) -> Candidates { |
|
| 236 | 236 | let mut c = Candidates { entries: undefined, n: 0 }; |
|
| 237 | 237 | let mut it = bitset::iter(set); |
|
| 238 | 238 | while let reg = bitset::iterNext(&mut it) { |
|
| 239 | - | if c.n >= MAX_CANDIDATES { |
|
| 240 | - | panic "collectCandidates: too many live values"; |
|
| 241 | - | } |
|
| 239 | + | assert c.n < MAX_CANDIDATES, "collectCandidates: too many live values"; |
|
| 242 | 240 | if reg < costs.len { |
|
| 243 | 241 | c.entries[c.n] = CostEntry { reg, cost: costs[reg].defs + costs[reg].uses }; |
|
| 244 | 242 | c.n += 1; |
|
| 245 | 243 | } |
|
| 246 | 244 | } |
| 311 | 309 | } |
|
| 312 | 310 | ||
| 313 | 311 | /// Callback for [`il::forEachReg`]: increments use count for register. |
|
| 314 | 312 | fn countRegUseCallback(reg: il::Reg, ctxPtr: *mut opaque) { |
|
| 315 | 313 | let ctx = ctxPtr as *mut CountCtx; |
|
| 316 | - | if reg.n >= ctx.costs.len { |
|
| 317 | - | panic "countRegUseCallback: register out of bounds"; |
|
| 318 | - | } |
|
| 314 | + | assert reg.n < ctx.costs.len, "countRegUseCallback: register out of bounds"; |
|
| 319 | 315 | ctx.costs[reg.n].uses = ctx.costs[reg.n].uses + ctx.weight; |
|
| 320 | 316 | } |
|
| 321 | 317 | ||
| 322 | 318 | /// Callback for [`il::forEachReg`]: adds register to live set. |
|
| 323 | 319 | fn addRegToSetCallback(reg: il::Reg, ctx: *mut opaque) { |
lib/std/lang/lower.rad
+5 -15
| 2364 | 2364 | ||
| 2365 | 2365 | /// Add a predecessor edge from `pred` to `target`. |
|
| 2366 | 2366 | /// Must be called before the target block is sealed. Duplicates are ignored. |
|
| 2367 | 2367 | fn addPredecessor(self: *mut FnLowerer, target: BlockId, pred: BlockId) { |
|
| 2368 | 2368 | let blk = getBlockMut(self, target); |
|
| 2369 | - | if blk.sealState == Sealed::Yes { |
|
| 2370 | - | panic "addPredecessor: adding predecessor to sealed block"; |
|
| 2371 | - | } |
|
| 2369 | + | assert blk.sealState != Sealed::Yes, "addPredecessor: adding predecessor to sealed block"; |
|
| 2372 | 2370 | let preds = &mut blk.preds; |
|
| 2373 | 2371 | for i in 0..preds.len { |
|
| 2374 | 2372 | if preds[i] == pred.n { // Avoid duplicate predecessor entries. |
|
| 2375 | 2373 | return; |
|
| 2376 | 2374 | } |
| 2404 | 2402 | ///////////////////// |
|
| 2405 | 2403 | ||
| 2406 | 2404 | /// Enter a loop context for break/continue handling. |
|
| 2407 | 2405 | /// `continueBlock` is `nil` when the continue target is created lazily. |
|
| 2408 | 2406 | fn enterLoop(self: *mut FnLowerer, breakBlock: BlockId, continueBlock: ?BlockId) { |
|
| 2409 | - | if self.loopDepth >= self.loopStack.len { |
|
| 2410 | - | panic "enterLoop: loop depth overflow"; |
|
| 2411 | - | } |
|
| 2407 | + | assert self.loopDepth < self.loopStack.len, "enterLoop: loop depth overflow"; |
|
| 2412 | 2408 | let slot = &mut self.loopStack[self.loopDepth]; |
|
| 2413 | 2409 | ||
| 2414 | 2410 | slot.breakTarget = breakBlock; |
|
| 2415 | 2411 | slot.continueTarget = continueBlock; |
|
| 2416 | 2412 | self.loopDepth += 1; |
|
| 2417 | 2413 | } |
|
| 2418 | 2414 | ||
| 2419 | 2415 | /// Exit the current loop context. |
|
| 2420 | 2416 | fn exitLoop(self: *mut FnLowerer) { |
|
| 2421 | - | if self.loopDepth == 0 { |
|
| 2422 | - | panic "exitLoop: loopDepth is zero"; |
|
| 2423 | - | } |
|
| 2417 | + | assert self.loopDepth != 0, "exitLoop: loopDepth is zero"; |
|
| 2424 | 2418 | self.loopDepth -= 1; |
|
| 2425 | 2419 | } |
|
| 2426 | 2420 | ||
| 2427 | 2421 | /// Get the current loop context. |
|
| 2428 | 2422 | fn currentLoop(self: *mut FnLowerer) -> ?*mut LoopCtx { |
| 2674 | 2668 | /// |
|
| 2675 | 2669 | /// This function creates a fresh register `%1` as a block parameter, then patches |
|
| 2676 | 2670 | /// each predecessor's jump to pass its value of `x` as an argument. |
|
| 2677 | 2671 | fn createBlockParam(self: *mut FnLowerer, block: BlockId, v: Var) -> il::Val throws (LowerError) { |
|
| 2678 | 2672 | // Entry block must not have block parameters. |
|
| 2679 | - | if block == self.entryBlock { |
|
| 2680 | - | panic "createBlockParam: entry block must not have block parameters"; |
|
| 2681 | - | } |
|
| 2673 | + | assert block != self.entryBlock, "createBlockParam: entry block must not have block parameters"; |
|
| 2682 | 2674 | // Allocate a register to hold the merged value. |
|
| 2683 | 2675 | let reg = nextReg(self); |
|
| 2684 | 2676 | let type = getVar(self, v).type; |
|
| 2685 | 2677 | ||
| 2686 | 2678 | // Create block parameter and add it to the block. |
| 2746 | 2738 | for predId in blk.preds { |
|
| 2747 | 2739 | let pred = BlockId { n: predId }; |
|
| 2748 | 2740 | // This may recursively trigger more block arg resolution if the |
|
| 2749 | 2741 | // predecessor also needs to look up the variable from its predecessors. |
|
| 2750 | 2742 | let val = try useVarInBlock(self, pred, v); |
|
| 2751 | - | if val == il::Val::Undef { |
|
| 2752 | - | panic "createBlockParam: predecessor provides undef value for block parameter"; |
|
| 2753 | - | } |
|
| 2743 | + | assert val != il::Val::Undef, "createBlockParam: predecessor provides undef value for block parameter"; |
|
| 2754 | 2744 | patchTerminatorArg(self, pred, block.n, paramIdx, val); |
|
| 2755 | 2745 | } |
|
| 2756 | 2746 | } |
|
| 2757 | 2747 | ||
| 2758 | 2748 | /// Check if a block parameter is trivial, i.e. all predecessors provide |
lib/std/lang/resolver.rad
+8 -24
| 939 | 939 | // Check for an existing scope for this node, and don't allocate a new |
|
| 940 | 940 | // one in that case. |
|
| 941 | 941 | if let scope = scopeFor(self, owner) { |
|
| 942 | 942 | return scope; |
|
| 943 | 943 | } |
|
| 944 | - | if owner.id >= self.nodeData.entries.len { |
|
| 945 | - | panic "allocScope: node ID out of bounds"; |
|
| 946 | - | } |
|
| 944 | + | assert owner.id < self.nodeData.entries.len, "allocScope: node ID out of bounds"; |
|
| 947 | 945 | let p = try! alloc::alloc(&mut self.arena, @sizeOf(Scope), @alignOf(Scope)); |
|
| 948 | 946 | let entry = p as *mut Scope; |
|
| 949 | 947 | ||
| 950 | 948 | // Allocate symbols from the arena. |
|
| 951 | 949 | let ptr = try! alloc::allocSlice(&mut self.arena, @sizeOf(*mut Symbol), @alignOf(*mut Symbol), capacity); |
| 1009 | 1007 | ||
| 1010 | 1008 | /// Visit the body of a loop while tracking nesting depth. |
|
| 1011 | 1009 | fn visitLoop(self: *mut Resolver, body: *ast::Node) -> Type |
|
| 1012 | 1010 | throws (ResolveError) |
|
| 1013 | 1011 | { |
|
| 1014 | - | if self.loopDepth >= MAX_LOOP_DEPTH { |
|
| 1015 | - | panic "visitLoop: loop nesting depth exceeded"; |
|
| 1016 | - | } |
|
| 1012 | + | assert self.loopDepth < MAX_LOOP_DEPTH, "visitLoop: loop nesting depth exceeded"; |
|
| 1017 | 1013 | self.loopStack[self.loopDepth] = LoopCtx { hasBreak: false }; |
|
| 1018 | 1014 | self.loopDepth += 1; |
|
| 1019 | 1015 | ||
| 1020 | 1016 | let ty = try infer(self, body) catch { |
|
| 1021 | - | if self.loopDepth == 0 { |
|
| 1022 | - | panic "visitLoop: loop depth underflow"; |
|
| 1023 | - | } |
|
| 1017 | + | assert self.loopDepth != 0, "visitLoop: loop depth underflow"; |
|
| 1024 | 1018 | self.loopDepth -= 1; |
|
| 1025 | 1019 | throw ResolveError::Failure; |
|
| 1026 | 1020 | }; |
|
| 1027 | 1021 | // Pop and check if break was encountered. |
|
| 1028 | 1022 | self.loopDepth -= 1; |
| 1055 | 1049 | } |
|
| 1056 | 1050 | } |
|
| 1057 | 1051 | ||
| 1058 | 1052 | /// Set the expected return type for a new function body. |
|
| 1059 | 1053 | fn enterFn(self: *mut Resolver, node: *ast::Node, ty: *FnType) { |
|
| 1060 | - | if self.currentFn != nil { |
|
| 1061 | - | panic "enterFn: already in a function"; |
|
| 1062 | - | } |
|
| 1054 | + | assert self.currentFn == nil, "enterFn: already in a function"; |
|
| 1063 | 1055 | self.currentFn = ty; |
|
| 1064 | 1056 | enterScope(self, node); |
|
| 1065 | 1057 | } |
|
| 1066 | 1058 | ||
| 1067 | 1059 | /// Clear the expected return type when leaving a function body. |
| 2160 | 2152 | ) -> *[*[u8]] throws (ResolveError) { |
|
| 2161 | 2153 | let mut out: *[*[u8]] = &[]; |
|
| 2162 | 2154 | ||
| 2163 | 2155 | match node.value { |
|
| 2164 | 2156 | case ast::NodeValue::Ident(name) if name.len > 0 => { |
|
| 2165 | - | if buf.len < 1 { |
|
| 2166 | - | panic "flattenPath: invalid output buffer size"; |
|
| 2167 | - | } |
|
| 2157 | + | assert buf.len >= 1, "flattenPath: invalid output buffer size"; |
|
| 2168 | 2158 | buf[0] = name; |
|
| 2169 | 2159 | out = &buf[..1]; |
|
| 2170 | 2160 | } |
|
| 2171 | 2161 | case ast::NodeValue::ScopeAccess(access) => { |
|
| 2172 | 2162 | // Recursively flatten parent path. |
|
| 2173 | 2163 | let parent = try flattenPath(self, access.parent, buf); |
|
| 2174 | - | if parent.len >= buf.len { |
|
| 2175 | - | panic "flattenPath: invalid output buffer size"; |
|
| 2176 | - | } |
|
| 2164 | + | assert parent.len < buf.len, "flattenPath: invalid output buffer size"; |
|
| 2177 | 2165 | let child = try nodeName(self, access.child); |
|
| 2178 | 2166 | buf[parent.len] = child; |
|
| 2179 | 2167 | out = &buf[..parent.len + 1]; |
|
| 2180 | 2168 | } |
|
| 2181 | 2169 | case ast::NodeValue::Super => { |
| 2296 | 2284 | node: *ast::Node, |
|
| 2297 | 2285 | access: ast::Access, |
|
| 2298 | 2286 | path: *[*[u8]], |
|
| 2299 | 2287 | scope: *Scope |
|
| 2300 | 2288 | ) -> *mut Symbol throws (ResolveError) { |
|
| 2301 | - | if path.len == 0 { |
|
| 2302 | - | panic "resolvePath: empty path"; |
|
| 2303 | - | } |
|
| 2289 | + | assert path.len != 0, "resolvePath: empty path"; |
|
| 2304 | 2290 | // Start by finding the root of the path. |
|
| 2305 | 2291 | let root = path[0]; |
|
| 2306 | 2292 | let sym = findInScopeRecursive(scope, root, isAnySymbol) else |
|
| 2307 | 2293 | throw emitError(self, node, ErrorKind::UnresolvedSymbol(root)); |
|
| 2308 | 2294 | let suffix = &path[1..]; |
| 3658 | 3644 | isAllVoid: true |
|
| 3659 | 3645 | }); |
|
| 3660 | 3646 | ||
| 3661 | 3647 | try visitList(self, decl.derives); |
|
| 3662 | 3648 | ||
| 3663 | - | if decl.variants.len > MAX_UNION_VARIANTS { |
|
| 3664 | - | panic "resolveUnionBody: maximum union variants exceeded"; |
|
| 3665 | - | } |
|
| 3649 | + | assert decl.variants.len <= MAX_UNION_VARIANTS, "resolveUnionBody: maximum union variants exceeded"; |
|
| 3666 | 3650 | let mut iota: u32 = 0; |
|
| 3667 | 3651 | for variantNode, i in decl.variants { |
|
| 3668 | 3652 | let case ast::NodeValue::UnionDeclVariant(variantDecl) = variantNode.value |
|
| 3669 | 3653 | else panic "resolveUnionBody: invalid union variant"; |
|
| 3670 | 3654 | let variantName = try nodeName(self, variantDecl.name); |
lib/std/lang/strings.rad
+1 -3
| 63 | 63 | /// Otherwise, adds the string pointer to the pool and returns it. |
|
| 64 | 64 | pub 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 | - | if sp.count >= TABLE_SIZE / 2 { |
|
| 69 | - | panic "intern: string pool is full"; |
|
| 70 | - | } |
|
| 68 | + | assert sp.count < TABLE_SIZE / 2, "intern: string pool is full"; |
|
| 71 | 69 | sp.table[idx] = str; |
|
| 72 | 70 | sp.count += 1; |
|
| 73 | 71 | ||
| 74 | 72 | return str; |
|
| 75 | 73 | } |