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

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

コミット

このコミットは、Go言語の初期開発段階(2008年12月)において、go ステートメントがインターフェースのメソッドを呼び出す際の挙動に関するバグをテストするために追加されたものです。具体的には、インターフェース型変数を介してメソッドをゴルーチンとして実行しようとした際に発生していたコンパイラまたはランタイムのエラーを捕捉するためのテストケース test/bugs/bug130.go を追加しています。このテストは、当時のGoコンパイラが go i.send(c) のようなコードを正しく処理できないことを示しており、test/golden.out に記録されたエラーメッセージ fatal error: getoutarg: not a func RANGE がその証拠です。

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

https://github.com/golang/go/commit/3f69acfb0c638f2f96cb21c2b5f8374e5cb6040d

元コミット内容

commit 3f69acfb0c638f2f96cb21c2b5f8374e5cb6040d
Author: Ian Lance Taylor <iant@golang.org>
Date:   Tue Dec 30 15:03:46 2008 -0800

    Test for a go statement which calls a method on an interface.

    R=ken
    DELTA=20  (20 added, 0 deleted, 0 changed)
    OCL=21889
    CL=21929
---\n test/bugs/bug130.go | 20 ++++++++++++++++++++\n test/golden.out     |  4 ++++\n 2 files changed, 24 insertions(+)

diff --git a/test/bugs/bug130.go b/test/bugs/bug130.go
new file mode 100644
index 0000000000..6e189ca5ce
--- /dev/null
+++ b/test/bugs/bug130.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+// 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
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+  s := S{0};
+  var i I = &s;
+  c := new(chan int);
+  go i.send(c);
+  sys.exit(<-c);
+}
diff --git a/test/golden.out b/test/golden.out
index feb0a4566e..50b957f121 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -157,6 +157,10 @@ BUG: errchk: command succeeded unexpectedly:  6g bugs/bug125.go
 bugs/bug129.go:6: syscall is package, not var
 BUG129
 
+=========== bugs/bug130.go
+bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE
+BUG: should run
+
 =========== fixedbugs/bug016.go
 fixedbugs/bug016.go:7: overflow converting constant to uint
 

変更の背景

このコミットは、Go言語の初期開発におけるバグ修正プロセスの一環として行われました。Go言語は、その設計当初から並行処理(コンカレンシー)を言語の核となる機能として重視しており、go ステートメントとチャネルはその主要な要素です。また、インターフェースはGoのポリモーフィズムを実現するための重要な機能です。

このコミットが追加された2008年当時、Go言語はまだ公開されておらず、活発な開発が行われていました。新しい言語機能が実装される過程では、予期せぬバグやエッジケースが頻繁に発見されます。特に、go ステートメントとインターフェースのメソッド呼び出しという、Goの重要な二つの概念が組み合わさる場面では、コンパイラやランタイムが正しくコードを生成・実行できない可能性がありました。

test/bugs/bug130.go は、まさにそのような問題、すなわち「インターフェースのメソッドをゴルーチンとして起動する」という特定のコードパターンが、当時のGoコンパイラ(またはランタイム)によって正しく処理されないことを示すために作成されました。test/golden.out に記録された fatal error: getoutarg: not a func RANGE というエラーは、コンパイラの内部的な問題、おそらくは関数呼び出しの引数処理や、ゴルーチン起動時のコンテキスト生成に関するバグを示唆しています。このテストの追加は、このバグを特定し、将来的に修正されたことを確認するための重要なステップでした。

前提知識の解説

Go言語の並行処理(Concurrency)

Go言語の最も特徴的な機能の一つが、軽量な並行処理のサポートです。

  • ゴルーチン (Goroutines): Goにおける並行実行の単位です。OSのスレッドよりもはるかに軽量で、数千、数万のゴルーチンを同時に実行することが可能です。go キーワードを関数の前に置くことで、その関数を新しいゴルーチンとして実行します。 例: go myFunction()
  • チャネル (Channels): ゴルーチン間の安全な通信を可能にするための「パイプ」のようなものです。チャネルを通じて値を送受信することで、共有メモリによる競合状態(race condition)を避けることができます。 例: c := make(chan int) (チャネルの作成), c <- value (送信), value := <-c (受信)

