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

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

このコミットは、Go言語の初期段階における型変換(Type Conversion)とマップリテラル(Map Literal)の挙動に関するテストケースを追加したものです。具体的には、構造体(struct)とマップ(map)の初期化における型変換の誤用、およびマップリテラルの構文エラーを検出するためのテストが追加されています。

コミット

commit bb57a5bc2c167f82698654419376ce3a4825489f
Author: Rob Pike <r@golang.org>
Date:   Mon Jun 16 15:18:10 2008 -0700

    added two new small tests
    
    SVN=123010

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

https://github.com/golang/go/commit/bb57a5bc2c167f82698654419376ce3a4825489f

元コミット内容

diff --git a/test/bugs/bug047.go b/test/bugs/bug047.go
new file mode 100644
index 0000000000..a5beae5b74
--- /dev/null
+++ b/test/bugs/bug047.go
@@ -0,0 +1,21 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+//
+// 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
+
+func main() {
+
+	type T struct {
+		s string;
+		f float;
+	};
+	var s string = "hello";
+	var f float = 0.2;
+	t := T(s, f);
+
+	type M map[int] int;
+	m0 := M(7 , 8);
+}
diff --git a/test/bugs/bug048.go b/test/bugs/bug048.go
new file mode 100644
index 0000000000..0dfbaae9ad
--- /dev/null
+++ b/test/bugs/bug048.go
@@ -0,0 +1,13 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+//
+// 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.\n
+//
+package main
+
+func main() {
+	type M map[int] int;
+	m0 := M(7 , 8);	// parses OK
+	m1 := M(7 : 8);	// BUG: syntax error
+}
diff --git a/test/golden.out b/test/golden.out
index 8845e16eaf..5c6b17b5d4 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -225,6 +225,23 @@ BUG: known to fail incorrectly
 bugs/bug046.go:7: illegal <this> pointer
 BUG: known to fail incorrectly
 
+=========== bugs/bug047.go
+bugs/bug047.go:13: illegal types for operand: CONV
+	(<T>{<s><string>*STRING;<f><float32>FLOAT32;})\n
+bugs/bug047.go:16: illegal types for operand: CONV
+	(MAP[<int32>INT32]<int32>INT32)\n
+bugs/bug047.go:13: illegal types for operand: CONV
+	(<T>{<s><string>*STRING;<f><float32>FLOAT32;})\n
+bugs/bug047.go:16: illegal types for operand: CONV
+	(MAP[<int32>INT32]<int32>INT32)\n
+BUG: known to fail incorrectly
+
+=========== bugs/bug048.go
+bugs/bug048.go:7: illegal types for operand: CONV
+	(MAP[<int32>INT32]<int32>INT32)\n
+bugs/bug048.go:8: syntax error
+BUG: known to fail incorrectly
+
 =========== fixedbugs/bug000.go
 
 =========== fixedbugs/bug001.go

変更の背景

このコミットは、Go言語のコンパイラや型システムがまだ初期開発段階にあった2008年6月に行われたものです。当時のGo言語は、現在のGo言語とは異なる構文やセマンティクスを持つ部分が多く、特に型変換や複合リテラル(structやmapの初期化)の扱いについて、まだ厳密なルールが確立されていませんでした。

bug047.gobug048.goというファイル名が示すように、これらはバグ報告や、Go言語の設計・実装における未定義または誤解されやすい挙動を特定するためのテストとして追加されました。特に、構造体やマップの初期化において、関数呼び出しのような構文で値を渡そうとした場合のコンパイラの挙動を確認し、それが期待通りにエラーとして扱われることを保証することが目的でした。

当時のGo言語は、C言語のような型変換の柔軟性と、より安全な型システムの両立を目指していました。そのため、意図しない型変換や、構文的に誤った初期化方法を早期に検出し、開発者に明確なエラーメッセージを提供することが重要でした。これらのテストは、そうしたコンパイラの堅牢性を高める一環として追加されたと考えられます。

前提知識の解説

Go言語の型変換 (Type Conversion)

Go言語における型変換は、ある型の値を別の型に明示的に変換する操作です。これはT(v)という形式で記述され、Tは変換先の型、vは変換元の値です。Go言語の型変換は、C言語のような暗黙的な型変換をほとんど許容せず、明示的な変換を要求することで、型安全性を高めています。

