// Call result annotation helpers // Extracted from builder_calls.rs to keep files lean use super::super::{MirBuilder, MirType, ValueId}; /// Annotate a call result `dst` with the return type and origin if the callee /// is a known user/static function in the current module. pub(in super::super) fn annotate_call_result_from_func_name>( builder: &mut MirBuilder, dst: ValueId, func_name: S, ) { let name = func_name.as_ref(); // 1) Prefer module signature when available if let Some(ref module) = builder.current_module { if let Some(func) = module.functions.get(name) { let mut ret = func.signature.return_type.clone(); // Targeted stabilization: JsonParser.parse/1 should produce JsonNode // If signature is Unknown/Void, normalize to Box("JsonNode") if name == "JsonParser.parse/1" { if matches!(ret, MirType::Unknown | MirType::Void) { ret = MirType::Box("JsonNode".into()); } } // Token path: JsonParser.current_token/0 should produce JsonToken if name == "JsonParser.current_token/0" { if matches!(ret, MirType::Unknown | MirType::Void) { ret = MirType::Box("JsonToken".into()); } } // Parser factory: JsonParserModule.create_parser/0 returns JsonParser if name == "JsonParserModule.create_parser/0" { // Normalize to Known Box(JsonParser) ret = MirType::Box("JsonParser".into()); } builder.type_ctx.value_types.insert(dst, ret.clone()); if let MirType::Box(bx) = ret { builder.type_ctx.value_origin_newbox.insert(dst, bx); if super::super::utils::builder_debug_enabled() || std::env::var("NYASH_BUILDER_DEBUG").ok().as_deref() == Some("1") { let bx = builder .type_ctx .value_origin_newbox .get(&dst) .cloned() .unwrap_or_default(); super::super::utils::builder_debug_log(&format!( "annotate call dst={} from {} -> Box({})", dst.0, name, bx )); } } return; } } // 2) No module signature—apply minimal heuristic for known functions if name == "JsonParser.parse/1" { let ret = MirType::Box("JsonNode".into()); builder.type_ctx.value_types.insert(dst, ret.clone()); if let MirType::Box(bx) = ret { builder.type_ctx.value_origin_newbox.insert(dst, bx); } if super::super::utils::builder_debug_enabled() || std::env::var("NYASH_BUILDER_DEBUG").ok().as_deref() == Some("1") { super::super::utils::builder_debug_log(&format!( "annotate call (fallback) dst={} from {} -> Box(JsonNode)", dst.0, name )); } } else if name == "JsonParser.current_token/0" { let ret = MirType::Box("JsonToken".into()); builder.type_ctx.value_types.insert(dst, ret.clone()); if let MirType::Box(bx) = ret { builder.type_ctx.value_origin_newbox.insert(dst, bx); } if super::super::utils::builder_debug_enabled() || std::env::var("NYASH_BUILDER_DEBUG").ok().as_deref() == Some("1") { super::super::utils::builder_debug_log(&format!( "annotate call (fallback) dst={} from {} -> Box(JsonToken)", dst.0, name )); } } else if name == "JsonTokenizer.tokenize/0" { // Tokenize returns an ArrayBox of tokens let ret = MirType::Box("ArrayBox".into()); builder.type_ctx.value_types.insert(dst, ret.clone()); if let MirType::Box(bx) = ret { builder.type_ctx.value_origin_newbox.insert(dst, bx); } if super::super::utils::builder_debug_enabled() || std::env::var("NYASH_BUILDER_DEBUG").ok().as_deref() == Some("1") { super::super::utils::builder_debug_log(&format!( "annotate call (fallback) dst={} from {} -> Box(ArrayBox)", dst.0, name )); } } else if name == "JsonParserModule.create_parser/0" { // Fallback path for parser factory let ret = MirType::Box("JsonParser".into()); builder.type_ctx.value_types.insert(dst, ret.clone()); if let MirType::Box(bx) = ret { builder.type_ctx.value_origin_newbox.insert(dst, bx); } if super::super::utils::builder_debug_enabled() || std::env::var("NYASH_BUILDER_DEBUG").ok().as_deref() == Some("1") { super::super::utils::builder_debug_log(&format!( "annotate call (fallback) dst={} from {} -> Box(JsonParser)", dst.0, name )); } } else { // Generic tiny whitelist for known primitive-like utilities (spec unchanged) crate::mir::builder::types::annotation::annotate_from_function(builder, dst, name); } }