Skip to content

WIP Struct - #1634

Draft
sbrantq wants to merge 8 commits into
mainfrom
structs
Draft

WIP Struct#1634
sbrantq wants to merge 8 commits into
mainfrom
structs

Conversation

@sbrantq

@sbrantq sbrantq commented Jul 27, 2026

Copy link
Copy Markdown

No description provided.

@sbrantq
sbrantq force-pushed the structs branch 5 times, most recently from 573a322 to 31559fb Compare July 31, 2026 01:55
sbrantq added 8 commits July 30, 2026 20:59
Type identity is the ordered sequence of slot representations, so slots
may have different types; contrast array-representation, whose identity
is (element type, length). Like array types, tuple types are synthesized
on demand by get-representation rather than registered by a platform, so
their names round-trip.

The two representations stay separate: tuples get their own struct, their
own constructor and their own clause in repr->prop, beside the array ones
rather than merged with them.
Each function that special-cases arrays gains an independent tuple
clause: repr-ulps, midpoint, random-generate, real->repr, repr->real and
the JSON conversions in float.rkt, and the four Rival flattening walkers
in core/arrays.rkt. Tuple clauses recurse per slot with that slot's own
representation; array clauses are carried over verbatim.

float.rkt is purely additive. In arrays.rkt three walkers change from if
to cond so the two clauses can sit side by side, and three aggregate
guards gain a tuple disjunct after the array one; the array bodies
themselves are unchanged, so deleting arrays later means deleting one
clause per walker.

Because flattening already returns one representation per scalar leaf,
and make-discretizations already builds one discretization per leaf, a
mixed-precision tuple core gets per-slot ground truth with no change to
the Rival shim.
Registers tuple as a real operator and adds tuple clauses alongside the
array ones in the syntax checker, the type checker and check-spec!'s
inference, in the same style and shape.

Unlike array, tuple slot types need not agree, and ref over a tuple is
typed by its literal index. A tuple type is compatible with any scalar
ambient :precision, since its identity already records every slot's
precision.

An argument annotation may name a tuple type in :precision. Rather than
teach the shared property validator a tuple mode, strip-tuple-precision
validates and removes such a prop at the one call site that allows it, so
core-level and expression-level :precision still reject tuple types.
A platform cannot enumerate one impl per sequence of slot types, and
which sequences occur is chosen by the program. So the constructor and
the per-slot accessors are synthesized the first time a shape is used,
the same way get-representation already synthesizes the type, and
registered into the active platform with costs taken from the platform's
own per-representation move costs.

fpcore->prog gets a tuple clause beside its existing neg, cast and ref
clauses, so the general impl resolver is left alone. Generated shapes
ride the existing platform-extensions list, ahead of the fpcore
extensions, so they survive the platform re-activation that sandbox.rkt
performs before every run; without that an already-lowered program would
name a dead impl.

Accessors are unary with the index baked into the impl, because the index
determines the output type and so cannot be resolved by get-fpcore-impl
on input types alone.
A tuple has as many slots as it was written with, so operator-info's
single fixed signature cannot describe it. Three places pair a spec
application's arguments with their types: egg-parsed->expr, rebuild-enode
and add-enode. Asked about a tuple, they would see a two-element
signature and drop every slot past the second.

spec-itypes reports the argument types at the arity the term actually
has. It is local to this file, and only tuple is special-cased: every
other operator, array included, is still reported exactly as
operator-info reports it, so array terms behave as before, truncation
and all.

all-reprs/types lists the tuple spec type beside the array one it
already hardcodes, or extraction dies in split-untyped-eclasses, whose
type->idx lookup has no failure thunk.
alt->fpcore picked the core's :precision with array-representation-base,
which returns a tuple representation unchanged, so an improved tuple core
came back with :precision (tuple binary64 binary64) and could not be read
back in. It now goes through repr->prop, which descends to a scalar for
every representation; on arrays the two agree exactly, including nested
arrays.

render-fpcore gains a tuple clause beside its array one, so a tuple-typed
argument prints its full structural type, which is the only thing that
identifies it.
Mirrors the array tests for type identity (per-slot and structural),
distance, midpoint, sampling, real conversions, type checking,
desugaring, and the platform-state round trip, including shapes of three
slots.
Seven cores covering construction, the accessor, a tuple-typed argument,
a three-slot tuple sharing one expensive subexpression, a multi-output
rewrite target, and one mixed-precision pair whose type is
(tuple binary32 binary64).
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