# 機能設計書 52-型推論 (Type Inference)

## 概要

本ドキュメントは、Lua Language Serverにおける型推論機能の設計を記載する。この機能は、Luaコード内の変数や式の型を自動的に推論し、コード補完、ホバー情報、診断などの機能に型情報を提供する。

### 本機能の処理概要

型推論機能は、動的型付け言語であるLuaのコードを静的に解析し、変数や式の型を推論するコア機能である。推論された型情報は、IDE機能全般（コード補完、ホバー、診断、リファクタリング等）の基盤となる。

**業務上の目的・背景**：Luaは動的型付け言語であり、コード上に明示的な型宣言がない。開発者がコードの型を把握するには、コードを追跡して理解する必要があり、大規模プロジェクトでは困難になる。型推論機能により、開発者は変数や関数の型を自動的に把握でき、開発効率とコード品質が向上する。

**機能の利用シーン**：
- コード補完時に適切な候補を表示するため
- ホバー表示で型情報を表示するため
- 型の不一致を診断するため
- リファクタリング時に影響範囲を特定するため

**主要な処理内容**：
1. AST（抽象構文木）からノード情報を収集
2. LuaDocアノテーションからの型情報を抽出
3. 代入文・関数戻り値・演算子から型を推論
4. 制御フロー解析による型の絞り込み
5. 推論結果をvm.nodeオブジェクトとしてキャッシュ

**関連システム・外部連携**：パーサーモジュール（AST生成）、LuaDoc解析モジュール、診断モジュール、コード補完モジュールと連携。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ホバー情報表示 | 補助機能 | ホバー表示時の型情報を推論 |
| 4 | シグネチャヘルプ | 補助機能 | 引数の型情報を推論 |
| 6 | 型定義へ移動 | 補助機能 | 変数の型を推論して定義位置を特定 |
| 25 | インレイヒント | 補助機能 | ヒント表示のための型情報を推論 |

## 機能種別

計算処理 / データ解析

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| source | parser.object | Yes | 型を推論するASTノード | 有効なASTノード |
| uri | string | No | ファイルURI（コンテキスト用） | - |

### 入力データソース

- パーサーが生成したAST（抽象構文木）
- LuaDocアノテーション解析結果
- ファイルシステム上のLuaファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| vm.node | object | 推論された型ノードオブジェクト |
| vm.infer | object | 型ビュー生成用のinferオブジェクト |
| view | string | 人間可読な型表現文字列 |

### 出力先

- vm.nodeCacheにキャッシュ
- 各LSP機能（ホバー、補完、診断等）に提供

## 処理フロー

### 処理シーケンス

```
1. vm.compileNode呼び出し
   └─ sourceのASTノードを受け取る

2. キャッシュ確認
   └─ 既に推論済みならキャッシュを返却

3. 空ノード作成
   └─ vm.createNode()で新規ノードを作成

4. グローバル解析
   └─ vm.compileByGlobalでグローバル変数情報を収集

5. 変数解析
   └─ vm.compileByVariableでローカル変数情報を収集

6. ノード種別解析
   └─ compileByNodeでノード種別に応じた推論を実行

7. 親ノード解析
   └─ compileByParentNodeでフィールドアクセスを解決

8. 関数呼び出しマッチング
   └─ matchCallで関数戻り値を推論

9. 結果返却
   └─ 推論されたvm.nodeを返却
```

### フローチャート