例えば、intからfloat64への変換はfloat64(myInt)のように行います。しかし、互換性のない型間での変換はコンパイルエラーとなります。

構造体リテラル (Struct Literal)

Go言語では、構造体の値を初期化するために構造体リテラルを使用します。これはStructType{Field1: Value1, Field2: Value2}のような形式で記述されます。フィールド名を省略してStructType{Value1, Value2}のように記述することも可能ですが、この場合、フィールドは宣言順に初期化されます。

重要なのは、構造体リテラルはStructType(Value1, Value2)のような関数呼び出しのような構文では初期化できないという点です。これは、Go言語の設計思想として、構造体の初期化と関数呼び出しを明確に区別するためです。

マップリテラル (Map Literal)

Go言語では、マップの値を初期化するためにマップリテラルを使用します。これはmap[KeyType]ValueType{Key1: Value1, Key2: Value2}のような形式で記述されます。

マップリテラルもまた、MapType(Key1, Value1)のような関数呼び出しのような構文では初期化できません。マップのキーと値のペアはコロン:で区切られ、全体が波括弧{}で囲まれる必要があります。

golden.out ファイル

golden.outファイルは、Go言語のテストスイートにおいて、特定のテストケースを実行した際に期待されるコンパイラのエラーメッセージや出力結果を記録しておくためのファイルです。コンパイラの挙動が変更された場合、このgolden.outファイルも更新され、テストがパスするように調整されます。これにより、コンパイラの意図しない変更やリグレッションを検出することができます。

このコミットでは、bug047.gobug048.goが意図的にコンパイルエラーを引き起こすように書かれており、そのエラーメッセージがgolden.outに追記されています。これは、これらの「誤った」構文が正しくエラーとして認識されることを保証するためのものです。

技術的詳細

このコミットで追加されたテストケースは、Go言語のコンパイラが型変換とリテラルの構文をどのように解釈するかを検証しています。

test/bugs/bug047.go の詳細

このファイルでは、以下の2つの不正な初期化が試みられています。

  1. 構造体の不正な初期化:

    type T struct {
    	s string;
    	f float;
    };
    var s string = "hello";
    var f float = 0.2;
    t := T(s, f); // ここが問題
    

    Go言語では、構造体TのインスタンスをT(s, f)のように関数呼び出しの形式で初期化することはできません。構造体はT{s: s, f: f}またはT{s, f}のように構造体リテラルで初期化する必要があります。コンパイラはこれを型変換(CONV)として解釈しようとしますが、T型への変換にsfという複数の引数を渡すことはできないため、「illegal types for operand: CONV」というエラーを発生させます。

  2. マップの不正な初期化:

    type M map[int] int;
    m0 := M(7 , 8); // ここが問題
    

    同様に、マップ型MのインスタンスをM(7, 8)のように関数呼び出しの形式で初期化することはできません。マップはM{7: 8}のようにマップリテラルで初期化する必要があります。ここでもコンパイラは型変換として解釈しようとしますが、マップ型への変換に複数の引数を渡すことはできないため、「illegal types for operand: CONV」というエラーを発生させます。

golden.outには、これらの行に対して「illegal types for operand: CONV」というエラーメッセージが記録されており、コンパイラがこれらの不正な構文を正しく検出していることを示しています。

test/bugs/bug048.go の詳細

このファイルでは、マップリテラルの構文エラーが検証されています。

type M map[int] int;
m0 := M(7 , 8); // parses OK (これはbug047.goと同じ不正な初期化だが、コメントで「パースはOK」と書かれている)
m1 := M(7 : 8); // BUG: syntax error (ここが問題)

m0 := M(7 , 8);bug047.goと同じく不正な型変換の試みであり、golden.outにも「illegal types for operand: CONV」エラーが記録されています。興味深いのは、コード内のコメントで「parses OK」と書かれている点です。これは、字句解析や構文解析の初期段階では問題なく、意味解析の段階で型エラーとして検出されることを示唆している可能性があります。

