Repository navigation
fix: fmt operand map literal, T: Ord over what < orders, channel buffer drop - #376
Merged
Merged
Conversation
fmt_wants_value named a few value positions one token at a time, so
`print {"x": 1}`, `print {"x": 1}.len()` and `m == {"x": 1}` had the
literal opened across three lines like a body (#374).
- fmt_takes_operand states the rule instead: every binary and prefix
operator by GRAMMAR's groups, and each keyword whose production goes
on to an expression (`print`, `assert`, `raise`, `return`, ...).
- the groups are the parser's own predicates, moved to token.zg as
is_add_op, is_mul_op, is_cmp_op and is_unary_op, so an operator the
parser learns is one the formatter knows.
- a type position (`is`, `as`, `->`), a postfix (`!`, `?`) and a body
keyword stay off, and fmt_brace_is_map still decides by content, so
a block after `print` or `+` keeps a block's layout.
A send moves an owned copy into the buffer, but zrt_chan_new knew only
the element's size, so chan_free freed the ring's bytes and kept every
str or list a buffered value pointed at (#334).
- zrt_chan_new takes the element's drop (a zrt_drop_fn, NULL for plain
data) and chan_free runs it on each element still in the ring,
oldest first from head
- c_chan_new passes c_elem_drop_fn of the element, the same thunk a
list element and a held send already use
- the runtime suite's drivers pass NULL for their long channels
The bound asked only for a declared `Ord` impl, so `least[T: Ord]` refused int, every
integer width, `str`, and the tuples and arrays #360 taught `<` to order. `T: Eq`
already asked `c_eq_legal`, the predicate `==` lowers by; `T: Ord` now asks
`c_ord_legal`, the whole-type form of #360's part rule.
- A part that orders reads through a strong typedef to its scalar, so a
`type Age = int` orders as its int does: inside a tuple as it already did alone,
per docs/core/types.md's "an operator `Y` has, `X` has".
- A `float`, a list and a tuple holding either are still E4010 at the call.
The bound widened to what `<` orders, and this case holds the edge of it: shown RED with
the `Ord` bound answering true, when the call built and the body's `<` reported E3044
in a template the caller never wrote.
- mem-check's chan_left leaves a called str, a named str's copy and a
list in buffered channels each round, beside an int channel that owes
nothing; it counted three live allocations a round before the fix
- the runtime suite frees a channel whose ring has wrapped and asserts
each buffered element is dropped once, oldest first
This was referenced Oct 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three of the four issues picked for this branch. #320 is left out; see below.
Fixes
printand==#374zerg fmt: a map literal on the right of an operator, or afterprint,assertand the otherkeywords that take an expression, stays on one line.
fmt_takes_operandstates the rule by GRAMMAR's operatorgroups, asked of the parser's own predicates (moved to
token.zg), so the two cannot drift. A block in the samepositions keeps a block's layout.
<but does not meet the boundT: Ord#369T: Ordis met by what<orders: int, every integer width,str, and a tuple or array whose partsorder. The bound and the
<lowering ask the samec_ord_legal. A strong typedef over an integer orders as itsinteger does. A
floatpart is still E4010 at the call.zrt_chan_newtakes the element's drop(
NULLfor plain data) andchan_freeruns it on what the ring holds. A send moves an owned copy in, so thisis not a double free.
Tests
fix/four-minor):fmt/map-literal-operand.zg,codegen/generic_ord_scalar.zg,codegen/generic_ord_tuple.zg(oracle-skipped: the seed has no tuple<).reject-check.sh: a tuple with afloatpart does not meetT: Ord. It is RED with the bound answering true.mem-check.shchan_leftand runtimeTestChannelDropsWhatItsBufferHolds. Both are RED before the fix.All CI gates were run locally and are green.
Not in this PR
#320 stays open. An
Errnever owns its message: a copy is a plain struct, and runtime Errs carry C literals.Releasing at
??alone would turn the leak into a use-after-free (wrap(e) ?? 0; print e.msg). It needs anownership model for
Err, which is larger than this branch.Closes #374
Closes #369
Closes #334
🤖 Generated with Claude Code
https://claude.ai/code/session_01N8jd1oK2orM6diHxhvWhC7