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

go/types: publish Error.{Start,End} fields

新規提案

要約

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

概要

go/types パッケージの型エラーを表す types.Error 構造体に、エラーの原因となった式の開始位置 Start と終了位置 End を公開フィールドとして追加する提案です。位置情報は内部ではすでに記録されているため、これを外から使えるようにするのが目的です。

ステータス変更

(新規) → active
2025年2月に Alan Donovan(@adonovan)氏が提案しました。2026年11月に @mrkfrmn 氏が「エラーの他の要素と同じく位置の安定性を保証しないのであれば問題はない」と賛成し、同月12日に @aclements 氏がproposal review groupを代表して active 列に追加しました。これで週次のproposal review meetingで正式に審査されます。追加の経緯について、issue上に明示的な説明はありません。考えられる理由は、gopls(Go公式の言語サーバー)やx/toolsでワークアラウンドを維持する負担が大きいことと、変更が小さく後方互換性の問題が少ないことです。

技術的背景

現状の問題点

#42290 の対応として、Go 1.16 から go/types はエラーごとに3つの位置(start、pos、end)を内部で記録しています。ただし公開されているのは Pos だけで、start と end は非公開フィールドのままです。
そのためx/toolsやgoplsは、主に次の2つのワークアラウンドに頼っています。

  • 非公開フィールドを無理に読み出す
  • ソースコードのテキストからヒューリスティック(経験則による推測)で終了位置を推測する
    提案者自身もこれらを「unsavory hacks(好ましくないハック)」と呼んでいます。#42290 には推測が外れる例も挙がっています。var _ = int(1) + int64(1) では右辺の式全体が型不一致の原因ですが、goplsは int(1) の部分だけに下線を引いてしまいます。

提案された解決策

type Error struct {
	Fset       *token.FileSet // Pos を解釈するための FileSet
	// 不変条件: Start <= Pos < End || Start == Pos == End
	Pos        token.Pos      // エラー位置
	Start, End token.Pos      // エラーを含む式の開始・終了位置(新規)
	Msg        string
	Soft       bool
}

Start と End は、エラーの原因となった式の範囲を表します。Pos は従来どおりエラーの代表位置で、通常はこの範囲の中に入ります。範囲が分からない場合は、3つとも同じ値になります。

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

  • エディタでの正確な表示: goplsなどのLSPサーバーが、エラーの原因となった式全体に正確に波線を引けるようになります。
  • 静的解析ツールの簡素化: 型エラーを扱うアナライザーで、エラー範囲から対応するASTノード(抽象構文木の節点)を確実に特定できます。修正候補(quick fix)の生成もより正確になります。関連する CL 650217 では、goplsの型エラー用アナライザーをCursorで簡素化する作業が進んでいます。
  • サードパーティツールの保守性向上: リンターやコード生成ツールが、非公開フィールドの読み出しやソーステキストの推測に頼らずに済みます。Goのバージョンが上がっても壊れにくくなります。

コード例

// Before: Pos しか使えないため、終了位置はソースから推測するしかない
if terr, ok := err.(types.Error); ok {
	start := terr.Pos
	end := guessEndFromSource(src, start) // ヒューリスティック。外れることがある
	report(start, end, terr.Msg)
}
// After: 型チェッカーが記録した範囲をそのまま使える
if terr, ok := err.(types.Error); ok {
	report(terr.Start, terr.End, terr.Msg)
}

議論のハイライト

  • この機能は #42290(Go 1.16、2020年)で、Robert Griesemer 氏とgoplsチームが検討を始めたものです。当時は「エラーコードの追加」と「開始・終了位置の追加」の2つが計画されましたが、APIの形が決まらず、どちらも非公開フィールドとして実装されました(CL 265250)。
  • この提案は内部にすでにある情報を公開するだけです。型チェッカーの動作は変わらないため、実装コストと互換性リスクは小さいと考えられます。
  • 構造体に Start <= Pos < End || Start == Pos == End という不変条件を明記し、3つの位置の関係をはっきりさせています。
  • @mrkfrmn 氏は、エラーメッセージと同様に、エラー位置の正確な値も将来のバージョンで変わりうる(安定性を保証しない)ことを前提に賛成しました。ドキュメントにもこの点が明記される可能性があります。
  • 提案は2025年2月に出され、約1年9か月後にactive入りしました。この間に大きな反対意見は出ていません。

関連リンク