From da1a5558e55519f2f7bb07d2a2fe112f3419f23c Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Mon, 24 Nov 2025 15:02:51 +0900 Subject: [PATCH] Normalize passes keep spans and clean warnings --- src/backend/mir_interpreter/exec.rs | 9 +- src/mir/basic_block.rs | 55 ++- src/mir/builder/exprs_peek.rs | 8 +- src/mir/builder/phi.rs | 8 +- src/mir/builder/phi_merge.rs | 1 - src/mir/builder/stmts.rs | 2 + src/mir/join_ir/lowering/min_loop.rs | 1 - .../join_ir/lowering/stage1_using_resolver.rs | 1 - src/mir/join_ir/mod.rs | 2 +- src/mir/join_ir_vm_bridge.rs | 1 - src/mir/loop_api.rs | 19 +- src/mir/loop_builder.rs | 10 +- src/mir/mod.rs | 10 +- src/mir/optimizer.rs | 4 +- src/mir/optimizer_passes/normalize.rs | 393 +++++++++--------- .../optimizer_passes/normalize_core13_pure.rs | 152 ++++--- src/mir/passes/escape.rs | 8 +- src/mir/printer.rs | 18 +- src/mir/query.rs | 1 - src/mir/spanned_instruction.rs | 9 +- src/mir/ssot/cf_common.rs | 21 +- src/mir/utils/phi_helpers.rs | 16 +- src/mir/value_kind.rs | 1 - src/mir/verification.rs | 11 +- src/mir/verification/barrier.rs | 19 +- src/mir/verification/cfg.rs | 10 +- src/mir/verification/dom.rs | 6 +- src/mir/verification/legacy.rs | 4 +- src/mir/verification/ssa.rs | 10 +- src/mir/verification/utils.rs | 8 +- src/runner/json_v0_bridge/lowering/expr.rs | 9 +- src/runner/json_v0_bridge/lowering/loop_.rs | 13 +- .../json_v0_bridge/lowering/match_expr.rs | 9 +- src/runner/json_v0_bridge/lowering/merge.rs | 4 +- src/runner/json_v0_bridge/lowering/ternary.rs | 9 +- .../json_v0_bridge/lowering/try_catch.rs | 41 +- src/runner/modes/common_util/diag.rs | 2 - .../common_util/resolve/prelude_manager.rs | 1 + src/runner/modes/common_util/resolve/strip.rs | 1 + src/runner/stage1_bridge/mod.rs | 2 +- 40 files changed, 547 insertions(+), 362 deletions(-) diff --git a/src/backend/mir_interpreter/exec.rs b/src/backend/mir_interpreter/exec.rs index 563820e2..8b130dc6 100644 --- a/src/backend/mir_interpreter/exec.rs +++ b/src/backend/mir_interpreter/exec.rs @@ -148,9 +148,9 @@ impl MirInterpreter { ) -> Option { let idx = inst_index?; if idx < block.instructions.len() { - block.instruction_span(idx) + block.instruction_with_span(idx).map(|sp| sp.span) } else if idx == block.instructions.len() { - block.terminator_span() + block.terminator_spanned().map(|sp| sp.span) } else { None } @@ -334,9 +334,10 @@ impl MirInterpreter { fn execute_block_instructions(&mut self, block: &BasicBlock) -> Result<(), VMError> { let phi_count = block.phi_instructions().count(); - for (idx, inst) in block.non_phi_instructions().enumerate() { + for (idx, sp) in block.iter_spanned_enumerated().skip(phi_count) { + let inst = sp.inst; self.last_block = Some(block.id); - self.last_inst_index = Some(phi_count + idx); + self.last_inst_index = Some(idx); self.last_inst = Some(inst.clone()); if Self::trace_enabled() { eprintln!("[vm-trace] inst bb={:?} {:?}", block.id, inst); diff --git a/src/mir/basic_block.rs b/src/mir/basic_block.rs index 9146e047..72c5fb80 100644 --- a/src/mir/basic_block.rs +++ b/src/mir/basic_block.rs @@ -4,7 +4,7 @@ * SSA-form basic blocks with phi functions and terminator instructions */ -use super::{EffectMask, MirInstruction, SpannedInstruction, ValueId}; +use super::{EffectMask, MirInstruction, SpannedInstRef, SpannedInstruction, ValueId}; use crate::ast::Span; use std::collections::HashSet; use std::fmt; @@ -239,11 +239,64 @@ impl BasicBlock { self.instruction_spans.get(idx).copied() } + /// Get instruction with span by index. + pub fn instruction_with_span(&self, idx: usize) -> Option> { + self.instructions + .get(idx) + .zip(self.instruction_spans.get(idx)) + .map(|(inst, span)| SpannedInstRef { + inst, + span: *span, + }) + } + /// Get span for terminator instruction pub fn terminator_span(&self) -> Option { self.terminator_span } + /// Get terminator together with its span. + pub fn terminator_spanned(&self) -> Option> { + self.terminator.as_ref().map(|inst| SpannedInstRef { + inst, + span: self.terminator_span.unwrap_or_else(Span::unknown), + }) + } + + /// Iterate instructions with their spans. + pub fn iter_spanned(&self) -> impl Iterator> { + self.instructions + .iter() + .zip(self.instruction_spans.iter()) + .map(|(inst, span)| SpannedInstRef { + inst, + span: *span, + }) + } + + /// Iterate instructions with index and span. + pub fn iter_spanned_enumerated( + &self, + ) -> impl Iterator)> { + self.iter_spanned() + .enumerate() + .map(|(idx, sp)| (idx, sp)) + } + + /// Iterate all instructions (including terminator) with spans. + pub fn all_spanned_instructions(&self) -> impl Iterator> { + self.iter_spanned() + .chain(self.terminator_spanned().into_iter()) + } + + /// Iterate all instructions (including terminator) with index and span. + /// Non-phi + phi + terminator share the same indexing as `all_instructions()`. + pub fn all_spanned_instructions_enumerated( + &self, + ) -> impl Iterator)> { + self.all_spanned_instructions().enumerate() + } + /// Insert instruction at the beginning (after phi instructions) pub fn insert_instruction_after_phis(&mut self, instruction: MirInstruction) { let phi_count = self.phi_instructions().count(); diff --git a/src/mir/builder/exprs_peek.rs b/src/mir/builder/exprs_peek.rs index 9bf654e0..5ee694c8 100644 --- a/src/mir/builder/exprs_peek.rs +++ b/src/mir/builder/exprs_peek.rs @@ -119,7 +119,13 @@ impl super::MirBuilder { self.start_new_block(merge_block)?; // フェーズM: PHI はブロック先頭に配置(cf_common 統一) if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { - crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, result_val, phi_inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + func, + cur_bb, + result_val, + phi_inputs, + self.current_span, + ); } else { self.emit_instruction(super::MirInstruction::Phi { dst: result_val, diff --git a/src/mir/builder/phi.rs b/src/mir/builder/phi.rs index 313754cb..cd9212f3 100644 --- a/src/mir/builder/phi.rs +++ b/src/mir/builder/phi.rs @@ -83,8 +83,12 @@ impl MirBuilder { if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { - crate::mir::ssot::cf_common::insert_phi_at_head( - func, cur_bb, merged, inputs, + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + func, + cur_bb, + merged, + inputs, + self.current_span, ); } else { self.emit_instruction(MirInstruction::Phi { diff --git a/src/mir/builder/phi_merge.rs b/src/mir/builder/phi_merge.rs index 61f7fc57..72bc5c7b 100644 --- a/src/mir/builder/phi_merge.rs +++ b/src/mir/builder/phi_merge.rs @@ -7,7 +7,6 @@ //! Box-First理論: PHI insertion の境界を明確にし、差し替え可能な箱として提供 use super::{BasicBlockId, MirBuilder, ValueId}; -use crate::mir::MirInstruction; use std::collections::BTreeMap; // Phase 25.1: 決定性確保 /// PHI Merge Helper - 統一PHI挿入ロジック(Conservative戦略) diff --git a/src/mir/builder/stmts.rs b/src/mir/builder/stmts.rs index 11255141..2641a118 100644 --- a/src/mir/builder/stmts.rs +++ b/src/mir/builder/stmts.rs @@ -213,6 +213,8 @@ impl super::MirBuilder { /// - While/ForRange は将来 Loop lowering へ委譲する拡張ポイントとして扱い、 /// 現状は他の専用ビルダ/既存パスと同様に build_expression に委譲する。 pub(super) fn build_statement(&mut self, node: ASTNode) -> Result { + // Align current_span to this statement node before lowering expressions under it. + self.current_span = node.span(); match node { // 将来ここに While / ForRange / Match / Using など statement 専用分岐を追加する。 other => self.build_expression(other), diff --git a/src/mir/join_ir/lowering/min_loop.rs b/src/mir/join_ir/lowering/min_loop.rs index 8e0034ef..8d51724b 100644 --- a/src/mir/join_ir/lowering/min_loop.rs +++ b/src/mir/join_ir/lowering/min_loop.rs @@ -54,7 +54,6 @@ pub fn lower_min_loop_to_joinir(module: &crate::mir::MirModule) -> Option, ) -> Result<(), String> { if let Some(ref mut f) = self.current_function { - if let Some(bb) = f.get_block_mut(block) { - let inst = MirInstruction::Phi { dst, inputs }; - // Update effect mask and insert at the very start - bb.effects = bb.effects | inst.effects(); - bb.instructions.insert(0, inst); - bb.instruction_spans - .insert(0, self.current_span); - Ok(()) - } else { - Err(format!("Block {} not found", block.as_u32())) - } + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + f, + block, + dst, + inputs, + self.current_span, + ); + Ok(()) } else { Err("No current function".into()) } diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index 4b9f70ef..21f1362a 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -23,7 +23,6 @@ use super::{BasicBlockId, ConstValue, MirInstruction, ValueId}; use crate::ast::ASTNode; use crate::mir::control_form::{is_control_form_trace_on, ControlForm, IfShape, LoopShape}; -use crate::mir::phi_core::loop_snapshot_merge::LoopSnapshotMergeBox; use crate::mir::phi_core::loopform_builder::{LoopFormBuilder, LoopFormOps}; use crate::mir::phi_core::phi_input_collector::PhiInputCollector; use std::collections::{BTreeMap, BTreeSet}; // Phase 25.1: 決定性確保 @@ -1049,7 +1048,7 @@ impl<'a> LoopBuilder<'a> { } let then_var_map_end = self.get_current_variable_map(); // フェーズS修正:最強モード指摘の「実到達predecessor捕捉」を統一 - let then_pred_to_merge = + let _then_pred_to_merge = capture_actual_predecessor_and_jump(self.parent_builder, merge_bb)?; // Pop then-branch debug region self.parent_builder.debug_pop_region(); @@ -1093,7 +1092,7 @@ impl<'a> LoopBuilder<'a> { else_var_map_end_opt = Some(self.get_current_variable_map()); } // フェーズS修正:else branchでも統一実到達predecessor捕捉 - let else_pred_to_merge = + let _else_pred_to_merge = capture_actual_predecessor_and_jump(self.parent_builder, merge_bb)?; // Pop else-branch debug region self.parent_builder.debug_pop_region(); @@ -1315,7 +1314,10 @@ impl crate::mir::phi_core::loop_phi::LoopPhiOps for LoopBuilder<'_> { preheader_id ); } - block.add_instruction(MirInstruction::Copy { dst, src }); + block.add_instruction_with_span( + MirInstruction::Copy { dst, src }, + self.parent_builder.current_span, + ); Ok(()) } else { if dbg { diff --git a/src/mir/mod.rs b/src/mir/mod.rs index 59bd9a09..65ea624f 100644 --- a/src/mir/mod.rs +++ b/src/mir/mod.rs @@ -56,7 +56,7 @@ pub use instruction::MirInstruction; pub use join_ir_runner::{run_joinir_function, JoinRuntimeError, JoinValue}; pub use optimizer::MirOptimizer; pub use printer::MirPrinter; -pub use spanned_instruction::SpannedInstruction; +pub use spanned_instruction::{SpannedInstRef, SpannedInstruction}; pub use query::{MirQuery, MirQueryBox}; pub use slot_registry::{BoxTypeId, MethodSlot}; pub use types::{ @@ -229,8 +229,8 @@ mod tests { // Ensure TypeOp exists in the resulting MIR let has_typeop = result.module.functions.values().any(|f| { f.blocks.values().any(|b| { - b.all_instructions() - .any(|i| matches!(i, MirInstruction::TypeOp { .. })) + b.all_spanned_instructions() + .any(|sp| matches!(sp.inst, MirInstruction::TypeOp { .. })) }) }); assert!( @@ -264,8 +264,8 @@ mod tests { // Ensure TypeOp exists in the resulting MIR let has_typeop = result.module.functions.values().any(|f| { f.blocks.values().any(|b| { - b.all_instructions() - .any(|i| matches!(i, MirInstruction::TypeOp { .. })) + b.all_spanned_instructions() + .any(|sp| matches!(sp.inst, MirInstruction::TypeOp { .. })) }) }); assert!( diff --git a/src/mir/optimizer.rs b/src/mir/optimizer.rs index 208e682a..9aeb9315 100644 --- a/src/mir/optimizer.rs +++ b/src/mir/optimizer.rs @@ -508,8 +508,8 @@ mod tests { let f = module.get_function("main").unwrap(); let block = f.get_block(bb0).unwrap(); let has_typeop = block - .all_instructions() - .any(|i| matches!(i, MirInstruction::TypeOp { .. })); + .all_spanned_instructions() + .any(|sp| matches!(sp.inst, MirInstruction::TypeOp { .. })); assert!( has_typeop, "TypeOp should not be dropped by DCE when used by console.log (ExternCall)" diff --git a/src/mir/optimizer_passes/normalize.rs b/src/mir/optimizer_passes/normalize.rs index e5ee471f..ba955f0d 100644 --- a/src/mir/optimizer_passes/normalize.rs +++ b/src/mir/optimizer_passes/normalize.rs @@ -1,7 +1,9 @@ -use crate::ast::Span; use crate::mir::optimizer::MirOptimizer; use crate::mir::optimizer_stats::OptimizationStats; -use crate::mir::{BarrierOp, MirModule, SpannedInstruction, TypeOpKind, ValueId, WeakRefOp}; +use crate::mir::{ + BarrierOp, EffectMask, MirModule, SpannedInstruction, TypeOpKind, ValueId, WeakRefOp, +}; +use crate::ast::Span; fn idemp_enabled() -> bool { std::env::var("NYASH_MIR_DEV_IDEMP").ok().as_deref() == Some("1") @@ -36,26 +38,46 @@ pub fn force_plugin_invoke(_opt: &mut MirOptimizer, module: &mut MirModule) -> O None => continue, }; for (_bb, block) in &mut function.blocks { - for inst in &mut block.instructions { - if let I::BoxCall { - dst, - box_val, - method, - args, - effects, - .. - } = inst.clone() - { - *inst = I::PluginInvoke { + let old_spanned = block.drain_spanned_instructions(); + let mut new_spanned = Vec::with_capacity(old_spanned.len()); + for SpannedInstruction { inst, span } in old_spanned { + let rewritten = match inst { + I::BoxCall { dst, box_val, method, args, effects, - }; - stats.intrinsic_optimizations += 1; - } + .. + } => { + stats.intrinsic_optimizations += 1; + I::PluginInvoke { + dst, + box_val, + method, + args, + effects, + } + } + other => other, + }; + new_spanned.push(SpannedInstruction { + inst: rewritten, + span, + }); } + + let (insts, spans): (Vec<_>, Vec<_>) = new_spanned + .into_iter() + .map(|sp| (sp.inst, sp.span)) + .unzip(); + block.instructions = insts; + block.instruction_spans = spans; + block.effects = block + .instructions + .iter() + .chain(block.terminator.iter()) + .fold(EffectMask::PURE, |mask, inst| mask | inst.effects()); } if idemp_enabled() { let key = idemp_key(pass_name, &fname); @@ -85,11 +107,13 @@ pub fn normalize_python_helper_calls( None => continue, }; for (_bb, block) in &mut function.blocks { - for inst in &mut block.instructions { + let old_spanned = block.drain_spanned_instructions(); + let mut new_spanned = Vec::with_capacity(old_spanned.len()); + for SpannedInstruction { mut inst, span } in old_spanned { if let I::PluginInvoke { - box_val, - method, - args, + ref mut box_val, + ref method, + ref mut args, .. } = inst { @@ -105,7 +129,20 @@ pub fn normalize_python_helper_calls( stats.intrinsic_optimizations += 1; } } + new_spanned.push(SpannedInstruction { inst, span }); } + + let (insts, spans): (Vec<_>, Vec<_>) = new_spanned + .into_iter() + .map(|sp| (sp.inst, sp.span)) + .unzip(); + block.instructions = insts; + block.instruction_spans = spans; + block.effects = block + .instructions + .iter() + .chain(block.terminator.iter()) + .fold(EffectMask::PURE, |mask, inst| mask | inst.effects()); } if idemp_enabled() { let key = idemp_key(pass_name, &fname); @@ -143,90 +180,79 @@ pub fn normalize_legacy_instructions( None => continue, }; for (_bb, block) in &mut function.blocks { - for inst in &mut block.instructions { - match inst { + let old_spanned = block.drain_spanned_instructions(); + let mut new_spanned = Vec::with_capacity(old_spanned.len()); + for SpannedInstruction { inst, span } in old_spanned { + let rewritten = match inst { I::WeakNew { dst, box_val } => { - let d = *dst; - let v = *box_val; - *inst = I::WeakRef { - dst: d, - op: WeakRefOp::New, - value: v, - }; stats.intrinsic_optimizations += 1; + I::WeakRef { + dst, + op: WeakRefOp::New, + value: box_val, + } } I::WeakLoad { dst, weak_ref } => { - let d = *dst; - let v = *weak_ref; - *inst = I::WeakRef { - dst: d, - op: WeakRefOp::Load, - value: v, - }; stats.intrinsic_optimizations += 1; + I::WeakRef { + dst, + op: WeakRefOp::Load, + value: weak_ref, + } } I::BarrierRead { ptr } => { - let p = *ptr; - *inst = I::Barrier { - op: BarrierOp::Read, - ptr: p, - }; stats.intrinsic_optimizations += 1; + I::Barrier { + op: BarrierOp::Read, + ptr, + } } I::BarrierWrite { ptr } => { - let p = *ptr; - *inst = I::Barrier { - op: BarrierOp::Write, - ptr: p, - }; stats.intrinsic_optimizations += 1; + I::Barrier { + op: BarrierOp::Write, + ptr, + } } I::Print { value, .. } => { - let v = *value; - *inst = I::ExternCall { + stats.intrinsic_optimizations += 1; + I::ExternCall { dst: None, iface_name: "env.console".to_string(), method_name: "log".to_string(), - args: vec![v], + args: vec![value], effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io), - }; - stats.intrinsic_optimizations += 1; + } } I::ArrayGet { dst, array, index } if array_to_boxcall => { - let d = *dst; - let a = *array; - let i = *index; + stats.intrinsic_optimizations += 1; let mid = crate::mir::slot_registry::resolve_slot_by_type_name("ArrayBox", "get"); - *inst = I::BoxCall { - dst: Some(d), - box_val: a, + I::BoxCall { + dst: Some(dst), + box_val: array, method: "get".to_string(), method_id: mid, - args: vec![i], + args: vec![index], effects: crate::mir::EffectMask::READ, - }; - stats.intrinsic_optimizations += 1; + } } I::ArraySet { array, index, value, } if array_to_boxcall => { - let a = *array; - let i = *index; - let v = *value; + stats.intrinsic_optimizations += 1; let mid = crate::mir::slot_registry::resolve_slot_by_type_name("ArrayBox", "set"); - *inst = I::BoxCall { + I::BoxCall { dst: None, - box_val: a, + box_val: array, method: "set".to_string(), method_id: mid, - args: vec![i, v], + args: vec![index, value], effects: crate::mir::EffectMask::WRITE, - }; - stats.intrinsic_optimizations += 1; + } } I::PluginInvoke { dst, @@ -235,176 +261,163 @@ pub fn normalize_legacy_instructions( args, effects, } => { - let d = *dst; - let recv = *box_val; - let m = method.clone(); - let as_ = args.clone(); - let eff = *effects; - *inst = I::BoxCall { - dst: d, - box_val: recv, - method: m, - method_id: None, - args: as_, - effects: eff, - }; stats.intrinsic_optimizations += 1; + I::BoxCall { + dst, + box_val, + method, + method_id: None, + args, + effects, + } } - I::Debug { .. } if !rw_dbg => { - *inst = I::Nop; - } - I::Safepoint if !rw_sp => { - *inst = I::Nop; - } - I::FutureNew { dst, value } if rw_future => { - let d = *dst; - let v = *value; - *inst = I::ExternCall { - dst: Some(d), - iface_name: "env.future".to_string(), - method_name: "new".to_string(), - args: vec![v], - effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io), - }; - } - I::FutureSet { future, value } if rw_future => { - let f = *future; - let v = *value; - *inst = I::ExternCall { - dst: None, - iface_name: "env.future".to_string(), - method_name: "set".to_string(), - args: vec![f, v], - effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io), - }; - } - I::Await { dst, future } if rw_future => { - let d = *dst; - let f = *future; - *inst = I::ExternCall { - dst: Some(d), - iface_name: "env.future".to_string(), - method_name: "await".to_string(), - args: vec![f], - effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io), - }; - } - _ => {} - } + I::Debug { .. } if !rw_dbg => I::Nop, + I::Safepoint if !rw_sp => I::Nop, + I::FutureNew { dst, value } if rw_future => I::ExternCall { + dst: Some(dst), + iface_name: "env.future".to_string(), + method_name: "new".to_string(), + args: vec![value], + effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io), + }, + I::FutureSet { future, value } if rw_future => I::ExternCall { + dst: None, + iface_name: "env.future".to_string(), + method_name: "set".to_string(), + args: vec![future, value], + effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io), + }, + I::Await { dst, future } if rw_future => I::ExternCall { + dst: Some(dst), + iface_name: "env.future".to_string(), + method_name: "await".to_string(), + args: vec![future], + effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io), + }, + other => other, + }; + new_spanned.push(SpannedInstruction { + inst: rewritten, + span, + }); } - // terminator rewrite (subset migrated as needed) - if let Some(term) = &mut block.terminator { - match term { + + let terminator = block.terminator.take(); + let terminator_span = block.terminator_span.take(); + if let Some(term) = terminator { + let span = terminator_span.unwrap_or_else(Span::unknown); + let rewritten = match term { I::TypeCheck { dst, value, expected_type, } => { - let ty = crate::mir::MirType::Box(expected_type.clone()); - *term = I::TypeOp { - dst: *dst, - op: TypeOpKind::Check, - value: *value, - ty, - }; + let ty = crate::mir::MirType::Box(expected_type); stats.intrinsic_optimizations += 1; + I::TypeOp { + dst, + op: TypeOpKind::Check, + value, + ty, + } } I::Cast { dst, value, target_type, } => { - let ty = target_type.clone(); - *term = I::TypeOp { - dst: *dst, - op: TypeOpKind::Cast, - value: *value, - ty, - }; + let ty = target_type; stats.intrinsic_optimizations += 1; + I::TypeOp { + dst, + op: TypeOpKind::Cast, + value, + ty, + } } I::WeakNew { dst, box_val } => { - let d = *dst; - let v = *box_val; - *term = I::WeakRef { - dst: d, - op: WeakRefOp::New, - value: v, - }; stats.intrinsic_optimizations += 1; + I::WeakRef { + dst, + op: WeakRefOp::New, + value: box_val, + } } I::WeakLoad { dst, weak_ref } => { - let d = *dst; - let v = *weak_ref; - *term = I::WeakRef { - dst: d, - op: WeakRefOp::Load, - value: v, - }; stats.intrinsic_optimizations += 1; + I::WeakRef { + dst, + op: WeakRefOp::Load, + value: weak_ref, + } } I::BarrierRead { ptr } => { - let p = *ptr; - *term = I::Barrier { - op: BarrierOp::Read, - ptr: p, - }; stats.intrinsic_optimizations += 1; + I::Barrier { + op: BarrierOp::Read, + ptr, + } } I::BarrierWrite { ptr } => { - let p = *ptr; - *term = I::Barrier { - op: BarrierOp::Write, - ptr: p, - }; stats.intrinsic_optimizations += 1; + I::Barrier { + op: BarrierOp::Write, + ptr, + } } I::Print { value, .. } => { - let v = *value; - *term = I::ExternCall { + stats.intrinsic_optimizations += 1; + I::ExternCall { dst: None, iface_name: "env.console".to_string(), method_name: "log".to_string(), - args: vec![v], + args: vec![value], effects: crate::mir::EffectMask::PURE, - }; - stats.intrinsic_optimizations += 1; + } } I::ArrayGet { dst, array, index } if array_to_boxcall => { - let d = *dst; - let a = *array; - let i = *index; - *term = I::BoxCall { - dst: Some(d), - box_val: a, + stats.intrinsic_optimizations += 1; + I::BoxCall { + dst: Some(dst), + box_val: array, method: "get".to_string(), method_id: None, - args: vec![i], + args: vec![index], effects: crate::mir::EffectMask::READ, - }; - stats.intrinsic_optimizations += 1; + } } I::ArraySet { array, index, value, } if array_to_boxcall => { - let a = *array; - let i = *index; - let v = *value; - *term = I::BoxCall { + stats.intrinsic_optimizations += 1; + I::BoxCall { dst: None, - box_val: a, + box_val: array, method: "set".to_string(), method_id: None, - args: vec![i, v], + args: vec![index, value], effects: crate::mir::EffectMask::WRITE, - }; - stats.intrinsic_optimizations += 1; + } } - _ => {} - } + other => other, + }; + block.terminator = Some(rewritten); + block.terminator_span = Some(span); } + + let (insts, spans): (Vec<_>, Vec<_>) = new_spanned + .into_iter() + .map(|sp| (sp.inst, sp.span)) + .unzip(); + block.instructions = insts; + block.instruction_spans = spans; + block.effects = block + .instructions + .iter() + .chain(block.terminator.iter()) + .fold(EffectMask::PURE, |mask, inst| mask | inst.effects()); } if idemp_enabled() { let key = idemp_key(pass_name, &fname); @@ -555,6 +568,12 @@ pub fn normalize_ref_field_access( block.terminator_span = Some(term_span); } } + + block.effects = block + .instructions + .iter() + .chain(block.terminator.iter()) + .fold(EffectMask::PURE, |mask, inst| mask | inst.effects()); } if idemp_enabled() { let key = idemp_key(pass_name, &fname); diff --git a/src/mir/optimizer_passes/normalize_core13_pure.rs b/src/mir/optimizer_passes/normalize_core13_pure.rs index 68b90c34..79273a46 100644 --- a/src/mir/optimizer_passes/normalize_core13_pure.rs +++ b/src/mir/optimizer_passes/normalize_core13_pure.rs @@ -1,7 +1,9 @@ use crate::ast::Span; use crate::mir::optimizer::MirOptimizer; use crate::mir::optimizer_stats::OptimizationStats; -use crate::mir::{BinaryOp, CompareOp, EffectMask, MirInstruction as I, MirModule, ValueId}; +use crate::mir::{ + BinaryOp, CompareOp, EffectMask, MirInstruction as I, MirModule, SpannedInstruction, ValueId, +}; /// Core-13 "pure" normalization: rewrite a few non-13 ops to allowed forms. /// - Load(dst, ptr) => ExternCall(Some dst, env.local.get, [ptr]) @@ -16,33 +18,34 @@ pub fn normalize_pure_core13(_opt: &mut MirOptimizer, module: &mut MirModule) -> let mut stats = OptimizationStats::new(); for (_fname, function) in &mut module.functions { for (_bb, block) in &mut function.blocks { - let mut out: Vec = Vec::with_capacity(block.instructions.len() + 8); - let mut out_spans: Vec = Vec::with_capacity(block.instructions.len() + 8); - let old = std::mem::take(&mut block.instructions); - let mut old_spans_iter = std::mem::take(&mut block.instruction_spans).into_iter(); - for inst in old.into_iter() { - let span = old_spans_iter.next().unwrap_or_else(Span::unknown); + let old = block.drain_spanned_instructions(); + let mut out: Vec = Vec::with_capacity(old.len() + 8); + for SpannedInstruction { inst, span } in old.into_iter() { match inst { I::Load { dst, ptr } => { - out.push(I::ExternCall { - dst: Some(dst), - iface_name: "env.local".to_string(), - method_name: "get".to_string(), - args: vec![ptr], - effects: EffectMask::READ, + out.push(SpannedInstruction { + inst: I::ExternCall { + dst: Some(dst), + iface_name: "env.local".to_string(), + method_name: "get".to_string(), + args: vec![ptr], + effects: EffectMask::READ, + }, + span, }); - out_spans.push(span); stats.intrinsic_optimizations += 1; } I::Store { value, ptr } => { - out.push(I::ExternCall { - dst: None, - iface_name: "env.local".to_string(), - method_name: "set".to_string(), - args: vec![ptr, value], - effects: EffectMask::WRITE, + out.push(SpannedInstruction { + inst: I::ExternCall { + dst: None, + iface_name: "env.local".to_string(), + method_name: "set".to_string(), + args: vec![ptr, value], + effects: EffectMask::WRITE, + }, + span, }); - out_spans.push(span); stats.intrinsic_optimizations += 1; } I::NewBox { @@ -53,22 +56,26 @@ pub fn normalize_pure_core13(_opt: &mut MirOptimizer, module: &mut MirModule) -> // prepend type name as Const String let ty_id = ValueId::new(function.next_value_id); function.next_value_id += 1; - out.push(I::Const { - dst: ty_id, - value: crate::mir::ConstValue::String(box_type), + out.push(SpannedInstruction { + inst: I::Const { + dst: ty_id, + value: crate::mir::ConstValue::String(box_type), + }, + span, }); - out_spans.push(span); let mut call_args = Vec::with_capacity(1 + args.len()); call_args.push(ty_id); call_args.append(&mut args); - out.push(I::ExternCall { - dst: Some(dst), - iface_name: "env.box".to_string(), - method_name: "new".to_string(), - args: call_args, - effects: EffectMask::PURE, // constructor is logically alloc; conservatively PURE here + out.push(SpannedInstruction { + inst: I::ExternCall { + dst: Some(dst), + iface_name: "env.box".to_string(), + method_name: "new".to_string(), + args: call_args, + effects: EffectMask::PURE, // constructor is logically alloc; conservatively PURE here + }, + span, }); - out_spans.push(span); stats.intrinsic_optimizations += 1; } I::UnaryOp { dst, op, operand } => { @@ -76,62 +83,71 @@ pub fn normalize_pure_core13(_opt: &mut MirOptimizer, module: &mut MirModule) -> crate::mir::UnaryOp::Neg => { let zero = ValueId::new(function.next_value_id); function.next_value_id += 1; - out.push(I::Const { - dst: zero, - value: crate::mir::ConstValue::Integer(0), + out.push(SpannedInstruction { + inst: I::Const { + dst: zero, + value: crate::mir::ConstValue::Integer(0), + }, + span, }); - out_spans.push(span); - out.push(I::BinOp { - dst, - op: BinaryOp::Sub, - lhs: zero, - rhs: operand, + out.push(SpannedInstruction { + inst: I::BinOp { + dst, + op: BinaryOp::Sub, + lhs: zero, + rhs: operand, + }, + span, }); - out_spans.push(span); } crate::mir::UnaryOp::Not => { let f = ValueId::new(function.next_value_id); function.next_value_id += 1; - out.push(I::Const { - dst: f, - value: crate::mir::ConstValue::Bool(false), + out.push(SpannedInstruction { + inst: I::Const { + dst: f, + value: crate::mir::ConstValue::Bool(false), + }, + span, }); - out_spans.push(span); - out.push(I::Compare { - dst, - op: CompareOp::Eq, - lhs: operand, - rhs: f, + out.push(SpannedInstruction { + inst: I::Compare { + dst, + op: CompareOp::Eq, + lhs: operand, + rhs: f, + }, + span, }); - out_spans.push(span); } crate::mir::UnaryOp::BitNot => { let all1 = ValueId::new(function.next_value_id); function.next_value_id += 1; - out.push(I::Const { - dst: all1, - value: crate::mir::ConstValue::Integer(-1), + out.push(SpannedInstruction { + inst: I::Const { + dst: all1, + value: crate::mir::ConstValue::Integer(-1), + }, + span, }); - out_spans.push(span); - out.push(I::BinOp { - dst, - op: BinaryOp::BitXor, - lhs: operand, - rhs: all1, + out.push(SpannedInstruction { + inst: I::BinOp { + dst, + op: BinaryOp::BitXor, + lhs: operand, + rhs: all1, + }, + span, }); - out_spans.push(span); } } stats.intrinsic_optimizations += 1; } - other => { - out.push(other); - out_spans.push(span); - } + other => out.push(SpannedInstruction { inst: other, span }), } } - block.instructions = out; - block.instruction_spans = out_spans; + block.instructions = out.iter().map(|s| s.inst.clone()).collect(); + block.instruction_spans = out.iter().map(|s| s.span).collect(); if let Some(term) = block.terminator.take() { let term_span = block.terminator_span.take().unwrap_or_else(Span::unknown); diff --git a/src/mir/passes/escape.rs b/src/mir/passes/escape.rs index ec7a6d3b..aa21bdcd 100644 --- a/src/mir/passes/escape.rs +++ b/src/mir/passes/escape.rs @@ -41,8 +41,8 @@ fn analyze_function(func: &MirFunction) -> EscapeInfo { let mut info = EscapeInfo::default(); // Collect local boxes: results of NewBox in this function for block in func.blocks.values() { - for ins in block.instructions.iter() { - if let MirInstruction::NewBox { dst, .. } = ins { + for sp in block.iter_spanned() { + if let MirInstruction::NewBox { dst, .. } = sp.inst { info.local_boxes.insert(*dst); } } @@ -54,8 +54,8 @@ fn analyze_function(func: &MirFunction) -> EscapeInfo { } // Conservative escape marking for block in func.blocks.values() { - for ins in block.all_instructions() { - match ins { + for sp in block.all_spanned_instructions() { + match sp.inst { MirInstruction::Return { value: Some(v) } => { if info.local_boxes.contains(v) { info.escaping.insert(*v); diff --git a/src/mir/printer.rs b/src/mir/printer.rs index 53fdd4a9..69420dc5 100644 --- a/src/mir/printer.rs +++ b/src/mir/printer.rs @@ -158,8 +158,8 @@ impl MirPrinter { let mut barrier_read = 0usize; let mut barrier_write = 0usize; for block in function.blocks.values() { - for inst in &block.instructions { - match inst { + for sp in block.iter_spanned() { + match sp.inst { MirInstruction::Throw { .. } => { if dlog::on("NYASH_DEBUG_MIR_PRINTER") { eprintln!("[PRINTER] found throw in {}", function.signature.name); @@ -191,8 +191,8 @@ impl MirPrinter { _ => {} } } - if let Some(term) = &block.terminator { - match term { + if let Some(sp) = block.terminator_spanned() { + match sp.inst { MirInstruction::Throw { .. } => { if dlog::on("NYASH_DEBUG_MIR_PRINTER") { eprintln!( @@ -306,17 +306,16 @@ impl MirPrinter { writeln!(output).unwrap(); // Instructions - let mut line_num = 0; - for instruction in block.all_instructions() { + for sp in block.all_spanned_instructions() { if self.show_line_numbers { - write!(output, " {:3}: ", line_num).unwrap(); + write!(output, " {:3}: ", sp.span.line).unwrap(); } else { write!(output, " ").unwrap(); } - let mut line = self.format_instruction(instruction, types); + let mut line = self.format_instruction(sp.inst, types); if self.show_effects_inline { - let eff = instruction.effects(); + let eff = sp.inst.effects(); let cat = if eff.is_pure() { "pure" } else if eff.is_read_only() { @@ -327,7 +326,6 @@ impl MirPrinter { line.push_str(&format!(" ; eff: {}", cat)); } writeln!(output, "{}", line).unwrap(); - line_num += 1; } // Block effects (if verbose and not pure) diff --git a/src/mir/query.rs b/src/mir/query.rs index 20f09158..3efaac4b 100644 --- a/src/mir/query.rs +++ b/src/mir/query.rs @@ -109,7 +109,6 @@ impl<'m> MirQuery for MirQueryBox<'m> { FutureSet { future, value } => vec![*future, *value], Await { future, .. } => vec![*future], Safepoint => Vec::new(), - _ => Vec::new(), } } diff --git a/src/mir/spanned_instruction.rs b/src/mir/spanned_instruction.rs index dc712158..23247650 100644 --- a/src/mir/spanned_instruction.rs +++ b/src/mir/spanned_instruction.rs @@ -1,5 +1,5 @@ -use crate::ast::Span; use super::MirInstruction; +use crate::ast::Span; /// MIR instruction bundled with its source span. #[derive(Debug, Clone)] @@ -7,3 +7,10 @@ pub struct SpannedInstruction { pub inst: MirInstruction, pub span: Span, } + +/// Reference view of a MIR instruction bundled with its span. +#[derive(Debug, Clone, Copy)] +pub struct SpannedInstRef<'a> { + pub inst: &'a MirInstruction, + pub span: Span, +} diff --git a/src/mir/ssot/cf_common.rs b/src/mir/ssot/cf_common.rs index 999aecb4..2bba3ac6 100644 --- a/src/mir/ssot/cf_common.rs +++ b/src/mir/ssot/cf_common.rs @@ -1,4 +1,7 @@ -use crate::mir::{BasicBlockId, CompareOp, MirFunction, MirInstruction, ValueId}; +use crate::mir::{ + BasicBlockId, CompareOp, MirFunction, MirInstruction, SpannedInstruction, ValueId, +}; +use crate::ast::Span; /// Emit a MIR Compare instruction into the current block (function-level SSOT helper) pub fn emit_compare_func( @@ -49,16 +52,28 @@ pub fn set_jump(f: &mut MirFunction, cur_bb: BasicBlockId, target: BasicBlockId) /// Insert a PHI instruction at block head (after existing PHIs) with normalized inputs order. pub fn insert_phi_at_head( + f: &mut MirFunction, + bb_id: BasicBlockId, + dst: ValueId, + inputs: Vec<(BasicBlockId, ValueId)>, +) { + insert_phi_at_head_spanned(f, bb_id, dst, inputs, Span::unknown()); +} + +/// Insert a PHI instruction at block head (after existing PHIs) with normalized inputs order. +/// Allows passing a span to retain source mapping when available. +pub fn insert_phi_at_head_spanned( f: &mut MirFunction, bb_id: BasicBlockId, dst: ValueId, mut inputs: Vec<(BasicBlockId, ValueId)>, + span: Span, ) { inputs.sort_by_key(|(bb, _)| bb.0); if let Some(bb) = f.get_block_mut(bb_id) { - bb.insert_spanned_after_phis(crate::mir::SpannedInstruction { + bb.insert_spanned_after_phis(SpannedInstruction { inst: MirInstruction::Phi { dst, inputs }, - span: crate::ast::Span::unknown(), + span, }); } } diff --git a/src/mir/utils/phi_helpers.rs b/src/mir/utils/phi_helpers.rs index 3c43ae6b..487d1092 100644 --- a/src/mir/utils/phi_helpers.rs +++ b/src/mir/utils/phi_helpers.rs @@ -72,7 +72,13 @@ impl MirBuilder { // 統一された挿入ロジック(既存パターンと完全互換) if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { // CFG経由の正規化挿入(predecessor順序の正規化を含む) - crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, phi_val, inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + func, + cur_bb, + phi_val, + inputs, + self.current_span, + ); } else { // フォールバック: 直接emit(主にテストや特殊ケース用) self.emit_instruction(MirInstruction::Phi { @@ -131,7 +137,13 @@ impl MirBuilder { // 統一された挿入ロジック(既存パターンと完全互換) if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { // CFG経由の正規化挿入(predecessor順序の正規化を含む) - crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, dst, inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + func, + cur_bb, + dst, + inputs, + self.current_span, + ); } else { // フォールバック: 直接emit(主にテストや特殊ケース用) self.emit_instruction(MirInstruction::Phi { dst, inputs })?; diff --git a/src/mir/value_kind.rs b/src/mir/value_kind.rs index 0aeefefc..5a78da14 100644 --- a/src/mir/value_kind.rs +++ b/src/mir/value_kind.rs @@ -5,7 +5,6 @@ // - ValueIdの意味的分類(Parameter, Local, Constant等)を導入 // - GUARDバグのような「ValueId(0)の曖昧性」から生じるバグを根絶 -use crate::mir::ConstValue; use crate::mir::ValueId; /// ValueIdの意味的分類(型安全性強化) diff --git a/src/mir/verification.rs b/src/mir/verification.rs index 6a2a8632..7a23d3b3 100644 --- a/src/mir/verification.rs +++ b/src/mir/verification.rs @@ -93,9 +93,10 @@ impl MirVerifier { instruction_index ); if let Some(bb) = function.blocks.get(block) { - let inst_opt = bb.all_instructions().nth(*instruction_index); - if let Some(inst) = inst_opt { - eprintln!("[mir-ssa-debug-inst] inst={:?}", inst); + let inst_opt = + bb.all_spanned_instructions_enumerated().nth(*instruction_index); + if let Some((_idx, sp)) = inst_opt { + eprintln!("[mir-ssa-debug-inst] inst={:?}", sp.inst); } } } @@ -291,8 +292,8 @@ impl MirVerifier { // Collect values used in merge block let mut used_values = std::collections::HashSet::new(); - for inst in merge_bb.all_instructions() { - for v in inst.used_values() { + for sp in merge_bb.all_spanned_instructions() { + for v in sp.inst.used_values() { used_values.insert(v); } } diff --git a/src/mir/verification/barrier.rs b/src/mir/verification/barrier.rs index f18484f9..1c2a8e03 100644 --- a/src/mir/verification/barrier.rs +++ b/src/mir/verification/barrier.rs @@ -9,15 +9,15 @@ pub fn check_weakref_and_barrier(function: &MirFunction) -> Result<(), Vec = std::collections::HashMap::new(); for (bid, block) in &function.blocks { - for (idx, inst) in block.all_instructions().enumerate() { - if let Some(dst) = inst.dst_value() { - def_map.insert(dst, (*bid, idx, inst)); + for (idx, sp) in block.all_spanned_instructions_enumerated() { + if let Some(dst) = sp.inst.dst_value() { + def_map.insert(dst, (*bid, idx, sp.inst)); } } } for (bid, block) in &function.blocks { - for (idx, inst) in block.all_instructions().enumerate() { - match inst { + for (idx, sp) in block.all_spanned_instructions_enumerated() { + match sp.inst { MirInstruction::WeakRef { op: crate::mir::WeakRefOp::Load, value, @@ -103,11 +103,10 @@ pub fn check_barrier_context(function: &MirFunction) -> Result<(), Vec = - block.instructions.iter().enumerate().collect(); - if let Some(term) = &block.terminator { - insts.push((usize::MAX, term)); - } + let insts: Vec<(usize, &MirInstruction)> = block + .all_spanned_instructions_enumerated() + .map(|(i, sp)| (i, sp.inst)) + .collect(); for (idx, inst) in &insts { let is_barrier = matches!( inst, diff --git a/src/mir/verification/cfg.rs b/src/mir/verification/cfg.rs index db497945..7429c4f9 100644 --- a/src/mir/verification/cfg.rs +++ b/src/mir/verification/cfg.rs @@ -42,8 +42,8 @@ pub fn check_merge_uses(function: &MirFunction) -> Result<(), Vec> = HashMap::new(); for (bid, block) in &function.blocks { let set = phi_dsts_in_block.entry(*bid).or_default(); - for inst in block.all_instructions() { - if let crate::mir::MirInstruction::Phi { dst, .. } = inst { + for sp in block.all_spanned_instructions() { + if let crate::mir::MirInstruction::Phi { dst, .. } = sp.inst { set.insert(*dst); } } @@ -57,11 +57,11 @@ pub fn check_merge_uses(function: &MirFunction) -> Result<(), Vec Result<(), Vec Result<(), Vec Some("TypeCheck"), // -> TypeOp(Check) MirInstruction::Cast { .. } => Some("Cast"), // -> TypeOp(Cast) MirInstruction::WeakNew { .. } => Some("WeakNew"), // -> WeakRef(New) diff --git a/src/mir/verification/ssa.rs b/src/mir/verification/ssa.rs index d0fe4505..ea0d24bc 100644 --- a/src/mir/verification/ssa.rs +++ b/src/mir/verification/ssa.rs @@ -14,8 +14,8 @@ pub fn check_ssa_form(function: &MirFunction) -> Result<(), Vec Result<(), Vec HashMap HashSet worklist.push(*successor); } } - for instruction in &block.instructions { - if let crate::mir::MirInstruction::Catch { handler_bb, .. } = instruction { + for sp in block.iter_spanned() { + if let crate::mir::MirInstruction::Catch { handler_bb, .. } = sp.inst { if !reachable.contains(handler_bb) { worklist.push(*handler_bb); } diff --git a/src/runner/json_v0_bridge/lowering/expr.rs b/src/runner/json_v0_bridge/lowering/expr.rs index 00659757..9bd1d9c6 100644 --- a/src/runner/json_v0_bridge/lowering/expr.rs +++ b/src/runner/json_v0_bridge/lowering/expr.rs @@ -3,6 +3,7 @@ use super::merge::new_block; use super::ternary; use super::BridgeEnv; use crate::mir::{BasicBlockId, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId}; +use crate::ast::Span; use std::collections::BTreeMap; use super::super::ast::ExprV0; @@ -290,7 +291,13 @@ pub(super) fn lower_expr_with_scope( } else { inputs.push((fall_bb, rval)); } - crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + f, + merge_bb, + out, + inputs, + Span::unknown(), + ); Ok((out, merge_bb)) } ExprV0::Call { name, args } => { diff --git a/src/runner/json_v0_bridge/lowering/loop_.rs b/src/runner/json_v0_bridge/lowering/loop_.rs index 353f9437..057bbbf0 100644 --- a/src/runner/json_v0_bridge/lowering/loop_.rs +++ b/src/runner/json_v0_bridge/lowering/loop_.rs @@ -23,10 +23,10 @@ use super::super::ast::ExprV0; use super::super::ast::StmtV0; use super::{lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext}; -use crate::mir::phi_core::loop_snapshot_merge::LoopSnapshotMergeBox; use crate::mir::phi_core::loopform_builder::{LoopFormBuilder, LoopFormOps}; use crate::mir::phi_core::phi_input_collector::PhiInputCollector; use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; +use crate::ast::Span; use std::collections::BTreeMap; /// LoopForm v2 用の JSON bridge 実装。 @@ -143,7 +143,13 @@ impl LoopFormOps for LoopFormJsonOps<'_> { dst: ValueId, inputs: Vec<(BasicBlockId, ValueId)>, ) -> Result<(), String> { - crate::mir::ssot::cf_common::insert_phi_at_head(self.f, self.current_block, dst, inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + self.f, + self.current_block, + dst, + inputs, + Span::unknown(), + ); Ok(()) } @@ -363,11 +369,12 @@ pub(super) fn lower_loop_stmt( // 異なる値を持つ場合は PHI ノードを continue_merge_bb に生成 let final_inputs = collector.finalize(); let phi_id = ops.f.next_value_id(); - crate::mir::ssot::cf_common::insert_phi_at_head( + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( ops.f, continue_merge_bb, phi_id, final_inputs, + Span::unknown(), ); phi_id }; diff --git a/src/runner/json_v0_bridge/lowering/match_expr.rs b/src/runner/json_v0_bridge/lowering/match_expr.rs index 87a2ed4e..a7ff5543 100644 --- a/src/runner/json_v0_bridge/lowering/match_expr.rs +++ b/src/runner/json_v0_bridge/lowering/match_expr.rs @@ -5,6 +5,7 @@ use super::expr::{lower_expr_with_scope, VarScope}; use super::merge::new_block; use super::BridgeEnv; use crate::mir::{BasicBlockId, CompareOp, ConstValue, MirFunction, MirInstruction, ValueId}; +use crate::ast::Span; pub(super) fn lower_match_expr_with_scope( env: &BridgeEnv, @@ -85,6 +86,12 @@ pub(super) fn lower_match_expr_with_scope( let out = f.next_value_id(); // フェーズM.2: PHI統一処理(no_phi分岐削除) let inputs = phi_inputs; - crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + f, + merge_bb, + out, + inputs, + Span::unknown(), + ); Ok((out, merge_bb)) } diff --git a/src/runner/json_v0_bridge/lowering/merge.rs b/src/runner/json_v0_bridge/lowering/merge.rs index 1fedf93f..9d16bcac 100644 --- a/src/runner/json_v0_bridge/lowering/merge.rs +++ b/src/runner/json_v0_bridge/lowering/merge.rs @@ -1,4 +1,5 @@ use crate::mir::{BasicBlock, BasicBlockId, MirFunction, MirInstruction, ValueId}; +use crate::ast::Span; fn next_block_id(f: &MirFunction) -> BasicBlockId { let mut mx = 0u32; @@ -41,11 +42,12 @@ pub(super) fn merge_values( bb.add_instruction_before_terminator(MirInstruction::Copy { dst, src: val_b }); } } else { - crate::mir::ssot::cf_common::insert_phi_at_head( + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( f, merge_bb, dst, vec![(pred_a, val_a), (pred_b, val_b)], + Span::unknown(), ); } dst diff --git a/src/runner/json_v0_bridge/lowering/ternary.rs b/src/runner/json_v0_bridge/lowering/ternary.rs index f45fd2cc..8181bbe9 100644 --- a/src/runner/json_v0_bridge/lowering/ternary.rs +++ b/src/runner/json_v0_bridge/lowering/ternary.rs @@ -7,6 +7,7 @@ use super::super::ast::ExprV0; use super::merge::new_block; use super::BridgeEnv; use crate::mir::{BasicBlockId, MirFunction, ValueId}; +use crate::ast::Span; use super::expr::{lower_expr_with_scope, VarScope}; @@ -40,6 +41,12 @@ pub(super) fn lower_ternary_expr_with_scope( let out = f.next_value_id(); // フェーズM.2: PHI統一処理(no_phi分岐削除) let inputs = vec![(tend, tval), (eend, eval)]; - crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + f, + merge_bb, + out, + inputs, + Span::unknown(), + ); Ok((out, merge_bb)) } diff --git a/src/runner/json_v0_bridge/lowering/try_catch.rs b/src/runner/json_v0_bridge/lowering/try_catch.rs index 0404887d..4f47e14f 100644 --- a/src/runner/json_v0_bridge/lowering/try_catch.rs +++ b/src/runner/json_v0_bridge/lowering/try_catch.rs @@ -1,6 +1,7 @@ use super::super::ast::{CatchV0, StmtV0}; use super::{lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext}; use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; +use crate::ast::Span; use std::collections::BTreeMap; pub(super) fn lower_try_stmt( @@ -102,8 +103,12 @@ pub(super) fn lower_try_stmt( if let Some(_bb) = f.get_block_mut(catch_bb) { let mut inputs = incoming_exc.clone(); inputs.sort_by_key(|(bbid, _)| bbid.0); - crate::mir::ssot::cf_common::insert_phi_at_head( - f, catch_bb, phi_dst, inputs, + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + f, + catch_bb, + phi_dst, + inputs, + Span::unknown(), ); } catch_vars.insert(param.clone(), phi_dst); @@ -170,7 +175,13 @@ pub(super) fn lower_try_stmt( } if let Some(_bb) = f.get_block_mut(finally_block) { for (dst, inputs) in phi_entries { - crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + f, + finally_block, + dst, + inputs, + Span::unknown(), + ); } } let mut finally_vars = merged_vars.clone(); @@ -226,7 +237,13 @@ pub(super) fn lower_try_stmt( } if let Some(_bb) = f.get_block_mut(exit_bb) { for (dst, inputs) in phi_entries { - crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + f, + exit_bb, + dst, + inputs, + Span::unknown(), + ); } } *vars = merged_vars; @@ -326,7 +343,13 @@ pub(super) fn lower_try_stmt( // フェーズM.2: PHI統一処理(no_phi分岐削除) if let Some(_bb) = f.get_block_mut(finally_block) { for (dst, inputs) in phi_entries { - crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + f, + finally_block, + dst, + inputs, + Span::unknown(), + ); } } let mut finally_vars = merged_vars.clone(); @@ -377,7 +400,13 @@ pub(super) fn lower_try_stmt( // フェーズM.2: PHI統一処理(no_phi分岐削除) if let Some(_bb) = f.get_block_mut(exit_bb) { for (dst, inputs) in phi_entries { - crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs); + crate::mir::ssot::cf_common::insert_phi_at_head_spanned( + f, + exit_bb, + dst, + inputs, + Span::unknown(), + ); } } *vars = merged_vars; diff --git a/src/runner/modes/common_util/diag.rs b/src/runner/modes/common_util/diag.rs index 70d577cc..bc5267d9 100644 --- a/src/runner/modes/common_util/diag.rs +++ b/src/runner/modes/common_util/diag.rs @@ -101,14 +101,12 @@ fn print_source_snippet(filename: &str, src: &str, line: usize, col: Option= col { break; } // Preserve tabs visually; spaces elsewhere underline.push(if ch == '\t' { '\t' } else { ' ' }); - idx = i; } let pad = " "; // align under " LNNNNN |" eprintln!(" {}{}^", pad, underline); diff --git a/src/runner/modes/common_util/resolve/prelude_manager.rs b/src/runner/modes/common_util/resolve/prelude_manager.rs index 781f59e9..67ebe147 100644 --- a/src/runner/modes/common_util/resolve/prelude_manager.rs +++ b/src/runner/modes/common_util/resolve/prelude_manager.rs @@ -178,6 +178,7 @@ impl<'a> PreludeManagerBox<'a> { }); current_line += main_lines; } + let _ = current_line; if trace { crate::runner::trace::log(format!( diff --git a/src/runner/modes/common_util/resolve/strip.rs b/src/runner/modes/common_util/resolve/strip.rs index f0242d26..60d39320 100644 --- a/src/runner/modes/common_util/resolve/strip.rs +++ b/src/runner/modes/common_util/resolve/strip.rs @@ -999,6 +999,7 @@ pub fn merge_prelude_text( }); current_line += main_lines; } + let _ = current_line; if trace { crate::runner::trace::log(format!( diff --git a/src/runner/stage1_bridge/mod.rs b/src/runner/stage1_bridge/mod.rs index afef1dbc..2f2e6c5b 100644 --- a/src/runner/stage1_bridge/mod.rs +++ b/src/runner/stage1_bridge/mod.rs @@ -21,7 +21,7 @@ mod modules; use super::NyashRunner; use crate::cli::CliGroups; -use std::{path::Path, process}; +use std::path::Path; impl NyashRunner { /// If enabled, run the Stage-1 CLI stub as a child process and return its exit code.