Skip to content

Develop - #13

Draft
MellKam wants to merge 15 commits into
mainfrom
develop
Draft

Develop#13
MellKam wants to merge 15 commits into
mainfrom
develop

Conversation

@MellKam

@MellKam MellKam commented Aug 11, 2026

Copy link
Copy Markdown
Member

No description provided.

MellKam and others added 15 commits August 11, 2026 19:57
Records the TIR-vs-MIR decision for ownership/borrow checking and the
resolved move-vs-Copy semantics, seeding the next design session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The bachelor's thesis now lives at github.com/MellKam/bachelor-thesis,
independent of the wx language project. thesis/ is gitignored here so
it can still be cloned into the same working directory for local
convenience, without any git-level coupling between the two repos.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Primitives (i8..f64, bool, char, never) were resolved via a hardcoded
string match in resolve_type_identifier, bypassing the item/DefId
system entirely - so LSP go-to-definition, hover, and find-references
never worked on them. They're now declared as `#[intrinsic] pub type X;`
items in std/main.wx: Item::TypeAlias.ty becomes an optional `body`,
ensure_signature binds a bodiless #[intrinsic] alias directly to the
matching pre-interned primitive TypeIndex, and the old string-match
shortcut is gone.

Also fixes an unrelated wx-fmt bug found along the way: impl-block
`ImplItem::Constant` never printed pub_span/attributes at all, so
`impl f32 { pub const PI }` silently lost its `pub` on format - which
had already round-tripped through the real std/main.wx and broken
~100 compiler tests via a spurious "PI is never used" warning.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Records today's session: primitives turned into real intrinsic items,
plus two bugs found but deliberately not fixed - root-level `use X::*;`
is crate-wide rather than per-file (lookup_global_symbol's ancestor-walk
conflates privacy-ancestry with import-lookup, confirmed via a multi-file
probe), and duplicate inherent-impl members for non-generic targets are
only ever caught at first use, or not at all if unused.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the `mutable: bool` flag on Type::Pointer/Slice/Array with an
Ownership::Exclusive|Shared kind: `*T` is now an exclusive pointer,
`&T` a shared read-only reference, dropping the old `*mut T`/bare-`*T`
and `[]mut T`/`[]T` spellings. Slices and arrays follow the same split
(`*[T]`/`&[T]`, `*[T; N]`/`&[T; N]`), and `.&mut` is removed — `.&`
always yields a shared reference now, with the one real call site that
needed the old mutable form (wasi_preview1_port's union-simulation
workaround) rewritten using a null-pointer offsetof idiom instead of
new syntax.

Full pipeline touched: AST grammar (new `&` sigil, slice/array
Rust-style size position), TIR Type/coercion/`as`-cast checks,
diagnostics wording, and wx-fmt's printer. std/main.wx and every `.wx`
file in the repo (doom/, examples/) are migrated, each verified with
`wx check` individually — not a blind mechanical rename, since several
call sites needed real judgment about whether a given pointer was
actually written through.

Also:
- Adds `ptr::align_up<Mem: Memory>` to std/main.wx and migrates every
  hand-rolled bump-allocator alignment formula in the repo to use it.
- Fixes two compiler bugs found while adding it: unary `^`/`-` on a
  typeset-bounded AssocTypeProjection (e.g. `Mem::Size`) crashed the
  compiler with a raw panic instead of a diagnostic, and the same
  shape failed to type-check under binary bitwise operators. Both
  fixed via one shared `is_typeset_bounded_assoc_type` check composed
  at all four operator-checking sites.
- Fixes a real bug in examples/bump_allocator: the bump allocator
  could hand out address 0, colliding with `ptr::null()` and causing
  the demo to terminate one linked-list node early.
- Refactors examples/bump_allocator's free functions into `impl Node`
  methods for readability.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ings

Two entries: the design-only session that planned the exclusive/shared
split before implementation (naming, AST/TIR shape, the .&mut removal
and null-pointer offsetof resolution, the deferred variant-item idea
for the union-simulation problem), and the implementation-session
findings around ptr::align_up — the fixed unary-panic/bitwise-binary
gap and the deferred bare-typeset-bounded-type-param gap.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nd LSP wiring

Add/Sub/Mul/Div/Rem/Neg become real #[tag]-resolved traits with #[inline]
primitive impls in std/main.wx; arithmetic and unary `-` desugar through
find_trait_impl (TIR::build_operator_dispatch), falling back to a plain
Binary/Unary node in Comptime contexts so const-folding stays untouched.
Generic (T: Add) and typeset-bounded (Mem::Size) operands defer dispatch to
monomorphization via GenericMethodCall's existing abstract-method path.

Compound assignment (`+=` etc.) is rebuilt as sugar over the same resolved
dispatch (`x = x.add(y)`) via four new TIR nodes split on resolved-now vs.
generic x plain-target vs. Place-target (Assign/CompoundAssign/
GenericCompoundAssign/CompoundStore/GenericCompoundStore), fixing a
pre-existing double-evaluation bug in arr[i()] += 1 along the way.

Also: primitives are real #[intrinsic] type-alias items (DefId, LSP
go-to-def/hover) instead of a hardcoded string match; struct/trait-impl
`pub` visibility fixes in wx-fmt; new tests covering struct (not just
primitive) operator-trait impls end-to-end through TIR/MIR/codegen+wasmtime.

