Go 1.26:型構築とサイクル検出の改善(コンパイラの安定性向上)
概要¶
Go 1.26でコンパイラの型チェッカー内の「型構築(type construction)」処理を大幅改善。一般的なGoプログラマーには直接影響しないが、循環型定義(サイクル)に関する複数のコンパイラクラッシュが修正され、安定性が向上した。型チェッカーが「完全性(completeness)」を追跡しながら型を深さ優先で構築する仕組みを解説する。
詳細¶
型チェッカーが行う2つの検証¶
型構築:シンプルなケース¶
型構築:再帰的なケース¶
ポイント:不完全な型への参照を「後で完全になる」前提で許容する。
問題:循環サイクルの検出¶
問題の構造:
T を完成させる → Array のサイズが必要
Array のサイズ → T のサイズが必要
T のサイズ → T を分解(deconstruct)する必要がある
→ T はまだ不完全 → 無限ループ
サイクルが発生しうる「上流(upstream)」のパターン¶
// 変換
type T [unsafe.Sizeof(T(42))]int
// 関数呼び出し
func f() T
type T [unsafe.Sizeof(f())]int
// 型アサーション
var i interface{}
type T [unsafe.Sizeof(i.(T))]int
// チャネル受信
type T [unsafe.Sizeof(<-(make(<-chan T)))]int
// マップアクセス
type T [unsafe.Sizeof(make(map[int]T)[42])]int
// ポインタ逆参照
type T [unsafe.Sizeof(*new(T))]int
いずれも「T の結果の型」が必要になる場所。型チェッカーは 結果の型が完全であることを確認し、そうでなければサイクルエラーを報告する。
型チェッカーの実装(変換ケースの擬似コード)¶
func callExpr(call *syntax.CallExpr) operand {
x := typeOrValue(call.Fun)
switch x.mode() {
case typeExpr:
// T() の場合は型変換
T := x.typ()
if !isComplete(T) {
reportCycleErr(T) // サイクルを報告
return invalid
}
// ここから先は T を安全に分解できる
}
}
Go 1.26 で修正されたバグ¶
| Issue | 内容 |
|---|---|
| #75918 | 循環型定義によるコンパイラクラッシュ |
| #76383 | 同上(別パターン) |
| #76384 | 同上 |
| #76478 | 同上 |
これらは複雑な循環型定義に関する稀なエッジケースだが、コンパイラの堅牢性向上につながる。
なぜ重要か / いつ使うか¶
- Go コンパイラの挙動について深く理解したいとき
unsafe.Sizeofを使った定数式で不思議なコンパイルエラーが出たとき- Go のジェネリクスや複雑な型定義を扱うライブラリを実装するとき
- 「なぜこの型定義はコンパイルエラーになるのか」の原理を追うとき