@@ -955,13 +955,25 @@ fn emit_object_or_map(toks: read List<Tok>, start: read Int, close: read Int, d:
955955// emit_type_ref renders one type starting at token i and returns the next index.
956956// -------------------------------------------------------------------------
957957
958+ // True if token j is a type-level prefix keyword skipped when locating the name
959+ // (read/mut/take effects + fresh/handle/weak/noescape/owned), matching name_index
960+ // in parse_type_ref.
961+ fn is_type_prefix(toks: read List<Tok >, j: read Int) -> Bool {
962+ return is_kw_text(toks: read toks, i: read j, word: read "read") || is_kw_text(toks: read toks, i: read j, word: read "mut") || is_kw_text(toks: read toks, i: read j, word: read "take") || is_kw_text(toks: read toks, i: read j, word: read "fresh") || is_kw_text(toks: read toks, i: read j, word: read "handle") || is_kw_text(toks: read toks, i: read j, word: read "weak") || is_kw_text(toks: read toks, i: read j, word: read "noescape") || is_kw_text(toks: read toks, i: read j, word: read "owned")
963+ }
964+
958965fn emit_type_ref(toks: read List<Tok >, i: read Int, tag: read String, eff: read String, d: read Int) -> Int {
959- let mut j = i
966+ // Prefix flags reflect ONLY the token at `i` (matching parse_type_ref, which
967+ // reads is_fresh/is_noescape/is_owned from tokens[start]).
960968 let mut isFresh = false
961- if at_ident(toks: read toks, i: read j, wid: read WORD_FRESH) {
962- isFresh = true
963- j = j + 1
964- }
969+ let mut isNoescape = false
970+ let mut isOwned = false
971+ if at_ident(toks: read toks, i: read i, wid: read WORD_FRESH) { isFresh = true }
972+ else if is_kw_text(toks: read toks, i: read i, word: read "noescape") { isNoescape = true }
973+ else if is_kw_text(toks: read toks, i: read i, word: read "owned") { isOwned = true }
974+ // Name is the first non-prefix token.
975+ let mut j = i
976+ while is_type_prefix(toks: read toks, j: read j) { j = j + 1 }
965977 let name = tk_text(toks: read toks, i: read j)
966978 j = j + 1
967979 local sb = StringBuilder.new()
@@ -974,9 +986,12 @@ fn emit_type_ref(toks: read List<Tok>, i: read Int, tag: read String, eff: read
974986 StringBuilder.push(builder: mut sb, value: read name)
975987 StringBuilder.push(builder: mut sb, value: read " fresh=")
976988 StringBuilder.push(builder: mut sb, value: read boolstr(b: read isFresh))
977- StringBuilder.push(builder: mut sb, value: read " noescape=false owned=false")
989+ StringBuilder.push(builder: mut sb, value: read " noescape=")
990+ StringBuilder.push(builder: mut sb, value: read boolstr(b: read isNoescape))
991+ StringBuilder.push(builder: mut sb, value: read " owned=")
992+ StringBuilder.push(builder: mut sb, value: read boolstr(b: read isOwned))
978993 emit(depth: read d, s: read StringBuilder.finish(builder: take sb))
979- // Generic args.
994+ // Generic args `<...>` .
980995 if at_symbol(toks: read toks, i: read j, code: read SYM_LANGLE) {
981996 let close = find_matching(toks: read toks, open: read j, openSym: read SYM_LANGLE, closeSym: read SYM_RANGLE)
982997 if close > j {
@@ -988,6 +1003,23 @@ fn emit_type_ref(toks: read List<Tok>, i: read Int, tag: read String, eff: read
9881003 j = close + 1
9891004 }
9901005 }
1006+ // Fn types: `Fn(<params >) -> <ret >` → fn-param (with optional effect) + fn-return.
1007+ if name == "Fn" && at_symbol(toks: read toks, i: read j, code: read SYM_LPAREN) {
1008+ let pclose = find_matching(toks: read toks, open: read j, openSym: read SYM_LPAREN, closeSym: read SYM_RPAREN)
1009+ let mut k = j + 1
1010+ while k < pclose {
1011+ let comma = split_comma(toks: read toks, start: read k, end: read pclose)
1012+ let pEff = effect_kw(toks: read toks, i: read k)
1013+ let mut pStart = k
1014+ if String.len(value: read pEff) > 0 { pStart = k + 1 }
1015+ emit_type_ref(toks: read toks, i: read pStart, tag: read "fn-param", eff: read pEff, d: read (d + 1))
1016+ if comma < 0 { k = pclose } else { k = comma + 1 }
1017+ }
1018+ j = pclose + 1
1019+ if at_symbol(toks: read toks, i: read j, code: read SYM_ARROW) {
1020+ j = emit_type_ref(toks: read toks, i: read (j + 1), tag: read "fn-return", eff: read "", d: read (d + 1))
1021+ }
1022+ }
9911023 return j
9921024}
9931025
@@ -1429,7 +1461,12 @@ fn emit_function(toks: read List<Tok>, start: read Int, d: read Int) -> Int {
14291461 if at_symbol(toks: read toks, i: read j, code: read SYM_ARROW) {
14301462 hasRet = true
14311463 retStart = j + 1
1432- if at_ident(toks: read toks, i: read (j + 1), wid: read WORD_FRESH) { retFresh = true }
1464+ // `-> fresh T` sets the fn's returns-fresh and the type ref begins AT T
1465+ // (the return TypeRef itself is fresh=false — matches parse_function_decl).
1466+ if at_ident(toks: read toks, i: read (j + 1), wid: read WORD_FRESH) {
1467+ retFresh = true
1468+ retStart = j + 2
1469+ }
14331470 }
14341471 // body
14351472 let bodyOpen = find_block_open(toks: read toks, start: read j, limit: read List.len(list: read toks))
0 commit comments