新機能
go/types のTypeParamList・TypeList・InstanceにString()メソッドを追加し、デバッグ出力の可読性を改善する
go/types
この項目の注釈は AI により生成されており、誤りを含む場合があります。
使用例のコンパイル検証: 検証済み
概要
go/types パッケージの TypeParamList、TypeList、Instance の3型に String() string メソッドを追加する。いずれも fmt.Stringer を実装していなかったため、これまで log.Println や fmt.Printf("%v", ...) に渡すと内部の非公開フィールド(要素スライス)がリフレクション越しに整形できず、ポインタのhex表記で出力されていた。今回の追加により、それぞれの型が保持する要素の既存 String() を利用して読みやすい文字列表現を返すようになる。
導入経緯
Issue #79287 は、TypeParamList・TypeList・Instance を log.Println に渡すとhex表記になってしまい、ジェネリクス関連のデバッグが不便だという指摘から始まった。レビューでは「これらは要素の String メソッドを呼ぶだけで済むが、スライスが(非公開フィールドとして)隠れているため今日はきれいにフォーマットされない」との整理がなされ、大きな設計上の論点はないまま話が進んだ。
議論タイムライン
- 2026-05-13: Proposal Review Meetingで審議され、実装が既存要素の
String()を呼び出すだけの低リスクな変更であることから「likely accept」と判定された。 - 2026-05-21: 1週間反論が上がらず、正式に「accepted」となった。
議論のハイライト
TypeListには過去に一度String()が実装されたことがあったが(CL 346552)、正式なproposalを経ていなかったため後に削除された(Issue #50760)。今回はその再提案を兼ねている。TypeListとTypeParamListは対称的な設計を持つべきで、片方にだけString()があるのは不自然という点が共有されていた。- 実装は CL 780581 として
go/typesとcmd/compile/internal/types2の両方に提出された。
使用例
Before
package main
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
)
func main() {
const src = `package p
type Pair[K comparable, V any] struct {
Key K
Value V
}
`
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "p.go", src, 0)
if err != nil {
panic(err)
}
conf := types.Config{Importer: importer.Default()}
pkg, err := conf.Check("p", fset, []*ast.File{f}, nil)
if err != nil {
panic(err)
}
pair := pkg.Scope().Lookup("Pair").Type().(*types.Named)
tparams := pair.TypeParams() // *types.TypeParamList
fmt.Println(tparams) // &{[0xc0000... 0xc0000...]} のようなhex表記になる
}
After
package main
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
)
func main() {
const src = `package p
type Pair[K comparable, V any] struct {
Key K
Value V
}
`
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "p.go", src, 0)
if err != nil {
panic(err)
}
conf := types.Config{Importer: importer.Default()}
pkg, err := conf.Check("p", fset, []*ast.File{f}, nil)
if err != nil {
panic(err)
}
pair := pkg.Scope().Lookup("Pair").Type().(*types.Named)
tparams := pair.TypeParams() // *types.TypeParamList
fmt.Println(tparams) // [K, V] のように読みやすく出力される
}
実装解説
実装は生成元の src/cmd/compile/internal/types2/typelists.go を元に go generate で src/go/types/typelists.go が生成される構成になっている(コンパイラ内部の型チェッカーである types2 と、公開APIである go/types が同一ロジックを共有する)。
TypeParamList.StringとTypeList.Stringは、各要素に対してWriteType(&buf, elem, nil)を呼び出しながら[、,、]で連結するだけの実装になっている。TypeParamListの要素は*TypeParamであり、この経路では制約(constraint)は出力されず、宣言された型パラメータ名のみが書き出される。Instance.Stringはfmt.Sprintf("%s%s", inst.TypeArgs, inst.Type)という1行で、TypeArgs(*TypeList)の文字列表現とインスタンス化後の型の文字列表現を単純に連結しているだけである。