Known follow-up, not fixed here: a chained-inlining flat-offset collision
in opt::builder::compute_locals_offsets causes codegen::tests::test_lerp to
trap — see devlog/2026-08-17-chained-inlining-offset-collision-investigation.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ng notes

Records the design/implementation trail for the feature commit above: the
compound-assignment node-shape design (rejected alternatives and why), the
implementation session (deferred bugs found: chained-inlining collision,
char arithmetic resolved as intentional "no impl"), the standalone
chained-inlining root-cause investigation (two fix candidates designed, not
implemented), and an unrelated pre-existing inline+intrinsic call-graph
crash found and fixed along the way.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nline] calls

compute_locals_offsets lets same-parent scopes share a flat local-offset
range, assuming they're mutually exclusive at runtime (true for if/else/match
arms, the only shape ordinary lowering produces). inline_call broke that
assumption by creating a new sibling scope per inlined call to hold its
arguments — two calls inlined at/under the same site (sibling arguments, or
separate sweeps substituting one after another) collided, silently
clobbering each other's staged values. Confirmed via wasmtime: test_lerp's
`a + (b-a)*t` traps, and calc(a,b,c,d){(a+b)+(c+d)} returned a wrong result.

Fixed by not creating that scope at all: an inlined call's parameters (and
any locals the callee declares in its own body) now get appended directly
to the caller's existing scope at the call site, so a second inlined call
there simply gets index ranges past the first's -- nothing to compare or
protect against, Vec::push can't collide with itself. The break-target
wrapper scope still exists unconditionally but never holds locals, so it's
always safe regardless of parent.

Also unified this with the pre-existing Rebaser (used by
MIR::build_start_function to combine globals' initializers) -- the old one
was a special case of the new one, removing a duplicate tree-walk. One
accepted, documented regression: opt::tests::test_simple_add now has one
extra dead SSA node per inlined call at a function's root (harmless, reused
via CSE). Verified build_start_function's globals-combining does not share
this bug (different, safe mechanism) with a new regression test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…references

Records the actual fix landed above -- a third, simpler design than either
candidate the investigation entry worked out, arrived at by questioning
whether inline_call needed a new per-call scope at all rather than how to
protect one. Also documents the accepted test_simple_add regression and the
empirical check ruling out the same bug shape in build_start_function's
globals-combining. Updated the investigation and compound-assignment
devlogs, plus the index, to stop describing this as deferred/open.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…/opt

Ported the codegen/wasm-shaped-instruction cleanup out of the
dwarf-debugging branch (which bundled it with DWARF debug-info support
we're not adopting here) — codegen's Expression/ValueType/Local/BlockResult
and opt::scheduler's near-identical Instruction/Local/ScalarType were two
independent copies of the same wasm stack-machine shape. They now share one
definition in the new wasm module, which codegen consumes for encoding and
opt::scheduler produces from the sea-of-nodes graph.

Along the way this deletes codegen's ~250-line Expression enum, which was
already entirely dead except its four *Const variants (global-init
encoding) now that function bodies lower through opt::scheduler::Instruction
instead, and switches BrTable from one Box<[u32]> heap allocation per
switch to indices into a shared br_table_depths arena.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rewrite effect-system.md to the does(...)/does(*)/does() syntax settled on
after comparing against Verse's effect system, and add
effect-tracking-plan.md laying out the MVP implementation (trap-only
EffectSet, resolution folded into existing TIR phases, trap as an
#[intrinsic] reusing the existing unreachable lowering).

Also replaces the stray examples/main.txt scratch file with main.wx, used
to sketch the syntax proposals during the design discussion.
…nary dispatch

Extends operator-overload traits to bitwise ops (BitAnd/BitOr/BitXor/Shl/
Shr/BitNot), same native-fast-path-preserving shape as the existing
arithmetic traits. Comparison operators still deferred.

Widened integer literals from i64 to u64 (ExprKind::Int/ast::Expression::Int),
fixing two real bugs this exposed: i8::MIN-class negation boundary checks
using the wrong (positive) bound, and eval_const_expr's Div/Rem folding with
signed semantics unconditionally regardless of the operand type's actual
signedness.

Enum variants now require an explicit anchor value before auto-increment is
legal (new E1071) — closes a real silent-collision bug in the old
`Ordering { Less, Equal = 0, Greater = 1 }` shape, where `Less` implicitly
got 0 too.

Added the missing Type::TypeParam branch to build_unary_operator_dispatch,
closing a generic-bound dispatch gap for Neg/BitNot that the binary
dispatcher didn't have.

Fixed two related bugs surfaced by a new Hasher/Hash example
(examples/hashing/main.wx): a trait-impl method with its own type params
(distinct from the impl block's) lost them entirely during TIR signature
building (AstNodeRef::TraitImplFunction), and, once fixed, the identical
shape crashed codegen via a MIR abstract-dispatch bug that conflated "impl
block is generic" with "impl's own copy of the method is generic."

Removed several genuinely dead code paths found along the way: an
unreachable coercion arm (confirmed via eprintln instrumentation across the
full suite), five already-unused ast::BinaryOp predicate methods, and
collapsed 9 near-identical integer-range-check branches into one lookup.

Found and documented (not yet implemented, see devlog): memory-tag positions
(Mem::&T) never check that the base is actually bounded by Memory.

762 passed / 0 failed / 4 ignored. See devlog/2026-08-18-bitwise-operators-
enum-anchor-generic-trait-bugs.md for full details.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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