Index interface methods and extend Type for Trait relations so call
hierarchy can show implementors as outgoing targets and .Method call
sites as incoming.
- interface I { func M } + extend T for I tracking
- prepare/outgoing/incoming with data Iface#Method
- smoke_lsp_iface_hierarchy (Drawable.Draw ↔ Circle / Render)
Add rtkMethod so .Method( call sites rename with the method decl, improve
type renames across extend/annotations, and clip self to the enclosing
method body.
- Len→Length includes self.Len(); Point→Vec2 hits extend + types
- self→this stays within one method (textual func bounds)
- smoke_lsp_rename_method + test-lsp wiring
Add tools/smoke_selfhost.sh and make test-selfhost-smoke (via make selfhost)
to the default make test suite, covering field-move ownership and per-file
#line paths under buxc2.
Stamp each merged .bux path onto decls, propagate to HirFunc, and emit
#line N \"path\" per function without requiring BUX_DEBUG_FILE.
- Decl.sourceFile + Cli_StampSourceFile on merge/project parse
- HirFunc.sourceFile; CBE switches currentFile per function
- Stdlib and multi-file user packages get distinct paths automatically
Expose LSP call hierarchy over a lightweight textual call graph of
known functions and Name( call sites across the workspace.
- prepareCallHierarchy on func decl or call site
- incomingCalls / outgoingCalls with fromRanges
- smoke_lsp_call_hierarchy + test-lsp wiring
bux-lsp 0.7 indexes struct fields and enum variants and renames only the
right binding: .member / ::Variant / field-init, without clobbering locals.
- Member scan in analyzeFile; access kinds bare/dot/colon/field-init
- classifyRenameTarget: local | member | global
- smoke_lsp_rename_deep + test-lsp wiring
Bring selfhost C backend closer to bootstrap ownership and debug quality.
- Mark locals moved into struct fields / returns (no double Drop)
- Mangle Array/Set/Map/Channel field types so user structs fully emit
- Emit #line N from HIR line; BUX_DEBUG_FILE / BUX_NO_LINE controls
Track locals moved by value into struct fields, let bindings, or return
values so Array/Drop types are not freed while still owned by the target.
- hir_lower: movedOutLocals + markMovedOutFromAst + shouldSkipDrop
- Nexus: drop zeroing workaround; free headers after each request
- examples/move_field.bux regression for Box { items: arr }
Session 36: prevent UAF when Array is moved into a struct field (Nexus
headers), align selfhost cc flags with bootstrap debug/release, and add
workspace/symbol search to bux-lsp 0.6.
- Parser: zero headers after embedding so auto-drop is a no-op
- Request_WantsKeepAlive uses RequestHeader_Get again safely
- Selfhost: default -O0 -g; --release -O2 -DNDEBUG; BUX_CFLAGS
- LSP: workspace/symbol + smoke; version 0.6.0
Reuse TCP connections for multiple requests, honor Connection close,
and raise wrk health RPS from ~45k to ~80k+ on the same machine.
- Loop HandleConnection up to 1000 reqs/fd with Connection keep-alive
- RawRequest_WantsKeepAlive (HTTP/1.1 default; HTTP/1.0 needs keep-alive)
- Nexus 0.3.0 banner; benches note before/after RPS
Add workspace-aware Find All References and Rename for scoped locals and
globals, plus registry/apps/dwarf smokes in the default test target.
- bux-lsp: textDocument/references, prepareRename, rename
- make test-lsp runs smoke_lsp_rename; make test includes registry/dwarf/apps
Ship the QUALITY_PLAN stretch from ownership through ecosystem: C.1
lifetime elision (bootstrap + selfhost), bux fmt/test/doc CI hooks,
stdlib goldens, package registry (bux search/add), and LSP 0.4
position-sensitive locals with inferred let types. Full-tree format
pass plus Map/Set remove double-free fix.
Multi-field variants use Enum_Variant_Payload nested types (avoids tag name clash).
Sema resolves data.Variant.Variant_i; enum field types fully resolve tuples.
Selfhost parses full type exprs in enum payloads; emit structs/tuples before enums.
Example: examples/nested_patterns.bux (Pair::Two, Box::Val((a,c)), Shape::Dot).
Blocks can yield a value: last expression statement is the result.
Match arms accept block bodies, so multi-statement arms work:
match n {
1 => { let a = 10; a + 1 },
_ => 0
}
Bootstrap: lowerBlock(asExpr) lifts the trailing skExpr. Selfhost: parse
{...} as ekBlock, emit __blk_N yield temps (retTypeKind -2), and treat
only non-empty strValue as match/block yield. Nested enum/struct pattern
bindings recurse in both compilers.
Example: match_block.bux. Selfhost-loop remains binary-identical.
Support destructuring in match arms:
- Tuple: (a, b) binds subject._0 / _1
- Struct: Point { x: px, y: py } and shorthand Point { x, y }
Bootstrap: matchPatternBindings for pkTuple/pkStruct; register local
tuple typedefs from function bodies. Selfhost: parse, Sema_BindPattern,
Lcx_PatternBindings with scope defines. Fix operator-overload path that
crashed when typeName was null after pattern binds.
Example: examples/struct_tuple_pat.bux. Selfhost-loop IDENTICAL.
Upgrade bux-lsp to 0.2.0 with a richer lightweight symbol index:
func signatures, typed let/var/const, struct/enum/interface/type/module.
Skip comments and strings while scanning. Hover shows markdown Bux
code fences; definition resolves in-file and across workspace .bux files;
documentSymbol provides outline. Fix responses writing to stdout (stdin
was a broken pipe). didChange refreshes symbols; diagnostics still run
via buxc on open/save.
Sessions 10–12 from QUALITY_PLAN:
- Pattern payload bindings (Some(value) => value) in bootstrap and selfhost
- Empty-param closures via || (tkPipePipe) with loop/return bodies
- Expression-form match: let x = match …; newline before arms
- f"…" string interpolation desugared to String_Concat + conversions
- Lexer preserves \{ \} for literal braces in f-strings
- Bootstrap fix: f"plain" strips the f prefix after escape processing
- Examples: pattern_matching, closure_control, match_let, string_interp
Selfhost-loop remains binary-identical; all examples and error goldens pass.
Lower match to if-else for literals, ranges, enum tags, and wildcards.
Fix bootstrap literal arms that always matched; port real arm AST/parser
and Lcx_LowerMatch to selfhost with last-expression return. Expand
pattern_matching example and add parse/use-after-move/double-mut golden
diagnostics. Selfhost-loop remains binary-identical.
Add int-specialized higher-order Iter helpers that accept fat function
pointers, plus an example using named funcs and capturing closures.
Fix selfhost C backend pointer field access and Array Push indexing.
Introduce fat function pointers (BuxFn {code, env}) so capturing closures
are heap-allocated per value in both bootstrap and selfhost. Expand
Array/Map/Set/String/Test/Result APIs, add proper tuple codegen and
error snippets with multi-char underlines, golden diagnostic tests, and
LSP diagnostics via buxc check.
- sema: range bounds now accept compatible integer types (e.g. int..uint)
instead of requiring exact type equality.
- hir_lower: derive loop variable type from the common range type.
- boko-framework: replace manual while loops with for loops in Query_Parse,
Request_Parse, Path_Match and App_Run.
- Rewrite apps/nexus with modular architecture:
Config, Http, Errors, Parser, Router, Handlers, Server, Main
- Use algebraic enums for ParseResult/FileResult/HttpError
- Thread-pool server via Channel<ConnectionTask> and spawn
- Fix C backend type ordering for generic struct instances
(Array_T, Iter_T) and algebraic enum struct payloads
- Collect Slice_T types from struct fields and enum payloads
- Fix match lowering for simple enums (direct value compare)
- Resolve match expression return type from first arm
- Infer element type for for-in over Array<UserStruct>
- Preserve generic type args in field access resolution
- Add fflush to PrintLine/Print for immediate server logs
- Add modern_features golden regression test
- Regenerate golden expected.c files
- Extend Lcx_BuildAutoDropFree to detect TypeName_Drop methods
registered by sema for extend Type for Drop impl blocks.
- Preserve existing @[Drop] attribute path and move semantics.
- Add design doc and implementation plan.
- Mark Destructors/Drop roadmap item done in selfhost.
- Export typeToTypeExpr from sema and preserve generic type args
- Derive loop variable type from collection element type in sema
- Substitute generic struct type params on field access
- Add getCollectionElementTypeExpr helper in hir_lower
- Replace placeholder collection for-in lowering
- Add Array/Iter lowering: Array_Iter_T / Iter_HasNext_T / Iter_Next_T
- Add Channel lowering: Channel_Recv_Ok_T loop
- Register loop variable in varTypeExprs before body lowering
Fixes _test_forin_stdlib, _test_forin_channel, _test_generic_trait, _test_import, _test_mono
- Preserve type args on tkNamed in resolveType
- Resolve explicit generic call return types with concrete substitutions
- Substitute method type params when looking up operator_index_get
- Skip strict arg checks for generic function calls (deferred to inference)
- Fix generic struct monomorphization when no caller substitution map exists
- Fix parameter varTypeExprs ordering so pointer params are visible in bodies
Fixes _test_drop_trait and _test_checked_index
- Add -Wl,--build-id=none to C compilation flags (removes non-deterministic build ID)
- Update Makefile selfhost-loop to strip debug info before ELF comparison
- Bootstrap compiler and selfhost compiler both deterministic
- @[Release] disables borrow checking and bounds checking in the function
- --release passes -O3 -flto to the C compiler for optimized builds
- Selfhost loop still deterministic
- Parse --target flag in Cli_Run before command dispatch
- Pass targetTriple through Cli_Build, Cli_BuildProject, Cli_RunProject
- Use clang with -target when cross-compiling, cc otherwise
- Selfhost loop: C output identical
Also fix runtime scheduler bugs:
- g_task_creating was thread-local but set on main thread and read on worker
- g_scheduler_context was global shared by all workers instead of per-thread
- Auto-drop now only triggers for user-defined types explicitly marked
with @[Drop] on the struct declaration.
- Added move tracking in C backend to skip auto-drop for variables
that have been moved (via let y = x, return x, or assignment).
- Prevents double-free when ownership is transferred.
- Selfhost bootstrap loop verified: C output is deterministic.
- lib/Drop.bux: interface Drop { func Drop(self: *Self); }
- sema.bux: define TypeName_MethodName in scope for impl block methods
so auto-drop (Lcx_BuildAutoDropFree) can find Drop implementations
via extend Type for Drop, not just @[Drop] or standalone functions
- Verified: extend Buffer for Drop auto-calls Buffer_Drop in @[Checked]
- ast.bux: add isDrop field to Decl
- parser.bux: parse @[Drop] attribute and attach to struct Decls
- hir_lower.bux: auto-drop now looks for TypeName_Drop for any type
- Test: _test_drop_user verifies Buffer_Drop is auto-called
- Auto-register func Type_Method(self: T, ...) as methods in sema.
- Add method table lookup for binary operators in sema.bux ekBinary.
- Add method table lookup for operator_index_get in sema.bux ekIndex.
- Add HIR lowering for binary operators to method calls in hir_lower.bux.
- Add HIR lowering for operator_index_get/set in hir_lower.bux.
- Set expr.refType for overloaded operators so chained ops work.
- Fix hir_lower.bux to recognize Array_int/Iter_string etc. in for-in loops
by checking Array_/Iter_ prefix outside the empty-elemTypeName branch.
- Update all golden expected.c files to include duplicate bux_bounds_check
declaration (matches actual C codegen).
- Remove duplicate Drop trait item from ROADMAP.md.
- Add lib/Slice.bux with Slice<T> generic struct
- Fix C backend to recognize Slice/Slice* as generic types
- Use var instead of let for uninitialized Slice<T> locals
- Selfhost loop passes, tests pass
In @[Checked] functions, variables of type Array<T> automatically get
a defer Array_Free_T(&var) injected at declaration site. This ensures
Array values are freed when they go out of scope, preventing leaks.
Implementation:
- HIR lowering detects Array_<T> types in skLet statements
- Generates Array_Free_T generic instance if needed
- Builds synthetic defer node: defer Array_Free_T(&var)
- Wraps let+defer in hBlock for proper statement chaining
Also adds checkedFunc flag to HirFunc and CEmitter for future use.
Mark as done:
- for x in collection iterator loops
- Trait bounds (T: Comparable)
- CTFE (compile-time const evaluation)
- Selfhost bootstrap loop (deterministic C output)
- Implicit generic type argument inference
- cli: buxc2 build now delegates to Cli_BuildProject for src/Main.bux,
enabling stdlib merging (Array_Iter, Iter_HasNext, etc. available)
- sema: set expr.refType on ekCall from function return type
(needed for for-loop type extraction from MakeArr()-style expressions)
- hir_lower: remove ekIdent restriction on collection-based for loops
- supports arbitrary expressions: for x in MakeArr() { ... }
- creates temp variable __tmp_coll_N for non-identifier iterators
- generates proper Array_T struct instances for temp variables
- Test: for x in MakeArr() sums [10,20,30] → 60
- Selfhost loop: C output IDENTICAL
- parser: extend-for only linked first 2 methods; now uses lastMethod pointer
- sema: trait bounds checking was after indirect-call early return (tyFunc path),
so Max<Circle>(...) skipped bounds check when callee had tekFunc refType.
Moved bounds check before both indirect/direct call returns.
- Negative test: Circle without Comparable impl now correctly errors.
- Selfhost loop: C output IDENTICAL.
- Fix Fmt_Format name conflict between lib/Fmt.bux and src/fmt.bux
by renaming selfhost formatter function to Fmt_FormatSource.
- Fix collection-based for-in loops to handle already-monomorphized
types like Array_int and Iter_string (typeArgCount=0 cases).
- Fix ekSizeOf and ekCast in HIR lowering to apply Lcx_SubstituteType
during generic monomorphization, so sizeof(T) and *T casts emit
correct concrete types in C output.
- Fix sema to infer stmt.refStmtType from initializer expression
when no explicit type annotation is given, ensuring C backend
emits correct pointer types for let data = ... as *T.
- Fix nested Lcx_GenerateStructInstance overwriting parent slot by
incrementing structCount BEFORE field processing
- Fix Lcx_LowerModule to skip generic structs from hm.structs (was missing
continue due to bootstrap compiler codegen limitation)
- Fix C backend to forward-declare ALL structs at top, removing second
generic-only forward declaration section that came too late
- Add empty-name guard in CBE_EmitStructDef
- Import system: parser supports ::* glob imports, sema two-pass resolution
- Add on-demand generic function/struct monomorphization in HIR lower
- Lcx_SubstituteType: substitute type params and mangle names (e.g. Array<int> -> Array_int)
- Lcx_GenerateFuncInstance: clone generic func with active substitution
- Lcx_GenerateStructInstance: create concrete struct definitions
- Detect generic calls (ekCall) and struct inits (ekStructInit)
- Parser: propagate generic type args from ident to ekStructInit node
- Fix duplicate HIR constant: hIndexPtr and hCall both had value 18,
causing index expressions to emit as comma expressions in C backend
- Implement collection-based for-in desugaring:
for x in arr { body } -> __iter = Array_Iter_T(&arr);
while Iter_HasNext_T(&__iter) { x = Iter_Next_T(&__iter); body }
Selfhost loop remains deterministic. All golden tests and examples pass.
- Parser: add parseRange for selfhost (.. / ..=)
- Sema: determine loop variable type from range bounds
- HIR Lower: desugar range for-in to while loop with counter
- Bootstrap sema: fix range-based for variable type (was unknown)
- Selfhost loop remains deterministic
- Mark capture-less closures as ✅ Done in ROADMAP
- Add closure syntax examples to LanguageRef.md Functions section
- Update PHASE8_STRATEGY.md Milestone A with closures
Implement MVP closures — anonymous functions without captures.
Syntax:
|a: int, b: int| -> int { return a + b; }
Changes:
- ast.bux + ast.nim: add ekClosure AST node
- parser.bux + parser.nim: parse |params| -> Ret { body }
- sema.bux + sema.nim: type-check closure params/body, return tyFunc
- hir_lower.bux + hir_lower.nim: generate __closure_N function + hAddrOf
- lir_c_backend.nim: fix function-pointer variable declaration (cParamDecl)
- C backend: closures compile to global functions with unique names
Test: _test_closure/src/Main.bux
- Closure as variable
- Closure passed to higher-order function
- Address of named function as function pointer
Both bootstrap and selfhost compilers build and pass the test.
Updated documentation to reflect changes from the last 2 days:
ROADMAP.md:
- Mark string interpolation, named/default params, bux fmt/test/new/init,
and basic borrow checker as ✅ Done
- Update Recommended Order (next: closures)
PHASE8_STRATEGY.md:
- Update date, achievements, and milestone statuses
- Borrow checker is now ✅ working in selfhost
- CTFE, LSP, formatter, test runner marked done where applicable
LanguageRef.md:
- Add defer, switch/case, string interpolation (f"...")
- Add &T, &mut T, own T to composite types
- Add named/default parameters and operator overloading sections
- Expand @[Checked] rules with double-mut-borrow and use-after-move
- Update keywords and operators
STRATEGY.md:
- Update date and version (0.3.0 selfhost)
- Mark 8.2 borrow checker, 8.4 CTFE, 8.7 LSP as ✅
BuildAndTest.md:
- Add bux init, bux fmt, bux test commands
- Expand test sections with golden tests and Std::Test
Line-based indentation formatter that:
- Adjusts indentation based on { } brace depth (4 spaces)
- Preserves original line structure and comments
- Skips braces inside string/char literals and // comments
- Handles } at line start and mixed brace lines
- 'bux fmt <file>' formats a single file
- 'bux fmt <dir>' formats all .bux files in directory
- Add inline movedName0..7 fields to Sema (avoids dynamic allocation issues)
- Sema_AddMoved: track variable moves from let/var init expressions
- Sema_IsMoved: check if variable was moved before use
- Sema_RemoveMoved: clear moved status on reinitialization (x = value)
- Report 'use of moved value' error for moved variable access