[インデックス 16297] ファイルの概要
このドキュメントは、Go言語のツールであるcmd/vet
に対するコミットd73452b30f777152895002792cfd5751df642ea4
の詳細な技術解説を提供します。このコミットは、go/types
パッケージの変更に対応し、exact.Value
の使用(またはスタブ化)を修正するものです。
コミット
- コミットハッシュ:
d73452b30f777152895002792cfd5751df642ea4
- 作者: Rob Pike r@golang.org
- 日付: Tue May 14 15:49:58 2013 -0700
- コミットメッセージ: cmd/vet: fix for changes to go/types package. Need to use (or stub) exact.Value.
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d73452b30f777152895002792cfd5751df642ea4
元コミット内容
cmd/vet: fix for changes to go/types package
Need to use (or stub) exact.Value.
R=gri
CC=golang-dev
https://golang.org/cl/9126043
変更の背景
このコミットは、Go言語の型システムを扱うgo/types
パッケージの内部的な変更に対応するために行われました。特に、数値リテラルの正確な値を表現するために導入されたexact.Value
型が、go/types
パッケージのAPIの一部として使用されるようになったことが背景にあります。
cmd/vet
は、Goプログラムの潜在的なバグや疑わしい構造を検出するための静的解析ツールです。このツールは、プログラムの型情報を利用して解析を行うため、go/types
パッケージに強く依存しています。go/types
パッケージがexact.Value
を返すように変更されたことで、cmd/vet
もその変更に適応する必要が生じました。
具体的には、go/types
パッケージが式(ast.Expr
)の評価結果として、以前はinterface{}
で表現されていた値を、より具体的なexact.Value
型で返すようになったため、cmd/vet
はこれらの正確な値を正しく処理できるように更新される必要がありました。また、cmd/vet
がgo/types
パッケージに直接依存しないように、go/types.Type
と同様にexact.Value
も内部でスタブ化(インターフェースとして定義)する必要がありました。
前提知識の解説
go vet
ツール
go vet
は、Go言語のソースコードを静的に解析し、潜在的なバグや疑わしい構造を報告するツールです。例えば、printf
フォーマット文字列と引数の不一致、到達不能なコード、構造体タグの誤りなどを検出します。開発者がコードの品質を向上させ、一般的な間違いを避けるのに役立ちます。
go/types
パッケージ
go/types
パッケージは、Goプログラムの型情報を扱うための標準ライブラリです。Goのソースコードを解析し、各識別子や式の型、スコープ、定義などを詳細に提供します。コンパイラ、リンター、IDEなどのツールがGoコードを理解し、分析するために不可欠なパッケージです。このパッケージは、Goの型システムを正確にモデル化しており、型チェックや型推論などの機能を提供します。
go/exact
パッケージ
go/exact
パッケージは、Go言語の数値リテラル(整数、浮動小数点数、複素数)の正確な値を表現するためのパッケージです。Goの数値リテラルは、コンパイル時に型付けされていない「untyped」な状態を持つことができ、その精度は任意です。exact.Value
型は、このようなuntypedな数値リテラルの値を、精度を失うことなく保持するために使用されます。これにより、コンパイル時の定数評価や型推論において、正確な数値計算が可能になります。
ast.Expr
ast.Expr
は、Go言語の抽象構文木(AST: Abstract Syntax Tree)における「式(Expression)」を表すインターフェースです。Goのソースコードは、go/ast
パッケージによってASTにパースされ、プログラムの構造がツリー形式で表現されます。ast.Expr
は、変数参照、関数呼び出し、リテラル、演算など、値を持つあらゆるコード要素を指します。cmd/vet
のような静的解析ツールは、このASTを走査してコードの構造を分析します。
技術的詳細
このコミットの主要な変更点は、cmd/vet
がgo/types
パッケージからのexact.Value
の情報を正しく処理できるようにすることです。
Package.values
マップの型変更:- 以前は
map[ast.Expr]interface{}
だったPackage.values
マップが、map[ast.Expr]ExactValue
に変更されました。これは、go/types
パッケージが式の値としてinterface{}
ではなく、より具体的なexact.Value
を返すようになったためです。
- 以前は
exprFn
のシグネチャ変更:go/types.Config.Check
に渡されるexprFn
のシグネチャが、val interface{}
からval exact.Value
に変更されました。これにより、cmd/vet
はgo/types
から直接exact.Value
を受け取れるようになります。
ExactValue
インターフェースの導入:src/cmd/vet/types.go
にExactValue
インターフェースが導入されました。これはexact.Value
のスタブであり、Kind()
とString()
メソッドを持ちます。これにより、cmd/vet
はgo/exact
パッケージに直接依存することなく、exact.Value
の振る舞いを模倣できます。src/cmd/vet/typestub.go
にも同様にExactValue
インターフェースが追加されましたが、こちらはスタブ実装のためメソッドは持ちません。これは、cmd/vet
がビルドされる際に、実際のexact.Value
が利用できない環境でもコンパイルが通るようにするためです。
matchArgType
でのexact.Kind
の使用:src/cmd/vet/types.go
のmatchArgType
関数内で、types.UntypedFloat
の場合の処理が変更されました。以前はf.pkg.values[arg].(type)
で具体的なGoの数値型(int
,int8
など)に型アサーションしていましたが、これがf.pkg.values[arg].Kind()
を使ってexact.Int
かどうかをチェックするように変更されました。これは、exact.Value
がその値の種類をexact.Kind
で表現するためです。
これらの変更により、cmd/vet
はgo/types
パッケージの最新のAPIと互換性を保ちつつ、数値リテラルの正確な値をより適切に処理できるようになりました。
コアとなるコードの変更箇所
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
index 2fefa0b47a..b3d12d09f9 100644
--- a/src/cmd/vet/main.go
+++ b/src/cmd/vet/main.go
@@ -179,7 +179,7 @@ func doPackageDir(directory string) {
type Package struct {
types map[ast.Expr]Type
- values map[ast.Expr]interface{}
+ values map[ast.Expr]ExactValue
files []*File
}
diff --git a/src/cmd/vet/types.go b/src/cmd/vet/types.go
index 75f195b0fb..46e4d94807 100644
--- a/src/cmd/vet/types.go
+++ b/src/cmd/vet/types.go
@@ -14,19 +14,27 @@ import (
"go/ast"
"go/token"
+ "code.google.com/p/go.exp/go/exact"
"code.google.com/p/go.exp/go/types"
)
-// Type is equivalent to go/types.Type. Repeating it here allows us to avoid
-// depending on the go/types package.
+// Type is equivalent to types.Type. Repeating it here allows us to avoid
+// having main depend on the go/types package.
type Type interface {
String() string
}
+// ExactValue is equivalent to exact.Value. Repeating it here allows us to
+// avoid having main depend on the go/exact package.
+type ExactValue interface {
+ Kind() exact.Kind
+ String() string
+}
+
func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
pkg.types = make(map[ast.Expr]Type)
- pkg.values = make(map[ast.Expr]interface{})
- exprFn := func(x ast.Expr, typ types.Type, val interface{}) {
+ pkg.values = make(map[ast.Expr]ExactValue)
+ exprFn := func(x ast.Expr, typ types.Type, val exact.Value) {
pkg.types[x] = typ
if val != nil {
pkg.values[x] = val
@@ -93,10 +101,8 @@ func (f *File) matchArgType(t printfArgType, arg ast.Expr) bool {
return t&argFloat != 0
case types.UntypedFloat:
// If it's integral, we can use an int format.
- switch f.pkg.values[arg].(type) {
- case int, int8, int16, int32, int64:
- return t&(argInt|argFloat) != 0
- case uint, uint8, uint16, uint32, uint64:
+ switch f.pkg.values[arg].Kind() {
+ case exact.Int:
return t&(argInt|argFloat) != 0
}
return t&argFloat != 0
diff --git a/src/cmd/vet/typestub.go b/src/cmd/vet/typestub.go
index fabbbe19dd..74a3b13e26 100644
--- a/src/cmd/vet/typestub.go
+++ b/src/cmd/vet/typestub.go
@@ -15,11 +15,16 @@ import (
)
// Type is equivalent to go/types.Type. Repeating it here allows us to avoid
-// depending on the go/types package.
+// having main depend on the go/types package.
type Type interface {
String() string
}
+// ExactValue is a stub for exact.Value. Stubbing it here allows us to
+// avoid having main depend on the go/exact package.
+type ExactValue interface {
+}
+
func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
return nil
}
コアとなるコードの解説
src/cmd/vet/main.go
Package
構造体のvalues
フィールドの型がmap[ast.Expr]interface{}
からmap[ast.Expr]ExactValue
に変更されました。これは、go/types
パッケージが式の値としてexact.Value
を返すようになったため、cmd/vet
がその新しい型を保持できるようにするためです。
src/cmd/vet/types.go
code.google.com/p/go.exp/go/exact
パッケージがインポートされました。これにより、exact.Value
型とその関連機能を利用できるようになります。ExactValue
インターフェースが新しく定義されました。このインターフェースは、exact.Value
のKind()
メソッドとString()
メソッドを模倣しています。これは、cmd/vet
がgo/exact
パッケージに直接依存することなく、exact.Value
の振る舞いを抽象化して利用するためのパターンです。Package.check
メソッド内のexprFn
の定義が変更されました。val
引数の型がinterface{}
からexact.Value
に変更され、go/types.Config.Check
からのコールバックがexact.Value
を直接渡すようになりました。matchArgType
関数内のtypes.UntypedFloat
のケースで、値の型チェックロジックが変更されました。以前はswitch f.pkg.values[arg].(type)
でGoの組み込み型に型アサーションしていましたが、新しいコードではswitch f.pkg.values[arg].Kind()
を使用してexact.Int
かどうかをチェックしています。これは、exact.Value
がその値の種類をexact.Kind
列挙型で表現するためです。これにより、untyped floatが整数として扱えるかどうかを正確に判断できるようになりました。
src/cmd/vet/typestub.go
ExactValue
インターフェースが追加されました。このファイルは、cmd/vet
がビルドされる際に、実際のgo/exact
パッケージが利用できない環境(例えば、クロスコンパイル環境や、go/exact
がまだ安定版ではない時期)でもコンパイルが通るようにするためのスタブを提供します。このスタブインターフェースはメソッドを持たず、単に型が存在することを示す役割を果たします。
これらの変更により、cmd/vet
はgo/types
パッケージの進化に対応し、より正確な型情報に基づいて静的解析を実行できるようになりました。
関連リンク
参考にした情報源リンク
- Go言語の
go/types
パッケージに関する公式ドキュメントやGoブログの関連記事 - Go言語の
go/exact
パッケージに関する公式ドキュメントやGoブログの関連記事 go vet
ツールの使用方法と機能に関するGo公式ドキュメント- Go言語のAST(抽象構文木)に関する情報
- Go言語の型システムに関する一般的な情報