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

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

このコミットは、Go言語のテストスイートの一部である test/index.go ファイルに対する変更です。具体的には、浮動小数点定数を配列やスライスのインデックスとして使用した場合のエラーメッセージの認識を改善するための修正が含まれています。

コミット

commit bdafe73ce4f4910efd71eb5fdd7a5fc4614a9afe
Author: Ian Lance Taylor <iant@golang.org>
Date:   Fri Sep 27 20:38:52 2013 -0700

    test: recognize gccgo error message in index.go
    
    When a floating point constant is used as an array/slice
    index, gccgo prints "error: index must be integer"; gc prints
    "constant 2.1 truncated to integer".
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/14044044

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

https://github.com/golang/go/commit/bdafe73ce4f4910efd71eb5fdd7a5fc4614a9afe

元コミット内容

浮動小数点定数が配列/スライスのインデックスとして使用された場合、gccgoは「error: index must be integer」と出力し、gcは「constant 2.1 truncated to integer」と出力する。このコミットは、index.go 内でgccgoのエラーメッセージを認識するようにテストを修正する。

変更の背景

Go言語には、主に2つの主要なコンパイラ実装が存在します。一つは公式のGoコンパイラである gc (Go Compiler) で、もう一つはGCC (GNU Compiler Collection) をベースにした gccgo です。これら二つのコンパイラは、Go言語の仕様に準拠してコードをコンパイルしますが、エラーメッセージの出力形式や詳細において差異が生じることがあります。

このコミットの背景にある問題は、浮動小数点数(例: 2.1)を配列やスライスのインデックスとして使用しようとした場合に発生するエラーメッセージの違いです。Go言語の仕様では、配列やスライスのインデックスは整数型である必要があります。浮動小数点数をインデックスとして使用することは文法的に誤りであり、コンパイル時にエラーとなるべき挙動です。

しかし、gcgccgo の間で、この特定のエラーに対するメッセージが異なっていました。

  • gc は「constant 2.1 truncated to integer」(定数2.1が整数に切り捨てられました)というメッセージを出力していました。これは、コンパイラが浮動小数点数を整数に変換しようとしたが、それが不適切であることを示唆しています。
  • gccgo は「error: index must be integer」(エラー: インデックスは整数でなければなりません)という、より直接的で明確なメッセージを出力していました。

Go言語のテストスイートは、様々なコンパイラ実装や環境下でコードが正しく動作し、期待されるエラーが適切に報告されることを検証するために設計されています。test/index.go は、インデックスに関する様々なケースをテストするファイルです。このファイル内のテストは、特定のコードがコンパイルエラーになることを期待し、そのエラーメッセージが特定のパターンに一致するかどうかを検証していました。

gccgo のエラーメッセージが既存のテストの期待パターンに含まれていなかったため、gccgo でテストを実行すると、本来エラーとして認識されるべきものが認識されず、テストが失敗する可能性がありました。このコミットは、この不一致を解消し、gccgo 環境下でもテストが正しく機能するようにするために行われました。

前提知識の解説

Go言語の配列とスライス

Go言語における配列とスライスは、複数の要素を格納するためのデータ構造です。

  • 配列 (Array): 長さが固定されたシーケンスです。宣言時に要素の型と長さを指定します。例: var a [5]int
  • スライス (Slice): 長さが可変なシーケンスです。配列の上に構築され、より柔軟な操作が可能です。例: var s []int

配列やスライスの個々の要素にアクセスするには、インデックスを使用します。インデックスは0から始まり、要素の順序を示します。

インデックスの型

Go言語の仕様では、配列やスライスのインデックスは整数型である必要があります。具体的には、int 型またはその基底型(int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr)の定数または変数を使用できます。浮動小数点数(float32, float64)をインデックスとして直接使用することはできません。これは、メモリ上の連続した領域から特定の要素を正確に指し示すために、離散的な整数値が必要だからです。

