メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

#79802active

go/parser: add deprecated func ResolveFile(\\*File)

新規提案

要約

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

概要

go/parser パッケージに、非推奨の識別子解決(オブジェクト解決)処理を後から適用できる関数 ResolveFile(*ast.File) を追加するproposal。SkipObjectResolution モードで高速化した後も、旧来の ast.Ident.Obj フィールドへのアクセスが必要な場面で使えるようにする。

ステータス変更

(なし)active
2026年6月17日のProposal Review Meeting(@cherrymui、@griesemer、@ianlancetaylor、@neild 参加)にてactiveカラムに追加され、週次レビューの対象となった。「added to minutes」とのみ記録されており、現時点では合意待ちの議論段階にある。

技術的背景

現状の問題点

Go 1.xの go/parser は、デフォルトで構文解析と同時に「レガシーオブジェクト解決」を行う。これは ast.Ident.Obj(識別子から宣言へのポインタ)と ast.File.Scope を埋める処理で、#46485 で追加された SkipObjectResolution フラグを使うと、この処理をスキップして大幅な高速化(20〜40%程度)が得られる。
しかし #52463 でこのAPIは正式に非推奨となり、ユーザーは go/types への移行を求められている。移行が非自明なケースが存在する。

  • ドキュメント生成ツールなど、型チェックが不要だが識別子の参照先を辿りたいツール
  • goplsのように、内部では SkipObjectResolution で高速に処理しつつ、外部に提供するAPIでは既存のアナライザーに対してオブジェクト解決済みのASTを返す義務があるケース
    後者の具体例としてgoplsが挙げられている。goplsは x/tools/gopls/internal/cache/parsego.(*File).Resolve() という独自の解決関数をコピー実装として保持しており、標準ライブラリの内部実装との重複・乖離リスクが生じている。

提案された解決策

go/parser パッケージに新しい公開関数を追加する。

package parser
// ResolveFile はパーサーのレガシー ast.Ident-to-ast.Object 解決を
// 指定ファイルの構文ツリーに適用する。
// SkipObjectResolution モードフラグでスキップされる処理と同じ操作で、冪等性を持つ。
//
// Deprecated: ast.Object は新しい設計では使用しないこと。代わりに go/types を使う。
// この関数は、デフォルトでレガシーオブジェクト解決を無効にしているが、
// 状況によって必要とするアプリケーションの移行を容易にするために提供される。
func ResolveFile(*ast.File)

冪等性と遅延実行を保証するため、ast.Filesync.Once を追加して解決処理をガードする必要があると提案者(@findleyr)は指摘している。

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

SkipObjectResolution による高速化と、必要な場面でのレガシーAPIへの対応を、外部の重複実装を持たずに両立できるようになる。

コード例

// Before: SkipObjectResolutionを使うと後からオブジェクト解決できない
f, err := parser.ParseFile(fset, "example.go", src, parser.SkipObjectResolution)
// f.Scope == nil, idents[i].Obj == nil のまま
// → 独自にオブジェクト解決ロジックを再実装する必要があった
// After: 必要なタイミングでResolveFileを呼べる
f, err := parser.ParseFile(fset, "example.go", src, parser.SkipObjectResolution)
// ... 高速処理を行う ...
parser.ResolveFile(f) // 遅延・冪等: 必要な時だけ解決する
// f.Scope, ident.Obj が利用可能になる

議論のハイライト

  • goplsの重複実装問題: goplsが内部に parsego.(*File).Resolve() を独自保持しており、これが標準ライブラリとの一貫性リスクを生んでいる点が主な動機
  • 冪等性の実現方法: sync.Onceast.File に追加して解決処理をガードする必要があり、ast パッケージにも変更が波及する
  • 「非推奨」関数を追加する逆説: この関数自体に Deprecated ドキュメントを付ける設計で、移行期間中のブリッジとして位置付けている点が設計上のユニークな特徴
  • 移行困難ケースの実在: #79614 で報告されたように、go/doc.NewFromFiles の内部変更により ast.Ident.Obj を使っていた既存ツールが突然壊れたケースがあり、即座に go/types へ移行できない現実がある
  • #45104 との関連: 2021年にも同様の提案(オブジェクト解決を独立したAPIとして公開する)がなされていたが、当時は非推奨化の議論と同時並行だったため未実現のまま

関連リンク