Skip to content

Bug-fix batch - #451

Merged
soronpo merged 13 commits into
mainfrom
training
Aug 7, 2026
Merged

soronpo merged 13 commits into
mainfrom
training

Conversation

@soronpo

@soronpo soronpo commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

Oron Port and others added 13 commits August 5, 2026 13:47
…/min chain absorption

Fixes #444

- `sel` is now a thin transparent-inline forwarder to `exactOp3`, with its
  candidate dispatch encoded as six mutually-exclusive ExactOp3 givens
  (NotGiven guards, no prioritization) and IR construction under a trydf'd
  `selRuntime`, so candidate mismatches surface as positioned elaboration
  errors instead of escaping derived-error exceptions.
- `exactOp3Macro` searches the op instance under the ControlledMacroError
  trap and reports the trapped candidate-specific message at the macro
  expansion position, so compile-time `sel` candidate errors point at the
  user's expression instead of the summon site inside the library.
- `SimplifyFunc.MaxMinChainAbsorb` absorbs a repeated operand into an
  existing max/min chain, keeping unrolled parametric widths minimal
  (`max(max(max(16, W), W), W)` becomes `max(16, W)`).
- `MetaContextGenPhase` keeps an `inlinedUserPosStack` of user-source
  Inlined nodes and substitutes the innermost user position wherever a
  meta-context stamp would carry an out-of-unit position (a library inline
  body's TASTy span or a macro-synthesized apply's quote-site span), so
  runtime error positions point at the failing user sub-expression.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes #442 and #447: disjoint slice/element connections with
