Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
732 commits
Select commit Hold shift + click to select a range
21bfad5
fix: 除普通赋值外没有任何赋值目标被校验 —— 索引、map 键值、结构体字段全放行
lollipopkit Aug 5, 2026
90a50fc
fix: 存储校验漏了 Tuple 这个载体 —— 异质字面量的索引写仍然不检查
lollipopkit Aug 5, 2026
c38f847
docs: #183 的判据在容器改成不变之后不成立 —— 剩下的是载体在构造时就定了
lollipopkit Aug 5, 2026
5bed9ce
fix: 浮点常量池按 `==` 去重,`0.0` 与 `-0.0` 互相吞;LSP 墙钟断言移出正确性套
lollipopkit Aug 5, 2026
a0d0ccd
docs: format 与 println 共用的占位规矩此前只写在代码注释里 —— 补成裁决,它不是漏检
lollipopkit Aug 5, 2026
67f178a
feat: 列表字面量的载体也可以被后续 push 推翻 —— 与空 `[]` 共用同一条重试通路
lollipopkit Aug 5, 2026
8d8b4f4
feat: map 字面量的载体也接上那条重试通路 —— 与列表共用一条规则
lollipopkit Aug 5, 2026
33b5e29
fix: 没写 `use chan;` 时 `chan.new(1)` 原生跑通而 VM 报错 —— 空的 import 分支
lollipopkit Aug 5, 2026
c817e40
fix: `time.sleep(-1)` 让 VM 挂起约 5.8 亿年 —— 负数转 u64 回绕
lollipopkit Aug 5, 2026
548197d
rm: 每模块的 natives 表 —— 唯一读它的 opcode 已经删了,表本身留成了诱饵
lollipopkit Aug 6, 2026
63e89dc
docs: 卫生只写了一个方向 —— 补上"宏体里的自由标识符在调用点解析"
lollipopkit Aug 6, 2026
cb50e1e
docs: `defer` 的两处说法互相矛盾;并裁决"只可能 raise 的操作发不发 raise"
lollipopkit Aug 6, 2026
1c5be22
fix: `export fn` 的错没说人话;`lk check` 把每条语法错打两遍
lollipopkit Aug 6, 2026
d953cb9
fix: 结构体字面量里拼错的类型名被静默构造成一个值
lollipopkit Aug 6, 2026
e3e209c
fix: 只因导入而已知的类型名,裸写字面量会造出一个残缺的同名类型
lollipopkit Aug 6, 2026
ac862e0
docs: 内联提示里的 `_` 与类型 `_` 是同一个拼写 —— 记下为什么这是对的
lollipopkit Aug 6, 2026
898ae53
docs: 导入类型可构造那条的方案已查清 —— 复用 `S$new` 那条解析期糖,不需要新 opcode
lollipopkit Aug 6, 2026
892ee8a
fix: 跨文件结构体原生显示成 map —— bundler 只合并了 impl,没合并 struct 声明
lollipopkit Aug 6, 2026
29d9ab5
feat: `use { P } from "m"` 绑定生成的构造函数,裸 `P { … }` 因此建的是声明方的类型
lollipopkit Aug 6, 2026
d050db6
fix: bundler 合出来的 artifact 里 impl 指向不存在的 trait —— 三张表只并了两张
lollipopkit Aug 6, 2026
0c7d99c
fix: 墙钟断言不能待在正确性套里 —— 比值型比预算型更脆,取最小值不够
lollipopkit Aug 6, 2026
9daeec9
fix: 标量接收者上的未知方法过得了 lk check;`impl` 是唯一不被提升的声明
lollipopkit Aug 6, 2026
c65c740
feat: 顶层调用不能读到还没初始化的顶层绑定 —— 之前答 nil,静默
lollipopkit Aug 6, 2026
7f89eae
docs: 并发文档说"每个通道操作都有两种拼写",对九个里的六个是假的
lollipopkit Aug 6, 2026
7347c6a
rm: examples/ 里两个 20MB 的编译产物进了版本库,而且挡不住第三个
lollipopkit Aug 6, 2026
3a202f0
fix: 包缓存目录能被 `..` 走出去;`[package]` 的三个字段写了没人读
lollipopkit Aug 6, 2026
dbecb84
test: 宏信任列表只有正向用例 —— 编译期任意进程执行的边界从没被反向断言过
lollipopkit Aug 6, 2026
23829e3
rm: CLI 路径参数的 `..` 守卫是摆设 —— 它挡不住绝对路径,却挡住 `lk ../x.lk`
lollipopkit Aug 6, 2026
5d9bf50
feat: REPL 里一条输入失败后,下一行的报错像是第二个无关的 bug
lollipopkit Aug 6, 2026
2ee05f5
opt.: 方法名常量先进池子 —— 上限从"第 129 个方法调用"回到"256 个方法名"
lollipopkit Aug 6, 2026
3cee7e1
fix: 语句嵌套没有界 —— 200 层 `if` 让 `lk check` abort 进程,没有行号可指
lollipopkit Aug 6, 2026
079b422
fix: nesting depth had two budgets that reset at every crossing, so n…
lollipopkit Aug 6, 2026
bd22dae
fix: a callee that widens a list parameter answered differently from …
lollipopkit Aug 6, 2026
5936ccd
feat: the same carrier rule covers maps, and both container stores sh…
lollipopkit Aug 6, 2026
9763bcf
feat: a store through a boxed receiver had no lowering, so half the c…
lollipopkit Aug 6, 2026
58fcf60
docs: defer's raise behaviour was stated only in a module comment
lollipopkit Aug 6, 2026
60e926d
fix: an erased container was not a container for `in` and `+`, and `i…
lollipopkit Aug 6, 2026
fe418eb
fix: the other two container operators refused an erased operand too
lollipopkit Aug 6, 2026
a153db2
fix: an assignment in a condition was accepted and silently dropped
lollipopkit Aug 6, 2026
4277bd2
fix: a lexer error was three lines, one of them empty, with raw sourc…
lollipopkit Aug 6, 2026
ab506e1
feat: the keyword somebody arrives with from another language is named
lollipopkit Aug 6, 2026
4e7217c
fix: every position that binds a name accepted binding it twice
lollipopkit Aug 6, 2026
cb0f31d
fix: lk check passed an impl whose method signature could not stand i…
lollipopkit Aug 6, 2026
793d536
feat: a positional parameter passed by name says so
lollipopkit Aug 6, 2026
2c6b46f
fix: a trait was the one declaration kind with no duplicate or existe…
lollipopkit Aug 6, 2026
6a70f56
feat: a package dependency bundles like a file import, so it lowers n…
lollipopkit Aug 6, 2026
5cc2caf
feat: the other two package-import spellings bundle too
lollipopkit Aug 6, 2026
60cc18e
test: pin all four package-import spellings, not just the one the swe…
lollipopkit Aug 6, 2026
616e077
feat: a closure nested in a closure lowers wherever it is handed on, …
lollipopkit Aug 17, 2026
aa22ed7
rm: the protected *call* nothing has called since try became a region
lollipopkit Aug 17, 2026
8526df6
feat: a `try` region carries closures, captured variables, and other …
lollipopkit Aug 17, 2026
ff38596
feat: a captured variable keeps its type across a `try` boundary, and…
lollipopkit Aug 17, 2026
0a03e83
feat: an outlined `try` body keeps the two compile-time facts it is r…
lollipopkit Aug 17, 2026
ee4f60e
fix: two silent wrong answers a `try` region could produce, and cells…
lollipopkit Aug 17, 2026
e539d44
fix: a struct renders the way it was declared, and a field it never d…
lollipopkit Aug 17, 2026
8a07203
feat: a map iterates in the order its keys were written
lollipopkit Aug 17, 2026
daa251e
feat: a value that occupies two registers crosses a `try` boundary as…
lollipopkit Aug 17, 2026
076aaab
fix: a method on a value that might be absent unwraps first, as the i…
lollipopkit Aug 17, 2026
12362c8
feat: an int-keyed map answers `.keys()` and `.values()` natively
lollipopkit Aug 17, 2026
affa3ef
docs: a closure as a runtime value — the design, and the answer it ge…
lollipopkit Aug 17, 2026
50dfa1f
docs: the closure-value miscompile is a `ListPush` bug, and two more …
lollipopkit Aug 17, 2026
edc9b0f
docs: binding one register to both a reference and a value is the wro…
lollipopkit Aug 17, 2026
ce73ea3
fix: recording a reference clears the register's stale value, as writ…
lollipopkit Aug 17, 2026
9b48aea
fix: `fs.push(|x| x + 1)` compiled to the list pushing itself
lollipopkit Aug 17, 2026
202eb5d
feat: a closure can be a runtime value — in a list, pushed, iterated,…
lollipopkit Aug 17, 2026
a62f573
feat: a closure is also a value in a map, in a struct field, and as a…
lollipopkit Aug 17, 2026
40edb0b
feat: a callable in a map entry or a struct field is called where it …
lollipopkit Aug 17, 2026
d33d90d
feat: a closure returned from a branch is a value, so calling it lowers
lollipopkit Aug 17, 2026
f84d782
fix: a closure whose environment is all static references still needs…
lollipopkit Aug 17, 2026
ef47b68
fix: a value a set cannot hold is named, not called a Float
lollipopkit Aug 17, 2026
32a6c3f
fix: a closure is one object with however many names
lollipopkit Aug 17, 2026
cf89ba7
fix: a per-function table that grows alone renumbers every later entry
lollipopkit Aug 17, 2026
52b23f6
fix: a global slot the program writes is the program's, whatever it i…
lollipopkit Aug 17, 2026
9c29b1a
feat: a trait is a type, so a signature can say what shape it wants
lollipopkit Aug 17, 2026
31dc772
feat: a sub-pattern inside a list or map is a pattern like any other
lollipopkit Aug 17, 2026
79b5710
fix: a match arm asks a question, so it does not constrain the value
lollipopkit Aug 17, 2026
a95512f
feat: the one bitwise operator with no spelling
lollipopkit Aug 17, 2026
3b26962
feat: the bitwise operators get compound assignment too
lollipopkit Aug 17, 2026
37f13cb
feat: a field's declared type travels with its name
lollipopkit Aug 17, 2026
1625f27
feat: a loop header inherits what a value is, not only what type it has
lollipopkit Aug 17, 2026
9386767
fix: a format template hoisted out of a loop is still a constant
lollipopkit Aug 17, 2026
b632ac7
opt.: one accessor for the compile-time string a register holds
lollipopkit Aug 17, 2026
124195a
docs: the field-type narrowing buys coverage, and the measurement say…
lollipopkit Aug 18, 2026
7a4f60a
fix: a declared field type is not a runtime guarantee, so it cannot t…
lollipopkit Aug 18, 2026
2fd0d9f
feat: a declared field type is checked, so the declaration means some…
lollipopkit Aug 18, 2026
dd3824e
docs: a container's element type is not a struct field, and should no…
lollipopkit Aug 18, 2026
3cddfed
opt.: the declared-field check is decided at compile time when it can be
lollipopkit Aug 18, 2026
3f80781
opt.: a store that cannot name a declared field asks nothing at run time
lollipopkit Aug 18, 2026
a65bc93
opt.: a map literal builds into its carrier, not into a builder first
lollipopkit Aug 18, 2026
8c0e228
docs: those timings were against a debug runtime, and the honest numb…
lollipopkit Aug 18, 2026
51910da
docs: mark the field-read timings as debug-runtime numbers
lollipopkit Aug 18, 2026
7d83a14
opt.: a type that declares no field type is not scanned on every store
lollipopkit Aug 18, 2026
36dbfca
docs: where a map entry's cost actually goes, measured against an opt…
lollipopkit Aug 18, 2026
9c03b97
fix: a trait is a type across a module boundary too
lollipopkit Aug 18, 2026
95b5221
fix: a read-only method on a parameter is a read, and taint reaches t…
lollipopkit Aug 18, 2026
7c8e18d
fix: a boxed receiver's method is not a map property, and that arm ne…
lollipopkit Aug 18, 2026
16478ca
test: an ABI name the schema does not have is a lowering bug, not a p…
lollipopkit Aug 18, 2026
202af7f
fix: clear hands back the map, and a map has no remove
lollipopkit Aug 18, 2026
8a7371e
fix: a set clears to itself, and a refusal's message is the error
lollipopkit Aug 18, 2026
602f1bc
test: the method table is compared as a whole, and clear says its ans…
lollipopkit Aug 18, 2026
07771da
fix: lk check is the check the executors run, including this one
lollipopkit Aug 18, 2026
8b4713a
fix: three mistakes lk check used to let through
lollipopkit Aug 18, 2026
9c393fe
fix: a spread's base has to have fields, said where it is written
lollipopkit Aug 18, 2026
b1c4f82
fix: the generated method-surface example is fmt-clean
lollipopkit Aug 18, 2026
8974f7c
test: what lk check must refuse, and what it must not
lollipopkit Aug 18, 2026
1d8e25a
docs: the biggest try fallback is a break that belongs to the loop ou…
lollipopkit Aug 18, 2026
951d857
docs: the try-region refusal names the shape, and the example carries…
lollipopkit Aug 19, 2026
6057f4a
feat: a break out of a try says which way it left, and lowers natively
lollipopkit Aug 19, 2026
692b46b
opt.: a try body reads its own arguments, and the arity cap goes with…
lollipopkit Aug 19, 2026
96c2013
test: the fuzz counts what lowered natively, and generates a break ou…
lollipopkit Aug 19, 2026
fe6f6ad
fix: a raise taken under a live runtime borrow says so, where it happens
lollipopkit Aug 19, 2026
bef117b
fix: an optimized lk compiles try, and links the runtime it refreshed
lollipopkit Aug 19, 2026
95b5687
opt.: a channel operation stops paying for select, futex and a hash i…
lollipopkit Aug 19, 2026
4de05d5
feat: a try inside a closure can read what the closure captured
lollipopkit Aug 19, 2026
02cd89c
fix: an out-of-range read is nil everywhere it lands, not a crash
lollipopkit Aug 19, 2026
1f67d57
fix: the sentence a caught nil carries is the same on both backends
lollipopkit Aug 19, 2026
06d5302
feat: a nullable value can be built into a list, not only stored in one
lollipopkit Aug 19, 2026
2c3f30d
fix: an empty catch does not mean the body always leaves
lollipopkit Aug 19, 2026
c9f7e5e
fix: a list pattern says how many, and ..rest is how you say at least
lollipopkit Aug 19, 2026
67f35e0
fix: a parameter takes a list and a number, and the empty one is no e…
lollipopkit Aug 19, 2026
edb542d
fix: a float reads the same however it reached the string
lollipopkit Aug 19, 2026
14fd056
fix: lk check has an opinion about the operand of !
lollipopkit Aug 19, 2026
b99f5e3
fix: a closure defers on the way out, like everything else
lollipopkit Aug 19, 2026
990e4a1
opt.: the collector's share stops growing with the data it holds
lollipopkit Aug 19, 2026
b115ba6
fix: the runtime guard reaches the crate root, and the snapshot says …
lollipopkit Aug 19, 2026
cc8339a
opt.: a released burst gives its slots back, and the sweep paces itse…
lollipopkit Aug 19, 2026
3918e04
opt.: joining two strings fills one buffer instead of copying three t…
lollipopkit Aug 19, 2026
409d7f0
feat: a needle that might be nil is looked for, not refused
lollipopkit Aug 19, 2026
92a43be
fix: a parsed document keeps the order it was written in
lollipopkit Aug 19, 2026
c23b5bb
fix: lkrt compiles without std again, so the x86 kernel can link it
lollipopkit Aug 19, 2026
fe04362
fix: reading a container parameter is not writing to it
lollipopkit Aug 19, 2026
f099084
fix: a list that is reset on one path still chains on the other
lollipopkit Aug 19, 2026
f678e10
fix: a boxed list is still a list when a method asks
lollipopkit Aug 19, 2026
ff4b860
fix: a list joins by its separator however it was carried
lollipopkit Aug 19, 2026
19e067b
fix: a list is in a list when it holds the same things
lollipopkit Aug 19, 2026
428d27b
docs: the exemption is what hid the divergence
lollipopkit Aug 19, 2026
5610311
fix: counting and finding are one scan, so they cover the same carriers
lollipopkit Aug 19, 2026
d72e292
fix: a concatenation's type is the wider side, and a list takes any o…
lollipopkit Aug 19, 2026
4ccf2e7
docs: what a list operand does to the one beside it
lollipopkit Aug 19, 2026
c221a96
fix: three more names take a boxed receiver, and a gate says which do…
lollipopkit Aug 19, 2026
2af6fb3
feat: a mixed list sorts, and the order is the interpreter's
lollipopkit Aug 19, 2026
5059dff
feat: a boxed list sums and answers whether it is empty
lollipopkit Aug 19, 2026
b0614e1
fix: unboxing a list argument is one function, so zip gets it too
lollipopkit Aug 19, 2026
cc0c925
fix: joining a container to a string prints it, like every other way
lollipopkit Aug 19, 2026
77737fc
fix: a negative repeat count stops the program, compiled too
lollipopkit Aug 19, 2026
4e8a614
fix: the coverage gate checks its own probes, and two were wrong
lollipopkit Aug 19, 2026
79c2a9b
fix: to_bytes refuses in the interpreter's words, and takes a boxed list
lollipopkit Aug 19, 2026
feda269
fix: a date with no time parses compiled too
lollipopkit Aug 19, 2026
57a78e5
fix: subtraction removes one value, in all three places at once
lollipopkit Aug 19, 2026
847672e
fix: asking whether a value is in a container always has an answer
lollipopkit Aug 20, 2026
e175e34
fix: a predicate takes any value, whichever spelling asks
lollipopkit Aug 20, 2026
2ae6d3c
fix: removal dispatches on the left operand, and takes any value
lollipopkit Aug 20, 2026
3a52088
fix: reading a key of another type is a miss, and a tuple slices
lollipopkit Aug 20, 2026
307c5ac
fix: a chain too long to walk is refused, not a core dump
lollipopkit Aug 20, 2026
197fcd3
fix: a type spelling too deep to walk is refused too
lollipopkit Aug 20, 2026
20f08b3
fix: a value too deep is refused the same way by both back ends
lollipopkit Aug 20, 2026
9d0cfeb
fix: a boxed value widens the container, and a value equals itself
lollipopkit Aug 20, 2026
e7772f7
fix: a nil capture boxes, the way a nil argument always has
lollipopkit Aug 20, 2026
9db33ca
fix: a nil crosses into a try region boxed, like everything else wide
lollipopkit Aug 20, 2026
9289107
docs: the string-building constant is memcpy, and both ends are quadr…
lollipopkit Aug 20, 2026
eb49817
docs: the string constant is page faults, and three fixes did not help
lollipopkit Aug 20, 2026
20b16f9
docs: the slowest workload profiles clean, so stop looking there
lollipopkit Aug 20, 2026
b1ffdb6
docs: the native back end has the same string problem, so the fix is …
lollipopkit Aug 20, 2026
08780df
fix: a try region's return joins with the function's, and a string pl…
lollipopkit Aug 20, 2026
c929631
fix: a fold needs the method to exist, and removing a non-key answers…
lollipopkit Aug 20, 2026
7abfdd0
test: fuzz the shapes that only break when two features meet
lollipopkit Aug 20, 2026
fad9ecc
fix: nine ways to write an ordinary call that would not lower
lollipopkit Aug 20, 2026
345c901
fix: fourteen stdlib module functions that ran on the VM instead
lollipopkit Aug 20, 2026
31fe96c
fix: a map keyed by Int has no field spelled like a method name
lollipopkit Aug 20, 2026
9c5917a
fix: a map's subscript is a key, and nil and a Bool are keys
lollipopkit Aug 20, 2026
0f0d771
fix: a caught error says what the interpreter says
lollipopkit Aug 20, 2026
46f8c84
docs: the boxed map is keyed by String, and nil and a Bool are keys
lollipopkit Aug 20, 2026
27bbd77
fix: a map key of eight bytes or more looked like anything but a string
lollipopkit Aug 20, 2026
63cc307
fix: the fuzzer's native-ratio floor cried wolf at small case counts
lollipopkit Aug 20, 2026
9e483c9
fix: a map takes any key kind, and the carrier is not the program's b…
lollipopkit Aug 20, 2026
a9eb197
docs: what a generally-keyed boxed map actually costs, measured by tr…
lollipopkit Aug 20, 2026
aaaff7a
fix: clearing a container whose carrier the name does not fix
lollipopkit Aug 20, 2026
e69413c
fix: a list you cannot name the carrier of can still be mutated
lollipopkit Aug 20, 2026
1a2798c
fix: an assignment target is a chain, and the store belongs to its la…
lollipopkit Aug 20, 2026
55f4b10
fix: a user impl on a built-in type had no native path at all
lollipopkit Aug 20, 2026
6a03eca
fix: a trait implemented for a built-in type, on three sides
lollipopkit Aug 20, 2026
19b7946
fix: a window is a type you can write an impl for
lollipopkit Aug 20, 2026
69c13ad
fix: the rest of the built-in impl targets, and a test that walks the…
lollipopkit Aug 20, 2026
d3efe01
fix: a trait implemented for a built-in type, asked of all thirteen
lollipopkit Aug 20, 2026
6e86192
fix: a materialized stream is not observationally a list
lollipopkit Aug 20, 2026
64e2559
fix: a channel was equal to the integer 1
lollipopkit Aug 20, 2026
94ede9c
fix: a channel carries its own tag, so it stops being an integer
lollipopkit Aug 20, 2026
038d129
fix: a stream carries its own tag, and the tracking is gone
lollipopkit Aug 20, 2026
0c045c5
fix: a struct is not a map, and a map pattern says so
lollipopkit Aug 20, 2026
647ecc3
fix: a struct is not a map, and len/keys/in say so
lollipopkit Aug 20, 2026
14ed80d
fix: a struct is not iterable either
lollipopkit Aug 20, 2026
ea7cb5e
fix: a struct keeps its name on another thread
lollipopkit Aug 20, 2026
987c4c4
fix: every map operation checks whether it has a map
lollipopkit Aug 20, 2026
93f6adf
fix: a container literal takes its declared element type everywhere
lollipopkit Aug 20, 2026
894a58d
fix: the machine-int literal rule was split the same way
lollipopkit Aug 20, 2026
fcab00f
fix: a literal inside a literal is fresh too
lollipopkit Aug 20, 2026
ab6aac1
rm: an accessor nothing reads
lollipopkit Aug 20, 2026
59e28a1
opt.: a constant container is read, not deep-copied twice
lollipopkit Aug 20, 2026
98b3615
fix: one text, one map key
lollipopkit Aug 20, 2026
7db654a
fix: a bracket index is not a method name
lollipopkit Aug 20, 2026
94c37a7
fix: the last two readers of a member name took an index too
lollipopkit Aug 20, 2026
257bb40
opt.: a constant key is shared with the map, not copied into it
lollipopkit Aug 20, 2026
d50ef02
opt.: a field name is allocated once for the program, not once per in…
lollipopkit Aug 20, 2026
9ecaef0
opt.: reading a struct field has a fast path too
lollipopkit Aug 20, 2026
c00923a
opt.: a container behind a parameter takes the fast path too
lollipopkit Aug 20, 2026
efedd44
fix: a macro expansion is one expression where an expression is wanted
lollipopkit Aug 20, 2026
c840547
fix: a float narrowed to a width saturates to that width
lollipopkit Aug 20, 2026
f77a5fb
fix: a declared width survives a call, a container and a shift
lollipopkit Aug 20, 2026
bf984a7
fix: one table, two answers, and the width crosses all ten boundaries
lollipopkit Aug 20, 2026
5171b2b
test: one command for the gates, and it answers with a status
lollipopkit Aug 20, 2026
a68b4e8
fix: every spelling of an import checks its members
lollipopkit Aug 20, 2026
3225ab9
opt.: marking a struct is not re-checking it
lollipopkit Aug 20, 2026
81ece4c
opt.: a struct literal knows how big its map is
lollipopkit Aug 20, 2026
f3b3d72
opt.: a constant key is borrowed, not copied into every instance
lollipopkit Aug 20, 2026
5860c0d
opt.: a map literal knows its size and its keys
lollipopkit Aug 20, 2026
abbe22d
opt.: the typed string carriers borrow their constant keys too
lollipopkit Aug 21, 2026
4514622
fix: a container is never nil, and ?. lowers again
lollipopkit Aug 21, 2026
593f008
test: the gate walks the language, not the examples
lollipopkit Aug 21, 2026
51a850d
fix: a lint is advice, and the editor says so
lollipopkit Aug 21, 2026
02e2d90
fix: a task's raise belongs to its awaiter
lollipopkit Aug 21, 2026
3680d6b
test: sweep the configuration users actually get
lollipopkit Aug 21, 2026
8b9a323
fix: a struct can come back across the hybrid bridge
lollipopkit Aug 21, 2026
c045133
rm: a guard whose reason stopped being true
lollipopkit Aug 21, 2026
9789159
fix: an error names the token you typed
lollipopkit Aug 21, 2026
a856c78
fix: random is random, and a stale coherence note goes
lollipopkit Aug 21, 2026
d6f427d
rm: two refusals the compiler cannot make, and a comment on the wrong…
lollipopkit Aug 21, 2026
1fdca18
fix: the differential half of the construct table could not fail
lollipopkit Aug 21, 2026
44ddf15
opt.: two allocations on paths that exist to avoid allocating
lollipopkit Aug 21, 2026
11bf5a8
fix: a macro defined in the REPL lasted exactly one line
lollipopkit Aug 21, 2026
3c0853d
fix: a raise crossing a module boundary lost its payload
lollipopkit Aug 21, 2026
14ca4bb
fix: a raise out of a task came back as an unrelated value
lollipopkit Aug 21, 2026
95dcb55
fix: the REPL pinned an unannotated parameter to its first call
lollipopkit Aug 21, 2026
6530b6e
fix: a named parameter's default read the caller's scope
lollipopkit Aug 21, 2026
887a9a9
fix: a struct declared in the REPL lost its field order on the next line
lollipopkit Aug 21, 2026
296a433
fix: a trait's default method did not reach an impl on a later REPL i…
lollipopkit Aug 21, 2026
7752ef7
docs: name the actual blocker for a shared REPL heap
lollipopkit Aug 21, 2026
f516291
fix: an import refusal claimed the module declares no such thing
lollipopkit Aug 21, 2026
8bb66af
docs: rule out three designs for cross-module named defaults, by meas…
lollipopkit Aug 21, 2026
acb7ee2
fix: verify.sh was missing five gates CI has, and two of them failed
lollipopkit Aug 21, 2026
6233f8b
fix: a module's own export map was not a root of its own heap
lollipopkit Aug 21, 2026
545fab3
fix: the collector walked the module graph once per path into it
lollipopkit Aug 21, 2026
0c6192a
fix: a stream crossing a module boundary silently dropped its filter
lollipopkit Aug 21, 2026
2d27adf
rm: two inline caches keyed by pc across every function in the module
lollipopkit Aug 21, 2026
c82cafc
docs: measure the string-constant allocation, and leave it alone
lollipopkit Aug 21, 2026
da70251
fix: an import in the REPL brought the value and not the type
lollipopkit Aug 21, 2026
758b65c
fix: the REPL ran a statement that was still being typed
lollipopkit Aug 21, 2026
a79eed1
fix: lk check said nothing about a `let` pattern that cannot match
lollipopkit Aug 21, 2026
176f7e4
fix: an unknown method on a channel or a task waited until run time
lollipopkit Aug 21, 2026
ea17590
fix: the runtime said a defaulted named argument was required
lollipopkit Aug 21, 2026
692cb10
fix: make the full CI pipeline pass
lollipopkit Aug 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
168 changes: 152 additions & 16 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,100 @@ jobs:
- uses: Swatinem/rust-cache@v2
- name: cargo test
run: cargo test --workspace --all-features
- name: LSP latency budgets
# Wall-clock budgets, so they run alone and single-threaded. Inside
# `cargo test --workspace` they share the machine with every other test
# binary and fail on contention: `analyze(complex program)` measures
# ~1.2ms and once failed a workspace run at 11.99ms against its 10ms
# budget. They are `#[ignore]`d for that reason — see the module doc.
run: cargo test -p lk-lsp --test perf_latency_test -- --ignored --test-threads=1
- name: Compiler scaling budget
# `compiling_many_functions_stays_linear` asserts a *ratio* of two
# wall-clock measurements, which contention breaks in both directions —
# min-of-5 per side was not enough. Same treatment, same reason.
run: cargo test -p lk-core --lib -- --ignored --test-threads=1
- name: no build artifacts in the example trees
# `lk compile foo.lk` writes `foo` — extensionless, so no suffix
# pattern in `.gitignore` reaches it and `git add -A` after a compile
# takes it. Two 20MB binaries reached `main` that way, inside commits
# about unrelated things. `.gitignore` now excludes extensionless files
# under these trees; this catches a `git add -f` past it.
run: |
found=$(git ls-files examples bench | grep -v '\.' || true)
if [ -n "$found" ]; then
echo "::error::tracked files with no extension under examples/ or bench/ — build artifacts?"
echo "$found"
exit 1
fi
- name: cargo fmt
run: cargo fmt --all -- --check
- name: cargo clippy
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
- name: cargo clippy (no_std)
# `--all-features` never compiles the `no_std` side, so the code that
# only exists there — `io_bare`, the interrupt stubs, every `#[cfg(not(
# feature = "std"))]` branch, and *all* of the test code in that profile
# — was never linted. It was not clean when this step was added: a raw
# pointer dereferenced in a safe `extern "C" fn`, a doc comment on a
# macro invocation, and four test files that had never compiled without
# `std` at all. The bare-metal *build* steps below do not catch these:
# they build the lib, not `--all-targets`, and without the lint.
run: |
cargo clippy -p lk-core --no-default-features --all-targets -- -D warnings
cargo clippy -p lkrt --no-default-features --all-targets -- -D warnings
- name: zed extension check
# `ecosystem/zed-ext` is excluded from the workspace (it targets
# wasm32-wasip1), so `cargo test --workspace` never sees it. The check
# existed as a Makefile target and was never wired up here, which means
# the extension could stop compiling and nothing would say so.
run: |
rustup target add wasm32-wasip1
make zed-ext-check
- name: wasm32 smoke (L0 no_std crates + browser playground)
run: |
rustup target add wasm32-unknown-unknown
cargo build -p lk-values --target wasm32-unknown-unknown
cargo build -p lk-wasm --target wasm32-unknown-unknown
- name: every bare-metal LK program type-checks
# The two bare-metal crates are excluded from the workspace, and their
# build steps only compile the *one* program each embeds — so a `.lk`
# beside it drifted out of the type system unnoticed. Two real bugs were
# found this way on the same day: a `Float` reaching `&` in seven PCI
# driver functions, and a `u32` mask assigned to an `Int` flag in
# `uart.lk`, which the embedded path never type-checked at all.
run: |
cargo build -p lk-cli --no-default-features --features stdlib
fail=0
# Matched by prefix, not by a hand-written list: `bare-metal-native`
# was added later and `find bare-metal bare-metal-x86` does not reach it,
# so the one program in it was outside the very gate this step is.
for f in $(find . -path './bare-metal*' -name '*.lk' -not -path '*/target/*'); do
if ! ./target/debug/lk check "$f"; then
echo "::error file=$f::does not type-check"
fail=1
fi
done
exit $fail
- name: VM vs native sweep (every example and bench program)
# Between the coverage gate ("does it lower?") and the differential
# suites ("does this pinned case agree?") sits the case that has bitten
# twice: lowers fine, answers differently, and no case in the corpus has
# that shape. This runs every program in the repo through both.
#
# It lived in a `/tmp` shell loop for months, which meant it was retyped
# from memory after every reboot and its expected counts lived in a
# commit message.
run: |
cargo build -p lk-cli --features aot
SWEEP_REQUIRE="identical=78 diverged=1" bash scripts/vm_native_sweep.sh
- name: every LK source is `lk fmt` shape
# `lk fmt --check` shipped as a CI feature and no workflow ran it, so
# 36 of the repo's 97 `.lk` files were not in the shape the tool
# produces — including the ones the formatter is demonstrated on. A
# formatter nobody can run is not one.
#
# This reuses the `lk` the step above builds, so it must stay after it.
run: ./target/debug/lk fmt --check
- name: thumbv7em MCU smoke (bare + alloc L0 profiles on bare-metal ARM)
# Proves the L0 foundations cross-compile to a real Cortex-M MCU target
# (no OS, no allocator provided): lk-values is the `alloc` profile
Expand All @@ -42,7 +127,7 @@ jobs:
# The computation-only stdlib modules must cross-compile too, each
# on its own: a crate that only builds because a sibling happened to
# enable `std` for it is not actually no_std.
for m in bytes encoding hash iter math slice string; do
for m in bytes encoding hash iter math string; do
cargo build -p "lk-stdlib-$m" --no-default-features --target thumbv7em-none-eabi
done
cargo build -p lk-stdlib-bare --target thumbv7em-none-eabi
Expand Down Expand Up @@ -199,7 +284,13 @@ jobs:
# says the font renderer drew. The '...' are timer interrupts handled
# by an LK function — three in a row, where one could be a fluke.
for expected in \
"display at pci slot" \
# `SS.F`, not a slot number: enumeration walks functions as well as
# devices, so what identifies the display is its (bus, device,
# function) address. This line said "slot" for as long as the x86
# step could not get past *building* the kernel — an assertion that
# never runs is not a gate, and this one went stale unnoticed
# because upstream failures kept it from ever being reached.
"display at pci 2.0" \
"framebuffer 0xfd000000" \
"half 44" \
"pixels 00001428 00ffc040" \
Expand All @@ -224,13 +315,15 @@ jobs:
echo "::error::the exception reporter did not report the faulting address"
exit 1
}
# Each `check_*.py` builds and objcopies its own image (`kernel.py`) —
# this used to do it for all of them, which meant the fault-probe
# build above had to be undone here before anything else ran, and
# nothing said so. A check that boots whatever is on disk is not a
# check: see `kernel.py` for the two ways that lied.
#
# Reading the framebuffer back proves the writes reached the device's
# memory; it does not prove the mode was set, because an unconfigured
# card still accepts them. Only what QEMU scans out shows that.
LK_BIN=../target/debug/lk cargo build --release
llvm-objcopy -O elf32-i386 \
target/x86_64-unknown-none/release/lk-bare-metal-x86 \
target/x86_64-unknown-none/release/lk-bare-metal-x86.multiboot
timeout 120 python3 check_screen.py
# The input half, end to end: `sendkey` puts real scancodes into the
# emulated PS/2 controller, the LK handler decodes them into a line,
Expand Down Expand Up @@ -275,6 +368,10 @@ jobs:
# looked up by name. The board supplies stacks and the switch; which
# code runs on them is no longer in `src/tasks.rs` at all.
timeout 300 python3 check_spawn.py
# Ring 3. The program prints through a syscall and is then refused a
# write to kernel memory — the boundary becoming a property of the
# machine rather than of the program's good manners.
timeout 300 python3 check_user.py
env:
LK_BIN: ../target/debug/lk
- name: AOT native-lowering coverage gate
Expand All @@ -284,18 +381,57 @@ jobs:
# pinned off, no fallback) is the only thing that catches it. Add a
# file to AOT_COVERAGE_ALLOW if it legitimately cannot lower.
run: |
cargo build -p lk-cli --features aot
# 48/51. The three allowed files are the try/catch corpus: `try`/`catch`
# became a real statement (`Stmt::Try` → `TryBegin`/`TryEnd`) to fix
# three silent wrong answers on the VM path, and the MIR lowering has no
# handler-region support yet, so they degrade to the Tier 0 VM bundle.
# Output stays VM-identical (see `try_catch_differential` in
# cli/tests/clif_differential_test.rs); what lapses is *native*
# lowering. Drop these entries when the region outlining lands —
# see todos.md.
# The script builds the compiler it scans with — a stale binary would
# report full coverage for code it does not contain, and unlike a
# missing one that failure is silent.
#
# 76/76, and no allow list. The try/catch corpus was the last thing
# on it; each of the three came off by a different fix, and each was
# checked by *running* it against the VM rather than by the fact that
# it compiled — see `aot/lower/src/try_region.rs`, where the two
# answers that compiled and computed the wrong thing are also
# recorded.
#
# An example that legitimately cannot lower goes back on this list
# with a rationale. It is empty now, which means a regression has
# nowhere to hide.
AOT_COVERAGE_REQUIRE_FULL=1 \
AOT_COVERAGE_ALLOW=examples/syntax/try_catch.lk,examples/syntax/error_unwrap.lk,examples/syntax/error_model_edges.lk \
bash scripts/aot_coverage.sh
- name: the same gate against an *optimized* compiler
# Every gate above builds `lk` unoptimized, and the `lk` people install
# is not that one. The difference is not academic: `debug_assert_eq!`
# discards its whole expression in a release build, and one of them held
# the call that grows the signature tables for a `try` body — so an
# optimized `lk` panicked on *every* program containing `try`, in every
# build ever shipped, while the debug build this file exercised was
# fine. Overflow checks and `debug_assert` are the two things a profile
# switch changes silently; this step is what notices.
#
# Release rather than dist: dist adds full LTO for a perf number nothing
# here measures, and costs several minutes for it. The profile
# difference that matters (`debug_assertions` off, optimizations on) is
# the same either way.
run: |
cargo build --release -p lk-cli --features aot
LK_BIN=./target/release/lk \
AOT_COVERAGE_REQUIRE_FULL=1 \
bash scripts/aot_coverage.sh
# And that it *runs*: compiling is not the property that broke the
# second time. An optimized `lk` links the lkrt archive sitting beside
# it, while the refresh that keeps that archive current used to build
# the debug one unconditionally — so a release `lk` linked whatever
# was last left there. The first `try` program it compiled died on
# `SIGILL` against a trampoline from a different day.
for f in examples/syntax/try_catch.lk examples/general/concurrency_demo.lk; do
LK_FORCE_VM=1 ./target/release/lk "$f" > /tmp/vm.txt
LK_AOT_HYBRID=0 LK_AOT_NO_FALLBACK=1 \
./target/release/lk compile "$f" --output /tmp/opt_native
/tmp/opt_native > /tmp/native.txt
diff /tmp/vm.txt /tmp/native.txt || {
echo "::error::$f differs between the VM and an optimized native build"
exit 1
}
done
- name: strict native-only differential (no Tier 0 fallback)
# Complements the scan above: the corpora must not just *compile*
# native, they must produce VM-identical output while pinned to the
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/correctness.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
# `lk compile` builds this on demand inside a test's per-case timeout —
# prebuild it so timeouts measure the compile itself, not a cold cargo.
- name: prebuild the lk-api staticlib
run: cargo build -p lk-api --features ffi --release
run: cargo build -p lk-api-cabi --release
- name: cargo test under LK_GC_STRESS
run: LK_GC_STRESS=1 cargo test -p lk-core -p lk-stdlib -p lk-cli