Go言語のインターフェース (Interfaces)

Goのインターフェースは、オブジェクト指向プログラミングにおけるポリモーフィズムを実現するための強力なメカニズムです。

  • 暗黙的な実装: Goのインターフェースは、JavaやC#のように implements キーワードを使って明示的に実装を宣言する必要がありません。ある型がインターフェースで定義されたすべてのメソッドを実装していれば、その型はそのインターフェースを「暗黙的に」実装しているとみなされます。
  • メソッドセット: インターフェースはメソッドのシグネチャ(名前、引数、戻り値)の集合を定義します。型がそのインターフェースを実装していると見なされるためには、その型のメソッドセットがインターフェースのメソッドセットを「含む」必要があります。
  • 動的ディスパッチ: インターフェース型変数に具体的な型の値を代入すると、そのインターフェースを介したメソッド呼び出しは、実行時にその具体的な型のメソッドが呼び出されます(動的ディスパッチ)。

fatal error: getoutarg: not a func RANGE

このエラーメッセージは、Goコンパイラの非常に低レベルな部分で発生する内部エラーを示しています。

  • getoutarg: これはGoコンパイラの内部関数名である可能性が高いです。関数呼び出しの引数(outarg は "output argument" または "outgoing argument" の略かもしれません)を処理する部分に関連していると推測されます。
  • not a func RANGE: RANGE はコンパイラがコードの特定の範囲(例えば、関数の本体やループの範囲)を処理する際に使用する内部的な概念かもしれません。not a func RANGE は、コンパイラが関数呼び出しのコンテキストで期待される「関数の範囲」を正しく識別できなかった、あるいは処理できなかったことを示唆しています。

このエラーは、特にインターフェースを介したメソッド呼び出しをゴルーチンとして起動する際に、コンパイラがその動的な性質を正しく解決し、ゴルーチン起動に必要なコード(スタックフレームの準備、引数の渡し方など)を生成できなかったために発生したと考えられます。これは、Go言語の初期段階におけるコンパイラの成熟度や、特定の複雑なコードパスの処理におけるバグを示しています。

技術的詳細

このコミットが追加した test/bugs/bug130.go は、以下のGo言語の機能の組み合わせをテストしています。

  1. インターフェースの定義: type I interface { send(chan <- int) } I というインターフェースを定義し、send というメソッドを持つことを規定しています。send メソッドは chan <- int 型のチャネルを引数にとり、何も返しません。chan <- int は「int型を送信専用のチャネル」であることを示します。
  2. 構造体とメソッドの実装:
    type S struct { v int }
    func (p *S) send(c chan <- int) { c <- p.v }
    
    S という構造体を定義し、そのポインタレシーバを持つ send メソッドを実装しています。この send メソッドは、S 型の v フィールドの値を引数 c のチャネルに送信します。これにより、*S 型は暗黙的に I インターフェースを実装します。
  3. インターフェース型変数への代入: var i I = &s; main 関数内で S 型の変数 s を作成し、そのアドレス &sI インターフェース型の変数 i に代入しています。これにより、i*S 型の具体的な値を保持し、I インターフェースで定義された send メソッドを呼び出すことができます。
  4. チャネルの作成: c := new(chan int); int 型の値を送受信するためのチャネルを作成しています。
  5. インターフェースメソッドのゴルーチン起動: go i.send(c); これがこのテストの核心部分です。インターフェース型変数 i を介して、そのメソッド send を新しいゴルーチンとして起動しようとしています。

当時のGoコンパイラは、この go i.send(c) という構文を正しく処理できませんでした。インターフェースメソッドの呼び出しは、実行時に具体的な型が決定される動的ディスパッチを伴います。これを go ステートメントと組み合わせることで、コンパイラはゴルーチン起動時に必要なコンテキスト(どの具体的なメソッドを呼び出すか、その引数は何かなど)を正しく構築できなかったと考えられます。

test/golden.out に記録された fatal error: getoutarg: not a func RANGE は、この問題がコンパイラのバックエンド、特に関数呼び出しの引数処理や、コードの実行範囲(RANGE)の解析に関連する部分で発生していたことを示唆しています。これは、コンパイラがインターフェースメソッドの動的ディスパッチとゴルーチン起動のメカニズムを統合する際に直面した初期の課題の一つであり、このテストケースは、そのバグを再現し、将来の修正を検証するための重要なリファレンスとなりました。

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

