0.8.83
Breaking
-
Member-access nil safety is now uniform across
.,[], and.().
Subscript (obj[key]) and method-call (obj.method(..)) receivers are
now held to the same standard the checker already applied to property
reads: a statically-nilorT | nilreceiver is an error, and an
unknownreceiver is a warning. Previously onlyobj.fieldwas
diagnosed, soobj[key]/obj.method()on a possibly-nil value passed
harn checkand failed at runtime instead. Migrate with the matching
optional operator (?[…],?.method()), a!= nilguard, or a??
default.anyreceivers remain a deliberate, undiagnosed escape hatch,
and the ambient dict-literal idiom (let d = {a: 1}; d["b"]) stays loose.To keep the stricter rule pleasant, two long-standing narrowing gaps were
closed alongside it: ano?.field != nil(or?[]/?.()) guard now
narrows the base identifieroto non-nil on the matching branch, and
the??coalesce operator now drops the nil arm even when its left operand
is a named type alias that expands to a nilable union (previously only
inlineT | nilunions were narrowed). The conformance harness also labels
failures by stage —type error/compile error/runtime error—
instead of calling every pre-runtime failure a "runtime error".
Added
-
Row polymorphism: open record types and row-polymorphic generics. Shape
types may now carry a trailing row tail —{id: string, ...R}is an open
record (the listed fields plus a row variableRstanding for any other
fields), and{...R1, ...R2}is the right-biased merge of two rows. A
function generic over rows types record merge precisely and soundly:pub fn merge<R1, R2>(a: {...R1}, b: {...R2}) -> {...R1, ...R2}merge({a: 1}, {b: "x"})now returns{a: int, b: string}— every field
preserved with its real type,boverridingaon overlap — instead of
failing to unify a single value type or collapsing todict. Open-record
parameters (fn f(x: {id: string, ...rest})) accept any record that has the
required fields and carry the rest through. Row variables bind one-sidedly
from the actual record's leftover fields; gradual tails (dict,any)
interoperate, and absence reasoning stays restricted to closed shapes.std's
mergeanddeep_mergeare re-typed with row signatures.
Changed
- Record merge and spread now infer the precise merged shape.
{...a, k: v},
{...a, ...b}, anda + bon record shapes now produce the right-biased
merged shape — every field carried through with its real type, later fields
overriding earlier ones — instead of collapsing to an untypeddict. On an
overlap the result is required if either side is required, and its type is the
overriding (right) field's type, or the union of both when the right field is
optional. Spreading a non-closed source (adict,dict<K,V>, union, or
unknown) still degrades todictrather than inventing fields. This is the
structural foundation for full row-polymorphism support. Generic functions
also now bind a type parameter from a named-alias argument the same way
they already did from an inline shape literal (type Opts = {…}arguments to
dict<string, V>parameters no longer fail to inferV).
Fixed
- Three parse-robustness fixes for the agent tool-call path. The
native-JSON salvage path no longer panics on multi-byte UTF-8
(emoji/accents/CJK) in trailing prose after a[{"id":...}]array — it now
parses the first JSON value with a boundary-safe forward
serde_json::Deserializerinstead of an O(n^2) backward byte scan that could
slice mid-codepoint and abort the turn. The tagged-protocol fence-parity
check no longer treats an earlier unbalanced```as fencing a later
legitimate<tool_call>block (which dropped the call and injected a spurious
protocol violation); an open fence only encloses a tag when a matching close
follows. Andagent_loopnow injectsparse_guidanceon partial-success
turns (some calls parsed, one malformed) flaggedhas_partial_successwith
the dispatched-call count, so the model gets a signal to re-emit the dropped
call instead of zero feedback — while the no-progress stall suppression stays
gated on full parse drops only. - The release publish step (
scripts/publish.sh) now treats cargo's "timeout
while waiting for published dependencies" / "timed out waiting for … to be
available" as a retryable index-propagation condition. Previously a slow
crates.io index could leave the last crate (e.g.harn-cli, waiting on
harn-lsp) unpublished and abort the run as a "non-retryable error" without
even trying the per-crate fallback; it now retries and falls back, so a
propagation lag no longer leaves a release half-published. - Fixed four latent stdlib type bugs surfaced by precise record-merge typing.
Now thatmergeinfers the exact merged shape, the type checker caught
mismatches the old untypeddictreturn had hidden:github.enable_auto_mergereadsmethod/merge_methodoptions that
GitHubCallOptionsnever declared — added them.github.wait_until_deploy_succeeds/wait_until_ci_green/
wait_until_pr_mergedbuilt monitor options with GitHub's millisecond
field names (timeout_ms,poll_interval_ms,max_wait_ms), which
wait_forsilently dropped — and since the monitor requires atimeout
duration, those calls would have thrown at runtime. They now translate
the millisecond cadence into the duration-typedMonitorWaitOptionsso the
caller's timing is honored.- The git-forge pull-request event builder is now annotated so its
filter_nil-projected fields type as the declaredGitForge*structs. graphql_parse_schema'scurrentaccumulator no longer trips a
narrow-to-neverreassignment error.
- The entire shipped stdlib now passes
harn checkcleanly. Closing the
loop on the precise-typing work, eight more latent type bugs were
root-caused and fixed: nilable option bags narrowed before reaching
non-nildictbuiltins (waitpoint), missing/mis-typed fields on the
context_artifact,TriageEvent, and agent option-bag shapes corrected to
match what the builders actually emit, a nilableproviderdefaulted before
a non-nil use (agent/options,agent/sitrep), a nilable hook registry
narrowed (tool_hooks), and an always-throwing__fact_errortyped
-> never. The type checker's.reverse()was also fixed to return the
receiver's own type (list-reversing alist<T>yieldslist<T>, not
string).
Install / Upgrade
cargo install harn-cliFull Changelog: v0.8.82...v0.8.83