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

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

このコミットは、Goコンパイラ(gc)の内部処理に関するバグ修正を含んでいます。具体的には、パッケージのインポート処理とシンボル解決のロジックが変更されています。また、関連するテストファイルがtest/bugsからtest/fixedbugsに移動されています。

変更されたファイルは以下の通りです。

  • src/cmd/gc/dcl.c: 宣言処理に関するC言語のソースファイル。
  • src/cmd/gc/go.h: Goコンパイラのヘッダーファイル。
  • src/cmd/gc/go.y: Go言語の文法定義ファイル(Yacc/Bison形式)。
  • test/{bugs => fixedbugs}/bug133.dir/bug0.go: テストファイル(リネーム)。
  • test/{bugs => fixedbugs}/bug133.dir/bug1.go: テストファイル(リネーム)。
  • test/{bugs => fixedbugs}/bug133.dir/bug2.go: テストファイル(リネーム)。
  • test/{bugs => fixedbugs}/bug133.go: テストファイル(リネーム)。
  • test/golden.out: テストの期待出力ファイル。

コミット

commit 4efad58d0a0a6d96d83ccfa39e27308c85be96a9
Author: Russ Cox <rsc@golang.org>
Date:   Mon Jan 26 16:57:24 2009 -0800

    bug133
    
    R=ken
    OCL=23528
    CL=23528

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

https://github.com/golang/go/commit/4efad58d0a0a6d96d83ccfa39e27308c85be96a9

元コミット内容

bug133

R=ken
OCL=23528
CL=23528

変更の背景

このコミットは、コミットメッセージにある「bug133」という特定のバグを修正するために行われました。Go言語の初期段階におけるコンパイラのバグであり、特にパッケージのインポートとシンボル解決のメカニズムに関連する問題であったと推測されます。

test/bugsディレクトリからtest/fixedbugsディレクトリへのテストファイルの移動は、このバグが修正され、その修正が将来のリグレッションテストで確実に検証されるようにするための標準的なプラクティスです。golden.outの変更は、テストの期待される出力がバグ修正によって変化したことを示しています。

Web検索の結果からも、「bug133」はGoプロジェクト自身のテストスイート内に存在する特定の歴史的なバグを指しており、Go言語自体の特定の問題に対する修正を実証し、検証するために使用されたことが示唆されています。

前提知識の解説

このコミットを理解するためには、以下のGoコンパイラ(gc)に関する基本的な知識が必要です。

  • Goコンパイラ (gc): Go言語の公式コンパイラであり、Goソースコードを機械語に変換します。src/cmd/gcディレクトリにそのソースコードが存在します。
  • Yacc/Bison (.yファイル): go.yファイルは、Go言語の文法を定義するYacc(Yet Another Compiler Compiler)またはBisonの入力ファイルです。Yacc/Bisonは、文法定義からパーサー(構文解析器)を生成するツールです。パーサーは、ソースコードが文法的に正しいかをチェックし、抽象構文木(AST)を構築します。
  • シンボルテーブルとシンボル解決: コンパイラは、変数、関数、型などの識別子(シンボル)に関する情報をシンボルテーブルに格納します。シンボル解決は、ソースコード中の識別子がどのシンボルテーブルのエントリに対応するかを決定するプロセスです。特に、異なるパッケージからインポートされたシンボルを正しく解決することが重要です。
  • パッケージインポート: Go言語では、importステートメントを使用して他のパッケージの機能を利用します。コンパイラは、インポートされたパッケージのシンボルを現在のスコープで利用できるように処理する必要があります。
  • dcl.c: gcにおける宣言(declaration)処理を担当するC言語のソースファイルです。変数、関数、型の宣言がどのように処理され、シンボルテーブルに登録されるかを定義します。
  • go.h: gc全体で共有されるグローバル変数、構造体、関数のプロトタイプなどが定義されているヘッダーファイルです。

技術的詳細

このコミットの技術的な核心は、Goコンパイラがパッケージのインポートされたシンボルをどのように解決するか、特にその「コンテキスト」をどのように管理するかという点にあります。

