Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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/vetgo/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/vetgo/typesパッケージからのexact.Valueの情報を正しく処理できるようにすることです。

  1. Package.valuesマップの型変更:
    • 以前はmap[ast.Expr]interface{}だったPackage.valuesマップが、map[ast.Expr]ExactValueに変更されました。これは、go/typesパッケージが式の値としてinterface{}ではなく、より具体的なexact.Valueを返すようになったためです。
  2. exprFnのシグネチャ変更:
    • go/types.Config.Checkに渡されるexprFnのシグネチャが、val interface{}からval exact.Valueに変更されました。これにより、cmd/vetgo/typesから直接exact.Valueを受け取れるようになります。
  3. ExactValueインターフェースの導入:
    • src/cmd/vet/types.goExactValueインターフェースが導入されました。これはexact.Valueのスタブであり、Kind()String()メソッドを持ちます。これにより、cmd/vetgo/exactパッケージに直接依存することなく、exact.Valueの振る舞いを模倣できます。
    • src/cmd/vet/typestub.goにも同様にExactValueインターフェースが追加されましたが、こちらはスタブ実装のためメソッドは持ちません。これは、cmd/vetがビルドされる際に、実際のexact.Valueが利用できない環境でもコンパイルが通るようにするためです。
  4. matchArgTypeでのexact.Kindの使用:
    • src/cmd/vet/types.gomatchArgType関数内で、types.UntypedFloatの場合の処理が変更されました。以前はf.pkg.values[arg].(type)で具体的なGoの数値型(int, int8など)に型アサーションしていましたが、これがf.pkg.values[arg].Kind()を使ってexact.Intかどうかをチェックするように変更されました。これは、exact.Valueがその値の種類をexact.Kindで表現するためです。

これらの変更により、cmd/vetgo/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.ValueKind()メソッドとString()メソッドを模倣しています。これは、cmd/vetgo/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/vetgo/typesパッケージの進化に対応し、より正確な型情報に基づいて静的解析を実行できるようになりました。

関連リンク

参考にした情報源リンク

  • Go言語のgo/typesパッケージに関する公式ドキュメントやGoブログの関連記事
  • Go言語のgo/exactパッケージに関する公式ドキュメントやGoブログの関連記事
  • go vetツールの使用方法と機能に関するGo公式ドキュメント
  • Go言語のAST(抽象構文木)に関する情報
  • Go言語の型システムに関する一般的な情報