Skip to content
← Back

src/syntax/trees/expressions/val_block.ghul

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
// Set by the wrapping context (compile-expressions). False
15
// when the block is in expression-statement position or in a
16
// void-returning `=>` body — fall-through is allowed to be
17
// void there. True everywhere else.
18
want_value: bool public;
19
20
// Pushed expected_type from outer context, threaded onto the
21
// tail expression and every return that targets us so they
22
// participate in inference / overload resolution against the
23
// expected type.
24
expected_type: Semantic.Types.Type? public;
25
expected_type_error_message: string? public;
26
27
// Collected at compile-expressions time: the value type of
28
// every return targeting this block. visit() LUBs these with
29
// the tail's value type to settle the block's value type.
30
return_types: Collections.MutableList[Semantic.Types.Type] public;
31
32
// True when any RETURN statement inside the body targets
33
// this block (with or without an expression). `return_types`
34
// alone misses bare `return;`; this flag is set by
35
// compile_bindings.pre_return whenever a return's target is
36
// resolved to this block.
37
has_targeted_return: bool public;
38
39
// Label placed at end of block body in generate-il; returns
40
// with this block as target push their value and `br` here.
41
// All paths (every targeted return + the natural fall-
42
// through) converge with the value on the evaluation stack —
43
// the same shape `if`/`case`-in-expression IL uses, so async
44
// and generator state machines work without value-across-
45
// suspend special handling.
46
end_label: IR.LABEL? public;
47
48
init(location: LOCATION, body: Statements.LIST) is
49
super.init(location);
50
51
52
self.body = body;
53
self.want_value = true;
54
self.return_types = Collections.LIST[Semantic.Types.Type]();
55
si
56
57
clear() is
58
super.clear();
59
60
want_value = true;
61
expected_type = null;
62
expected_type_error_message = null;
63
return_types = Collections.LIST[Semantic.Types.Type]();
64
has_targeted_return = false;
65
end_label = null;
66
si
67
68
set_expected_type(expected_type: Semantic.Types.Type?, error_message: string?) is
69
self.expected_type = expected_type;
70
self.expected_type_error_message = error_message;
71
72
// Push the constraint onto the tail expression so it
73
// participates in inference / overload resolution against
74
// the expected type — same shape as `if`/`case`
75
// expression-position branches. Returns targeting this
76
// block pick the constraint up from `expected_type` via
77
// compile_bindings.pre_return.
78
body.set_expected_type(expected_type, error_message);
79
si
80
81
clear_expected_type() is
82
expected_type = null;
83
expected_type_error_message = null;
84
body.clear_expected_type();
85
si
86
87
accept(visitor: Visitor) is
88
visitor.visit(self);
89
si
90
91
walk(visitor: Visitor) is
92
if !visitor.pre(self) then
93
body.walk(visitor);
94
fi
95
96
accept(visitor);
97
si
98
si
99
si