[インデックス 13954] ファイルの概要
このコミットは、Go言語の実験的な型システム (exp/types/staging
) における gcimporter
パッケージの更新に関するものです。具体的には、types.go
および const.go
で定義された新しい型定義に合わせるための、主に軽微な変更が含まれています。
変更されたファイルは以下の通りです。
src/pkg/exp/types/staging/exportdata.go
: 新規追加されたファイルで、Goコンパイラが生成するオブジェクトファイルやアーカイブファイルからエクスポートデータセクションを見つけるためのロジックを実装しています。src/pkg/exp/types/staging/gcimporter.go
: 新規追加されたファイルで、gc
(Goコンパイラ) が生成したオブジェクトファイルからパッケージをインポートするためのast.Importer
の実装を含んでいます。src/pkg/exp/types/staging/gcimporter_test.go
: 新規追加されたテストファイルで、gcimporter
の機能、特にパッケージのインポートと型情報の正確な読み込みを検証します。src/pkg/exp/types/staging/testdata/exports.go
: 新規追加されたテストデータファイルで、gcimporter_test.go
が使用するオブジェクトファイルを生成するためのGoソースコードです。様々なGoの型、定数、変数、関数、メソッドの定義が含まれています。
コミット
commit 1785bfca6b0bbf84c44b438968f328c02aeee73d
Author: Robert Griesemer <gri@golang.org>
Date: Tue Sep 25 17:39:02 2012 -0700
exp/types/staging: updated gcimporter
Mostly minor changes to match the new
definitions in types.go and const.go.
R=rsc, r
CC=golang-dev
https://golang.org/cl/6506101
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1785bfca6b0bbf84c44b438968f328c02aeee73d
元コミット内容
exp/types/staging: updated gcimporter
Mostly minor changes to match the new
definitions in types.go and const.go.
R=rsc, r
CC=golang-dev
https://golang.org/cl/6506101
変更の背景
このコミットの主な背景は、Go言語の型システム (exp/types
) が進化する中で、その内部表現や定義が変更されたことにあります。特に、types.go
と const.go
というGo言語の型システムの中核をなすファイルで新しい定義が導入されたため、それらの変更に合わせて、コンパイラが生成するエクスポートデータを読み込む gcimporter
も更新する必要がありました。
exp/types
は、Go言語のコンパイラやツールがコードの型チェックを行う際に使用する、型情報の抽象的な表現を提供するパッケージです。gcimporter
は、Goコンパイラ (gc
) がコンパイル時に生成するパッケージのエクスポートデータ(他のパッケージから参照可能な型、関数、変数などの情報)を読み込み、それを exp/types
の内部表現に変換する役割を担っています。
したがって、types.go
や const.go
の変更は、エクスポートデータのフォーマットや内容に影響を与える可能性があり、gcimporter
がその新しいフォーマットを正しく解釈できるように更新される必要がありました。このコミットは、その整合性を保つためのメンテナンス作業の一環として行われました。
前提知識の解説
このコミットを理解するためには、以下のGo言語の概念と関連パッケージに関する知識が必要です。
- Go言語のパッケージシステム: Go言語のコードはパッケージに分割され、他のパッケージの公開された(エクスポートされた)エンティティ(型、関数、変数など)を利用できます。コンパイラは、パッケージをコンパイルする際に、そのパッケージのエクスポート情報を生成します。
go/ast
パッケージ: Go言語のソースコードの抽象構文木 (AST: Abstract Syntax Tree) を表現するためのパッケージです。コンパイラやリンターなどのツールがGoコードを解析する際に使用します。ast.Object
はAST内の名前付きエンティティ(変数、関数、型など)を表し、ast.Scope
は識別子のスコープを管理します。go/token
パッケージ: Go言語のソースコードのトークン(識別子、キーワード、演算子など)とソースコード上の位置情報を扱うパッケージです。go/build
パッケージ: Go言語のパッケージのビルドプロセスに関する情報(パッケージの検索、依存関係の解決など)を提供するパッケージです。build.Import
関数は、インポートパスからパッケージの情報を解決するために使用されます。bufio
パッケージ: バッファリングされたI/Oを提供するパッケージです。ファイルからの効率的な読み込みに使用されます。text/scanner
パッケージ: テキストをトークンに分割するためのスキャナーを提供します。gcimporter
は、エクスポートデータを解析するためにこれを使用します。math/big
パッケージ: 任意精度の整数、有理数、浮動小数点数を扱うためのパッケージです。Goのエクスポートデータには、任意精度の定数も含まれるため、これらを正確に表現するために使用されます。os
パッケージ: オペレーティングシステムとのインタフェースを提供するパッケージです。ファイル操作(ファイルのオープン、ディレクトリの取得など)に使用されます。path/filepath
パッケージ: ファイルパスを操作するためのユーティリティを提供するパッケージです。プラットフォームに依存しないパスの結合などに使用されます。strconv
パッケージ: 文字列と数値の変換を行うパッケージです。エクスポートデータ内の数値リテラルを解析する際に使用されます。strings
パッケージ: 文字列操作のためのユーティリティを提供するパッケージです。exp/types
パッケージ: Go言語の型システムを表現するための実験的なパッケージです。このパッケージは、Goの型チェックやセマンティック分析の基盤となります。gcimporter
は、このパッケージの型表現にエクスポートデータをマッピングします。- Goコンパイラ (
gc
) のエクスポートデータ: Goコンパイラは、コンパイルされたパッケージの公開されたAPI(型、関数、変数など)を記述したエクスポートデータを生成します。このデータは、他のパッケージがそのパッケージをインポートする際に使用されます。通常、.a
(アーカイブ) ファイルや、特定のアーキテクチャに特化したファイル (.5
,.6
,.8
など) の中に埋め込まれています。
技術的詳細
このコミットで追加・変更された gcimporter
は、Goコンパイラが生成するエクスポートデータを解析し、それを go/ast
パッケージの ast.Object
や exp/types
パッケージの型表現に変換する役割を担っています。
主要なコンポーネントと機能は以下の通りです。
-
FindGcExportData
関数 (exportdata.go
):- この関数は、Goコンパイラが生成したオブジェクトファイルまたはアーカイブファイルの中から、エクスポートデータが格納されているセクションの開始位置を見つけます。
- Goのアーカイブファイル (
.a
ファイル) は、UNIXのar
形式に似た構造を持っています。この関数は、アーカイブヘッダを読み込み、__.SYMDEF
(または__.GOSYMDEF
) と__.PKGDEF
という特殊なエントリを検索します。__.PKGDEF
がエクスポートデータを含んでいます。 - オブジェクトファイルの場合、
"go object "
で始まる行を読み込み、"$$"
で区切られたエクスポートデータの開始位置までスキップします。 - この関数は、
bufio.Reader
を使用して効率的にファイルを読み進めます。
-
gcParser
構造体 (gcimporter.go
):gcParser
は、エクスポートデータを実際に解析するためのパーサーです。text/scanner.Scanner
を内部に持ち、エクスポートデータをトークンに分割します。init
メソッドで初期化され、ファイル名、パッケージID、入力ストリーム、および既にインポートされたパッケージのマップを受け取ります。next
メソッドで次のトークンを読み込みます。declare
メソッドは、新しいast.Object
を作成し、現在のスコープに挿入します。これにより、インポートされたエンティティが型システム内で利用可能になります。- エラーハンドリングは、
importError
型のパニックとリカバリによって行われます。
-
エクスポートデータの解析ロジック (
gcimporter.go
):gcParser
は、エクスポートデータの様々なセクションを解析するためのメソッド群を持っています。parsePkgId()
: パッケージのインポートパスを解析し、対応するast.Object
(パッケージオブジェクト) を返します。unsafe
パッケージは特別扱いされます。parseExportedName()
:@
プレフィックスを持つエクスポートされた名前(例:@\"math\".Pi
)を解析し、そのパッケージと名前を抽出します。- 型解析 (
parseType()
,parseBasicType()
,parseArrayType()
,parseMapType()
,parseStructType()
,parseInterfaceType()
,parseChanType()
,parseSignature()
):- Goの様々な型(基本型、配列、スライス、構造体、インターフェース、マップ、チャネル、関数シグネチャ、ポインタ)のエクスポート表現を解析し、
exp/types
パッケージの対応する型構造体 (Array
,Map
,Struct
,Interface
,Chan
,Signature
,Pointer
など) に変換します。 - 構造体のフィールドやインターフェースのメソッドも再帰的に解析されます。
- 匿名フィールドや可変長引数 (
...
) も適切に処理されます。
- Goの様々な型(基本型、配列、スライス、構造体、インターフェース、マップ、チャネル、関数シグネチャ、ポインタ)のエクスポート表現を解析し、
- 宣言解析 (
parseImportDecl()
,parseConstDecl()
,parseTypeDecl()
,parseVarDecl()
,parseFuncDecl()
,parseMethodDecl()
):- エクスポートデータ内のインポート宣言、定数宣言、型宣言、変数宣言、関数宣言、メソッド宣言を解析します。
- 定数宣言では、
math/big
パッケージを使用して任意精度の数値リテラルを正確に解析します。 - 型宣言では、
NamedType
を使用して、前方参照(型が定義される前に参照されるケース)を適切に処理します。 - 関数やメソッドの本体 (
FuncBody
) は、エクスポートデータには含まれないため、単にスキップされます。
parseExport()
: エクスポートデータの最上位の解析エントリポイントです。package
句を読み込み、その後に続くすべての宣言を$$
終端記号まで解析します。
この gcimporter
の実装は、Goコンパイラが生成するバイナリ形式のエクスポートデータを、Goのツールが利用できる抽象構文木や型システム表現に変換するための重要なブリッジとして機能します。これにより、Goのツールは、ソースコードを再解析することなく、コンパイル済みのパッケージのAPI情報を効率的に取得できます。
コアとなるコードの変更箇所
このコミットでは、以下の4つのファイルが新規追加されています。
-
src/pkg/exp/types/staging/exportdata.go
:FindGcExportData
関数が追加されています。この関数は、Goのオブジェクトファイルやアーカイブファイルからエクスポートデータセクションを見つけるためのロジックを実装しています。readGopackHeader
ヘルパー関数も含まれており、Goのアーカイブファイルのヘッダを解析します。
-
src/pkg/exp/types/staging/gcimporter.go
:FindPkg
関数が追加されています。これは、インポートパスに基づいてパッケージのファイル名とユニークなIDを検索します。GcImportData
関数が追加されています。これは、FindGcExportData
で見つけられたエクスポートデータのリーダーを受け取り、パッケージをインポートします。GcImport
関数が追加されています。これはast.Importer
インターフェースを満たし、インポートパスからパッケージ全体をインポートする主要なエントリポイントです。gcParser
構造体とその多数のメソッドが追加されています。これらは、エクスポートデータの各要素(型、定数、変数、関数、メソッドなど)を解析するための中心的なロジックを構成します。init
,next
,declare
, エラーハンドリング関連のメソッド。parsePkgId
,parseDotIdent
,parseExportedName
など、名前解決に関するメソッド。parseBasicType
,parseArrayType
,parseMapType
,parseName
,parseField
,parseStructType
,parseParameter
,parseParameters
,parseSignature
,parseInterfaceType
,parseChanType
,parseType
など、Goの型を解析するメソッド群。parseImportDecl
,parseInt
,parseNumber
,parseConstDecl
,parseTypeDecl
,parseVarDecl
,parseFuncBody
,parseFuncDecl
,parseMethodDecl
,parseDecl
など、Goの宣言を解析するメソッド群。parseExport
は、エクスポートデータ全体の解析を開始するメソッドです。
-
src/pkg/exp/types/staging/gcimporter_test.go
:gcPath
変数とinit
関数が追加され、Goコンパイラのパスを特定します。compile
ヘルパー関数が追加され、テスト用のGoファイルをコンパイルします。imports
グローバルマップが定義され、インポートされたパッケージを保持します。testPath
とtestDir
関数が追加され、特定のパスやディレクトリ内のパッケージのインポートをテストします。TestGcImport
関数が追加され、gcimporter
を使用してパッケージをインポートする基本的なテストを行います。importedObjectTests
スライスとTestGcImportedTypes
関数が追加され、unsafe.Pointer
,math.Pi
,io.Reader
などの特定のインポートされたオブジェクトの型と種類が正しいことを検証します。
-
src/pkg/exp/types/staging/testdata/exports.go
:exports
パッケージとして定義されたGoソースファイルです。- 様々な種類の定数 (
C0
からC7
)、型 (T1
からT28
)、変数 (V0
,V1
)、関数 (F1
からF5
) が定義されています。これらは、gcimporter
が正しくエクスポートデータを解析できることを確認するためのテストケースとして機能します。 - 特に、複雑な型(構造体、インターフェース、チャネル、関数シグネチャ、再帰的な型定義)や、ドット付き識別子 (
Issue 3682
) のテストが含まれています。
これらのファイルは、Go言語の型システムがコンパイル済みパッケージの情報をどのように読み込み、内部表現に変換するかを示す、gcimporter
の初期実装を構成しています。
コアとなるコードの解説
このコミットのコアとなるコードは、src/pkg/exp/types/staging/gcimporter.go
と src/pkg/exp/types/staging/exportdata.go
にあります。
exportdata.go
の解説
FindGcExportData(r *bufio.Reader) (err error)
:- この関数は、Goコンパイラが生成したバイナリファイル(オブジェクトファイルまたはアーカイブファイル)から、エクスポートデータが始まる位置を特定します。
- Goのアーカイブファイル (
.a
ファイル) の場合、!<arch>\n
で始まるシグネチャをチェックし、その後__.SYMDEF
(または__.GOSYMDEF
) と__.PKGDEF
という特殊なアーカイブエントリを検索します。__.PKGDEF
が実際のGoのエクスポートデータを含んでいます。 - オブジェクトファイルの場合、ファイルが
go object
で始まることを確認し、$$
というマーカーが現れるまで行を読み飛ばします。この$$
の後にエクスポートデータが続きます。 - この関数は、
bufio.Reader
を使用して効率的にファイルを読み込み、エクスポートデータの開始位置にリーダーを配置します。これにより、後続のパーサーが直接エクスポートデータを読み取れるようになります。
gcimporter.go
の解説
-
FindPkg(path, srcDir string) (filename, id string)
:- Goの
build
パッケージを利用して、与えられたインポートパス (path
) とソースディレクトリ (srcDir
) から、対応するコンパイル済みパッケージのファイル名とユニークなパッケージIDを特定します。 - Goのパッケージファイルは通常、
.a
、.5
、.6
、.8
などの拡張子を持ちます。この関数はこれらの拡張子を試行してファイルを見つけます。
- Goの
-
GcImportData(imports map[string]*ast.Object, filename, id string, data *bufio.Reader) (pkg *ast.Object, err error)
:- この関数は、既にエクスポートデータの開始位置に配置された
bufio.Reader
(data
) を受け取り、実際のパッケージインポート処理を行います。 - 内部で
gcParser
を初期化し、parseExport()
メソッドを呼び出してエクスポートデータを解析します。 - エラーハンドリングのために
panic
/recover
メカニズムを使用し、importError
型のパニックを捕捉します。
- この関数は、既にエクスポートデータの開始位置に配置された
-
GcImport(imports map[string]*ast.Object, path string) (pkg *ast.Object, err error)
:ast.Importer
インターフェースを満たす主要な関数です。- インポートパス (
path
) を受け取り、FindPkg
を使用してパッケージファイルを見つけます。 - ファイルを開き、
FindGcExportData
を呼び出してエクスポートデータの開始位置に移動します。 - 最終的に
GcImportData
を呼び出してパッケージをインポートし、結果のast.Object
(パッケージオブジェクト) を返します。 unsafe
パッケージは特別に処理され、組み込みのUnsafe
オブジェクトが返されます。
-
gcParser
構造体と解析メソッド群:gcParser
は、エクスポートデータの構文解析を行う中心的なコンポーネントです。scanner.Scanner
:text/scanner
パッケージのScanner
を使用して、エクスポートデータをトークン(識別子、数値、文字列、記号など)に分割します。declare(scope *ast.Scope, kind ast.ObjKind, name string) *ast.Object
:- 新しい名前付きオブジェクト(定数、型、変数、関数など)を現在のスコープに宣言します。
- 既に同じ名前のオブジェクトがスコープに存在する場合は、既存のオブジェクトを返します。これは、前方参照や複数回インポートされるケースを処理するために重要です。
- 型オブジェクトの場合、
NamedType
を使用して、基底型が後で解決される可能性のある名前付き型を表現します。
- 型解析メソッド (
parseType
,parseStructType
,parseInterfaceType
,parseSignature
など):- エクスポートデータ内のGoの型表現(例:
struct { a int; b float32 }
,interface { m1() }
,func(x int) float32
)を読み込み、exp/types
パッケージの対応する型構造体(Struct
,Interface
,Signature
など)に変換します。 - これらのメソッドは再帰的に呼び出され、複雑なネストされた型も処理できます。
- エクスポートデータ内のGoの型表現(例:
- 宣言解析メソッド (
parseConstDecl
,parseTypeDecl
,parseVarDecl
,parseFuncDecl
,parseMethodDecl
など):- エクスポートデータ内の各種宣言(定数、型、変数、関数、メソッド)を解析し、対応する
ast.Object
を作成し、その型情報を設定します。 - 定数については、
math/big
を使用して任意精度の数値(整数、浮動小数点数、複素数)を正確に表現します。
- エクスポートデータ内の各種宣言(定数、型、変数、関数、メソッド)を解析し、対応する
parseExport() *ast.Object
:- エクスポートデータの最上位の解析メソッドです。
package
句を読み込み、その後$$
終端記号が現れるまで、すべての宣言 (parseDecl()
) を繰り返し解析します。- これにより、パッケージ全体のエクスポートされたAPIが
ast.Object
とexp/types
の型表現として構築されます。
これらのコードは、Go言語のコンパイラと型システムの間で、コンパイル済みパッケージの型情報をやり取りするための基盤を提供します。これにより、Goのツールは、ソースコードを再解析することなく、型チェックやコード補完などの機能を実現できます。
関連リンク
参考にした情報源リンク
Web検索では、この特定のコミットに関する追加の情報は見つかりませんでした。解説は、コミットメッセージ、変更されたコード、およびGo言語の一般的な知識に基づいて生成されています。