Appearance
| 1 | namespace IR.Values is | |
| 2 | use Semantic.Types.Type | |
| 3 | ||
| 4 | // The result of `a ?? b` for a reference-typed `a: T?`. `T?` is a | |
| 5 | // reference that may be null at IL, so a single dup-and-branch is | |
| 6 | // enough — `b` is evaluated only when `a` is null. | |
| 7 | // | |
| 8 | // <left IL> // [..., a] | |
| 9 | // dup // [..., a, a] | |
| 10 | // brtrue.s <end> // pops the top a; non-null leaves the | |
| 11 | // // other a on the stack at end | |
| 12 | // pop // [...] | |
| 13 | // <right IL> // [..., b] | |
| 14 | // <end>: | |
| 15 | // | |
| 16 | // Built by COMPILE_OPERATORS.visit_binary when the operator is `??`. | |
| 17 | // The two operands are evaluated by their own Values; this Value | |
| 18 | // composes the surrounding short-circuit shell. | |
| 19 | class NULL_COALESCE: Value is | |
| 20 | left: Value | |
| 21 | right: Value | |
| 22 | _result_type: Type | |
| 23 | ||
| 24 | type: Type => _result_type | |
| 25 | is_lightweight_pure: bool => false | |
| 26 | ||
| 27 | init(left: Value, right: Value, result_type: Type) is | |
| 28 | super.init() | |
| 29 | ||
| 30 | self.left = left | |
| 31 | self.right = right | |
| 32 | self._result_type = result_type | |
| 33 | si | |
| 34 | ||
| 35 | gen(context: IR.CONTEXT) is | |
| 36 | let end_label = IR.LABEL() | |
| 37 | ||
| 38 | gen(left, context) | |
| 39 | ||
| 40 | let body = context.current_srm_body_emitter! | |
| 41 | body.op(System.Reflection.Metadata.ILOpCode.DUP) | |
| 42 | body.branch(System.Reflection.Metadata.ILOpCode.BRTRUE, end_label) | |
| 43 | body.op(System.Reflection.Metadata.ILOpCode.POP) | |
| 44 | gen(right, context) | |
| 45 | body.mark_label(end_label) | |
| 46 | si | |
| 47 | ||
| 48 | to_string() -> string => | |
| 49 | "null-coalesce:[{type}]({left},{right})" | |
| 50 | si | |
| 51 | si |