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

[インデックス 10811] ファイルの概要

このコミットは、Goコンパイラ (gc) のフォーマット処理と、それに関連するテストファイルに影響を与えています。具体的には、以下の2つのファイルが変更されています。

  • src/cmd/gc/fmt.c: Goコンパイラの型フォーマット処理を司るC言語のソースファイルです。エラーメッセージにおける関数型の表示方法が変更されています。
  • test/fixedbugs/bug389.go: Goコンパイラのバグ修正を検証するためのテストファイルです。このコミットで新規追加されており、関数型の引数名がエラーメッセージに表示されないことを確認するテストケースが含まれています。

コミット

commit 5b2f8d96cec0b1800cc099e022175b3588fd86a2
Author: Luuk van Dijk <lvd@golang.org>
Date:   Thu Dec 15 17:38:47 2011 +0100

    gc: omit argument names from function types in error messages
    
    Fixes #2563
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/5495047

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/5b2f8d96cec0b1800cc099e022175b3588fd86a2

元コミット内容

Goコンパイラ (gc) がエラーメッセージ内で関数型を表示する際に、引数名を省略するように変更します。

この変更は、Issue 2563を修正します。

レビュー担当者: rsc CC: golang-dev 関連するGo CL (Change List): https://golang.org/cl/5495047

変更の背景

このコミットの背景には、Goコンパイラが生成するエラーメッセージの可読性向上の課題がありました。Go言語では、関数型を定義する際に引数名を指定することができますが、これはあくまでドキュメンテーション目的であり、型の同一性には影響しません。例えば、func(a int)func(b int)は同じ関数型と見なされます。

しかし、以前のGoコンパイラは、型不一致のエラーメッセージなどで関数型を表示する際に、これらの引数名を含めて出力していました。これにより、エラーメッセージが冗長になり、特に複雑な関数型の場合には、ユーザーが本当に知りたい「型が一致しない」という本質的な情報が埋もれてしまう可能性がありました。

Issue 2563は、この問題点を指摘しており、エラーメッセージから関数型の引数名を省略することで、より簡潔で分かりやすいエラーメッセージを提供することを目的としています。これにより、開発者はエラーの原因を迅速に特定し、デバッグの効率を向上させることができます。

前提知識の解説

Go言語の型システムと関数型

Go言語は静的型付け言語であり、変数は特定の型を持ちます。関数もまた型を持ち、これを「関数型」と呼びます。関数型は、その関数の引数の型と戻り値の型によって定義されます。

例: func(int, string) bool は、intstringを引数にとり、boolを返す関数型です。

Go言語の関数型において、引数名は型の識別には使用されません。つまり、func(a int)func(b int)は同じ型として扱われます。引数名は、コードの可読性を高めるためのものであり、コンパイラが型を比較する際には無視されます。

Goコンパイラ (gc)

gcは、Go言語の公式コンパイラです。Goのソースコードを機械語に変換する役割を担っています。コンパイラは、構文解析、型チェック、最適化、コード生成など、複数のフェーズを経て実行されます。

src/cmd/gc/fmt.cと型フォーマット

src/cmd/gc/fmt.cは、Goコンパイラのバックエンドの一部であり、主にGoの型情報を文字列としてフォーマットする機能を提供します。これは、エラーメッセージの生成、デバッグ情報の出力、リフレクションなど、様々な場面で利用されます。

このファイル内で、typefmt関数はGoの型を文字列に変換する主要な関数です。この関数は、fmtmodeというフラグに基づいて、型のフォーマット方法を調整します。

  • FTypeId: 型の識別子として使用されるフォーマットモードです。このモードでは、型の同一性を比較するために必要な情報のみが含まれ、冗長な情報は省略されます。
  • FErr: エラーメッセージで使用されるフォーマットモードです。このコミット以前は、FTypeIdとは異なる振る舞いをし、関数型の引数名を含んでいました。

test/fixedbugs/bug389.goerrchk

test/fixedbugs/ディレクトリは、Goコンパイラやランタイムの特定のバグを修正したことを検証するためのテストケースを格納しています。これらのテストは、バグが再発しないことを保証するために重要です。

errchkは、Goのテストフレームワークの一部であり、特定の行でコンパイラエラーが発生することを期待するテストに使用されます。errchk $G $D/$F.goというコメントは、Goコンパイラ ($G) を使用して現在のファイル ($D/$F.go) をコンパイルし、指定されたエラーメッセージが出力されることを検証する指示です。

技術的詳細

このコミットの技術的な核心は、Goコンパイラがエラーメッセージ内で関数型をフォーマットする際の挙動を変更することにあります。具体的には、src/cmd/gc/fmt.c内のtypefmt関数が修正されています。

typefmt関数は、Goの様々な型(構造体、配列、関数など)を文字列に変換する役割を担っています。この関数内で、関数型 (TSTRUCTかつt->funargが真の場合) の処理において、fmtmodeという変数の値に基づいてフォーマットの挙動が分岐しています。

変更前のコードでは、fmtmode == FTypeIdの場合にのみ、関数型の引数名が省略されていました。FTypeIdは、型の識別子を生成する際に使用されるモードであり、型の同一性を比較する上で不要な情報は含まれません。

