# 機能設計書 82-状態マシン変換

## 概要

本ドキュメントは、F#コンパイラにおける`task { ... }`や`async { ... }`などの再開可能コード（Resumable Code）を状態マシンに変換する機能の設計について記述する。この機能は、コンピュテーション式を効率的な状態マシン実装に変換し、.NETの非同期パターンに適合させる。

### 本機能の処理概要

**業務上の目的・背景**：
F#のtask式やasync式は、非同期プログラミングを宣言的に記述できる強力な機能である。しかし、これらの構文をそのまま実行すると、クロージャや継続の多用によりオーバーヘッドが大きくなる。本機能は、コンピュテーション式を状態マシンにコンパイルすることで、.NETのValueTask/Taskパターンに最適化された効率的な実装を生成する。

**機能の利用シーン**：
- `task { ... }` 構文を使用したタスク式のコンパイル時
- `async { ... }` 構文を使用した非同期式のコンパイル時
- `__resumableEntry`、`__resumeAt`などの再開可能コード構文の処理時
- カスタムの再開可能コードビルダーのコンパイル時

**主要な処理内容**：
1. `StructStateMachineExpr`パターンで状態マシン式を検出
2. 再開可能コード定義（`__expand_*`変数）のバインドと展開
3. 2フェーズ変換：コード解析（フェーズ1）とラベル付きコード生成（フェーズ2）
4. MoveNext、SetStateMachine、AfterCodeの3メソッド生成
5. プログラムカウンタ（pc）によるジャンプテーブルの構築

**関連システム・外部連携**：
- TypedTree: 型付き抽象構文木の入力元
- TypedTreeOps: TAST操作ユーティリティ
- ResumableStateMachine: F#コアライブラリの状態マシン基盤型

**権限による制御**：
特になし。コンパイラ内部の最適化フェーズとして自動的に適用される。

## 関連画面

該当なし（コンパイラ内部機能）

## 機能種別

コンパイラ最適化機能（状態マシン変換）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| g | TcGlobals | Yes | コンパイラグローバル状態 | null不可 |
| overallExpr | Expr | Yes | 変換対象の状態マシン式 | StructStateMachineExprにマッチすること |

### 入力データソース

- 型検査済みTAST（TypedTree）
- F#コンパイラサービスのグローバル状態
- 再開可能コード定義（`__expand_*`変数）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| templateStructTy | TType | ResumableStateMachine<データ型>のテンプレート型 |
| dataTy | TType | 状態マシンのデータ型 |
| stateVars | ValRef list | 状態変数のリスト |
| thisVars | ValRef list | thisポインタ変数のリスト |
| moveNext | Val * Expr | MoveNextメソッドの変数と本体 |
| setStateMachine | Val * Val * Expr | SetStateMachineメソッドの変数群と本体 |
| afterCode | Val * Expr | AfterCodeメソッドの変数と本体 |

### 出力先

最適化済みTASTとしてコンパイルパイプラインに渡される

## 処理フロー

### 処理シーケンス

