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

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

このコミットは、Goコンパイラ(gc)における内部的な「ideal bool」型の概念を削除するものです。これにより、Go言語の型システムにおけるブーリアン値の扱いが簡素化され、より一貫性のあるものになります。

コミット

commit 126d475a4311c5c34f380a11941dbeeac39145fd
Author: Russ Cox <rsc@golang.org>
Date:   Sat Feb 18 21:07:08 2012 -0500

    gc: drop ideal bool
    
    R=golang-dev, ken2
    CC=golang-dev
    https://golang.org/cl/5674098

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

https://github.com/golang/go/commit/126d475a4311c5c34f380a11941dbeeac39145fd

元コミット内容

gc: drop ideal bool

R=golang-dev, ken2
CC=golang-dev
https://golang.org/cl/5674098

変更の背景

Go言語のコンパイラ(gc)は、内部的に「ideal types(理想型)」という概念を使用していました。これは、リテラル値(例えば、数値リテラルや文字列リテラル)が、具体的な型に束縛される前に持つ、より汎用的な型を指します。例えば、1という数値リテラルは、それがint型として使われるかfloat64型として使われるかによって型が決定されるまで、内部的には「ideal int」のような型として扱われます。

同様に、ブーリアンリテラル(truefalse)も、かつては「ideal bool」という内部的な理想型を持っていました。しかし、ブーリアン型は数値型や文字列型のように複数の具体的な型に変換されることがなく、常にbool型として扱われます。このため、「ideal bool」という中間的な型を持つことのメリットが少なく、コンパイラの複雑性を増す要因となっていました。

このコミットは、この「ideal bool」の概念をGoコンパイラから削除し、ブーリアンリテラルが直接bool型として扱われるようにすることで、コンパイラのコードベースを簡素化し、保守性を向上させることを目的としています。

前提知識の解説

  • Goコンパイラ (gc): Go言語の公式コンパイラです。Goのソースコードを機械語に変換する役割を担います。
  • 型システム: プログラミング言語において、値や変数がどのような種類のデータを保持できるかを定義する規則の集合です。Goは静的型付け言語であり、コンパイル時に厳密な型チェックが行われます。
  • リテラル: ソースコード中に直接記述される値のことです。例えば、123(数値リテラル)、"hello"(文字列リテラル)、true(ブーリアンリテラル)などがあります。
  • 理想型 (Ideal Types): Goコンパイラの内部的な概念で、リテラルが具体的な型に決定される前に持つ、より汎用的な型を指します。例えば、1というリテラルは、int型にもfloat64型にもなり得るため、コンパイラは一時的に「理想的な整数型」として扱います。文字列リテラルにはidealstringという理想型が存在します。
  • bool: Go言語の組み込み型の一つで、真偽値(trueまたはfalse)を表します。

技術的詳細

この変更は、Goコンパイラの内部実装に深く関わるものです。具体的には、src/cmd/gcディレクトリ内の複数のファイルが修正されています。

  1. idealboolの定義の削除: src/cmd/gc/go.hからEXTERN Type* idealbool;の宣言が削除されます。これは、idealbool型がもはや存在しないことを意味します。
  2. ブーリアンリテラルの型付けの変更:
    • src/cmd/gc/const.cnodlit関数では、ブーリアンリテラル(CTBOOL)の型をidealboolからtypes[TBOOL](つまり、組み込みのbool型)に直接設定するように変更されます。
    • src/cmd/gc/lex.clexinit関数では、truefalseの組み込み定数の型がidealboolからtypes[TBOOL]に変更されます。
    • src/cmd/gc/subr.cnodbool関数でも同様に、ブーリアンノードの型がidealboolからtypes[TBOOL]に変更されます。
  3. idealboolへの参照の削除:
    • src/cmd/gc/export.csrc/cmd/gc/fmt.csrc/cmd/gc/subr.cなど、idealboolを参照していた箇所からその参照が削除されます。例えば、型が理想型であるかどうかをチェックするisideal関数からはt == idealboolの条件が削除されます。
    • src/cmd/gc/fmt.ctypefmt関数では、エラー出力時に「ideal bool」という文字列を付加するロジックが削除されます。
  4. テストコードの修正:
    • test/fixedbugs/bug285.gotest/named.gotest/named1.goといったテストファイルが修正されています。これらの修正は、ideal boolの削除によって型推論の挙動が変わる可能性があったため、既存のテストが新しい型システムに適合するように調整されたものです。特に、truefalseといったブーリアンリテラルが、ユーザー定義のBool型に直接代入できなくなるケースが修正されています。これは、ideal boolが存在しないため、リテラルが直接bool型として扱われ、ユーザー定義型への暗黙的な変換が許容されなくなるためです。