m1 := M(7 : 8); は、マップリテラルの構文を意図的に誤って記述したものです。Go言語のマップリテラルはmap[KeyType]ValueType{Key1: Value1}のように波括弧{}で囲む必要があります。M(7 : 8)のように丸括弧()を使用すると、これはマップリテラルとして認識されず、コンパイラは「syntax error」を発生させます。golden.outには、この行に対して「syntax error」が記録されており、コンパイラが構文の誤りを正しく検出していることを示しています。

これらのテストは、Go言語のコンパイラが、型変換のルールとリテラルの構文規則を厳密に適用し、開発者が意図しないコードを記述した場合に明確なエラーメッセージを提供することの重要性を示しています。

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

このコミットにおけるコアとなるコードの変更は、Go言語のソースコードそのものではなく、Goコンパイラの挙動を検証するためのテストケースの追加です。

具体的には以下の3つのファイルが変更されています。

  1. test/bugs/bug047.go: 構造体とマップの不正な型変換を試みるGoソースファイル。
  2. test/bugs/bug048.go: マップの不正な型変換と構文エラーを試みるGoソースファイル。
  3. test/golden.out: 上記2つのテストファイルを実行した際に期待されるコンパイラのエラーメッセージが追記されたファイル。

これらのファイルは、Go言語のテストスイートの一部であり、コンパイラの正確性と堅牢性を保証するために使用されます。

コアとなるコードの解説

test/bugs/bug047.go

package main

func main() {
	type T struct {
		s string;
		f float;
	};
	var s string = "hello";
	var f float = 0.2;
	t := T(s, f); // 構造体の不正な初期化

	type M map[int] int;
	m0 := M(7 , 8); // マップの不正な初期化
}

このテストの目的は、Go言語のコンパイラが、構造体やマップを関数呼び出しのように初期化しようとした場合に、それが不正な型変換であると正しく認識し、エラーを報告することを確認することです。Go言語では、構造体やマップの初期化には専用のリテラル構文({}を使用)が必要です。T(s, f)M(7, 8)のような記述は、型TMへの型変換として解釈されますが、複数の引数を伴う型変換は許可されていないため、コンパイラはエラーを生成します。

test/bugs/bug048.go

package main

func main() {
	type M map[int] int;
	m0 := M(7 , 8); // 不正な型変換 (bug047.goと同じ)
	m1 := M(7 : 8); // マップリテラルの構文エラー
}

このテストは、マップリテラルの構文が正しくない場合にコンパイラが構文エラーを報告することを確認します。M(7 : 8)という記述は、マップリテラルに必要な波括弧{}が欠けているため、Go言語の構文規則に違反します。コンパイラはこれを解析できず、「syntax error」を発生させます。m0の行はbug047.goと同様の不正な型変換のテストです。

test/golden.out

このファイルには、bug047.gobug048.goの実行によって期待されるエラーメッセージが追記されています。

=========== bugs/bug047.go
bugs/bug047.go:13: illegal types for operand: CONV
	(<T>{<s><string>*STRING;<f><float32>FLOAT32;})
bugs/bug047.go:16: illegal types for operand: CONV
	(MAP[<int32>INT32]<int32>INT32)
BUG: known to fail incorrectly

=========== bugs/bug048.go
bugs/bug048.go:7: illegal types for operand: CONV
	(MAP[<int32>INT32]<int32>INT32)
bugs/bug048.go:8: syntax error
BUG: known to fail incorrectly

golden.outにこれらのエラーメッセージが記録されていることで、Goコンパイラがこれらの不正なコードパターンを正しく識別し、適切なエラーを報告する能力を持っていることが保証されます。特に「BUG: known to fail incorrectly」という記述は、当時のコンパイラがこれらのケースをまだ完全に正しく扱えていなかった可能性を示唆しており、このテストの追加がその修正に向けた一歩であったことを示唆しています。

関連リンク

参考にした情報源リンク

  • Go言語のGitHubリポジトリ: https://github.com/golang/go
  • Go言語の初期のコミット履歴 (SVNリポジトリ): Go言語の初期のコミットはSVNで行われていたため、GitHubの履歴はSVNからの移行後にミラーされたものです。SVNのコミットID SVN=123010 は、当時の開発プロセスにおけるコミットを特定するためのものです。
  • Go言語の型変換に関する議論 (Go言語のメーリングリストや初期の設計ドキュメント): これらのテストが追加された背景には、Go言語の型システム設計に関する議論があったと考えられます。