コンテンツにスキップ

Internal Type API

このドキュメントは、すべてのRigorの型オブジェクトがMUST満たすパブリック契約(contract)を規定します。不変性と等価性の規律、メソッドサーフェス(surface)、結果値オブジェクト、ラッパー合成ルール、そして正規化・消去・診断表示のルーティングが対象です。

これはdocs/type-specification/の型言語セマンティクスと対になるエンジン内部の仕様です。ここでの記述が型言語の振る舞いと矛盾する場合は、型仕様が優先されます。

このドキュメントで定められた決定事項は安定しています。docs/adr/3-type-representation.mdで追跡されている2つの未解決問題——定数スカラー/オブジェクトキャリア(carrier)形状と三値返却メソッドの命名規約——はいずれも契約がそれらに依存しないよう、ここでは意図的に抽象化されています。

このドキュメントが拘束するもの:

  • エンジンコード、プラグイン、CLIコンポーネント、テストが型を推論するために使用するRubyサーフェス。
  • すべての型インスタンスがMUST満たす同一性・等価性・ハッシュ化・不変性のルール。
  • メソッドサーフェスの分類(ケイパビリティ(capability)クエリ、リファインメント(refinement、篩型とも)射影、関係クエリ、構造クエリ、コンビネータ、メタ)と、各グループの結果形状契約。
  • ラッパー形式(Dynamic[T]、リファインメント、ユニオン(union、合併型とも)、インターセクション、差分、補集合、ジェネリック位置キャリア)の合成ルール。
  • パブリックメソッドから型仕様へのルーティングルール(describe(verbosity)からdiagnostic-policy.mderase_to_rbsからrbs-erasure.mdnormalizeからnormalization.md)。

このドキュメントが拘束しないもの:

  • 具体的なクラスの正確なセット。docs/adr/3-type-representation.mdの未解決問題1が未解決なためです。そのADRにあるクラスカタログのドラフトは、縦断的なスライス(slice)の実装がオプションを選択するまでは例示にとどまります。
  • 三値返却の命名規約(同ADRの未解決問題2)が未解決な場合の具体的なRubyメソッド名。命名が重要な箇所では、?サフィックスなしの抽象的な形式でメソッドを記述しています。最終的な規約はすべてのメソッドに一様に適用されます。
  • すべての型インスタンスは構築の終わりにfreezeされなければなりません(MUST)。構築後にインスタンスを変更することは、内部アクセサを通じても、契約違反です。
  • 等価性はMUST構造的でなければなりません。==eql?は一致しなければならず(MUST)、構造的に等価なデータを保持する2つのインスタンスに対して両方ともtrueを返さなければなりません(MUST)。
  • hashは同じ構造的データから導出されなければならず(MUST)、eql?で等しいインスタンスは同一のhash値を生成しなければなりません(MUST)。
  • 等価性はオブジェクト同一性に依存してはなりません(MUST NOT)。同じRubyオブジェクトでなくても、等しい構造を持つ2つの型インスタンスは等しいと比較されなければなりません(MUST)。
  • 型インスタンスはハッシュキーとして再利用してもかまいません(MAY)。実装はキャッシュが有効な場合に共通インスタンスをフライウェイト化してもかまいませんが(MAY)、フライウェイト化を正確さのために依存してはなりません(MUST NOT)。
  • 「構造的に等価なデータ」には、キャリアが自身の同一性に畳み込むあらゆる判別子が含まれます。とりわけConstantはラップした値のRubyクラスをMUST区別します。したがって1 == 1.0であってもConstant[1](Integer)とConstant[1.0](Float)は等しくありません。フィールドごとの比較だけではこの二つを混同してしまうからです。

この同一性契約はsig/rigor/type.rbsにおいて構造的インターフェース_Typeとして成文化されています ── これは構造的インターフェース(RBS/Goの意味での)であり、ADR-28のプロトコル契約ではありません。同一性が素のフィールドごとの比較であるキャリアは、== / eql? / hashの三つ組をそのフィールドリストから生成してもかまいません(MAY)(Rigor::ValueSemanticsvalue_fieldsマクロ)。これにより三つのメソッドは構成上一致した状態に保たれます。一方、洗練された同一性を持つキャリア(上記のConstantのクラス判別子、フィールドを持たないTop / Botシングルトン)は三つ組を手書きします。生成のメカニズムは実装であり、拘束力を持つ契約は上記の三つのルールです。