この変更により、Goコンパイラはブーリアンリテラルをより直接的に扱い、型システムにおけるブーリアン値の処理が簡素化されます。これは、コンパイラの内部構造のクリーンアップと効率化に貢献します。

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

src/cmd/gc/const.c (ブーリアンリテラルの型付け)

--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -936,7 +935,7 @@ nodlit(Val v)
 		n->type = idealstring;
 		break;
 	case CTBOOL:
-		n->type = idealbool;
+		n->type = types[TBOOL];
 		break;
 	case CTINT:
 	case CTRUNE:
@@ -1025,7 +1024,7 @@ defaultlit(Node **np, Type *t)
 			defaultlit(&n->left, t);
 			defaultlit(&n->right, t);
 		}
-		if(n->type == idealbool || n->type == idealstring)
+		if(n->type == types[TBOOL] || n->type == idealstring)
 			n->type = types[n->type->etype];
 		else
 			n->type = n->left->type;

src/cmd/gc/go.h (idealboolの宣言削除)

--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -775,7 +775,6 @@ EXTERN	Idir*	idirs;
 
 EXTERN	Type*	types[NTYPE];
 EXTERN	Type*	idealstring;
-EXTERN	Type*	idealbool;
 EXTERN	Type*	bytetype;
 EXTERN	Type*	runetype;
 EXTERN	Type*	errortype;

src/cmd/gc/lex.c (true/false定数の型付け)

--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -1824,17 +1824,16 @@ lexinit(void)
 	// this is the ideal form
 	// (the type of x in const x = "hello").
 	idealstring = typ(TSTRING);
-	idealbool = typ(TBOOL);
 
 	s = pkglookup("true", builtinpkg);
 	s->def = nodbool(1);
 	s->def->sym = lookup("true");
-	s->def->type = idealbool;
+	s->def->type = types[TBOOL];
 
 	s = pkglookup("false", builtinpkg);
 	s->def = nodbool(0);
 	s->def->sym = lookup("false");
-	s->def->type = idealbool;
+	s->def->type = types[TBOOL];
 
 	s = lookup("_");
 	s->block = -100;

コアとなるコードの解説

上記のコード変更は、idealboolという概念をGoコンパイラから完全に排除するためのものです。

  • src/cmd/gc/const.cの変更: nodlit関数は、リテラルノードを作成する際にその型を設定します。以前はブーリアンリテラル(CTBOOL)に対してidealbool型を割り当てていましたが、変更後は直接types[TBOOL](Goの組み込みbool型)を割り当てるようになります。これにより、ブーリアンリテラルは最初から具体的なbool型を持つことになります。defaultlit関数も、idealbool型をtypes[TBOOL]に変換するロジックからidealboolのチェックを削除しています。
  • src/cmd/gc/go.hの変更: このヘッダーファイルは、コンパイラ全体で共有されるグローバル変数や型定義を宣言しています。idealboolの宣言を削除することで、この型がコンパイラのどの部分からも参照されなくなることを保証します。
  • src/cmd/gc/lex.cの変更: lexinit関数は、コンパイラの初期化時に組み込みの定数(truefalseなど)を定義します。以前はこれらの定数にidealbool型を割り当てていましたが、変更後は直接types[TBOOL]を割り当てるようになります。これは、truefalseが常にbool型であることを明確にします。

これらの変更は、Goコンパイラの型システムにおけるブーリアン値の扱いを簡素化し、idealboolという中間的な型が不要であることを示しています。これにより、コンパイラのコードベースがよりクリーンで理解しやすくなり、将来的なメンテナンスや機能追加が容易になります。

関連リンク

参考にした情報源リンク