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

[インデックス 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は、intstringを引数にとり、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.: このコメントは、このテストケースの目的を明確に説明しています。gccgoiの再定義について不平を言っていたが、Goの仕様では関数型におけるパラメータ名にそのような要件はない、という背景が述べられています。
  • package p: 標準的なGoパッケージ宣言です。
  • type F func(i int) (i int): これがこのテストケースの核心です。Fという名前の関数型を定義しています。この関数型は、int型の入力パラメータ(名前はi)と、int型の出力パラメータ(名前もi)を持つ関数を表します。前述の通り、Goの仕様ではこの記述は完全に合法であり、gccgoはこの型定義をエラーなくコンパイルできる必要があります。

このテストケースが追加されたことで、gccgoの開発者はこのバグを修正し、Go言語の仕様に準拠した挙動を保証できるようになります。

関連リンク

参考にした情報源リンク

  • The Go Programming Language Specification (Go言語の公式仕様書) - 特に「Function types」のセクション。
  • GCCGo (GCCのGo言語フロントエンドに関する情報)