parameter-dependent bounds were falsely rejected ("multiple connections
write" / "read-to-read"), because `departial` collapsed any parametric
bound to `Slice.Unknown` and the overlap check treated unknown as
possibly-overlapping.

- `Slice.Symbolic(lo, width)` carries `IntExprCalc.Linear` forms;
  `departial` composes selections symbolically and collapses to
  `Concrete` when the bounds fold. Vector `ApplyRange` indices are now
  scaled from cell units to bit coordinates (previously even literal
  vector range connections falsely collided).
- `IntExprCalc.DataCalc` (AppliedData mode): disjointness/overlap proofs
  on linear forms with slice-width >= 1 validity facts, covering the
  `k*W` equal-bin family at any pair distance. Root-design parameters
  stay opaque, so acceptance holds for any HDL parameter override.
- `DesignParam.instAppliedConstDataOpt`: applied-value resolution only
  through an instantiation site (cached instance, instance map, or
  parent sub-DB walk-up), shared with `protGetConstData`. Never gated on
  `isTop`, which reads true for every design block under the
  hierarchical model and in DBs flattened from it.
- `getConnToMap` reports an undecidable relation with a dedicated
  "cannot be proven disjoint" error instead of the misleading
  "multiple connections write" message.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes #446: a variable (or any part of it) written with both a blocking
(`:=`) and a non-blocking (`:==`) assignment inside the same process was
silently accepted, emitting mixed `=`/`<=` on one variable in a single
`always_ff`, which downstream tools reject (Verilator BLKSEQ).

`DB.mixedAssignKindCheck` (in `subDBCheck`, so `SanityCheck` also
enforces it between stages) errors per declaration and per process,
pointing at the conflicting write and the previous one. Consistent
kinds stay legal either way: a blocking-assigned temporary in a clocked
process is a supported idiom (see DropBAssignFromSeqProc), and shared
variables are excluded since their writes are compile-time restricted
to `:==` already. The `ownerProcessOpt` walk is hoisted out of
`sharedVarCheck` and shared by both checks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`UInt(16) := x + y` with `x: UInt(WIDTH)` errored "width (WIDTH max 16)
is undefined compared to (16)": the comparison only answered when the
symbolic parts cancelled exactly.

`IntParamRef.compare` (via `IntExprCalc.constDiff`) gains an
`elimSymbolicMaxMin` mode: a mixed max/min reduces to its constant
operands, eliminating the symbolic dependency, so `16 >= WIDTH max 16`
decides as `16 >= 16` (accepted), and a too-narrow receiver now gets
the definitive "larger than" error. A residual plain-symbol comparison
(`16 >= WIDTH`) stays undecidable and errors as before.

The mode is enabled at exactly two sites, which must agree: the DFXInt
TC width-fit check and `carryPromoteWidthCheck` (otherwise anonymous
`sum := x + y` carry-promotes to `max+1` and is rejected while the
named form passes). It is deliberately NOT used for `=~`/`isSimilarTo`
or the Bits/vector equality checks, where `max(W, 16)` and `16` must
stay distinct (similarity would skip the resize insertion in
`toDFXIntOf`).

The `1*W == W`, `0*W == 0`, `W + 0 == W`, `W - 0 == W` linearization
identities are pinned by tests, and the `sel` parametric-width case
(`16 max W >= 16`, the provably-sound direction of the same rule) is
now accepted instead of erroring.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mbers (#449)

Fixes the ghost refTable bindings that crashed sub-design cache adoption
(NoSuchElementException on a legitimate cache hit): MergeAssocFunc removed its
absorbed intermediate Func while lsbitsAt still held a handle and bound the
slice's offset refs to it afterwards.

Operation simplifications are now purely additive: superseded intermediates are
never revised in place and never removed; unread debris is swept once at the
endDesign snapshot boundary (skipped for duplicates and meta-programming). The
kind-level keep-predicate is shared with DropUnreferencedAnons, and val-binding
names over collapsed results are applied by Ident wrapping instead of meta
restamping, with the =~-based simplifications made ident-transparent through a
strip helper shared with IntExprCalc. SubDesignEntry.isSelfContained documents
the entry contract as a test-level sanity check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The fix is in; the durable knowledge lives in the /bugfix skill lessons and
the elaboration-caching feature doc, whose references now stand on their own.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…l(0) (#450)

The crash (an internal NoSuchElementException on the parameter default's
literal) shared the #449 root cause, naming-by-mutation in
SimplifyFunc.rebindMeta, through a different door: a class parameter default is
evaluated inside the child's own context, so restamping the value a
simplification returned missed the parent context's memberTable. Fixed by the
issue #449 work (6fe77a0); the test pins the shape and fails with the exact
issue signature under the pre-fix code.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ejected (#445)

An `Int <> CONST` parameter in a carry op (`+^`, `-^`, `*^`) was treated as a
concrete signed 32-bit value, so `UInt[10] +^ K` yielded `SInt[33]` instead of
`UInt[11]`. The carry givens now adapt a wildcard `Int` operand (runtime
`isDFInt32`) to the bit-accurate operand's sign and width with a
`checkWildcardFit` guard: add/sub widen that operand by one bit, mul doubles
its width. Scala `Int` operands keep contributing their value's minimal width.

A carry op between two `Int` operands has no bit-accurate anchor and is now a
compile-time error via the shared `Constraints.CarryCheck` (`Check2`), also
enforced at runtime for widened types.

Docs: carry-ops wildcard rules and examples; unsized `d"$param"` documented as
a wildcard pass-through rather than an unsigned binding.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rror site (#448)

Same-named width constants in a parent and child design printed identically in
width-mismatch elaboration errors ("The argument width (OUTPUT_WIDTH) is
different than the receiver width (OUTPUT_WIDTH)"), giving no way to tell the
sides apart. Diagnostics now render a named width/length reference relative to
the error site's owner (`c.OUTPUT_WIDTH` vs `OUTPUT_WIDTH`) via a dedicated
`refErrorString`/`widthErrorString`, including design parameters, which the
code printer always names bare. Code printing (`refCodeString`) is unchanged.

Switched sites: DFBits TC and Compare, DFDecimal TC (larger/undefined), and
the DFVector length checks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`.uint` on an enum value returns its entry encoding as an unsigned integer of
the enum's width, as the type-system docs already promised. It is deliberately
a `.bits.uint` composition rather than a dedicated enum-to-uint alias: both
backends already render the chain as a direct cast (SystemVerilog `{i}`, VHDL
`unsigned(to_slv(i))`), so a new AsIs pairing would only add cases to every
cast-matrix consumer without changing the output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hs (#452)

The implicit-Int mismatch warning was silent whenever the operand widths were
parameterized (`SInt(CORDW + 1)`), exactly where hand-checking the widening is
hardest. Two independent gates suppressed it:

1. The narrow-width test read the width under the non-resolving policy, so a
   parametric width answered "unknown" and counted as not-narrow. It now
   resolves through design parameters at elaboration (applied/default value),
   and a width that still cannot resolve counts as narrow, since a false
   positive costs one carry op while a false negative is silently wrong
   hardware.
2. The `ImplicitlyFromIntTag` check saw only the operand member itself. A
   literal width folds the implicit-Int const into a single tagged const, but
   a parametric width keeps it under an untagged resize alias
   (`sd"3'2".resize(CORDW + 1)`), so the check now follows alias chains.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…written operand order (#452)

A narrow unsigned implicit-Int chain meeting a signed sibling or target escaped
the auto-carry promotion: the `.signed` sign fix wrapped the func in an alias
before the promotion match saw it, and the emitted Verilog then evaluated the
chain inside the self-determined `$signed({1'b0, ...})` concat at its narrow
operand width, truncating ahead of the sign extension. The promotion candidate
is now taken before any sign conversion (unwrapping the commutative sign
alignment's alias by its exact signature), and the conversion re-applies on the
promoted value.

Even a promoted func printed bare inside the concat still self-determines, so a
new `NamedVerilogSelection` criterion names a carry-widened unsigned func
consumed by a sign conversion; its assignment provides the widening context and
the concat sees a declared identifier. This also fixes the pre-existing
carry-bit loss of `(a +^ b).signed`.

Commutative arithmetic now preserves the written operand order: the
wildcard-LHS and wider-RHS branches convert the narrow side in place instead of
reordering wider-first (`5 + u8` prints as `d"8'5" + u8`).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…itive (#453)

Since #452 the promoted chain is emitted under the assignment target's
width context (a size cast or the assignment itself), and truncation to N
bits commutes with +/-/*, so Verilog's 32-bit evaluation agrees for every
input. Pattern 4 of the implicit-Int warning therefore reported a
divergence that can no longer occur; the other three patterns keep their
independent warning sites. The auto-carry promotion of implicit-Int chains
is now pinned in DFDecimalSpec and shown in the docs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@soronpo
soronpo merged commit 7289122 into main Aug 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant