[インデックス 10604] ファイルの概要
このコミットは、Go言語のコンパイラ(gc
)におけるビルドの問題を修正するものです。具体的には、コンポジットリテラルにおいて型を括弧で囲むことを禁止するエラーチェックが何らかの理由で失われていたため、それを再導入しています。
コミット
commit 214ec7b5477cbb44bf702014e6f036f9533ad9ee
Author: Russ Cox <rsc@golang.org>
Date: Fri Dec 2 15:05:45 2011 -0500
gc: fix build (not sure how this edit got lost)
R=ken2, ken
CC=golang-dev
https://golang.org/cl/5449072
---
src/cmd/gc/go.y | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index a42a7488f7..530e54112a 100644
--- a/src/cmd/gc/go.y
+++ b/cmd/gc/go.y
@@ -915,6 +915,7 @@ pexpr_no_paren:
}\n |\t\'(\' expr_or_type \')\' \'{\' start_complit braced_keyval_list \'}\'\n \t{\n+\t\tyyerror("cannot parenthesize type in composite literal");\n \t\t$$ = $5;\n \t\t$$->right = $2;\n \t\t$$->list = $6;\n```
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/214ec7b5477cbb44bf702014e6f036f9533ad9ee](https://github.com/golang/go/commit/214ec7b5477cbb44bf702014e6f036f9533ad9ee)
## 元コミット内容
コミットメッセージは「gc: fix build (not sure how this edit got lost)」です。これは、Goコンパイラ(`gc`)のビルドに関する修正であり、特定の編集(この場合はコンポジットリテラルにおける型の括弧化を禁止するエラーチェック)が何らかの理由で失われたため、それを元に戻す、あるいは再適用するものであることを示しています。
## 変更の背景
Go言語では、コンポジットリテラルを記述する際に、その型を括弧で囲むことは通常許可されていません。例えば、`type MyStruct struct { ... }` という構造体がある場合、`MyStruct{}` のように直接型名を記述し、その後に波括弧で要素を記述します。` (MyStruct){}` のように型を括弧で囲むことは、Goの構文としては不正です。
このコミットの背景には、Goコンパイラのパーサー(構文解析器)が、このような不正な構文を検出してエラーを報告するべきであるにもかかわらず、そのチェックが何らかの理由で失われていたという問題があります。コミットメッセージの「not sure how this edit got lost」という記述から、このエラーチェックは以前は存在していたが、意図せず削除されたか、あるいは他の変更によって上書きされてしまった可能性が示唆されます。この修正は、コンパイラの堅牢性を保ち、Go言語の構文規則を厳密に適用するために必要でした。
## 前提知識の解説
### Go言語のコンポジットリテラル
Go言語におけるコンポジットリテラル(Composite Literal)は、構造体(struct)、配列(array)、スライス(slice)、マップ(map)といった複合型の値を生成するための構文です。基本的な形式は `Type{elements}` となります。
* **構造体リテラル**: `Person{Name: "Alice", Age: 30}`
* **スライスリテラル**: `[]int{1, 2, 3}`
* **配列リテラル**: `[3]string{"red", "green", "blue"}`
* **マップリテラル**: `map[string]int{"apple": 1, "banana": 2}`
コンポジットリテラルでは、型名の後に直接波括弧 `{}` を続けて要素を記述します。型名を括弧で囲むことは、Goの通常の構文規則では許可されていません。ただし、特定の文脈(例えば、`if` や `for` ステートメントの初期化部分で、複合リテラルが曖昧な解釈をされる可能性がある場合)では、パーサーの曖昧さを解消するために、コンポジットリテラル全体を括弧で囲むことが必要になる場合があります。しかし、これはリテラル全体を囲むものであり、型自体を括弧で囲むこととは異なります。
### `go.y` ファイルとYacc/Bison
`src/cmd/gc/go.y` は、Goコンパイラ(`gc`)の字句解析器および構文解析器の一部を定義するファイルです。`.y` 拡張子は、通常Yacc(Yet Another Compiler Compiler)またはそのGNU版であるBisonの入力ファイルであることを示します。
* **Yacc/Bison**: これらは、BNF(Backus-Naur Form)のような形式で記述された文法定義から、C言語などのソースコードを生成するパーサー生成ツールです。生成されたコードは、入力ストリーム(この場合はGoのソースコード)を読み込み、文法規則に従って構文木を構築します。
* **`go.y` の役割**: `go.y` ファイルには、Go言語の構文規則が記述されており、コンパイラがGoのソースコードを正しく解釈するための基盤となります。このファイル内のルールは、Goの様々な構文要素(式、ステートメント、宣言など)がどのように構成されるかを定義しています。
### `yyerror` 関数
`yyerror` は、Yacc/Bisonによって生成されるパーサーにおいて、構文エラーが発生した際に呼び出される標準的なエラー報告関数です。この関数は、通常、エラーメッセージを標準エラー出力に表示し、パーサーがエラー回復処理を行うか、あるいは解析を中止するかを決定します。
このコミットでは、`yyerror` を呼び出すことで、コンポジットリテラルにおける不正な型の括弧化を検出した際に、明確なエラーメッセージをユーザーに提供するようにしています。
## 技術的詳細
このコミットは、Goコンパイラの構文解析器(パーサー)の修正に焦点を当てています。`src/cmd/gc/go.y` ファイルは、Go言語の文法規則を定義しており、コンパイラがソースコードを解析する際の基盤となります。
変更箇所は、`pexpr_no_paren` という文法規則のセクションにあります。この規則は、括弧で囲まれていない式(`expr_no_paren`)を処理する部分に関連しています。特に注目すべきは、以下のパターンです。
`'(' expr_or_type ')' '{' start_complit braced_keyval_list '}'`
このパターンは、`(` で始まり、`expr_or_type`(式または型)が続き、`)` で閉じられ、その後に `{` で始まるコンポジットリテラルが続く構文を捕捉しようとしています。Go言語の通常の構文では、コンポジットリテラルの型を括弧で囲むことは許可されていません。例えば、`(` `MyStruct` `)` `{}` のような形式は不正です。
このコミットでは、この不正な構文パターンが検出された場合に、`yyerror("cannot parenthesize type in composite literal");` というエラーメッセージを出力するように修正が加えられました。これは、コンパイラがGo言語の構文規則を厳密に適用し、開発者に不正な構文の使用を警告するためのものです。
コミットメッセージにある「not sure how this edit got lost」という記述は、このエラーチェックが以前のバージョンでは存在していたが、何らかの理由でコードベースから失われていたことを示唆しています。これは、リファクタリング、マージの競合、あるいは単なる見落としなど、様々な原因が考えられます。このコミットは、失われた重要な構文チェックを復元し、コンパイラの正確性と堅牢性を向上させることを目的としています。
## コアとなるコードの変更箇所
```diff
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -915,6 +915,7 @@ pexpr_no_paren:
}\n |\t\'(\' expr_or_type \')\' \'{\' start_complit braced_keyval_list \'}\'\n \t{\n+\t\tyyerror("cannot parenthesize type in composite literal");\n \t\t$$ = $5;\n \t\t$$->right = $2;\n \t\t$$->list = $6;\n```
## コアとなるコードの解説
変更は `src/cmd/gc/go.y` ファイルの915行目付近にあります。
元のコードでは、以下の文法規則が定義されていました。
```yacc
pexpr_no_paren:
// ... 既存の規則 ...
|\t'(' expr_or_type ')' '{' start_complit braced_keyval_list '}'
{
$$ = $5;
$$->right = $2;
$$->list = $6;
}
この規則は、(
で始まり、expr_or_type
(式または型)が続き、)
で閉じられ、その後に波括弧で囲まれたコンポジットリテラルが続く構文を認識します。Go言語の構文では、コンポジットリテラルの型を括弧で囲むことは許可されていません。
このコミットでは、この規則のアクションブロックに以下の行が追加されました。
+\t\tyyerror("cannot parenthesize type in composite literal");
この追加により、パーサーが (Type){...}
のような形式のコンポジットリテラルを検出した場合、直ちに yyerror
関数が呼び出され、「cannot parenthesize type in composite literal」(コンポジットリテラルで型を括弧で囲むことはできません)というエラーメッセージが生成されます。
この変更の目的は、Go言語の構文規則に違反するコードに対して、コンパイラが明確なエラーを報告するようにすることです。これにより、開発者は不正な構文の使用を早期に認識し、修正することができます。
$$ = $5; $$->right = $2; $$->list = $6;
の行は、パーサーが構文木を構築する際に行うセマンティックアクションです。エラーが報告された後も、パーサーは部分的に構文木を構築しようとしますが、このエラーによってコンパイルは失敗します。
関連リンク
参考にした情報源リンク
- Go Composite Literals: https://medium.com/@vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFdy8J49uE3nYDFEemikurlvz2xJJlWlPEQoqyMOOazadLTOwvZppiPWteUBxbDEpikKrztqlVEEngHXk92CFqnju6ipd0S08hzHwKdkhl8Mq1ncqsHKK2Fv0F2Cr7ZqZhzrE5m3Wktz3bulzFthFcKn65eyNeycrbTW1FSJPgRLYnSUxMi91SBQpqX2erYRQ==
- Go Composite Literals (boldlygo.tech): https://boldlygo.tech/posts/2020/01/20/go-composite-literals/
- Go Composite Literals (Stack Overflow): https://stackoverflow.com/questions/20503470/go-composite-literals
- Go Parser Ambiguity (boldlygo.tech): https://boldlygo.tech/posts/2020/01/20/go-composite-literals/#parser-ambiguity
- Go Parser Ambiguity (GitHub issue): https://github.com/golang/go/issues/11359
- Go Parser Ambiguity (GitHub discussion): https://github.com/golang/go/issues/11359#issuecomment-11359