Appearance
| 1 | namespace Semantic is | |
| 2 | use Types.Type | |
| 3 | ||
| 4 | // What a function's inferred return type settles at once one of its | |
| 5 | // returns has produced null. A null says a value can be absent | |
| 6 | // without saying what it holds when present, so it settles nothing | |
| 7 | // itself: what it does is make whatever the other returns settled on | |
| 8 | // able to be absent. | |
| 9 | // | |
| 10 | // The widening is the one ARM_NULL_JOIN already decides for an if or | |
| 11 | // case arm, so a body's returns and an expression's arms answer | |
| 12 | // alike. | |
| 13 | class NULL_RETURN_JOIN is | |
| 14 | of( | |
| 15 | pinned: Type, | |
| 16 | returned_genuine_null: bool, | |
| 17 | innate_symbol_lookup: Lookups.InnateSymbolLookup | |
| 18 | ) -> Type static is | |
| 19 | if !returned_genuine_null then | |
| 20 | return pinned | |
| 21 | fi | |
| 22 | ||
| 23 | // Already able to be absent - the slot asked for an optional, | |
| 24 | // or another return produced one - so the null adds nothing | |
| 25 | // and wrapping again would make an optional of an optional. | |
| 26 | if pinned.is_optional \/ pinned.is_maybe then | |
| 27 | return pinned | |
| 28 | fi | |
| 29 | ||
| 30 | let decision = ARM_NULL_JOIN().decide(pinned, true, true) | |
| 31 | ||
| 32 | if decision == ArmNullJoinDecision.WIDEN_VALUE_OPTIONAL then | |
| 33 | return innate_symbol_lookup.get_optional_type(pinned) | |
| 34 | fi | |
| 35 | ||
| 36 | if decision == ArmNullJoinDecision.WIDEN_REFERENCE_OPTIONAL then | |
| 37 | return pinned | |
| 38 | .as_optional() | |
| 39 | fi | |
| 40 | ||
| 41 | // A type variable has no optional carrier to widen into, the | |
| 42 | // same verdict an arm reaches: left as it is, and whatever | |
| 43 | // the return is checked against reports it. | |
| 44 | return pinned | |
| 45 | si | |
| 46 | si | |
| 47 | si |