[インデックス 1684] ファイルの概要
このコミットは、Go言語のコンパイラ(gc
)におけるインターフェース型に関する重要な変更を導入しています。具体的には、インターフェース内に他のインターフェース型を埋め込む機能(embedded interface types)を実装し、それによってコードの再利用性と表現力を向上させています。
コミット
commit b4af09ab569d72c7103b46f4e4833a4c7bc4ae78
Author: Russ Cox <rsc@golang.org>
Date: Mon Feb 16 16:36:18 2009 -0800
embedded interface types in interfaces.
R=ken
OCL=25072
CL=25072
---
src/cmd/gc/dcl.c | 36 +++++++++++++++++++++++++++++++++---\n src/cmd/gc/go.y | 14 +++++++++++---\n 2 files changed, 44 insertions(+), 6 deletions(-)\n
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b4af09ab569d72c7103b46f4e4833a4c7bc4ae78
元コミット内容
embedded interface types in interfaces.
R=ken
OCL=25072
CL=25072
変更の背景
このコミットは、Go言語の初期開発段階(2009年2月)に行われたもので、Go言語のインターフェースの設計と機能拡張の一環として導入されました。当時のGo言語はまだ公開されておらず、言語仕様が活発に議論・実装されていた時期です。
インターフェースはGo言語の重要な特徴の一つであり、ポリモーフィズムを実現するための強力なメカニズムです。しかし、複数のインターフェースが共通のメソッドセットを持つ場合や、あるインターフェースが別のインターフェースの機能を「継承」したい場合に、冗長なメソッド宣言が必要になるという課題がありました。
この「インターフェースの埋め込み」機能は、このような冗長性を排除し、より簡潔で表現力豊かなインターフェースの定義を可能にすることを目的としています。これにより、既存のインターフェースのメソッドセットを新しいインターフェースに簡単に含めることができるようになり、インターフェースの設計と利用がより柔軟になります。
前提知識の解説
Go言語のインターフェース
Go言語のインターフェースは、メソッドのシグネチャの集合を定義する型です。Goのインターフェースは「暗黙的」に実装されます。つまり、ある型がインターフェースで定義されたすべてのメソッドを実装していれば、その型はそのインターフェースを満たしていると見なされます。implements
キーワードのような明示的な宣言は不要です。
例:
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
構造体の埋め込み (Struct Embedding)
Go言語には、構造体の中に他の構造体を「埋め込む」機能があります。これにより、埋め込まれた構造体のフィールドやメソッドが、外側の構造体のフィールドやメソッドであるかのようにアクセスできるようになります。これは、Goにおける「継承」に似たコードの再利用メカニズムとして機能します。
例:
type Base struct {
ID int
}
func (b Base) GetID() int {
return b.ID
}
type User struct {
Base // Base構造体を埋め込み
Name string
}
// User型のインスタンスからBaseのフィールドやメソッドに直接アクセスできる
// user := User{Base: Base{ID: 1}, Name: "Alice"}
// fmt.Println(user.GetID()) // 1
このコミットは、この構造体の埋め込みの概念をインターフェースにも拡張するものです。
技術的詳細
このコミットの主要な変更点は、Goコンパイラ(gc
)がインターフェース定義内で他のインターフェース型を認識し、その埋め込まれたインターフェースのメソッドを自動的に新しいインターフェースのメソッドセットに含めるようにすることです。
具体的には、以下のコンパイラ内部の処理が変更されています。
-
src/cmd/gc/go.y
の変更:go.y
はGoコンパイラの字句解析器と構文解析器の定義ファイル(Yacc/Bison形式)です。interfacedcl
(インターフェース宣言)の文法が拡張され、latype
(型名)を直接インターフェース宣言内に記述できるようになりました。これは、他のインターフェースを埋め込むための構文的な変更です。- 以前は、インターフェースの宣言はメソッドのリストのみを許可していましたが、この変更により、型名(つまり、他のインターフェース型)も許可されるようになりました。
-
src/cmd/gc/dcl.c
の変更:dcl.c
はGoコンパイラの宣言処理を担当するファイルです。stotype
関数(おそらく "structure to type" の略で、ASTノードから型を構築する関数)が変更されています。- この関数内で、
et == TINTER && n->left == N
という条件が追加されています。これは、現在の処理対象がインターフェース型(TINTER
)であり、かつノードがメソッド名を持たない(つまり、埋め込まれた型である)場合に該当します。 - 埋め込まれたインターフェース型が検出されると、そのインターフェースが持つすべてのメソッドがループ処理され、新しいインターフェースのメソッドセットに「インライン化」されます。
- この際、埋め込まれる型が実際にインターフェース型であるかどうかのチェック(
n->type->etype != TINTER
)が行われ、非インターフェース型が埋め込まれた場合にはエラーが報告されます。 - また、埋め込まれたインターフェースに含まれるメソッドがエクスポートされていない(小文字で始まる)場合、つまり、異なるパッケージから埋め込まれたインターフェースが非エクスポートメソッドを持つ場合にもエラーが報告されます。これは、Goのエクスポートルール(大文字で始まる識別子のみがエクスポートされる)に準拠するためです。
この変更により、コンパイラはインターフェースの埋め込みを構文的に解釈し、セマンティックに処理できるようになります。結果として、ユーザーは以下のようなコードを書けるようになります。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader // Readerインターフェースを埋め込み
Writer // Writerインターフェースを埋め込み
}
ReadWriter
インターフェースは、Read
メソッドと Write
メソッドの両方を持つことになります。
コアとなるコードの変更箇所
src/cmd/gc/dcl.c
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -666,20 +666,50 @@ loop:
\tgoto next;\n \t}\n \n-\tif(n->op != ODCLFIELD || n->type == T)\n+\tif(n->op != ODCLFIELD)\n \t\tfatal(\"stotype: oops %N\\n\", n);\n \n+\tif(n->type == T) {\n+\t\t// assume error already printed\n+\t\tgoto next;\n+\t}\n+\n \tswitch(n->val.ctype) {\n \tcase CTSTR:\n+\t\tif(et != TSTRUCT)\n+\t\t\tyyerror(\"interface method cannot have annotation\");\n \t\tnote = n->val.u.sval;\n \t\tbreak;\n \tdefault:\n-\t\tyyerror(\"field annotation must be string\");\n+\t\tif(et != TSTRUCT)\n+\t\t\tyyerror(\"interface method cannot have annotation\");\n+\t\telse\n+\t\t\tyyerror(\"field annotation must be string\");\n \tcase CTxxx:\n \t\tnote = nil;\n \t\tbreak;\n \t}\n \n+\tif(et == TINTER && n->left == N) {\n+\t\t// embedded interface - inline the methods\n+\t\tif(n->type->etype != TINTER) {\n+\t\t\tyyerror(\"interface contains embedded non-interface %T\", t);\n+\t\t\tgoto next;\n+\t\t}\n+\t\tfor(t1=n->type->type; t1!=T; t1=t1->down) {\n+\t\t\tif(strcmp(t1->sym->package, package) != 0)\n+\t\t\t\tyyerror(\"embedded interface contains unexported method %S\", t1->sym);\n+\t\t\tf = typ(TFIELD);\n+\t\t\tf->type = t1->type;\n+\t\t\tf->width = BADWIDTH;\n+\t\t\tf->nname = newname(t1->sym);\n+\t\t\tf->sym = t1->sym;\n+\t\t\t*t = f;\n+\t\t\tt = &f->down;\n+\t\t}\n+\t\tgoto next;\n+\t}\n+\n \tf = typ(TFIELD);\n \tf->type = n->type;\n \tf->note = note;\n```
### `src/cmd/gc/go.y`
```c
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -1385,8 +1385,8 @@ embed:\n \t\tcontext = nil;\n \t}\n \n-interfacedcl:\n-\tnew_name \',\' interfacedcl\n+interfacedcl1:\n+\tnew_name \',\' interfacedcl1\n \t{\n \t\t$$ = nod(ODCLFIELD, $1, N);\n \t\t$$ = nod(OLIST, $$, $3);\n@@ -1397,6 +1397,14 @@ interfacedcl:\n \t\t$$->type = $2;\n \t}\n \n+interfacedcl:\n+\tinterfacedcl1\n+|\tlatype\n+\t{\n+\t\t$$ = nod(ODCLFIELD, N, N);\n+\t\t$$->type = oldtype($1);\n+\t}\n+\n indcl:\n \t\'(\' oarg_type_list \')\' fnres\n \t{\n```
## コアとなるコードの解説
### `src/cmd/gc/dcl.c` の変更点
* **`stotype` 関数の変更**: この関数は、Goの型システムにおいて、構文解析されたノード(`Node`)から実際の型(`Type`)を構築する役割を担っています。特に、構造体フィールドやインターフェースメソッドの宣言を処理します。
* **埋め込みインターフェースの検出と処理**:
* `if(et == TINTER && n->left == N)`: この条件が、インターフェース定義内で「埋め込まれた型」(メソッド名を持たない型)を検出する肝となる部分です。`et == TINTER` は現在の処理がインターフェース型を構築中であることを示し、`n->left == N` は現在のノードがメソッド名を持たないことを示します。
* `if(n->type->etype != TINTER)`: 埋め込まれようとしている型が実際にインターフェース型であるかを確認します。もしそうでなければ、`yyerror` でエラーを報告します。
* `for(t1=n->type->type; t1!=T; t1=t1->down)`: 埋め込まれたインターフェース(`n->type`)のメソッドリストをイテレートします。`t1` は個々のメソッドを表す型ノードです。
* `if(strcmp(t1->sym->package, package) != 0) && ... yyerror(...)`: 埋め込まれたインターフェースのメソッドが、現在のパッケージと異なるパッケージに属しているにもかかわらず、エクスポートされていない(シンボル名が小文字で始まる)場合にエラーを報告します。これは、Goの可視性ルールに則ったものです。
* `f = typ(TFIELD); ... *t = f; t = &f->down;`: 埋め込まれたインターフェースの各メソッドを、新しいインターフェースのメソッドリストに「フィールド」として追加します。`TFIELD` はコンパイラ内部でメソッドを表すために使用される型です。これにより、埋め込まれたインターフェースのメソッドが、あたかも新しいインターフェースで直接宣言されたかのように扱われます。
### `src/cmd/gc/go.y` の変更点
* **`interfacedcl` ルールの拡張**:
* `interfacedcl1` という新しいルールが導入され、これは従来のメソッドリストの宣言を扱います。
* 元の `interfacedcl` ルールが変更され、`interfacedcl1`(メソッドリスト)または `latype`(型名)のいずれかを受け入れるようになりました。
* `latype` は、Goの型名を指します。これにより、インターフェース定義内で他のインターフェースの型名を記述することが構文的に許可されます。
* `$$ = nod(ODCLFIELD, N, N); $$->type = oldtype($1);`: `latype` が検出された場合、これは埋め込みインターフェースとして扱われ、`ODCLFIELD` ノード(フィールド宣言ノード)として表現され、その型が埋め込まれるインターフェースの型として設定されます。`N` はノードが子を持たないことを示し、ここではメソッド名がないことを意味します。
これらの変更により、Goコンパイラはインターフェースの埋め込みという新しい構文を正しく解析し、そのセマンティクス(埋め込まれたインターフェースのメソッドを新しいインターフェースに含める)を適切に処理できるようになりました。
## 関連リンク
* Go言語のインターフェースに関する公式ドキュメント: [https://go.dev/tour/methods/10](https://go.dev/tour/methods/10)
* Go言語の埋め込みに関する公式ドキュメント: [https://go.dev/tour/methods/11](https://go.dev/tour/methods/11)
* Go言語の初期のコミット履歴 (GitHub): [https://github.com/golang/go/commits/master?after=b4af09ab569d72c7103b46f4e4833a4c7bc4ae78+34&branch=master&path%5B%5D=src%2Fcmd%2Fgc](https://github.com/golang/go/commits/master?after=b4af09ab569d72c7103b46f4e4833a4c7bc4ae78+34&branch=master&path%5B%5D=src%2Fcmd%2Fgc)
## 参考にした情報源リンク
* Go言語の公式ドキュメントおよびGo Tour
* Go言語のGitHubリポジトリのコミット履歴
* Yacc/Bisonの構文解析器の概念に関する一般的な知識
* Go言語のコンパイラ(`gc`)のソースコード構造に関する一般的な理解# [インデックス 1684] ファイルの概要
このコミットは、Go言語のコンパイラ(`gc`)におけるインターフェース型に関する重要な変更を導入しています。具体的には、インターフェース内に他のインターフェース型を埋め込む機能(embedded interface types)を実装し、それによってコードの再利用性と表現力を向上させています。
## コミット
commit b4af09ab569d72c7103b46f4e4833a4c7bc4ae78 Author: Russ Cox rsc@golang.org Date: Mon Feb 16 16:36:18 2009 -0800
embedded interface types in interfaces.
R=ken
OCL=25072
CL=25072
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/b4af09ab569d72c7103b46f4e4833a4c7bc4ae78](https://github.com/golang/go/commit/b4af09ab569d72c7103b46f4e4833a4c7bc4ae78)
## 元コミット内容
embedded interface types in interfaces.
R=ken OCL=25072 CL=25072
## 変更の背景
このコミットは、Go言語の初期開発段階(2009年2月)に行われたもので、Go言語のインターフェースの設計と機能拡張の一環として導入されました。当時のGo言語はまだ公開されておらず、言語仕様が活発に議論・実装されていた時期です。
インターフェースはGo言語の重要な特徴の一つであり、ポリモーフィズムを実現するための強力なメカニズムです。しかし、複数のインターフェースが共通のメソッドセットを持つ場合や、あるインターフェースが別のインターフェースの機能を「継承」したい場合に、冗長なメソッド宣言が必要になるという課題がありました。
この「インターフェースの埋め込み」機能は、このような冗長性を排除し、より簡潔で表現力豊かなインターフェースの定義を可能にすることを目的としています。これにより、既存のインターフェースのメソッドセットを新しいインターフェースに簡単に含めることができるようになり、インターフェースの設計と利用がより柔軟になります。
## 前提知識の解説
### Go言語のインターフェース
Go言語のインターフェースは、メソッドのシグネチャの集合を定義する型です。Goのインターフェースは「暗黙的」に実装されます。つまり、ある型がインターフェースで定義されたすべてのメソッドを実装していれば、その型はそのインターフェースを満たしていると見なされます。`implements`キーワードのような明示的な宣言は不要です。
例:
```go
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
構造体の埋め込み (Struct Embedding)
Go言語には、構造体の中に他の構造体を「埋め込む」機能があります。これにより、埋め込まれた構造体のフィールドやメソッドが、外側の構造体のフィールドやメソッドであるかのようにアクセスできるようになります。これは、Goにおける「継承」に似たコードの再利用メカニズムとして機能します。
例:
type Base struct {
ID int
}
func (b Base) GetID() int {
return b.ID
}
type User struct {
Base // Base構造体を埋め込み
Name string
}
// User型のインスタンスからBaseのフィールドやメソッドに直接アクセスできる
// user := User{Base: Base{ID: 1}, Name: "Alice"}
// fmt.Println(user.GetID()) // 1
このコミットは、この構造体の埋め込みの概念をインターフェースにも拡張するものです。
技術的詳細
このコミットの主要な変更点は、Goコンパイラ(gc
)がインターフェース定義内で他のインターフェース型を認識し、その埋め込まれたインターフェースのメソッドを自動的に新しいインターフェースのメソッドセットに含めるようにすることです。
具体的には、以下のコンパイラ内部の処理が変更されています。
-
src/cmd/gc/go.y
の変更:go.y
はGoコンパイラの字句解析器と構文解析器の定義ファイル(Yacc/Bison形式)です。interfacedcl
(インターフェース宣言)の文法が拡張され、latype
(型名)を直接インターフェース宣言内に記述できるようになりました。これは、他のインターフェースを埋め込むための構文的な変更です。- 以前は、インターフェースの宣言はメソッドのリストのみを許可していましたが、この変更により、型名(つまり、他のインターフェース型)も許可されるようになりました。
-
src/cmd/gc/dcl.c
の変更:dcl.c
はGoコンパイラの宣言処理を担当するファイルです。stotype
関数(おそらく "structure to type" の略で、ASTノードから型を構築する関数)が変更されています。- この関数内で、
et == TINTER && n->left == N
という条件が追加されています。これは、現在の処理対象がインターフェース型(TINTER
)であり、かつノードがメソッド名を持たない(つまり、埋め込まれた型である)場合に該当します。 - 埋め込まれたインターフェース型が検出されると、そのインターフェースが持つすべてのメソッドがループ処理され、新しいインターフェースのメソッドセットに「インライン化」されます。
- この際、埋め込まれる型が実際にインターフェース型であるかどうかのチェック(
n->type->etype != TINTER
)が行われ、非インターフェース型が埋め込まれた場合にはエラーが報告されます。 - また、埋め込まれたインターフェースに含まれるメソッドがエクスポートされていない(小文字で始まる)場合、つまり、異なるパッケージから埋め込まれたインターフェースが非エクスポートメソッドを持つ場合にもエラーが報告されます。これは、Goのエクスポートルール(大文字で始まる識別子のみがエクスポートされる)に準拠するためです。
この変更により、コンパイラはインターフェースの埋め込みを構文的に解釈し、セマンティックに処理できるようになります。結果として、ユーザーは以下のようなコードを書けるようになります。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader // Readerインターフェースを埋め込み
Writer // Writerインターフェースを埋め込み
}
ReadWriter
インターフェースは、Read
メソッドと Write
メソッドの両方を持つことになります。
コアとなるコードの変更箇所
src/cmd/gc/dcl.c
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -666,20 +666,50 @@ loop:
\tgoto next;\n \t}\n \n-\tif(n->op != ODCLFIELD || n->type == T)\n+\tif(n->op != ODCLFIELD)\n \t\tfatal(\"stotype: oops %N\\n\", n);\n \n+\tif(n->type == T) {\n+\t\t// assume error already printed\n+\t\tgoto next;\n+\t}\n+\n \tswitch(n->val.ctype) {\n \tcase CTSTR:\n+\t\tif(et != TSTRUCT)\n+\t\t\tyyerror(\"interface method cannot have annotation\");\n \t\tnote = n->val.u.sval;\n \t\tbreak;\n \tdefault:\n-\t\tyyerror(\"field annotation must be string\");\n+\t\tif(et != TSTRUCT)\n+\t\t\tyyerror(\"interface method cannot have annotation\");\n+\t\telse\n+\t\t\tyyerror(\"field annotation must be string\");\n \tcase CTxxx:\n \t\tnote = nil;\n \t\tbreak;\n \t}\n \n+\tif(et == TINTER && n->left == N) {\n+\t\t// embedded interface - inline the methods\n+\t\tif(n->type->etype != TINTER) {\n+\t\t\tyyerror(\"interface contains embedded non-interface %T\", t);\n+\t\t\tgoto next;\n+\t\t}\n+\t\tfor(t1=n->type->type; t1!=T; t1=t1->down) {\n+\t\t\tif(strcmp(t1->sym->package, package) != 0)\n+\t\t\t\tyyerror(\"embedded interface contains unexported method %S\", t1->sym);\n+\t\t\tf = typ(TFIELD);\n+\t\t\tf->type = t1->type;\n+\t\t\tf->width = BADWIDTH;\n+\t\t\tf->nname = newname(t1->sym);\n+\t\t\tf->sym = t1->sym;\n+\t\t\t*t = f;\n+\t\t\tt = &f->down;\n+\t\t}\n+\t\tgoto next;\n+\t}\n+\n \tf = typ(TFIELD);\n \tf->type = n->type;\n \tf->note = note;\n```
### `src/cmd/gc/go.y`
```c
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -1385,8 +1385,8 @@ embed:\n \t\tcontext = nil;\n \t}\n \n-interfacedcl:\n-\tnew_name \',\' interfacedcl\n+interfacedcl1:\n+\tnew_name \',\' interfacedcl1\n \t{\n \t\t$$ = nod(ODCLFIELD, $1, N);\n \t\t$$ = nod(OLIST, $$, $3);\n@@ -1397,6 +1397,14 @@ interfacedcl:\n \t\t$$->type = $2;\n \t}\n \n+interfacedcl:\n+\tinterfacedcl1\n+|\tlatype\n+\t{\n+\t\t$$ = nod(ODCLFIELD, N, N);\n+\t\t$$->type = oldtype($1);\n+\t}\n+\n indcl:\n \t\'(\' oarg_type_list \')\' fnres\n \t{\n```
## コアとなるコードの解説
### `src/cmd/gc/dcl.c` の変更点
* **`stotype` 関数の変更**: この関数は、Goの型システムにおいて、構文解析されたノード(`Node`)から実際の型(`Type`)を構築する役割を担っています。特に、構造体フィールドやインターフェースメソッドの宣言を処理します。
* **埋め込みインターフェースの検出と処理**:
* `if(et == TINTER && n->left == N)`: この条件が、インターフェース定義内で「埋め込まれた型」(メソッド名を持たない型)を検出する肝となる部分です。`et == TINTER` は現在の処理がインターフェース型を構築中であることを示し、`n->left == N` は現在のノードがメソッド名を持たないことを示します。
* `if(n->type->etype != TINTER)`: 埋め込まれようとしている型が実際にインターフェース型であるかを確認します。もしそうでなければ、`yyerror` でエラーを報告します。
* `for(t1=n->type->type; t1!=T; t1=t1->down)`: 埋め込まれたインターフェース(`n->type`)のメソッドリストをイテレートします。`t1` は個々のメソッドを表す型ノードです。
* `if(strcmp(t1->sym->package, package) != 0) && ... yyerror(...)`: 埋め込まれたインターフェースのメソッドが、現在のパッケージと異なるパッケージに属しているにもかかわらず、エクスポートされていない(シンボル名が小文字で始まる)場合にエラーを報告します。これは、Goの可視性ルールに則ったものです。
* `f = typ(TFIELD); ... *t = f; t = &f->down;`: 埋め込まれたインターフェースの各メソッドを、新しいインターフェースのメソッドリストに「フィールド」として追加します。`TFIELD` はコンパイラ内部でメソッドを表すために使用される型です。これにより、埋め込まれたインターフェースのメソッドが、あたかも新しいインターフェースで直接宣言されたかのように扱われます。
### `src/cmd/gc/go.y` の変更点
* **`interfacedcl` ルールの拡張**:
* `interfacedcl1` という新しいルールが導入され、これは従来のメソッドリストの宣言を扱います。
* 元の `interfacedcl` ルールが変更され、`interfacedcl1`(メソッドリスト)または `latype`(型名)のいずれかを受け入れるようになりました。
* `latype` は、Goの型名を指します。これにより、インターフェース定義内で他のインターフェースの型名を記述することが構文的に許可されます。
* `$$ = nod(ODCLFIELD, N, N); $$->type = oldtype($1);`: `latype` が検出された場合、これは埋め込みインターフェースとして扱われ、`ODCLFIELD` ノード(フィールド宣言ノード)として表現され、その型が埋め込まれるインターフェースの型として設定されます。`N` はノードが子を持たないことを示し、ここではメソッド名がないことを意味します。
これらの変更により、Goコンパイラはインターフェースの埋め込みという新しい構文を正しく解析し、そのセマンティクス(埋め込まれたインターフェースのメソッドを新しいインターフェースに含める)を適切に処理できるようになりました。
## 関連リンク
* Go言語のインターフェースに関する公式ドキュメント: [https://go.dev/tour/methods/10](https://go.dev/tour/methods/10)
* Go言語の埋め込みに関する公式ドキュメント: [https://go.dev/tour/methods/11](https://go.dev/tour/methods/11)
* Go言語の初期のコミット履歴 (GitHub): [https://github.com/golang/go/commits/master?after=b4af09ab569d72c7103b46f4e4833a4c7bc4ae78+34&branch=master&path%5B%5D=src%2Fcmd%2Fgc](https://github.com/golang/go/commits/master?after=b4af09ab569d72c7103b46f4e4833a4c7bc4ae78+34&branch=master&path%5B%5D=src%2Fcmd%2Fgc)
## 参考にした情報源リンク
* Go言語の公式ドキュメントおよびGo Tour
* Go言語のGitHubリポジトリのコミット履歴
* Yacc/Bisonの構文解析器の概念に関する一般的な知識
* Go言語のコンパイラ(`gc`)のソースコード構造に関する一般的な理解
* Web検索: "Go language embedded interface types in interfaces 2009"