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

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

このコミットは、Goコンパイラ(cmd/gc)における無効なインデックス操作のエラーメッセージをより明確な表現に修正するものです。具体的には、「invalid operation: this[i] (index of type int)」というメッセージを「invalid operation: this[i] (type int does not support indexing)」に変更し、エラーの原因をより正確に伝えることを目的としています。

コミット

656a40254566bb1fae3bfa30448d103d911e04c4

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

https://github.com/golang/go/commit/656a40254566bb1fae3bfa30448d103d911e04c4

元コミット内容

commit 656a40254566bb1fae3bfa30448d103d911e04c4
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Thu Feb 13 21:01:33 2014 -0500

    cmd/gc: rephrase the invalid indexing operation error message
    Old:
    prog.go:9: invalid operation: this[i] (index of type int)
    New:
    prog.go:9: invalid operation: this[i] (type int does not support indexing)
    
    LGTM=r
    R=golang-codereviews, r
    CC=golang-codereviews
    https://golang.org/cl/52540043

変更の背景

Go言語では、配列、スライス、マップ、文字列などの特定のデータ型に対してのみインデックス操作([]演算子)が許可されています。しかし、Goコンパイラ(gc)が、インデックス操作をサポートしない型(例えばint型)に対してインデックス操作が行われた場合に生成するエラーメッセージが、その原因を正確に伝えていませんでした。

以前のメッセージ「invalid operation: this[i] (index of type int)」は、「this[i]という操作が無効であり、そのインデックスがint型である」という情報を提供していました。しかし、問題はインデックスの型ではなく、this(インデックス操作の対象)の型がインデックス操作をサポートしていないことでした。

この曖昧さを解消し、開発者がエラーの原因をより迅速に特定できるようにするため、エラーメッセージを「invalid operation: this[i] (type int does not support indexing)」という、より直接的で分かりやすい表現に修正する必要がありました。これにより、ユーザーは「int型はインデックスをサポートしていない」という明確な情報を得ることができ、コードの修正が容易になります。

前提知識の解説

Go言語の型システムとインデックス操作

Go言語は静的型付け言語であり、各変数には明確な型が関連付けられています。インデックス操作([])は、特定の複合データ型にアクセスするためのメカニズムです。

  • 配列 (Arrays): 固定長のシーケンス。a[i]i番目の要素にアクセスします。
  • スライス (Slices): 可変長のシーケンス。配列と同様にs[i]でアクセスします。
  • マップ (Maps): キーと値のペアのコレクション。m[key]keyに対応する値にアクセスします。
  • 文字列 (Strings): バイトのシーケンス。s[i]i番目のバイトにアクセスします(UTF-8文字ではなくバイトである点に注意)。

これらの型はインデックス操作をサポートしていますが、intfloat64bool、構造体、関数などのプリミティブ型やその他の複合型は、直接的なインデックス操作をサポートしていません。これらの型に対してインデックス操作を行おうとすると、コンパイル時にエラーが発生します。

Goコンパイラ (cmd/gc)

cmd/gcは、Go言語の公式コンパイラツールチェーンの一部であり、Goソースコードを機械語に変換する主要なコンポーネントです。コンパイルプロセス中に、gcは字句解析、構文解析、型チェック、最適化、コード生成などの複数のフェーズを実行します。

  • 型チェック (Type Checking): このフェーズでは、プログラムがGo言語の型規則に準拠しているかどうかが検証されます。例えば、変数の型と代入される値の型が一致しているか、関数呼び出しの引数の型が関数のパラメータの型と一致しているか、そして今回のケースのように、特定の操作(インデックス操作など)がその操作の対象となる型に対して有効であるか、などがチェックされます。型チェック中にエラーが検出された場合、コンパイラはエラーメッセージを出力し、コンパイルを停止します。

このコミットで変更されたtypecheck.cファイルは、gcコンパイラの型チェックフェーズにおける重要な部分を担っています。

技術的詳細

この変更は、Goコンパイラのsrc/cmd/gc/typecheck.cファイル内のエラーメッセージ文字列を修正するものです。

