fix(env): improve Environment::set scope resolution (partial)

Fixed:
- Environment::set now properly searches ancestor chain before creating new binding
- Added exists_in_chain_locked() helper for explicit existence checking
- Simple {} blocks now correctly update outer scope variables

Verified Working:
- local x = 10; { x = 42 }; print(x) → prints 42 

Still Broken:
- else blocks don't update outer scope variables
- local x = 10; if flag { x = 99 } else { x = 42 }; print(x) → prints 10 

Root Cause Identified:
- Issue is in MIR Builder (compile-time), not Environment (runtime)
- src/mir/builder/if_form.rs:108 resets variable_map before else block
- PHI generation at merge doesn't use else_var_map_end correctly
- MIR shows: phi [%32, bb1], [%1, bb2] where %1 is original value, not else value

Next: Fix else block variable merging in if_form.rs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-13 18:55:14 +09:00
parent 1ac0c6b880
commit 801833df8d
5 changed files with 187 additions and 11 deletions

View File

@ -102,6 +102,13 @@ static box Main {
}
}
}
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
print("[DEBUG] Source length: " + s.length())
print("[DEBUG] k0 (main position) = " + k0)
}
}
if k0 >= 0 {
// find '(' after k0 (skip inside strings)
local k1 = -1
@ -124,6 +131,12 @@ static box Main {
j = j + 1
}
}
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
print("[DEBUG] k1 ('(' position) = " + k1)
}
}
if k1 >= 0 {
// find ')' after k1 (skip inside strings)
local k2 = -1
@ -146,6 +159,12 @@ static box Main {
j = j + 1
}
}
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
print("[DEBUG] k2 (')' position) = " + k2)
}
}
if k2 >= 0 {
// Find opening '{' following ')' (skip inside strings)
local k3 = -1
@ -168,6 +187,12 @@ static box Main {
j = j + 1
}
}
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
print("[DEBUG] k3 ('{' position) = " + k3)
}
}
if k3 >= 0 {
// Balanced scan for matching '}'
local depth = 0
@ -175,6 +200,8 @@ static box Main {
local n = s.length()
local in_str = 0
local esc = 0
local start_pos = -1
local end_pos = -1
loop(i < n) {
local ch = s.substring(i, i + 1)
if in_str == 1 {
@ -194,16 +221,85 @@ static box Main {
}
i = i + 1
}
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
print("[DEBUG] After balanced scan: depth=" + depth + ", i=" + i)
}
}
if depth == 0 {
// inside of '{'..'}'
body_src = s.substring(k3 + 1, i - 1)
start_pos = k3 + 1
end_pos = i - 1
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
print("[DEBUG] Will extract substring(" + start_pos + ", " + end_pos + ")")
}
}
}
// Extract outside the nested blocks to avoid potential scoping issues
if start_pos >= 0 && end_pos >= start_pos {
body_src = s.substring(start_pos, end_pos)
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
if body_src == null {
print("[DEBUG] After extraction: body_src is NULL!")
} else {
print("[DEBUG] After extraction: body_src length = " + body_src.length())
}
}
}
}
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
if body_src == null { print("[DEBUG] body_src is NULL after line 254") } else { print("[DEBUG] body_src OK after line 254, len=" + body_src.length()) }
}
}
}
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
if body_src == null { print("[DEBUG] body_src is NULL after line 256") } else { print("[DEBUG] body_src OK after line 256, len=" + body_src.length()) }
}
}
}
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
if body_src == null { print("[DEBUG] body_src is NULL after line 268") } else { print("[DEBUG] body_src OK after line 268, len=" + body_src.length()) }
}
}
}
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
if body_src == null { print("[DEBUG] body_src is NULL after line 269") } else { print("[DEBUG] body_src OK after line 269, len=" + body_src.length()) }
}
}
}
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
if body_src == null { print("[DEBUG] body_src is NULL after line 270") } else { print("[DEBUG] body_src OK after line 270, len=" + body_src.length()) }
}
}
}
// Fallback: if extraction failed or produced empty, use full src
{
local dbg = env.get("HAKO_STAGEB_DEBUG")
if dbg != null && ("" + dbg) == "1" {
print("[DEBUG] Body extraction:")
if body_src == null {
print("[DEBUG] body_src = null")
} else {
print("[DEBUG] body_src length = " + ("" + body_src).length())
print("[DEBUG] body_src = [" + body_src + "]")
}
}
}
if body_src == null || ("" + body_src).length() == 0 { body_src = src }
}