```
1. 状態マシン式の検出
   └─ IsStateMachineExpr / StructStateMachineExprパターン

2. 再開可能コード定義のバインド
   └─ BindResumableCodeDefinitionsで__expand_*変数を収集

3. コード展開
   ├─ TryReduceExprで再開可能コード定義を展開
   └─ RepeatBindAndApplyOuterDefinitionsで繰り返し適用

4. フェーズ1：ConvertResumableCode
   ├─ 再帰的に式を解析
   ├─ ResumableEntryMatchExpr: 再開ポイントの処理
   ├─ ResumeAtExpr: 再開位置へのジャンプ
   ├─ SequentialResumableCode: 逐次実行
   ├─ WhileExpr: whileループ
   ├─ TryFinallyExpr: try/finally（同期的のみ）
   ├─ TryWithExpr: try/with
   └─ 状態変数・エントリーポイントの収集

5. 状態マシン変数の割り当て
   ├─ pc（プログラムカウンタ）変数
   └─ ラベルからPCへのマッピング

6. フェーズ2：phase2関数の実行
   └─ ラベル付きコードの生成

7. ジャンプテーブルの構築
   └─ addPcJumpTable関数でPC値に基づくswitch生成

8. 結果の組み立て
   └─ LoweredStateMachineの生成
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{IsStateMachineExpr?}
    B -->|No| Z1[NotAStateMachine]
    B -->|Yes| C[BindResumableCodeDefinitions]
    C --> D{StructStateMachineExpr?}
    D -->|No| Z2[代替式使用/エラー]
    D -->|Yes| E[RepeatBindAndApplyOuterDefinitions]
    E --> F[ConvertResumableCode フェーズ1]
    F --> G{変換成功?}
    G -->|No| Z2
    G -->|Yes| H[PC/ラベルマッピング生成]
    H --> I[phase2実行]
    I --> J[ジャンプテーブル追加]
    J --> K[LoweredStateMachine生成]
    K --> L[Lowered返却]
    L --> M[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-82-01 | スタック変数判定 | `__stack_*`で始まる変数名はローカル変数として扱う | 変数名が規約に従う場合 |
| BR-82-02 | 状態変数昇格 | resumableVarsに含まれる変数は状態マシンのフィールドに昇格 | 変数が再開後も参照される場合 |
| BR-82-03 | thisポインタ判定 | byref型でテンプレート構造体型と一致する変数はthisVarsとして扱う | 構造体状態マシンの場合 |
| BR-82-04 | try/finally制限 | try/finally内での再開ポイントは禁止 | 非同期try/finallyの場合 |
| BR-82-05 | ハンドラ再開制限 | catchハンドラやフィルタ内での再開ポイントは禁止 | 例外ハンドラ内の場合 |

### 計算ロジック

- **PC生成**: `genPC()`でインクリメンタルに割り当て
- **ラベル生成**: 各PCに対してILコードラベルを生成

## データベース操作仕様

該当なし（メモリ内変換のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| reprResumableCodeInvokeNotReduced | 変換エラー | ResumableCode.Invokeが展開されない | 代替式使用またはエラー |
| reprResumableCodeContainsConstrainedGenericLet | 変換エラー | 制約付きジェネリック関数を含む | 代替式使用またはエラー |
| reprResumableCodeContainsLetRec | 変換エラー | let recを含む | 代替式使用またはエラー |
| reprResumableCodeContainsDynamicResumeAtInBody | 変換エラー | 動的な再開位置を含む | 代替式使用またはエラー |
| reprResumableCodeContainsResumptionInTryFinally | 変換エラー | try/finally内に再開ポイント | 代替式使用またはエラー |
| reprResumableCodeContainsFastIntegerForLoop | 変換エラー | 高速forループ内に再開ポイント | 代替式使用またはエラー |
| reprResumableCodeContainsResumptionInHandlerOrFilter | 変換エラー | ハンドラ/フィルタ内に再開ポイント | 代替式使用またはエラー |

### リトライ仕様

リトライなし。変換不可の場合は代替式（altExpr）使用またはエラー報告。

## トランザクション仕様

該当なし（ステートレス変換）

## パフォーマンス要件

- 変換処理はコンパイル時のみ実行
- 生成される状態マシンは構造体ベースでヒープ割り当てを最小化
- ValueTask互換の効率的な非同期パターン

## セキュリティ考慮事項

該当なし

## 備考

- 再開可能コードはF# 6.0で導入された機能
- `__useResumableCode`分岐で状態マシンパスと代替パスを切り替え
- try/finally内での再開は意図的に禁止（繰り返しfinally実行を防ぐため、473-474行目コメント）
- デバッグビルドでは`FSharp_StateMachineVerbose`環境変数で詳細ログを有効化可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、状態マシン変換で使用される主要なデータ型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | StateMachineConversionFirstPhaseResult型（16-36行目） |
| 1-2 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | LoweredStateMachine型（146-154行目） |
| 1-3 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | LoweredStateMachineResult型（156-167行目） |

**主要な型定義**:
- **16-36行目**: `StateMachineConversionFirstPhaseResult`レコード型
  - `phase1`: 展開された式（ラベル決定前）
  - `phase2`: ラベルマップを受け取り最終式を返す関数
  - `entryPoints`: 再開ポイントのPCリスト
  - `stateVars`: 状態変数のリスト
  - `thisVars`: thisポインタ変数のリスト
  - `resumableVars`: 再開パスで捕捉される変数

- **146-154行目**: `LoweredStateMachine` - 最終出力型
- **156-167行目**: `LoweredStateMachineResult` - 変換結果の判別共用体（Lowered/UseAlternative/NoAlternative/NotAStateMachine）

**読解のコツ**: この機能はシーケンス変換（LowerSequences.fs）と類似の2フェーズ変換を行うが、try/with内の再開やthis変数の扱いなど、より複雑な制御フローに対応している。

#### Step 2: エントリーポイントを理解する

メインの変換関数から読み始める。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | LowerStateMachineExpr関数（916-924行目） |
| 2-2 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | IsStateMachineExpr関数（128-144行目） |
| 2-3 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | LowerStateMachineクラス（170行目〜） |

**主要処理フロー**:
- **916-924行目**: `LowerStateMachineExpr` - メインエントリーポイント
- **128-144行目**: `IsStateMachineExpr` - 状態マシン式かどうかの判定
- **170行目**: `LowerStateMachine`クラス - 変換ロジックを保持

#### Step 3: 再開可能コード定義の処理を理解する

再開可能コード定義のバインドと展開を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | BindResumableCodeDefinitions関数（178-193行目） |
| 3-2 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | TryReduceExpr関数（315-348行目） |
| 3-3 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | RepeatBindAndApplyOuterDefinitions関数（367-372行目） |

**主要処理フロー**:
- **178-193行目**: `BindResumableCodeDefinitions` - `__expand_*`変数を環境に登録
- **195-312行目**: `TryReduceApp` - 関数適用の展開
- **315-348行目**: `TryReduceExpr` - 再開可能コード定義の置換
- **367-372行目**: `RepeatBindAndApplyOuterDefinitions` - 繰り返し展開

#### Step 4: パターン変換処理を理解する

各構文要素の変換ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | ConvertResumableCode関数（430-531行目） |

**主要処理フロー**:
- **430-531行目**: `ConvertResumableCode` - 再帰的な変換関数
- **452-453行目**: `ResumableEntryMatchExpr` - 再開ポイントの処理
- **455-456行目**: `ResumeAtExpr` - 再開位置へのジャンプ
- **466-467行目**: `SequentialResumableCode` - 逐次実行
- **470-471行目**: `WhileExpr` - whileループ
- **475-476行目**: `TryFinallyExpr` - try/finally（同期的のみ）
- **484-485行目**: `TryWithExpr` - try/with
- **488-489行目**: `Expr.Match` - パターンマッチ
- **493-500行目**: `Expr.Let` - let束縛

#### Step 5: 個別変換関数を理解する

各構文要素の詳細な変換ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | ConvertResumableEntry（533-559行目） |
| 5-2 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | ConvertResumableTryWith（710-757行目） |
| 5-3 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | ConvertResumableLet（803-842行目） |

**主要処理フロー**:
- **533-559行目**: `ConvertResumableEntry` - 再開ポイント（PCを割り当て、Someブランチをラベル付き）
- **710-757行目**: `ConvertResumableTryWith` - try/with（内部PCに対する内部ジャンプテーブル生成）
- **803-842行目**: `ConvertResumableLet` - let束縛（ローカル/状態変数/this変数の判定）

#### Step 6: 状態変数表現の決定を理解する

バインディングの表現方法の決定ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | RepresentBindingAsTopLevelOrLocal（51-57行目） |
| 6-2 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | RepresentBindingAsThis（61-69行目） |
| 6-3 | LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | RepresentBindingAsStateVar（72-100行目） |

**主要処理フロー**:
- **51-57行目**: `RepresentBindingAsTopLevelOrLocal` - ローカル変数またはトップレベル束縛
- **61-69行目**: `RepresentBindingAsThis` - thisポインタとして表現
- **72-100行目**: `RepresentBindingAsStateVar` - 状態変数として表現（成功時にクリア）

### プログラム呼び出し階層図

```
LowerStateMachineExpr (g, overallExpr)
    │
    ├─ IsStateMachineExpr (g, overallExpr)
    │      ├─ IfUseResumableStateMachinesExpr g
    │      └─ StructStateMachineExpr g
    │
    └─ LowerStateMachine(g).Apply (overallExpr, altExprOpt)
           │
           ├─ ExpandedStateMachineInContext パターン
           │      ├─ BindResumableCodeDefinitions (env, inputExpr)
           │      └─ StructStateMachineExpr g
           │
           ├─ RepeatBindAndApplyOuterDefinitions (env, codeExpr)
           │      ├─ BindResumableCodeDefinitions
           │      └─ TryReduceExpr (env, expr, args, remake)
           │             └─ TryReduceApp (env, expr, args)
           │
           ├─ ConvertResumableCode (env, pcValInfo, expr)
           │      │
           │      ├─ ConvertResumableEntry (再開ポイント)
           │      │      └─ genPC()
           │      │
           │      ├─ ConvertResumableResumeAt (再開位置)
           │      │
           │      ├─ ConvertResumableSequential (逐次実行)
           │      │
           │      ├─ ConvertResumableWhile (whileループ)
           │      │
           │      ├─ ConvertResumableTryFinally (try/finally)
           │      │
           │      ├─ ConvertResumableIntegerForLoop (forループ)
           │      │
           │      ├─ ConvertResumableTryWith (try/with)
           │      │      └─ addPcJumpTable (内部ジャンプテーブル)
           │      │
           │      ├─ ConvertResumableMatch (パターンマッチ)
           │      │
           │      └─ ConvertResumableLet (let束縛)
           │             ├─ RepresentBindingAsThis
           │             ├─ RepresentBindingAsTopLevelOrLocal
           │             └─ RepresentBindingAsStateVar
           │
           ├─ phase2 (pc2lab)
           │
           ├─ addPcJumpTable (m, pcs, pc2lab, pcExpr, expr)
           │
           └─ LoweredStateMachine 生成
