末尾呼び出し最適化¶
現在の状態(2026-01-26)¶
検出: ✅ 実装済み 変換: 🚧 計画中
Onionコンパイラは、コンパイル時に末尾再帰メソッドを特定する末尾呼び出し検出システムを含んでいます。
仕組み¶
検出フェーズ¶
コンパイラはメソッドを分析して末尾再帰呼び出しを特定します。
- 末尾位置の分析: 最後の文(または制御フローの分岐内の文)が自己呼び出しかどうかを確認
- 再帰的探索:
StatementBlockとIfStatementノードを再帰的に検索して末尾呼び出しを見つける - メソッド一致の確認: 呼び出し対象が現在のメソッドと一致することを確認(同じ名前、クラス、パラメータ型)
サポートされるパターン¶
検出器は以下の末尾再帰を認識します。
- 直接末尾呼び出し:
return method(args) - 条件分岐: if文の
thenとelseの両方の分岐 - ネストしたブロック: 文ブロックを再帰的に検索
例¶
def factorial(n: Int, acc: Int): Int {
if (n <= 1) {
return acc
}
return factorial(n - 1, n * acc) // ✅ 末尾呼び出しとして検出
}
検出された末尾呼び出しの表示¶
--verbose フラグを付けてコンパイルすると、どのメソッドが末尾再帰であるかを確認できます。
出力:
[TCO] Detected tail-recursive method: YourClass.factorial
[TCO] Note: Tail call optimization is not yet fully implemented
実装の詳細¶
ファイルの場所¶
- ソース:
src/main/scala/onion/compiler/optimization/TailCallOptimization.scala - パイプライン統合:
TypingフェーズとCodeGenerationフェーズの間に追加
コンパイラパイプライン¶
Parsing → Rewriting → Typing → [TailCallOptimization] → MutualRecursionOptimization → TypedAstCodeGeneration
今後の作業¶
計画中の変換¶
変換フェーズ(末尾再帰をループに変換)には以下が必要です。
- ローカル変数の割り当て:
LocalFrameを使った一時変数の適切な割り当て - パラメータの書き換え: メソッド本体全体でパラメータ参照を一時変数参照に変換
- ループの構築: メソッド本体を
while(true)ループで囲む - 末尾呼び出しの置換: 末尾呼び出しを変数の代入 + continue に置き換える
変換の例(計画中)¶
// 元のコード
def factorial(n: Int, acc: Int): Int {
if (n <= 1) {
return acc
}
return factorial(n - 1, n * acc)
}
概念的には以下のように変換されます。
def factorial(n: Int, acc: Int): Int {
var n_temp: Int = n
var acc_temp: Int = acc
while (true) {
if (n_temp <= 1) {
return acc_temp
}
val n_next = n_temp - 1
val acc_next = n_temp * acc_temp
n_temp = n_next
acc_temp = acc_next
// ループ継続
}
}
テスト¶
テストファイルは src/test/run/ にあります。
- tail_recursion_factorial.on - 末尾再帰による階乗
- tail_recursion_simple.on - シンプルなカウントダウンの例
- tail_recursion_direct.on - 直接の無限再帰(テスト用)
貢献¶
変換フェーズの実装に貢献したい場合:
TypedASTノード構造(特にLocalFrame、RefLocal、SetLocal)を理解するsrc/main/scala/onion/compiler/backend/asm/LocalVarContext.scalaのLocalVarContextを学習する- パラメータ参照を置き換える再帰的な文書き換えを実装する
- さまざまな末尾再帰パターンの包括的なテストを追加する
参考¶
- Tail Call Optimization (Wikipedia)
- 関連実装: Scala の
@tailrecアノテーション - 同様の最適化を持つ関数型言語: Haskell、Scheme、OCaml