Appearance
| 1 | namespace IR.Values is | |
| 2 | use Semantic.Types.Type; | |
| 3 | ||
| 4 | // Project a flow-narrowed value-type optional (`MAYBE[T]` / | |
| 5 | // `NULLABLE[T]`) to its inner `T`. `underlying` is the original | |
| 6 | // wrapper load; `projected` is the `.value` access against that | |
| 7 | // wrapper. The type-system view is `T`, so member access, | |
| 8 | // operator resolution and slot-boundary coercion all see the | |
| 9 | // narrowed type. IL gen emits the projection. `visit_has_value` | |
| 10 | // and `visit_unwrap` peel back to `underlying` so the wrapper- | |
| 11 | // shaped operations stay sound. | |
| 12 | class NARROW_PROJECT: Value is | |
| 13 | underlying: Value; | |
| 14 | projected: Value; | |
| 15 | ||
| 16 | type: Type? => projected.type; | |
| 17 | has_symbol: bool => underlying.has_symbol; | |
| 18 | symbol: Semantic.Symbols.Symbol => underlying.symbol; | |
| 19 | is_lightweight_pure: bool => projected.is_lightweight_pure; | |
| 20 | ||
| 21 | init(underlying: Value, projected: Value) is | |
| 22 | super.init(); | |
| 23 | ||
| 24 | self.underlying = underlying; | |
| 25 | self.projected = projected; | |
| 26 | si | |
| 27 | ||
| 28 | // Strip a NARROW_PROJECT wrapper back to the underlying | |
| 29 | // optional-shaped load — for consumers (`?`, `!`, refutable | |
| 30 | // binding) that want to operate on the wrapper itself. A | |
| 31 | // no-op when `value` isn't a projection. | |
| 32 | peel(value: Value?) -> Value? static => | |
| 33 | if isa NARROW_PROJECT(value) then | |
| 34 | (cast NARROW_PROJECT(value)).underlying; | |
| 35 | else | |
| 36 | value; | |
| 37 | fi; | |
| 38 | ||
| 39 | gen(context: IR.CONTEXT) is | |
| 40 | gen(projected, context); | |
| 41 | si | |
| 42 | ||
| 43 | to_string() -> string => | |
| 44 | "narrow-project:[{type}]({underlying})"; | |
| 45 | si | |
| 46 | si |