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

Go Proposal Weekly Digest

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

破壊的変更

gotypesalias GODEBUG設定が完全に削除され、go/typesは常にAlias型ノードを生成するようになった

go/types

この項目の注釈は AI により生成されており、誤りを含む場合があります。
使用例のコンパイル検証: 検証済み

概要

Go 1.22で導入された gotypesalias GODEBUG 設定が完全に削除された。これにより、パッケージ
go/typesGODEBUG の設定値に関わらず、常に
エイリアス宣言に対して
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/typestypes2 側の削除は 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.modgodebug ディレクティブで
明示的に gotypesalias=0 を指定し、旧挙動(エイリアス宣言を *types.Alias として表現しない
挙動)に固定していたコードは、Go 1.27では設定が無効化されるため、常に *types.Alias
前提としたコードに移行する必要がある。型スイッチや型アサーションで *types.Alias
考慮していないコードは、types.Unalias を通して
非エイリアス型に正規化することを検討するとよい。

実装解説

go/typescmd/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*AliasRhs(右辺)をたどり、最初に現れる
非エイリアス型を返す実装になっており、GODEBUG 設定の有無に関係なく利用できる。

関連リンク