refactor(mir): Extract TypeFacts Box from ops.rs (Phase 136 follow-up 1/3)

## Summary
Extracts type inference logic from ops.rs into independent TypeFacts Box,
improving testability and responsibility separation.

## Changes
- New file: src/mir/builder/type_facts.rs (TypeFactsBox + OperandTypeClass)
- Modified: src/mir/builder/ops.rs - Use TypeFacts Box instead of method
- Modified: src/mir/builder.rs - Add type_facts module

## Effect
- Type inference logic is now independently testable
- ops.rs responsibility simplified to "operator lowering only"
- Enables future sharing with lifecycle.rs:repropagate_binop_types()

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-15 19:49:41 +09:00
parent 455d511187
commit 47d6f50e96
3 changed files with 97 additions and 41 deletions

View File

@ -52,6 +52,7 @@ mod router; // RouterPolicyBoxUnified 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 type_facts; // Phase 136 follow-up: Type inference facts box
pub(crate) mod type_registry; pub(crate) mod type_registry;
mod types; // types::annotation / inference型注釈/推論の箱: 推論は後段) mod types; // types::annotation / inference型注釈/推論の箱: 推論は後段)
mod utils; mod utils;

View File

@ -10,40 +10,7 @@ enum BinaryOpType {
Comparison(CompareOp), Comparison(CompareOp),
} }
// Phase 131-11-E: TypeFacts - operand type classification
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum OperandTypeClass {
String,
Integer,
Unknown,
}
impl super::MirBuilder { impl super::MirBuilder {
// Phase 131-11-E: TypeFacts - classify operand type for BinOp inference
fn classify_operand_type(&self, vid: ValueId) -> OperandTypeClass {
let result = match self.value_types.get(&vid) {
Some(MirType::String) => OperandTypeClass::String,
Some(MirType::Box(bt)) if bt == "StringBox" => OperandTypeClass::String,
Some(MirType::Integer) => OperandTypeClass::Integer,
Some(MirType::Bool) => OperandTypeClass::Integer, // Bool can be used as integer
_ => {
// Check value_origin_newbox for StringBox
if self
.value_origin_newbox
.get(&vid)
.map(|s| s == "StringBox")
.unwrap_or(false)
{
return OperandTypeClass::String;
}
OperandTypeClass::Unknown
}
};
if std::env::var("NYASH_TYPEFACTS_DEBUG").is_ok() {
eprintln!("[typefacts] classify {:?} -> {:?}", vid, result);
}
result
}
// Build a binary operation // Build a binary operation
pub(super) fn build_binary_op( pub(super) fn build_binary_op(
&mut self, &mut self,
@ -101,11 +68,15 @@ impl super::MirBuilder {
vec![lhs, rhs], vec![lhs, rhs],
)?; )?;
// Phase 196: TypeFacts SSOT - AddOperator call type annotation // Phase 196: TypeFacts SSOT - AddOperator call type annotation
// Phase 131-11-E: TypeFacts - classify operand types // Phase 131-11-E: TypeFacts - classify operand types (Phase 136: use TypeFactsBox)
let lhs_type = self.classify_operand_type(lhs); let type_facts = super::type_facts::TypeFactsBox::new(
let rhs_type = self.classify_operand_type(rhs); &self.value_types,
&self.value_origin_newbox,
);
let lhs_type = type_facts.classify_operand_type(lhs);
let rhs_type = type_facts.classify_operand_type(rhs);
use OperandTypeClass::*; use super::type_facts::OperandTypeClass::*;
match (lhs_type, rhs_type) { match (lhs_type, rhs_type) {
(String, String) => { (String, String) => {
// BOTH are strings: result is string // BOTH are strings: result is string
@ -189,11 +160,15 @@ impl super::MirBuilder {
// Phase 196: TypeFacts SSOT - BinOp type is determined by operands only // Phase 196: TypeFacts SSOT - BinOp type is determined by operands only
// String concatenation is handled at use-site in LLVM lowering // String concatenation is handled at use-site in LLVM lowering
if matches!(op, crate::mir::BinaryOp::Add) { if matches!(op, crate::mir::BinaryOp::Add) {
// Phase 131-11-E: TypeFacts - classify operand types // Phase 131-11-E: TypeFacts - classify operand types (Phase 136: use TypeFactsBox)
let lhs_type = self.classify_operand_type(lhs); let type_facts = super::type_facts::TypeFactsBox::new(
let rhs_type = self.classify_operand_type(rhs); &self.value_types,
&self.value_origin_newbox,
);
let lhs_type = type_facts.classify_operand_type(lhs);
let rhs_type = type_facts.classify_operand_type(rhs);
use OperandTypeClass::*; use super::type_facts::OperandTypeClass::*;
match (lhs_type, rhs_type) { match (lhs_type, rhs_type) {
(String, String) => { (String, String) => {
// BOTH are strings: result is definitely a string // BOTH are strings: result is definitely a string

View File

@ -0,0 +1,80 @@
//! Type inference facts for MIR operands
//!
//! Provides type classification and inference for binary operations.
//!
//! Phase 136 follow-up: Extracted from ops.rs to improve testability
//! and responsibility separation.
use crate::mir::{MirType, ValueId};
use std::collections::BTreeMap;
/// Operand type classification for binary operation type inference
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OperandTypeClass {
Integer,
String,
Unknown,
}
/// Type facts box for type inference
///
/// Provides type classification services for MIR operands during lowering.
/// Immutable by design - operates on borrowed type maps.
pub struct TypeFactsBox<'a> {
value_types: &'a BTreeMap<ValueId, MirType>,
value_origin_newbox: &'a BTreeMap<ValueId, String>,
}
impl<'a> TypeFactsBox<'a> {
/// Create a new TypeFacts Box with borrowed type information
pub fn new(
value_types: &'a BTreeMap<ValueId, MirType>,
value_origin_newbox: &'a BTreeMap<ValueId, String>,
) -> Self {
Self {
value_types,
value_origin_newbox,
}
}
/// Classify operand type for binary operation inference
///
/// Phase 131-11-E: TypeFacts - operand type classification
/// (Extracted from ops.rs:23-46)
///
/// # Classification Strategy
/// 1. Check explicit type annotation first (value_types)
/// 2. Infer from NewBox origin (value_origin_newbox)
/// 3. Default to Unknown
///
/// # Returns
/// - `OperandTypeClass::Integer` - Integer or Bool type
/// - `OperandTypeClass::String` - String or StringBox type
/// - `OperandTypeClass::Unknown` - Unable to infer
pub fn classify_operand_type(&self, vid: ValueId) -> OperandTypeClass {
let result = match self.value_types.get(&vid) {
Some(MirType::String) => OperandTypeClass::String,
Some(MirType::Box(bt)) if bt == "StringBox" => OperandTypeClass::String,
Some(MirType::Integer) => OperandTypeClass::Integer,
Some(MirType::Bool) => OperandTypeClass::Integer, // Bool can be used as integer
_ => {
// Check value_origin_newbox for StringBox
if self
.value_origin_newbox
.get(&vid)
.map(|s| s == "StringBox")
.unwrap_or(false)
{
return OperandTypeClass::String;
}
OperandTypeClass::Unknown
}
};
if std::env::var("NYASH_TYPEFACTS_DEBUG").is_ok() {
eprintln!("[typefacts] classify {:?} -> {:?}", vid, result);
}
result
}
}