@@ -1223,20 +1223,29 @@ fn emit_let(toks: read List<Tok>, start: read Int, limit: read Int, d: read Int)
12231223 let a = String.concat(left: read "let kind=", right: read kind)
12241224 let b = String.concat(left: read a, right: read " name=")
12251225 let c = String.concat(left: read b, right: read name)
1226- let f = String.concat(left: read c, right: read " mut=")
1227- let g = String.concat(left: read f, right: read boolstr(b: read isMut))
1228- let h = String.concat(left: read g, right: read " async=false")
1229- emit(depth: read d, s: read h)
12301226 // Value split is the FIRST `=` after the name (matching parse_let_stmt): a
12311227 // let's name/annotation never contains `=`, so no `>=`/`==` guard is needed —
12321228 // and top_assign's guard would wrongly skip the `=` after a generic `>`
12331229 // (`let x: Option<Int > = …`).
12341230 let asg = first_eq(toks: read toks, start: read j, end: read e)
1235- if at_symbol(toks: read toks, i: read j, code: read SYM_COLON) {
1231+ let hasColon = at_symbol(toks: read toks, i: read j, code: read SYM_COLON)
1232+ let mut typeEnd = e
1233+ if asg >= 0 { typeEnd = asg }
1234+ // malformed=true when `=` is present with no value expression, or `:` with no
1235+ // type (parse_let_stmt: equals.is_some && value.is_none, or the colon analog).
1236+ let emptyVal = asg >= 0 && (asg + 1) >= e
1237+ let emptyType = hasColon && (j + 1) >= typeEnd
1238+ let malformed = emptyVal || emptyType
1239+ let f = String.concat(left: read c, right: read " mut=")
1240+ let g = String.concat(left: read f, right: read boolstr(b: read isMut))
1241+ let mut h = String.concat(left: read g, right: read " async=false")
1242+ if malformed { h = String.concat(left: read h, right: read " malformed=true") }
1243+ emit(depth: read d, s: read h)
1244+ if hasColon && emptyType == false {
12361245 emit_type_ref(toks: read toks, i: read (j + 1), tag: read "type", eff: read "", d: read (d + 1))
12371246 }
12381247 // Value.
1239- if asg >= 0 {
1248+ if asg >= 0 && emptyVal == false {
12401249 emit(depth: read (d + 1), s: read "value")
12411250 emit_expr(toks: read toks, start: read (asg + 1), end: read e, d: read (d + 2))
12421251 }
@@ -1778,8 +1787,13 @@ fn emit_type_decl(toks: read List<Tok>, start: read Int, d: read Int) -> Int {
17781787 emit(depth: read d, s: read h)
17791788 j = emit_generics(toks: read toks, i: read j, d: read (d + 1))
17801789 j = emit_derives(toks: read toks, i: read j, d: read (d + 1))
1781- let openb = find_block_open(toks: read toks, start: read j, limit: read List.len(list: read toks))
1782- if openb < 0 { return declaration_line_end(toks: read toks, start: read start) }
1790+ // After the name (and any generics/derives) the very next token is either the
1791+ // body `{` or the start of the NEXT declaration — so a body exists iff that
1792+ // token is `{`. (A raw find_block_open would borrow a LATER decl's brace for a
1793+ // body-less declaration like `struct Image`, swallowing everything up to it.)
1794+ let mut openb = -1
1795+ if at_symbol(toks: read toks, i: read j, code: read SYM_LBRACE) { openb = j }
1796+ if openb < 0 { return j }
17831797 let close = find_matching(toks: read toks, open: read openb, openSym: read SYM_LBRACE, closeSym: read SYM_RBRACE)
17841798 let dropPos = find_drop(toks: read toks, open: read openb, close: read close)
17851799 let mut fieldsEnd = close
@@ -1810,8 +1824,13 @@ fn emit_sum(toks: read List<Tok>, start: read Int, d: read Int) -> Int {
18101824 emit(depth: read d, s: read c)
18111825 j = emit_generics(toks: read toks, i: read j, d: read (d + 1))
18121826 j = emit_derives(toks: read toks, i: read j, d: read (d + 1))
1813- let openb = find_block_open(toks: read toks, start: read j, limit: read List.len(list: read toks))
1814- if openb < 0 { return declaration_line_end(toks: read toks, start: read start) }
1827+ // After the name (and any generics/derives) the very next token is either the
1828+ // body `{` or the start of the NEXT declaration — so a body exists iff that
1829+ // token is `{`. (A raw find_block_open would borrow a LATER decl's brace for a
1830+ // body-less declaration like `struct Image`, swallowing everything up to it.)
1831+ let mut openb = -1
1832+ if at_symbol(toks: read toks, i: read j, code: read SYM_LBRACE) { openb = j }
1833+ if openb < 0 { return j }
18151834 let close = find_matching(toks: read toks, open: read openb, openSym: read SYM_LBRACE, closeSym: read SYM_RBRACE)
18161835 // Variants: newline-separated `Name` or `Name(fields)`.
18171836 let mut i = openb + 1
0 commit comments