Core レビュー
作成日: 2026-04-25
対象: nepl-core/src/**
レビュー範囲
確認した主要ファイルは次の通りです。
| 区分 | ファイル |
|---|---|
| パイプライン | lib.rs, compiler.rs, loader.rs, module_graph.rs, target_precheck.rs |
| frontend | lexer.rs, parser.rs, ast.rs, nm.rs |
| 型・名前解決 | types.rs, typecheck.rs, resolve.rs, name_resolve.rs, effects.rs |
| HIR / pass | hir.rs, passes/move_check.rs, passes/drop_insertion.rs, passes/codegen_precheck.rs |
| codegen | codegen_wasm.rs, codegen_llvm.rs, wasm_shared.rs, runtime_helpers.rs, monomorphize.rs |
| 診断 | diagnostic.rs, diagnostic_ids.rs, error.rs, span.rs, log.rs |
行数上の最大リスクは typecheck.rs 8759 行、parser.rs 3891 行、codegen_llvm.rs 3528 行、codegen_wasm.rs 2339 行です。設計書 doc/neplg3/impl/compiler_structure.md が指摘している巨大ファイル問題は、現行コードにもそのまま残っています。
総評
NEPLg2.0 の core は、動く経路を増やすために型検査・名前解決・HIR 生成・trait 解決・effect 判定・一部の codegen 前処理が密結合しています。特に typecheck.rs の hot path は、全走査、Vec::remove、TypeCtx clone、BTreeMap 線形探索を多用しており、「コンパイラが異常に遅い」原因候補として優先的に分解・測定すべきです。
また、core は no_std 境界、診断、import semantics、Resource IR のいずれも計画とずれており、局所パッチではなく pipeline stage ごとの分割が必要です。
RV-CORE-001: core の no_std 境界が崩れている
- 解決済: true
- 状態: verified
- 優先度: P1
- 種別: architecture
- 対象:
nepl-core/Cargo.toml,nepl-core/src/lib.rs,nepl-core/src/source_map.rs,nepl-core/src/loader.rs,nepl-core/src/compiler.rs,nepl-core/src/typecheck.rs,nepl-core/src/codegen_wasm.rs,nepl-core/src/monomorphize.rs,nepl-core/src/types.rs
根拠
nepl-core/src/lib.rs:1: crate root は#![no_std]。nepl-core/src/compiler.rs:2:extern crate std;が unconditional。nepl-core/src/typecheck.rs:3:extern crate std;が unconditional。nepl-core/src/typecheck.rs:9:std::path::Pathを core 側で直接使用。nepl-core/src/codegen_wasm.rs:4: wasm backend もextern crate std;を持つ。
問題
plan.md と doc/self_host.md は compiler core を WASI なしの純粋 core として扱う方針ですが、現行 core は std に直接依存しています。nepl-core を wasm32/no_std 対象へ切り出す前提が崩れ、CLI と core の責務分離も不明確です。
影響
core をブラウザ / WASM / self-host bootstrap で再利用する際に、host I/O や path 処理が混入します。将来の stdlib/neplg3/core へ移植するときも、どこまでが pure compiler core なのか判別しにくくなります。
修正方針
SourceMap を loader.rs から source_map.rs へ切り出し、path は PathBuf ではなく alloc::String の source label として保持するようにしました。host filesystem に依存する loader / module_graph / resolve は target_os = "none" では公開しない module に分離し、pure core 側の compiler / typecheck は source_map::SourceMap だけを見る構成に変更しました。
thiserror / walkdir は nepl-core の未使用依存で、wasm32v1-none では transitive に std を要求していたため削除しました。wasm-encoder と wasmparser は default feature を無効化し、validator に必要な validate feature だけを有効化しています。
debug logging は host target でのみ std::eprintln! を使い、target_os = "none" では format 引数を型検査するだけの no-op macro に集約しました。typecheck.rs の default import alias 処理は std::path::Path へ依存せず、import path 文字列から alias を導出します。
検証
cargo check -p nepl-core --target wasm32v1-none: passcargo fmt --all --check: passcargo check -p nepl-core: passcargo check --workspace: passcargo test -p nepl-core: passtrunk build: passnode tests/compiler/tree/run.js:total=19,passed=19,failed=0node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests-rv-core-001.json:caseCount=13,passedCount=13,failedCount=0git diff --check: pass
RV-CORE-002: typecheck.rs が巨大化しすぎて責務が分離できていない
- 解決済: true
- 状態: verified
- 優先度: P1
- 種別: architecture
- 対象:
nepl-core/src/typecheck.rs
根拠
nepl-core/src/typecheck.rs: 8759 行。nepl-core/src/typecheck.rs:566: instantiation cache を型検査本体が直接持つ。nepl-core/src/typecheck.rs:7777:Env/Scope実装も同じファイル内。nepl-core/src/typecheck.rs:8354:LabelEnv/StringTableなど補助構造も同居。
問題
型推論、trait capability、overload、名前探索、HIR lowering、effect 判定、import alias 補助、diagnostic recovery が 1 ファイルに集中しています。局所修正が別機能へ波及しやすく、性能改善も profiling point を切りにくい状態です。
影響
既知バグの根本原因を追いにくく、修正のたびに回帰範囲が広がります。doc/neplg3/impl/compiler_structure.md で示されている check/, ty/, resolve/, hir/ 分割方針との乖離も大きいです。
修正方針
短期的には Env、overload 解決、prefix reduction、trait impl 検査を別 module へ切り出します。中期的には AST flat list から HIR への lowering を型検査結果と分離し、resolve / ty / check の依存方向を固定します。
検証
分割ごとに既存 tests/compiler/** と stdlib doctest を走らせ、ファイル移動だけの段階では出力 JSON の差分がないことを確認します。
RV-CORE-003: reduce_calls が O(n^2) 化しやすく固定上限で正当な入力を落とす
- 解決済: true
- 状態: verified
- 優先度: P0
- 種別: performance
- 対象:
nepl-core/src/typecheck.rs,nepl-core/tests/call_reduction.rs,tests/compiler/tree/19_call_reduction_large_prefix.js
根拠
- 旧実装の
reduce_callsはmax_iterations = 1000の固定上限で停止していた。 - 旧実装の
reduce_calls/reduce_calls_guardedは各 iteration で stack を後ろから全走査していた。 - 旧実装は引数取り出しに
stack.remove(func_pos + 1)、callee 取り出しにstack.remove(func_pos)を使っていた。 - guarded reduction 側にも同じ固定上限と全走査 / middle remove が重複していた。
問題
prefix expression の縮約が「全走査して middle remove」を繰り返すため、長い式や overload が多い式で O(n^2) 以上になりやすいです。さらに iteration 上限が 1000 固定なので、入力が正しくても TypeCallReductionLimitExceeded になる可能性があります。
対応中に、縮約上限を外すだけでは深い HIR の後段 traversal / codegen で native stack overflow が残ることも確認しました。この残件は RV-CORE-015 として分離し、ここでは reduce_calls と typecheck/semantics 段階の根本原因を修正対象にしています。
影響
コンパイル時間が式長と候補数に対して急激に増えます。stdlib の巨大な関数や tutorial の複雑な式で体感速度が悪化し、CI timeout の原因にもなります。
修正方針
reduce_calls / reduce_calls_guarded を共通の縮約ループへ統合し、open_calls を末尾候補スタックとして使うようにしました。通常の prefix chain では毎 iteration の全 stack 走査を行わず、callee と引数は連続範囲の drain で取り出すため、Vec::remove の繰り返しを避けます。
固定の 1000 回上限は削除し、0-arity などで stack 長が縮まらない場合だけ状態キーで進捗なしを検出する方式にしました。また、縮約済みの深い HIR を毎回 clone していた通常 call の引数生成と check_prefix 戻り値生成を move ベースに変更し、長い chain の typecheck が再帰 clone で stack overflow しないようにしました。型 ID 解決の HIR 式走査も明示スタックに置き換えています。
検証
確認済み:
cargo check -p nepl-corecargo test -p nepl-core --test call_reductiontrunk buildnode tests/compiler/tree/run.js(total=19,passed=19,failed=0)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests.json(caseCount=13,passedCount=13,failedCount=0)
追加した fixture:
nepl-core/tests/call_reduction.rs: 1105 個の prefix call chain が typecheck できることを確認。tests/compiler/tree/19_call_reduction_large_prefix.js: wasm API の semantics 経由で 1105-call chain がok=trueになることを JSON 出力で確認。
未解決の後段問題:
cargo run -p nepl-cli -- -i tmp/rv-core-003-large.nepl --check --target coreは、typecheck 後の compile pipeline で native stack overflow になる。この codegen /--check側の深い HIR traversal はRV-CORE-015で追跡します。
RV-CORE-004: overload 解決が候補ごとに TypeCtx 全体を clone している
- 解決済: true
- 状態: verified
- 優先度: P0
- 種別: performance
- 対象:
nepl-core/src/types.rs,nepl-core/src/typecheck.rs,nepl-core/src/codegen_llvm.rs,nepl-core/src/codegen_wasm.rs,nepl-core/tests/typectx_checkpoint.rs
根拠
nepl-core/src/typecheck.rs:6497: overload candidate ごとにlet mut tmp_ctx = self.ctx.clone();。nepl-core/src/typecheck.rs:7234: 関数値解決でもTypeCtxclone。nepl-core/src/codegen_llvm.rs:2976付近: layout 計算でtypes.clone()を使う。nepl-core/src/codegen_wasm.rs:75以降: generic Apply の storage 計算でctx.clone()を使う。
問題
TypeCtx は arena と型変数状態を持つため、clone は候補数と型数に比例して重くなります。overload が stdlib 全体に広がるほど、1 call の型解決で大量の一時 arena clone が発生します。
影響
「コンパイラが異常に遅い」問題の主要候補です。特に add, eq, len, get, push のような多重定義名が頻出する stdlib / tutorial で悪化します。
修正方針
候補検査用の checkpoint/rollback を TypeCtx に実装し、候補ごとの arena 全体 clone を除去しました。型変数束縛と named type table の変更は undo log で戻し、copy/drop trait target と copy trait flag は checkpoint の長さ・値へ復元します。これにより、候補検査中の一時的な instantiate / unify / substitute が外側の型文脈へ漏れません。
overload candidate 走査と関数値引数の候補照合は、TypeCtx::clone() ではなく checkpoint 上の一時変更として評価し、各候補の終了時に rollback します。codegen の generic Apply layout 計算は、TypeCtx を clone して substitute する方式をやめ、type parameter mapping を引き回して storage size / align / field offset を計算する形に変更しました。
検証
確認済み:
cargo check -p nepl-corecargo test -p nepl-core --test typectx_checkpoint(2 passed)node nodesrc/tests.js -i tests/compiler/overload.n.md --no-tree -o tmp/overload-rv-core-004.json -j 1(total=45,passed=45,failed=0)trunk buildnode tests/compiler/tree/run.js(total=19,passed=19,failed=0)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests.json(caseCount=13,passedCount=13,failedCount=0)
追加した fixture:
nepl-core/tests/typectx_checkpoint.rs: checkpoint が型変数束縛、一時 arena entry、named type table、copy/drop trait target、copy trait flag を復元することを確認。
補足:
cargo test -p nepl-core --test overloadは、HEAD から分けた baseline worktree でも同じ 3 件が失敗する既存状態でした。RV-CORE-004 の回帰判定には、現行のtests/compiler/overload.n.mddoctest を使用しています。
RV-CORE-005: loader が import clause を無視して全 import をフラット結合している
- 解決済: true
- 状態: verified
- 優先度: P1
- 種別: bug
- 対象:
nepl-core/src/loader.rs,nepl-core/src/parser.rs,nepl-core/src/typecheck.rs
根拠
nepl-core/src/parser.rs:458:ImportClauseはDefaultAlias,Alias,Open,Selective,Mergeまで parse している。nepl-core/src/loader.rs:436:Directive::Import { path, .. }として clause を捨てている。nepl-core/src/loader.rs:457: imported module の root items を clause に関係なく親へ push。nepl-core/src/typecheck.rs:8310: qualified alias map は後段で別途作っているが、loader の item 可視性は制御していない。
問題
#import "x" as name や as { a } の構文があっても、loader は対象 module の item をすべて親 module に混ぜます。alias / selective import は型検査の一部補助にしか効かず、未選択 symbol が見えてしまう可能性があります。
影響
名前衝突、意図しない overload 候補増加、import 順依存の挙動が起きます。性能面でも、使っていない module の item まで常に型検査候補になります。
修正方針
loader は AST を物理的に結合せず、module graph と export/import table を構築するだけにします。可視性は resolve stage で clause に従って解決し、HIR には canonical symbol を渡します。
対応
現行 pipeline は qualified import と codegen が loader の flat merge 済み AST を前提にしているため、この issue では main typecheck の名前解決境界を根本修正しました。SourceMap と import directive の span.file_id から「参照元 file -> import 先 file -> 未修飾可視性」を構築し、未修飾 lookup を import clause で必ず filter するようにしています。
as name / default alias は未修飾参照から隠し、qualified alias は既存の alias target map で維持します。as { a } は選択した symbol のみ、as { a as b } は alias 名のみを公開します。as * / as @merge と selective glob は既存 module_graph の open semantics に合わせて全 symbol を未修飾公開します。
可視性 table は #include と #prelude / default prelude も扱い、as * / as @merge / prelude / include の open closure は参照元へ伝播させます。一方で selective import の import 先がさらに open import している場合でも、未選択の transitive symbol が参照元へ漏れないよう、直接可視性がない target file は未修飾 lookup から除外します。
相対 import の ./dep が source map suffix と一致しない経路も同時に修正し、import target file の正規化を qualified / unqualified lookup で共通化しました。loader の物理非結合化は、既存の RV-CORE-010 で main pipeline と resolve.rs を統合する時に扱います。
検証
cargo fmt --all --checkcargo test -p nepl-core --test import_clause -- --nocapture: 7 passedcargo check -p nepl-corecargo test -p nepl-corenode tests/compiler/tree/run.js: 19/19 passedtrunk buildcargo check --workspacenode nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests-rv-core-005.json: 13/13 passed
RV-CORE-006: 通常実行でデバッグ出力が stderr へ漏れる
- 解決済: true
- 状態: verified
- 優先度: P1
- 種別: bug
- 対象:
nepl-core/src/loader.rs,nepl-core/src/types.rs,nepl-cli/src/main.rs
根拠
nepl-core/src/loader.rs:166:load_inline_with_providerが常時eprintln!。nepl-core/src/loader.rs:271:load_from_contents_withが path/canon を出す。nepl-core/src/loader.rs:320:load_fileが常時 loading log を出す。nepl-core/src/typecheck.rs:1965: diagnostics summary を stderr 出力する経路がある。nepl-core/src/types.rs:1527:type_to_stringcycle で常時eprintln!。
問題
verbose option と関係なく stderr が汚染されます。compiler を library として使う web / test runner / CLI で、stderr を診断やプログラム出力として扱う経路と衝突します。
影響
doctest の stderr 比較、JSON 出力、CI log が不安定になります。大量 import ではログ出力そのものも性能劣化要因になります。
修正方針
core から直接 eprintln! を排除し、Diagnostic または injectable logger に統一します。debug-only log は crate::log::is_verbose() を通し、default は完全に無出力にします。
対応
loader の [Loader] 出力を loader_log! に集約し、crate::log::is_verbose() が有効な場合だけ stderr へ出すようにしました。type_to_string の cycle 検出ログも verbose gate 配下へ移動し、通常の型文字列化で stderr を汚染しないようにしました。
CLI は loader を呼ぶ前に nepl_core::log::set_verbose(cli.verbose) を設定するようにし、--verbose が core loader にも伝播するようにしました。CLI 自身の DEBUG: 出力は既存の RV-CLI-002 として別 issue で扱います。
検証
確認済み:
cargo fmt --all --checkcargo check -p nepl-corecargo build -p nepl-clitarget/debug/nepl-cli.exe --check -i tmp/rv-core-003-large.nepl --target coreで[Loader]出力 0 件target/debug/nepl-cli.exe --verbose --check -i tmp/rv-core-003-large.nepl --target coreで[Loader]出力ありcargo check --workspacetrunk buildnode tests/compiler/tree/run.js:total=19,passed=19,failed=0node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests.json:13/13 passed
RV-CORE-007: codegen が診断ではなく panic で落ちる経路を多数持つ
- 解決済: true
- 状態: verified
- 優先度: P0
- 種別: bug
- 対象:
nepl-core/src/codegen_wasm.rs,nepl-core/src/codegen_llvm.rs
根拠
nepl-core/src/codegen_wasm.rs:476: unsupported extern signature でpanic!。nepl-core/src/codegen_wasm.rs:504: unsupported function signature でpanic!。nepl-core/src/codegen_wasm.rs:1123: string literal lookup failure でpanic!。nepl-core/src/codegen_wasm.rs:1140: unknown variable でpanic!。nepl-core/src/codegen_llvm.rs:1391: unknown variable でpanic!。nepl-core/src/codegen_llvm.rs:2863: unsupported intrinsic でpanic!。
問題
compiler はユーザー入力に対して診断を返すべきですが、backend は内部不整合を panic! で処理しています。precheck が完全でない場合、通常のコンパイルエラーではなくプロセス異常終了になります。
影響
CLI / web / doctest runner が compiler crash と compile error を区別できません。クラッシュ時には span も失われ、根本原因の追跡が難しくなります。
修正方針
codegen API を Result<CodegenResult, Vec<Diagnostic>> に寄せ、panic 経路をすべて DiagnosticId::Codegen... 付きエラーに置き換えます。precheck は「panic を防ぐ安全網」ではなく「早い診断」の位置づけにします。
対応
codegen_wasm::generate_wasm を Result<CodegenResult, Vec<Diagnostic>> に変更し、unsupported signature、raw wasm parse error、missing return、unknown variable / function / intrinsic、string literal table mismatch、field selector mismatch、aggregate lower 非対応を Diagnostic として返すようにしました。これにより codegen_wasm.rs の production 経路から explicit panic! / unwrap() / expect() を除去しました。
LLVM backend は LlvmCodegenError::CodegenDiagnostic を追加し、raw body mismatch、unknown variable / function / function value、unsupported intrinsic、残りの lowering invariant failure を diagnostic error として返すようにしました。get_field / set_field は WASM / LLVM の precheck supported intrinsic list に追加し、precheck と backend の supported set がずれて誤診断になる問題も同時に修正しました。
検証
unsupported intrinsic、unknown field selector、invalid raw wasm を tests/compiler/codegen_diagnostics.n.md の compile_fail として固定しました。precheck を bypass した backend 直接呼び出しについては nepl-core/tests/codegen_diagnostics.rs で unsupported function signature、unknown variable、missing string literal が panic ではなく diagnostic を返すことを確認しました。
RV-CORE-008: effect 判定が文字列包含に依存していて不健全
- 解決済: true
- 状態: verified
- 優先度: P1
- 種別: bug
- 対象:
nepl-core/src/effects.rs,nepl-core/src/typecheck.rs,nepl-core/tests/effects.rs
根拠
nepl-core/src/effects.rs:57:marker_is_impure_ioがtext.contains(m)。nepl-core/src/effects.rs:69: raw body effect は行文字列の contains で判定。nepl-core/src/effects.rs:77:HirBody::Block(_)は raw body 判定では Pure。
問題
raw wasm / LLVM IR の effect を文字列検索で推定しています。コメントや別名に fd_write が含まれれば false positive になり、逆に wrapper 名や syscall 経由は missed detection になります。
影響
pure 関数から外部 I/O が呼べる、または pure な raw body が impure と誤判定されるなど、effect system の信頼性が落ちます。
修正方針
raw body は明示 effect annotation を必須にするか、extern / intrinsic 宣言に effect を持たせて call graph で伝播します。文字列検索は診断補助に限定します。
対応
raw body の effect 推定から行文字列の contains 判定を削除し、raw wasm / LLVM IR の direct call target だけを抽出するようにしました。コメント内の fd_write や、fd_write_like のように impure marker を部分文字列として含むだけの名前は effect 判定に使いません。
抽出した call target は、まず NEPL 側の宣言済み callable / extern symbol の effect と照合します。同じ target に impure な宣言があれば impure とし、pure 宣言だけなら pure として扱います。宣言が見つからない場合に限り、fd_write などの既知 WASI I/O marker と完全一致する intrinsic fallback で impure 判定します。LLVM の llvm.* intrinsic は compiler intrinsic として pure 扱いにしました。
検証
確認済み:
cargo test -p nepl-core --test effects(5 passed)cargo fmt --all --checkcargo check --workspacetrunk buildnode tests/compiler/tree/run.js(total=19,passed=19,failed=0)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests.json(13/13 passed)
既存残件:
cargo test -p nepl-coreで見つかった first-class function / lambda wasm codegen の失敗はRV-CORE-017として分離し、後続修正で解決済みです。node nodesrc/tests.js -i tests/compiler/move_effect.n.md --no-stdlib --no-tree -o tmp/rv-core-008-move-effect.jsonは23/26です。raw body effect のfd_writecompile_fail は維持されていますが、既存の D3090 impl method signature mismatch がdoctest#5からdoctest#7で残っています。
RV-CORE-009: move/borrow/drop が Resource IR なしで後付け実装されている
- 解決済: false
- 状態: open
- 優先度: P1
- 種別: architecture
- 対象:
nepl-core/src/passes/move_check.rs,nepl-core/src/passes/drop_insertion.rs,nepl-core/src/compiler.rs
根拠
nepl-core/src/compiler.rs:374: drop 挿入後に monomorphize し、その後 move check。nepl-core/src/passes/move_check.rs:35: 変数状態はBTreeMap<String, Vec<VarState>>。nepl-core/src/passes/move_check.rs:616:AddrOfは borrow として状態を変える。nepl-core/src/passes/drop_insertion.rs:91: scope exit で trait drop call を後付け生成。
問題
Resource IR がなく、HIR 木を直接走査して所有権状態を推測しています。borrow の lifetime release、field move、auto drop と user drop の整合、branch merge が局所状態で処理されており、仕様化しづらいです。
影響
false positive / false negative の両方が起きやすく、stdlib の owning collection と組み合わせたときに double free や use-after-move を防ぎきれません。
修正方針
doc/neplg3/impl/compiler_structure.md の方針どおり HIR 後に Resource IR を導入し、move、borrow、region、drop elaboration を別 pass に分けます。drop 挿入前に ownership を確定し、auto drop は Resource IR 上で挿入します。
検証
branch/loop/borrow/field move/drop trait の compile_fail と should_panic を整理し、Resource IR dump の snapshot test を追加します。
RV-CORE-010: name resolution が二重化し本パイプラインに統合されていない
- 解決済: false
- 状態: open
- 優先度: P2
- 種別: architecture
- 対象:
nepl-core/src/resolve.rs,nepl-core/src/name_resolve.rs,nepl-core/src/typecheck.rs
根拠
nepl-core/src/resolve.rs:1: DefId / export table の scaffolding。nepl-core/src/name_resolve.rs:1: 別の name resolution skeleton。nepl-core/src/name_resolve.rs:48:resolve_namesは diagnostics 空で返すだけ。nepl-core/src/typecheck.rs:7777: 実際の値・関数探索はtypecheck.rs内のEnvが担う。
問題
名前解決の意図は resolve.rs と name_resolve.rs にありますが、本 pipeline は typecheck.rs 内 Env に依存しています。DefId を持つ canonical resolution になっていません。
影響
import alias、overload、shadowing、qualified path の責務が分散し、同名関数や module boundary のバグが出やすくなります。
修正方針
name_resolve.rs は削除または resolve/ へ統合し、DefId を AST/HIR lowering の入力にします。typecheck.rs の Env は型検査用 local binding に限定します。
検証
cross-file import、qualified alias、shadowing、ambiguous open import の tree test を DefId snapshot として追加します。
RV-CORE-011: TypeExpr が span を保持せず診断位置が失われる
- 解決済: true
- 状態: verified
- 優先度: P2
- 種別: bug
- 対象:
nepl-core/src/ast.rs,nepl-core/src/parser.rs,nepl-core/src/typecheck.rs
根拠
nepl-core/src/ast.rs:TypeExpr::span()が常にSpan::dummy()を返していました。nepl-core/src/parser.rs: 型式 parsing が元 token の開始・終了 span を AST へ保存していませんでした。nepl-core/src/typecheck.rs: call reduction no-progress diagnostic がSpan::dummy()を使っていました。
問題
型注釈や型式のエラー位置を正確に出せません。dummy span は <unknown>:1:1 のような診断に化け、修正箇所が分からなくなっていました。
影響
ユーザー体験が悪く、compile_fail テストで span を固定しにくい状態でした。内部バグの triage でも、問題の型式を特定しづらくなっていました。
修正方針
TypeExpr に source span を持てる wrapper を追加します。parser は型式の開始・終了 span を保存し、typecheck / codegen 側は wrapper を剥がして既存の型意味論を維持します。diagnostic は TypeExpr::span() から元の型式位置を使います。
対応
TypeExpr::Spanned と span / as_unspanned / into_unspanned / with_span を追加し、parser の parse_type_expr が実 token 範囲を wrapper として保存するようにしました。type_from_expr と LLVM signature lowering は as_unspanned 経由で処理し、span wrapper が型解決の意味論へ混入しないようにしています。
generic impl target の TypeImplTargetMustBeConcrete 診断が impl Marker for .T の .T 範囲を指す regression を追加しました。call reduction no-progress diagnostic も dummy span ではなく現在の call reduction 対象 expression span を使うようにしました。
検証
確認済み:
cargo check -p nepl-corecargo test -p nepl-core --test neplg2 impl_generic_target_diagnostic_uses_type_expr_span -- --nocapture(1 passed)cargo fmt --all --checkcargo test -p nepl-core --test neplg2(36 passed)trunk buildcargo test -p nepl-corecargo check --workspacenode tests/compiler/tree/run.js(19/19 passed)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests-rv-core-011.json(13/13 passed)
RV-CORE-012: target/profile gate の評価が複数箇所に散っている
- 解決済: true
- 状態: verified
- 優先度: P2
- 種別: architecture
- 対象:
nepl-core/src/compiler.rs,nepl-core/src/target_precheck.rs,nepl-core/src/typecheck.rs
根拠
nepl-core/src/compiler.rs:44: target gate parser は compiler に定義。nepl-core/src/target_precheck.rs:54:gate_allowsは compiler の parser を呼ぶ。nepl-core/src/typecheck.rs:8976: typecheck 側にも target gate helper がある。nepl-core/src/target_precheck.rs:285: precheck は codegen 前に別途実行される。
問題
target/profile gate の有効 statement 判定が複数箇所に散っています。未知 gate は false に丸められやすく、診断になる箇所と静かに無効化される箇所が分かれます。
影響
#if[target=...] を含む stdlib で、target ごとに実行される関数 body がずれる可能性があります。raw body precheck と typecheck の見ている active statements が一致しないと、backend panic に繋がります。
修正方針
gate evaluation を passes/target_gate 相当へ一本化し、AST から inactive item を明示的に除外した lowered module を作ります。未知 gate は warning ではなく diagnostic error にします。
対応
nepl-core/src/target_gate.rs に target/profile gate の共通 evaluator と invalid gate 診断を集約しました。compiler.rs、typecheck.rs、target_precheck.rs は同じ evaluator を使うようにし、未知 target/profile や構文不正な gate は InvalidConditionalGate として診断します。
関数直下だけでなく、式内部の block / match arm / tuple / group / intrinsic argument も再帰的に検証し、active statement 判定と診断の取りこぼしを防ぎます。既存の「非該当 target はスキップする」テストは、未知 gate ではなく既知の false gate (llvm on wasm) を使うよう更新しました。
検証
追加・更新した検証:
cargo fmt --all --checkcargo test -p nepl-core target_gate -- --nocapture(4 passed)cargo test -p nepl-core --test neplg2 invalid_ -- --nocapture(3 passed)cargo test -p nepl-core(pass)trunk build(pass)cargo check --workspace(pass)node tests/compiler/tree/run.js(19/19 passed)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests-rv-core-012.json(13/13 passed)git diff --check(pass)
補足: node nodesrc/tests.js -i tests/compiler/neplg2.n.md --no-tree -o tmp/neplg2-rv-core-012.json -j 2 は doctest#39 の既存 fixture 不整合で 1 件失敗しました。これは target/profile gate 変更とは独立しているため、RV-CORE-021 として追加しました。
RV-CORE-013: 参照引数の関数呼び出しが一時 borrow にならず所有値を固定する
- 解決済: true
- 状態: verified
- 優先度: P0
- 種別: bug
- 対象:
nepl-core/src/passes/move_check.rs,tests/compiler/move_check.n.md,stdlib/alloc/collections/vec.nepl,stdlib/alloc/collections/stack.nepl
根拠
nepl-core/src/passes/move_check.rs: 通常の関数呼び出し引数はvisit_exprで処理され、AddrOfがvisit_borrowによりスコープ終端までの borrow として記録される。stdlib/alloc/collections/vec.nepl:len_ref &vの後にpush v ...する doctest が、VecからCopyを外した時点でcannot move out of shared borrowed valueになる。stdlib/alloc/collections/stack.nepl:peek_ref &stk/len_ref &stkも同じ構造です。
問題
len_ref &v のように参照を関数呼び出しへ渡すだけの式でも、move checker は v をスコープ終端まで shared borrow として扱います。参照引数の呼び出しは式の評価中だけの一時 borrow であるべきですが、現状では borrow が解放されないため、非 Copy 所有値を読み取った後に移動・更新できません。
影響
Vec / Stack を正しく非 Copy にすると、borrow-based read API を追加しても、その後の push / free / move が拒否されます。所有権を安全にした stdlib API と現在の borrow checker が噛み合わず、RV-STDLIB-003 の根本修正を妨げます。
修正方針
move checker で call target の parameter type を参照し、parameter が &T / &mut T の場合は対応する引数を一時 borrow として評価するよう修正しました。&x は呼び出し式の評価中だけ borrow し、呼び出し後の x の所有権状態を Valid のまま保ちます。非参照引数の by-value move と、永続的な local borrow (let r &x) は従来どおり区別します。
検証
tests/compiler/move_check.n.md に「非 Copy 値を参照引数へ渡した後に move できる」回帰テストを追加しました。local に保持した shared borrow については、参照束縛が後続で使われる場合だけ move を拒否し、未使用の参照束縛は last-use 解析で borrow を解放する方針です。
確認済み:
cargo check -p nepl-coretrunk buildnode nodesrc/tests.js -i tests/compiler/move_check.n.md --no-tree -o tmp/move-check-rv-core-013.json -j 1(total=14,passed=14,failed=0)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests.json(caseCount=13,passedCount=13,failedCount=0)
RV-CORE-014: Pair から取り出した generic collection の型が overload 解決へ伝播しない
- 解決済: true
- 状態: verified
- 優先度: P1
- 種別: bug
- 対象:
nepl-core/src/typecheck.rs,tests/compiler/overload.n.md,stdlib/alloc/collections/vec.nepl
根拠
stdlib/alloc/collections/vec.nepl::doctest#28:partitionの戻り値.Pairからlet evens get parts 0で取り出した後、len<i32> evensがerror[D3006]: no matching overload foundになる。- 同じ箇所へ明示型注釈を付けると、過去の調査では overload error ではなく codegen の internal panic 経路へ進んだ。
RV-CORE-004は overload 解決の clone 過多を扱うが、この件は.Pairfield access 結果の型伝播と overload 候補選択の正当性問題です。
問題
.Pair のような generic tuple 相当の値から get で取り出した collection の型情報が、その後の overloaded function call に十分伝播していませんでした。原因は field accessor ではなく、関数本体で .Pair が実際の tuple 型へ推論された後、関数チェック終了時の snapshot 復元でその束縛まで破棄していた点でした。結果として Vec<i32> であるべき値に対して len<i32> の候補を選べず、正常な stdlib doctest が compile error になっていました。
影響
partition のように複数の collection を返す API を利用したコードで、明示型注釈なしに後続 API を呼べません。型注釈で回避しようとしても backend panic 経路へ進む可能性があり、診断品質と codegen 安全性の両方に影響します。
修正方針
関数チェック成功時の型変数復元を、明示的な関数 type parameter の束縛に限定しました。.Pair のようなシグネチャ内の非 type parameter 推論結果は保持し、field accessor / overload 解決から Vec<i32> として参照できるようにしました。関数チェック失敗時は従来どおり関数シグネチャ全体の snapshot を復元し、失敗した部分推論が外へ漏れないようにしています。
検証
確認済み:
cargo check -p nepl-corecargo run -p nepl-cli -- -i tmp/rv-core-014-repro.nepl --check --target coretrunk buildnode nodesrc/tests.js -i tests/compiler/overload.n.md --no-tree -o tmp/overload-rv-core-014.json -j 1(total=45,passed=45,failed=0)node nodesrc/tests.js -i stdlib/alloc/collections/vec.nepl --no-tree -o tmp/vec-rv-core-014.json -j 1(total=37,passed=37,failed=0)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests.json(caseCount=13,passedCount=13,failedCount=0)
RV-CORE-015: 深い HIR を check pipeline が再帰処理して stack overflow する
- 解決済: true
- 状態: verified
- 優先度: P1
- 種別: bug
- 対象:
nepl-core/src/compiler.rs,nepl-core/src/lib.rs,nepl-cli/src/main.rs
根拠
RV-CORE-003の 1105 identity prefix call chain は typecheck / wasm semantics では通る。- 一方で
cargo run -p nepl-cli -- -i tmp/rv-core-003-large.nepl --check --target coreは、DEBUG: Calling compile_module後にthread 'main' has overflowed its stackで異常終了する。
問題
--check は型検査だけで終わらず compile pipeline を進めています。後段の drop insertion / move check / codegen precheck / wasm codegen などが深い HirExpr を再帰的にたどるため、型検査済みの正当な長い式でも native stack overflow で落ちます。
影響
深いが正当なプログラムを CLI で確認できず、診断ではなくプロセス異常終了になります。CI や editor integration では入力サイズに依存して compiler process が落ちるため、RV-CORE-003 の typecheck 改善だけではユーザー体験が安定しません。
修正方針
--check の責務を型検査成功可否に限定できる path として分離します。artifact 生成が必要ない確認用途で、drop insertion / move check / codegen precheck / wasm codegen へ進まないようにします。
対応
nepl_core::check_module_with_source_map を追加し、target/profile precheck と typecheck までを実行する check-only path を提供しました。nepl-cli --check はこの API を呼ぶようにし、compile_module_with_source_map による artifact 生成へ進まないようにしました。
これにより、RV-CLI-001 で必要だった「未定義シンボルなどの compiler diagnostics を拾う」性質は維持しつつ、1105 identity prefix call chain のような深いが正当な入力で後段の再帰 pipeline に入らなくなりました。
対応中に、--output による実際の wasm artifact 生成は同じ深い HIR で引き続き native stack overflow することを確認しました。この残件は RV-CORE-016 として分離し、後段 HIR pass / codegen の iterative 化で追跡します。
検証
確認済み:
cargo test -p nepl-core --test check_pipelinecargo test -p nepl-cli check_cargo run -p nepl-cli -- -i tmp/rv-core-003-large.nepl --check --target core
未解決として分離:
cargo run -p nepl-cli -- -i tmp/rv-core-003-large.nepl --target core -o tmp/rv-core-003-large-rv-core-015.wasmはthread 'main' has overflowed its stackで失敗する。artifact 生成側の深い HIR traversal はRV-CORE-016で追跡します。
RV-CORE-016: 深い HIR を artifact codegen pipeline が再帰処理して stack overflow する
- 解決済: true
- 状態: verified
- 優先度: P1
- 種別: bug
- 対象:
nepl-core/src/monomorphize.rs,nepl-core/src/passes/move_check.rs,nepl-core/src/passes/codegen_precheck.rs,nepl-core/src/wasm_shared.rs,nepl-core/src/codegen_wasm.rs
根拠
RV-CORE-015 の check-only path 分離後、同じ 1105 identity prefix call chain を実際に artifact 生成すると、compile_module 後段で native stack overflow します。
再現:
cargo run -p nepl-cli -- -i tmp/rv-core-003-large.nepl --target core -o tmp/rv-core-003-large-rv-core-015.wasm
問題
artifact 生成に必要な HIR pass / codegen backend は、深い HirExpr を再帰的に走査します。--check は分離済みですが、実際の wasm 出力では drop insertion、monomorphize、move check、codegen precheck、wasm codegen のいずれかで native stack を消費し、診断ではなくプロセス異常終了になります。
影響
型検査上は正当な深い式でも、wasm artifact を生成できません。CI や配布ビルドで入力サイズ依存の compiler crash が残ります。
修正方針
artifact 生成側の HIR traversal を段階別に切り分け、深い call chain で再帰しない iterative visitor へ置き換えます。最低限、1105-call chain の wasm 出力が stack overflow せず成功する regression を追加します。
対応
monomorphize では非 generic 関数の元 HIR を clone せず移動し、type parameter mapping が空の具象関数では body 全体の再帰 substitute を避け、callee queue のみを iterative traversal で処理するようにしました。move check は borrow / control-flow に関わらない単純な値式を explicit stack で走査する fast path を追加し、既存の ownership semantics が必要な式は従来の分岐へ残しています。
wasm codegen precheck と signature / reachable collection は shared helper 側で recursive walk をやめ、explicit stack で HirExpr を辿るようにしました。さらに wasm lowering では単純な literal / variable / direct call tree を iterative post-order lowering できる path を追加し、1105 個の prefix call chain を native stack に積まずに wasm instruction へ落とせるようにしました。
検証
確認済み:
cargo fmt --all --checkcargo check -p nepl-corecargo test -p nepl-core --test check_pipeline(3 passed)cargo run -p nepl-cli -- -i tmp/rv-core-003-large.nepl --target core -o tmp/rv-core-003-large-rv-core-016.wasmcargo check --workspacetrunk buildnode tests/compiler/tree/run.js(total=19,passed=19,failed=0)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests.json(13/13 passed)
RV-CORE-017: 関数値として渡した関数と lambda が backend 到達時に未登録になる
- 解決済: true
- 状態: fixed
- 優先度: P0
- 種別: bug
- 対象:
nepl-core/src/typecheck.rs,nepl-core/src/monomorphize.rs,nepl-core/src/wasm_shared.rs,nepl-core/src/codegen_wasm.rs,nepl-core/src/codegen_llvm.rs
根拠
- GitHub Actions run
24932659255のwasi-test/nmd-doctest:tests/compiler/functions.n.md::doctest#6がerror[D4008]: unknown function value 'square__i32__i32__pure' reached wasm codegenで失敗。 - 同 run:
tests/compiler/functions.n.md::doctest#8がerror[D4007]: unknown variable 'add_op' reached wasm codegen、doctest#12が generated lambda 名__lambda_0_214_218の unknown variable で失敗。 - 同 run:
tests/compiler/list_dot_map.n.md、tests/compiler/move_check.n.md、tests/compiler/overload.n.md、tests/compiler/prelude_copy.n.md、tests/compiler/typeannot.n.mdでも、関数値として渡したinc/token_id/calc/as_i32/fがD4008で失敗。 - 同 run の
tutorials-test: 競プロ I/O 系 tutorial 6 件がstdlib/std/streamio.neplのstream_writer_noncopy_marker__i32__i32__pureを unknown function value として失敗。 tests/compiler/tree/08_function_value_call_indirect.jsは function value call の lowering を期待しているが、実際の doctest / Rust integration 経路では関数値が backend へ届く前後の登録が揃っていない。- 手元の
stdlib/alloc/collections/vec.nepl広域 doctest でも、map/fold/reduce/find/take_whileなどの高階 API がerror[D4008]: unknown function value ... reached wasm codegenで失敗した。 Vec高階 API は(.T)->.Uや(.U,.T)->.Uの関数値を引数に取るため、CI の関数値 failure と同じ lowering 契約不備に含めて追跡する。
問題
型検査は higher-order function や lambda を通している一方で、monomorphize / reachable collection / backend lowering のどこかで、関数値としてだけ参照される関数や generated lambda が module の callable set に安定して登録されていません。その結果、ユーザーコード上は関数値として正当な式が、backend の内部不変条件エラーである D4007 / D4008 に到達します。
これは RV-CORE-007 で panic を diagnostic 化した後に可視化された根本バグです。diagnostic を返すこと自体は改善ですが、正当な higher-order code を compile できない状態は残っています。
影響
標準ライブラリの List::map / filter / fold 相当、Vec::map / filter / fold 相当、streamio の writer marker、tutorial の競プロ I/O、関数値を返す基本サンプルが CI 上で失敗します。wasi-test / nmd-doctest / tutorials-test / stdlib-test にまたがるため、CI の大半が赤くなり、他の stdlib 不具合も同じ failure set に埋もれます。
修正方針
関数値を first-class に扱うための lowering 契約を明確にします。typecheck で関数値・lambda・indirect call の型を確定した後、monomorphize と reachable function collection は「直接 call される関数」だけでなく「値として参照される関数」と generated lambda も収集し、WASM / LLVM backend の function table と name map に登録します。
@func と bare func の扱い、純粋/非純粋 signature、capturing lambda の未対応診断を整理し、未実装の capture は typecheck diagnostic に留めます。backend に到達してから unknown になる経路をなくします。
対応
monomorphize.rs の concrete 関数処理で、直接 call だけでなく Var / FnValue として現れる関数参照も収集し、対応する specialized function を worklist へ積むようにしました。
generic 関数の substitute_expr では既に関数値参照を request_instantiation へ通していましたが、type parameter mapping が空の concrete 関数では queue_concrete_callees が direct Call しか見ていませんでした。そのため square、add_op、generated lambda のように値として渡される関数が backend の name_map に入らず、D4007 / D4008 に到達していました。
今回の修正では concrete 関数の param / let / match bind を local 名として集めたうえで、local ではない bare Var と FnValue をユーザー関数として解決し、direct call と同じ monomorphize queue に登録します。
検証
確認済み:
cargo fmt --all -- --checkcargo test -p nepl-core --test functions function_first_class -- --nocapture(2 passed)cargo test -p nepl-core --test functions function_return -- --nocapturecargo test -p nepl-core --test functions(12 passed,1 ignored)trunk buildnode nodesrc/tests.js -i tests/compiler/functions.n.md -o tmp/functions-rv-core-017.json -j 1(41/41 passed)node nodesrc/tests.js -i tests/compiler/list_dot_map.n.md -o tmp/list-dot-map-rv-core-017.json -j 1(23/23 passed)node nodesrc/tests.js -i tutorials/getting_started/22_competitive_io_and_arith.n.md -o tmp/tutorial-io-rv-core-017.json -j 1(22/22 passed)node nodesrc/tests.js -i stdlib/alloc/collections/vec.nepl -o tmp/vec-rv-core-017.json -j 1(57/57 passed)
未解決として分離:
node nodesrc/tests.js -i stdlib/tests/vec.n.md -o tmp/vec-tests-rv-core-017.json -j 1は20/21 passedで、partitionの right bucket 読み取りが runtime 値不一致になる。関数値登録漏れではなく nested aggregate field access の問題としてRV-CORE-018へ分離しました。
GitHub Actions での確認は、この修正を push した後の run で行います。
RV-CORE-018: nested aggregate を tuple から取り出すと 2 番目以降の値が壊れる
- 解決済: true
- 状態: verified
- 優先度: P0
- 種別: bug
- 対象:
nepl-core/src/types.rs,nepl-core/src/codegen_wasm.rs,nepl-core/src/codegen_llvm.rs,nepl-core/src/typecheck.rs,stdlib/tests/vec.n.md
根拠
node nodesrc/tests.js -i stdlib/tests/vec.n.md -o tmp/vec-tests-rv-core-017.json -j 1:stdlib/tests/vec.n.md::doctest#2がerr assert_eq_i32 failed: expected=1 actual=0で失敗。- 失敗箇所は
partition<i32>の戻り値.Pairからget parts 1で取り出した odd 側Vec<i32>の先頭要素。 - 一時再現
tmp/rv-pair-vec-runtime.n.mdでは、Tuple: left rightの 2 番目のVec<i32>をget pair 1で取り出し、get_ref &got_right 0すると expected1に対して actual2208になった。
問題
Vec<i32> の単体操作と partition の predicate / length 計算は動いています。一方で、tuple に nested struct / aggregate を 2 つ入れた後、2 番目以降の aggregate を取り出すと内部 field、特に data pointer か payload layout が壊れます。
RV-CORE-014 は .Pair から取り出した generic collection の型伝播問題でしたが、今回は型検査は通り runtime 値が壊れるため別問題です。aggregate の ABI / layout / field selector lowering のどこかで、tuple field offset と nested struct value の copy 幅が一致していない可能性があります。
影響
Vec::partition の (matched, rest) の rest 側、複数 collection を返す stdlib API、nested struct を tuple / anonymous aggregate 経由で返すユーザーコードが誤った値を読みます。runtime trap ではなく値化けになるため、検出しにくいデータ破壊です。
修正方針
WASM / LLVM の aggregate layout を同じ仕様に揃え、tuple field access が nested struct の size / alignment / field offset を正しく使うことを確認します。最小回帰として、2 本の Vec<i32> を tuple に入れて 2 番目を取り出し、len と先頭要素を検査する doctest または Rust integration test を追加します。
対応
根本原因は、generic named struct の Apply base が Named("Vec") のまま storage layout 計算へ渡る経路で、Vec<i32> を実体 struct の 12 byte ではなく fallback の 4 byte として扱っていたことでした。そのため Tuple(Vec<i32>, Vec<i32>) の 2 番目 field offset が 12 ではなく 4 になり、最初の Vec の cap 以降を 2 番目の Vec として読んでいました。
TypeCtx::resolve_named_type_id を layout 計算から使えるように公開し、WASM / LLVM / typecheck の storage size / align / field offset 計算で Apply の base を named type 実体へ解決するようにしました。併せて aggregate get が nested aggregate を byte copy した後に destination pointer を stack へ戻すようにし、copy 結果を正しく式値として返すようにしました。
stdlib/tests/vec.n.md には Tuple(Vec<i32>, Vec<i32>) の 2 番目を直接取り出して len_ref と先頭要素を確認する回帰を追加しました。これにより partition の偶然の値化けだけでなく、aggregate field offset の直接破壊を検出できます。
検証
確認済み:
cargo fmt --all --checkcargo test -p nepl-core --test tuple_new_syntax(20 passed)cargo test -p nepl-corecargo check --workspacetrunk buildnode nodesrc/tests.js -i stdlib/tests/vec.n.md -o tmp/vec-tests-rv-core-018-after-rebase.json -j 1(total=21,passed=21,failed=0)node tests/compiler/tree/run.js(total=19,passed=19,failed=0)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests-rv-core-018.json(caseCount=13,passedCount=13,failedCount=0)
RV-CORE-019: generic wrapper / nested generic enum の期待型伝播が TypeNoMatchingOverload になる
- 解決済: true
- 状態: verified
- 優先度: P1
- 種別: bug
- 対象:
nepl-core/src/typecheck.rs,nepl-core/src/types.rs,nepl-core/tests/generics.rs,tests/compiler/generics.n.md
根拠
cargo test -p nepl-core で、tests/generics.rs の generics_make_pair_wrapper / generics_nested_option_match が TypeNoMatchingOverload / TypeReturnTypeMismatch で失敗していました。
問題
TypeCtx::unify が Apply 型同士を比較する際に、Pair / Option などの nominal な enum / struct 定義本体まで unify していました。そのため Pair<i32,bool> の照合で共有定義側の型変数が具体型へ固定され、次の Pair<bool,i32> や nested generic enum constructor 呼び出しが壊れていました。
対応
nominal な enum / struct の Apply は base 定義本体を unify せず、同じ kind / name / arity であることだけを確認し、型引数だけを unify / compare するようにしました。TypeCtx::substitute でも nominal base は置換対象から外し、定義側 type parameter が instantiation 側へ漏れないようにしています。
外側 callable から内側式の期待型を推論する経路では generic callable の宣言型をそのまま使わず、fresh instantiate した関数型から引数型を読ませるようにしました。
検証中に red になった Rust integration fixture は、doctest 側の現行状態と揃えました。loader 経由テストでは SourceMap を保持し、古い alloc/vec / vec_* / kp/kpread 参照は現行 alloc/collections/vec / std/streamio API へ更新しています。
検証
確認済み:
cargo fmt --all --checkcargo test -p nepl-core --test generics generics_make_pair_wrapper(1 passed)cargo test -p nepl-core --test generics generics_nested_option_match(1 passed)cargo test -p nepl-core --test generics(24 passed)cargo test -p nepl-core(pass)cargo check --workspacenode nodesrc/tests.js -i tests/compiler/generics.n.md --no-stdlib --no-tree -o tmp/rv-core-019-generics.json -j 1(24/24 passed)node tests/compiler/tree/run.js(19/19 passed)trunk buildnode nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests.json(13/13 passed)
RV-CORE-020: pipe 左辺の部分適用が D3013 になり Rust test と doctest の状態が不整合
- 解決済: true
- 状態: verified
- 優先度: P2
- 種別: bug
- 対象:
nepl-core/src/typecheck.rs,nepl-core/tests/pipe_operator.rs,tests/compiler/pipe_operator.n.md
根拠
RV-CORE-019 の検証で cargo test -p nepl-core を実行すると、nepl-core/tests/pipe_operator.rs の pipe_nested_pipes / pipe_in_if が TypePipeError (D3013: pipe left-hand side did not reduce to a single value) で失敗しました。一方、同じ内容の tests/compiler/pipe_operator.n.md doctest は既に neplg2:test[skip] として記録されています。
問題
pipe 左辺に add 1 や if true 1 のような、後続の |> を見ないと値へ縮約できない式があると、typecheck は base_depth から stack 末尾までを pipe 左辺として退避していました。そのため、未完了の外側 prefix call (add / if) まで左辺へ含まれ、target 注入前の左辺縮約で単一値にならず D3013 になっていました。
影響
doctest と Rust integration test の期待状態が不整合になり、pipe の部分適用・if 内 pipe の仕様が固定できていないため、parser/typecheck 改修で回帰しやすい状態でした。
修正方針
pipe 左辺の退避範囲を決める時に、現在の stack 内に未完了の外側 callable があるかを確認します。未完了 callable が直近の値より下に残っている場合は、その callable を左辺へ含めず、stack 末尾の直近引数式だけを pipe 左辺として target へ注入します。既に単一値へ縮約済みの top-level pipe では従来通り base_depth から退避します。
対応
BlockChecker::pipe_pending_base を追加し、PrefixItem::Pipe で退避する stack 範囲を未完了 callable に応じて決定するようにしました。これにより add 1 |> add 2 3 は add (1 |> add 2) 3 として、if true 1 |> add 2 0 は if true (1 |> add 2) 0 として型検査・実行できます。
nepl-core/tests/pipe_operator.rs の pipe_nested_pipes / pipe_in_if の ignore を解除し、tests/compiler/pipe_operator.n.md の doctest skip も解除しました。
検証
cargo fmt --all --checkcargo test -p nepl-core --test pipe_operator pipe_nested_pipes -- --nocapture(1 passed)cargo test -p nepl-core --test pipe_operator pipe_in_if -- --nocapture(1 passed)cargo test -p nepl-core --test pipe_operator(20 passed)trunk buildnode nodesrc/tests.js -i tests/compiler/pipe_operator.n.md --no-stdlib --no-tree -o tmp/rv-core-020-pipe-after-rebase.json -j 1(20/20 passed)cargo test -p nepl-corecargo check --workspacenode tests/compiler/tree/run.js(19/19 passed)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests-rv-core-020-after-rebase.json(13/13 passed)
RV-CORE-021: neplg2.n.md の overload arity fixture が Rust test と不整合
- 解決済: true
- 状態: verified
- 優先度: P2
- 種別: test
- 対象:
tests/compiler/neplg2.n.md,nepl-core/tests/neplg2.rs
根拠
RV-CORE-012 の検証で trunk build 後に node nodesrc/tests.js -i tests/compiler/neplg2.n.md --no-tree -o tmp/neplg2-rv-core-012.json -j 2 を実行すると、doctest#39 が D3005 ambiguous overload で失敗しました。
同じ内容に対応する Rust integration test は nepl-core/tests/neplg2.rs の overloads_with_different_arity_are_error で、現行実装では同名かつ arity の異なる overload を error として扱っています。
問題
tests/compiler/neplg2.n.md 側の overloads_with_different_arity_are_allowed は、現行 Rust test と逆の仕様を期待しています。そのため Node doctest runner では red になりますが、Rust suite では green になり、compiler 仕様と doctest fixture のどちらが正か読み取りにくい状態です。
影響
tests/compiler/neplg2.n.md 全体の regression test が 1 件失敗し続けます。target/profile gate の検証とは独立した不整合ですが、同じ fixture を使うため、関連変更の検証結果を曇らせます。
修正方針
言語仕様として「同名 overload の arity 差を許可する」のか「現行通り error とする」のかを確認し、Rust test と .n.md doctest を同じ期待値へ揃えます。現行実装を維持する場合は .n.md 側を compile_fail + diagnostic ID 期待へ更新します。
対応
現行 Rust test の overloads_with_different_arity_are_error に合わせ、tests/compiler/neplg2.n.md の fixture 名と期待値を compile_fail + diag_id: 3005 へ変更しました。これにより neplg2.n.md の doctest と Rust integration test が同じ仕様を検証します。
検証
cargo test -p nepl-core --test neplg2 overloads_with_different_arity_are_error -- --nocapture(1 passed)node nodesrc/tests.js -i tests/compiler/neplg2.n.md --no-tree -o tmp/neplg2-rv-core-021.json -j 2(total=45,passed=45,failed=0)
RV-CORE-022: GitHub Actions 24940960078 で compiler doctest が広範囲に回帰している
- 解決済: true
- 状態: verified
- 優先度: P0
- 種別: bug
- 対象:
tests/compiler/*.n.md,nepl-core/tests/*.rs,nepl-core/src/typecheck.rs,nepl-core/src/passes/**
根拠
- GitHub Actions run
24940960078(Fix RV-CLI-008 node cli argument errors, head96ae78bc872a314d857ec8e8c2f77fd7e38c7393) のwasi-test/nmd-doctestが失敗している。 gh run view 24940960078 --repo neknaj/NEPLg2 --log-failedで、node nodesrc/tests.js -i tests -o tests-current.json -j 4とnode nodesrc/tests.js -i tests -o nmd-tests.json -j 4の両方がtotal=693,passed=661,failed=31,errored=1を返した。- 代表例として
tests/compiler/move_check.n.md::doctest#7はexpected compile_fail, but compiled successfully、tests/compiler/move_effect.n.md::doctest#5/#6/#7はD3090 impl method signature does not match trait、tests/compiler/overload.n.md::doctest#13/#14/#23/#24/#25はD3005/D3068/D3006の連鎖で失敗している。move_check.n.md::doctest#7はRV-CORE-024、move_effect.n.mdのD30903件はRV-CORE-025、overload.n.mdの5件はRV-CORE-026に分離し、修正済み。 tests/compiler/raw_body_precheck.n.md::doctest#6もexpected compile_fail, but compiled successfullyになっていた。この件は unit 引数の zero-sized lowering 対応後の fixture ずれとしてRV-CORE-023に分離し、修正済み。
問題
core compiler の move/effect/trait impl/overload/raw-body precheck が同時に赤くなっており、単なる fixture ずれとして処理すると危険です。特に compile_fail が成功扱いになるケースは、不正な所有権移動や effect 境界違反を実行可能コードとして通す可能性があります。
影響
wasi-test と nmd-doctest が同じ failure set で落ちるため、main CI は compiler regression を検出した状態で失敗します。stdlib 側の失敗にも core compiler の D3006 / D3016 が混ざるため、stdlib 実装の問題と core 側の型推論・stack discipline 問題を切り分けにくくなっています。
修正方針
まず tests-current.json の failure を root cause 別に最小再現へ分解します。compile_fail が成功するものは move/effect/precheck の安全性問題として P0 で先に直し、D3090 は trait method signature の期待型生成と impl 側 signature 正規化を比較します。overload 系は RV-CORE-021 の arity 方針と tests/compiler/overload.n.md の期待値が現在の仕様に一致しているかを確認し、仕様が正しければ resolver 側、fixture が古ければ doctest 側を修正します。
対応
run 24940960078 の compiler doctest 代表failureを root cause 別に分離しました。raw_body_precheck.n.md の D4002 fixture ずれは RV-CORE-023、local borrow fixture ずれは RV-CORE-024、標準 Clone signature ずれは RV-CORE-025、同名arity違い overload fixture は RV-CORE-026 として修正済みです。
stdlib 側の残り failure は RV-STDLIB-013 / RV-STDLIB-018 に分離済みです。LLVM full dual backend verification の timeout / cancelled は RV-CLI-011 に残し、この issue では compiler doctest suite の再検証完了をもって verified とします。
検証
node nodesrc/tests.js -i tests/compiler --no-tree -o tmp/compiler-rv-core-026.json -j 4(total=474,passed=474,failed=0)
RV-CORE-023: raw_body_precheck の unsupported signature fixture が zero-sized unit 引数対応後の仕様とずれている
- 解決済: true
- 状態: verified
- 優先度: P2
- 種別: test
- 対象:
tests/compiler/raw_body_precheck.n.md,nepl-core/src/wasm_shared.rs,nepl-core/src/codegen_wasm.rs
根拠
GitHub Actions run 24940960078 の wasi-test / nmd-doctest で、tests/compiler/raw_body_precheck.n.md::doctest#6 が expected compile_fail, but compiled successfully になりました。ローカルでも node nodesrc/tests.js -i tests/compiler/raw_body_precheck.n.md --no-tree -o tmp/raw-body-precheck-rv-core-022.json -j 1 により同じ1件だけを再現しました。
問題
該当 fixture は fn bad <(())->i32> (u): を「WASM backend が扱えない関数 signature」として D4002 を期待していました。しかし RV-CORE-018 対応で unit 引数は zero-sized 値として WASM parameter から省略され、local lowering でも slot を持たない値として扱えるようになっています。したがって (())->i32 は現在の実装では未対応 signature ではなく、compile_fail 期待が古くなっていました。
影響
この fixture が赤いままだと、実際の raw body / codegen precheck regression と、仕様変更後の doctest ずれが RV-CORE-022 の failure set 内で混ざります。D4002 の回帰確認としても、既に対応済みの unit 引数を使うため検出内容が不正確でした。
修正方針
D4002 の意図は「WASM signature へ落とせない関数を codegen 前に診断する」ことなので、現在も未対応である never 戻り値を使う fixture に変更します。unit 引数の対応は維持し、zero-sized lowering を戻して表面上 compile_fail にする修正は行いません。
対応
raw_body_precheck.n.md の wasm_precheck_rejects_unsupported_function_signature を wasm_precheck_rejects_unsupported_function_result に変更し、fn main <()->never> (): が #intrinsic "unreachable" <> () を返すケースで D4002 を期待するようにしました。
検証
node nodesrc/tests.js -i tests/compiler/raw_body_precheck.n.md --no-tree -o tmp/raw-body-precheck-rv-core-023.json -j 1(total=5,passed=5,failed=0)
RV-CORE-024: move_check の local borrow fixture が last-use borrow release 後の仕様とずれている
- 解決済: true
- 状態: verified
- 優先度: P2
- 種別: test
- 対象:
tests/compiler/move_check.n.md,tests/compiler/move_effect.n.md,nepl-core/tests/move_check.rs
根拠
GitHub Actions run 24940960078 とローカル再現で、tests/compiler/move_check.n.md::doctest#7 が expected compile_fail, but compiled successfully になりました。該当fixture名は move_reference_ok であり、Rust integration test nepl-core/tests/move_check.rs::move_reference_ok も同じ内容を成功期待として保持しています。
問題
move_check.n.md 側だけが let r <&LocalToken> &x の直後に let y <LocalToken> x するケースを D3051 compile_fail としていました。しかし move checker は参照束縛の残り使用回数を数え、参照束縛が後続で使われない場合は borrow を即時解放します。この last-use borrow release により、未使用参照を作っただけの値は move 可能です。
一方で tests/compiler/move_effect.n.md の shared borrow 中 move fixture も r を後続で使っておらず、同じ理由でcompile_failとして不正確でした。これをそのまま strict に戻すと、未使用参照まで所有値をscope終端まで固定し、RV-CORE-013 で直した borrow lifetime 方針と衝突します。
影響
CI の compiler doctest failure set に、実装退行ではなく仕様に反した compile_fail fixture が混ざります。また「未使用参照はmoveを阻害しない」と「後続使用される参照がある間はmoveを拒否する」という2つの安全性条件を別々に確認できません。
修正方針
未使用参照の fixture は成功期待に戻します。shared borrow中のmove拒否を確認するfixtureでは、参照束縛をmove後にも使用してborrowをliveに保ち、D3051を期待します。Rust integration testにも同じlive borrow拒否ケースを追加し、Node doctestとRust testの仕様を揃えます。
対応
move_check.n.md::move_reference_ok を通常実行テストへ戻し、move_live_reference_blocks_move を追加しました。move_effect.n.md の「非Copy値の shared borrow 中 move は拒否」は let keep r を追加し、borrowが後続使用される状態で let c b を拒否するfixtureにしました。Rust側にも move_live_reference_blocks_move を追加しました。
検証
node nodesrc/tests.js -i tests/compiler/move_check.n.md --no-tree -o tmp/move-check-rv-core-024.json -j 1(total=15,passed=15,failed=0)node nodesrc/tests.js -i tests/compiler/move_effect.n.md --no-tree -o tmp/move-effect-rv-core-024.json -j 1(total=26,passed=23,failed=3; 残りは既存のD30903件)cargo fmt --all --checkcargo test -p nepl-core --test move_check -- --nocapture(14 passed)trunk buildnode nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests-rv-core-024.json(13/13 passed)git diff --check
RV-CORE-025: move_effect の Copy fixture が標準 Clone signature 変更後の仕様とずれている
- 解決済: true
- 状態: verified
- 優先度: P2
- 種別: test
- 対象:
tests/compiler/move_effect.n.md,stdlib/core/traits/copy.nepl
根拠
GitHub Actions run 24940960078 とローカル再現で、tests/compiler/move_effect.n.md::doctest#5/#6/#7 が D3090 impl method signature does not match trait で失敗しました。3件はいずれも #import "core/traits/copy" as * した標準 Clone に対する impl で、method signature だけが (Self)->Self の旧形でした。
問題
標準 Clone は stdlib/core/traits/copy.nepl で fn clone <(&Self)->Self> (x): と定義されています。一方、move_effect.n.md の Point / Pair<i32> / Score fixture は fn clone <(T)->T> (x): x と実装していました。これは trait method signature と一致しないため、compiler が D3090 を返すのが正しい挙動です。
影響
標準 trait の仕様変更後も旧fixtureが残っていたため、move_effect.n.md の Copy capability 回帰が赤くなり、実装側の trait signature 正規化バグと区別しにくくなっていました。
修正方針
標準 Clone を使うfixtureは (&T)->T へ揃えます。#no_prelude で独自に by-value Clone trait を定義している後続fixtureは、そのtrait仕様を検証しているため変更しません。
対応
Point / Pair<i32> / Score の impl Clone を fn clone <(&T)->T> (x): *x へ変更しました。これにより標準 Clone の borrowed source 仕様と Copy capability fixture の期待値が一致します。
検証
node nodesrc/tests.js -i tests/compiler/move_effect.n.md --no-tree -o tmp/move-effect-rv-core-025-probe.json -j 1(total=26,passed=26,failed=0)node nodesrc/tests.js -i tests/compiler/raw_body_precheck.n.md -i tests/compiler/move_check.n.md -i tests/compiler/move_effect.n.md --no-tree -o tmp/core-move-raw-rv-core-025.json -j 1(total=46,passed=46,failed=0)node nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests-rv-core-025.json(13/13 passed)git diff --check
RV-CORE-026: overload.n.md に同名arity違いを許可する旧fixtureが残っている
- 解決済: true
- 状態: verified
- 優先度: P2
- 種別: test
- 対象:
tests/compiler/overload.n.md,nepl-core/tests/overload.rs
根拠
GitHub Actions run 24940960078 とローカル再現で、tests/compiler/overload.n.md::doctest#13/#14/#23/#24/#25 が失敗しました。5件はいずれも calc <(i32)->i32> と calc <(i32,i32)->i32> を同時定義し、同名かつarity違いの overload を選択できる前提のfixtureでした。
問題
Rust integration test nepl-core/tests/overload.rs は「overloaded functions must have the same number of arguments」と明記しています。また RV-CORE-021 で tests/compiler/neplg2.n.md 側も同名arity違いを D3005 として扱う方針へ更新済みです。overload.n.md だけ旧仕様のまま残っていたため、現行compilerの D3005 / D3068 を失敗として扱っていました。
影響
overload.n.md の5件が赤くなり、実際に必要な same-arity overload 解決や型注釈による戻り値選択の回帰と、仕様外のarity違いfixtureが混ざっていました。
修正方針
同名arity違いの overload は選択テストではなく拒否テストとして扱います。既存の same-arity overload / 戻り値型選択 / 引数型選択のfixtureは維持し、arity違いの5件だけを D3005 compile_fail 期待へ揃えます。
対応
overload_select_by_arity* 系の5件を overload_different_arity*_is_error に改名し、実行期待または D3006 期待を compile_fail + diag_id: 3005 へ変更しました。
検証
node nodesrc/tests.js -i tests/compiler/overload.n.md --no-tree -o tmp/overload-rv-core-026.json -j 1(total=45,passed=45,failed=0)node nodesrc/tests.js -i tests/compiler --no-tree -o tmp/compiler-rv-core-026.json -j 4(total=474,passed=474,failed=0)
RV-CORE-027: LLVM top-level #llvmir entry が HIR 関数としてしか解決されない
- 解決済: true
- 状態: verified
- 優先度: P0
- 種別: bug
- 対象:
nepl-core/src/typecheck.rs,nepl-core/src/compiler.rs,nepl-core/src/codegen_llvm.rs,nepl-core/src/llvm_ir.rs
根拠
GitHub Actions run 24943072735 (bb1fb7a) の llvm-test job で、tests/compiler/llvm_target.n.md::doctest#1/#4/#5 が D3092 entry function is missing or ambiguous により失敗しました。これらは top-level #llvmir で define i32 @main() を直接定義する smoke fixture であり、NEPL の fn main は存在しません。
問題
LLVM codegen は top-level #llvmir を最終IRへ連結できますが、typecheck と LLVM prepare 段の #entry 解決は HIR 関数だけを見ていました。そのため raw LLVM IR が @main を定義していても、#entry main は「関数が存在しない」と誤診断され、LLVM smoke が実際の codegen/link 検証へ進めませんでした。
影響
RV-CLI-014 で LLVM smoke の入力pathを実在fixtureへ直した後、これまで0件成功で隠れていた raw LLVM entry の未対応がCI上で顕在化しました。smoke test が赤いままだと、RV-CLI-011 の full dual backend timeout 対策に進む前に、LLVM backendの最小検証自体が機能しません。
修正方針
#entry の意味は維持しつつ、LLVM target の場合だけ top-level #llvmir の define @name(...) も entry 定義として認識します。署名行の解析は codegen_llvm.rs から共有 helper へ分離し、typecheck と LLVM prepare が同じ raw function name 判定を使うようにします。
対応
nepl-core/src/llvm_ir.rs を追加し、LLVM IR の define / declare 行から関数名を抽出する処理を共有化しました。typecheck は #entry 対象の HIR 関数が見つからない場合でも、LLVM target かつ active top-level #llvmir が同名関数を定義していれば D3092 を出さないようにしました。LLVM prepare 段も同じ raw 定義を entry として扱い、HIR reachability 解決を要求しないようにしました。
検証
cargo fmt --all --checkcargo test -p nepl-core codegen_llvm::tests -- --nocapture(9 passed)cargo test -p nepl-cli -- --nocapture(21 passed,2 ignored)trunk buildnode nodesrc/cli.js -i tests/playground_editor --playground-editor-tests -o json=tmp/playground-editor-tests-rv-core-027.json(13/13 passed)
未確認:
- Windows 環境では既存の LLVM Linux host gate により
node nodesrc/tests.js -i tests/compiler/llvm_target.n.md --runner llvmは実行不能です。push CI の Linuxllvm-testでD3092が消えることを確認します。
RV-CORE-028: pipe 左辺の完結した open call が途中で分断される
- 解決済: true
- 状態: verified
- 優先度: P0
- 種別: bug
- 対象:
nepl-core/src/typecheck.rs,nepl-core/tests/pipe_operator.rs
根拠
GitHub Actions run 24943435970 の stdlib-test / wasi-test / nmd-doctest で、collection doctest 群が D3006 no matching overload found を返していました。ローカルでは stdlib/alloc/collections/bitset.nepl::doctest#2/#4/#5 と stdlib/alloc/collections/adjacency_matrix.nepl::doctest#2/#4/#5 が同じ D3006 で失敗しました。
問題
pipe の左辺切り出しは、左辺スタック内に未解決の open call がある場合、常に最後の値だけを左辺として扱っていました。そのため unwrap_ok<BitSet, Diag> new 32 |> insert 5 のように、unwrap_ok (new 32) 全体が既に単一値へ reduce できる式でも、new 32 または 32 だけが pipe 左辺として分断されました。結果として insert へ Result<BitSet, Diag> や i32 が渡り、overload 解決が D3006 で失敗していました。
影響
fixed-size collection の初期化を pipe でつなぐ doctest が広範囲に赤くなり、stdlib API の問題に見えていました。実際には compiler の pipe source 範囲判定が、完結した nested call と未完結の outer call を区別できていない core バグでした。
修正方針
pipe 左辺の候補範囲について、範囲内を副作用なしに試験的に call reduction し、単一値へ reduce できる最も外側の範囲を左辺として採用します。これにより unwrap_ok new 32 のような完結済み call は全体を pipe に渡しつつ、既存の add 1 |> add 2 3 のような未完結 call では最後の値だけを pipe 左辺にする挙動を維持します。
対応
pipe_pending_base を、open call の有無だけではなく「その stack segment が単一値に reduce できるか」で判定する実装へ変更しました。判定時は TypeCtx checkpoint/rollback と diagnostics の巻き戻しを使い、試験的な reduction が本番の型状態や診断へ残らないようにしました。Rust integration test には、new 32 |> unwrap_ok<BitSet, Diag> が BitSet へ解決される回帰テストを追加しました。
検証
cargo test -p nepl-core --test pipe_operator -- --nocapture(21 passed)trunk buildnode nodesrc/tests.js -i stdlib/alloc/collections/bitset.nepl --no-tree -o tmp/bitset-rv-core-028.json -j 1(total=7,passed=7,failed=0)node nodesrc/tests.js -i stdlib/alloc/collections/adjacency_matrix.nepl --no-tree -o tmp/adjacency-rv-core-028.json -j 1(total=6,passed=6,failed=0)
未解決:
tests/stdlib/pipe_collections.n.mdは D3006 ではなく runtime trap 2件へ進みました。残件は collection helper 側の runtime 問題としてRV-STDLIB-013で継続します。
RV-CORE-029: pipe 左辺の試験簡約が open call を再構築せず nullary call を分断する
- 解決済: true
- 状態: verified
- 優先度: P0
- 種別: bug
- 対象:
nepl-core/src/typecheck.rs,nepl-core/tests/pipe_operator.rs
根拠
GitHub Actions run 24943799653 の stdlib-test で、stdlib/alloc/collections/btreemap.nepl::doctest#2-#7 が D3004 type annotation mismatch (expected BTreeMap<i32,i32>, got unit) で失敗しました。この調査中に、同じ unwrap_ok new |> ... 形から末尾セミコロンだけを除いた場合でも、pipe 左辺の試験簡約に nullary call を扱えない core バグが残っていることを確認しました。
問題
RV-CORE-028 で追加した pipe 左辺の試験簡約は、対象 segment を clone して reduce_calls に渡していましたが、segment 内の open_calls を再構築せず空配列のままにしていました。そのため unwrap_ok<BTreeMap<i32,i32>, Diag> new<i32,i32> のように nullary call を含む完結済み式を、試験簡約では単一値へ reduce できませんでした。
結果として pipe 左辺は式全体ではなく最後の new 側へ縮退し、後続の |> insert ... へ BTreeMap ではない値が渡り得る状態でした。
影響
BTreeMap / BTreeSet / Queue / RingBuffer など、new<T> のような0引数generic constructorを unwrap_ok new |> ... 形式でpipe初期化する正当なコードが、compiler の pipe source 範囲判定により壊れる可能性がありました。
実際の stdlib doctest の D3004 には、値ブロック末尾セミコロンが戻り値を unit にしている fixture 問題も含まれていたため、これは RV-STDLIB-019 として分離します。
修正方針
試験簡約用に clone した segment から callable entry の位置を再収集し、その open_calls を使って reduce_calls します。これにより本番のstack状態を汚さず、nullary call も通常のprefix式と同じ規則で単一値へ簡約できるか判定します。
対応
pipe_segment_reduces_to_single_value で segment 内の auto_call function entry を走査し、segment-local な open_calls を構築するようにしました。Rust integration test には unwrap_ok<BTreeMap<i32,i32>, Diag> new<i32,i32> |> insert ... の回帰を追加し、0引数関数を含む完結済みpipe左辺が分断されないことを固定しました。
検証
cargo fmt --all --checkcargo test -p nepl-core --test pipe_operator -- --nocapture(22 passed)cargo build -p nepl-clitrunk build
未解決:
- 実際の
btreemap.nepl::doctest#2-#7はlet hm <BTreeMap<...>>:の値ブロック末尾;により引き続きunitを返します。これはRV-STDLIB-019で修正します。