Go言語のコンパイラ: gcgccgo

  • gc (Go Compiler): Go言語の公式かつ主要なコンパイラです。Go言語のソースコードから直接実行可能なバイナリを生成します。Go言語の開発チームによってメンテナンスされており、Go言語の最新の機能や最適化が最も早く反映されます。通常、go build コマンドを使用すると、この gc コンパイラが使用されます。

  • gccgo: GCC (GNU Compiler Collection) のフロントエンドとして実装されたGo言語のコンパイラです。GCCの既存の最適化インフラストラクチャやバックエンドを利用してGoコードをコンパイルします。gccgo は、GCCがサポートする様々なアーキテクチャやオペレーティングシステムでGoコードをコンパイルできるという利点があります。しかし、gc とは独立して開発されているため、Go言語の最新機能のサポートが遅れたり、エラーメッセージの形式が異なったりすることがあります。

Go言語のテストフレームワークとエラーメッセージの検証

Go言語の標準ライブラリには、testing パッケージが提供されており、ユニットテストやベンチマークテストを記述するためのフレームワークが含まれています。Goのテストは通常、_test.go で終わるファイルに記述され、go test コマンドで実行されます。

このコミットで関連するのは、コンパイルエラーを期待するテストの記述方法です。Goのテストスイートでは、特定のコードがコンパイル時にエラーを発生させることを期待する場合、そのコードの行に特別なコメント // ERROR "pattern" を追加することがあります。この pattern は正規表現であり、コンパイラが出力するエラーメッセージがこの正規表現に一致するかどうかをテストツールが検証します。もし一致しない場合、テストは失敗します。

このメカニズムにより、コンパイラの挙動が期待通りであるか、または異なるコンパイラ実装間でのエラー報告の一貫性が保たれているかを自動的に確認できます。

技術的詳細

このコミットの技術的な核心は、Go言語のテストフレームワークがコンパイルエラーメッセージをどのように検証しているか、そして異なるコンパイラ(gcgccgo)が同じエラー条件に対して異なるメッセージを出力する場合に、そのテストをどのように適応させるかという点にあります。

test/index.go ファイルは、Go言語のコンパイラが配列やスライスのインデックスに関する様々な不正な使用方法を正しく検出するかどうかを検証するためのテストケースを含んでいます。このファイルには、testExpr という関数があり、これは与えられたGoの式がコンパイル時にエラーを発生させることを期待する場合に、そのエラーメッセージを検証するためのロジックを含んでいます。

元のコードでは、浮動小数点定数をインデックスとして使用するような不正な式に対して、以下のようなコメントが付けられていました。

fmt.Fprintf(b, "\tuse(%s)  // ERROR \"index|overflow|truncated\"\\n", expr)

この行は、expr で表されるGoの式がコンパイルエラーになることを期待しており、そのエラーメッセージが正規表現 "index|overflow|truncated" のいずれかに一致することを要求していました。

  • "index": インデックスに関する一般的なエラー
  • "overflow": 数値のオーバーフローに関するエラー
  • "truncated": 数値が切り捨てられたことを示すエラー(gc の「constant 2.1 truncated to integer」に対応)

しかし、gccgo はこのケースで「error: index must be integer」というメッセージを出力します。このメッセージは、既存の正規表現 "index|overflow|truncated" には一致しませんでした。具体的には、"index" は部分的に一致する可能性はありますが、gccgo のメッセージ全体をカバーするには不十分でした。

このコミットでは、この問題を解決するために、正規表現に |must be integer を追加しました。

fmt.Fprintf(b, "\tuse(%s)  // ERROR \"index|overflow|truncated|must be integer\"\\n", expr)

これにより、テストツールは gc の「truncated」メッセージと gccgo の「must be integer」メッセージの両方を正しく認識できるようになります。この変更は、Go言語のテストスイートが複数のコンパイラ実装に対して堅牢であることを保証するための典型的なアプローチです。コンパイラの実装詳細に起因するエラーメッセージの差異を吸収し、テストの網羅性と信頼性を維持します。