Expand All @@ -60,7 +60,7 @@ jobs:
with:
cache-on-failure: true
- name: prebuild the lk-api staticlib
run: cargo build -p lk-api --features ffi --release
run: cargo build -p lk-api-cabi --release
- name: hand-written differential cases
run: LK_NATIVE_SANITIZE=address,undefined cargo test -p lk-cli --test aot_differential_test
- name: examples corpus differential
Expand Down Expand Up @@ -89,7 +89,7 @@ jobs:
with:
cache-on-failure: true
- name: prebuild the lk-api staticlib
run: cargo build -p lk-api --features ffi --release
run: cargo build -p lk-api-cabi --release
- name: build ASan lkrt
run: bash scripts/build_lkrt_asan.sh
- name: differential suites against the instrumented lkrt
Expand All @@ -111,7 +111,7 @@ jobs:
with:
cache-on-failure: true
- name: prebuild the lk-api staticlib
run: cargo build -p lk-api --features ffi --release
run: cargo build -p lk-api-cabi --release
- name: fuzz with the run id as seed (printed for reproduction)
run: LK_FUZZ_SEED=${{ github.run_id }} LK_FUZZ_CASES=500 cargo test -p lk-cli --test aot_fuzz_differential_test -- --nocapture
- name: artifact decoder/verifier fuzz with the run id as seed
Expand Down
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@ website/dist/
website/src/wasm/pkg/.gitignore

lk-lsp-debug.log

# `lk compile foo.lk` writes the executable as `foo` — no extension, so no
# suffix pattern reaches it. Two 20MB binaries got committed this way
# (`examples/syntax/{closure,struct_trait}`, in commits about unrelated
# things), because running the compiler on an example dirties the tree and
# `git add -A` then takes it.
#
# Every file the repository actually tracks under these two trees has an
# extension, so "no dot" *is* the compiled-artifact shape here. The
# directories have to be re-included first: git cannot re-include a file
# whose parent directory is excluded.
examples/**/*
!examples/**/
!examples/**/*.*
bench/**/*
!bench/**/
!bench/**/*.*
main

lua-5.5.0/
__pycache__/
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
{}
{
"lk.lsp.inlayHints.parameters.enabled": false
}
Loading
Loading