Rigor::Trinary値オブジェクトは、ケイパビリティクエリ、関係クエリ、および「証明されたyes」「証明されたno」「どちらも証明できない」を区別するアナライザーサーフェスが使用する標準的な三値結果です。そのセマンティクスはrelations-and-certainty.mdで規範的に定義されており、このセクションはパブリックなRuby契約を拘束します。

  • Rigor::Trinaryは、yesnomaybeという名前のファクトリーを通じてアクセス可能な3つのフライウェイトインスタンスを公開しなければなりません(MUST)。フライウェイトは同じ値に対してequal?==eql?を満たさなければなりません(MUST)。
  • Rigor::Trinaryは、trueまたはfalseを返すブールな述語yes?no?maybe?を公開しなければなりません(MUST)。これらはTrinary上で?-returns-boolean規約に従う唯一のメソッドでなければなりません(MUST)。
  • Rigor::Trinaryは少なくとも標準コンビネータand(other)or(other)negateyesの否定はnonoの否定はyesmaybeの否定はmaybe)を公開しなければなりません(MUST)。コンビネータはRigor::Trinaryインスタンスを返さなければなりません(MUST)。
  • Rigor::Trinary値は暗黙にRubyのブール値に強制変換されてはなりません(MUST NOT)。ブール値が必要な呼び出し元は明示的な述語(yes?no?maybe?)を選択しなければなりません(MUST)。
  • maybeは繰り返しの証拠によってyesに昇格されてはなりません(MUST NOT)。relations-and-certainty.mdの昇格ルールだけが確実性の変更の源です。

関係クエリは、アナライザーが呼び出し元が消費してもよい(MAY)理由メタデータを持つ場合、裸のブール値や裸のRigor::Trinary値ではなく、不変の結果値オブジェクトを返さなければなりません(MUST)。

  • 部分型(subtype)クエリ(subtype_of)は、型APIの残りの部分で選ばれる三値命名規約に従ったメソッドを通じてRigor::Trinaryの回答を公開するオブジェクトに加え、どのルールが発動したか、どの動的起源ファクト(fact)が参照されたか、どの予算カットオフに達したかを説明する理由メタデータを持つオブジェクトを返さなければなりません(MUST)。
  • 受容クエリ(accepts)は、受容固有のメタデータ(モード、変換パス、動的起源の来歴)をカバーする類似のオブジェクトを返さなければなりません(MUST)。スライス4フェーズ2cは、次の形状を持つ具体的なRigor::Type::AcceptsResult値オブジェクトにこれを紐付けます:
    • trinary — 保持するRigor::Trinaryの回答。
    • mode — 回答が計算された境界モード(:gradualが現在利用可能;:strictは後のスライスのために予約)。
    • reasons — 発動したルールを発動順に説明する凍結されたArray<String>
    • 述語yes?no?maybe?は保持するRigor::Trinaryに委譲しなければならず(MUST)、?-returns-boolean規約に従うAcceptsResult上の唯一のメソッドでなければなりません(MUST)。
    • with_reason(reason)は同じtrinarymodeを持ちつつreasonreasonsに追加した新しいAcceptsResultを返さなければなりません(MUST)。レシーバーを変更してはなりません(MUST NOT)。nilまたは空文字列を渡すことはno-op(同じインスタンスが返される)でなければなりません(MUST)。
    • (trinary, mode, reasons)の構造的等価性は、同一性と不変性セクションに従って保持されなければなりません(MUST)。
    • reasonsは人間が読めるログ以外のすべての呼び出し元から不透明として扱われなければなりません(MUST)。後のスライスはエントリーを構造化レコード(ルールid、サポートファクト、動的来歴)にアップグレードしてもよく(MAY)、それに関する事前通知は不要です;より豊かなキャリアが必要な呼び出し元は文字列を解析するのではなく将来の名前付きアクセサを通じてそれを消費しなければなりません(MUST)。
  • 単純なクエリ(consistent_withequal_value)は有用な理由メタデータが存在しない場合に裸のRigor::Trinaryを返してもかまいません(MAY)。
  • 結果オブジェクトは不変であり、型インスタンスと同じルールで構造的に比較可能でなければなりません(MUST)。

結果オブジェクトサーフェスは、docs/adr/3-type-representation.mdに記録されたPHPStanのIsSuperTypeOfResultAcceptsResult設計を反映しています。

すべての具体的な型実装は以下に列挙するメソッドサーフェスを公開しなければなりません(MUST)。?サフィックスなしのメソッド名はこの仕様で使用される抽象形式に従います;最終的な具体的なスペルはADR-3の未解決問題2の解決によって固定され、Rigor::Trinaryを返すすべてのメソッドに一様に適用されます。

ケイパビリティ述語は型が特定のRubyの種類として振る舞うかどうかを問います。Rigor::Trinaryを返さなければなりません(MUST)。最小サーフェスは:

stringintegerfloatsymbolbooleannil_valuearrayhashtuplerecordproccallableiterablevoiddynamicclass_objectmodule_object

実装は型仕様が対応する区別を得た場合に追加の種類のケイパビリティ述語を追加してもかまいません(MAY)。実装は振る舞い的に弱いチェックでケイパビリティ述語を置き換えてはなりません(MUST NOT)。

リファインメント射影は特定のリファインメントファミリーの証人を列挙します。RubyのArray<Rigor::Type>を返さなければなりません(MUST)。空の配列は「この射影の証明された証人がない」ことを意味します。空でない配列はアナライザーが証人を列挙できることを意味します。最小サーフェスは:

constant_stringsconstant_integersconstant_floatsconstant_symbolsconstant_booleansconstant_arraysarraystuplesrecordshashesenum_casesfinite_values

合成ルール:

  • ユニオンは各射影をメンバーに転送し、結果を順序を保持しながら連結しなければなりません(MUST)。
  • インターセクションは各射影をメンバーに転送し、結果を交差させなければなりません(MUST)。
  • Dynamic[T]ラッパーはvalue-lattice.mdに従って静的ファセットTへの射影を転送しなければなりません(MUST)。Dynamic[T]を通じて取得された証人は自身に動的起源の来歴を持たなければなりません(MUST)。
  • リファインメントラッパー(精緻化された名前的型(nominal type、公称型とも)、整数範囲、有限リテラルユニオン等)は基底型を通じて射影を転送し、適用可能な場合は独自の貢献を追加しなければなりません(MUST)(例えば、文字列の有限リテラルユニオンはconstant_stringsにそのメンバーを提供しなければなりません)。

関係クエリは(理由メタデータが意味を持つ場合)結果値オブジェクトを、(持たない場合)Rigor::Trinaryを返さなければなりません(MUST)。最小サーフェスは:

  • subtype_of(other) — 部分型結果オブジェクトを返す;セマンティクスはrelations-and-certainty.mdを参照。
  • accepts(other, mode:) — 受容結果オブジェクトを返す;mode:キーワードは境界モード(strict、gradual、プラグイン提供)を持つ。
  • consistent_with(other)Rigor::Trinaryを返す;セマンティクスはrelations-and-certainty.mdを参照。
  • equal_value(other)Rigor::Trinaryを返す;型セット等価性ではなく値等価性の絞り込みを意図している。

関係クエリはvalue-lattice.mdに従ってDynamic[T]の静的ファセットを扱わなければなりません(MUST)。動的な値が型付き境界を越えるかどうかを支配するのは、サブタイピング(subtyping)ではなく漸進的一貫性gradual consistencyです。

構造クエリはADR-2の拡張APIに必要なメンバーレベルのサーフェスを公開します。最小サーフェスは:

  • has_method(name)Rigor::Trinaryを返す。
  • method(name, scope:) — メソッドリフレクション結果または「利用不可」のセンチネルを返す。
  • membersstructural-interfaces-and-object-shapes.mdの構造化された形状を返す。
  • key_typevalue_typetuple_arityiterable_key_typeiterable_value_typeRigor::Typeまたは「適用不可」のセンチネルを返す。

メンバーを持つ型(オブジェクト形状、ケイパビリティロール、ハッシュ形状、レコード)はこれらの結果を埋める際にstructural-interfaces-and-object-shapes.mdのスキーマを参照しなければなりません(MUST)。

コンビネータはファクトリーモジュール(仮称Rigor::Type::Combinator)に置かれ、すべてのパブリック構築をnormalization.mdの決定論的な正規化ルールを通じてルーティングしなければなりません(MUST)。最小サーフェスは:

  • union(*types)intersect(*types)difference(left, right)complement_within(domain, type)
  • refine(base, predicate) — リファインメントを既存の型に付加する。predicateの正確な形状は適用されるリファインメントファミリーに依存する(rigor-extensions.mdを参照)。
  • dynamic(static_facet)Dynamic[T]ラッパーを構築する。dynamic(top)untypedの標準形でなければなりません(MUST)。

型インスタンスは変更するコンビネータを公開してはなりません(MUST NOT)。追加のリファインメントを持つ新しい型を返すインスタンスメソッド(仮称with_refinement)はADR-3の未解決問題1が解決されたら追加してもかまいません(MAY)。

ファクトリーの正規化ルートを迂回する直接コンストラクタ呼び出しはテストと移行のために予約された内部エスケープハッチです。本番コードパスはファクトリーを通じなければなりません(MUST)。