変更点を見ると、src/cmd/gc/dcl.cではpkgimportnameという変数がpkgcontextという変数に置き換えられています。

  • pkgimportname: これは、おそらく特定のインポートされたパッケージの名前を保持していた変数です。しかし、シンボル解決の際には、単にインポートされたパッケージの名前だけでなく、そのシンボルがどのパッケージのコンテキストで定義されたものなのか、というより広範な情報が必要になる場合があります。
  • pkgcontext: この新しい変数は、より一般的な「パッケージコンテキスト」を指すと考えられます。これは、現在処理しているシンボルが属するパッケージの情報を保持し、シンボル解決の際にそのコンテキストを利用して正しいシンボルを特定するために使用されます。

src/cmd/gc/go.yの変更は、このpkgcontextの導入と密接に関連しています。

  • %type <node> hidden_funres ohidden_funres hidden_importsym%type <node> hidden_funres ohidden_funres hidden_importsym hidden_pkg_importsym に変更されています。これは、Yaccの型定義にhidden_pkg_importsymという新しい型が追加されたことを意味します。
  • hidden_importルールの変更では、LVAR, LCONST, LTYPE, LFUNCといったキーワードに続くシンボルが、これまでのhidden_importsymからhidden_pkg_importsymに変わっています。これは、インポートされた変数、定数、型、関数のシンボルを解析する際に、より詳細なパッケージコンテキスト情報を持つhidden_pkg_importsymを使用するように文法が変更されたことを示しています。
  • 新しく追加されたhidden_pkg_importsymルールは、hidden_importsymを解析した後、そのシンボルのpsym->name(おそらくパッケージシンボルの名前)をグローバル変数pkgcontextに設定しています。これにより、パーサーがインポートされたシンボルを処理する際に、そのシンボルがどのパッケージに属しているかというコンテキスト情報がpkgcontextを通じて利用可能になります。

この変更は、Goコンパイラがインポートされたシンボルを曖昧さなく解決するために、より堅牢なメカニズムを導入したことを示唆しています。特に、異なるパッケージで同じ名前のシンボルが存在する場合や、複雑なインポートパスを持つ場合に、正しいシンボルを特定するためのコンテキスト情報が不可欠になります。

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

src/cmd/gc/dcl.c

--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -517,7 +517,7 @@ loop:
 		f->embedded = n->embedded;
 		f->sym = f->nname->sym;
 		if(pkgimportname != S && !exportname(f->sym->name))
-			f->sym = pkglookup(f->sym->name, pkgimportname->name);
+			f->sym = pkglookup(f->sym->name, pkgcontext);
 	}
 
 	*t = f;

src/cmd/gc/go.h

--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -504,6 +504,7 @@ EXTERN	Node*	fskel;
 EXTERN	Node*	addtop;
 
 EXTERN	char*	context;
+EXTERN	char*	pkgcontext;
 EXTERN	int	thechar;
 EXTERN	char*	thestring;
 EXTERN	char*	hunk;

src/cmd/gc/go.y

--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -80,7 +80,7 @@
 %type	<node>		hidden_interfacedcl_list ohidden_interfacedcl_list hidden_interfacedcl_list_r
 %type	<node>		hidden_interfacedcl
 %type	<node>		hidden_funarg_list ohidden_funarg_list hidden_funarg_list_r
-%type	<node>		hidden_funres ohidden_funres hidden_importsym
+%type	<node>		hidden_funres ohidden_funres hidden_importsym hidden_pkg_importsym
 
 %left			LOROR
 %left			LANDAND
@@ -1730,23 +1730,23 @@ oliteral:
 hidden_import:
 	LPACKAGE sym1
 	/* variables */
-|\tLVAR hidden_importsym hidden_type
+|\tLVAR hidden_pkg_importsym hidden_type
 	{
 		importvar($2, $3);
 	}
-|\tLCONST hidden_importsym '=' hidden_constant
+|\tLCONST hidden_pkg_importsym '=' hidden_constant
 	{
 		importconst($2, T, &$4);
 	}
