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

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

このコミットは、Go言語の初期段階におけるimport文の構文解析に関するバグを修正するものです。具体的には、importブロック内でパッケージにエイリアスを付けてインポートする際に、本来セミコロン(または改行)が必要な箇所でそれが省略されていてもコンパイラがエラーを報告せず、不正な構文を許容してしまっていた問題に対処しています。この修正は、新しいテストケースtest/bugs/bug125.goの追加と、そのテストの期待される出力(test/golden.out)の更新によって行われています。

コミット

import syntax incorrect

R=r
OCL=19457
CL=19457

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

https://github.com/golang/go/commit/6c5fc055c804c4b2327e23f1a03f5ffec5ddbf91

元コミット内容

commit 6c5fc055c804c4b2327e23f1a03f5ffec5ddbf91
Author: Robert Griesemer <gri@golang.org>
Date:   Tue Nov 18 09:39:34 2008 -0800

    import syntax incorrect
    
    R=r
    OCL=19457
    CL=19457
---
 test/bugs/bug125.go | 15 +++++++++++++++
 test/golden.out     |  7 +++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/test/bugs/bug125.go b/test/bugs/bug125.go
new file mode 100644
index 0000000000..e2be1645bc
--- /dev/null
+++ b/test/bugs/bug125.go
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	OS "os"  // should require semicolon here; this is no different from other decls
+	IO "io"
+)
+
+func main() {
+}
diff --git a/test/golden.out b/test/golden.out
index 3e113a375b..efad87433d 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -125,7 +125,7 @@ BUG: errchk: command succeeded unexpectedly:  6g bugs/bug104.go
 
 =========== bugs/bug105.go
 bugs/bug105.go:8: P: undefined
-bugs/bug105.go:8: illegal types for operand: RETURN
+bugs/bug105.go:9: illegal types for operand: RETURN
 	int
 BUG: should compile
 
@@ -139,7 +139,7 @@ BUG: bug115 should compile
 
 =========== bugs/bug117.go
 bugs/bug117.go:9: undefined DOT get on PS
-bugs/bug117.go:9: illegal types for operand: RETURN
+bugs/bug117.go:10: illegal types for operand: RETURN
 	int
 BUG: should compile
 
@@ -169,6 +169,9 @@ BUG: errchk: command succeeded unexpectedly:  6g bugs/bug123.go
 =========== bugs/bug124.go
 BUG: errchk: command succeeded unexpectedly:  6g bugs/bug124.go
 
+=========== bugs/bug125.go
+BUG: errchk: command succeeded unexpectedly:  6g bugs/bug125.go
+
 =========== fixedbugs/bug016.go
 fixedbugs/bug016.go:7: overflow converting constant to uint
 

変更の背景

Go言語の初期開発段階において、コンパイラの構文解析器がimport文の特定の形式、特にパッケージにエイリアスを付けてインポートする際に、Go言語の文法規則を厳密に適用していませんでした。具体的には、以下のようなimportブロック内で、各インポート宣言の間にセミコロン(;)がない場合でも、コンパイラがエラーを報告せずに受け入れてしまっていました。

import (
	OS "os"
	IO "io"
)

Go言語の文法では、複数の宣言が同じ行に記述される場合や、特定の文脈ではセミコロンによる区切りが必要です。通常、Goでは改行がセミコロンとして扱われるため、明示的にセミコロンを記述することは稀ですが、このケースではコンパイラが期待通りに構文エラーを検出できていませんでした。このバグにより、不正な構文のコードがコンパイルされてしまう可能性があり、言語の厳密性と一貫性を保つ上で修正が必要とされました。

前提知識の解説

Go言語のimport

Go言語では、外部パッケージの機能を利用するためにimport文を使用します。import文にはいくつかの形式があります。

  1. 単一インポート: import "fmt"
  2. 複数インポート(グループ化):
    import (
    	"fmt"
    	"net/http"
    )
    
  3. エイリアス付きインポート: パッケージ名を変更してインポートする場合。
    import myfmt "fmt"
    
    この場合、fmt.Printlnmyfmt.Printlnとして呼び出されます。
  4. ブランクインポート: パッケージのinit関数を実行するだけで、そのパッケージの識別子を直接使用しない場合。
    import _ "image/png"
    
  5. ドットインポート: パッケージの識別子を修飾なしで直接使用する場合(非推奨)。
    import . "fmt"
    
    この場合、fmt.PrintlnPrintlnとして呼び出せます。

Go言語におけるセミコロンの扱い

Go言語の文法では、C言語やJavaのような言語とは異なり、ほとんどの文の終わりに明示的にセミコロンを記述する必要はありません。これは、Goのコンパイラが改行を自動的にセミコロンとして解釈する「自動セミコロン挿入(Automatic Semicolon Insertion: ASI)」ルールを持っているためです。

しかし、ASIルールには例外があります。例えば、複数の文を同じ行に記述する場合や、forループの初期化、条件、後処理の各セクションなど、特定の文脈では明示的なセミコロンが必要です。また、importブロック内でのエイリアス付きインポートのように、複数の宣言が連続する場合に、コンパイラが正しく区切りを認識できないケースも存在しました。

