julia-script / julia-script/silk
type-system: Add a nominal C-compatible union
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 48
- Forks
- 0
- Avg merge
- 4h 49m
- Merged PRs (30d)
- 213
Description
Context
Silk calls C code and reads C data structures. Many C headers declare a union, in which
every member starts at offset 0 and the structure carries no tag. Silk has no type with
that layout. A user who reads such a structure today must copy bytes by hand. This ticket
adds a nominal union type for interoperation with C.
Current behavior
Silk unions are structural and the compiler owns their layout. unionEntry in
packages/compiler/src/Layout.ts:497-530 gives every union a 32-bit tag at offset 0,
then aligns the payload after it. The size is the largest member plus the tag and the
padding.
The two layouts differ:
- A Silk structural union has a 32-bit tag at offset 0. The payload starts after the tag,
at an aligned offset. The size includes the tag. - A C union has no tag. Every member starts at offset 0. The size is the size of the
largest member, rounded up to the largest member alignment.
A user therefore cannot map a C union onto a Silk union. The offsets do not agree and the
sizes do not agree.
Requirements
- The parser must accept a nominal union declaration with a name and a list of members.
- Each member must have a name and a type, as a struct field does.
- The layout must place every member at offset 0.
- The layout must not add any tag.
- The size must equal the size of the largest member, rounded up to the alignment.
- The alignment must equal the largest member alignment.
- A read of a member must be an
unsafeoperation, because the compiler cannot know
which member holds the current value. - A write of a member must be an ordinary safe operation.
- The compiler must reject a member type that needs a drop operation.
- The compiler must reject a member type that carries a reference.
- The type must be distinct from a structural union and must not convert to one.
- The LLVM backend and the Wasm backend must agree on the layout.
Example
pub union Word {
bytes: [u8; 4]
value: u32
}
pub fn lowByte(word: &Word) -> u8 {
unsafe {
return word.bytes[counted(0)]
}
}
Out of scope
- A tagged nominal enum. #15 covers it.
- A change to the existing structural union layout.
- A bit-field member.
- An automatic import of a C header.
- A check that a read selects the member that the last write set.
Implementation note
The safety rule is the reason this type needs its own ticket. A structural union is safe
to read, because the tag states which member holds the value. A nominal union has no tag,
so a read can observe bytes that a different member wrote. The read is therefore an
unsafe operation and the user must state the invariant.
Two member restrictions follow from the same fact. A member that needs a drop operation
cannot be dropped correctly, because the compiler cannot know whether that member holds
the current value. A member that carries a reference can produce a reference from bytes
that a numeric write set, which breaks the borrow rules. Both must be rejected at the
declaration, not at the use.
The layout code must not reuse unionEntry. That function always adds the tag
(packages/compiler/src/Layout.ts:512-514). A nominal union needs a separate layout
entry with its own representation tag, so that the backends can tell the two apart.
Dependencies
None.
Acceptance criteria
- The parser accepts a
uniondeclaration and keeps the syntax tree lossless. - A layout test shows that every member has offset 0.
- A layout test shows that the size has no tag and no tag padding.
- A layout test compares one Silk union against the C layout of the same members.
- A semantic test shows that a read outside an
unsafeblock gets a diagnostic. - A semantic test shows that a member needing a drop gets a diagnostic.
- A semantic test shows that a member carrying a reference gets a diagnostic.
- An LLVM test and a Wasm test show the same size and alignment.
-
openspec/specs/bootstrap-target-layout/spec.mdgets a new layout requirement. -
openspec/specs/bootstrap-structural-unions/spec.mdgets an amendment that states
the nominal union is a separate type with no tag.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with packages/compiler/src/Layout.ts, especially unionEntry, then trace the parser, semantic checks, LLVM backend, and Wasm backend involved in union declarations. Use the requested layout and semantic tests to verify zero offsets, untagged size and alignment, unsafe reads, and rejected members. Update openspec/specs/bootstrap-target-layout/spec.md and openspec/specs/bootstrap-structural-unions/spec.md as specified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript, wasm
- Domain
- backend, compilers, documentation, testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100