go/analysis: publish x/tools/go/analysis types in the standard library
要約
概要
golang.org/x/tools/go/analysis パッケージの型(Analyzer、Pass、Diagnostic など)を、標準ライブラリの新パッケージ go/analysis として公開する提案です。x/tools 側の型は標準ライブラリの型への型エイリアスに置き換えます。これにより、標準ライブラリ(std)、cmd、x/tools の3者が同一の型を共有できるようになります。
ステータス変更
(新規) → active
2026年10月28日のProposal Review Meetingで議論され、翌29日に @aclements がactive列への追加を告知しました。会議では「std が x/tools を vendoring していることに起因する技術的な事情がなくても、これは正しい判断か」が問われました。結論は「Yes」です。本当の目的は解析機能を go test に統合すること(#82464)ですが、go/analysis はコミュニティでも std 内部でも広く使われているので、std の go/ ツリーに置くのは自然だと判断されました。
技術的背景
現状の問題点
現在、GOROOT/src/cmd には x/tools/go/analysis のコピーが vendoring されています。vendoring とは、依存パッケージをリポジトリ内に複製して取り込むことです。go/analysis は、アナライザー(リンター)と cmd/vet などのドライバーツールをつなぐインターフェースを定義しています。
関連提案 #82464 では、ワークスペース内で指定したユーザー定義アナライザーを go test が実行できるようにすることを目指しています。そのためには、go test が cmd/vet のようなツールをその場でビルドする必要があります。しかし、ユーザーのアナライザーは本物の golang.org/x/tools/go/analysis.Analyzer を使っており、vendor 内のコピーとは別の型として扱われます。結果として両者は互換性がなく、一緒にリンクできません。
提案された解決策
- 新パッケージ
go/analysisを標準ライブラリに追加し、以下の型を公開する:Analyzer,Diagnostic,Fact,Module,ModuleError,ObjectFact,PackageFact,Pass,Range,RelatedInformation,SuggestedFix,TextEdit Validate関数とCycleInRequiresGraphErrorは対象外- x/tools 側の各型は
type Analyzer = analysis.Analyzerのようなエイリアスに置き換える - 型宣言は一切変更しない。v2 として API を整理する機会ではないため、レビューの論点は「実施するか否か」だけ
- まず
GOEXPERIMENT=goanalysisの下で実装する。新しい std パッケージも x/tools のエイリアスも、このフラグを有効にしたときだけ存在するので、完全に元に戻せる
これによって何ができるようになるか
go testでのカスタムアナライザー実行(#82464)の前提が整う: プロジェクト固有の不変条件チェックや、自作ライブラリの API 誤用を検出するアナライザーを、go testの編集・テストのループの中で実行できるようになる見込みです。- std と x/tools で型の不一致がなくなる: vendor コピーとの型の食い違いを気にせずに、std 内のツールとサードパーティのアナライザーを組み合わせられます。
- 既存アナライザーはそのまま動く: x/tools の型がエイリアスになるので、既存のアナライザーのコードを書き換える必要はありません。
コード例
// Before: アナライザーは x/tools の型で定義する
import "golang.org/x/tools/go/analysis"
var Analyzer = &analysis.Analyzer{
Name: "mycheck",
Doc: "reports misuse of mypkg API",
Run: run,
}
// cmd 内に vendoring された analysis.Analyzer とは別の型になり、
// go test が生成するドライバーとはリンクできない
// After: std の go/analysis を直接使える(x/tools の型はその別名)
import "go/analysis" // GOEXPERIMENT=goanalysis 下で
var Analyzer = &analysis.Analyzer{
Name: "mycheck",
Doc: "reports misuse of mypkg API",
Run: run,
}
// x/tools 版をそのまま使っていても、
// golang.org/x/tools/go/analysis.Analyzer == go/analysis.Analyzer(同一の型)
議論のハイライト
- 型宣言は凍結: API は長年安定しています。互換性を守るため宣言は変えず、v2 として整理する機会にはしない、と提案者 @adonovan が明言しました。
- std に置く必然性: 会議では「vendoring 問題は std 特有の事情ではないか」という疑問が出ました。本当の動機は
go testへの統合だと認めたうえで、広く使われている基盤 API なので std のgo/配下に置くのは妥当、という結論になりました。 - モジュールをまたぐエイリアスの互換性: @mateusz834 が指摘しました。古い x/tools と新しい Go を組み合わせていた場合、x/tools を更新すると、以前は別だった2つの型が同一になります。その結果、両方の型を並べた型 switch がコンパイルエラーになりえます。@adonovan は、そうしたコードはまれで、
reflect.Type.Stringの値が変わる程度だと応じました。このやり取りは off-topic として非表示にされています。 - go doc でのエイリアス表示:
go docではエイリアスの表示が貧弱になることが懸念されました。x/tools 側のドキュメントをできる限り良い状態に保つと @adonovan が約束しています。 - 段階的な導入: GOEXPERIMENT を使うことで、可逆的に試しながら設計を検討する方針です。