Skip to content

(Basic) Classes! - #26

Merged
deviaze merged 102 commits into
masterfrom
classes-version-1
Sep 28, 2026
Merged

deviaze merged 102 commits into
masterfrom
classes-version-1

Conversation

@deviaze

@deviaze deviaze commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Rendered

Designs and implements classes with public, private, static, const, __init, but no inheritance yet.

Uh, also adds Rust project setup and Cargo.toml so we can build this project with Cargo if we want.

Edit: We've decided against inheritance

@deviaze deviaze linked an issue Aug 12, 2026 that may be closed by this pull request
…ion trust (behavior changing in o2) to new fflag DebugLuwuCompilerTrustsTypeAnnotations instead of being on with classes by default
The fallback in `ConstraintGenerator::check(AstExprGlobal)` that answers a
global read through a control-flow phi with its scope binding was meant for
classes referenced past an `if`, but applied to every global. A type
function calling itself inside a loop reads its own name through the loop's
phi, got its own still-unsolved type back, and every call made with the
result failed with "outstanding free or blocked type in function call".
Definition files using that pattern failed to load in luwu-lsp, which
always enables classes.

Track the names bound by class declarations and take the fallback only for
those.
Size each table's attached props by entries, not properties. A property
with different read and write types attaches two entries, so upstream's
one-per-property sizing wrote past the allocation, corrupting whatever
the arena put next (`{ read x: number, write x: string }` under
`luau-analyze --annotate` asserts "Unknown AstType" in upstream's debug
build). Still present upstream.

Follow a function's generics before reading them, backported from
upstream 0.736: a generalized function's generic list can hold a
bound type, which asserted, and crashed release builds on plain
metatable OOP code under --annotate.
Luwu stops sharing upstream's bytecode version counter. The compiler now
writes a 0xff magic byte, a Luwu version (1, or the WIP version 200 while
DebugLuauUserDefinedClasses is on) and the types version, always in the
v12 layout. Version bytes 3..12 still load as legacy upstream bytecode.

The loader parses the header once into named features and gates on
those, with no raw version comparisons. Upstream-only versions (13, 14,
100, anything newer) and Luwu versions newer than the VM are refused by
name. Legacy blobs are scanned at load for opcodes, fastcall builtin ids,
type tags and class shapes Luwu never emitted under legacy numbering;
Luwu blobs skip the scan.

Removes LuauBytecodeCostModel and LuauCostModel, which nothing read any
more, and makes BytecodeGraph read the feedback count and inlining cost
unconditionally to match the writer.
…degen

Fixes from the classes-version-1 review:

- VM: GC barriers when filling object fields across __index calls; the
  constructor's debug name is kept alive by the constructor; luaR_newclass
  is OOM-safe; the POD constructor reads with its caller's access; const
  fields are writable only by __init on its own self; __init can't be read
  by name for any class; Point(nil) is Point(); member slots above 255 are
  never cached.
- Parser: a class method's self is const; the named const-binding error
  no longer depends on LuauExportValueSyntax; PrettyPrinter round-trips
  class generics, defaults and parameter access.
- Compiler: classes used before their declaration are checked; recursive
  primary-constructor defaults fall back to __init; construction order
  matches __init; private access can't leak through call-site defaults,
  cross-class inlining or POD constructions; only fused asserts prove a
  receiver, and a returning assert is rechecked; closures and upvalue
  reads in default arguments compile.
- CodeGen: a64 fallback spills, scratch registers reserved before
  rejoining branches, native const-write auth matches the VM, compiler
  invariants asserted, and a local keeps a refined type only when every
  write to it agrees.
- Analysis: private checks compare modules, Class.method(obj) is typed,
  recursive generic classes report instead of becoming error types,
  reading __init is an error, LocalShadow reports locals shadowing a class.
- Tests: ClassesFuzz runs under the Makefile and fails without seal unless
  LUWU_SKIP_CLASSES_FUZZ is set; vacuous tests now reach their paths.

Known failing: ClassConstructionHintSkipsWrittenLocals (a type-hint test).
…n failing since we aren't luau-lang/luau, rm pet cmake file
…st from using poisoned memory (test bug not src bug)
@deviaze
deviaze marked this pull request as ready for review September 27, 2026 23:23
@deviaze
deviaze merged commit 01c9411 into master Sep 28, 2026
10 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.

Classes!

2 participants