Features
Tyda は Ruby / Rails のコードから型を推論し、RBS を出力する CLI、LSP、AI agent 向け MCP server を提供する。 対応状況の正本は capability-matrix.md、設計上の線引きは design.md に置く。
プロダクト
- Ruby source と
.rbsを中心にした query 型推論 engine - CLI の RBS 出力、JSON Lines diagnostics、型カバレッジ JSON
- TypeProf VSCode 拡張と接続できる LSP server
- stdio MCP server による AI agent 向けの位置指定型推論
- Rails / gem DSL plugin
- Sorbet
sig/.rbiの実験的な補助 - wasm playground(Playground)
Ruby 推論
主な対応範囲は次のとおり。
- class / module / method / mixin / constant / local / instance variable(LSP / Playground の定義・参照 hover を含む。宣言済み引数の定義位置も対象)
- method dispatch、visibility、
super、singleton method、refinement(include/prepend/extendの適用順を反映。静的に完全なModule#ancestorsは順序付きTuple) - block / Proc / lambda /
yield/ Enumerable / Enumerator / Lazy(遅延解決された source method return を block dispatch 前に反映し、tuple の要素 union とリテラル演算を block 内へ伝播) - Array / Hash / Set / Tuple / Record の要素型と shape
- if / case / rescue / safe navigation / pattern matching の flow narrowing。標準の
Class#===による postfix の local 代入条件や、pure な no-arg ivar reader の再呼び出しも扱い、分岐で相関したlocalも識別可能な型で絞られた場合に反映 - 多重代入、operator-write、method 内の instance variable 再代入、文字列・シンボル補間(静的な literal / union の展開を含む)
- Thread / Fiber / Queue の bounded な値伝播
- 静的に名前を求められる
alias/define_method/attr_*/Struct.new/Data.define(位置引数・キーワード引数のnew呼び出しからmember型を推定) /Forwardable/send/const_get
実行時にしか決まらない名前、object identity、method surface は推測せず untyped にする。 型の深さ・union・collection shape には上限がある。
型情報ソース
RBS
.rbsの自動発見、stdlib の lazy load、generic、overload、interface、alias- inline RBS(
#:/# @rbs)の単一・複数行宣言、block signature、type alias self/instanceを call site の受け手へ解決する factory 型
Sorbet(実験的)
sorbet/config がある project で、sig、T.let、T::Struct、T::Enum、.rbi と 対応する comment extension を読み込む。RBS と同じ安定性や網羅性は保証しない。
Diagnostics
型推論が主であり、diagnostics は補助である。権威ある宣言に対する確実な不一致だけを報告する。
| 種類 | 既定の severity | 方針 |
|---|---|---|
argument_type_mismatch | error | 宣言 param と actual が確実に不一致のときだけ。分岐内のインスタンス変数や File.exist? で確認したパスも、その分岐で絞られた型で判定する。Union receiver は各候補型の権威ある署名で調べ、不一致の候補型を message に含める |
return_type_mismatch | error | inline RBS、@rbs、Sorbet sig、外部RBS/RBIの戻り値型と、メソッド本体の到達可能な返却型が確実に不一致のとき。untyped や未解決型を含む不確かな結果は報告しない |
arity_mismatch | error / experimental | Union receiver は候補型と権威ある署名が分かる場合に、引数個数・必須キーワードの不一致を候補型ごとに報告する。ソース定義の initialize を標準の Class#new 経由で呼ぶ場合は必須引数の不一致を error にする。祖先解決では :: による絶対指定を保つ。Struct.new 由来の constructor は member の省略を許し、上限超過だけを報告する。Data.define 由来は、member 名が静的に分かり独自 initialize がない場合に限り、必須 member 数と位置・キーワード引数の規則で判定する。それ以外は TYDA_EXPERIMENTAL_CHECKS=1 のときだけ |
missing_record_key | warning | 形状が分かる非空 record のすべての候補にリテラルキーが存在しないとき。空 record は動的な to_h の推論結果と区別できないため対象外。Hash#merge の引数が untyped や未解決型なら、結果を動的な Hash として扱い対象外。record のキー存在確認後は既知のキーへ絞り、`[] |
missing_method | warning | receiver と祖先の method surface が完全に既知のときだけ。Union receiver は各候補型で欠けている method を報告する。安全 navigation の nil は候補から除く。bare Object / Class / Module、plugin が解決する method、既知の class-body DSL は対象外。ActiveRecord 系ではDBスキーマや宣言RBIから動的なカラム属性を確認できない場合も対象外 |
unresolved_constant | information | receiver 文脈で未定義と証明できるときだけ |
Unknown、untyped、動的な record key、開いた method_missing 面、未解決の祖先は誤検知を避けて沈黙する。Union の候補型を名前付き class に解決できない場合、引数型チェックはその呼び出し全体を Unknown として扱う。戻り値の判定では return / 末尾式 / 分岐 / loop の到達可能な返却型を使い、到達不能な末尾や bot は不一致に含めない。 詳細は incomplete-code-policy.md を参照する。
診断を一行だけ抑制するには、対象式の行末に # tyda: ignore を置く。特定の種類だけを 抑制する場合は # tyda: ignore[missing_method] のように診断 code を指定できる。現在の code は missing_method、argument_type_mismatch、arity_mismatch、missing_record_key、 unresolved_constant などで、CLI・LSP・Playground で同じ書式を使う。コメントは同じ行の末尾に 置いた場合だけ有効で、単独行のコメントが次の行へ影響することはない。対応する診断がない ignore は unused_ignore warning になり、診断が解消したあとに不要な抑制を見つけられる。
--diagnostics の JSON Lines 出力は実行間で byte-identical になる。ファイルは 辞書順の走査順(CLI に明示的に渡したパスはその順序を保つ)、ファイル内の各行は position 順(line/column 昇順)で並ぶため、複数回実行した出力をそのまま diff できる。
型カバレッジ
--coverage は、compact scan が記録した推論サイトを最終 workspace registry で再解決し、 宣言スロットと合わせて決定的な JSON として出力する。通常の RBS 出力ではサイトを保持しない ため、明示的に指定した実行だけがこの追加コストを負う。
宣言と参照は意味の違う単位なので、レポートでは分母を分ける。
declarations: Ruby source の method parameter / return / instance variable。外部 RBS だけの宣言と synthetic DSL method は含めないreferences: 推論中に観測したvalue/method_call/constant_reference
各グループと種別には次の三段階を出力する。
typed: 型が確定し、入れ子の型にも未解決 marker がないuntyped: サイトは解析経路に結び付いているが、型がuntypedまたは deferredunknown: receiver や constant の結び付き自体を確立できない
型構造が極端に大きい、または深い場合は、報告処理の上限を超えたサイトを安全側に untyped として扱う。これにより coverage の計測自体が入力によって無制限に膨らまないようにする。
type_coverage_percent は typed / total、tracking_coverage_percent は (typed + untyped) / total である。型が String から Integer に変わるような、両方とも typed の精度差はこのレポートでは扱わない。Performance workflow では既存の全 subject を base/head の同じ release binary で一度ずつ解析し、解析ファイル数の減少、typed / tracked サイトの減少、unknown の増加を失敗として検出する。untyped の増加は警告として結果 JSON と CI log に残す。Perf と同じ matrix 内で実行するため、追加の Rust build や PR comment は発生しない。
Rails / gem DSL
Rails の ActiveRecord、ActiveModel、ActiveSupport、ActionController、ActionMailer、ActiveJob、 routes、schema と、主要な gem plugin を扱う。対応 gem の正本は src/inference/plugins/ であり、 個別 gem の一覧をこの文書に重複して持たない。
- schema /
attribute/ relation から model の型を補う - Concern、association、scope、enum(plural map method を含む)、delegate などの静的な DSL を展開する。
structure.sqlの外部キー先は明示的なself.table_nameも参照する - ActiveRecord の
findは単一 ID、ID 配列、複数 ID の overload とモデル/配列の戻り値を出力する Rails.application.configureの block では、receiver のない呼び出しを application のselfで推論する- Grape、GraphQL-Ruby、Devise、Doorkeeper、Sidekiq、Draper、AASM などを plugin で補う
- GitLab in-tree の Presenter / CurrentSettings / Metrics / EE 拡張を検出する
- Redmine の
acts_as_*など、ライブラリ内部の実行時登録は展開しない。必要なら手書き.rbs/.rbi、または生成済み定義を入力する
LSP / Playground
LSP は TypeProf VSCode 拡張が期待する起動・version・request 契約に対応する。
- incremental text sync(full change も受理)
- Hover、CodeLens、definition、typeDefinition、completion
- method hover は呼び出し形に合う RBS overload を選び、推論済みの引数・戻り値から generic と block 型を具体化する
- Playground は入力中の Ruby とユーザー RBS を debounce 解析し、RBS の変更も同じ hover / diagnostics に反映する
- diagnostics の publish と workspace refresh
- CLI と共通の
WorkspaceState/ query backend - Playground の複数行選択を
Ctrl+/(Windows/Linux)またはCommand+/(macOS)で Ruby 行コメントに切り替え
Playground は同じ LSP 表示経路を wasm で実行し、Ruby と手書き RBS の結果をブラウザで確認する。 右上の Examples メニューから、配列・Tuple・mixin・RBS などの短いサンプルに切り替えられる。 サンプルのソースは末尾改行一つで統一する。 Ruby エディタを主領域として PC / 横長画面では左、狭い画面(768px 以下)では上に置き、RBS は補助領域として右または下に配置する。エディタ内の長い行は折り返し、横スクロールは使わない。動的viewportとSafe Area insetにも対応する。
主なコマンド
cargo run -- <path> # RBS
cargo run -- --diagnostics <path> # JSON Lines diagnostics
cargo run -- --coverage <path> # JSON type coverage
cargo run -- --lsp # LSP server
cargo run -- mcp # MCP server for AI agents
cargo run -- --include-synthetic-dsl-methods <path>
mise run dev # playgroundMCP の client 設定と infer_type_at_position の入力・出力は mcp.md を参照する。
開発・拡張の手順は development.md、テストの追加方法は testing.md を参照する。