[インデックス 17696] ファイルの概要
このコミットは、Go言語の抽象構文木(AST)とパーサーに関する変更です。具体的には、Go 1.2で導入された3インデックススライス式(a[low:high:max]
)を正確に表現し、型チェックを可能にするための基盤を構築しています。
コミット
commit 20db0f428a28a529146b5016b97061f2b13c54d4
Author: Robert Griesemer <gri@golang.org>
Date: Tue Sep 24 16:35:35 2013 -0700
go/ast: add Slice3 field to SliceExpr
If Slice3 is set, the expression is
a 3-index slice expression (2 colons).
Required for type-checking.
Backward-compatible API extension.
R=r, rsc
CC=golang-dev
https://golang.org/cl/13826050
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/20db0f428a28a529146b5016b97061f2b13c54d4
元コミット内容
go/ast
パッケージのSliceExpr
構造体にSlice3
フィールドを追加し、go/parser
パッケージで3インデックススライス式が検出された場合にこのフィールドをtrue
に設定するように変更しました。これにより、2つのコロン(:
)を含むスライス式(例: a[low:high:max]
)をAST上で正確に表現できるようになり、後続の型チェック処理で利用されます。この変更は後方互換性のあるAPI拡張です。
変更の背景
Go言語では、スライスは配列の一部を参照するための強力なデータ構造です。初期のGo言語では、スライス式はa[low:high]
のように2つのインデックス(開始と終了)を持つ形式が一般的でした。しかし、スライスの「容量(capacity)」を明示的に指定して新しいスライスを作成する、あるいは既存のスライスから容量を制限した新しいスライスを作成するニーズがありました。
Go 1.2で、このニーズに応えるために3インデックススライス式(a[low:high:max]
)が導入されました。ここでmax
は新しいスライスの容量を決定します。この機能が言語仕様に追加されるにあたり、コンパイラがこの新しい構文を正しく解析し、ASTに表現し、そして型チェックを行うための変更が必要となりました。
このコミットは、そのための第一歩として、ASTが3インデックススライス式の存在を認識できるようにするためのものです。ASTはコンパイラのフロントエンドがソースコードを解析して生成する中間表現であり、その後の型チェック、最適化、コード生成といったフェーズで利用されます。したがって、新しい言語機能が導入される際には、まずASTがその機能を表現できるようになる必要があります。
前提知識の解説
Go言語のスライス
Go言語のスライスは、基盤となる配列への参照です。スライスは「長さ(length)」と「容量(capacity)」という2つの重要なプロパティを持ちます。
- 長さ (length): スライスに含まれる要素の数。
len(s)
で取得できます。 - 容量 (capacity): スライスの基盤となる配列の、スライスの開始位置から数えた要素の総数。
cap(s)
で取得できます。
通常のスライス式 s[low:high]
は、low
からhigh-1
までの要素を含む新しいスライスを作成します。この新しいスライスの長さは high - low
で、容量は cap(s) - low
です。
3インデックススライス式 (s[low:high:max]
)
Go 1.2で導入された3インデックススライス式 s[low:high:max]
は、新しいスライスの容量を明示的に指定することを可能にします。
low
: 新しいスライスの開始インデックス。high
: 新しいスライスの終了インデックス(high-1
までが含まれる)。max
: 新しいスライスの容量。新しいスライスの容量はmax - low
となります。
このmax
インデックスは、元のスライスまたは配列の容量の範囲内である必要があり、high
以上である必要があります。この機能は、特にスライスを関数に渡す際に、そのスライスがアクセスできる基盤配列の範囲を制限したい場合や、append
操作によって基盤配列が再割り当てされるのを防ぎたい場合に有用です。
抽象構文木 (AST)
抽象構文木(Abstract Syntax Tree, AST)は、ソースコードの抽象的な構文構造を木構造で表現したものです。コンパイラの字句解析器(lexer)と構文解析器(parser)によって生成されます。ASTは、ソースコードの具体的な構文(括弧やセミコロンなど)を省略し、プログラムの論理的な構造に焦点を当てます。
Go言語のコンパイラでは、go/ast
パッケージがASTのノード型を定義しており、go/parser
パッケージがソースコードを解析してASTを構築します。コンパイラの各フェーズ(型チェック、最適化など)は、このASTを走査して処理を進めます。
go/ast
パッケージとSliceExpr
構造体
go/ast
パッケージは、Go言語のソースコードのASTを表現するための型を提供します。スライス式はast.SliceExpr
構造体で表現されます。この構造体は、スライスされる元の式(X
)、角括弧の位置(Lbrack
, Rbrack
)、そしてlow
、high
、max
の各インデックスを表すフィールド(Low
, High
, Max
)を持ちます。
go/parser
パッケージ
go/parser
パッケージは、Go言語のソースコードを解析し、go/ast
パッケージで定義されたASTを構築する機能を提供します。ソースコードの文字列やファイルパスを受け取り、対応するASTのルートノード(通常は*ast.File
)を返します。
技術的詳細
このコミットの技術的詳細は、Go言語のコンパイラが新しい言語構文をどのように内部的に処理するかを示しています。
-
ASTの拡張:
src/pkg/go/ast/ast.go
にあるSliceExpr
構造体にSlice3 bool
フィールドが追加されました。type ( // ... SliceExpr struct { X Expr // expression being sliced Lbrack token.Pos // position of "[" Low Expr // begin of slice range; or nil High Expr // end of slice range; or nil Max Expr // maximum capacity of slice; or nil Slice3 bool // true if 3-index slice (2 colons present) Rbrack token.Pos // position of "]" } // ... )
この
Slice3
フィールドは、スライス式が2つのコロン(:
)を持つ3インデックス形式であるかどうかを示すブール値です。これにより、ASTの構造自体が、2インデックススライス(a[low:high]
)と3インデックススライス(a[low:high:max]
)を区別できるようになります。これは、後続の型チェックフェーズで、スライスの長さと容量の計算ロジックを適切に適用するために不可欠です。 -
パーサーの変更:
src/pkg/go/parser/parser.go
にあるparseIndexOrSlice
関数が変更されました。この関数は、配列、スライス、または文字列のインデックスアクセスまたはスライス式を解析する役割を担っています。 変更前:// ... if ncolons > 0 { // slice expression return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Rbrack: rbrack} } // ...
変更後:
// ... if ncolons > 0 { // slice expression return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Slice3: ncolons == 2, Rbrack: rbrack} } // ...
ここで
ncolons
は、解析中に検出されたコロンの数を表します。ncolons == 1
の場合:a[low:high]
のような2インデックススライス式。ncolons == 2
の場合:a[low:high:max]
のような3インデックススライス式。 変更後のコードでは、Slice3
フィールドがncolons == 2
の場合にtrue
に設定されるようになりました。これにより、パーサーがソースコードから3インデックススライス式を認識し、その情報をASTに正確に埋め込むことができるようになります。
この変更は、Goコンパイラのフロントエンドにおける重要なステップであり、新しい言語機能のサポートを可能にするための基盤となります。ASTにこの情報が追加されることで、型チェッカーはmax
インデックスが有効であるか、high
とmax
の関係が正しいか、そして結果として得られるスライスの容量が適切に計算されるかといった検証を行うことができます。
コアとなるコードの変更箇所
src/pkg/go/ast/ast.go
SliceExpr
構造体にSlice3 bool
フィールドが追加されました。
--- a/src/pkg/go/ast/ast.go
+++ b/src/pkg/go/ast/ast.go
@@ -298,6 +298,7 @@ type (
Low Expr // begin of slice range; or nil
High Expr // end of slice range; or nil
Max Expr // maximum capacity of slice; or nil
+ Slice3 bool // true if 3-index slice (2 colons present)
Rbrack token.Pos // position of "]"
}
src/pkg/go/parser/parser.go
parseIndexOrSlice
関数内でSliceExpr
を生成する際に、Slice3
フィールドにncolons == 2
の結果が設定されるようになりました。
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -1187,7 +1187,7 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
if ncolons > 0 {
// slice expression
- return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Rbrack: rbrack}
+ return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Slice3: ncolons == 2, Rbrack: rbrack}
}
return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
コアとなるコードの解説
src/pkg/go/ast/ast.go
の変更
SliceExpr
構造体は、Go言語のスライス式(例: a[low:high]
や a[low:high:max]
)をAST上で表現するためのものです。このコミットで追加されたSlice3 bool
フィールドは、そのスライス式が3つのインデックス(つまり2つのコロン)を持つ形式であるかどうかを明示的に示すフラグです。
true
の場合:a[low:high:max]
の形式。false
の場合:a[low:high]
の形式(またはa[:high]
、a[low:]
、a[:]
など、max
が指定されていない形式)。
このフラグは、ASTを走査する後続のコンパイラフェーズ(特に型チェッカー)が、スライスの長さと容量を計算する際に、どのルールを適用すべきかを判断するために使用されます。例えば、3インデックススライスの場合、結果のスライスの容量はmax - low
として計算されますが、2インデックススライスではcap(original_slice) - low
となります。このSlice3
フィールドがなければ、型チェッカーはMax
フィールドが存在するかどうかだけで判断することになり、それはMax
がnil
でない場合にのみ機能しますが、Max
がnil
でない場合でも2インデックススライスである可能性を考慮できません。Slice3
フラグは、この曖昧さを解消し、より堅牢な型チェックを可能にします。
src/pkg/go/parser/parser.go
の変更
parseIndexOrSlice
関数は、Goのパーサーの中核部分であり、角括弧[]
で囲まれた式(インデックスアクセスやスライス式)を解析します。この関数は、コロンの数(ncolons
)を数えることで、それがインデックスアクセスなのか、2インデックススライスなのか、3インデックススライスなのかを判別します。
変更前のコードでは、ncolons > 0
(つまりスライス式である)場合に、一律にSliceExpr
を生成していました。しかし、Slice3
フィールドが追加されたことで、パーサーはスライス式の種類をより詳細に区別してASTに反映させる必要があります。
変更後のコードでは、Slice3: ncolons == 2
という条件が追加されました。
ncolons == 1
の場合(例:a[low:high]
):Slice3
はfalse
になります。ncolons == 2
の場合(例:a[low:high:max]
):Slice3
はtrue
になります。
これにより、パーサーはソースコードの構文を正確にASTにマッピングし、3インデックススライス式の存在をASTを通じてコンパイラの他の部分に伝えることができるようになります。これは、Go 1.2で導入された3インデックススライス機能が、言語の構文解析から型チェック、そして最終的なコード生成まで、コンパイラ全体で正しく処理されるための基盤を築く重要な変更です。
関連リンク
- Go 1.2 Release Notes: 3インデックススライスに関する公式情報が含まれています。 https://go.dev/doc/go1.2
- Go言語の仕様 - Slices: スライスの詳細な仕様について。 https://go.dev/ref/spec#Slice_expressions
- Go言語のASTパッケージドキュメント:
go/ast
パッケージの公式ドキュメント。 https://pkg.go.dev/go/ast - Go言語のパーサーパッケージドキュメント:
go/parser
パッケージの公式ドキュメント。 https://pkg.go.dev/go/parser
参考にした情報源リンク
- Go言語の公式ドキュメント (go.dev)
- Go言語のソースコード (github.com/golang/go)
- Go言語のコミット履歴
- Go言語のIssueトラッカー (golang.org/issue)
- Go言語のメーリングリスト (golang-dev)
- 各種Go言語に関する技術ブログや解説記事 (3インデックススライスに関するもの)