[インデックス 11446] ファイルの概要
このコミットは、Goコンパイラ(gc
)におけるエラーメッセージの改善に関するものです。具体的には、定数式が関わるエラーメッセージにおいて、その定数式の「元の」表現(例えば、time.Wednesday
のようなシンボリックな名前)をエラーメッセージに含めるように変更することで、ユーザーがより理解しやすいエラーメッセージを提供するように修正されています。
コミット
このコミットは、Goコンパイラが生成するエラーメッセージの品質を向上させることを目的としています。特に、定数式が型変換エラーなどの原因となる場合に、コンパイラがその定数式の内部的な値(例: 4
)ではなく、ソースコードで記述された元のシンボボリックな表現(例: time.Wednesday
)をエラーメッセージに表示するように修正します。これにより、開発者はエラーの原因をより迅速に特定できるようになります。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/21f1769519eb8eb50ed9600395073a2ed2f41971
元コミット内容
gc: use original constant expression in error messages.
Fixes #2768.
R=golang-dev, lvd, iant
CC=golang-dev, remy
https://golang.org/cl/5572081
変更の背景
この変更は、GoのIssue 2768を修正するために行われました。Issue 2768では、time.Wednesday
のような定数(この場合、time.Weekday
型の値)をint
型を期待する関数に渡した場合に、コンパイラが「cannot use 3 (type time.Weekday) as type int in function argument
」というエラーメッセージを出力していました。ここで問題となるのは、time.Wednesday
が内部的に数値の3
として表現されているにもかかわらず、ユーザーがソースコードで3
と直接記述したわけではない点です。
開発者にとって、3
という数値だけを見ても、それがtime.Wednesday
に由来するものだとすぐに理解するのは困難です。より良いエラーメッセージは、元の定数式であるtime.Wednesday
を明示的に示すことで、エラーの原因と修正方法をより明確にすることです。このコミットは、このような状況でコンパイラがより人間が理解しやすいエラーメッセージを生成するように改善することを目的としています。
同様の背景として、unsafe.Alignof(0)
のような式が使用されなかった場合に、以前は「4 not used
」のようなメッセージが表示されていました。これもまた、元の式unsafe.Alignof(0)
を表示する方が、開発者にとってより有益であるという考えに基づいています。
前提知識の解説
- Goコンパイラ (
gc
): Go言語の公式コンパイラです。ソースコードを機械語に変換する過程で、構文解析、型チェック、最適化など様々な処理を行います。エラーメッセージの生成もコンパイラの重要な機能の一つです。 - 定数式 (Constant Expression): コンパイル時に値が決定される式のことです。Goでは、数値、文字列、真偽値、およびそれらから派生する型付き定数などが含まれます。例えば、
100
、"hello"
、true
、time.Wednesday
などが定数式です。 - エラーメッセージ: コンパイラがソースコード内の問題(構文エラー、型エラーなど)を検出した際に、開発者にその問題を通知するために出力するメッセージです。エラーメッセージは、問題の特定と修正を助けるために、できるだけ具体的で分かりやすいものであるべきです。
unsafe.Alignof
: Goのunsafe
パッケージに含まれる関数で、引数の型のメモリ配置におけるアライメント(整列)要件をバイト単位で返します。通常、unsafe
パッケージは低レベルな操作や特定の最適化のために使用され、一般的なGoプログラミングではあまり使われません。time.Weekday
: Goのtime
パッケージで定義されている型で、曜日を表す定数(time.Sunday
,time.Monday
, ...,time.Saturday
)を持ちます。これらは内部的にはint
型の値として表現されますが、time.Weekday
型として扱われます。
技術的詳細
このコミットの技術的な核心は、Goコンパイラの内部で、定数式が処理される際にその「元の名前」または「元の表現」を保持するメカニズムを追加することにあります。
変更は主にsrc/cmd/gc/export.c
ファイルにあります。このファイルは、Goコンパイラのバックエンドの一部であり、シンボルや定数のエクスポート/インポートに関連する処理を扱います。
具体的には、importconst
関数内で、Node
構造体(コンパイラがコードの各要素を表現するために使用するデータ構造)にorig
フィールドを設定する行が追加されています。
n->orig = newname(s);
n
: 現在処理している定数式を表すNode
へのポインタ。orig
:Node
構造体に追加された新しいフィールドで、定数式の「元の名前」を保持するために使用されます。newname(s)
: シンボルs
から新しい名前(Node
)を作成する関数です。ここでs
は、例えばtime.Wednesday
のような定数のシンボルを表します。
この変更により、コンパイラは定数式の値だけでなく、その定数がソースコードでどのように記述されていたか(例: time.Wednesday
)という情報もNode
構造体内に保持できるようになります。後続のコンパイルフェーズ、特にエラーメッセージを生成する段階で、このorig
フィールドを参照することで、より意味のあるエラーメッセージを出力することが可能になります。
test/fixedbugs/bug381.go
ファイルは、この修正が正しく機能することを確認するためのテストケースです。このテストファイルは、unsafe.Alignof(0)
とf(time.Wednesday)
の2つのケースで、期待されるエラーメッセージが元の定数式を含む形になっていることを検証しています。
コアとなるコードの変更箇所
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -423,6 +423,7 @@ importconst(Sym *s, Type *t, Node *n)
*n1 = *n;
n = n1;
}
+ n->orig = newname(s);
n->sym = s;
declare(n, PEXTERN);
--- a/test/fixedbugs/bug381.go
+++ b/test/fixedbugs/bug381.go
@@ -7,14 +7,25 @@
// Issue 2276.
// Check that the error messages says
-// bug378.go:19: unsafe.Alignof(0) not used
+// bug381.go:29: unsafe.Alignof(0) not used
// and not
-// bug378.go:19: 4 not used
+// bug381.go:29: 4 not used
+
+// Issue 2768: previously got
+// bug381.go:30: cannot use 3 (type time.Weekday) as type int in function argument
+// want
+// bug381.go:30: cannot use time.Wednesday (type time.Weekday) as type int in function argument
package main
-import "unsafe"
+import (
+ "time"
+ "unsafe"
+)
+
+func f(int)
func main() {
unsafe.Alignof(0) // ERROR "unsafe\\.Alignof|value computed is not used"
+ f(time.Wednesday) // ERROR "time.Wednesday|incompatible type"
}
コアとなるコードの解説
src/cmd/gc/export.c
の変更
n->orig = newname(s);
の追加は、コンパイラの内部表現において、定数式の元のシンボリックな名前を保持するための重要なステップです。
Node
構造体: Goコンパイラは、ソースコードを抽象構文木(AST)として表現し、その各ノードをNode
構造体で表します。このNode
構造体には、式の種類、型、値などの情報が含まれます。orig
フィールド: このコミット以前は、定数式が処理されると、その値(例:time.Wednesday
の3
)は保持されても、元のシンボリックな名前は失われる可能性がありました。orig
フィールドは、この失われがちな情報を明示的に保持するために追加されました。newname(s)
:s
はシンボル(例えば、time.Wednesday
という名前のシンボル)を表します。newname(s)
は、このシンボルから新しいNode
を作成し、そのNode
が元の名前を表すようにします。このNode
がn->orig
に割り当てられることで、n
が表す定数式が、元のシンボルs
に由来するという関連付けが確立されます。
この変更により、コンパイラの後のフェーズ(特にエラー報告フェーズ)で、n
が表す定数式に関するエラーメッセージを生成する際に、n->orig
を参照することで、元のシンボリックな名前(例: time.Wednesday
)をエラーメッセージに含めることができるようになります。
test/fixedbugs/bug381.go
の変更
このテストファイルは、修正が意図通りに機能することを確認するためのものです。
unsafe.Alignof(0)
: この行は、unsafe.Alignof
の戻り値が使用されない場合に、コンパイラが適切なエラーメッセージを生成するかどうかをテストします。以前は「4 not used
」のようなメッセージでしたが、修正後は「unsafe.Alignof(0) not used
」のような、元の式を含むメッセージが期待されます。// ERROR "unsafe\\.Alignof|value computed is not used"
というコメントは、正規表現を使って期待されるエラーメッセージを定義しています。f(time.Wednesday)
: この行は、time.Wednesday
(time.Weekday
型)をint
型を期待する関数f
に渡すことで、型不一致のエラーを意図的に発生させます。以前は「cannot use 3 (type time.Weekday) as type int in function argument
」というメッセージでしたが、修正後は「cannot use time.Wednesday (type time.Weekday) as type int in function argument
」のような、元の定数名を含むメッセージが期待されます。// ERROR "time.Wednesday|incompatible type"
というコメントが、この期待を正規表現で示しています。
これらのテストケースは、orig
フィールドの導入によって、コンパイラがよりユーザーフレンドリーなエラーメッセージを生成できるようになったことを実証しています。
関連リンク
- Go CL 5572081: https://golang.org/cl/5572081
参考にした情報源リンク
- Go Issue 2768: https://github.com/golang/go/issues/2768
- Go Issue 2276: https://github.com/golang/go/issues/2276 (関連する以前のIssue)
- Go言語の
unsafe
パッケージに関するドキュメント: https://pkg.go.dev/unsafe - Go言語の
time
パッケージに関するドキュメント: https://pkg.go.dev/time - Goコンパイラの内部構造に関する一般的な情報 (Goのソースコードや関連する論文など)