Appearance
| 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 |