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

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

このコミットは、Goコンパイラ(gc)におけるエラーメッセージの表示に関するバグ修正です。具体的には、受信専用チャネルを閉じようとした際に表示されるエラーメッセージ内のフォーマット指定子%#Nが誤っており、これを正しい%Nに修正することで、より正確なエラーメッセージが表示されるように改善されています。

コミット

commit 556258e57b4a937b0021472b7489520605f80c79
Author: Luuk van Dijk <lvd@golang.org>
Date:   Tue Jan 10 11:09:04 2012 +0100

    gc: fix stray %#N in error message
    
    Fixes #2639.
    
    R=rsc
    CC=bradfitz, golang-dev
    https://golang.org/cl/5489140

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

https://github.com/golang/go/commit/556258e57b4a937b0021472b7489520605f80c79

元コミット内容

gc: fix stray %#N in error message

Fixes #2639.

R=rsc
CC=bradfitz, golang-dev
https://golang.org/cl/5489140

変更の背景

この変更は、Goコンパイラが特定の状況下で誤ったエラーメッセージを表示するバグを修正するために行われました。具体的には、Go言語のチャネル(channel)において、受信専用として宣言されたチャネルを閉じようとした際に、コンパイラが生成するエラーメッセージに%#Nという不適切なフォーマット指定子が含まれていました。

この問題は、Goの公式イシュートラッカーでIssue 2639: compiler error message closing receive-only channelとして報告されていました。%#Nは、通常、ノード(抽象構文木における要素)のデバッグ表現を出力するために使用されるフォーマット指定子ですが、このエラーメッセージの文脈では、ノードの簡潔な表現である%Nが適切でした。誤ったフォーマット指定子の使用により、ユーザーにとって分かりにくい、あるいは意図しない情報が含まれたエラーメッセージが表示される可能性がありました。

このコミットは、エラーメッセージの正確性とユーザーフレンドリーさを向上させることを目的としています。

前提知識の解説

このコミットを理解するためには、以下の概念についての知識が役立ちます。

  • Goコンパイラ (gc): Go言語の公式コンパイラです。ソースコードを機械語に変換する役割を担います。src/cmd/gcディレクトリ以下にそのソースコードが存在します。
  • チャネル (Channels): Go言語における並行処理のプリミティブの一つで、ゴルーチン間で値を安全に送受信するための通信路です。チャネルは、送信専用 (chan<- T)、受信専用 (<-chan T)、または双方向 (chan T) として宣言できます。
  • close 関数: Goの組み込み関数で、チャネルを閉じます。閉じられたチャネルへの送信はパニックを引き起こしますが、受信は可能で、チャネルが閉じられた後に送信された値がない場合はゼロ値が返されます。受信専用チャネルを閉じようとすることは、Goの型システムによって禁止されています。
  • yyerror: コンパイラやパーサーの文脈でよく見られるエラー報告関数です。通常、printfのようなフォーマット文字列と可変個の引数を取り、エラーメッセージを標準エラー出力に出力します。Goコンパイラの内部でも、構文解析や型チェックの段階でエラーを報告するために使用されます。
  • フォーマット指定子 (%N, %#N): Goコンパイラの内部で、抽象構文木(AST)のノードや型などの内部構造を文字列として表現するために使用される特殊なフォーマット指定子です。
    • %N: ノードの簡潔な表現(例: 変数名、型名など)を出力します。
    • %#N: ノードのより詳細な、デバッグ目的の表現を出力します。これには、ノードの内部構造に関する追加情報が含まれる場合があります。
  • typecheck.c: Goコンパイラのソースコードの一部で、型チェック(type checking)を担当するC言語のファイルです。Goのソースコードが型規則に準拠しているかを確認し、型エラーを検出します。
  • Csend: Goコンパイラの内部でチャネルの能力(capability)を表すフラグの一つです。チャネルが送信可能(sendable)であることを示します。

技術的詳細

このコミットの技術的な核心は、yyerror関数に渡されるフォーマット文字列の修正にあります。

src/cmd/gc/typecheck.cの該当箇所は、close関数が受信専用チャネルに対して呼び出された場合にエラーを報告するロジックです。

元のコードでは、エラーメッセージのフォーマット文字列として以下が使用されていました。

yyerror("invalid operation: %#N (cannot close receive-only channel)", n);

ここで、%#Nは、エラーの原因となったノードnの「デバッグ表現」を出力するように指示しています。しかし、このエラーメッセージの文脈では、ユーザーに表示すべきはノードの簡潔な表現(例えば、チャネル変数名)であり、内部的なデバッグ情報は不要でした。%#Nを使用すると、例えばチャネルの内部的な型情報やメモリレイアウトなど、ユーザーが理解する必要のない詳細な情報がエラーメッセージに混入する可能性がありました。

修正後のコードでは、フォーマット指定子が%Nに変更されています。

yyerror("invalid operation: %N (cannot close receive-only channel)", n);

%Nは、ノードnの「簡潔な表現」を出力します。これにより、エラーメッセージは「invalid operation: [チャネル変数名] (cannot close receive-only channel)」のような形式になり、ユーザーにとってより分かりやすく、関連性の高い情報のみが提供されるようになります。

この変更は、コンパイラのエラーメッセージの品質を向上させ、開発者が問題をより迅速に特定し、修正できるようにするために重要です。

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

--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -1013,7 +1013,7 @@ reswitch:
 		        goto error;
 		}
 		if(!(t->chan & Csend)) {
-			yyerror("invalid operation: %#N (cannot close receive-only channel)", n);
+			yyerror("invalid operation: %N (cannot close receive-only channel)", n);
 			goto error;
 		}
 		ok |= Etop;

コアとなるコードの解説

変更はsrc/cmd/gc/typecheck.cファイルのreswitchラベル内のコードブロックにあります。

  1. if(!(t->chan & Csend)): この条件文は、tが表すチャネルの型が送信能力(Csend)を持っていないかどうかをチェックしています。つまり、チャネルが受信専用であるか、または双方向チャネルではないことを確認しています。
  2. yyerror(...): この行がエラーメッセージを出力する部分です。
    • 変更前: yyerror("invalid operation: %#N (cannot close receive-only channel)", n);
      • %#Nが使用されており、ノードnのデバッグ表現が出力されていました。
    • 変更後: yyerror("invalid operation: %N (cannot close receive-only channel)", n);
      • %Nに変更されたことで、ノードnの簡潔な表現(例えば、チャネル変数名)が出力されるようになります。
  3. goto error;: エラーが検出されたため、現在の処理を中断し、エラー処理ルーチンにジャンプします。

このコードブロック全体は、close関数が呼び出された際に、その引数が受信専用チャネルである場合に型エラーを検出して報告する役割を担っています。今回の修正は、このエラー報告の「内容」を改善するものです。

関連リンク

参考にした情報源リンク