しかし、エラーメッセージを生成する際のモード (FErr) では、この引数名の省略が行われていませんでした。そのため、型不一致のエラーメッセージなどで関数型が表示される際に、func(a int)のように引数名が含まれてしまい、冗長な出力となっていました。

このコミットでは、fmtmode == FTypeIdの条件に|| fmtmode == FErrを追加しています。これにより、FTypeIdモードだけでなく、FErrモードでも関数型の引数名が省略されるようになります。結果として、エラーメッセージ内で表示される関数型は、func(int)のように引数名が取り除かれた、より簡潔な形式になります。

この変更は、Go言語の設計思想である「シンプルさ」と「明瞭さ」に合致しています。エラーメッセージは、開発者が問題を迅速に理解し、解決するための重要な情報源であるため、そのメッセージは可能な限り簡潔で、かつ必要な情報が明確に伝わるように設計されるべきです。引数名が型の同一性に影響しない以上、エラーメッセージに含めることは冗長であり、混乱を招く可能性がありました。

コアとなるコードの変更箇所

diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
index 886488a368..c627adb34f 100644
--- a/src/cmd/gc/fmt.c
+++ b/src/cmd/gc/fmt.c
@@ -680,7 +680,7 @@ typefmt(Fmt *fp, Type *t)\n 	case TSTRUCT:\n 		if(t->funarg) {\n 			fmtstrcpy(fp, \"(\");\n-			if(fmtmode == FTypeId) {\t// no argument names on function signature, and no \"noescape\" tags
+			if(fmtmode == FTypeId || fmtmode == FErr) {\t// no argument names on function signature, and no \"noescape\" tags
 				for(t1=t->type; t1!=T; t1=t1->down)\n 					if(t1->down)\n 						fmtprint(fp, \"%hT, \", t1);\
diff --git a/test/fixedbugs/bug389.go b/test/fixedbugs/bug389.go
new file mode 100644
index 0000000000..40d6c419cf 100644
--- /dev/null
+++ b/test/fixedbugs/bug389.go
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 2563
+package foo
+
+func fn(a float32) {}
+
+var f func(arg int) = fn  // ERROR "cannot use fn .type func.float32.. as type func.int. in assignment"
\ No newline at end of file

コアとなるコードの解説

src/cmd/gc/fmt.cの変更

-			if(fmtmode == FTypeId) {\t// no argument names on function signature, and no \"noescape\" tags
+			if(fmtmode == FTypeId || fmtmode == FErr) {\t// no argument names on function signature, and no \"noescape\" tags

この変更は、typefmt関数内の関数型 (TSTRUCTかつt->funargが真) のフォーマットロジックにあります。

  • fmtmode == FTypeId: これは、型の識別子を生成するモードです。このモードでは、型の同一性を比較する上で不要な情報(引数名など)は省略されます。
  • || fmtmode == FErr: このコミットで追加された条件です。FErrは、コンパイラがエラーメッセージを生成する際に使用するフォーマットモードです。この条件が追加されたことにより、エラーメッセージ内で関数型が表示される際にも、FTypeIdモードと同様に引数名が省略されるようになりました。

この変更により、例えば func(a int) という関数型がエラーメッセージに表示される場合、変更前は func(a int) と表示されていたものが、変更後は func(int) と表示されるようになります。これにより、エラーメッセージがより簡潔になり、型の不一致という本質的な情報が明確に伝わるようになります。

test/fixedbugs/bug389.goの追加

+// errchk $G $D/$F.go
+
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 2563
+package foo
+
+func fn(a float32) {}
+
+var f func(arg int) = fn  // ERROR "cannot use fn .type func.float32.. as type func.int. in assignment"

このファイルは、Issue 2563の修正を検証するために新しく追加されたテストケースです。

  • // errchk $G $D/$F.go: この行は、Goコンパイラ ($G) を使用してこのファイル ($D/$F.go) をコンパイルし、その出力に特定のエラーメッセージが含まれることを期待するテストであることを示しています。
  • func fn(a float32) {}: float32型の引数aを持つ関数fnを定義しています。
  • var f func(arg int) = fn: ここがテストの核心です。func(arg int)という関数型の変数fに、func(a float32)という関数型のfnを代入しようとしています。Go言語では、引数名が異なっていても引数の型が同じであれば関数型は一致しますが、ここでは引数の型 (int vs float32) が異なるため、型不一致のエラーが発生することが期待されます。
  • // ERROR "cannot use fn .type func.float32.. as type func.int. in assignment": このコメントは、コンパイラがこの行で特定のエラーメッセージを出力することを期待していることを示しています。注目すべきは、エラーメッセージ内の関数型が func.float32.func.int. となっており、引数名 (aarg) が省略されている点です。これは、fmt.cの変更が正しく機能していることを検証しています。

このテストケースは、コンパイラが関数型の引数名をエラーメッセージから正しく省略していることを確認するための重要な役割を果たしています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (型システム、関数型に関する情報)
  • Goコンパイラのソースコード (src/cmd/gc/ ディレクトリ内のファイル構造と機能)
  • Goのテストフレームワークに関する情報 (errchkの利用方法など)
  • Web検索: "Go issue 2563" (関連するGoのバグトラッカーの情報を確認)