feat(llvm/phi): Phase 277 P1 - fail-fast validation for PHI strict mode
## Summary Implemented fail-fast validation for PHI ordering and value resolution in strict mode. ## Changes ### P1-1: Strict mode for "PHI after terminator" - File: `src/llvm_py/phi_wiring/wiring.py::ensure_phi` - Behavior: `NYASH_LLVM_PHI_STRICT=1` → RuntimeError if PHI created after terminator - Default: Warning only (no regression) ### P1-2: Strict mode for "fallback 0" - File: `src/llvm_py/phi_wiring/wiring.py::wire_incomings` - Behavior: Strict mode forbids silent fallback to 0 (2 locations) - Location 1: Unresolvable incoming value - Location 2: Type coercion failure - Error messages point to next debug file: `llvm_builder.py::_value_at_end_i64` ### P1-3: Connect verify_phi_ordering() to execution path - File: `src/llvm_py/builders/function_lower.py` - Behavior: Verify PHI ordering after all instructions emitted - Debug mode: Shows "✅ All N blocks have correct PHI ordering" - Strict mode: Raises RuntimeError with block list if violations found ## Testing ✅ Test 1: strict=OFF - passes without errors ✅ Test 2: strict=ON - passes without errors (no violations in test fixtures) ✅ Test 3: debug mode - verify_phi_ordering() connected and running ## Scope - LLVM harness (Python) changes only - No new environment variables (uses existing 3 from Phase 277 P2) - No JoinIR/Rust changes (root fix is Phase 279) - Default behavior unchanged (strict mode opt-in) ## Next Steps - Phase 278: Remove deprecated env var support - Phase 279: Root fix - unify "2本のコンパイラ" pipelines 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -72,7 +72,7 @@ Rust製インタープリターによる高性能実行と、直感的な構文
|
||||
```nyash
|
||||
box ClassName {
|
||||
# フィールド宣言(Phase 12.7形式)
|
||||
field1: TypeBox # フィールド型アノテーション(P0では無視)
|
||||
field1: TypeBox # 型アノテーション(現状は契約として未強制。SSOT: docs/reference/language/types.md)
|
||||
field2: TypeBox
|
||||
field3 # 型なしも可
|
||||
|
||||
@ -133,10 +133,9 @@ static box Main {
|
||||
```
|
||||
|
||||
注意(静的Boxのメソッド引数規約)
|
||||
- 静的Boxのメソッドは先頭に暗黙の `self`(= Singleton)が存在する。
|
||||
- つまり呼び出し側は `Main.main()` のように書いても、意味論上は `Main.main(self, ...)` の形になる。
|
||||
- VM/MIR/LLVM いずれのバックエンドでも、この規約に基づき引数個数(arity)を判定する。
|
||||
- 開発時のガイドライン: 静的Box内に定義する全メソッドは「先頭に `self` を取る」形で設計すること(将来の最適化や検証で一貫性を保つため)。
|
||||
- 静的Boxのメソッドは **暗黙の receiver(`me/self`)を持たない**(既定)。
|
||||
- 呼び出し側の `Main.main()` は、`Main.main/<arity>` のような **receiver無しの関数呼び出し**へ正規化される。
|
||||
- 静的Box内で `me/this` を instance receiver として扱うのは禁止(Fail-Fast)。必要なら `Main.some_static()` の形で呼び出す。
|
||||
|
||||
📌 **構文に関する注意(`static method` について)**
|
||||
|
||||
|
||||
@ -19,6 +19,9 @@ Imports and namespaces
|
||||
Variables and scope
|
||||
- See: reference/language/variables-and-scope.md — Block-scoped locals, assignment resolution, and strong/weak reference guidance.
|
||||
|
||||
Type system (SSOT)
|
||||
- See: reference/language/types.md — runtime truthiness, `+`/compare/equality semantics, and the role/limits of MIR type facts.
|
||||
|
||||
Grammar (EBNF)
|
||||
- See: reference/language/EBNF.md — Stage‑2 grammar specification used by parser implementations.
|
||||
- Unified Members (stored/computed/once/birth_once): see reference/language/EBNF.md “Box Members (Phase 15)” and the Language Reference section. Default ON (disable with `NYASH_ENABLE_UNIFIED_MEMBERS=0`).
|
||||
|
||||
@ -40,21 +40,18 @@ Semicolons and ASI (Automatic Semicolon Insertion)
|
||||
- Ambiguous continuations; parser must Fail‑Fast with a clear message.
|
||||
|
||||
Truthiness (boolean context)
|
||||
- `Bool` → itself
|
||||
- `Integer` → `0` is false; non‑zero is true
|
||||
- `String` → empty string is false; otherwise true
|
||||
- `Array`/`Map` → non‑null is true (size is not consulted)
|
||||
- `null`/`void` → false
|
||||
- SSOT: `reference/language/types.md`(runtime truthiness)
|
||||
- 実行上は `Bool/Integer/Float/String/Void` が中心。`BoxRef` は一部のコアBoxのみ許可され、その他は `TypeError`(Fail-Fast)。
|
||||
|
||||
Equality and Comparison
|
||||
- `==` and `!=` compare primitive values (Integer/Bool/String). No implicit cross‑type coercion.
|
||||
- Box/Instance comparisons should use explicit methods (`equals`), or be normalized by the builder.
|
||||
- Compare operators `< <= > >=` are defined on integers (MVP).
|
||||
- SSOT: `reference/language/types.md`(`==`/`!=` と `< <= > >=` の runtime 仕様)
|
||||
- `==` は一部の cross-kind(`Integer↔Bool`, `Integer↔Float`)を best-effort で扱う。その他は `false`。
|
||||
- `< <= > >=` は `Integer/Float/String` の **同型同士**のみ(異型は `TypeError`)。
|
||||
|
||||
String and Numeric `+`
|
||||
- If either side is `String`, `+` is string concatenation.
|
||||
- If both sides are numeric, `+` is addition.
|
||||
- Other mixes are errors (dev: warn; prod: error) — keep it explicit(必要なら `str(x)` を使う)。
|
||||
- SSOT: `reference/language/types.md`(runtime `+` 仕様)
|
||||
- `Integer+Integer`, `Float+Float` は加算。片側が `String` なら文字列連結(相手は文字列化)。
|
||||
- それ以外(例: `Integer+Bool`, `Integer+Float`)は `TypeError`(Fail-Fast)。
|
||||
|
||||
Blocks and Control
|
||||
- `if (cond) { ... } [else { ... }]`
|
||||
|
||||
133
docs/reference/language/types.md
Normal file
133
docs/reference/language/types.md
Normal file
@ -0,0 +1,133 @@
|
||||
# Type System (SSOT)
|
||||
|
||||
Status: Draft / active (2025-12)
|
||||
|
||||
This document defines the **current, executable** type semantics of Nyash/Hakorune.
|
||||
Implementation is currently anchored to the Rust VM (`src/backend/mir_interpreter/*`).
|
||||
|
||||
If another backend differs from this document, treat it as a bug unless explicitly noted.
|
||||
|
||||
Coercion SSOT status:
|
||||
- Decisions: `docs/development/current/main/phases/phase-274/P3-DECISIONS.md`
|
||||
- Implemented (VM + LLVM parity): Phase 275 P0
|
||||
|
||||
---
|
||||
|
||||
## 1. Big Picture
|
||||
|
||||
- Nyash is **dynamically typed**: runtime values carry a tag (Integer/Float/Bool/String/Void/BoxRef/Future).
|
||||
- `local` declares a variable; **re-assignment is allowed** (single keyword policy).
|
||||
- There is currently no static type checker. Some parts of MIR carry **type facts** as metadata for optimization / routing, not for semantics.
|
||||
|
||||
Terminology (SSOT):
|
||||
- **Runtime type**: what the VM executes on (`VMValue`).
|
||||
- **MIR type facts**: builder annotations (`MirType`, `value_types`, `value_origin_newbox`, `TypeCertainty`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Variables and Re-assignment
|
||||
|
||||
- `local x` / `local x = expr` introduces a mutable local variable.
|
||||
- Re-assignment is always allowed: `x = expr`.
|
||||
- “Immutable locals” (let/const) are not part of the language today; they can be introduced later as lint/strict checks without changing core semantics.
|
||||
|
||||
Note: Field type annotations like `field: TypeBox` exist in syntax, but are currently **not enforced** as a type contract (docs-only) — see `LANGUAGE_REFERENCE_2025.md`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Boolean Context (truthiness)
|
||||
|
||||
Boolean context means:
|
||||
- `if (cond) { ... }`
|
||||
- `loop(cond) { ... }`
|
||||
- `!cond`
|
||||
- branch conditions generated from `&&` / `||` lowering
|
||||
|
||||
Runtime rule (SSOT) is implemented by `to_bool_vm` (`src/backend/abi_util.rs`):
|
||||
|
||||
- `Bool` → itself
|
||||
- `Integer` → `0` is false; non-zero is true
|
||||
- `Float` → `0.0` is false; non-zero is true
|
||||
- `String` → empty string is false; otherwise true
|
||||
- `Void` → **TypeError** (fail-fast)
|
||||
- `BoxRef`:
|
||||
- bridge boxes only:
|
||||
- `BoolBox` / `IntegerBox` / `StringBox` are unboxed and coerced like their primitive equivalents
|
||||
- `VoidBox` is treated as `Void` → **TypeError**
|
||||
- other BoxRef types → **TypeError**
|
||||
- `Future` → error (`TypeError`)
|
||||
|
||||
This is intentionally fail-fast: “any object is truthy” is **not** assumed by default today.
|
||||
|
||||
---
|
||||
|
||||
## 4. Operators: `+`, comparisons, equality
|
||||
|
||||
### 4.1 `+` (BinaryOp::Add)
|
||||
|
||||
Runtime semantics are defined in the Rust VM (`eval_binop` in `src/backend/mir_interpreter/helpers.rs`):
|
||||
|
||||
- Numeric addition:
|
||||
- `Integer + Integer` → `Integer`
|
||||
- `Float + Float` → `Float`
|
||||
- Numeric promotion:
|
||||
- `Integer + Float` / `Float + Integer` → `Float` (promote int→float)
|
||||
- String concatenation:
|
||||
- `String + String` → `String`
|
||||
- Other combinations are `TypeError` (e.g., `Integer + Bool`, `Integer + Float`, `Bool + Bool`, `BoxRef + ...`).
|
||||
|
||||
Dev-only note:
|
||||
- `NYASH_VM_TOLERATE_VOID=1` (or `--dev` paths) may tolerate `Void` in some arithmetic as a safety valve; do not rely on it for spec.
|
||||
|
||||
### 4.2 `< <= > >=` (CompareOp)
|
||||
|
||||
Runtime semantics (`eval_cmp` in `src/backend/mir_interpreter/helpers.rs`):
|
||||
|
||||
- `Integer <=> Integer`
|
||||
- `Float <=> Float`
|
||||
- `String <=> String` (lexicographic)
|
||||
- Other combinations are `TypeError`.
|
||||
|
||||
### 4.3 `==` / `!=`
|
||||
|
||||
Equality is implemented as `eq_vm` (`src/backend/abi_util.rs`) and used by comparisons:
|
||||
|
||||
- Same-kind equality for primitives: `Integer/Float/Bool/String/Void`.
|
||||
- Cross-kind coercions (Number-only):
|
||||
- `Integer` ↔ `Float` only, with a precise rule (avoid accidental true via float rounding)
|
||||
- `BoxRef == BoxRef` is pointer identity (`Arc::ptr_eq`).
|
||||
- `Void` is treated as equal to `BoxRef(VoidBox)` and `BoxRef(MissingBox)` for backward compatibility.
|
||||
- Other mixed kinds are `false` (not an error).
|
||||
|
||||
Precise rule for `Int == Float` (or `Float == Int`):
|
||||
- if Float is NaN → false
|
||||
- if Float is finite, integral, and exactly representable as i64 → compare as i64
|
||||
- otherwise → false
|
||||
|
||||
---
|
||||
|
||||
## 5. `is` / `as` and TypeOp
|
||||
|
||||
Source patterns like `x.is("TypeName")` / `x.as("TypeName")` are lowered to MIR `TypeOp(Check/Cast)` (see `src/mir/builder/exprs.rs`).
|
||||
|
||||
Runtime behavior (Rust VM):
|
||||
- `TypeOp(Check, value, ty)` produces a `Bool`.
|
||||
- `TypeOp(Cast, value, ty)` returns the input value if it matches; otherwise `TypeError`.
|
||||
|
||||
Backend note:
|
||||
- LLVM (llvmlite harness) must match this SSOT; if it differs, treat it as a bug.
|
||||
- Tracking: Phase 274 P2 (`docs/development/current/main/phases/phase-274/P2-INSTRUCTIONS.md`).
|
||||
|
||||
---
|
||||
|
||||
## 6. MIR Type Facts (non-semantic metadata)
|
||||
|
||||
MIR has a lightweight type vocabulary (`MirType` in `src/mir/types.rs`) and per-value metadata:
|
||||
- `value_types: ValueId -> MirType` (type annotations / inferred hints)
|
||||
- `value_origin_newbox: ValueId -> BoxName` (origin facts for “Known receiver”)
|
||||
- `TypeCertainty::{Known, Union}` used by call routing (`src/mir/definitions/call_unified.rs`)
|
||||
|
||||
Important rule:
|
||||
- These facts are for **optimization/routing** (e.g., Known-only rewrite, callee resolution) and must not be treated as semantic truth.
|
||||
|
||||
If you need semantics, define it at the runtime layer (VM) and then optionally optimize by using these facts.
|
||||
Reference in New Issue
Block a user