feat(lang): a name is defined once, a local once per block, and a result is always returned
L1. Two vars, consts, enums, properties or events of one name in a program are an error naming both places (functions already were); the first used to win silently. A let / var of a name its own block already declared is an error (it used to shadow). A function with a result type whose body can reach its end without a return is an error, asked structurally of the body - a return, an if/else or a match with a default arm whose every branch ends - rather than handing back whatever the result slot held. The game, the lab and every package example pass all three; the lab had one harmless shadow, and the game's split screens had two real bugs of the kind. examples/rejected/ holds the four refusals, checked by the test runner's new reject_case. Seed regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c57eafcacc
commit
dc75a5a5ab
13 changed files with 46652 additions and 44931 deletions
|
|
@ -2,12 +2,17 @@
|
|||
# block is skipped until a new basic block opens.
|
||||
|
||||
function emit_block(b: Node) -> void {
|
||||
# each block is its own place to declare a name once (loc_blk), though a local declared in a
|
||||
# block still stays visible after it
|
||||
let outer = g_blk_cur
|
||||
g_blk_next += 1
|
||||
g_blk_cur = g_blk_next
|
||||
var i = 0
|
||||
while i < len(b.kids) {
|
||||
if g_term { return }
|
||||
while i < len(b.kids) and not g_term {
|
||||
emit_stmt(b.kids[i])
|
||||
i += 1
|
||||
}
|
||||
g_blk_cur = outer
|
||||
}
|
||||
|
||||
# store `val` (llvm type `lt`) into address `addr`
|
||||
|
|
@ -126,6 +131,39 @@ function emit_return(st: Node) -> void {
|
|||
g_term = true
|
||||
}
|
||||
|
||||
# Does this block always end - a return on every path through it? A return ends it; an `if` ends
|
||||
# it when it has an `else` and both branches end; a `match` when it has a default arm and every
|
||||
# arm ends. Asked of a function's body, so one with a result cannot run off its end.
|
||||
function block_ends(b: Node) -> bool {
|
||||
if b == null { return false }
|
||||
var i = 0
|
||||
while i < len(b.kids) {
|
||||
if stmt_ends(b.kids[i]) { return true }
|
||||
i += 1
|
||||
}
|
||||
return false
|
||||
}
|
||||
function stmt_ends(st: Node) -> bool {
|
||||
if st.kind == S_RETURN { return true }
|
||||
if st.kind == S_IF {
|
||||
if st.c == null or not block_ends(st.b) { return false }
|
||||
if st.c.kind == S_IF { return stmt_ends(st.c) }
|
||||
return block_ends(st.c)
|
||||
}
|
||||
if st.kind == S_MATCH {
|
||||
var has_default = false
|
||||
var i = 0
|
||||
while i < len(st.kids) {
|
||||
let arm = st.kids[i]
|
||||
if arm_is_default(arm) { has_default = true }
|
||||
if not block_ends(arm.a) { return false }
|
||||
i += 1
|
||||
}
|
||||
return has_default
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function arm_is_default(arm: Node) -> bool {
|
||||
var p = 0
|
||||
while p < len(arm.kids) { if arm.kids[p].kind == E_ID and (arm.kids[p].s == "_") { return true }; p += 1 }
|
||||
|
|
@ -312,14 +350,16 @@ function emit_stmt(st: Node) -> void {
|
|||
g_err_file = st.file; g_err_line = st.line # so a lowering error names its statement
|
||||
emit_cov_hit(st.line) # --coverage: bump this line's hit counter (no-op otherwise)
|
||||
if st.kind == S_LET {
|
||||
loc_check_redeclared(st.s)
|
||||
var ty = st.ty
|
||||
if (ty == null) { let v0 = emit_expr(st.a); ty = v0.ty
|
||||
let slot = emit_alloca(llty(ty)); store_at(llty(ty), v0.code, slot); loc_push(st.s, slot, ty); loc_set_mut(st.ival); return }
|
||||
let slot = emit_alloca(llty(ty)); store_at(llty(ty), v0.code, slot); loc_push(st.s, slot, ty); loc_mark_declared(); loc_set_mut(st.ival); return }
|
||||
let slot = emit_alloca(llty(ty))
|
||||
if (st.a == null) {
|
||||
store_at(llty(ty), zero_of(llty(ty)), slot)
|
||||
} else { let v = emit_expr(st.a); store_at(llty(ty), coerce_code(v, ty), slot) }
|
||||
loc_push(st.s, slot, ty)
|
||||
loc_mark_declared()
|
||||
loc_set_mut(st.ival)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue