gotypesalias GODEBUG設定が完全に削除され、go/typesは常にAlias型ノードを生成するようになった
go/types
概要
Go 1.22で導入された gotypesalias GODEBUG 設定が完全に削除された。これにより、パッケージ
go/types は GODEBUG の設定値に関わらず、常に
エイリアス宣言に対して
Alias 型ノードを生成するようになる。
導入経緯
golang/go#76472 にて、Go 1.26のリリースノートで
Go 1.27での gotypesalias および asynctimerchan の2つの GODEBUG フラグ削除を事前告知する
ことが提案された。提案はレビュー会議で "active" 入りののち "likely accept" とされ、最終的に
反対意見なく "accepted" となった。Go 1.26でリリースノートへの事前告知が行われ、実際のフラグ
削除は本項目の対象であるGo 1.27で実施されている。
議論のハイライト
- 提案は関連する golang/go#76163(GODEBUGフラグ
削除の一般的なポリシー)に沿った運用の一環として提出された。 go/types・types2側の削除は CL 736441
(go/types, types2: remove support for gotypesalias GODEBUG flag)で行われた。- 削除に合わせて、明示的に
gotypesaliasを設定していた呼び出し側([x/tools]など)の
設定除去も CL 733880 で行われている。
使用例
Before
package main
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
)
func main() {
const src = `package p
type A = int
`
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)
}
obj := pkg.Scope().Lookup("A")
// Go 1.26以前、環境変数 GODEBUG=gotypesalias=0 を設定した場合は
// エイリアス宣言でも *types.Alias ではなく解決済みの型が返っていた。
fmt.Printf("%T\n", obj.Type())
}
After
package main
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
)
func main() {
const src = `package p
type A = int
`
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)
}
obj := pkg.Scope().Lookup("A")
// Go 1.27では GODEBUG=gotypesalias の値に関わらず常に *types.Alias が返る。
fmt.Printf("%T\n", obj.Type())
}
移行時の注意
gotypesalias の既定値はGo 1.23以降すでに 1(Aliasノードを生成する挙動)になっていたため、
多くの利用者には影響がない。ただし、環境変数や go.mod の godebug ディレクティブで
明示的に gotypesalias=0 を指定し、旧挙動(エイリアス宣言を *types.Alias として表現しない
挙動)に固定していたコードは、Go 1.27では設定が無効化されるため、常に *types.Alias を
前提としたコードに移行する必要がある。型スイッチや型アサーションで *types.Alias を
考慮していないコードは、types.Unalias を通して
非エイリアス型に正規化することを検討するとよい。
実装解説
go/types は cmd/compile/internal/types2
から自動生成されるパッケージであり、型チェッカーの実体は types2 側にある。
decl.go
のエイリアス宣言処理は if tdecl.Alias { ... alias := check.newAlias(obj, nil) ... } という
無条件の分岐になっており、GODEBUG の値を参照する分岐は存在しない
(実際に types2/go/types 配下を検索しても gotypesalias への参照はない)。
Alias 型自体の定義と、非エイリアス型への正規化を行う
Unalias 関数は
go/types/alias.go にある。Unalias は *Alias の Rhs(右辺)をたどり、最初に現れる
非エイリアス型を返す実装になっており、GODEBUG 設定の有無に関係なく利用できる。