Appearance
| 1 | namespace Syntax.Trees.Expressions is | |
| 2 | use Source | |
| 3 | ||
| 4 | // `val ... lav` — a value-producing block. | |
| 5 | // | |
| 6 | // The block's value is the LUB of every contributing source: the | |
| 7 | // tail expression of `body` (if the tail provides a value) and | |
| 8 | // every `return E` whose target is this block. `return E` inside | |
| 9 | // a `val ... lav` exits this block (innermost wins on nesting), | |
| 10 | // not the enclosing function. | |
| 11 | class VAL_BLOCK: Expression is | |
| 12 | body: Statements.LIST public | |
| 13 | ||
| 14 | // True when the block was written in its parenthesised | |
| 15 | // spelling `(statement; ...; value)` rather than as | |
| 16 | // `val ... lav`. Semantics are identical; the formatter uses | |
| 17 | // this to round-trip the spelling the user wrote. | |
| 18 | is_parenthesised: bool public | |
| 19 | ||
| 20 | // A block yields a tuple literal when its tail is one and no | |
| 21 | // return contributes a value of another shape. | |
| 22 | is_tuple_literal: bool => body.is_tuple_literal /\ !has_targeted_return | |
| 23 | ||
| 24 | // Set by the wrapping context (compile-expressions). False | |
| 25 | // when the block is in expression-statement position or in a | |
| 26 | // void-returning `=>` body — fall-through is allowed to be | |
| 27 | // void there. True everywhere else. | |
| 28 | want_value: bool public => block_state.want_value, = value is block_state.want_value = value si | |
| 29 | ||
| 30 | // True where a value is wanted but a void one is acceptable — | |
| 31 | // the body of a function literal whose return type is still | |
| 32 | // being inferred. A body that yields no value there settles | |
| 33 | // the block, and the literal's return, as void. | |
| 34 | void_tolerated: bool public => block_state.void_tolerated, = value is block_state.void_tolerated = value si | |
| 35 | ||
| 36 | // Pushed expected_type from outer context, threaded onto the | |
| 37 | // tail expression and every return that targets us so they | |
| 38 | // participate in inference / overload resolution against the | |
| 39 | // expected type. | |
| 40 | expected_type: Semantic.Types.Type? public => block_state.expected_type, = value is block_state.expected_type = value si | |
| 41 | expected_type_error_message: string? public => block_state.expected_type_error_message, = value is block_state.expected_type_error_message = value si | |
| 42 | ||
| 43 | // Collected at compile-expressions time: the value type of | |
| 44 | // every return targeting this block. visit() LUBs these with | |
| 45 | // the tail's value type to settle the block's value type. | |
| 46 | return_types: Collections.MutableList[Semantic.Types.Type] => block_state.returns() | |
| 47 | ||
| 48 | // True when any RETURN statement inside the body targets | |
| 49 | // this block (with or without an expression). `return_types` | |
| 50 | // alone misses bare `return;`; this flag is set by | |
| 51 | // compile_bindings.pre_return whenever a return's target is | |
| 52 | // resolved to this block. | |
| 53 | has_targeted_return: bool public => block_state.has_targeted_return, = value is block_state.has_targeted_return = value si | |
| 54 | ||
| 55 | // Label placed at end of block body in generate-il; returns | |
| 56 | // with this block as target push their value and `br` here. | |
| 57 | // All paths (every targeted return + the natural fall- | |
| 58 | // through) converge with the value on the evaluation stack — | |
| 59 | // the same shape `if`/`case`-in-expression IL uses, so async | |
| 60 | // and generator state machines work without value-across- | |
| 61 | // suspend special handling. | |
| 62 | end_label: IR.LABEL? public => block_state.end_label, = value is block_state.end_label = value si | |
| 63 | ||
| 64 | block_state: Syntax.Process.VAL_BLOCK_STATE field | |
| 65 | ||
| 66 | init(location: LOCATION, body: Statements.LIST) is | |
| 67 | super.init(location) | |
| 68 | ||
| 69 | ||
| 70 | self.body = body | |
| 71 | self.want_value = true | |
| 72 | self.void_tolerated = false | |
| 73 | si | |
| 74 | ||
| 75 | clear() is | |
| 76 | super.clear() | |
| 77 | block_state.clear() | |
| 78 | si | |
| 79 | ||
| 80 | clear_outputs() is | |
| 81 | super.clear_outputs() | |
| 82 | block_state.clear_outputs() | |
| 83 | si | |
| 84 | ||
| 85 | set_expected_type(expected_type: Semantic.Types.Type?, error_message: string?) is | |
| 86 | self.expected_type = expected_type | |
| 87 | self.expected_type_error_message = error_message | |
| 88 | ||
| 89 | // Push the constraint onto the tail expression so it | |
| 90 | // participates in inference / overload resolution against | |
| 91 | // the expected type — same shape as `if`/`case` | |
| 92 | // expression-position branches. Returns targeting this | |
| 93 | // block pick the constraint up from `expected_type` via | |
| 94 | // compile_bindings.pre_return. | |
| 95 | body.set_expected_type(expected_type, error_message) | |
| 96 | si | |
| 97 | ||
| 98 | clear_expected_type() is | |
| 99 | expected_type = null | |
| 100 | expected_type_error_message = null | |
| 101 | body.clear_expected_type() | |
| 102 | si | |
| 103 | ||
| 104 | accept(visitor: Visitor) is | |
| 105 | visitor.visit(self) | |
| 106 | si | |
| 107 | ||
| 108 | walk(visitor: Visitor) is | |
| 109 | if !visitor.pre(self) then | |
| 110 | body.walk(visitor) | |
| 111 | fi | |
| 112 | ||
| 113 | accept(visitor) | |
| 114 | si | |
| 115 | si | |
| 116 | si |