メインコンテンツへスキップ
#63477active

go/types.ImportFunc

新規提案

要約

AIによる要約であり、誤りを含む場合があります。

概要

go/types パッケージに、関数値をそのまま types.Importer インターフェースとして使えるアダプタ型 ImporterFunc を追加する提案です。net/http の http.HandlerFunc と同じ仕組みです。Issueのタイトルは ImportFunc ですが、本文で提案されている型名は ImporterFunc です。

ステータス変更

(新規) → active
2023年10月に @adonovan が提出しました。その直後に @rsc が「#47487(関数値を単一メソッドのインターフェースへ変換できるようにする言語変更)が承認されれば、この型は不要になる。それまでは各所の非公開実装でしのげばよい」とコメントし、議論はそこで止まっていました。その後 #47487 は2026年7月に declined(却下)となりました。言語側での解決がなくなったため、ライブラリ側で対応するこの提案が再び検討対象になり、2026年11月に proposal review meeting の active 列に追加されたと考えられます。

技術的背景

現状の問題点

型チェッカー(types.Config)には、import されたパッケージを解決するための Importer を渡す必要があります。

type Importer interface {
    Import(path string) (*Package, error)
}

実際のツールでは「パス → *types.Package」の対応表をすでに持っていることが多く、クロージャを1つ渡せば足ります。それでも Importer を満たすには毎回アダプタ型を自前で定義しなければなりません。提案者によると、golang.org/x/tools の中だけでも次の7箇所に、同じ importerFunc 型が重複して定義されています。

  • go/analysis/unitchecker(本体とテスト)
  • go/analysis/passes/cgocall
  • go/packages
  • gopls/internal/lsp/cache
  • internal/gcimporter のテスト
  • internal/refactor/inline のテスト

提案された解決策

// An ImporterFunc is an implementation of the single-method
// types.Importer interface based on a function value.
type ImporterFunc func(path string) (*types.Package, error)
func (f ImporterFunc) Import(path string) (*types.Package, error) { return f(path) }

これによって何ができるようになるか

  • 静的解析ツール: go/packages で読み込んだ依存パッケージのマップを引くクロージャを、そのまま types.Config.Importer に渡せます。
  • テストコード: テスト用に用意したパッケージを返すだけの簡単なインポータを、1行で書けます。
  • gopls や unitchecker などの基盤ツール: 重複しているアダプタ型を標準の型に置き換え、ボイラープレート(毎回書く定型コード)を減らせます。

コード例

// Before: パッケージごとにアダプタ型を自前で定義する
type importerFunc func(path string) (*types.Package, error)
func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }
conf := types.Config{
    Importer: importerFunc(func(path string) (*types.Package, error) {
        if p, ok := deps[path]; ok {
            return p, nil
        }
        return nil, fmt.Errorf("no package %q", path)
    }),
}
// After: 標準の型を使う
conf := types.Config{
    Importer: types.ImporterFunc(func(path string) (*types.Package, error) {
        if p, ok := deps[path]; ok {
            return p, nil
        }
        return nil, fmt.Errorf("no package %q", path)
    }),
}

議論のハイライト

  • ImporterFrom 版を求める意見(@mvdan): types.ImporterFrom を実装していると Import は呼ばれないため、vendor を考慮できる ImportFrom(path, dir, mode) 向けの ImporterFromFunc を追加すべきではないか、という提案がありました。garble でも同様の実装を使っているそうです。
  • 反論(@findleyr): 一般的なケースでは、go/packages などで読み込み済みのため、パスとパッケージの対応はすでに決まっています。そのため、単純な ImporterFunc の方が役に立つ場面が多いと述べました。
  • 言語変更待ち(@rsc): #47487 が承認されれば types.Importer(func...) と直接変換できるようになり、この型は不要になるとして、判断を先送りしました。
  • #47487 の却下: 関連する「interface literals」の提案(#25860)の方が有力だとされ、#47487 は2026年7月に却下されました。@adonovan は、WriterFunc のような標準のアダプタ型の追加は #25860 の結論が出るまで控えたいとも述べています。このため、今回の提案でも #25860 との関係が論点になる可能性があります。

関連リンク