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

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

このコミットは、Go言語のコンパイラの一つであるgccgoが生成するエラーメッセージを、テストスイートが正しく認識できるようにするための変更です。具体的には、インターフェースの不適合に関するエラーメッセージのパターンに、gccgoが出力する可能性のある新しいメッセージを追加しています。

コミット

commit 2eb17d78947efbb3140f8ab4e017693fc633301d
Author: Ian Lance Taylor <iant@golang.org>
Date:   Fri Oct 31 14:55:57 2008 -0700

    Recognize gccgo error message:
    interface1.go:29:6: error: incompatible type in initialization (missing method Next)
    
    R=rsc
    DELTA=1  (0 added, 0 deleted, 1 changed)
    OCL=18183
    CL=18271
---
 test/interface1.go | 2 +--
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/interface1.go b/test/interface1.go
index 089a8b5c1b..c81cad54ba 100644
--- a/test/interface1.go
+++ b/test/interface1.go
@@ -30,6 +30,6 @@ func AddInst(Inst) *Inst {
 func main() {
 	re := new(Regexp);
 	print("call addinst\\n");
-	var x Inst = AddInst(new(Start));	// ERROR "illegal"\n
+	var x Inst = AddInst(new(Start));	// ERROR "illegal|incompatible"\n
 	print("return from  addinst\\n");
 }

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

https://github.com/golang/go/commit/2eb17d78947efbb3140f8ab4e017693fc633301d

元コミット内容

このコミットの目的は、「gccgoが生成するエラーメッセージを認識する」ことです。具体的には、interface1.goというテストファイルにおいて、インターフェースの不適合によって発生するエラーメッセージのパターンに、gccgoが出力する可能性のある「incompatible type in initialization (missing method Next)」というメッセージを追加しています。これにより、テストがgccgoで実行された際にも、期待されるエラーが正しく検出されるようになります。

変更の背景

Go言語の初期段階では、複数のコンパイラが存在しました。このコミットが作成された2008年当時、Goの主要なコンパイラはgc(Goコンパイラ)とgccgo(GCCベースのGoコンパイラ)でした。テストスイートは、これらの異なるコンパイラが生成する可能性のあるエラーメッセージのバリエーションを考慮に入れる必要がありました。

test/interface1.goのようなテストファイルは、特定のコードがコンパイルエラーを引き起こすことを意図しており、そのエラーメッセージが期待されるパターンと一致するかどうかを検証します。もしコンパイラが異なるエラーメッセージを出力した場合、テストは失敗してしまいます。このコミットは、gccgoがインターフェースの不適合に対して「incompatible type」というメッセージを出力するようになったため、既存のテストがこの新しいメッセージを認識できるようにするために行われました。

前提知識の解説

Go言語のインターフェース

Go言語のインターフェースは、型が実装すべきメソッドのシグネチャ(メソッド名、引数、戻り値)の集合を定義します。Goのインターフェースは、JavaやC#のような明示的なimplementsキーワードを必要とせず、型がインターフェースで定義されたすべてのメソッドを実装していれば、そのインターフェースを満たしているとみなされます(構造的型付け)。これにより、柔軟なポリモーフィズムを実現します。

例えば、以下のようなインターフェースがあるとします。

type Reader interface {
    Read(p []byte) (n int, err error)
}

もしある型がReadメソッドを定義していなければ、その型はReaderインターフェースを満たしません。インターフェースを満たさない型をインターフェース型の変数に代入しようとすると、コンパイルエラーが発生します。

Go言語のコンパイラ (gcgccgo)

  • gc (Go Compiler): Go言語の公式コンパイラであり、Goツールチェインの一部として提供されています。Go言語の進化に合わせて開発され、高速なコンパイルと最適化が特徴です。
  • gccgo (GCC-based Go Compiler): GCC(GNU Compiler Collection)のフロントエンドとして実装されたGoコンパイラです。GCCの強力な最適化機能や、C/C++との連携のしやすさといった利点があります。しかし、gcとは独立して開発されているため、エラーメッセージの形式や、特定の言語機能の解釈に微妙な違いが生じることがありました。

テストにおけるエラーメッセージの検証

ソフトウェア開発において、特定の入力に対してエラーが発生することを期待するテストは一般的です。コンパイラのエラーメッセージを検証するテストでは、正規表現などを用いて、コンパイラが出力するエラーメッセージが期待されるパターンに一致するかどうかを確認します。これは、コンパイラの挙動が正しいことを保証するため、また、将来のコンパイラの変更によってエラーメッセージの形式が変わった場合にテストが失敗し、その変更を開発者に知らせるために重要です。

技術的詳細

このコミットの技術的なポイントは、Go言語のテストフレームワークが、コンパイラが出力するエラーメッセージをどのように検証しているかという点にあります。

Goのテストスイートでは、特定の行にコメントとして// ERROR "pattern"のような形式で、その行がコンパイルエラーを引き起こすことを期待し、かつそのエラーメッセージがpatternに一致することを指定できます。このpatternは正規表現として解釈されます。

元のコードでは、var x Inst = AddInst(new(Start));という行に対して、// ERROR "illegal"というコメントが付与されていました。これは、この行が「illegal」という文字列を含むエラーメッセージを生成することを期待していることを意味します。

しかし、gccgoがこのコードをコンパイルした際に、「incompatible type in initialization (missing method Next)」というエラーメッセージを出力するようになりました。このメッセージは「illegal」という文字列を含んでいないため、gccgoでテストを実行すると、テストが失敗してしまいます。

このコミットでは、エラーメッセージのパターンを"illegal|incompatible"に変更しています。これは正規表現のOR演算子(|)を使用しており、「illegal」または「incompatible」のいずれかの文字列がエラーメッセージに含まれていれば、テストが成功することを意味します。これにより、gcgccgoの両方のコンパイラで、このテストが正しく動作するようになりました。

これは、コンパイラのバージョンや実装の違いによってエラーメッセージの文言が異なる場合でも、テストの堅牢性を保つための一般的なアプローチです。

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

--- a/test/interface1.go
+++ b/test/interface1.go
@@ -30,6 +30,6 @@ func AddInst(Inst) *Inst {
 func main() {
 	re := new(Regexp);
 	print("call addinst\\n");
-	var x Inst = AddInst(new(Start));	// ERROR "illegal"\n
+	var x Inst = AddInst(new(Start));	// ERROR "illegal|incompatible"\n
 	print("return from  addinst\\n");
 }

コアとなるコードの解説

変更はtest/interface1.goファイルの1行のみです。

元の行: var x Inst = AddInst(new(Start)); // ERROR "illegal"

変更後の行: var x Inst = AddInst(new(Start)); // ERROR "illegal|incompatible"

この変更は、Goのテストフレームワークがエラーメッセージを検証するために使用する正規表現パターンを更新しています。

  • var x Inst = AddInst(new(Start));: この行は、Start型の新しいインスタンスをAddInst関数に渡し、その結果をInst型の変数xに代入しようとしています。このテストの文脈では、Start型がInstインターフェースを正しく実装していないため、コンパイルエラーが発生することが期待されています。
  • // ERROR "...": これはGoのテストスイートが認識する特別なコメントです。このコメントが付与された行でコンパイルエラーが発生した場合、コメント内の文字列がエラーメッセージのどこかに含まれているかを検証します。
  • "illegal": 元のパターンです。gcコンパイラがこの状況で「illegal」という単語を含むエラーメッセージを出力していたことを示唆しています。
  • "illegal|incompatible": 変更後のパターンです。正規表現の|(OR)演算子により、「illegal」または「incompatible」のいずれかの文字列がエラーメッセージに含まれていれば、テストが成功するようになります。これは、gccgoが「incompatible type in initialization (missing method Next)」のようなメッセージを出力するようになったため、そのメッセージもテストで許容されるようにするための対応です。

このシンプルな変更により、異なるGoコンパイラ間でのエラーメッセージの差異を吸収し、テストの互換性と堅牢性を高めています。

関連リンク

参考にした情報源リンク