```mermaid
flowchart TD
    A[vm.compileNode開始] --> B{キャッシュ存在?}
    B -->|Yes| C[キャッシュ返却]
    B -->|No| D[空ノード作成]
    D --> E[vm.compileByGlobal]
    E --> F[vm.compileByVariable]
    F --> G[compileByNode]
    G --> H{ノード種別}
    H -->|local| I[ローカル変数推論]
    H -->|getglobal| J[グローバル変数推論]
    H -->|call| K[関数戻り値推論]
    H -->|binary| L[二項演算推論]
    H -->|table| M[テーブル推論]
    H -->|function| N[関数型推論]
    H -->|その他| O[その他の推論]
    I --> P[compileByParentNode]
    J --> P
    K --> P
    L --> P
    M --> P
    N --> P
    O --> P
    P --> Q[matchCall]
    Q --> R[vm.node返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-52-01 | アノテーション優先 | LuaDocアノテーションがある場合は推論より優先 | アノテーション存在時 |
| BR-52-02 | 代入追跡 | 代入文から型を推論 | ローカル変数・グローバル変数 |
| BR-52-03 | 戻り値推論 | 関数呼び出しから戻り値型を推論 | 関数呼び出し |
| BR-52-04 | 制御フロー | if文などで型を絞り込む | 条件分岐内 |
| BR-52-05 | Union型 | 複数の型が可能な場合はUnion型として表現 | 複数型候補時 |

### 計算ロジック

**型推論の優先順位**：
1. `---@type`アノテーション
2. `---@class`アノテーション
3. `---@param`/`---@return`アノテーション
4. 代入値からの推論
5. 演算子からの推論
6. デフォルト型（unknown）

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

### 操作別データベース影響一覧

本機能はデータベースを使用しない。内部的にはvm.nodeCacheにキャッシュを保持。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 再帰検出 | 循環参照を検出 | 再帰を中断しunknown型を返却 |
| - | nil source | sourceがnilの場合 | ログ出力してnil返却 |

### リトライ仕様

リトライは行わない。キャッシュクリア後に再計算。

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

トランザクションは使用しない。

## パフォーマンス要件

- 型推論結果はvm.nodeCacheにキャッシュされる
- ファイル変更時にキャッシュをクリア
- キャッシュヒット時は即座に結果を返却

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

特になし。

## 備考

- 型推論はLSPサーバーの中核機能であり、多くの機能がこれに依存する
- キャッシュ管理が重要で、ファイル変更時に適切にクリアされる必要がある

---

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

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

### 推奨読解順序

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

まず、型推論の結果を格納するデータ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | node.lua | `script/vm/node.lua` | vm.nodeクラスの定義（14-27行目） |
| 1-2 | infer.lua | `script/vm/infer.lua` | vm.inferクラスの定義（7-22行目） |

**読解のコツ**:
- `vm.node`は推論された型情報を格納するコンテナ
- 複数の型オブジェクトを配列として保持（Union型の表現）
- `optional`フラグでnil許容を表現
- `vm.infer`は`vm.node`から人間可読な型文字列を生成

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | compiler.lua | `script/vm/compiler.lua` | vm.compileNode関数（2609-2634行目） |

**主要処理フロー**:
1. **2618-2621行目**: キャッシュ確認、存在すれば即返却
2. **2624行目**: 空のvm.nodeを作成
3. **2625行目**: vm.compileByGlobalでグローバル解析
4. **2626行目**: vm.compileByVariableでローカル変数解析
5. **2627行目**: compileByNodeでノード種別ごとの推論
6. **2628行目**: compileByParentNodeでフィールドアクセス解決
7. **2629行目**: matchCallで関数呼び出しマッチング
8. **2631-2633行目**: 結果のvm.nodeを返却

#### Step 3: ノードクラスの操作を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | node.lua | `script/vm/node.lua` | merge関数（31-57行目）、eachObject（416-422行目） |

**主要処理フロー**:
- **31-57行目**: `merge`関数 - 別のノードを現在のノードにマージ
- **60-62行目**: `isEmpty`関数 - ノードが空かどうか判定
- **416-422行目**: `eachObject`関数 - ノード内の型オブジェクトを列挙

#### Step 4: 型ビュー生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | infer.lua | `script/vm/infer.lua` | view関数（409-483行目） |

**主要処理フロー**:
- **264-281行目**: `vm.getInfer`関数 - sourceからinferオブジェクトを取得
- **409-483行目**: `view`関数 - 型を文字列として表現
- **40-251行目**: `viewNodeSwitch` - ノード種別ごとのビュー生成ロジック

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

```
vm.compileNode(source)
    │
    ├─ vm.getNode(source) [キャッシュ確認]
    │
    ├─ vm.createNode() [新規ノード作成]
    │
    ├─ vm.compileByGlobal(source)
    │      └─ グローバル変数の型情報を収集
    │
    ├─ vm.compileByVariable(source)
    │      └─ ローカル変数の型情報を収集
    │
    ├─ compileByNode(source) [内部関数]
    │      │
    │      ├─ local → ローカル変数推論
    │      ├─ getglobal/setglobal → グローバル推論
    │      ├─ call → 関数戻り値推論
    │      │      └─ getReturn(func, index, args)
    │      ├─ binary → 二項演算推論
    │      ├─ table → テーブルリテラル推論
    │      ├─ function → 関数型推論
    │      └─ doc.* → LuaDocノード推論
    │
    ├─ compileByParentNode(source) [内部関数]
    │      └─ フィールドアクセスの解決
    │
    └─ matchCall(source) [内部関数]
           └─ 関数呼び出しの引数マッチング

vm.getInfer(source)
    │
    └─ mt:view(uri)
           │
           ├─ _computeViews(uri)
           │      └─ viewNodeSwitch(type, node, infer, uri)
           │
           ├─ _trim() [重複型の整理]
           │
           └─ _eraseAlias(uri) [エイリアス展開]
```

### データフロー図

```
[入力]                    [処理]                      [出力]

parser.object      ───▶  vm.compileNode          ───▶  vm.node
(ASTノード)               │                           (型情報)
                         ├─ bindDocs (LuaDoc解析)
                         ├─ compileByNode
                         └─ compileByParentNode
                                │
                                ▼
                         vm.nodeCache
                         (キャッシュ)

vm.node            ───▶  vm.getInfer             ───▶  文字列
                         │                           "string|number"
                         └─ mt:view(uri)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| compiler.lua | `script/vm/compiler.lua` | ソース | 型推論のメインロジック |
| node.lua | `script/vm/node.lua` | ソース | vm.nodeクラス定義 |
| infer.lua | `script/vm/infer.lua` | ソース | 型ビュー生成 |
| vm.lua | `script/vm/vm.lua` | ソース | vm名前空間の基本定義 |
| type.lua | `script/vm/type.lua` | ソース | 型チェック機能 |
| generic.lua | `script/vm/generic.lua` | ソース | ジェネリック型サポート |
| global.lua | `script/vm/global.lua` | ソース | グローバル変数管理 |
| tracer.lua | `script/vm/tracer.lua` | ソース | 制御フロー解析 |
| guide.lua | `script/parser/guide.lua` | ソース | ASTユーティリティ |
| luadoc.lua | `script/parser/luadoc.lua` | ソース | LuaDoc解析 |
