[インデックス 14467] ファイルの概要
このコミットは、Go言語の代替コンパイラであるgccgo
が誤ったエラーを報告していたバグを特定し、その回帰テストケースを追加するものです。具体的には、関数型定義において入力パラメータと出力パラメータで同じ名前を使用した場合にgccgo
が「再定義」エラーを出す問題に対応しています。Go言語の仕様では、このようなパラメータ名の使用は許可されており、エラーとなるべきではありません。
コミット
commit be5c445909ca872a67683a3f1720df8f99593656
Author: Ian Lance Taylor <iant@golang.org>
Date: Sat Nov 24 16:53:08 2012 -0800
test: add bug469, a case where gccgo gaves an incorrect error
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/6856084
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/be5c445909ca872a67683a3f1720df8f99593656
元コミット内容
test: add bug469, a case where gccgo gaves an incorrect error
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/6856084
変更の背景
Go言語のコンパイラには、公式のgc
コンパイラ以外にも、GCCをバックエンドとして利用するgccgo
という代替コンパイラが存在します。このgccgo
コンパイラが、Go言語の仕様に準拠していない誤ったエラーを報告するバグを抱えていました。
具体的には、Goの関数型を定義する際に、入力パラメータと出力パラメータに同じ名前を付けた場合に、gccgo
が「i
が再定義されています」といったエラーを発生させていました。しかし、Go言語の仕様では、関数型におけるパラメータ名はあくまでドキュメンテーションのためのものであり、実際の識別子としてのスコープを持たないため、このような命名は完全に合法です。このコミットは、このgccgo
の誤った挙動を修正するためのテストケースを追加し、将来的な回帰を防ぐことを目的としています。
前提知識の解説
Go言語の関数型
Go言語では、関数自体も型として扱うことができます。これは「関数型」と呼ばれ、特定の引数の型と戻り値の型を持つ関数を表現します。例えば、func(int, string) bool
は、int
とstring
を引数にとり、bool
を返す関数を表す関数型です。
関数型を定義する際に、パラメータ名を記述することも可能です。例: func(x int, y string) (result bool)
。このパラメータ名は、コードの可読性を高めるためのドキュメンテーション目的で提供されます。重要なのは、関数型定義内のパラメータ名は、その関数型が使用されるスコープに識別子を導入しないという点です。つまり、これらの名前は型定義の外部からは参照できず、単にその型がどのような意味を持つ引数や戻り値を持つのかを示すヒントに過ぎません。
gccgo
gccgo
は、Go言語のソースコードをコンパイルするための代替コンパイラの一つです。これは、GNU Compiler Collection (GCC) のフロントエンドとしてGo言語をサポートしており、GCCの最適化バックエンドを利用して実行可能ファイルを生成します。公式のgc
コンパイラとは異なる実装であるため、Go言語の仕様に対する解釈や実装の詳細において、稀に差異が生じることがあります。今回のバグも、その一例でした。
Go言語の仕様におけるパラメータ名
Go言語の仕様書(The Go Programming Language Specification)では、関数型におけるパラメータ名について明確に規定されています。特に重要なのは、**「関数型におけるパラメータ名は、その型が使用されるスコープに識別子を導入しない」**という点です。これは、入力パラメータと出力パラメータで同じ名前を使用しても、それが「再定義」エラーを引き起こすことはない、ということを意味します。それぞれのi
は、その関数型定義内でのみ意味を持つドキュメンテーション用の名前であり、互いに衝突することはありません。
技術的詳細
このバグは、gccgo
がGo言語の関数型におけるパラメータ名のセマンティクスを誤解していたことに起因します。通常の変数宣言や関数定義では、同じスコープ内で同じ名前の識別子を複数回宣言することは「再定義」エラーとなります。しかし、Goの関数型定義においては、入力パラメータと出力パラメータのセクションはそれぞれ独立しており、それぞれのセクション内で使用されるパラメータ名は、そのセクション内でのみ意味を持ちます。
例えば、type F func(i int) (i int)
という関数型を考えます。
- 最初の
i int
は、入力パラメータがint
型であり、そのドキュメンテーション上の名前がi
であることを示します。 - 次の
(i int)
は、出力パラメータがint
型であり、そのドキュメンテーション上の名前がi
であることを示します。
Goの仕様では、これら二つのi
は異なる「名前」として扱われ、互いに衝突しません。gccgo
は、この仕様を誤って解釈し、これらを同じスコープ内での再定義と見なしてエラーを報告していました。このコミットで追加されたテストケースは、この特定のシナリオを再現し、gccgo
が正しくコンパイルできることを保証するためのものです。
コアとなるコードの変更箇所
追加されたファイルは test/fixedbugs/bug469.go
です。
// compile
// Copyright 2012 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.
// The gccgo compiler would complain about a redefinition of i, but
// the spec imposes no requirements on parameter names in a function
// type.
package p
type F func(i int) (i int)
コアとなるコードの解説
test/fixedbugs/bug469.go
は、gccgo
のバグを再現するための非常に簡潔なテストケースです。
// compile
: このコメントは、Goのテストフレームワークに対して、このファイルをコンパイルするだけでテストが成功することを示します。つまり、コンパイルエラーが発生しなければテストはパスします。// The gccgo compiler would complain about a redefinition of i, but // the spec imposes no requirements on parameter names in a function // type.
: このコメントは、このテストケースの目的を明確に説明しています。gccgo
がi
の再定義について不平を言っていたが、Goの仕様では関数型におけるパラメータ名にそのような要件はない、という背景が述べられています。package p
: 標準的なGoパッケージ宣言です。type F func(i int) (i int)
: これがこのテストケースの核心です。F
という名前の関数型を定義しています。この関数型は、int
型の入力パラメータ(名前はi
)と、int
型の出力パラメータ(名前もi
)を持つ関数を表します。前述の通り、Goの仕様ではこの記述は完全に合法であり、gccgo
はこの型定義をエラーなくコンパイルできる必要があります。
このテストケースが追加されたことで、gccgo
の開発者はこのバグを修正し、Go言語の仕様に準拠した挙動を保証できるようになります。
関連リンク
- Go CL (Code Review) ページ: https://golang.org/cl/6856084
参考にした情報源リンク
- The Go Programming Language Specification (Go言語の公式仕様書) - 特に「Function types」のセクション。
- https://go.dev/ref/spec#Function_types (現在の最新版の仕様書へのリンクですが、当時の仕様も同様の記述であったと推測されます。)
- GCCGo (GCCのGo言語フロントエンドに関する情報)