ラッパー(Dynamic[T]、リファインメントキャリア、UnionIntersectionDifferenceComplement、ジェネリック位置キャリア)は基底クラスを継承するのではなく、内部のRigor::Type参照を保持しなければなりません(MUST)。振る舞いは内部型に以下に従って委譲されます:

  • Dynamic[T]についてはvalue-lattice.mdの動的起源代数。
  • 負形式と差分形式についてはtype-operators.mdのコンビネータ代数。
  • リファインメントキャリアについてはrigor-extensions.mdのリファインメント合成ルール。
  • ジェネリック位置キャリアについてはvalue-lattice.mdのジェネリックスロット保全ルール。

ラッパーはケイパビリティと射影クエリを内部型に転送してから独自の貢献を適用しなければなりません(MUST)。ラッパーは転送中に来歴を暗黙に除去してはなりません(MUST NOT)(例えば、Dynamic[T]は返す値に動的起源の来歴を記録し続けなければなりません)。

すべての型インスタンスは以下を公開しなければなりません(MUST):

  • describe(verbosity) — 診断表示ルールに従った文字列を返す。実装はdiagnostic-policy.mdDynamic[T]ファミリーの例外を含む)、type-operators.md(否定ファクトと演算子省略ルール)、structural-interfaces-and-object-shapes.mdrbs-erasure.md(ハッシュ形状とタプル表示)を遵守しなければなりません(MUST)。
  • erase_to_rbsrbs-erasure.mdに従った保守的なRBS消去を返す。消去は証明された型以上に広くなければならず(MUST)、有効なRBS構文でなければなりません(MUST)。
  • normalize — 冪等でなければなりません(MUST)。すでに正規化された型はselfを返さなければなりません(MUST)。ファクトリールート外で構築された型は、同じ入力に対してファクトリーが生成するのと同じインスタンスに正規化されなければなりません(MUST)。
  • traverse(&block) — コンビネータとラッパーの内部型参照を歩き、各内部型を決定論的な順序でブロックにyieldします。リーフ型はno-opとしてtraverseを実装してもかまいません(MAY)。
  • 上記の同一性と不変性セクションに従った構造的==eql?hash

inspectは開発の便宜のために存在してもかまいません(MAY)。inspectを診断サーフェスとして使用してはなりません(MUST NOT);describe(verbosity)が診断と説明の拘束契約です。

Rubyモジュールのレイアウトは上記の契約に必要な粒度で固定されています。名前はプレースホルダーであり、実装中に変更されるかもしれません(MAY)。

  • Rigor::Typeはドキュメントのみのモジュールであり、ダックタイプ契約を名付けるものでなければなりません(MUST)。具体的な型クラスはRigor::Typeを継承してはならず(MUST NOT)、振る舞いを得るためにRigor::Typeincludeしてはなりません(MUST NOT)。ミックスインは狭いトレイト的な共有に使用してもかまいませんが(MAY)、部分型関係を表すための継承の代わりとして使用してはなりません(MUST NOT)。
  • 具体的な型クラスはRigor::Type::*以下に置かれます。正確なリストはdocs/adr/3-type-representation.mdの未解決問題1に依存します。
  • Rigor::Trinaryは型ネームスペースとは別のトップレベル値オブジェクトです。制御フロー解析、プラグインのスコープクエリ、および三値確実性を返すその他のサーフェスと共有されます。
  • コンビネータファクトリー(仮称Rigor::Type::Combinator)は正規化された構築のエントリーポイントです。直接クラスコンストラクタは本番コードパスで使用してはなりません(MUST NOT)。

sig/rigor.rbsはサーフェスが安定したらここで説明するパブリックサーフェスと一貫した状態に保たれなければなりません(MUST)。ADR-3で追跡される最初の縦断的スライスは、対応するRBSシグネチャを導入する場所です。

このドキュメントの契約は、implementation-expectations.mdと同じ意味で、メジャーバージョン内で安定しています。以下も追加的に安定しています:

  • ケイパビリティ述語・リファインメント射影・メタ操作のリスト。
  • subtype_ofacceptsの結果値オブジェクトの形状。
  • ファクトリー正規化ルーティング。
  • ラッパー合成ルール。

以下はADR-3が昇格させるまで安定性契約の外です:

  • 定数スカラー/オブジェクトキャリア形状(ADR-3の未解決問題1)。
  • 三値返却メソッドの命名規約(ADR-3の未解決問題2)。
  • 型仕様が要求するもの以外のRigor::Type::*以下の具体的なクラスの正確なカタログ。

プラグイン作成者とエンジンコンシューマーは、リストされた安定契約を拘束力があるものとして扱い、リストされた不安定な項目は最初の縦断的スライス中に精緻化の対象とされることを理解しなければなりません(MUST)。

© 2026 TypedDuck. Licensed under CC BY-SA 4.0.