この修正は、Go言語のコンパイラ開発における重要な側面を示しています。それは、言語仕様の遵守だけでなく、異なる実装間での互換性や一貫性を確保するための継続的な努力です。特に、エラーメッセージのようなユーザーに直接影響を与える部分については、可能な限り明確で一貫性のある情報を提供することが望ましいですが、コンパイラの実装上の制約から差異が生じる場合、テスト側でそれを許容するように調整する必要があります。

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

変更は test/index.go ファイルの1箇所のみです。

--- a/test/index.go
+++ b/test/index.go
@@ -164,7 +164,7 @@ func testExpr(b *bufio.Writer, expr string) {
  	if pass == 0 {
  		fmt.Fprintf(b, "\ttest(func(){use(%s)}, %q)\\n", expr, expr)
  	} else {
-\t\tfmt.Fprintf(b, "\tuse(%s)  // ERROR \"index|overflow|truncated\"\\n", expr)
+\t\tfmt.Fprintf(b, "\tuse(%s)  // ERROR \"index|overflow|truncated|must be integer\"\\n", expr)
  	}
  }
  

コアとなるコードの解説

変更された行は、testExpr 関数内の else ブロックにあります。この関数は、Goの式 expr を受け取り、それがコンパイルエラーになることを期待する場合に、そのエラーメッセージを検証するためのテストコードを生成します。

  • fmt.Fprintf(b, ...): b という bufio.Writer にフォーマットされた文字列を書き込みます。これは、テストスクリプトの一部として実行されるGoコードを生成するために使用されます。
  • use(%s): これは、expr で与えられた式が実際に使用されることを保証するためのプレースホルダーです。Goでは、宣言されたが使用されていない変数はコンパイルエラーになるため、use 関数(このテストファイル内で定義されているダミー関数)を呼び出すことで、式が「使用された」と見なされます。
  • // ERROR "...": このコメントは、Goのテストツール(特に go test の内部で使われる run.go や関連ツール)によって特別に解釈されます。この行を含むGoコードがコンパイルされる際に、指定された正規表現パターンに一致するエラーメッセージが出力されることを期待します。もし一致するエラーメッセージが出力されなかったり、別のエラーメッセージが出力されたりした場合、テストは失敗します。
  • "index|overflow|truncated": これは元の正規表現パターンです。
    • index: インデックス関連のエラーメッセージにマッチします。
    • overflow: 数値のオーバーフロー関連のエラーメッセージにマッチします。
    • truncated: 数値が切り捨てられたことを示すエラーメッセージにマッチします。これは gc コンパイラが「constant 2.1 truncated to integer」のようなメッセージを出力する場合に対応していました。
  • "index|overflow|truncated|must be integer": 変更後の正規表現パターンです。
    • |must be integer: 新たに追加された部分です。これにより、gccgo コンパイラが浮動小数点数をインデックスとして使用した場合に出力する「error: index must be integer」というメッセージにマッチするようになります。

この変更により、test/index.go 内の関連するテストケースは、gcgccgo の両方のコンパイラ実装で、浮動小数点定数を配列/スライスのインデックスとして使用する不正なコードに対して、期待されるエラーメッセージを正しく認識し、テストがパスするようになります。これは、Go言語のテストスイートが異なるコンパイラ実装間での互換性を維持するための重要な調整です。

関連リンク

参考にした情報源リンク

  • Go言語のコミット履歴 (GitHub): https://github.com/golang/go/commits/master
  • Go言語のコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (コミットメッセージに記載されている https://golang.org/cl/14044044 は、このGerritシステムへのリンクです。)
  • Go言語の仕様 (The Go Programming Language Specification): https://go.dev/ref/spec (特に「Index expressions」のセクション)
  • Go言語のテストの仕組みに関する一般的な情報源 (例: 各種ブログ、技術記事など)