[インデックス 1059] ファイルの概要
このコミットは、Go言語の初期のコンパイラである6g
における特定のバグを修正するものです。具体的には、名前付きポインタ型(type MyPointer *MyStruct
のような定義)の変数に対してメソッドを呼び出す際に、6g
コンパイラがそのメソッドを正しく認識できない問題に対処しています。この修正を検証するために、bug117.go
という新しいテストケースが追加され、既存のpowser1.go
ファイルもコンパイルが通るように変更されています。
コミット
このコミットは、現在の6g
コンパイラでコンパイルが通るようにpowser1.go
を修正します。6g
は、名前付きポインタ型である変数のメソッドを認識しませんでした。このケースをテストするためにbug117
が追加されました。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7fe34ea002609aba6d36a5ebd4c0f351cf6a39f1
元コミット内容
Fix powser1.go to compile with the current 6g, which doesn't
recognize methods for a variable whose type is a named type
which is a pointer type. Add bug117 to test this case.
R=r
DELTA=24 (22 added, 0 deleted, 2 changed)
OCL=18547
CL=18554
変更の背景
Go言語の初期開発段階において、コンパイラ(特に6g
)はまだ成熟しておらず、様々なエッジケースやバグが存在していました。このコミットで対処されている問題は、Goの型システムにおける特定の組み合わせ、すなわち「名前付き型であり、かつポインタ型である変数」に対するメソッド呼び出しの認識に関するものです。
当時の6g
コンパイラは、以下のようなコードパターンを正しく処理できませんでした。
- 構造体
S
を定義する。 S
のポインタ型*S
に対してメソッドを定義する。*S
を基底とする新しい名前付き型PS
を定義する(例:type PS *S
)。PS
型の変数に対して、*S
に定義されたメソッドを呼び出す。
このシナリオで6g
はメソッドの解決に失敗し、コンパイルエラーを引き起こしていました。このコミットは、このコンパイラの制限を解消し、Go言語の型システムが意図する通りの挙動を保証することを目的としています。powser1.go
は、このバグの影響を受けていた既存のコードベースの一部であり、その修正が必要とされました。
前提知識の解説
このコミットを理解するためには、以下のGo言語の基本的な概念と、当時のコンパイラに関する知識が必要です。
-
Go言語の型システム:
- 構造体 (Struct): 複数のフィールドをまとめた複合データ型です。
- ポインタ (Pointer): 変数のメモリアドレスを保持する型です。Goでは
*T
のように記述され、T
型の値へのポインタを表します。 - 名前付き型 (Named Type):
type MyType BaseType
のように、既存の型に新しい名前を付けて定義する型です。新しい名前付き型は、基底型とは異なる独自のメソッドセットを持つことができます。 - メソッド (Method): 特定の型に関連付けられた関数です。Goでは、関数名の前にレシーバ引数を記述することでメソッドを定義します。
- レシーバ (Receiver): メソッドがどの型の値に対して動作するかを指定する引数です。レシーバには「値レシーバ」(
func (t MyType) MethodName(...)
)と「ポインタレシーバ」(func (t *MyType) MethodName(...)
)があります。ポインタレシーバは、メソッド内でレシーバの値を変更できる点が特徴です。
-
Go言語の初期コンパイラ (6g):
6g
は、Go言語の初期に存在したコンパイラの一つで、特にamd64
アーキテクチャ(64ビットIntel/AMDプロセッサ)をターゲットとしていました。当時のGoコンパイラは、ターゲットアーキテクチャに応じて6g
(amd64)、8g
(386)、5g
(arm)のように命名されていました。- これらのコンパイラは、Go言語の初期のツールチェインの一部であり、Plan 9のコンパイラツールチェインから派生し、C言語で実装されていました。
- 現代のGo(Go 1.5以降)では、これらのアーキテクチャ固有のコンパイラは
go tool compile
という単一のバイナリに統合され、コンパイラ自体もGo言語で再実装されています。したがって、6g
は現在では直接使用されることはありませんが、Go言語の歴史と進化を理解する上で重要な存在です。
このコミットは、6g
コンパイラが、type PS *S
のように定義されたPS
型の変数(これは*S
というポインタ型に新しい名前を付けたもの)に対して、*S
に定義されたメソッド(例: (*S).get()
)を正しく解決できなかったという、当時のコンパイラの限界を示しています。
技術的詳細
このコミットの技術的な核心は、6g
コンパイラの型解決およびメソッド解決ロジックの不備にあります。Go言語では、基底型に定義されたメソッドは、その基底型を埋め込んだ構造体や、その基底型を基にした名前付き型に対しても、特定のルールに基づいてプロモート(昇格)され、呼び出すことができます。
問題は、名前付き型がポインタ型である場合に発生しました。具体的には、type PS *S
という定義があった場合、PS
は*S
の別名であり、*S
に定義されたメソッド(例: func (p *S) get() int
)はPS
型の変数からも呼び出せるべきです。しかし、当時の6g
コンパイラはこのプロモーションを正しく処理できず、PS
型の変数に対してget()
メソッドを呼び出そうとすると「未定義のメソッド」としてエラーを報告していました。
この修正は、コンパイラの内部で、名前付きポインタ型がその基底ポインタ型に定義されたメソッドを継承し、正しく解決できるようにするための変更が加えられたことを示唆しています。これにより、Go言語の型システムの一貫性が保たれ、開発者はより柔軟な型定義とメソッドの使用が可能になりました。
test/bugs/bug117.go
は、この問題を明確に再現するための最小限のテストケースとして設計されています。このテストケースがコンパイルエラーを発生させることが期待されており、修正後はエラーなくコンパイルが成功するようになることで、バグが解消されたことを検証します。
test/chan/powser1.go
の変更は、このコンパイラのバグによって影響を受けていた既存のコードを、修正後のコンパイラで正しく動作するように適応させたものです。具体的な変更内容は、関数の引数型をitem
から*rat
に変更している点です。これは、item
が名前付きポインタ型として定義されており、その型に対するメソッド呼び出しが6g
で問題となっていた可能性を示唆しています。*rat
への変更は、コンパイラが正しく処理できる型に明示的に変更することで、一時的に問題を回避するか、あるいはitem
の定義自体がこのバグの影響を受けていたため、より具体的なポインタ型に修正したと考えられます。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下の2つのファイルにあります。
-
test/bugs/bug117.go
(新規追加)- このファイルは、
6g
コンパイラのバグを再現するための新しいテストケースです。 type S struct { a int }
で構造体S
を定義。type PS *S
で、*S
(S
へのポインタ)を基底とする名前付きポインタ型PS
を定義。func (p *S) get() int
で、*S
に対するメソッドget()
を定義。func fn(p PS) int { return p.get() }
で、PS
型の引数p
を取り、そのp
に対してget()
メソッドを呼び出す関数fn
を定義。このp.get()
の部分が、修正前の6g
でコンパイルエラーとなっていた箇所です。// errchk $G $D/$F.go
というコメントは、このファイルがコンパイルエラーを発生させることを期待するテストであることを示しています。修正後はこのエラーが解消されるべきです。
- このファイルは、
-
test/chan/powser1.go
(変更)- 既存の
get
関数とcheck
関数のシグネチャが変更されています。 func get(in *dch) item
がfunc get(in *dch) *rat
に変更。func check(U PS, c item, count int, str string)
がfunc check(U PS, c *rat, count int, str string)
に変更。- この変更は、
item
型が名前付きポインタ型であり、その型に対するメソッド呼び出しが6g
で問題となっていたため、より具体的なポインタ型である*rat
に置き換えることで、コンパイルエラーを回避または修正後のコンパイラで正しく動作するように適応させたものと推測されます。
- 既存の
コアとなるコードの解説
test/bugs/bug117.go
// 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
type S struct { a int }
type PS *S
func (p *S) get() int {
return p.a
}
func fn(p PS) int {
return p.get()
}
func main() {
s := S{1};
if s.get() != 1 {
panic()
}
}
このテストケースは、6g
コンパイラのバグをピンポイントで狙っています。
type S struct { a int }
:単純な構造体S
を定義します。type PS *S
:ここで、S
へのポインタ型*S
にPS
という新しい名前を付けています。PS
は名前付きポインタ型です。func (p *S) get() int { return p.a }
:*S
型に対するメソッドget
を定義しています。このメソッドはS
のフィールドa
を返します。func fn(p PS) int { return p.get() }
:この関数fn
がバグの核心を突いています。引数p
はPS
型(名前付きポインタ型)ですが、p.get()
と呼び出しています。Goの言語仕様では、PS
は*S
の基底型を持つため、*S
に定義されたget()
メソッドはPS
型の変数からも呼び出せるべきです。しかし、修正前の6g
コンパイラは、このp.get()
を「PS
型にget
というメソッドは定義されていない」と誤って判断し、コンパイルエラーを発生させていました。main
関数内のs.get()
は、S
型の変数s
から直接get()
を呼び出しており、これは問題なくコンパイルされることを示しています。問題はあくまで「名前付きポインタ型」に対するメソッド呼び出しに限定されていました。
このファイルがerrchk
コメントと共に存在するということは、このファイルがコンパイルエラーを出すことを期待するテストであり、このコミットによってそのエラーが解消されることを意味します。
test/chan/powser1.go
--- a/test/chan/powser1.go
+++ b/test/chan/powser1.go
@@ -116,7 +116,7 @@ func put(dat item, out *dch){
out.dat <- dat;
}
-func get(in *dch) item{
+func get(in *dch) *rat {
seqno++;
in.req <- seqno;
return <-in.dat;
@@ -610,7 +610,7 @@ func Init() {
Twos = Rep(itor(2));
}
-func check(U PS, c item, count int, str string) {
+func check(U PS, c *rat, count int, str string) {
for i := 0; i < count; i++ {
\tr := get(U);\
\tif !r.eq(c) {
この差分は、powser1.go
ファイル内の2つの関数シグネチャの変更を示しています。
get
関数の戻り値の型がitem
から*rat
に変更されました。check
関数の第2引数c
の型がitem
から*rat
に変更されました。
この変更は、item
型がbug117.go
で示されたような「名前付きポインタ型」であり、その型が6g
コンパイラのバグの影響を受けていたために、コンパイルが通らなかった可能性が高いです。*rat
は、おそらくrat
構造体へのポインタ型であり、この型に直接変更することで、コンパイラが正しくメソッドを解決できるようになり、powser1.go
のコンパイルが成功するようになったと考えられます。これは、コンパイラの修正が、既存のコードベースのコンパイル問題を解決した具体的な例と言えます。
関連リンク
参考にした情報源リンク
- Go言語の初期コンパイラ
6g
に関する情報:- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFYUHsujJy1VpReeQ75gsV2AqjPoQqL9qQKXj8RjvlZN3EcZ9skyE_NjL7CecCm0LdsbUesm5KsIKb2YSnmVAv8vBE6q3g4007OeV4GtC1WpAD8LQu_eW4ogR-pz9gLexw6T_nzyEAa5RD_-vbTEMMcKe06j08spCk0vv_F1OD96-unWPIBkFgW6rI1AoI=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF0v7K93GtfmwHuVG4EbpDEIZivgvi1e0WTEAI5B0agVo_ApyZJZXJtMlhdHWi9UwFpfj16417m3Wg3_pICwUJ5_qIy5pdR7gaM0hTCTnNeBsdADPtVnTllyXydme1M7kYMUqsMrfvTWlc3D2tjCfoieVKWwi7yghs5jYECPbpy
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF_l2sK__yS5ctFEMo4uMTDCoJe7G-wvFmHFHbQ-QBbfPGSmzy7HyOT-WpA_oSZ3mYzrR80zkLyWCDxwWEn8-jT1QVGtoRGS-2qJJGC22I8TkXwYw==