Skip to content

Report IsComplete() true for a division-by-zero $size_in_bytes#275

Open
AaronWebster wants to merge 1 commit into
emboss/divmod-undefinedfrom
emboss/divmod-iscomplete
Open

Report IsComplete() true for a division-by-zero $size_in_bytes#275
AaronWebster wants to merge 1 commit into
emboss/divmod-undefinedfrom
emboss/divmod-iscomplete

Conversation

@AaronWebster

@AaronWebster AaronWebster commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Part 3 of 3 of the integer division/modulus series.

Stacked on #274 (base branch: emboss/divmod-undefined). Review/merge #273
and #274 first; the base retargets automatically as the chain merges. The diff
below is only this phase's changes.

A structure whose intrinsic size divides by zero has an undefined size: it can
never be Ok(), so per the design doc
(doc/design_docs/division_and_modulus.md, "IsComplete()") it should report
IsComplete() == true -- there is nothing more to wait for -- to distinguish it
from a structure that is merely a few bytes short.

What this does

To carry that distinction, Maybe<T> gains an Unknowability reason
(kKnown / kUnreadable / kUndefined) explaining why a value is un-Known.
A default-constructed Maybe is kUnreadable (the common absent/short-field
case, so most sites need no change); a // 0 or % 0 at runtime is the sole
source of kUndefined. The expression operators in emboss_arithmetic.h thread
and merge the reason, with operation-dependent precedence:

  • arithmetic (MaybeDo/Sum/Product/Maximum/comparisons): kUndefined
    dominates -- an undefined input can never be fixed by more bytes;
  • short-circuiting And/Or: kUnreadable dominates -- an unreadable
    operand could still resolve the whole expression with more bytes;
  • Choice: propagates the condition's reason, or the taken branch's;
  • ///%: a Known() zero divisor is kUndefined, else propagates.

Generated views gain Maybe<bool> IsUndefined() (on both the dynamic and
constant virtual-field views), and IsComplete() returns true when
IntrinsicSizeIn*().IsUndefined(). Net effect for a /0 size: Ok() false,
IsComplete() true, IsUndefined() true; a truncated buffer (defined but
unreadable size) still reports IsComplete() false -- the crux distinction.

The reason is a uint8_t enum kept fully constexpr to avoid disturbing the
size-sensitive Ok() path. All C++ goldens regenerate (the shared Maybe<T>
and virtual-view templates changed); the changes are uniform
IsComplete/IsUndefined plumbing. Adds Maybe reason tests, an
emboss_arithmetic reason-merge matrix, and IsComplete/IsUndefined integration
assertions (including the unreadable-vs-undefined case).

bazel test //... is green under both gcc and clang.


PR chain (merge in order): #273#274#275 (this)

Phase C of the `//`/`%` rework.  A structure whose intrinsic size divides
by zero has an *undefined* size: it can never be `Ok()`, so per the design
doc (doc/design_docs/division_and_modulus.md, "IsComplete()") it should
report `IsComplete() == true` -- there is nothing more to wait for -- to
distinguish it from a structure that is merely short a few bytes.

To carry that distinction, `Maybe<T>` gains an `Unknowability` reason
(kKnown / kUnreadable / kUndefined) explaining *why* a value is un-Known.
A default-constructed `Maybe` is kUnreadable (the common absent/short-field
case, so most sites need no change); a `// 0` or `% 0` at runtime is the
sole source of kUndefined.  The expression operators in emboss_arithmetic.h
thread and merge the reason, with operation-dependent precedence:

  * arithmetic (MaybeDo/Sum/Product/Maximum/comparisons): kUndefined
    dominates -- an undefined input can never be fixed by more bytes;
  * short-circuiting And/Or: kUnreadable dominates -- an unreadable operand
    could still resolve the whole expression with more bytes;
  * Choice: propagates the condition's reason, or the taken branch's;
  * `//`/`%`: a Known() zero divisor is kUndefined, else propagates.

Generated views gain `Maybe<bool> IsUndefined()` (on both the dynamic and
constant virtual-field views), and `IsComplete()` returns true when
`IntrinsicSizeIn*().IsUndefined()`.  Net effect for a `/0` size: `Ok()`
false, `IsComplete()` true, `IsUndefined()` true.

The reason is a `uint8_t` enum kept fully constexpr to avoid disturbing the
size-sensitive `Ok()` path.  All C++ goldens regenerate (the shared
`Maybe<T>` and virtual-view templates changed); the changes are uniform
IsComplete/IsUndefined plumbing.  Adds Maybe reason tests, an
emboss_arithmetic reason-merge matrix, and IsComplete/IsUndefined
integration assertions (including the unreadable-vs-undefined case).
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