このコミットのコアとなる変更は、新しいテストファイル test/bugs/bug130.go の追加です。

--- a/test/bugs/bug130.go
+++ b/test/bugs/bug130.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+// 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
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+  s := S{0};
+  var i I = &s;
+  c := new(chan int);
+  go i.send(c);
+  sys.exit(<-c);
+}

そして、このテストが失敗することを期待して、test/golden.out にそのエラーメッセージを追加しています。

--- a/test/golden.out
+++ b/test/golden.out
@@ -157,6 +157,10 @@ BUG: errchk: command succeeded unexpectedly:  6g bugs/bug125.go
 bugs/bug129.go:6: syscall is package, not var
 BUG129
 
+=========== bugs/bug130.go
+bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE
+BUG: should run
+
 =========== fixedbugs/bug016.go
 fixedbugs/bug016.go:7: overflow converting constant to uint
 

コアとなるコードの解説

test/bugs/bug130.go は、Go言語のコンパイラまたはランタイムにおける特定のバグを再現するための最小限のコードです。

  1. インターフェース I の定義: type I interface { send(chan <- int) } これは、send という名前のメソッドを持つインターフェースを定義しています。このメソッドは int 型の値を送信するためのチャネルを引数にとります。

  2. 構造体 S とそのメソッド send の実装:

    type S struct { v int }
    func (p *S) send(c chan <- int) { c <- p.v }
    

    S は単一の整数フィールド v を持つシンプルな構造体です。*S 型に定義された send メソッドは、I インターフェースの send メソッドのシグネチャと一致するため、*S 型は暗黙的に I インターフェースを実装します。このメソッドは、レシーバ pv の値を引数で渡されたチャネル c に送信します。

  3. main 関数内のロジック:

    func main() {
      s := S{0};
      var i I = &s;
      c := new(chan int);
      go i.send(c);
      sys.exit(<-c);
    }
    
    • s := S{0};: S 型の変数 s を初期値 0 で宣言・初期化します。
    • var i I = &s;: I インターフェース型の変数 i を宣言し、s のアドレス(*S 型)を代入します。これにより、iS のインスタンスをインターフェースとして参照します。
    • c := new(chan int);: int 型のチャネル c を作成します。
    • go i.send(c);: この行がテストの核心です。 インターフェース型変数 i を介して、その send メソッドを新しいゴルーチンとして起動しようとしています。当時のGoコンパイラは、この動的なメソッドディスパッチを伴うゴルーチン起動を正しく処理できず、内部エラー fatal error: getoutarg: not a func RANGE を発生させていました。
    • sys.exit(<-c);: main ゴルーチンは、c チャネルから値を受信するまでブロックします。もし go i.send(c) が成功していれば、send ゴルーチンが 0 をチャネルに送信し、main ゴルーチンは 0 を受け取って正常終了するはずです。しかし、バグによりゴルーチンが起動しないため、この行は実行されず、コンパイル時または実行時にエラーが発生します。

test/golden.out の変更は、このテストが期待通りに失敗し、特定のエラーメッセージを出力することを確認するためのものです。これは、テスト駆動開発(TDD)のアプローチに似ており、まずバグを再現するテストを作成し、そのテストが失敗することを確認してから、バグ修正に取り掛かるという流れを示唆しています。

関連リンク

参考にした情報源リンク

  • Go言語のソースコードリポジトリ (GitHub): https://github.com/golang/go
  • Go言語の初期のメーリングリストやバグトラッカー(当時の情報源は公開されていない可能性が高いですが、コミットメッセージの OCLCL 番号は内部的な変更リスト番号を示唆しています)
  • Go言語のコンパイラ設計に関する一般的な情報(Goのコンパイラは、初期にはC言語で書かれ、後にGo自身で書き直されました。このコミットの時期はC言語版コンパイラの時代です。)

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

コミット

