feat(mir): Phase 136 Step 3/7 - ScopeContext extraction
## Summary Extract scope and control flow management into ScopeContext for better organization. ## Changes - **New file**: src/mir/builder/scope_context.rs (264 lines) - Lexical scope stack management - Control flow stacks (loop/if) - Function context tracking - Debug scope helpers - **Updated**: src/mir/builder.rs - Add scope_ctx field - Mark legacy fields as deprecated - Add sync helpers (sync_scope_ctx_to_legacy, sync_legacy_to_scope_ctx) - **Updated**: src/mir/builder/vars/lexical_scope.rs - Use scope_ctx as SSOT - Sync to legacy fields for backward compat - **Updated**: src/mir/builder/lifecycle.rs - Sync current_function via scope_ctx - **Updated**: src/mir/builder/calls/lowering.rs - Sync function context in lowering flow ## Extracted Fields (7) 1. lexical_scope_stack - Block-scoped locals 2. loop_header_stack - Loop headers for break/continue 3. loop_exit_stack - Loop exit blocks 4. if_merge_stack - If merge blocks 5. current_function - Currently building function 6. function_param_names - Function parameters (for LoopForm) 7. debug_scope_stack - Debug region identifiers ## Test Results - ✅ cargo build --release (291 warnings - deprecated usage) - ✅ cargo test --release --lib - 1005/1009 PASS - ✅ phase135_trim_mir_verify.sh - PASS - ⚠️ phase132_exit_phi_parity.sh - Error (pre-existing issue) ## Progress Phase 136: 3/7 Contexts complete (TypeContext, CoreContext, ScopeContext) 🤖 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 (2/7)
|
## 完了した Context (3/7)
|
||||||
|
|
||||||
### ✅ TypeContext (Step 1) - 完了
|
### ✅ TypeContext (Step 1) - 完了
|
||||||
|
|
||||||
@ -65,37 +65,66 @@ builder.rs の 1219 行を責任ごとに Context Box に分割し、保守性
|
|||||||
- builder 内 30+ ファイルで `block_gen.next()` を `next_block_id()` に自動置換
|
- builder 内 30+ ファイルで `block_gen.next()` を `next_block_id()` に自動置換
|
||||||
- 段階的移行により破壊的変更なし
|
- 段階的移行により破壊的変更なし
|
||||||
|
|
||||||
**コミット**: 81d79161
|
**コミット**: 81d79161, 89edf116
|
||||||
|
|
||||||
## 残りの Context (5/7)
|
### ✅ ScopeContext (Step 3) - 完了
|
||||||
|
|
||||||
### 3. ScopeContext (計画中)
|
**実装日**: 2025-12-15
|
||||||
- `lexical_scope_stack: Vec<LexicalScopeFrame>`
|
|
||||||
- `scope_stack: Vec<...>` (既存の control flow スタック)
|
**抽出したフィールド** (7個):
|
||||||
- `current_function: Option<MirFunction>`
|
- `lexical_scope_stack: Vec<LexicalScopeFrame>` - Block-scoped local 変数スコープ
|
||||||
|
- `loop_header_stack: Vec<BasicBlockId>` - ループヘッダースタック (break/continue 用)
|
||||||
|
- `loop_exit_stack: Vec<BasicBlockId>` - ループ出口スタック
|
||||||
|
- `if_merge_stack: Vec<BasicBlockId>` - If マージブロックスタック
|
||||||
|
- `current_function: Option<MirFunction>` - 現在ビルド中の関数
|
||||||
|
- `function_param_names: HashSet<String>` - 関数パラメータ名 (LoopForm PHI 用)
|
||||||
|
- `debug_scope_stack: Vec<String>` - デバッグリージョン識別子スタック
|
||||||
|
|
||||||
|
**ファイル**:
|
||||||
|
- `/home/tomoaki/git/hakorune-selfhost/src/mir/builder/scope_context.rs` (新規作成)
|
||||||
|
|
||||||
|
**統合方法**:
|
||||||
|
- `MirBuilder` に `scope_ctx: ScopeContext` フィールドを追加
|
||||||
|
- 既存フィールドは `#[deprecated]` でマーク(後方互換性維持)
|
||||||
|
- Lexical scope ヘルパー (`push_lexical_scope()`, `pop_lexical_scope()`, `declare_local_in_current_scope()`) が scope_ctx を SSOT として使用
|
||||||
|
- Control flow stack ヘルパー (`push_if_merge()`, `pop_if_merge()`) が両方を同期
|
||||||
|
- Debug scope ヘルパー (`debug_push_region()`, `debug_pop_region()`, `debug_current_region_id()`) を更新
|
||||||
|
- Function context は設定/復元時に両方を同期 (lifecycle.rs, calls/lowering.rs)
|
||||||
|
|
||||||
|
**テスト結果**:
|
||||||
|
- ✅ `cargo build --release` 成功 (291 warnings - deprecated フィールド使用)
|
||||||
|
- ✅ `cargo test --release --lib` - 1005/1009 PASS (4 tests 失敗は既存問題)
|
||||||
|
- ✅ `phase135_trim_mir_verify.sh` - PASS
|
||||||
|
- ⚠️ `phase132_exit_phi_parity.sh` - エラー (既存問題、ScopeContext 変更とは無関係)
|
||||||
|
|
||||||
|
**影響範囲**:
|
||||||
|
- `vars/lexical_scope.rs` - scope_ctx 使用に更新
|
||||||
|
- `lifecycle.rs` - current_function 設定/復元を scope_ctx 同期
|
||||||
|
- `calls/lowering.rs` - 関数 lowering の文脈管理を scope_ctx 同期
|
||||||
|
- 段階的移行により破壊的変更なし
|
||||||
|
|
||||||
|
**コミット**: [今回のコミット]
|
||||||
|
|
||||||
|
## 残りの Context (4/7)
|
||||||
|
|
||||||
### 4. BindingContext (計画中)
|
### 4. BindingContext (計画中)
|
||||||
- `bindings_stack: ...`
|
- `binding_map: BTreeMap<String, BindingId>` - 変数名 → BindingId マッピング
|
||||||
- `global_bindings: ...`
|
- `variable_map: BTreeMap<String, ValueId>` - 変数名 → ValueId マッピング (SSA)
|
||||||
- `next_binding_id: u32`
|
|
||||||
- `binding_map: BTreeMap<String, BindingId>`
|
|
||||||
|
|
||||||
### 5. ControlFlowContext (計画中)
|
### 5. MetadataContext (計画中)
|
||||||
- `current_basic_block: Option<BasicBlockId>`
|
- `hint_sink: HintSink` - ヒントシンク (zero-cost guidance)
|
||||||
- `pending_phis: Vec<...>`
|
- `current_span: Span` - 現在の AST スパン
|
||||||
- `loop_header_stack: Vec<BasicBlockId>`
|
- `source_file: Option<String>` - ソースファイルヒント
|
||||||
- `loop_exit_stack: Vec<BasicBlockId>`
|
- `current_region_stack: Vec<RegionId>` - Region 観測スタック
|
||||||
- `if_merge_stack: Vec<BasicBlockId>`
|
|
||||||
|
|
||||||
### 6. MetadataContext (計画中)
|
### 6. CompilationContext (計画中)
|
||||||
- `metadata: ...`
|
- `compilation_context: Option<BoxCompilationContext>` - Box コンパイルコンテキスト
|
||||||
- `loc_gen: ...`
|
- `current_static_box: Option<String>` - 現在の static box 名
|
||||||
- `source_map: ...`
|
- `user_defined_boxes: HashSet<String>` - ユーザー定義 Box 名
|
||||||
- `hint_sink: HintSink`
|
- `reserved_value_ids: HashSet<ValueId>` - 予約済み ValueId
|
||||||
|
|
||||||
### 7. ResourceContext (計画中)
|
### 7. ResourceContext (将来予定)
|
||||||
- `handle_registry: ...` (将来追加予定)
|
- リソース管理関連フィールド (将来追加)
|
||||||
- その他リソース管理関連
|
|
||||||
|
|
||||||
## 設計原則
|
## 設計原則
|
||||||
|
|
||||||
@ -106,10 +135,10 @@ builder.rs の 1219 行を責任ごとに Context Box に分割し、保守性
|
|||||||
|
|
||||||
## 次のステップ
|
## 次のステップ
|
||||||
|
|
||||||
**優先順位 3**: ScopeContext 抽出
|
**優先順位 4**: BindingContext 抽出
|
||||||
- スコープスタック管理の集約
|
- 変数バインディング管理の集約
|
||||||
- 制御フロースタック (loop/if/try) の統合
|
- variable_map と binding_map の統一管理
|
||||||
- 関数コンテキスト管理の整理
|
- SSA 変換との連携強化
|
||||||
|
|
||||||
## 参考資料
|
## 参考資料
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,7 @@ mod router; // RouterPolicyBox(Unified vs BoxCall)
|
|||||||
mod schedule; // BlockScheduleBox(物理順序: PHI→materialize→body)
|
mod schedule; // BlockScheduleBox(物理順序: PHI→materialize→body)
|
||||||
mod ssa; // LocalSSA helpers (in-block materialization)
|
mod ssa; // LocalSSA helpers (in-block materialization)
|
||||||
mod stmts;
|
mod stmts;
|
||||||
|
mod scope_context; // Phase 136 follow-up (Step 3/7): ScopeContext extraction
|
||||||
mod type_context; // Phase 136 follow-up: TypeContext extraction
|
mod type_context; // Phase 136 follow-up: TypeContext extraction
|
||||||
mod type_facts; // Phase 136 follow-up: Type inference facts box
|
mod type_facts; // Phase 136 follow-up: Type inference facts box
|
||||||
pub(crate) mod type_registry;
|
pub(crate) mod type_registry;
|
||||||
@ -73,7 +74,9 @@ pub struct MirBuilder {
|
|||||||
/// Current module being built
|
/// Current module being built
|
||||||
pub(super) current_module: Option<MirModule>,
|
pub(super) current_module: Option<MirModule>,
|
||||||
|
|
||||||
/// Current function being built
|
/// [DEPRECATED] Current function being built
|
||||||
|
/// Phase 136: Moved to scope_ctx.current_function (backward compat wrapper)
|
||||||
|
#[deprecated(note = "Use scope_ctx.current_function instead")]
|
||||||
pub(super) current_function: Option<MirFunction>,
|
pub(super) current_function: Option<MirFunction>,
|
||||||
|
|
||||||
/// Current basic block being built
|
/// Current basic block being built
|
||||||
@ -104,15 +107,20 @@ pub struct MirBuilder {
|
|||||||
/// Direct field access for backward compatibility (migration in progress).
|
/// Direct field access for backward compatibility (migration in progress).
|
||||||
pub(super) type_ctx: type_context::TypeContext,
|
pub(super) type_ctx: type_context::TypeContext,
|
||||||
|
|
||||||
|
/// Phase 136 follow-up (Step 3/7): Scope and control flow context
|
||||||
|
/// Consolidates lexical_scope_stack, loop stacks, if_merge_stack, current_function,
|
||||||
|
/// function_param_names, debug_scope_stack for better organization.
|
||||||
|
/// Direct field access for backward compatibility (migration in progress).
|
||||||
|
pub(super) scope_ctx: scope_context::ScopeContext,
|
||||||
|
|
||||||
/// Variable name to ValueId mapping (for SSA conversion)
|
/// Variable name to ValueId mapping (for SSA conversion)
|
||||||
/// 注意: compilation_contextがSomeの場合は使用されません
|
/// 注意: compilation_contextがSomeの場合は使用されません
|
||||||
/// Phase 25.1: HashMap → BTreeMap(PHI生成の決定性確保)
|
/// Phase 25.1: HashMap → BTreeMap(PHI生成の決定性確保)
|
||||||
pub(super) variable_map: BTreeMap<String, ValueId>,
|
pub(super) variable_map: BTreeMap<String, ValueId>,
|
||||||
|
|
||||||
/// Lexical scope stack for block-scoped `local` declarations.
|
/// [DEPRECATED] Lexical scope stack for block-scoped `local` declarations.
|
||||||
///
|
/// Phase 136: Moved to scope_ctx.lexical_scope_stack (backward compat wrapper)
|
||||||
/// This tracks per-block shadowing so `local x` inside `{...}` restores the
|
#[deprecated(note = "Use scope_ctx.lexical_scope_stack instead")]
|
||||||
/// outer binding when the block ends.
|
|
||||||
lexical_scope_stack: Vec<vars::lexical_scope::LexicalScopeFrame>,
|
lexical_scope_stack: Vec<vars::lexical_scope::LexicalScopeFrame>,
|
||||||
|
|
||||||
/// Pending phi functions to be inserted
|
/// Pending phi functions to be inserted
|
||||||
@ -172,8 +180,9 @@ pub struct MirBuilder {
|
|||||||
/// Index of static methods seen during lowering: name -> [(BoxName, arity)]
|
/// Index of static methods seen during lowering: name -> [(BoxName, arity)]
|
||||||
pub(super) static_method_index: std::collections::HashMap<String, Vec<(String, usize)>>,
|
pub(super) static_method_index: std::collections::HashMap<String, Vec<(String, usize)>>,
|
||||||
|
|
||||||
/// Function parameter names (for LoopForm PHI construction)
|
/// [DEPRECATED] Function parameter names (for LoopForm PHI construction)
|
||||||
/// Tracks the original parameter names at function entry
|
/// Phase 136: Moved to scope_ctx.function_param_names (backward compat wrapper)
|
||||||
|
#[deprecated(note = "Use scope_ctx.function_param_names instead")]
|
||||||
pub(super) function_param_names: HashSet<String>,
|
pub(super) function_param_names: HashSet<String>,
|
||||||
|
|
||||||
/// Fast lookup: method+arity tail → candidate function names (e.g., ".str/0" → ["JsonNode.str/0", ...])
|
/// Fast lookup: method+arity tail → candidate function names (e.g., ".str/0" → ["JsonNode.str/0", ...])
|
||||||
@ -209,14 +218,17 @@ pub struct MirBuilder {
|
|||||||
pub binding_map: BTreeMap<String, super::BindingId>,
|
pub binding_map: BTreeMap<String, super::BindingId>,
|
||||||
|
|
||||||
// include guards removed
|
// include guards removed
|
||||||
/// Loop context stacks for lowering break/continue inside nested control flow
|
/// [DEPRECATED] Loop context stacks for lowering break/continue inside nested control flow
|
||||||
/// Top of stack corresponds to the innermost active loop
|
/// Phase 136: Moved to scope_ctx.loop_header_stack (backward compat wrapper)
|
||||||
|
#[deprecated(note = "Use scope_ctx.loop_header_stack instead")]
|
||||||
pub(super) loop_header_stack: Vec<BasicBlockId>,
|
pub(super) loop_header_stack: Vec<BasicBlockId>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[deprecated(note = "Use scope_ctx.loop_exit_stack instead")]
|
||||||
pub(super) loop_exit_stack: Vec<BasicBlockId>,
|
pub(super) loop_exit_stack: Vec<BasicBlockId>,
|
||||||
|
|
||||||
/// If/merge context stack (innermost first). Used to make merge targets explicit
|
/// [DEPRECATED] If/merge context stack (innermost first)
|
||||||
/// when lowering nested conditionals and to simplify jump generation.
|
/// Phase 136: Moved to scope_ctx.if_merge_stack (backward compat wrapper)
|
||||||
|
#[deprecated(note = "Use scope_ctx.if_merge_stack instead")]
|
||||||
pub(super) if_merge_stack: Vec<BasicBlockId>,
|
pub(super) if_merge_stack: Vec<BasicBlockId>,
|
||||||
|
|
||||||
// フェーズM: no_phi_modeフィールド削除(常にPHI使用)
|
// フェーズM: no_phi_modeフィールド削除(常にPHI使用)
|
||||||
@ -250,7 +262,9 @@ pub struct MirBuilder {
|
|||||||
// ----------------------
|
// ----------------------
|
||||||
// Debug scope context (dev only; zero-cost when unused)
|
// Debug scope context (dev only; zero-cost when unused)
|
||||||
// ----------------------
|
// ----------------------
|
||||||
/// Stack of region identifiers like "loop#1/header" or "join#3/join".
|
/// [DEPRECATED] Stack of region identifiers like "loop#1/header" or "join#3/join".
|
||||||
|
/// Phase 136: Moved to scope_ctx.debug_scope_stack (backward compat wrapper)
|
||||||
|
#[deprecated(note = "Use scope_ctx.debug_scope_stack instead")]
|
||||||
debug_scope_stack: Vec<String>,
|
debug_scope_stack: Vec<String>,
|
||||||
/// [DEPRECATED] Monotonic counter for region IDs (deterministic across a run).
|
/// [DEPRECATED] Monotonic counter for region IDs (deterministic across a run).
|
||||||
/// Phase 136: Moved to core_ctx.debug_join_counter (backward compat wrapper)
|
/// Phase 136: Moved to core_ctx.debug_join_counter (backward compat wrapper)
|
||||||
@ -320,6 +334,7 @@ impl MirBuilder {
|
|||||||
|
|
||||||
compilation_context: None, // 箱理論: デフォルトは従来モード
|
compilation_context: None, // 箱理論: デフォルトは従来モード
|
||||||
type_ctx: type_context::TypeContext::new(), // Phase 136: Type context
|
type_ctx: type_context::TypeContext::new(), // Phase 136: Type context
|
||||||
|
scope_ctx: scope_context::ScopeContext::new(), // Phase 136 Step 3/7: Scope context
|
||||||
variable_map: BTreeMap::new(), // Phase 25.1: 決定性確保
|
variable_map: BTreeMap::new(), // Phase 25.1: 決定性確保
|
||||||
lexical_scope_stack: Vec::new(),
|
lexical_scope_stack: Vec::new(),
|
||||||
pending_phis: Vec::new(),
|
pending_phis: Vec::new(),
|
||||||
@ -396,11 +411,42 @@ impl MirBuilder {
|
|||||||
self.type_ctx.value_origin_newbox = self.value_origin_newbox.clone();
|
self.type_ctx.value_origin_newbox = self.value_origin_newbox.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Phase 136 Step 3/7: ScopeContext synchronization helpers ----
|
||||||
|
/// Sync scope_ctx changes back to legacy fields (backward compatibility)
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn sync_scope_ctx_to_legacy(&mut self) {
|
||||||
|
self.lexical_scope_stack = self.scope_ctx.lexical_scope_stack.clone();
|
||||||
|
self.loop_header_stack = self.scope_ctx.loop_header_stack.clone();
|
||||||
|
self.loop_exit_stack = self.scope_ctx.loop_exit_stack.clone();
|
||||||
|
self.if_merge_stack = self.scope_ctx.if_merge_stack.clone();
|
||||||
|
self.current_function = self.scope_ctx.current_function.clone();
|
||||||
|
self.function_param_names = self.scope_ctx.function_param_names.clone();
|
||||||
|
self.debug_scope_stack = self.scope_ctx.debug_scope_stack.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sync legacy field changes to scope_ctx (backward compatibility)
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn sync_legacy_to_scope_ctx(&mut self) {
|
||||||
|
self.scope_ctx.lexical_scope_stack = self.lexical_scope_stack.clone();
|
||||||
|
self.scope_ctx.loop_header_stack = self.loop_header_stack.clone();
|
||||||
|
self.scope_ctx.loop_exit_stack = self.loop_exit_stack.clone();
|
||||||
|
self.scope_ctx.if_merge_stack = self.if_merge_stack.clone();
|
||||||
|
self.scope_ctx.current_function = self.current_function.clone();
|
||||||
|
self.scope_ctx.function_param_names = self.function_param_names.clone();
|
||||||
|
self.scope_ctx.debug_scope_stack = self.debug_scope_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)]
|
||||||
pub(super) fn push_if_merge(&mut self, bb: BasicBlockId) {
|
pub(super) fn push_if_merge(&mut self, bb: BasicBlockId) {
|
||||||
|
// Phase 136 Step 3/7: Update both scope_ctx (SSOT) and legacy field (backward compat)
|
||||||
|
self.scope_ctx.push_if_merge(bb);
|
||||||
self.if_merge_stack.push(bb);
|
self.if_merge_stack.push(bb);
|
||||||
}
|
}
|
||||||
|
#[allow(deprecated)]
|
||||||
pub(super) fn pop_if_merge(&mut self) {
|
pub(super) fn pop_if_merge(&mut self) {
|
||||||
|
// Phase 136 Step 3/7: Update both scope_ctx (SSOT) and legacy field (backward compat)
|
||||||
|
let _ = self.scope_ctx.pop_if_merge();
|
||||||
let _ = self.if_merge_stack.pop();
|
let _ = self.if_merge_stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,18 +513,27 @@ impl MirBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub(crate) fn debug_push_region<S: Into<String>>(&mut self, region: S) {
|
pub(crate) fn debug_push_region<S: Into<String>>(&mut self, region: S) {
|
||||||
self.debug_scope_stack.push(region.into());
|
// Phase 136 Step 3/7: Update both scope_ctx (SSOT) and legacy field (backward compat)
|
||||||
|
let region = region.into();
|
||||||
|
self.scope_ctx.debug_push_region(region.clone());
|
||||||
|
self.debug_scope_stack.push(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub(crate) fn debug_pop_region(&mut self) {
|
pub(crate) fn debug_pop_region(&mut self) {
|
||||||
|
// Phase 136 Step 3/7: Update both scope_ctx (SSOT) and legacy field (backward compat)
|
||||||
|
self.scope_ctx.debug_pop_region();
|
||||||
let _ = self.debug_scope_stack.pop();
|
let _ = self.debug_scope_stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub(crate) fn debug_current_region_id(&self) -> Option<String> {
|
pub(crate) fn debug_current_region_id(&self) -> Option<String> {
|
||||||
self.debug_scope_stack.last().cloned()
|
// Phase 136 Step 3/7: Read from scope_ctx (SSOT)
|
||||||
|
self.scope_ctx.debug_current_region_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
|
|||||||
@ -79,8 +79,9 @@ impl MirBuilder {
|
|||||||
let entry = self.next_block_id();
|
let entry = self.next_block_id();
|
||||||
let function = self.new_function_with_metadata(signature, entry);
|
let function = self.new_function_with_metadata(signature, entry);
|
||||||
|
|
||||||
// 現在の関数・ブロックを保存
|
// Phase 136 Step 3/7: Save from scope_ctx (SSOT), sync to legacy field
|
||||||
ctx.saved_function = self.current_function.take();
|
ctx.saved_function = self.scope_ctx.current_function.take();
|
||||||
|
self.current_function = None;
|
||||||
ctx.saved_block = self.current_block.take();
|
ctx.saved_block = self.current_block.take();
|
||||||
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
@ -89,7 +90,8 @@ impl MirBuilder {
|
|||||||
);
|
);
|
||||||
eprintln!("[DEBUG/create_function_skeleton] Entry block: {:?}", entry);
|
eprintln!("[DEBUG/create_function_skeleton] Entry block: {:?}", entry);
|
||||||
|
|
||||||
// 新しい関数に切り替え
|
// Phase 136 Step 3/7: Update both scope_ctx (SSOT) and legacy field (backward compat)
|
||||||
|
self.scope_ctx.current_function = Some(function.clone());
|
||||||
self.current_function = Some(function);
|
self.current_function = Some(function);
|
||||||
self.current_block = Some(entry);
|
self.current_block = Some(entry);
|
||||||
// 新しい関数スコープ用の SlotRegistry を準備するよ(観測専用)
|
// 新しい関数スコープ用の SlotRegistry を準備するよ(観測専用)
|
||||||
@ -103,7 +105,10 @@ impl MirBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 🎯 箱理論: Step 3 - パラメータ設定
|
/// 🎯 箱理論: Step 3 - パラメータ設定
|
||||||
|
#[allow(deprecated)]
|
||||||
fn setup_function_params(&mut self, params: &[String]) {
|
fn setup_function_params(&mut self, params: &[String]) {
|
||||||
|
// Phase 136 Step 3/7: Clear both scope_ctx (SSOT) and legacy field (backward compat)
|
||||||
|
self.scope_ctx.function_param_names.clear();
|
||||||
self.function_param_names.clear();
|
self.function_param_names.clear();
|
||||||
// SlotRegistry 更新は borrow 競合を避けるため、まずローカルに集約してから反映するよ。
|
// SlotRegistry 更新は borrow 競合を避けるため、まずローカルに集約してから反映するよ。
|
||||||
let mut slot_regs: Vec<(String, Option<MirType>)> = Vec::new();
|
let mut slot_regs: Vec<(String, Option<MirType>)> = Vec::new();
|
||||||
@ -138,6 +143,8 @@ impl MirBuilder {
|
|||||||
new_pid
|
new_pid
|
||||||
};
|
};
|
||||||
self.variable_map.insert(p.clone(), pid);
|
self.variable_map.insert(p.clone(), pid);
|
||||||
|
// Phase 136 Step 3/7: Insert into both scope_ctx (SSOT) and legacy field
|
||||||
|
self.scope_ctx.function_param_names.insert(p.clone());
|
||||||
self.function_param_names.insert(p.clone());
|
self.function_param_names.insert(p.clone());
|
||||||
|
|
||||||
// Phase 26-A-3: パラメータ型情報を収集(後で一括登録)
|
// Phase 26-A-3: パラメータ型情報を収集(後で一括登録)
|
||||||
@ -172,6 +179,7 @@ impl MirBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 🎯 箱理論: Step 5 - 関数finalize
|
/// 🎯 箱理論: Step 5 - 関数finalize
|
||||||
|
#[allow(deprecated)]
|
||||||
fn finalize_function(&mut self, returns_value: bool) -> Result<(), String> {
|
fn finalize_function(&mut self, returns_value: bool) -> Result<(), String> {
|
||||||
// Void return追加(必要な場合)
|
// Void return追加(必要な場合)
|
||||||
if !returns_value {
|
if !returns_value {
|
||||||
@ -215,7 +223,9 @@ impl MirBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Moduleに追加
|
// Moduleに追加
|
||||||
|
// Phase 136 Step 3/7: Take from legacy field, sync to scope_ctx
|
||||||
let finalized = self.current_function.take().unwrap();
|
let finalized = self.current_function.take().unwrap();
|
||||||
|
self.scope_ctx.current_function = None;
|
||||||
if let Some(ref mut module) = self.current_module {
|
if let Some(ref mut module) = self.current_module {
|
||||||
module.add_function(finalized);
|
module.add_function(finalized);
|
||||||
}
|
}
|
||||||
@ -225,7 +235,8 @@ impl MirBuilder {
|
|||||||
|
|
||||||
/// 🎯 箱理論: Step 6 - Context復元
|
/// 🎯 箱理論: Step 6 - Context復元
|
||||||
fn restore_lowering_context(&mut self, ctx: LoweringContext) {
|
fn restore_lowering_context(&mut self, ctx: LoweringContext) {
|
||||||
// 関数・ブロック復元
|
// Phase 136 Step 3/7: Restore to scope_ctx (SSOT), sync to legacy field
|
||||||
|
self.scope_ctx.current_function = ctx.saved_function.clone();
|
||||||
self.current_function = ctx.saved_function;
|
self.current_function = ctx.saved_function;
|
||||||
self.current_block = ctx.saved_block;
|
self.current_block = ctx.saved_block;
|
||||||
|
|
||||||
@ -261,11 +272,13 @@ impl MirBuilder {
|
|||||||
let entry = self.next_block_id();
|
let entry = self.next_block_id();
|
||||||
let function = self.new_function_with_metadata(signature, entry);
|
let function = self.new_function_with_metadata(signature, entry);
|
||||||
|
|
||||||
// 現在の関数・ブロックを保存
|
// Phase 136 Step 3/7: Save from scope_ctx (SSOT), sync to legacy field
|
||||||
ctx.saved_function = self.current_function.take();
|
ctx.saved_function = self.scope_ctx.current_function.take();
|
||||||
|
self.current_function = None;
|
||||||
ctx.saved_block = self.current_block.take();
|
ctx.saved_block = self.current_block.take();
|
||||||
|
|
||||||
// 新しい関数に切り替え
|
// Phase 136 Step 3/7: Update both scope_ctx (SSOT) and legacy field (backward compat)
|
||||||
|
self.scope_ctx.current_function = Some(function.clone());
|
||||||
self.current_function = Some(function);
|
self.current_function = Some(function);
|
||||||
self.current_block = Some(entry);
|
self.current_block = Some(entry);
|
||||||
// instance method 用の関数スコープ SlotRegistry もここで用意するよ。
|
// instance method 用の関数スコープ SlotRegistry もここで用意するよ。
|
||||||
@ -464,7 +477,8 @@ impl MirBuilder {
|
|||||||
// FunctionRegion を 1 段ポップして元の関数コンテキストに戻るよ。
|
// FunctionRegion を 1 段ポップして元の関数コンテキストに戻るよ。
|
||||||
crate::mir::region::observer::pop_function_region(self);
|
crate::mir::region::observer::pop_function_region(self);
|
||||||
|
|
||||||
// Step 6: Context復元(simple version)
|
// Phase 136 Step 3/7: Restore to scope_ctx (SSOT), sync to legacy field
|
||||||
|
self.scope_ctx.current_function = ctx.saved_function.clone();
|
||||||
self.current_function = ctx.saved_function;
|
self.current_function = ctx.saved_function;
|
||||||
self.current_block = ctx.saved_block;
|
self.current_block = ctx.saved_block;
|
||||||
if let Some(saved) = ctx.saved_var_map {
|
if let Some(saved) = ctx.saved_var_map {
|
||||||
|
|||||||
@ -118,6 +118,8 @@ impl super::MirBuilder {
|
|||||||
main_function.metadata.is_entry_point = true;
|
main_function.metadata.is_entry_point = true;
|
||||||
|
|
||||||
self.current_module = Some(module);
|
self.current_module = Some(module);
|
||||||
|
// Phase 136 Step 3/7: Update both scope_ctx (SSOT) and legacy field (backward compat)
|
||||||
|
self.scope_ctx.current_function = Some(main_function.clone());
|
||||||
self.current_function = Some(main_function);
|
self.current_function = Some(main_function);
|
||||||
self.current_block = Some(entry_block);
|
self.current_block = Some(entry_block);
|
||||||
|
|
||||||
@ -306,7 +308,9 @@ impl super::MirBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut module = self.current_module.take().unwrap();
|
let mut module = self.current_module.take().unwrap();
|
||||||
|
// Phase 136 Step 3/7: Take from legacy field, sync to scope_ctx
|
||||||
let mut function = self.current_function.take().unwrap();
|
let mut function = self.current_function.take().unwrap();
|
||||||
|
self.scope_ctx.current_function = None;
|
||||||
// Phase 84-2: Copy命令型伝播(return型推論の前に実行)
|
// Phase 84-2: Copy命令型伝播(return型推論の前に実行)
|
||||||
//
|
//
|
||||||
// Loop exit や If merge の edge copy で発生する型欠如を解消する。
|
// Loop exit や If merge の edge copy で発生する型欠如を解消する。
|
||||||
|
|||||||
288
src/mir/builder/scope_context.rs
Normal file
288
src/mir/builder/scope_context.rs
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
//! ScopeContext - Lexical scope and control flow stack management
|
||||||
|
//!
|
||||||
|
//! Phase 136 Step 3/7: Extract scope-related state from MirBuilder
|
||||||
|
//!
|
||||||
|
//! # Responsibilities
|
||||||
|
//! - Lexical scope management (variable shadowing, block-scoped locals)
|
||||||
|
//! - Control flow stack management (loop header/exit, if merge)
|
||||||
|
//! - Function context management (current function, parameters)
|
||||||
|
//! - Debug scope tracking (region identifiers)
|
||||||
|
//!
|
||||||
|
//! # Design
|
||||||
|
//! - Encapsulates scope/control flow state for cleaner separation
|
||||||
|
//! - Provides type-safe push/pop operations
|
||||||
|
//! - Maintains deterministic iteration order (BTreeMap/BTreeSet)
|
||||||
|
|
||||||
|
use crate::mir::{BasicBlockId, MirFunction};
|
||||||
|
use std::collections::{BTreeMap, BTreeSet, HashSet};
|
||||||
|
|
||||||
|
pub(in crate::mir::builder) use super::vars::lexical_scope::LexicalScopeFrame;
|
||||||
|
|
||||||
|
/// Scope and control flow context for MIR building
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct ScopeContext {
|
||||||
|
// ---- Lexical scope management ----
|
||||||
|
/// Stack of lexical scopes for block-scoped `local` declarations
|
||||||
|
/// Tracks per-block shadowing so variables restore on scope exit
|
||||||
|
pub(super) lexical_scope_stack: Vec<LexicalScopeFrame>,
|
||||||
|
|
||||||
|
// ---- Control flow stacks ----
|
||||||
|
/// Stack of loop header blocks (innermost first)
|
||||||
|
/// Used for break/continue target resolution
|
||||||
|
pub(super) loop_header_stack: Vec<BasicBlockId>,
|
||||||
|
|
||||||
|
/// Stack of loop exit blocks (innermost first)
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(super) loop_exit_stack: Vec<BasicBlockId>,
|
||||||
|
|
||||||
|
/// Stack of if/merge blocks (innermost first)
|
||||||
|
/// Used for nested conditional lowering and jump generation
|
||||||
|
pub(super) if_merge_stack: Vec<BasicBlockId>,
|
||||||
|
|
||||||
|
// ---- Function context ----
|
||||||
|
/// Current function being built
|
||||||
|
pub(super) current_function: Option<MirFunction>,
|
||||||
|
|
||||||
|
/// Parameter names for current function
|
||||||
|
/// Same lifecycle as current_function
|
||||||
|
pub(super) function_param_names: HashSet<String>,
|
||||||
|
|
||||||
|
// ---- Debug scope ----
|
||||||
|
/// Stack of region identifiers (e.g., "loop#1/header", "join#3/join")
|
||||||
|
/// Zero-cost when unused (dev only)
|
||||||
|
pub(super) debug_scope_stack: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScopeContext {
|
||||||
|
/// Create new scope context (empty state)
|
||||||
|
pub(super) fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
lexical_scope_stack: Vec::new(),
|
||||||
|
loop_header_stack: Vec::new(),
|
||||||
|
loop_exit_stack: Vec::new(),
|
||||||
|
if_merge_stack: Vec::new(),
|
||||||
|
current_function: None,
|
||||||
|
function_param_names: HashSet::new(),
|
||||||
|
debug_scope_stack: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Lexical scope helpers ----
|
||||||
|
|
||||||
|
/// Push new lexical scope frame
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn push_lexical_scope(&mut self) {
|
||||||
|
self.lexical_scope_stack
|
||||||
|
.push(LexicalScopeFrame::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pop lexical scope frame (returns frame for restoration)
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn pop_lexical_scope(&mut self) -> Option<LexicalScopeFrame> {
|
||||||
|
self.lexical_scope_stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get mutable reference to current scope frame
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn current_scope_mut(&mut self) -> Option<&mut LexicalScopeFrame> {
|
||||||
|
self.lexical_scope_stack.last_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Control flow stack helpers ----
|
||||||
|
|
||||||
|
/// Push loop header block
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn push_loop_header(&mut self, bb: BasicBlockId) {
|
||||||
|
self.loop_header_stack.push(bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pop loop header block
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn pop_loop_header(&mut self) -> Option<BasicBlockId> {
|
||||||
|
self.loop_header_stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get innermost loop header
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn current_loop_header(&self) -> Option<BasicBlockId> {
|
||||||
|
self.loop_header_stack.last().copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Push loop exit block
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn push_loop_exit(&mut self, bb: BasicBlockId) {
|
||||||
|
self.loop_exit_stack.push(bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pop loop exit block
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn pop_loop_exit(&mut self) -> Option<BasicBlockId> {
|
||||||
|
self.loop_exit_stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Push if/merge block
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn push_if_merge(&mut self, bb: BasicBlockId) {
|
||||||
|
self.if_merge_stack.push(bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pop if/merge block
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn pop_if_merge(&mut self) -> Option<BasicBlockId> {
|
||||||
|
self.if_merge_stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Debug scope helpers ----
|
||||||
|
|
||||||
|
/// Push debug region identifier
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn debug_push_region<S: Into<String>>(&mut self, region: S) {
|
||||||
|
self.debug_scope_stack.push(region.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pop debug region identifier
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn debug_pop_region(&mut self) {
|
||||||
|
let _ = self.debug_scope_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get current debug region identifier
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn debug_current_region_id(&self) -> Option<String> {
|
||||||
|
self.debug_scope_stack.last().cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ScopeContext {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lexical_scope_stack() {
|
||||||
|
let mut ctx = ScopeContext::new();
|
||||||
|
|
||||||
|
// Initially empty
|
||||||
|
assert_eq!(ctx.lexical_scope_stack.len(), 0);
|
||||||
|
|
||||||
|
// Push scope
|
||||||
|
ctx.push_lexical_scope();
|
||||||
|
assert_eq!(ctx.lexical_scope_stack.len(), 1);
|
||||||
|
|
||||||
|
// Push another
|
||||||
|
ctx.push_lexical_scope();
|
||||||
|
assert_eq!(ctx.lexical_scope_stack.len(), 2);
|
||||||
|
|
||||||
|
// Pop scope
|
||||||
|
let frame = ctx.pop_lexical_scope();
|
||||||
|
assert!(frame.is_some());
|
||||||
|
assert_eq!(ctx.lexical_scope_stack.len(), 1);
|
||||||
|
|
||||||
|
// Pop last
|
||||||
|
let frame = ctx.pop_lexical_scope();
|
||||||
|
assert!(frame.is_some());
|
||||||
|
assert_eq!(ctx.lexical_scope_stack.len(), 0);
|
||||||
|
|
||||||
|
// Pop from empty
|
||||||
|
let frame = ctx.pop_lexical_scope();
|
||||||
|
assert!(frame.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_loop_stacks() {
|
||||||
|
let mut ctx = ScopeContext::new();
|
||||||
|
|
||||||
|
let header1 = BasicBlockId(1);
|
||||||
|
let header2 = BasicBlockId(2);
|
||||||
|
|
||||||
|
// Initially empty
|
||||||
|
assert!(ctx.current_loop_header().is_none());
|
||||||
|
|
||||||
|
// Push first loop
|
||||||
|
ctx.push_loop_header(header1);
|
||||||
|
assert_eq!(ctx.current_loop_header(), Some(header1));
|
||||||
|
|
||||||
|
// Push nested loop (innermost)
|
||||||
|
ctx.push_loop_header(header2);
|
||||||
|
assert_eq!(ctx.current_loop_header(), Some(header2));
|
||||||
|
|
||||||
|
// Pop innermost
|
||||||
|
assert_eq!(ctx.pop_loop_header(), Some(header2));
|
||||||
|
assert_eq!(ctx.current_loop_header(), Some(header1));
|
||||||
|
|
||||||
|
// Pop outermost
|
||||||
|
assert_eq!(ctx.pop_loop_header(), Some(header1));
|
||||||
|
assert!(ctx.current_loop_header().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_if_merge_stack() {
|
||||||
|
let mut ctx = ScopeContext::new();
|
||||||
|
|
||||||
|
let merge1 = BasicBlockId(10);
|
||||||
|
let merge2 = BasicBlockId(20);
|
||||||
|
|
||||||
|
// Push merge blocks
|
||||||
|
ctx.push_if_merge(merge1);
|
||||||
|
ctx.push_if_merge(merge2);
|
||||||
|
|
||||||
|
// Pop in LIFO order
|
||||||
|
assert_eq!(ctx.pop_if_merge(), Some(merge2));
|
||||||
|
assert_eq!(ctx.pop_if_merge(), Some(merge1));
|
||||||
|
assert_eq!(ctx.pop_if_merge(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_debug_scope_stack() {
|
||||||
|
let mut ctx = ScopeContext::new();
|
||||||
|
|
||||||
|
// Initially empty
|
||||||
|
assert!(ctx.debug_current_region_id().is_none());
|
||||||
|
|
||||||
|
// Push region
|
||||||
|
ctx.debug_push_region("loop#1/header");
|
||||||
|
assert_eq!(
|
||||||
|
ctx.debug_current_region_id(),
|
||||||
|
Some("loop#1/header".to_string())
|
||||||
|
);
|
||||||
|
|
||||||
|
// Push nested region
|
||||||
|
ctx.debug_push_region("join#3/join");
|
||||||
|
assert_eq!(
|
||||||
|
ctx.debug_current_region_id(),
|
||||||
|
Some("join#3/join".to_string())
|
||||||
|
);
|
||||||
|
|
||||||
|
// Pop
|
||||||
|
ctx.debug_pop_region();
|
||||||
|
assert_eq!(
|
||||||
|
ctx.debug_current_region_id(),
|
||||||
|
Some("loop#1/header".to_string())
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.debug_pop_region();
|
||||||
|
assert!(ctx.debug_current_region_id().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_function_context() {
|
||||||
|
let mut ctx = ScopeContext::new();
|
||||||
|
|
||||||
|
// Initially no function
|
||||||
|
assert!(ctx.current_function.is_none());
|
||||||
|
assert!(ctx.function_param_names.is_empty());
|
||||||
|
|
||||||
|
// Simulate setting function context
|
||||||
|
ctx.function_param_names.insert("x".to_string());
|
||||||
|
ctx.function_param_names.insert("y".to_string());
|
||||||
|
|
||||||
|
assert_eq!(ctx.function_param_names.len(), 2);
|
||||||
|
assert!(ctx.function_param_names.contains("x"));
|
||||||
|
assert!(ctx.function_param_names.contains("y"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +1,12 @@
|
|||||||
use crate::mir::{BindingId, ValueId};
|
use crate::mir::{BindingId, ValueId};
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub(in crate::mir::builder) struct LexicalScopeFrame {
|
pub(in crate::mir::builder) struct LexicalScopeFrame {
|
||||||
declared: BTreeSet<String>,
|
pub(in crate::mir::builder) declared: BTreeSet<String>,
|
||||||
restore: BTreeMap<String, Option<ValueId>>,
|
pub(in crate::mir::builder) restore: BTreeMap<String, Option<ValueId>>,
|
||||||
/// Phase 74: Parallel BindingId restoration on scope exit
|
/// Phase 74: Parallel BindingId restoration on scope exit
|
||||||
restore_binding: BTreeMap<String, Option<BindingId>>,
|
pub(in crate::mir::builder) restore_binding: BTreeMap<String, Option<BindingId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LexicalScopeFrame {
|
impl LexicalScopeFrame {
|
||||||
@ -35,15 +35,26 @@ impl Drop for LexicalScopeGuard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl super::super::MirBuilder {
|
impl super::super::MirBuilder {
|
||||||
|
#[allow(deprecated)]
|
||||||
pub(in crate::mir::builder) fn push_lexical_scope(&mut self) {
|
pub(in crate::mir::builder) fn push_lexical_scope(&mut self) {
|
||||||
|
// Phase 136 Step 3/7: Update both scope_ctx (SSOT) and legacy field (backward compat)
|
||||||
|
self.scope_ctx.push_lexical_scope();
|
||||||
self.lexical_scope_stack.push(LexicalScopeFrame::new());
|
self.lexical_scope_stack.push(LexicalScopeFrame::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
pub(in crate::mir::builder) fn pop_lexical_scope(&mut self) {
|
pub(in crate::mir::builder) fn pop_lexical_scope(&mut self) {
|
||||||
|
// Phase 136 Step 3/7: Pop from scope_ctx (SSOT)
|
||||||
let frame = self
|
let frame = self
|
||||||
|
.scope_ctx
|
||||||
|
.pop_lexical_scope()
|
||||||
|
.expect("COMPILER BUG: pop_lexical_scope without push_lexical_scope");
|
||||||
|
|
||||||
|
// Sync to legacy field
|
||||||
|
let _ = self
|
||||||
.lexical_scope_stack
|
.lexical_scope_stack
|
||||||
.pop()
|
.pop()
|
||||||
.expect("COMPILER BUG: pop_lexical_scope without push_lexical_scope");
|
.expect("COMPILER BUG: legacy stack out of sync");
|
||||||
|
|
||||||
// Restore ValueId mappings
|
// Restore ValueId mappings
|
||||||
for (name, previous) in frame.restore {
|
for (name, previous) in frame.restore {
|
||||||
@ -70,12 +81,14 @@ impl super::super::MirBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
pub(in crate::mir::builder) fn declare_local_in_current_scope(
|
pub(in crate::mir::builder) fn declare_local_in_current_scope(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
value: ValueId,
|
value: ValueId,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let Some(frame) = self.lexical_scope_stack.last_mut() else {
|
// Phase 136 Step 3/7: Use scope_ctx (SSOT)
|
||||||
|
let Some(frame) = self.scope_ctx.current_scope_mut() else {
|
||||||
return Err("COMPILER BUG: local declaration outside lexical scope".to_string());
|
return Err("COMPILER BUG: local declaration outside lexical scope".to_string());
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -98,6 +111,9 @@ impl super::super::MirBuilder {
|
|||||||
let binding_id = self.allocate_binding_id();
|
let binding_id = self.allocate_binding_id();
|
||||||
self.binding_map.insert(name.to_string(), binding_id);
|
self.binding_map.insert(name.to_string(), binding_id);
|
||||||
|
|
||||||
|
// Sync to legacy field
|
||||||
|
self.sync_scope_ctx_to_legacy();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user