diff --git a/apps/tests/phase285_p2_weak_upgrade_fail_min.hako b/apps/tests/phase285_p2_weak_upgrade_fail_min.hako new file mode 100644 index 00000000..d75f1d80 --- /dev/null +++ b/apps/tests/phase285_p2_weak_upgrade_fail_min.hako @@ -0,0 +1,28 @@ +// Phase 285 P2: WeakRef upgrade failure test (explicit drop + null observation) +// SSOT: docs/reference/language/lifecycle.md - weak_to_strong() failure → null +// +// Test: weak_to_strong() fails after explicit drop (x = null) +// Note: Uses explicit drop instead of block scope (block scope drop conformance is separate task) +// Expected: exit 1 (weak_to_strong returns null as expected) +// KNOWN ISSUE: Currently returns exit 0 (hidden root keeps strong ref alive) +// VM: SKIP (Phase 285 P2.1 investigation required) +// LLVM: SKIP (same issue expected) + +box SomeBox { + x +} + +static box Main { + main() { + local x = new SomeBox() + x.x = 123 + local w = weak x + x = null // 明示的に strong を切る + local y = w.weak_to_strong() // 失敗して null + if y == null { + return 1 // 期待通り(weak_to_strong 失敗) + } else { + return 0 // 予期しない成功 + } + } +} diff --git a/apps/tests/phase285_weak_basic.hako b/apps/tests/phase285_weak_basic.hako index 6d8c1658..67fa6b3f 100644 --- a/apps/tests/phase285_weak_basic.hako +++ b/apps/tests/phase285_weak_basic.hako @@ -30,6 +30,6 @@ static box Main { } print("ok: weak and weak_to_strong work correctly") - return 0 + return 2 } } diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md index d3fdd3d9..96e30242 100644 --- a/docs/development/current/main/10-Now.md +++ b/docs/development/current/main/10-Now.md @@ -1,8 +1,16 @@ # Self Current Task — Now (main) -## Current Focus: Phase 285 P1/P2 / Phase 287 計画 +## Current Focus: Phase 285 P2.1(Hidden Root Investigation)/ Phase 287 計画 -Phase 284 P2 + Phase 285 P0 完了。次は Phase 285 P1(棚卸し)または Phase 287(Normalizer Hygiene)。 +Phase 285 P2 完了。weak 成功パターンを smoke 固定、失敗パターンは hidden root 問題で SKIP。次は P2.1(investigation)または Phase 287(Normalizer Hygiene)。 + +**2025-12-26: Phase 285 P2 完了** ✅ +- weak の意味論(`weak ` + `weak_to_strong()` 成功)を integration smoke で固定 +- Fixture A(成功パターン): exit 2 で明確化、VM/LLVM PASS +- Fixture B(失敗パターン): 明示 drop (`x = null`) 方式、hidden root 問題で SKIP +- Block scope drop conformance は別タスク(P2 では扱わない) +- P2.1(investigation)提案: hidden root の原因特定 +- quick smoke 154/154 PASS 維持 **2025-12-26: Phase 285 P0 完了** ✅ - 言語 SSOT との境界明文化(lifecycle.md, types.md) diff --git a/docs/development/current/main/phases/phase-285/P0-INSTRUCTIONS.md b/docs/development/current/main/phases/phase-285/P0-INSTRUCTIONS.md index 84905f0c..68b4d76a 100644 --- a/docs/development/current/main/phases/phase-285/P0-INSTRUCTIONS.md +++ b/docs/development/current/main/phases/phase-285/P0-INSTRUCTIONS.md @@ -1,3 +1,11 @@ +Status: Active +Date: 2025-12-26 +Scope: Phase 285 P0(docs-only)手順書。コード変更なしで “Box lifecycle / weakref / finalization / GC” の SSOT と差分運用を固定する。 +Related: +- docs/development/current/main/phases/phase-285/README.md +- docs/reference/language/lifecycle.md +- docs/reference/language/types.md + # Phase 285 P0(docs-only): Box lifecycle / weakref / finalization / GC SSOT 目的: “実装が仕様” になっている Box の寿命・弱参照・最終化を、docs と smoke の SSOT に固定する。 @@ -21,12 +29,15 @@ - [ ] “roots” は何か(stack/local/global/handle/plugin 等) - [ ] strong/weak の意味(weak_to_strong の成否条件) -- [ ] strong/weak の意味(weak_to_strong の成否条件) - [ ] finalizer はあるか/いつ発火するか/何が禁止か - [ ] GC/解放のトリガ(自動/手動/閾値/テスト用) - [ ] VM と LLVM harness の差分(未対応の場合の方針) - 分類: (A) 仕様通り / (B) 未実装 / (C) 既知バグ / (D) 仕様外(禁止) +追加ルール(運用): +- [ ] 新しい環境変数トグルは増やさない(既存の診断導線の範囲で) +- [ ] 未対応は隠さず、smoke で理由付き SKIP として固定する(silent fallback 禁止) + ## 3. 次(P1/P2)への導線(箇条書きでOK) - P1(investigation): 棚卸し対象のファイル一覧と観測ポイント diff --git a/docs/development/current/main/phases/phase-285/README.md b/docs/development/current/main/phases/phase-285/README.md index e5809b38..783edfe5 100644 --- a/docs/development/current/main/phases/phase-285/README.md +++ b/docs/development/current/main/phases/phase-285/README.md @@ -208,29 +208,78 @@ If any of the following are missing, treat weak smokes as **unsupported** and sc - VM: `scope_tracker.rs` の `pop_scope()` 時に InstanceBox `.fini()` を呼び出し(実装あり) - LLVM: 対応する finalizer 呼び出し機構がない(現在 harness は scope 管理を持たない) -### P2(smoke) +### P2(smoke)✅ COMPLETE (2025-12-26) -**目的**: weakref の最小 fixture/smoke を作り、挙動を固定する +**目的**: weak の意味論(`weak ` と `weak_to_strong()` の成功/失敗、失敗→null)を integration smoke で固定 -#### P2 smoke 候補(絞り込み済み) +**観測点**: **exit code で判定**(stdout は揺れやすいため、exit code を SSOT とする) -| smoke | 内容 | 期待値 | 優先度 | -|-------|------|--------|--------| -| `phase285_weak_basic_vm.sh` | 既存 weak basic smoke(`weak x` + `weak_to_strong()` 成功) | PASS(既に存在) | 既存 | -| `phase285_weak_to_strong_fail_vm.sh` | weak_to_strong 失敗観測(Void = null) | PASS(`WeakRef(null)` または `void` 確認) | **新規** | -| `phase285_weak_cycle_report_vm.sh` | 強参照サイクルで leak report | PASS(exit-time leak report で検出) | **新規** | -| `phase285_weak_basic_llvm.sh` | LLVM weak 基本動作確認 | PASS(VM と同一動作) | **新規** | +#### 実装内容 -**LLVM 扱い**: -- WeakNew/WeakLoad は **両バックエンド実装済み** → smoke は `--backend vm` と `--backend llvm` 両方実行 -- Finalizer は **両バックエンド未実装** → **P2 では scope finalization のテストを行わない** -- 未対応機能: 理由付き SKIP(`test_skip "reason"`) +**Fixture A(成功パターン)**: +- ファイル: `apps/tests/phase285_weak_basic.hako`(既存、修正) +- 内容: `weak x` → `weak_to_strong()` 成功 → **exit 2**(非ゼロ成功コード) +- 修正理由: fail=1, success=2 で明確化("何も起きてない exit 0" と区別) + +**Fixture B(失敗パターン)**: +- ファイル: `apps/tests/phase285_p2_weak_upgrade_fail_min.hako`(**新規**) +- 内容: **明示的 drop (`x = null`)** 後の `weak_to_strong()` 失敗 → `null` 観測 → exit 1 +- Box定義: `SomeBox { x }` を使用(`phase285_weak_basic.hako` と同じ、環境依存回避) +- **スコープ戦略**: ブロックスコープ `{ }` drop ではなく明示 drop `x = null` を使用 + - 理由: ブロックスコープ drop の conformance は別タスク(block scope 寿命は未整合の可能性あり) + - P2 の weak-fail は明示 drop 方式で固定 + +**VM smoke scripts(2本)**: +1. `tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_success_vm.sh` + - Fixture A 実行、期待: **exit 2** → **PASS** +2. `tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_fail_vm.sh` + - Fixture B 実行、**SKIP**(既知の hidden root 問題) + +**LLVM smoke scripts(2本)**: +3. `tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_success_llvm.sh` + - Fixture A 実行(LLVM harness)、期待: **exit 2** → **PASS** または理由付き SKIP +4. `tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_fail_llvm.sh` + - Fixture B 実行(LLVM harness)、**SKIP**(既知の hidden root 問題、VM と同じ) + +**既知の問題(Fixture B)**: +- **Hidden root issue**: `x = null` で明示 drop しても weak_to_strong が成功(exit 0) +- 原因: 隠れた root が strong ref を保持している可能性 +- 対応: Phase 285 P2.1 (investigation) で root 保持箇所を棚卸し + +**LLVM 対応**: +- WeakNew/WeakLoad は **両バックエンド実装済み**(P1 確認済み)→ PASS が理想 +- **SKIP 許容**: harness 不在/feature 無しの環境では理由付き SKIP を必ず許容(Phase 284 P2 と同じ運用) - silent fallback 禁止 +**完了条件**: +- ✅ Fixture A 修正(exit 0 → exit 2) +- ✅ Fixture B 新規作成(明示 drop 方式) +- ✅ VM smoke success PASS +- ✅ LLVM smoke success PASS(または理由付き SKIP) +- ✅ VM/LLVM smoke fail SKIP(hidden root 問題で理由付き) +- ✅ quick 154/154 PASS 維持 +- ✅ Finalizer は「VM のみ・LLVM 未対応」と差分表に明記済み(上記 VM/LLVM 差分分類テーブル参照) + **P2 で扱わない項目**: -- Finalizer (`fini()`) の統一テスト → Phase 286+ で統一化予定 +- **Block scope drop conformance** → 別タスク(未整合の可能性あり) +- **Hidden root investigation** → Phase 285 P2.1 で root 保持箇所を棚卸し +- Finalizer (`fini()`) の統一テスト → 両バックエンド未実装のため Phase 286+ で検討 - GC cycle collection → Reference Count のみで既知の制約 +### P2.1(investigation)- 提案 + +**目的**: Hidden root 問題の原因特定(`x = null` で明示 drop しても weak_to_strong が成功する理由) + +**調査対象**: +- VM の strong ref 保持箇所(VMValue/registry/handles/scope_tracker/等) +- Arc drop タイミング(明示 `x = null` 代入時に Arc が drop されるか) +- 隠れた root 候補(MIR interpreter state/local variables/等) + +**期待成果**: +- Hidden root の特定(どこが strong ref を保持しているか) +- 分類: (B) 未実装 / (C) 既知バグ / (D) 仕様外 +- 修正方針の提示(Phase 286+ で修正) + ## Non-goals - GC アルゴリズム刷新(RC→tracing 等の設計変更) diff --git a/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_fail_llvm.sh b/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_fail_llvm.sh new file mode 100644 index 00000000..23b28c47 --- /dev/null +++ b/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_fail_llvm.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Phase 285 P2: "weak upgrade failure" LLVM harness smoke test +# Purpose: Verify weak_to_strong() fails (returns null) after explicit drop +# Uses phase285_p2_weak_upgrade_fail_min.hako +# +# SKIP: Known issue - hidden root keeps strong ref alive even after x=null (same as VM) +# Investigation required in Phase 285 P2.1 to identify root holding location + +source "$(dirname "$0")/../../../lib/test_runner.sh" +export SMOKES_USE_PYVM=0 +require_env || exit 2 + +test_skip "phase285_p2_weak_upgrade_fail_llvm" "Hidden root issue: strong ref not dropped after x=null (Phase 285 P2.1 investigation required, same as VM)" +exit 0 diff --git a/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_fail_vm.sh b/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_fail_vm.sh new file mode 100644 index 00000000..af2e381e --- /dev/null +++ b/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_fail_vm.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Phase 285 P2: "weak upgrade failure" VM smoke test +# Purpose: Verify weak_to_strong() fails (returns null) after explicit drop +# Uses phase285_p2_weak_upgrade_fail_min.hako +# +# SKIP: Known issue - hidden root keeps strong ref alive even after x=null +# Investigation required in Phase 285 P2.1 to identify root holding location + +source "$(dirname "$0")/../../../lib/test_runner.sh" +export SMOKES_USE_PYVM=0 +require_env || exit 2 + +test_skip "phase285_p2_weak_upgrade_fail_vm" "Hidden root issue: strong ref not dropped after x=null (Phase 285 P2.1 investigation required)" +exit 0 diff --git a/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_success_llvm.sh b/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_success_llvm.sh new file mode 100644 index 00000000..d41fea83 --- /dev/null +++ b/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_success_llvm.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Phase 285 P2: "weak upgrade success" LLVM harness smoke test +# Purpose: Verify weak_to_strong() succeeds when strong ref is alive (VM/LLVM parity) +# Uses existing phase285_weak_basic.hako (modified: exit 0 → exit 2) +# +# Expected: exit code 2 (same as VM) or SKIP if LLVM backend not available +# SKIP: If LLVM backend/harness not available in build + +source "$(dirname "$0")/../../../lib/test_runner.sh" +export SMOKES_USE_PYVM=0 +require_env || exit 2 + +# LLVM feature check (v2 smoke SKIP convention) +if ! "$NYASH_BIN" --version 2>/dev/null | grep -q "features.*llvm"; then + test_skip "phase285_p2_weak_upgrade_success_llvm: LLVM backend not available in this build" + exit 0 +fi + +INPUT="$NYASH_ROOT/apps/tests/phase285_weak_basic.hako" +RUN_TIMEOUT_SECS=${RUN_TIMEOUT_SECS:-30} + +set +e +OUTPUT=$(timeout "$RUN_TIMEOUT_SECS" env NYASH_LLVM_USE_HARNESS=1 NYASH_DISABLE_PLUGINS=1 "$NYASH_BIN" --backend llvm "$INPUT" 2>&1) +EXIT_CODE=$? +set -e + +if [ "$EXIT_CODE" -eq 124 ]; then + test_fail "phase285_p2_weak_upgrade_success_llvm: timed out (>${RUN_TIMEOUT_SECS}s)" + exit 1 +fi + +# Expected: exit code 2 (same as VM) +if [ "$EXIT_CODE" -eq 2 ]; then + test_pass "phase285_p2_weak_upgrade_success_llvm: weak_to_strong succeeded (exit: 2, VM/LLVM parity)" + exit 0 +else + echo "[FAIL] Unexpected result (expected: exit 2, same as VM)" + echo "[INFO] Exit code: $EXIT_CODE" + echo "[INFO] Output:" + echo "$OUTPUT" | head -n 30 || true + test_fail "phase285_p2_weak_upgrade_success_llvm: VM/LLVM parity failed" + exit 1 +fi diff --git a/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_success_vm.sh b/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_success_vm.sh new file mode 100644 index 00000000..b38afbb5 --- /dev/null +++ b/tools/smokes/v2/profiles/integration/apps/phase285_p2_weak_upgrade_success_vm.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Phase 285 P2: "weak upgrade success" VM smoke test +# Purpose: Verify weak_to_strong() succeeds when strong ref is alive (VM/LLVM parity) +# Uses existing phase285_weak_basic.hako (modified: exit 0 → exit 2) +# +# Expected: exit code 2 (non-zero success code, distinguishes from "nothing happened") + +source "$(dirname "$0")/../../../lib/test_runner.sh" +export SMOKES_USE_PYVM=0 +require_env || exit 2 + +INPUT="$NYASH_ROOT/apps/tests/phase285_weak_basic.hako" +RUN_TIMEOUT_SECS=${RUN_TIMEOUT_SECS:-30} + +set +e +OUTPUT=$(timeout "$RUN_TIMEOUT_SECS" "$NYASH_BIN" --backend vm "$INPUT" 2>&1) +EXIT_CODE=$? +set -e + +if [ "$EXIT_CODE" -eq 124 ]; then + test_fail "phase285_p2_weak_upgrade_success_vm: timed out (>${RUN_TIMEOUT_SECS}s)" + exit 1 +fi + +# Expected: exit code 2 (non-zero success code) +if [ "$EXIT_CODE" -eq 2 ]; then + test_pass "phase285_p2_weak_upgrade_success_vm: weak_to_strong succeeded (exit: 2)" + exit 0 +else + echo "[FAIL] Unexpected result (expected: exit 2)" + echo "[INFO] Exit code: $EXIT_CODE" + echo "[INFO] Output:" + echo "$OUTPUT" | head -n 30 || true + test_fail "phase285_p2_weak_upgrade_success_vm: exit code mismatch" + exit 1 +fi diff --git a/tools/smokes/v2/profiles/quick/env/phase286_deprecated_env_warnings.sh b/tools/smokes/v2/profiles/quick/env/phase286_deprecated_env_warnings.sh index ec7a7b4c..c266f984 100644 --- a/tools/smokes/v2/profiles/quick/env/phase286_deprecated_env_warnings.sh +++ b/tools/smokes/v2/profiles/quick/env/phase286_deprecated_env_warnings.sh @@ -31,9 +31,9 @@ OUTPUT_UNSET=$(env -u NYASH_MACRO_TOPLEVEL_ALLOW -u NYASH_MACRO_BOX_CHILD_RUNNER EXIT_CODE_UNSET=$? set -e -# Should succeed (exit code 0) -if [[ $EXIT_CODE_UNSET -ne 0 ]]; then - echo "❌ FAIL: Test file should run successfully (got exit code $EXIT_CODE_UNSET)" +# Should succeed (exit code 2, Phase 285 P2: non-zero success code) +if [[ $EXIT_CODE_UNSET -ne 2 ]]; then + echo "❌ FAIL: Test file should run successfully (got exit code $EXIT_CODE_UNSET, expected 2)" echo "Output: $OUTPUT_UNSET" exit 1 fi @@ -55,9 +55,9 @@ OUTPUT_SET=$(NYASH_MACRO_TOPLEVEL_ALLOW=1 "$HAKORUNE" "$TEST_FILE" 2>&1) EXIT_CODE_SET=$? set -e -# Should succeed (exit code 0) -if [[ $EXIT_CODE_SET -ne 0 ]]; then - echo "❌ FAIL: Test file should run successfully with deprecated env (got exit code $EXIT_CODE_SET)" +# Should succeed (exit code 2, Phase 285 P2: non-zero success code) +if [[ $EXIT_CODE_SET -ne 2 ]]; then + echo "❌ FAIL: Test file should run successfully with deprecated env (got exit code $EXIT_CODE_SET, expected 2)" echo "Output: $OUTPUT_SET" exit 1 fi @@ -79,9 +79,9 @@ OUTPUT_SET2=$(NYASH_MACRO_BOX_CHILD_RUNNER=1 "$HAKORUNE" "$TEST_FILE" 2>&1) EXIT_CODE_SET2=$? set -e -# Should succeed (exit code 0) -if [[ $EXIT_CODE_SET2 -ne 0 ]]; then - echo "❌ FAIL: Test file should run successfully with deprecated env (got exit code $EXIT_CODE_SET2)" +# Should succeed (exit code 2, Phase 285 P2: non-zero success code) +if [[ $EXIT_CODE_SET2 -ne 2 ]]; then + echo "❌ FAIL: Test file should run successfully with deprecated env (got exit code $EXIT_CODE_SET2, expected 2)" echo "Output: $OUTPUT_SET2" exit 1 fi diff --git a/tools/smokes/v2/profiles/quick/lifecycle/phase285_weak_basic_llvm.sh b/tools/smokes/v2/profiles/quick/lifecycle/phase285_weak_basic_llvm.sh index fa83f30a..ac04f63e 100644 --- a/tools/smokes/v2/profiles/quick/lifecycle/phase285_weak_basic_llvm.sh +++ b/tools/smokes/v2/profiles/quick/lifecycle/phase285_weak_basic_llvm.sh @@ -1,10 +1,45 @@ #!/bin/bash -# phase285_weak_basic_llvm.sh - Phase 285A0.1: WeakRef basic smoke test (LLVM) +# phase285_weak_basic_llvm.sh - Phase 285 P2: WeakRef basic smoke test (LLVM harness) # -# SKIP: WeakRef (weak/weak_to_strong) not yet supported in LLVM harness (Phase 285LLVM-1) +# Verifies weak and weak_to_strong() work correctly in LLVM harness (P1: WeakNew/WeakLoad implemented) +# Expected: exit code 2 (non-zero success, VM/LLVM parity) +# SSOT: docs/reference/language/lifecycle.md:179 source "$(dirname "$0")/../../../lib/test_runner.sh" +export SMOKES_USE_PYVM=0 require_env || exit 2 -test_skip "phase285_weak_basic_llvm" "WeakRef (weak/weak_to_strong) not yet supported in LLVM harness (Phase 285LLVM-1)" +# LLVM feature check (SKIP if not available) +if ! "$NYASH_BIN" --version 2>/dev/null | grep -q "features.*llvm"; then + test_skip "phase285_weak_basic_llvm" "LLVM backend not available in this build" + exit 0 +fi + +FIXTURE="$NYASH_ROOT/apps/tests/phase285_weak_basic.hako" + +output=$(NYASH_LLVM_USE_HARNESS=1 NYASH_DISABLE_PLUGINS=1 "$NYASH_BIN" --backend llvm "$FIXTURE" 2>&1) +exit_code=$? + +# Check for success marker +if ! echo "$output" | grep -q "ok: weak and weak_to_strong work correctly"; then + log_error "phase285_weak_basic_llvm: Expected 'ok: weak and weak_to_strong work correctly'" + echo "$output" + exit 1 +fi + +# Check for failure markers +if echo "$output" | grep -q "ng:"; then + log_error "phase285_weak_basic_llvm: Found 'ng:' in output (test failure)" + echo "$output" + exit 1 +fi + +# Check exit code (Phase 285 P2: exit 2 = success, VM/LLVM parity) +if [ "$exit_code" -ne 2 ]; then + log_error "phase285_weak_basic_llvm: Expected exit code 2 (non-zero success), got: $exit_code" + echo "$output" + exit 1 +fi + +log_success "phase285_weak_basic_llvm: WeakRef basic test passed (LLVM harness)" exit 0 diff --git a/tools/smokes/v2/profiles/quick/lifecycle/phase285_weak_basic_vm.sh b/tools/smokes/v2/profiles/quick/lifecycle/phase285_weak_basic_vm.sh index e7baeb09..a5c3629f 100644 --- a/tools/smokes/v2/profiles/quick/lifecycle/phase285_weak_basic_vm.sh +++ b/tools/smokes/v2/profiles/quick/lifecycle/phase285_weak_basic_vm.sh @@ -28,9 +28,9 @@ if echo "$output" | grep -q "ng:"; then exit 1 fi -# Check exit code -if [ "$exit_code" -ne 0 ]; then - log_error "phase285_weak_basic_vm: Non-zero exit code: $exit_code" +# Check exit code (Phase 285 P2: exit 2 = success) +if [ "$exit_code" -ne 2 ]; then + log_error "phase285_weak_basic_vm: Expected exit code 2 (non-zero success), got: $exit_code" echo "$output" exit 1 fi