このコミットは、Go言語の初期開発段階(2008年12月)において、go ステートメントがインターフェースのメソッドを呼び出す際の挙動に関するバグをテストするために追加されたものです。具体的には、インターフェース型変数を介してメソッドをゴルーチンとして実行しようとした際に発生していたコンパイラまたはランタイムのエラーを捕捉するためのテストケース test/bugs/bug130.go を追加しています。このテストは、当時のGoコンパイラが go i.send(c) のようなコードを正しく処理できないことを示しており、test/golden.out に記録されたエラーメッセージ fatal error: getoutarg: not a func RANGE がその証拠です。

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

https://github.com/golang/go/commit/3f69acfb0c638f2f96cb21c2b5f8374e5cb6040d

元コミット内容

commit 3f69acfb0c638f2f96cb21c2b5f8374e5cb6040d
Author: Ian Lance Taylor <iant@golang.org>
Date:   Tue Dec 30 15:03:46 2008 -0800

    Test for a go statement which calls a method on an interface.

    R=ken
    DELTA=20  (20 added, 0 deleted, 0 changed)
    OCL=21889
    CL=21929
---\n test/bugs/bug130.go | 20 ++++++++++++++++++++\n test/golden.out     |  4 ++++\n 2 files changed, 24 insertions(+)

diff --git a/test/bugs/bug130.go b/test/bugs/bug130.go
new file mode 100644
index 0000000000..6e189ca5ce
--- /dev/null
+++ b/test/bugs/bug130.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+// 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
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+  s := S{0};
+  var i I = &s;
+  c := new(chan int);
+  go i.send(c);
+  sys.exit(<-c);
+}
diff --git a/test/golden.out b/test/golden.out
index feb0a4566e..50b957f121 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -157,6 +157,10 @@ BUG: errchk: command succeeded unexpectedly:  6g bugs/bug125.go
 bugs/bug129.go:6: syscall is package, not var
 BUG129
 
+=========== bugs/bug130.go
+bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE
+BUG: should run
+
 =========== fixedbugs/bug016.go
 fixedbugs/bug016.go:7: overflow converting constant to uint
 

変更の背景

このコミットは、Go言語の初期開発におけるバグ修正プロセスの一環として行われました。Go言語は、その設計当初から並行処理(コンカレンシー)を言語の核となる機能として重視しており、go ステートメントとチャネルはその主要な要素です。また、インターフェースはGoのポリモーフィズムを実現するための重要な機能です。

このコミットが追加された2008年当時、Go言語はまだ公開されておらず、活発な開発が行われていました。新しい言語機能が実装される過程では、予期せぬバグやエッジケースが頻繁に発見されます。特に、go ステートメントとインターフェースのメソッド呼び出しという、Goの重要な二つの概念が組み合わさる場面では、コンパイラやランタイムが正しくコードを生成・実行できない可能性がありました。

test/bugs/bug130.go は、まさにそのような問題、すなわち「インターフェースのメソッドをゴルーチンとして起動する」という特定のコードパターンが、当時のGoコンパイラ(またはランタイム)によって正しく処理されないことを示すために作成されました。test/golden.out に記録された fatal error: getoutarg: not a func RANGE というエラーは、コンパイラの内部的な問題、おそらくは関数呼び出しの引数処理や、ゴルーチン起動時のコンテキスト生成に関するバグを示唆しています。このテストの追加は、このバグを特定し、将来的に修正されたことを確認するための重要なステップでした。

前提知識の解説

Go言語の並行処理(Concurrency)

Go言語の最も特徴的な機能の一つが、軽量な並行処理のサポートです。

  • ゴルーチン (Goroutines): Goにおける並行実行の単位です。OSのスレッドよりもはるかに軽量で、数千、数万のゴルーチンを同時に実行することが可能です。go キーワードを関数の前に置くことで、その関数を新しいゴルーチンとして実行します。 例: go myFunction()
  • チャネル (Channels): ゴルーチン間の安全な通信を可能にするための「パイプ」のようなものです。チャネルを通じて値を送受信することで、共有メモリによる競合状態(race condition)を避けることができます。 例: c := make(chan int) (チャネルの作成), c <- value (送信), value := <-c (受信)

Go言語のインターフェース (Interfaces)

