ジェネリクス

ジェネリクスはパラメータオーバーライドでは実現できないアイテムのパラメータ化を可能にします。以下のアイテムがジェネリクスをサポートしています。

  • 関数
  • モジュール
  • インターフェース
  • パッケージ
  • 構造体
  • ユニオン

それぞれのジェネリック定義はジェネリックパラメータ(T のような大文字1文字がよく使われます)を持ち、定義内で識別子や式として配置できます。ジェネリックパラメータはアイテムの識別子の後に ::<> を用いて宣言します。

各ジェネリックパラメータにはコロンの後に T: const のようなジェネリック境界が必要です。ジェネリック境界はどのような値をそのパラメータに渡すことができるかを示します。使用可能なジェネリック境界は以下の通りです。

  • const: 定数値を渡すことができる
  • type: 任意の型を渡すことができる
  • 名前付きプロトタイプ

名前付きプロトタイプは特別なジェネリック境界です。詳細は プロトタイプ を参照してください。

ジェネリクスを使用するためには ::<> を用いて実パラメータを与えます。実パラメータとしては数値リテラルと :: で連結された識別子を使用することができます。

さらに、実パラメータはジェネリクス定義位置から参照できなければなりません。例えば、モジュール名はプロジェクト全体から参照できるので、実パラメータとして使用できます。一方、ローカルパラメータは多くの場合、実パラメータとして使用できません。これはローカルパラメータがジェネリクス定義位置からは参照できない場合に発生します。

ジェネリック関数

module ModuleA {
    function FuncA::<T: const> (
        a: input logic<T>,
    ) -> logic<T> {
        return a + 1;
    }

    let _a: logic<10> = FuncA::<10>(1);
    let _b: logic<20> = FuncA::<20>(1);
}

ジェネリックモジュール/インターフェース

module ModuleA {
    inst u0: ModuleB::<ModuleC>;
    inst u1: ModuleB::<ModuleD>;
}

proto module ProtoA;

module ModuleB::<T: ProtoA> {
    inst u: T;
}

module ModuleC for ProtoA {}
module ModuleD for ProtoA {}

ジェネリックパッケージ

module ModuleA {
    const A: u32 = PackageA::<1>::X;
    const B: u32 = PackageA::<2>::X;
}

package PackageA::<T: const> {
    const X: u32 = T;
}

ジェネリック構造体

module ModuleA {
    type TypeA = i32;

    struct StructA::<T: type> {
        A: T,
    }

    // ローカルに定位された型が使用できています
    // これは `TypeA` が `StructA` の定義位置から参照できるためです
    var _a: StructA::<TypeA>          ;
    var _b: StructA::<PackageA::TypeB>;
    var _c: StructA::<PackageA::TypeC>;
}

package PackageA {
    type TypeB = u32;
    type TypeC = u64;
}