このコミットが修正しようとしているのは、まさにこのASIルールが正しく適用されていなかった、あるいは構文解析器が特定のimport文の構造を誤って解釈していたケースです。

技術的詳細

このコミットは、Goコンパイラの構文解析器(パーサー)がimportブロック内のエイリアス付きインポート宣言を処理する際のロジックの不備を修正しています。

Go言語の文法仕様では、importブロック内の各インポートパスは、改行またはセミコロンによって区切られる必要があります。例えば、以下の形式は有効です。

import (
	OS "os" // 改行で区切られる
	IO "io"
)

しかし、このコミット以前のコンパイラは、エイリアス付きインポートが連続する場合に、たとえ改行があっても、そのエイリアス部分の解析が不完全であったため、本来エラーとすべき構文を誤って受け入れてしまっていました。

test/bugs/bug125.goのコメント// should require semicolon here; this is no different from other declsが示唆するように、この問題はimport宣言が他の一般的な宣言(変数宣言など)と同様に扱われるべきであるにもかかわらず、エイリアス付きインポートの特定のケースでその一貫性が保たれていなかったことに起因します。

このコミットは、コンパイラがimport ( ... )ブロック内でエイリアス付きインポートを解析する際に、各インポート宣言の区切りをより厳密にチェックするように変更を加えたと考えられます。これにより、OS "os"の後に続くIO "io"が、前の宣言と正しく区切られていない場合に、コンパイラが構文エラーを報告するようになります。

test/golden.outの変更は、この修正が正しく機能していることを確認するためのものです。test/bugs/bug125.goは、このバグを再現するためのテストケースであり、このテストがコンパイル時にエラーを発生させることを期待しています。コミット前の状態では、このテストは「予期せず成功」していましたが、修正後は期待通りにエラーを発生させるようになります。

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

このコミットで変更されたコアとなるコードは、Go言語のコンパイラそのものではなく、そのコンパイラの動作を検証するためのテストファイルです。

  1. test/bugs/bug125.go (新規追加): このファイルは、import文の構文解析バグを再現するための新しいテストケースです。

    package main
    
    import (
    	OS "os"  // should require semicolon here; this is no different from other decls
    	IO "io"
    )
    
    func main() {
    }
    

    このコードは、importブロック内でOS "os"IO "io"という2つのエイリアス付きインポート宣言が連続しています。コメントにあるように、この形式は本来セミコロン(または改行による適切な区切り)が必要であり、それがなければ構文エラーとなるべきです。

  2. test/golden.out (変更): このファイルは、Goコンパイラのテストスイートにおける期待されるエラー出力やテスト結果を記録する「ゴールデンファイル」です。 このコミットでは、test/golden.outbugs/bug125.goに関する新しいエントリが追加されています。

    =========== bugs/bug125.go
    BUG: errchk: command succeeded unexpectedly:  6g bugs/bug125.go
    

    この行は、6g bugs/bug125.go(当時のGoコンパイラコマンド)を実行した際に、errchkツールが「予期せず成功した」ことを示しています。これは、bug125.goが本来エラーを出すべきなのに、コミット前のコンパイラがエラーを出さずにコンパイルを成功させてしまっていた、というバグの状態を記録しています。このgolden.outの更新は、コンパイラの修正が適用された後、このテストが期待通りにエラーを出すようになったことを検証するために使用されます。

コアとなるコードの解説

test/bugs/bug125.goは、Goコンパイラの構文解析器がimport文のエイリアス付き宣言を正しく処理しているかを検証するためのものです。

このテストファイルは、// errchk $G $D/$F.goという特別なコメントで始まっています。これは、Goのテストフレームワークがこのファイルをコンパイルし、その結果がエラーになることを期待していることを示します。もしエラーにならなければ、それはバグ(BUG: errchk: command succeeded unexpectedly)として報告されます。

問題の核心は、importブロック内の以下の部分です。

import (
	OS "os"  // should require semicolon here; this is no different from other decls
	IO "io"
)

Go言語の文法では、importブロック内の各インポート宣言は、改行またはセミコロンによって区切られる必要があります。エイリアス付きインポートOS "os"の後に改行がありますが、当時のコンパイラはこの特定のケースで、エイリアスと次のインポートパスの間の区切りを正しく認識できていなかったと考えられます。

このコミットが行われる前は、このbug125.goはコンパイルが成功してしまっていました。しかし、Go言語の設計思想からすると、これは不正な構文であり、コンパイラはエラーを報告すべきでした。

このコミットの修正(コンパイラ内部の構文解析ロジックの変更)により、bug125.goは期待通りにコンパイルエラーを発生させるようになりました。test/golden.outの更新は、この新しい振る舞い(エラーの発生)が正しいものであることをテストスイートに伝える役割を果たしています。

つまり、このコミットは、Go言語の文法規則に対するコンパイラの厳密性を向上させ、より堅牢な言語処理系を構築するための一歩であったと言えます。

関連リンク

参考にした情報源リンク