Goのインターフェースは、オブジェクト指向プログラミングにおけるポリモーフィズムを実現するための強力なメカニズムです。

  • 暗黙的な実装: Goのインターフェースは、JavaやC#のように implements キーワードを使って明示的に実装を宣言する必要がありません。ある型がインターフェースで定義されたすべてのメソッドを実装していれば、その型はそのインターフェースを「暗黙的に」実装しているとみなされます。
  • メソッドセット: インターフェースはメソッドのシグネチャ(名前、引数、戻り値)の集合を定義します。型がそのインターフェースを実装していると見なされるためには、その型のメソッドセットがインターフェースのメソッドセットを「含む」必要があります。
  • 動的ディスパッチ: インターフェース型変数に具体的な型の値を代入すると、そのインターフェースを介したメソッド呼び出しは、実行時にその具体的な型のメソッドが呼び出されます(動的ディスパッチ)。

fatal error: getoutarg: not a func RANGE

このエラーメッセージは、Goコンパイラの非常に低レベルな部分で発生する内部エラーを示しています。Web検索の結果によると、このエラーは2009年頃のGo言語の初期バージョンで報告された内部コンパイラエラーであり、関数引数または範囲式の処理におけるコンパイラの問題を示していました。これはユーザーが書いたコードのエラーではなく、Goコンパイラ自体のバグであり、その後のGoツールチェーンのアップデートで解決されたはずです。

  • getoutarg: これはGoコンパイラの内部関数名である可能性が高いです。関数呼び出しの引数(outarg は "output argument" または "outgoing argument" の略かもしれません)を処理する部分に関連していると推測されます。
  • not a func RANGE: RANGE はコンパイラがコードの特定の範囲(例えば、関数の本体やループの範囲)を処理する際に使用する内部的な概念かもしれません。not a func RANGE は、コンパイラが関数呼び出しのコンテキストで期待される「関数の範囲」を正しく識別できなかった、あるいは処理できなかったことを示唆しています。

このエラーは、特にインターフェースを介したメソッド呼び出しをゴルーチンとして起動する際に、コンパイラがその動的な性質を正しく解決し、ゴルーチン起動に必要なコード(スタックフレームの準備、引数の渡し方など)を生成できなかったために発生したと考えられます。これは、Go言語の初期段階におけるコンパイラの成熟度や、特定の複雑なコードパスの処理におけるバグを示しています。

技術的詳細

このコミットが追加した test/bugs/bug130.go は、以下のGo言語の機能の組み合わせをテストしています。

  1. インターフェースの定義: type I interface { send(chan <- int) } I というインターフェースを定義し、send というメソッドを持つことを規定しています。send メソッドは chan <- int 型のチャネルを引数にとり、何も返しません。chan <- int は「int型を送信専用のチャネル」であることを示します。
  2. 構造体とメソッドの実装:
    type S struct { v int }
    func (p *S) send(c chan <- int) { c <- p.v }
    
    S という構造体を定義し、そのポインタレシーバを持つ send メソッドを実装しています。この send メソッドは、S 型の v フィールドの値を引数 c のチャネルに送信します。これにより、*S 型は暗黙的に I インターフェースを実装します。
  3. インターフェース型変数への代入: var i I = &s; main 関数内で S 型の変数 s を作成し、そのアドレス &sI インターフェース型の変数 i に代入しています。これにより、i*S 型の具体的な値を保持し、I インターフェースで定義された send メソッドを呼び出すことができます。
  4. チャネルの作成: c := new(chan int); int 型の値を送受信するためのチャネルを作成しています。
  5. インターフェースメソッドのゴルーチン起動: go i.send(c); これがこのテストの核心部分です。インターフェース型変数 i を介して、そのメソッド send を新しいゴルーチンとして起動しようとしています。

当時のGoコンパイラは、この go i.send(c) という構文を正しく処理できませんでした。インターフェースメソッドの呼び出しは、実行時に具体的な型が決定される動的ディスパッチを伴います。これを go ステートメントと組み合わせることで、コンパイラはゴルーチン起動時に必要なコンテキスト(どの具体的なメソッドを呼び出すか、その引数は何かなど)を正しく構築できなかったと考えられます。

test/golden.out に記録された fatal error: getoutarg: not a func RANGE は、この問題がコンパイラのバックエンド、特に関数呼び出しの引数処理や、コードの実行範囲(RANGE)の解析に関連する部分で発生していたことを示唆しています。これは、Go言語の初期段階におけるコンパイラの成熟度や、特定の複雑なコードパスの処理におけるバグを示しており、このテストケースは、そのバグを再現し、将来の修正を検証するための重要なリファレンスとなりました。

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

