feat(phase285w): Phase 285W-Syntax-0.1 - Reject weak(...) syntax (Parser-level Fail-Fast)
- Parser guard: Reject weak(...) with LPAREN check in parse_unary()
- Error: "Use 'weak expr', not 'weak(expr)'" (helpful message)
- Location: src/parser/expressions.rs:248-256
- MIR builder guard: Defense-in-depth for any bypassed cases
- Location: src/mir/builder/calls/build.rs:37-46
- Rejection test: apps/tests/phase285w_weak_call_rejected.hako
- Smoke test: phase285w_weak_call_rejected_vm.sh (PASS ✅)
- Documentation:
- EBNF.md: Add ~ (BitNot) to unary operators
- lifecycle.md: Document weak(expr) as invalid syntax
- phase-285/README.md: Add Phase 285W-Syntax-0.1 entry
Test results: 5/6 phase285 tests PASS (1 unrelated failure)
SSOT: docs/reference/language/lifecycle.md
Closes: Phase 285W-Syntax-0.1
This commit is contained in:
@ -94,7 +94,8 @@ Forbidden on **Dead** (Fail-Fast, UseAfterFini):
|
||||
- Method calls
|
||||
- ByRef (`RefGet/RefSet`) operations
|
||||
- Conversions / truthiness (`if dead_box { ... }` is an error)
|
||||
- Creating new weak references from a dead object (`weak(dead)` is an error)
|
||||
- Creating new weak references from a dead object (`weak dead` is an error)
|
||||
- Note: the surface form is `weak <expr>` (not `weak(<expr>)`).
|
||||
|
||||
### Finalization precedence
|
||||
|
||||
@ -175,7 +176,9 @@ Note:
|
||||
Weak references exist to avoid strong cycles and to model back-pointers.
|
||||
|
||||
SSOT operations:
|
||||
- `weak(x)` produces a `WeakRef` to `x` (x must be Alive).
|
||||
- `weak <expr>` produces a `WeakRef` to the target (the target must be Alive).
|
||||
- **Syntax**: `weak <expr>` (unary operator, Phase 285W-Syntax-0)
|
||||
- **Invalid**: `weak(expr)` ❌ (compile error: "Use 'weak expr', not 'weak(expr)'")
|
||||
- `weakRef.weak_to_strong()` returns the target box if it is usable, otherwise `null` (none).
|
||||
- It returns `null` if the target is **Dead** (finalized) or **Freed** (collected).
|
||||
- Note: `null` and `void` are equivalent at runtime (SSOT: `docs/reference/language/types.md`).
|
||||
@ -201,22 +204,22 @@ WeakRef equality:
|
||||
Weak fields enforce strict type requirements at compile time:
|
||||
|
||||
**Allowed assignments** (3 cases):
|
||||
1. **Explicit weak reference**: `me.parent = weak(p)`
|
||||
1. **Explicit weak reference**: `me.parent = weak p`
|
||||
2. **WeakRef variable**: `me.parent = other.parent` (where `other.parent` is weak field)
|
||||
3. **Void**: `me.parent = Void` (clear operation; null is sugar for Void)
|
||||
|
||||
**Forbidden assignments** (Fail-Fast compile error):
|
||||
- Direct BoxRef: `me.parent = p` where `p` is BoxRef
|
||||
- Primitives: `me.parent = 42`
|
||||
- Any non-WeakRef type without explicit `weak()`
|
||||
- Any non-WeakRef type without explicit `weak` conversion
|
||||
|
||||
**Error message example**:
|
||||
```
|
||||
Cannot assign Box (NodeBox) to weak field 'Tree.parent'.
|
||||
Use weak(...) to create weak reference: me.parent = weak(value)
|
||||
Use `weak <expr>` to create weak reference: me.parent = weak value
|
||||
```
|
||||
|
||||
**Rationale**: Explicit `weak()` calls make the semantic difference between strong and weak references visible. This prevents:
|
||||
**Rationale**: Explicit `weak` conversions make the semantic difference between strong and weak references visible. This prevents:
|
||||
- Accidental strong references in weak fields (reference cycles)
|
||||
- Confusion about object lifetime and ownership
|
||||
- Silent bugs from automatic conversions
|
||||
@ -228,7 +231,7 @@ box Node {
|
||||
|
||||
set_parent(p) {
|
||||
// ❌ me.parent = p // Compile error
|
||||
// ✅ me.parent = weak(p) // Explicit weak()
|
||||
// ✅ me.parent = weak p // Explicit weak conversion
|
||||
// ✅ me.parent = Void // Clear operation (SSOT: Void primary)
|
||||
}
|
||||
|
||||
@ -301,7 +304,7 @@ This section documents current backend reality so we can detect drift as bugs.
|
||||
|
||||
| Feature | VM | LLVM | WASM |
|
||||
|---------|-----|------|------|
|
||||
| WeakRef (`weak(x)`, `weak_to_strong()`) | ✅ | ❌ unsupported (285LLVM-1) | ❌ unsupported |
|
||||
| WeakRef (`weak <expr>`, `weak_to_strong()`) | ✅ | ❌ unsupported (285LLVM-1) | ❌ unsupported |
|
||||
| Leak Report (`NYASH_LEAK_LOG`) | ✅ | ⚠️ Parent process roots only (285LLVM-0) | ❌ |
|
||||
|
||||
**LLVM Leak Report の制限** (Phase 285LLVM-0):
|
||||
@ -313,7 +316,7 @@ This section documents current backend reality so we can detect drift as bugs.
|
||||
### Notes
|
||||
|
||||
- **Block-scoped locals** are the language model (`local` drops at `}`), but the *observable* effects depend on where the last strong reference is held.
|
||||
- **WeakRef** (Phase 285A0): VM backend fully supports `weak(x)` and `weak_to_strong()`. LLVM harness support is planned for Phase 285LLVM-1.
|
||||
- **WeakRef** (Phase 285A0): VM backend fully supports `weak <expr>` and `weak_to_strong()`. LLVM harness support is planned for Phase 285LLVM-1.
|
||||
- **WASM backend** currently treats MIR `WeakNew/WeakLoad` as plain copies (weak behaves like strong). This does not satisfy the SSOT weak semantics yet (see also: `docs/guides/wasm-guide/planning/unsupported_features.md`).
|
||||
- **Leak Report** (Phase 285): `NYASH_LEAK_LOG={1|2}` prints exit-time diagnostics showing global roots still held (modules, host_handles, plugin_boxes). See `docs/reference/environment-variables.md`.
|
||||
- Conformance gaps (any backend differences from this document) must be treated as bugs and tracked explicitly; do not "paper over" differences by changing this SSOT without a decision.
|
||||
@ -330,7 +333,7 @@ box SomeBox { }
|
||||
static box Main {
|
||||
main() {
|
||||
local x = new SomeBox()
|
||||
local w = weak(x)
|
||||
local w = weak x
|
||||
x = null
|
||||
local y = w.weak_to_strong()
|
||||
if y == null { print("ok: dropped") }
|
||||
@ -345,8 +348,8 @@ static box Main {
|
||||
main() {
|
||||
local a = new Node()
|
||||
local b = new Node()
|
||||
a.next_weak = weak(b)
|
||||
b.next_weak = weak(a)
|
||||
a.next_weak = weak b
|
||||
b.next_weak = weak a
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user