版本與變更
Teyru 的版本:0.4.0 是正確性版本——改了什麼、量到什麼、還沒實作什麼,以及這一版刻意不宣稱什麼。
這一頁描述 0.4.0:這個專案第一個以「正確性」為主題的版本。它處理的是外部審查與實測 找出來的一批問題(計畫的 W1–W12),不是速度——速度是下一個階段的事。
這一頁在 0.4.0 發佈前寫成,所以每一項都標了狀態:已合入 main 的項目就是讀者現在裝得到 的行為;其餘的附上 PR 或工作項。還沒收尾的只有 §3 與 §5 明列的那幾項。
這一版的關卡第一次真的跑起來。 .github/workflows/release.yml 是這個倉庫唯一的
工作流程,只在有 release 發佈時跑,而 0.4.0 是第一次有 release 讓它跑:它在 tag 上
建置、跑整套測試、把執行檔附上 release,並依序呼叫六個檢查——make build、make ci、
make java-compat、make jdk-diff、make backend-matrix、make notices。這一頁引用的
數字就是那些指令在同一個 tag 上的輸出,每一列都註明它是怎麼量的。
同一串檢查在 3cd9c70(v0.4.0 的 tag)上先由人跑過一次,四條腿全綠——說「人跑過」而不是
「CI 通過」,因為工作流程是 tag 之後才跑的,而且它的首跑還在進行中。四行照抄 make ci 自己的
輸出,不改數字:notices 與樹一致、預設編譯器那一條 ok 801.427s、gcc 那一條 ok 931.287s、
JDK differential PASS(ok 284.091s),整體 EXIT=0。
但這四行是「手跑綠」,不是「工作流綠」——這一版兩者不是同一件事。 工作流程在同一棵樹
3cd9c70 上的首跑失敗在兩支時區測試(TestPrograms/t189_timezone_lookup、
t190_timezone_tzif):負 DST 的時區(Europe/Dublin 的標準時間是 +01、冬天是 GMT 而
isdst=1;Africa/Casablanca 同理)在這台主機上綠、在 runner 較新的 宿主 tzdata 上紅——
差別不在程式碼,而在宿主 tzdata 的建構佈局:vanguard(本機)與 rearguard(Debian/Ubuntu)
對愛爾蘭給出相同的 offset 與縮寫、相反的 isdst,所以錯的是測試,不是讀取程式——沒有
任何一個固定的期望值能同時滿足兩種佈局。修法是讓測試自己帶資料(t189/t190),
lib/46_timezone.teyru 一行未改;這件事走 v0.4.1,而它的說明會寫成「套件以前會因為
機器的 tzdata 佈局而過或不過」,不是「修好了一個時區缺陷」。
1. 改了什麼
測試基礎設施與 JDK 差分(W1、W2,已合入 main)
- JDK 差分測試:
teyru emit-java把 Teyru 的 AST 印成等價的 Java(補分號、for標頭 換回分號、val換成final var、java.*與標準程式庫對照),翻譯不了的 Teyru 專屬特性 以TY-INT-0102具名拒絕並說明原因。TEYRU_JDK=<JDK 21>時go test會編譯並執行那些 程式、比對 stdout 與結束狀態;期望值是真的 JDK 跑出來的,不是手寫的。 - 已知失敗清單:
tests/known-failures.txt一行一個<案例> <工作項> <原因>;列出的案例 失敗不算失敗,列出卻通過才會讓整次跑失敗,所以條目不會活得比它描述的 bug 久。 與 JDK 的差異另外由tests/jdk-diff-allow.txt決定接受,平台差異由.skip檔決定。 - 兩個診斷開關:
TEYRU_GC_STRESS=N(每 N 次配置強制收集一次)、TEYRU_GCTRACE=1(每次收集印出觸發原因、停頓時間與前後堆積大小)。 make ci/make jdk-diff/make notices:一次 CI job 會跑的東西,在這裡由人跑;這個 倉庫只有一個 workflow(.github/workflows/release.yml),在發佈 release 時呼叫它們。- 一條流程規則,因為它真的發生過:測試比它要驗的程式碼先推上 main,會讓整道關卡在一個
小時後變紅(
t196_string_bytes與t180_http_gzip就是這樣)。規則現在寫在測試倉庫的README.md:先推的測試必須在同一個提交裡帶一條known-failures.txt條目,程式碼到了再 把條目刪掉。
HTTP 伺服器加固(W3,已合入 main)
一台伺服器現在是「一條執行緒 accept、一串 cached 工作執行緒回答」,並發有三個上限(工作
執行緒 64、等待佇列 100、WebSocket 工作階段 256),超過的連線得到 503 而不是把伺服器拖住。
請求行、標頭、標頭數與主體都有上限(414/431/413),逾時是總時長而不是單次讀取;
解析器對 RFC 9112 的不一致(Content-Length 與 Transfer-Encoding 同時出現、多個不一致的
長度、obs-fold、冒號前空白、非十六進位的 chunk…)一律拒絕並關閉連線;WebSocket 的協議上限
是 1002/1007/1009/1001。全部十三個設定鍵——十二個 server.teyru.*,加上 Spring Boot
自己的 server.max-http-request-header-size——與預設值見
docs/framework.md 的〈並發模型〉與〈客戶端的限制〉。
證據是那兩個外部重現腳本在修好後得到的相反結果:慢速用戶端(一條連線每 4 秒送 1 個位元組)
連著時,另一個用戶端連續 5 次請求全部 200(修正前 5 次全部逾時);一個
Content-Length: 1000000000 的請求讓 RSS 成長 36 kB(修正前 983 MB)。測試是
t220(位元組主體)、t221(上限與嚴格性)、t222(解析器 fuzz)、t223(慢速用戶端與
100 個並行客戶端)、t224(WebSocket 關閉碼)、t225(serve()/close())。
這一版不宣稱兩件事。 伺服器的每一個等待都以 250 毫秒為上限,所以「沒有任何服務
執行緒會阻塞超過 250 毫秒」是被證明的(t223);「一條阻塞在 recv() 的執行緒不會拖住
停止世界收集」是執行期的性質(internal/runtime/src),文件把它寫成上限而不是修好的性質。
而計畫裡「64 條閒置 keep-alive 連線不影響停頓時間」那一條驗收沒有量測支撐(它需要
TEYRU_GCTRACE 的數據),所以這一頁不引用它。
遞迴過深是 StackOverflowError,不是行程死亡(W4,已合入 main)
每個產生的函式開頭拿自己的框架位址跟執行緒的 ty_stack_limit(堆疊底端加 256 KB)比一次,
低於就丟出該執行緒預先配置的 StackOverflowError——可攔截,執行緒與行程繼續跑;原生程式碼
真的把堆疊寫壞時由 sigaltstack 上的 SIGSEGV 處理器印出訊息後 abort()(不做 longjmp)。
在伺服器裡,處理函式的深遞迴是那一個請求得到 500,伺服器繼續服務下一個。代價是量到的:
每個函式多一次檢查,bench_fib 長跑因此回退約 32%(owner 已裁決接受)。
字串與 Unicode(W5,已合入 main)
字串的索引語意現在是 Java 的。 length/charAt/substring/indexOf/compareTo/
hashCode、codePoint 家族、toCharArray/getChars/chars/codePoints,以及
char[] 與 int[] 建構子,全部以 UTF-16 code unit 計算;儲存仍是 WTF-8(ASCII 走快速
路徑、麵包屑表首次用到才建,非法位元組以 U+FFFD 取代、沒有夥伴的代理以 ? 編出)。
讀者最常踩到的三件事:substring 可以切開一對代理(那是 Java 的語意,不是缺陷)、
hashCode 是 JDK 的,所以 HashMap<String, …> 走的是 JDK 的順序。計畫裡「改用 JDK 式
compact strings」那個備案由量測結案:與位元組索引的版本相比 bench_string 0.994×、
bench_string_cjk 0.949×,都在 10% 預算內,所以不換。
Character 與大小寫映射改用 Unicode 15.0,資料是入庫的產生查表(產生器
internal/tools/genunicode,make unicode-tables 重跑;重跑不會改動任何檔案):
isLetter/isDigit/isAlphabetic/isWhitespace/isSpaceChar/getType/digit/
getNumericValue/代理判斷/toCodePoint/charCount;完整大小寫映射(ß → SS、
希臘語詞尾 sigma);strip/isBlank 走 Character.isWhitespace,所以 U+3000 會被去掉,
而 trim 仍然只認 ≤ U+0020;parseInt/parseLong 收全角與其他 Nd 數字
(Integer.parseInt("123") 是 123)。StringBuilder/StringBuffer 與 Java 一致,
包括 delete(start,end) 的夾取與 replace 的 NullPointerException。
兩件要說出來而不是埋起來的事。 詞尾 sigma 的「詞」判定是這個執行期自己的:對 JDK 量過
8,000 個產生的字串與每個測到的形狀都一致,AGENTS.md §10 記下那一個已知不同的形狀。
locale 相關的映射(tr、az、lt)沒有實作。
這一項留下了兩條與 JDK 的差異(都是刻意的,寫在
docs/language.md §12):regex 引擎逐 code unit 比對,所以
"😀a".matches(".a") 在這裡是 false(JDK 的 . 吃一個 code point,是 true);
String.offsetByCodePoints 走出兩端時丟 StringIndexOutOfBoundsException(JDK 丟
IndexOutOfBoundsException;前者是後者的子類別,所以 catch (IndexOutOfBoundsException)
仍然攔得到)。
我怎麼驗的。 在 adf58e7(tests 指標 10ef6b2)上,同一支程式寫兩次——.teyru 與
Java——用 OpenJDK 21 跑再逐行比對:寫的那一半 32 項逐位元組相同;讀的那一半 41 項裡
39 項相同,其餘兩項就是上面那兩條已聲明的差異(ß→SS、詞尾 sigma、strip 的
U+3000、全角 parseInt 的接受與拒絕都在 39 項裡面)。語料
sh tests/run.sh java-compat 是 45 過、0 失敗(我自己跑的,兩次)。
裝箱、容器順序與例外名稱(W6,已合入 main)
- 裝箱快取(已合入):
Integer/Short/Byte/Long快取 −128..127、Character快取 0..127、Boolean只有兩個實例,所以Integer.valueOf(127) == Integer.valueOf(127)與 Java 一樣是true;跨過一次呼叫也不會壞(t242_box_identity_across_call,期望值由 javac 產生)。 - 越界訊息(已合入):
Index 5 out of bounds for length 3(大寫I,JDK 的句子)。 - 容器順序(已合入):
HashMap/HashSet的迭代順序照 JDK 21 的版面(決策 D7)。 實測程式是測試倉庫的t250_map_order,期望值由 JDK 跑t250_map_order.java.ref產生: 五個字串鍵(依序放入banana、apple、cherry、date、elderberry)迭代出banana, date, apple, cherry, elderberry,與 JDK 逐字相同;同一桶保持插入序、第 13 個鍵 擴容到 32 桶、複製建構子與putAll的事先定量、負載因子 0.6 的門檻加倍(9 → 18)各有一行。 - 例外名稱與訊息(已合入):
Class.getName()報告 JDK 的全限定名(決策 D8), 未捕捉的例外因此印Exception in thread "main" java.lang.IllegalStateException: boom, 與 JDK 相同(t251_exception_names、t79_uncaught);System.arraycopy的型別不符訊息 也是 JDK 的arraycopy: type mismatch: can not copy long[] into byte[](t65_arraycopy)。 還沒對齊的三條訊息(cast 的 module/loader 括號、有幫助的 NullPointerException 訊息、ArrayStoreException的元素類別)寫在測試倉庫的known-failures.txt。
Java 原始碼相容(W7,已合入 main)
合入了:main 07ce0a3(PR #124,8 個 commit)。
main 上的行為我自己重跑過:.teyru 的敘述寫了分號也編得過、.java 檔可以直接當輸入、
xs.sort(naturalOrder()) 與 Comparator.comparing(f).thenComparing(g) 不再需要型別見證、
String.join 解析得到。這一節寫的時候 W5 還沒合入(那時缺的是 new String(char[])、
String.codePointAt),現在兩個都在了(見上面 W5 那一節);仍然缺的是巢狀的泛型推論
(主體本身是需要目標型別的泛型呼叫時還是要先把型別寫出來)。
語料現在從 main 就重現得出來。 teyru-lang/tests 的 main 是 af41a7d(45 支未修改的 Java
程式),而 Teyru main 的指標在 PR #128 合入後
(0e8e592)指到它。我在 main 的那個內容上自己跑過 sh tests/run.sh java-compat:
45 過、0 失敗、0 已知失敗、0 跳過——PR 描述的 45 支全過是重現得出來的,不是只有分支上成立。
tag 上那一行整套是 348 過、0 失敗、3 已知失敗、0 跳過(exit=0;見 §2 那一列,Teyru
3cd9c70 → tests 2d72fc5)。為什麼跟 PR 描述裡的 320 過、1 失敗、9 已知失敗 不同:那一行
量的是分支那一對,而 tests main 之後多了 W8 的裝箱賦值探針、拿掉了 W5 的兩條、也修好了那個
C 測試的連結——所以 tag 上是 348 過、0 失敗,3 條已知失敗正好是 known-failures.txt 當時的
三條(t235/t237/t239);45 支 java-compat 在 348 裡面。
兩組數字為什麼不同,原因要寫清楚:PR 描述裡的 320 過、1 失敗、9 已知失敗、0 跳過 量的是
分支那一對——tests main 多了 W8 的裝箱賦值探針(t246–t248,三個都是已知失敗),而且不再列
t180/t196(W5 的測試工作把它們拿掉了)。這一頁引用 main 的那一組;語料那 45 支我自己重跑過,
整套那一行依照上面標的來源。
在語料進來之前,這一頁宣稱的是子集,不是那句話。 適用範圍是 docs/language.md §12(語法層)與 §13(缺的 API 與被誤拒的寫法), 而它們不是空的。
兩個後端的語意一致性(W8,已合入 main)
矩陣先落地(#122):scripts/backend-matrix.sh 與 make backend-matrix 把 tests/programs
的每一支程式在六個格子裡建置並執行——{C+clang、C+gcc、LLVM} × {-O0、-O2}——每一格與
.expected/.exit/.experr 比,格子之間再互相比;被驅動具名拒絕的建置(例如 LLVM 的
TY-INT-0100)算「拒絕」而不是「編錯」。發佈的工作流程會呼叫它,與 make ci/make jdk-diff/
make notices 並列。允許的跨格差異寫在 scripts/backend-matrix-allow.txt:沒有工作項與原因的
條目不收,而已經不再分歧的條目會讓它失敗。矩陣量到的停止點數字(406 格、66 支程式六格齊全)
留在 §2。
它找到的兩個真實缺陷,兩個都修好了(#129、#131)。
- 裝箱目標的複合指定:兩個後端現在共用同一個降階(JLS 15.26.2 的拆箱→運算→裝箱),所以
1L <<= 33是8589934592(JDK 的答案),紅先測的t246/t247/t248現在通過——那三條known-failures.txt條目已經刪掉,這是它要求刪的。 a + b + c的求值順序:C 後端不再把運算式摺成單一 C 運算式,所以 gcc 與 clang 都印1(1)2(2)3(3)=6,與 javac 21 相同(我兩個--cc各建一次驗的)。
一件仍然不宣稱的事實說出來:Java 的 HashMap 在表長到 64 格之後,同一個桶超過 8 個元素時
會把它樹化,而樹化後的次序由 System.identityHashCode 決勝——那個值原則上不可重現。所以那個
形狀的迭代順序我們不宣稱與 JDK 相同。64 格以下不會樹化,所以任何更小的表在任何鍵集合上
都走 Java 的順序(我對照 JDK 驗過:六個字串鍵,以及 20 個只有 hashCode 的自訂鍵型別)。
TLS 可達性與平台(W9,已合入 main)
TLS 現在由程式的呼叫圖決定要不要連結,不再因為反射表而自動可達:一個不呼叫 ssl() 的
web 程式在沒有 OpenSSL 標頭的機器上照樣建置與服務,Gson 形狀的程式能編給 windows/amd64,
而真的呼叫 ssl() 的程式行為不變(連結的內容與輸出都一樣)。透過反射到達 TLS 的呼叫得到
一個具名、可攔截的 UnsupportedOperationException,而不是跳到 NULL。tests/run.sh 與
go test 都讀 TEYRU_TARGET,resolveTarget 也接受呼叫端給的 --cc,所以
darwin/amd64 與 darwin/arm64 可以用 zig cc 透過 teyru build 建置。
基準與宣稱一致(W10)
examples/bench_*.teyru 與對應的 .java 改成從命令列讀規模,scripts/bench.sh 因此輸出
短跑與長跑兩組表,並新增 bench_string_cjk(非 ASCII 的拼接、charAt 走訪、substring)
與尖峰 RSS;量測窗口跑完了(RUNS=5 JAVA=1、-O2、樹 130565a,進入與離開時的 1 分鐘
負載都低於 1)。長跑那一組是唯一能支持吞吐結論的,而它說的是 Teyru 一項都沒贏
(fib 平手,其餘 Java 快 1.13~6.8 倍);短跑那組的優勢是啟動,不是吞吐。這一頁不重述
數字,因為它們必須連著量測方法讀:見 docs/index.md 的〈為什麼比 JVM 快〉。
GraalVM 的 native-image 對照未測(這台機器上沒有 GraalVM),如實寫成未測。
第三方聲明與文件規範(W11、W12,已合入 main)
THIRD-PARTY-NOTICES.md補上 OpenSSL(版本下限 1.1,動態連結)、Windows 目標靜態連結的 mingw-w64 執行期、主機自己的 IANA tzdata(不散布、不內建)與 W5 的 Unicode 資料(Unicode License v3);執行期不再逐檔列名,而是按目錄宣告,清單由scripts/check-notices.sh(make notices)產生、也由同一個腳本核對。AGENTS.md增補三條規則:Java 語意的改動必須附 JDK 差分測試、面向外部輸入的程式碼必須附 對抗測試、文件裡的每一條能力聲明都要指得到測試。- GPL-2.0 with Classpath Exception 與 OpenSSL 3(Apache-2.0)的相容性列為需要 owner 決定, 文件只敘述事實、不下結論(見 docs/legal.md §9)。
2. 量到什麼
數字都連著方法與環境讀;這一頁只放幾個這一版特有的:
| 量到的東西 | 數字 | 怎麼量的 |
|---|---|---|
執行檔大小(hello world,-O2) | 67,240 B(-O0 118,608、-O1 90,352、-O3 70,672) | wc -c;比 0.2 時代的 55,920 大,三次成長是裝箱快取(+6,016)、堆疊檢查(+2,256)與 W9 的 TLS 連結(+120),量在 docs/index.md |
| LLVM 後端的邊界 | tests/programs(34584f2)256 支裡 159 支建得起來、153 支輸出相同、93 支具名拒絕 | 2026-09-17,teyru build --backend=llvm 逐支跑並與 .expected 比(docs/index.md 有完整分類) |
linux/arm64 的整套 | 250 項全過、0 項不符(qemu-aarch64,容器裡的 sysroot 自建);W9 之後用 TEYRU_TARGET 重測:286 項裡 271 過、5 失敗、10 已知失敗,而 5 個失敗原生也一樣失敗 | sh tests/run.sh 與 TEYRU_TARGET=linux/arm64 … sh run.sh,見 docs/index.md 的平台表 |
| Windows 目標 | 302 支裡 290 支逐位元組相同、11 支 TLS 具名拒絕、1 支 NTFS 跳過、0 支不符(Wine 下跑,2026-10-17) | 同上 |
| macOS 兩列 | 只到「編譯並連結」:257 支裡 240 支建得起來、9 支因 TLS 被具名拒絕、8 支那個版本的編譯器還不接受;產物是 Mach-O,沒有任何一行被執行過 | teyru build --cc <zig 包裝>(zig cc -target aarch64-macos),見平台表 |
| 遞迴過深的代價 | bench_fib 長跑回退約 32% | scripts/bench.sh 長跑前後,owner 已裁決接受 |
| W7 的語料 | 45 支全過、0 失敗(tests/java-compat;Teyru main 9be8159 → tests 4ac49a7) | sh tests/run.sh java-compat,在 main 上的那個內容跑(我自己跑的;make java-compat 是同一件事) |
| 字串與 Unicode(W5)的 JDK 差分 | 寫的一半 32/32 逐位元組相同;讀的一半 39/41,其餘兩項是已聲明的差異 | 同一支程式寫兩次(.teyru 與 Java),/opt/jdk21/jdk-21.0.11+10 跑 Java 那一半再逐行 diff;於 9be8159 上跑 |
| W8 的兩個缺陷 | 裝箱複合指定 1L <<= 33 → 8589934592;f(1)+f(2)+f(3) 在 clang 與 gcc 都印 1(1)2(2)3(3)=6 | t246–t248(已從 known-failures.txt 拿掉)與一支 --cc 各建一次的程式;與 javac 21 比對 |
| 整套測試 | 348 過、0 失敗、3 已知失敗、0 跳過(exit=0)——量在 tag 的樹上:Teyru 3cd9c70(v0.4.0)→ tests 2d72fc5 | sh tests/run.sh,我自己在 tag 那棵樹上跑的;3 條已知失敗就是 known-failures.txt 當時的三條(t235/t237/t239),所以「列出的都失敗、沒列出的都沒漏」成立 |
(macOS 那一列是 W9 之後重量的(2026-09-17,tests @ e4268a6,編譯器 5ac017b);
linux/arm64 那一列 W9 之後的 TEYRU_TARGET 重測已經跑完,兩個數字都寫在上面。)
三條已知失敗,具名。 「3 已知失敗」不該是一個裝飾用的數字,所以三條都寫出來(括號裡是
known-failures.txt 那一行的原因):
t235_probe_exceptions(W6:類名已經對上java.lang.*,剩下的是轉型的括號註記、有幫助的NullPointerException訊息,與ArrayStoreException的元素類別)t237_probe_missing_api(W6:new Integer(int)與new Boolean(boolean)沒有宣告;這支探針 另外要的字串 API 已經隨 W5 的寫入那一半到位)t239_probe_negative_array(W7:負的陣列大小在這裡是編譯錯誤,在 Java 是執行期例外)
那個檔案自己的規則讓這份名單有牙齒:列出的案例如果通過,整次跑就失敗——所以一個條目活不過 它描述的那個缺陷。所以這三行同時是進度表(每一條都掛著工作項)與承諾(哪一條修好,它就必須 從檔案裡消失)。
3. 還沒實作
完整的清單在 docs/language.md §13,與標準程式庫的缺口在同頁 §11;
執行期與執行緒的已知限制在 AGENTS.md §10。這一頁不複製它們,只說方向:
- checked exception 沒有編譯期檢查;
sealed的permits子句沒有被驗證(switch 窮盡性因此要求default);- 反射沒有泛型型別參數,所有的陣列共用一個類別;
- 與 Java 生態互通(JAR、JDK 類別庫、JNI)沒有,這是刻意的取捨;
- locale 相關的大小寫映射(
tr、az、lt)沒有實作,String.toUpperCase()一律走 root locale 的規則。
4. 這一版不宣稱什麼
- 速度。0.4.0 是正確性版本:計畫的第 5 階段(W13 編譯速度、W14 執行期性能)不在這一版,
而且 W14 在計畫裡本來就是選用的。已經量到的回退如實寫在上面(
bench_fib長跑 32%), 而 W10 的長跑表就是這個立場的證據:六列裡 Teyru 一列都沒贏(bench_alloc那一列要排除在外—— 它量的是「Teyru 真的配置」對上「Java 把配置最佳化掉」,關掉 JIT 之後同一支程式 Teyru 反而快 約 20 倍,見 docs/index.md 的說明)。唯一的例外是啟動、執行檔 大小與尖峰記憶體——那三項是量到的,也是這一版真正贏的地方。 - 精確或分代收集器。owner 的順序是「先把這些修好、切 0.4,再談把伺服器的執行期換成 精確或分代的收集器」,所以那是下一個版本的事;0.4 的收集器仍然是保守式標記清除。
- macOS 可以跑。那兩列只到「編譯並連結」:沒有任何 Mach-O 執行檔被執行過(這裡沒有 一台 macOS),而「編譯成功」不等於「跑得起來」。
HashMap在那個形狀上的迭代順序。表長到 64 格以後、同一個桶超過 8 個元素時 Java 會 樹化,而樹化後的次序由System.identityHashCode決勝——那個值原則上不可重現,所以那個 形狀我們不宣稱與 JDK 相同(64 格以下不會樹化,見 W8 那一節)。- 「Java 原始碼不改就能編」當成一句沒有範圍的話。W7 已合入 main,未修改的 Java 在測過的 子集上編得過(見上),但語料還沒進 main 的 submodule 指標,而 §12/§13 的差別也還在—— 所以這一版宣稱的是那個子集,不是那句話。
- 與 javac 一致。我們不是一致的:
'😀'在這裡是TY-SYN-0008(一個char字面值只收一個 UTF-16 code unit),而 JDK 21 接受它並取 55357——這一條是我們比較嚴,不是我們對。 - checked exception 有被追蹤。完全沒有:
throws只被解析,JDK 差分裡 javac 拒絕的 16 個 案例有 8 個是這個原因(tests/jdk-diff-allow.txt逐條寫著)。owner 決定把這條留成文件化的 差異,不是待辦事項。 - 靜態初始化的急切程度與 Java 相同。這個編譯器在
main之前先初始化程式自己的類別, Java 是第一次使用時才初始化;語意差異與它的測試寫在AGENTS.md§10。 - LLVM 後端與 C 後端同等。它不是發佈建置預設用的後端(預設是 C),而且兩者還不同等:
2026-09-17 實測 256 支測試程式,159 支建得起來、其中 153 支輸出與期望完全相同、6 支不同
(JDK 探針,列在
known-failures.txt)、93 支被具名拒絕、0 個模組 clang 不收;lambda 與 方法參照現在不在拒絕名單裡,排在最前面的是要靠註解的宣告(38)。完整的拒絕分類見 docs/index.md 的〈後端與平台〉。 - 有 CI。這個專案沒有在 push 或 PR 上跑的 CI(owner 的決定),關卡是人在這台機器上跑
make ci;唯一的工作流程是發佈 release 時那一個。
5. 需要 owner 操作或決定
- 授權:GPL-2.0 with Classpath Exception 與 OpenSSL 3(Apache-2.0)的相容性,以及散布 「靜態連結了 mingw-w64 執行期」的 windows/amd64 產物時的義務(docs/legal.md §9)。
- 文件站的自動部署:把 Vercel 的 GitHub App 授權給
teyru-lang組織,在那之前每次文件 改動都要有人手動vercel deploy --prod。