このコミットのコアとなる変更は、新しいテストファイル test/bugs/bug130.go の追加です。

--- a/test/bugs/bug130.go
+++ b/test/bugs/bug130.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+// 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
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+  s := S{0};
+  var i I = &s;
+  c := new(chan int);
+  go i.send(c);
+  sys.exit(<-c);
+}

そして、このテストが失敗することを期待して、test/golden.out にそのエラーメッセージを追加しています。

--- a/test/golden.out
+++ b/test/golden.out
@@ -157,6 +157,10 @@ BUG: errchk: command succeeded unexpectedly:  6g bugs/bug125.go
 bugs/bug129.go:6: syscall is package, not var
 BUG129
 
+=========== bugs/bug130.go
+bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE
+BUG: should run
+
 =========== fixedbugs/bug016.go
 fixedbugs/bug016.go:7: overflow converting constant to uint
 

コアとなるコードの解説

test/bugs/bug130.go は、Go言語のコンパイラまたはランタイムにおける特定のバグを再現するための最小限のコードです。

  1. インターフェース I の定義: type I interface { send(chan <- int) } これは、send という名前のメソッドを持つインターフェースを定義しています。このメソッドは int 型の値を送信するためのチャネルを引数にとります。

  2. 構造体 S とそのメソッド send の実装:

    type S struct { v int }
    func (p *S) send(c chan <- int) { c <- p.v }
    

    S は単一の整数フィールド v を持つシンプルな構造体です。*S 型に定義された send メソッドは、I インターフェースの send メソッドのシグネチャと一致するため、*S 型は暗黙的に I インターフェースを実装します。このメソッドは、レシーバ pv の値を引数で渡されたチャネル c に送信します。

  3. main 関数内のロジック:

    func main() {
      s := S{0};
      var i I = &s;
      c := new(chan int);
      go i.send(c);
      sys.exit(<-c);
    }
    
    • s := S{0};: S 型の変数 s を初期値 0 で宣言・初期化します。
    • var i I = &s;: I インターフェース型の変数 i を宣言し、s のアドレス(*S 型)を代入します。これにより、iS のインスタンスをインターフェースとして参照します。
    • c := new(chan int);: int 型のチャネル c を作成します。
    • go i.send(c);: この行がテストの核心です。 インターフェース型変数 i を介して、その send メソッドを新しいゴルーチンとして起動しようとしています。当時のGoコンパイラは、この動的なメソッドディスパッチを伴うゴルーチン起動を正しく処理できず、内部エラー fatal error: getoutarg: not a func RANGE を発生させていました。
    • sys.exit(<-c);: main ゴルーチンは、c チャネルから値を受信するまでブロックします。もし go i.send(c) が成功していれば、send ゴルーチンが 0 をチャネルに送信し、main ゴルーチンは 0 を受け取って正常終了するはずです。しかし、バグによりゴルーチンが起動しないため、この行は実行されず、コンパイル時または実行時にエラーが発生します。

test/golden.out の変更は、このテストが期待通りに失敗し、特定のエラーメッセージを出力することを確認するためのものです。これは、テスト駆動開発(TDD)のアプローチに似ており、まずバグを再現するテストを作成し、そのテストが失敗することを確認してから、バグ修正に取り掛かるという流れを示唆しています。

関連リンク

参考にした情報源リンク

  • Go言語のソースコードリポジトリ (GitHub): https://github.com/golang/go
  • Go言語の初期のメーリングリストやバグトラッカー(当時の情報源は公開されていない可能性が高いですが、コミットメッセージの OCLCL 番号は内部的な変更リスト番号を示唆しています。)
  • Go言語のコンパイラ設計に関する一般的な情報(Goのコンパイラは、初期にはC言語で書かれ、後にGo自身で書き直されました。このコミットの時期はC言語版コンパイラの時代です。)
  • Web検索: "Go language "fatal error: getoutarg: not a func RANGE" 2008 2009" (この検索により、エラーメッセージがGoコンパイラの内部エラーであり、後のアップデートで解決されたことが確認されました。)