Files
hakorune/src/mir/builder/metadata_context.rs
nyash-codex 903ab8ef4c 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>
2025-12-15 22:03:34 +09:00

184 lines
5.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* 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 スタックに pushNYASH_REGION_TRACE=1 専用)
#[inline]
pub(crate) fn push_region(&mut self, region_id: RegionId) {
self.current_region_stack.push(region_id);
}
/// Region スタックから popNYASH_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");
}
}