typecheck.cファイルは、Goプログラムの型チェックロジックを実装しています。このファイル内には、様々な型関連のエラーを検出して報告するためのコードが含まれています。インデックス操作に関するエラーは、yyerror関数を呼び出すことで報告されます。yyerrorは、コンパイラがエラーメッセージを出力するために使用する内部関数です。

変更前のコードでは、無効なインデックス操作が検出された際に、以下のフォーマット文字列を使用してエラーメッセージを生成していました。

yyerror("invalid operation: %N (index of type %T)", n, t);

ここで、%Nは操作の対象(例: this[i])、%Tはインデックス操作の対象の型(例: int)を表します。この結果、例えばint型の変数xに対してx[0]のような操作を行った場合、「invalid operation: x[0] (index of type int)」というメッセージが出力されていました。このメッセージは、あたかもインデックス自体がint型であることが問題であるかのように読めてしまい、誤解を招く可能性がありました。

コミットによって、このフォーマット文字列が以下のように変更されました。

yyerror("invalid operation: %N (type %T does not support indexing)", n, t);

この変更により、同じx[0]の例では、「invalid operation: x[0] (type int does not support indexing)」というメッセージが出力されるようになります。この新しいメッセージは、問題がインデックスの型ではなく、インデックス操作の対象であるint型がインデックスをサポートしていないことにある、という事実を明確に伝えます。

この修正は、コンパイラの出力するエラーメッセージの品質を向上させ、開発者がGoコードの型関連の問題をデバッグする際の効率を高めることに貢献します。コードの機能的な振る舞いには影響を与えず、コンパイラのユーザーエクスペリエンスのみを改善するものです。

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

--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -866,7 +866,7 @@ reswitch:
 		        goto error;
 		switch(t->etype) {
 		default:
-			yyerror("invalid operation: %N (index of type %T)", n, t);
+			yyerror("invalid operation: %N (type %T does not support indexing)", n, t);
 			goto error;
 

コアとなるコードの解説

上記の差分は、src/cmd/gc/typecheck.cファイル内のreswitchラベルの後のswitch文の中にあるdefaultケースの変更を示しています。

  • reswitch:: これは、Goコンパイラの型チェックロジックにおける特定の処理フローのジャンプ先として使用されるラベルです。
  • switch(t->etype): ここでのtは、インデックス操作の対象となる式の型を表すポインタです。t->etypeは、その型の基本的な種類(例えば、TARRAYTSLICETMAPTSTRINGなど)を示します。
  • default:: このdefaultケースは、t->etypeがインデックス操作をサポートする既知の型(配列、スライス、マップ、文字列など)のいずれにも一致しない場合に実行されます。つまり、インデックス操作が許可されていない型に対してインデックス操作が行われた場合にここに至ります。
  • yyerror(...): これはGoコンパイラの内部関数で、コンパイルエラーを報告するために使用されます。引数としてフォーマット文字列と、そのフォーマット文字列に埋め込む変数を取ります。
    • 変更前: yyerror("invalid operation: %N (index of type %T)", n, t);
      • %N: エラーが発生したノード(式)を表します。例えば、a[i]のような形です。
      • %T: インデックス操作の対象となっている式の型を表します。例えば、int型などです。
      • このメッセージは、「%Nという操作は無効です(インデックスが%T型であるため)」と解釈されがちでした。
    • 変更後: yyerror("invalid operation: %N (type %T does not support indexing)", n, t);
      • この新しいメッセージは、「%Nという操作は無効です(%T型はインデックスをサポートしていません)」と明確に伝えます。

この変更は、エラーメッセージの文言をわずかに変更するだけですが、その意味合いは大きく異なります。これにより、コンパイラが報告するエラーがより正確になり、開発者が問題の原因を特定しやすくなります。これは、コンパイラのユーザーフレンドリーさを向上させるための典型的な改善例です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント(型システム、配列、スライス、マップ、文字列に関するセクション)
  • Goコンパイラ(cmd/gc)のソースコード(特にsrc/cmd/gc/typecheck.c
  • Go言語のエラーメッセージの改善に関する一般的な議論(Goコミュニティのフォーラムやメーリングリストなど)