refactor(mir): Extract MetadataContext from MirBuilder (Phase 136 follow-up 6/7)
## Summary Extracted metadata and debug information management into dedicated MetadataContext struct, completing step 6 of 7 in the Context Box refactoring plan. ## Changes - NEW: src/mir/builder/metadata_context.rs (MetadataContext struct + helpers) - Modified: src/mir/builder.rs (added metadata_ctx field + sync helpers) - Modified: src/mir/hints.rs (added Clone + Debug derives to HintSink) - Updated: phase-136-context-box-progress.md (6/7 progress) ## Extracted Fields - current_span: Span → metadata_ctx.current_span - source_file: Option<String> → metadata_ctx.source_file - hint_sink: HintSink → metadata_ctx.hint_sink - current_region_stack: Vec<RegionId> → metadata_ctx.current_region_stack ## Key Features - Zero-cost type inference hints (HintSink) - Source position tracking for error messages - Region observation stack for debug builds - Phase 135 contract_checks integration ## Tests - cargo test --release --lib: 1019/1023 passed (4 pre-existing failures) - phase135_trim_mir_verify.sh: PASS - Backward compatibility: 100% maintained (deprecated fields synced) ## Progress Phase 136 Context Extraction: 6/7 complete (86%) - ✅ Step 1: TypeContext - ✅ Step 2: CoreContext - ✅ Step 3: ScopeContext - ✅ Step 4: BindingContext - ✅ Step 5: VariableContext - ✅ Step 6: MetadataContext (this commit) - ⏳ Step 7: CompilationContext 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
builder.rs の 1219 行を責任ごとに Context Box に分割し、保守性・テスト容易性を向上させる段階的リファクタリング。
|
builder.rs の 1219 行を責任ごとに Context Box に分割し、保守性・テスト容易性を向上させる段階的リファクタリング。
|
||||||
|
|
||||||
## 完了した Context (5/7)
|
## 完了した Context (6/7)
|
||||||
|
|
||||||
### ✅ TypeContext (Step 1) - 完了
|
### ✅ TypeContext (Step 1) - 完了
|
||||||
|
|
||||||
@ -166,15 +166,48 @@ builder.rs の 1219 行を責任ごとに Context Box に分割し、保守性
|
|||||||
- JoinIR lowering で `CarrierInfo::from_variable_map()` を使用
|
- JoinIR lowering で `CarrierInfo::from_variable_map()` を使用
|
||||||
- 段階的移行により破壊的変更なし
|
- 段階的移行により破壊的変更なし
|
||||||
|
|
||||||
|
**コミット**: ee2915a6
|
||||||
|
|
||||||
|
### ✅ MetadataContext (Step 6) - 完了
|
||||||
|
|
||||||
|
**実装日**: 2025-12-15
|
||||||
|
|
||||||
|
**抽出したフィールド** (4個):
|
||||||
|
- `current_span: Span` - 現在の AST span (命令アノテーション用)
|
||||||
|
- `source_file: Option<String>` - ソースファイルヒント (メタデータ用)
|
||||||
|
- `hint_sink: HintSink` - 型推論ヒント (ゼロコストガイダンス)
|
||||||
|
- `current_region_stack: Vec<RegionId>` - Region 観測用スタック (NYASH_REGION_TRACE=1 デバッグ用)
|
||||||
|
|
||||||
|
**ファイル**:
|
||||||
|
- `/home/tomoaki/git/hakorune-selfhost/src/mir/builder/metadata_context.rs` (新規作成)
|
||||||
|
- `/home/tomoaki/git/hakorune-selfhost/src/mir/hints.rs` (HintSink に Clone, Debug 追加)
|
||||||
|
|
||||||
|
**統合方法**:
|
||||||
|
- `MirBuilder` に `metadata_ctx: MetadataContext` フィールドを追加
|
||||||
|
- 既存フィールドは `#[deprecated]` でマーク(後方互換性維持)
|
||||||
|
- 同期ヘルパー (`sync_metadata_ctx_to_legacy()`, `sync_legacy_to_metadata_ctx()`) を実装
|
||||||
|
- Hint メソッド (`hint_scope_enter()`, `hint_scope_leave()`, `hint_join_result()`) が metadata_ctx を SSOT として使用し、legacy フィールドを同期
|
||||||
|
- Source file メソッド (`set_source_file_hint()`, `clear_source_file_hint()`, `current_source_file()`) を metadata_ctx 経由に更新
|
||||||
|
- Span 使用箇所 (`add_instruction_with_span()`) を metadata_ctx.current_span() 経由に更新
|
||||||
|
|
||||||
|
**特徴**:
|
||||||
|
- **HintSink**: 型推論最適化への将来対応 (現在は no-op デフォルト)
|
||||||
|
- **Span**: 命令単位で保持され、エラー報告・デバッグ情報生成に使用
|
||||||
|
- **source_file**: 関数メタデータに伝播 (FunctionMetadata.source_file)
|
||||||
|
- **current_region_stack**: 開発用トレース専用 (本番コストゼロ)
|
||||||
|
|
||||||
|
**テスト結果**:
|
||||||
|
- ✅ `cargo build --release` 成功 (381 warnings - deprecated フィールド使用)
|
||||||
|
- ✅ `cargo test --release --lib` - 1019/1023 PASS (4 tests 失敗は既存問題)
|
||||||
|
- ✅ `phase135_trim_mir_verify.sh` - PASS
|
||||||
|
|
||||||
|
**影響範囲**:
|
||||||
|
- builder 内で current_span, source_file, hint_sink, current_region_stack を使用中のコードを metadata_ctx 経由に移行
|
||||||
|
- 段階的移行により破壊的変更なし
|
||||||
|
|
||||||
**コミット**: [今回のコミット]
|
**コミット**: [今回のコミット]
|
||||||
|
|
||||||
## 残りの Context (2/7)
|
## 残りの Context (1/7)
|
||||||
|
|
||||||
### 5. MetadataContext (計画中)
|
|
||||||
- `hint_sink: HintSink` - ヒントシンク (zero-cost guidance)
|
|
||||||
- `current_span: Span` - 現在の AST スパン
|
|
||||||
- `source_file: Option<String>` - ソースファイルヒント
|
|
||||||
- `current_region_stack: Vec<RegionId>` - Region 観測スタック
|
|
||||||
|
|
||||||
### 6. CompilationContext (計画中)
|
### 6. CompilationContext (計画中)
|
||||||
- `compilation_context: Option<BoxCompilationContext>` - Box コンパイルコンテキスト
|
- `compilation_context: Option<BoxCompilationContext>` - Box コンパイルコンテキスト
|
||||||
@ -182,9 +215,6 @@ builder.rs の 1219 行を責任ごとに Context Box に分割し、保守性
|
|||||||
- `user_defined_boxes: HashSet<String>` - ユーザー定義 Box 名
|
- `user_defined_boxes: HashSet<String>` - ユーザー定義 Box 名
|
||||||
- `reserved_value_ids: HashSet<ValueId>` - 予約済み ValueId
|
- `reserved_value_ids: HashSet<ValueId>` - 予約済み ValueId
|
||||||
|
|
||||||
### 7. ResourceContext (将来予定)
|
|
||||||
- リソース管理関連フィールド (将来追加)
|
|
||||||
|
|
||||||
## 設計原則
|
## 設計原則
|
||||||
|
|
||||||
1. **段階的移行** - 全フィールドを一度に移行せず、1-2 Context ずつ
|
1. **段階的移行** - 全フィールドを一度に移行せず、1-2 Context ずつ
|
||||||
@ -194,9 +224,9 @@ builder.rs の 1219 行を責任ごとに Context Box に分割し、保守性
|
|||||||
|
|
||||||
## 次のステップ
|
## 次のステップ
|
||||||
|
|
||||||
**優先順位 6**: MetadataContext 抽出
|
**優先順位 7**: CompilationContext 抽出 (最終ステップ)
|
||||||
- ヒントシンク・スパン・リージョン管理の集約
|
- Box コンパイルコンテキストの集約
|
||||||
- コンパイル時メタデータの統一管理
|
- 静的 Box 管理・予約済み ValueId の統一管理
|
||||||
|
|
||||||
## 参考資料
|
## 参考資料
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@ mod calls; // Call system modules (refactored from builder_calls)
|
|||||||
mod binding_context; // Phase 136 follow-up (Step 4/7): BindingContext extraction
|
mod binding_context; // Phase 136 follow-up (Step 4/7): BindingContext extraction
|
||||||
mod context; // BoxCompilationContext - 箱理論による静的Boxコンパイル時のコンテキスト分離
|
mod context; // BoxCompilationContext - 箱理論による静的Boxコンパイル時のコンテキスト分離
|
||||||
mod core_context; // Phase 136 follow-up (Step 2/7): CoreContext extraction
|
mod core_context; // Phase 136 follow-up (Step 2/7): CoreContext extraction
|
||||||
|
mod metadata_context; // Phase 136 follow-up (Step 6/7): MetadataContext extraction
|
||||||
mod variable_context; // Phase 136 follow-up (Step 5/7): VariableContext extraction
|
mod variable_context; // Phase 136 follow-up (Step 5/7): VariableContext extraction
|
||||||
mod decls; // declarations lowering split
|
mod decls; // declarations lowering split
|
||||||
mod exprs; // expression lowering split
|
mod exprs; // expression lowering split
|
||||||
@ -125,6 +126,11 @@ pub struct MirBuilder {
|
|||||||
/// Direct field access for backward compatibility (migration in progress).
|
/// Direct field access for backward compatibility (migration in progress).
|
||||||
pub(super) variable_ctx: variable_context::VariableContext,
|
pub(super) variable_ctx: variable_context::VariableContext,
|
||||||
|
|
||||||
|
/// Phase 136 follow-up (Step 6/7): Metadata context
|
||||||
|
/// Consolidates current_span, source_file, hint_sink, current_region_stack.
|
||||||
|
/// Direct field access for backward compatibility (migration in progress).
|
||||||
|
pub(super) metadata_ctx: metadata_context::MetadataContext,
|
||||||
|
|
||||||
/// [DEPRECATED] Variable name to ValueId mapping (for SSA conversion)
|
/// [DEPRECATED] Variable name to ValueId mapping (for SSA conversion)
|
||||||
/// Phase 136 Step 5/7: Moved to variable_ctx.variable_map (backward compat wrapper)
|
/// Phase 136 Step 5/7: Moved to variable_ctx.variable_map (backward compat wrapper)
|
||||||
/// 注意: compilation_contextがSomeの場合は使用されません
|
/// 注意: compilation_contextがSomeの場合は使用されません
|
||||||
@ -204,8 +210,10 @@ pub struct MirBuilder {
|
|||||||
/// Source size snapshot to detect when to rebuild the tail index
|
/// Source size snapshot to detect when to rebuild the tail index
|
||||||
pub(super) method_tail_index_source_len: usize,
|
pub(super) method_tail_index_source_len: usize,
|
||||||
|
|
||||||
/// Region 観測用のスタックだよ(FunctionRegion がルート)。
|
/// [DEPRECATED] Region 観測用のスタックだよ(FunctionRegion がルート)。
|
||||||
|
/// Phase 136 Step 6/7: Moved to metadata_ctx.current_region_stack (backward compat wrapper)
|
||||||
/// - NYASH_REGION_TRACE=1 のときだけ使われる開発用メタデータだよ。
|
/// - NYASH_REGION_TRACE=1 のときだけ使われる開発用メタデータだよ。
|
||||||
|
#[deprecated(note = "Use metadata_ctx.current_region_stack instead")]
|
||||||
pub(super) current_region_stack: Vec<RegionId>,
|
pub(super) current_region_stack: Vec<RegionId>,
|
||||||
|
|
||||||
/// Phase 200-C: Original function body AST for capture analysis
|
/// Phase 200-C: Original function body AST for capture analysis
|
||||||
@ -261,7 +269,9 @@ pub struct MirBuilder {
|
|||||||
pub(super) cleanup_allow_return: bool,
|
pub(super) cleanup_allow_return: bool,
|
||||||
pub(super) cleanup_allow_throw: bool,
|
pub(super) cleanup_allow_throw: bool,
|
||||||
|
|
||||||
/// Hint sink (zero-cost guidance; currently no-op)
|
/// [DEPRECATED] Hint sink (zero-cost guidance; currently no-op)
|
||||||
|
/// Phase 136 Step 6/7: Moved to metadata_ctx.hint_sink (backward compat wrapper)
|
||||||
|
#[deprecated(note = "Use metadata_ctx.hint_sink instead")]
|
||||||
pub(super) hint_sink: crate::mir::hints::HintSink,
|
pub(super) hint_sink: crate::mir::hints::HintSink,
|
||||||
|
|
||||||
/// [DEPRECATED] Internal counter for temporary pin slots (block-crossing ephemeral values)
|
/// [DEPRECATED] Internal counter for temporary pin slots (block-crossing ephemeral values)
|
||||||
@ -305,10 +315,14 @@ pub struct MirBuilder {
|
|||||||
/// Tracks the depth of build_expression calls to detect infinite loops
|
/// Tracks the depth of build_expression calls to detect infinite loops
|
||||||
pub(super) recursion_depth: usize,
|
pub(super) recursion_depth: usize,
|
||||||
|
|
||||||
/// Current AST span being lowered (used to annotate MIR instructions)
|
/// [DEPRECATED] Current AST span being lowered (used to annotate MIR instructions)
|
||||||
|
/// Phase 136 Step 6/7: Moved to metadata_ctx.current_span (backward compat wrapper)
|
||||||
|
#[deprecated(note = "Use metadata_ctx.current_span instead")]
|
||||||
pub(super) current_span: Span,
|
pub(super) current_span: Span,
|
||||||
|
|
||||||
/// Optional source file hint for metadata/spans
|
/// [DEPRECATED] Optional source file hint for metadata/spans
|
||||||
|
/// Phase 136 Step 6/7: Moved to metadata_ctx.source_file (backward compat wrapper)
|
||||||
|
#[deprecated(note = "Use metadata_ctx.source_file instead")]
|
||||||
pub(super) source_file: Option<String>,
|
pub(super) source_file: Option<String>,
|
||||||
|
|
||||||
/// Root lowering mode: how to treat top-level Program
|
/// Root lowering mode: how to treat top-level Program
|
||||||
@ -349,6 +363,7 @@ impl MirBuilder {
|
|||||||
scope_ctx: scope_context::ScopeContext::new(), // Phase 136 Step 3/7: Scope context
|
scope_ctx: scope_context::ScopeContext::new(), // Phase 136 Step 3/7: Scope context
|
||||||
binding_ctx: binding_context::BindingContext::new(), // Phase 136 Step 4/7: Binding context
|
binding_ctx: binding_context::BindingContext::new(), // Phase 136 Step 4/7: Binding context
|
||||||
variable_ctx: variable_context::VariableContext::new(), // Phase 136 Step 5/7: Variable context
|
variable_ctx: variable_context::VariableContext::new(), // Phase 136 Step 5/7: Variable context
|
||||||
|
metadata_ctx: metadata_context::MetadataContext::new(), // Phase 136 Step 6/7: Metadata context
|
||||||
variable_map: BTreeMap::new(), // Phase 25.1: 決定性確保 (backward compat)
|
variable_map: BTreeMap::new(), // Phase 25.1: 決定性確保 (backward compat)
|
||||||
lexical_scope_stack: Vec::new(),
|
lexical_scope_stack: Vec::new(),
|
||||||
pending_phis: Vec::new(),
|
pending_phis: Vec::new(),
|
||||||
@ -475,6 +490,25 @@ impl MirBuilder {
|
|||||||
self.variable_ctx.variable_map = self.variable_map.clone();
|
self.variable_ctx.variable_map = self.variable_map.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Phase 136 Step 6/7: MetadataContext synchronization helpers ----
|
||||||
|
/// Sync metadata_ctx changes back to legacy fields (backward compatibility)
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn sync_metadata_ctx_to_legacy(&mut self) {
|
||||||
|
self.current_span = self.metadata_ctx.current_span;
|
||||||
|
self.source_file = self.metadata_ctx.source_file.clone();
|
||||||
|
self.hint_sink = self.metadata_ctx.hint_sink.clone();
|
||||||
|
self.current_region_stack = self.metadata_ctx.current_region_stack.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sync legacy field changes to metadata_ctx (backward compatibility)
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn sync_legacy_to_metadata_ctx(&mut self) {
|
||||||
|
self.metadata_ctx.current_span = self.current_span;
|
||||||
|
self.metadata_ctx.source_file = self.source_file.clone();
|
||||||
|
self.metadata_ctx.hint_sink = self.hint_sink.clone();
|
||||||
|
self.metadata_ctx.current_region_stack = self.current_region_stack.clone();
|
||||||
|
}
|
||||||
|
|
||||||
/// Push/pop helpers for If merge context (best-effort; optional usage)
|
/// Push/pop helpers for If merge context (best-effort; optional usage)
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub(super) fn push_if_merge(&mut self, bb: BasicBlockId) {
|
pub(super) fn push_if_merge(&mut self, bb: BasicBlockId) {
|
||||||
@ -526,17 +560,25 @@ impl MirBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---- Hint helpers (no-op by default) ----
|
// ---- Hint helpers (no-op by default) ----
|
||||||
|
// Phase 136 Step 6/7: Delegate to metadata_ctx with legacy sync
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub(crate) fn hint_scope_enter(&mut self, id: u32) {
|
pub(crate) fn hint_scope_enter(&mut self, id: u32) {
|
||||||
self.hint_sink.scope_enter(id);
|
self.metadata_ctx.hint_scope_enter(id);
|
||||||
|
self.hint_sink.scope_enter(id); // Legacy sync
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub(crate) fn hint_scope_leave(&mut self, id: u32) {
|
pub(crate) fn hint_scope_leave(&mut self, id: u32) {
|
||||||
self.hint_sink.scope_leave(id);
|
self.metadata_ctx.hint_scope_leave(id);
|
||||||
|
self.hint_sink.scope_leave(id); // Legacy sync
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub(crate) fn hint_join_result<S: Into<String>>(&mut self, var: S) {
|
pub(crate) fn hint_join_result<S: Into<String>>(&mut self, var: S) {
|
||||||
self.hint_sink.join_result(var.into());
|
let var = var.into();
|
||||||
|
self.metadata_ctx.hint_join_result(var.clone());
|
||||||
|
self.hint_sink.join_result(var); // Legacy sync
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------
|
// ----------------------
|
||||||
@ -576,19 +618,27 @@ impl MirBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Hint for downstream metadata: set the logical source file name/path for the next build.
|
/// Hint for downstream metadata: set the logical source file name/path for the next build.
|
||||||
|
/// Phase 136 Step 6/7: Delegate to metadata_ctx with legacy sync
|
||||||
|
#[allow(deprecated)]
|
||||||
pub fn set_source_file_hint<S: Into<String>>(&mut self, source: S) {
|
pub fn set_source_file_hint<S: Into<String>>(&mut self, source: S) {
|
||||||
self.source_file = Some(source.into());
|
let source = source.into();
|
||||||
|
self.metadata_ctx.set_source_file(source.clone());
|
||||||
|
self.source_file = Some(source); // Legacy sync
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear the source file hint (used when reusing the builder across modules).
|
/// Clear the source file hint (used when reusing the builder across modules).
|
||||||
|
/// Phase 136 Step 6/7: Delegate to metadata_ctx with legacy sync
|
||||||
|
#[allow(deprecated)]
|
||||||
pub fn clear_source_file_hint(&mut self) {
|
pub fn clear_source_file_hint(&mut self) {
|
||||||
self.source_file = None;
|
self.metadata_ctx.clear_source_file();
|
||||||
|
self.source_file = None; // Legacy sync
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve current source file hint (builder field or env fallback).
|
/// Resolve current source file hint (builder field or env fallback).
|
||||||
|
/// Phase 136 Step 6/7: Delegate to metadata_ctx
|
||||||
fn current_source_file(&self) -> Option<String> {
|
fn current_source_file(&self) -> Option<String> {
|
||||||
self.source_file
|
self.metadata_ctx
|
||||||
.clone()
|
.current_source_file()
|
||||||
.or_else(|| std::env::var("NYASH_SOURCE_FILE_HINT").ok())
|
.or_else(|| std::env::var("NYASH_SOURCE_FILE_HINT").ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1003,7 +1053,8 @@ impl MirBuilder {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
block.add_instruction_with_span(instruction.clone(), self.current_span);
|
// Phase 136 Step 6/7: Use metadata_ctx for span
|
||||||
|
block.add_instruction_with_span(instruction.clone(), self.metadata_ctx.current_span());
|
||||||
// Drop the mutable borrow of `block` before updating other blocks
|
// Drop the mutable borrow of `block` before updating other blocks
|
||||||
}
|
}
|
||||||
// Update predecessor sets for branch/jump immediately so that
|
// Update predecessor sets for branch/jump immediately so that
|
||||||
|
|||||||
183
src/mir/builder/metadata_context.rs
Normal file
183
src/mir/builder/metadata_context.rs
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*!
|
||||||
|
* Phase 136 Step 6/7: MetadataContext - Metadata/Span/Hint 管理の統一箱
|
||||||
|
*
|
||||||
|
* 責務:
|
||||||
|
* - current_span: 現在の AST span(命令アノテーション用)
|
||||||
|
* - source_file: ソースファイルヒント(メタデータ用)
|
||||||
|
* - hint_sink: 型推論ヒント(ゼロコストガイダンス)
|
||||||
|
* - current_region_stack: Region 観測用スタック(NYASH_REGION_TRACE=1 デバッグ用)
|
||||||
|
*
|
||||||
|
* 設計:
|
||||||
|
* - HintSink は no-op デフォルトだが、将来の型推論最適化に備える
|
||||||
|
* - Span は命令単位で保持され、エラー報告・デバッグ情報生成に使用
|
||||||
|
* - source_file は関数メタデータに伝播
|
||||||
|
* - current_region_stack は開発用トレース(本番コストゼロ)
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::ast::Span;
|
||||||
|
use crate::mir::hints::HintSink;
|
||||||
|
use crate::mir::region::RegionId;
|
||||||
|
|
||||||
|
/// Phase 136 Step 6/7: Metadata/Span/Hint 管理を統一した構造体だよ
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MetadataContext {
|
||||||
|
/// 現在の AST span(命令アノテーション用)
|
||||||
|
pub(super) current_span: Span,
|
||||||
|
|
||||||
|
/// ソースファイルヒント(関数メタデータに伝播)
|
||||||
|
pub(super) source_file: Option<String>,
|
||||||
|
|
||||||
|
/// 型推論ヒント(ゼロコストガイダンス)
|
||||||
|
pub(super) hint_sink: HintSink,
|
||||||
|
|
||||||
|
/// Region 観測用のスタック(NYASH_REGION_TRACE=1 のデバッグ専用)
|
||||||
|
/// - FunctionRegion がルート
|
||||||
|
/// - 開発時のみ使用(本番コストゼロ)
|
||||||
|
pub(super) current_region_stack: Vec<RegionId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetadataContext {
|
||||||
|
/// 新規 MetadataContext を生成(デフォルト状態)
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
current_span: Span::unknown(),
|
||||||
|
source_file: None,
|
||||||
|
hint_sink: HintSink::new(),
|
||||||
|
current_region_stack: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Span 管理 ----
|
||||||
|
|
||||||
|
/// 現在の span を取得
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn current_span(&self) -> Span {
|
||||||
|
self.current_span
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 現在の span を設定
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn set_current_span(&mut self, span: Span) {
|
||||||
|
self.current_span = span;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Source File 管理 ----
|
||||||
|
|
||||||
|
/// ソースファイルヒントを設定
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn set_source_file<S: Into<String>>(&mut self, source: S) {
|
||||||
|
self.source_file = Some(source.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ソースファイルヒントをクリア
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn clear_source_file(&mut self) {
|
||||||
|
self.source_file = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 現在のソースファイルヒントを取得
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn current_source_file(&self) -> Option<String> {
|
||||||
|
self.source_file.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Hint Sink 管理(型推論ガイダンス)----
|
||||||
|
|
||||||
|
/// スコープ開始ヒント(no-op デフォルト)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn hint_scope_enter(&mut self, id: u32) {
|
||||||
|
self.hint_sink.scope_enter(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// スコープ終了ヒント(no-op デフォルト)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn hint_scope_leave(&mut self, id: u32) {
|
||||||
|
self.hint_sink.scope_leave(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Join 結果ヒント(no-op デフォルト)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn hint_join_result<S: Into<String>>(&mut self, var: S) {
|
||||||
|
self.hint_sink.join_result(var.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Region Stack 管理(デバッグ専用)----
|
||||||
|
|
||||||
|
/// Region スタックに push(NYASH_REGION_TRACE=1 専用)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn push_region(&mut self, region_id: RegionId) {
|
||||||
|
self.current_region_stack.push(region_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Region スタックから pop(NYASH_REGION_TRACE=1 専用)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn pop_region(&mut self) -> Option<RegionId> {
|
||||||
|
self.current_region_stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 現在の Region スタックを取得(読み取り専用)
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn current_region_stack(&self) -> &[RegionId] {
|
||||||
|
&self.current_region_stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MetadataContext {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_metadata_context_creation() {
|
||||||
|
let ctx = MetadataContext::new();
|
||||||
|
assert!(ctx.source_file.is_none());
|
||||||
|
assert_eq!(ctx.current_region_stack.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_span_management() {
|
||||||
|
let mut ctx = MetadataContext::new();
|
||||||
|
let span = Span::new(0, 10, 1, 1);
|
||||||
|
ctx.set_current_span(span);
|
||||||
|
assert_eq!(ctx.current_span().start, 0);
|
||||||
|
assert_eq!(ctx.current_span().end, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_source_file_management() {
|
||||||
|
let mut ctx = MetadataContext::new();
|
||||||
|
ctx.set_source_file("test.hako");
|
||||||
|
assert_eq!(ctx.current_source_file(), Some("test.hako".to_string()));
|
||||||
|
ctx.clear_source_file();
|
||||||
|
assert!(ctx.current_source_file().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_region_stack() {
|
||||||
|
let mut ctx = MetadataContext::new();
|
||||||
|
let region1 = RegionId(1);
|
||||||
|
let region2 = RegionId(2);
|
||||||
|
|
||||||
|
ctx.push_region(region1);
|
||||||
|
ctx.push_region(region2);
|
||||||
|
assert_eq!(ctx.current_region_stack().len(), 2);
|
||||||
|
|
||||||
|
assert_eq!(ctx.pop_region(), Some(region2));
|
||||||
|
assert_eq!(ctx.pop_region(), Some(region1));
|
||||||
|
assert_eq!(ctx.pop_region(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hint_operations_no_panic() {
|
||||||
|
let mut ctx = MetadataContext::new();
|
||||||
|
// These should not panic (no-op by default)
|
||||||
|
ctx.hint_scope_enter(1);
|
||||||
|
ctx.hint_scope_leave(1);
|
||||||
|
ctx.hint_join_result("test_var");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,7 +20,7 @@ pub enum HintKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Hint sink (no-op). Backends/resolvers may hook into this later.
|
/// Hint sink (no-op). Backends/resolvers may hook into this later.
|
||||||
#[derive(Default)]
|
#[derive(Default, Clone, Debug)]
|
||||||
pub struct HintSink {
|
pub struct HintSink {
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user