-|\tLCONST hidden_importsym hidden_type '=' hidden_constant
+|\tLCONST hidden_pkg_importsym hidden_type '=' hidden_constant
 	{
 		importconst($2, $3, &$5);
 	}
-|\tLTYPE hidden_importsym hidden_type
+|\tLTYPE hidden_pkg_importsym hidden_type
 	{
 		importtype($2, $3);
 	}
-|\tLFUNC hidden_importsym '(' ohidden_funarg_list ')' ohidden_funres
+|\tLFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
 	{
 		importvar($2, functype(N, $4, $6));
 	}
@@ -1920,6 +1920,14 @@ hidden_importsym:
 		$$->sym = $3;
 	}
 
+hidden_pkg_importsym:
+\thidden_importsym
+\t{
+\t\t$$ = $1;
+\t\tpkgcontext = $$->psym->name;
+\t}\n
+\n
 /*
  * helpful error messages.
  * THIS SECTION MUST BE AT THE END OF THE FILE.

コアとなるコードの解説

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

-			f->sym = pkglookup(f->sym->name, pkgimportname->name);
+			f->sym = pkglookup(f->sym->name, pkgcontext);

この変更は、シンボルf->symをルックアップする際に、これまでのpkgimportname->name(インポートされたパッケージの名前)の代わりに、新しく導入されたグローバル変数pkgcontextを使用するように修正しています。pkglookup関数は、指定された名前とパッケージコンテキストに基づいてシンボルテーブルからシンボルを検索します。この変更により、シンボル解決の際に、より正確なパッケージのコンテキスト情報が利用されるようになります。

src/cmd/gc/go.hの変更

+EXTERN	char*	pkgcontext;

go.hpkgcontextというchar*型のグローバル変数が追加されました。EXTERNキーワードは、この変数が他のファイルで定義されていることを示し、このファイルでは宣言のみを行うことを意味します。これにより、コンパイラの複数の部分でpkgcontextが共有され、現在のパッケージコンテキストを追跡できるようになります。

src/cmd/gc/go.yの変更

  1. 型定義の追加:

    -%type	<node>		hidden_funres ohidden_funres hidden_importsym
    +%type	<node>		hidden_funres ohidden_funres hidden_importsym hidden_pkg_importsym
    

    Yaccの型定義にhidden_pkg_importsymが追加されました。これは、パーサーがhidden_pkg_importsymという新しい種類のノードを扱うことを可能にします。

  2. hidden_importルールの変更:

    -|\tLVAR hidden_importsym hidden_type
    +|\tLVAR hidden_pkg_importsym hidden_type
    // ... (同様の変更がLCONST, LTYPE, LFUNCにも適用)
    

    hidden_importルール内で、LVAR(変数)、LCONST(定数)、LTYPE(型)、LFUNC(関数)といったインポートされた要素のシンボルを解析する際に、これまでのhidden_importsymの代わりにhidden_pkg_importsymを使用するように変更されました。これは、インポートされたシンボルを解析する際に、そのシンボルが属するパッケージのコンテキストをより明示的に取得するための準備です。

  3. hidden_pkg_importsymルールの追加:

    +hidden_pkg_importsym:
    +\thidden_importsym
    +\t{
    +\t\t$$ = $1;
    +\t\tpkgcontext = $$->psym->name;
    +\t}\n
    

    この新しいルールは、まずhidden_importsymを解析します。その後、アクションブロック内で、解析されたシンボルノード($1)を現在のノード($$)に代入し、さらにそのシンボルが持つパッケージシンボル(psym)の名前をグローバル変数pkgcontextに設定しています。これにより、パーサーがインポートされたシンボルを認識した時点で、そのシンボルが属するパッケージの名前がpkgcontextに格納され、後続のシンボル解決処理で利用できるようになります。

これらの変更は全体として、Goコンパイラがインポートされたシンボルを処理する際に、より正確で堅牢なパッケージコンテキスト情報を利用できるようにするためのものです。これにより、シンボル解決の曖昧さが解消され、コンパイラの正確性が向上したと考えられます。

関連リンク

参考にした情報源リンク