```

### データフロー図

```
[入力]                        [定義バインド]                  [変換]                    [出力]

Expr (task/async式)
    │
    ▼
IsStateMachineExpr ──────▶ BindResumableCodeDefinitions
                                   │
                                   ├─▶ env.ResumableCodeDefns (__expand_* マップ)
                                   │
                                   └─▶ RepeatBindAndApplyOuterDefinitions
                                              │
                                              ▼
                                        ConvertResumableCode
                                              │
                                              ├─▶ phase1 (展開済み式)
                                              │
                                              ├─▶ entryPoints (PC一覧)
                                              │
                                              ├─▶ stateVars (状態変数)
                                              │
                                              ├─▶ thisVars (this変数)
                                              │
                                              └─▶ phase2 (クロージャ)
                                                        │
                                   PC/ラベル割り当て◀────┘
                                              │
                                              ▼
                                        phase2 (pc2lab)
                                              │
                                              ▼
                                        addPcJumpTable
                                              │
                                              ▼
                                   LoweredStateMachine
                                        (templateStructTy,
                                         dataTy,
                                         stateVars,
                                         thisVars,
                                         moveNext,
                                         setStateMachine,
                                         afterCode)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| LowerStateMachines.fs | `src/Compiler/Optimize/LowerStateMachines.fs` | ソース | 状態マシン変換の実装 |
| TypedTree.fs | `src/Compiler/TypedTree/TypedTree.fs` | ソース | TAST型定義 |
| TypedTreeOps.fs | `src/Compiler/TypedTree/TypedTreeOps.fs` | ソース | TAST操作ユーティリティ |
| TypedTreeBasics.fs | `src/Compiler/TypedTree/TypedTreeBasics.fs` | ソース | 基本的なTAST操作 |
| TcGlobals.fs | `src/Compiler/TypedTree/TcGlobals.fs` | ソース | グローバル型情報 |
| Optimizer.fs | `src/Compiler/Optimize/Optimizer.fs` | ソース | 最適化パイプライン（呼び出し元） |
