Skip to content
← Back

src/syntax/process/void_tolerant_position.ghul

1
namespace Syntax.Process is
2
use Type = Semantic.Types.Type
3
4
// Whether a composite expression (`if` / `case`) sitting in a
5
// position that wants a value but tolerates a void one should
6
// decline to produce a value at all, and be compiled as the
7
// statement it is.
8
//
9
// Two positions tolerate void: the body of a function literal whose
10
// return type is still being inferred, where nothing has yet said
11
// whether the body yields a value, and a function body's implicit
12
// tail, where a void tail is an effect-only statement that falls
13
// through rather than returning. In both, a composite with no arm
14
// yielding a non-void value - void arms, diverging arms, or a mix -
15
// is the statement it is, so an arm that only calls a void function
16
// is not an error the way it is in `let x = if ... fi`, and a guard
17
// whose arms all return has no else demanded of it. Arms that do
18
// yield a value keep the value form, so a void arm mixed in with
19
// them is still reported where it cannot be consumed.
20
class VOID_TOLERANT_POSITION is
21
declines_value(
22
void_tolerated: bool,
23
seen_non_void_arm: bool
24
) -> bool static pure =>
25
void_tolerated /\
26
!seen_non_void_arm
27
28
// An arm in error says nothing about whether the composite
29
// yields a value: what it would have produced is unknown, and
30
// on a walk made before the types around it are known the error
31
// is that walk's alone. So a composite with such an arm, and
32
// none that yields a value, neither declines nor joins: it is
33
// in error itself, silently, and a later walk decides.
34
is_undecided(
35
void_tolerated: bool,
36
seen_non_void_arm: bool,
37
seen_error_arm: bool
38
) -> bool static pure =>
39
void_tolerated /\
40
!seen_non_void_arm /\
41
seen_error_arm
42
43
is_in_error(type: Type?) -> bool static pure =>
44
type? /\ type.is_error
45
46
// An arm's contribution to the count above. An error-typed arm
47
// does not count: it has already been reported, and letting it
48
// force the value form would pile a second diagnostic onto the
49
// same arm. Neither does an arm typed at the enclosing
50
// function's own unsettled return - a recursive self-call in a
51
// composite that is itself helping to settle that return -
52
// since nothing has said yet that it yields a value. An
53
// unresolved variable type does count: it stands for a slot
54
// some later walk will fill with a real type, not for a body
55
// that might turn out to be void.
56
counts_as_non_void(type: Type?) -> bool static pure =>
57
type? /\
58
!type.is_void /\
59
!type.is_error /\
60
!isa Semantic.Types.INFERRED_RETURN_TYPE(type)
61
si
62
si