[インデックス 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のソースコードや関連する論文など)