Appearance
| 1 | namespace IR.Values is | |
| 2 | use Semantic.Types.Type; | |
| 3 | ||
| 4 | // The result of `a ?? b` for a value-type optional `a` — | |
| 5 | // NULLABLE[T] or MAYBE[T]. The receiver is spilled to a local so | |
| 6 | // its address can feed the has_value / value accessor calls: the | |
| 7 | // left operand can be any expression, not just an addressable | |
| 8 | // slot. `b` is evaluated only on the absent path. | |
| 9 | // | |
| 10 | // .locals init (<recv type> '.coalesce.N') | |
| 11 | // <receiver IL> // [..., recv] | |
| 12 | // stloc '.coalesce.N' // [...] | |
| 13 | // ldloca '.coalesce.N' // [..., &recv] | |
| 14 | // <presence_test IL> // [..., bool] (get_has_value on 'this' addr) | |
| 15 | // brfalse <absent> | |
| 16 | // ldloca '.coalesce.N' // [..., &recv] | |
| 17 | // <value_extract IL> // [..., T] (get_value on 'this' addr) | |
| 18 | // <present_arm IL> // [..., R] (coercion over the payload, often nothing) | |
| 19 | // br <end> | |
| 20 | // <absent>: | |
| 21 | // <absent_arm IL> // [..., R] | |
| 22 | // <end>: | |
| 23 | // | |
| 24 | // Built by COMPILE_OPERATORS._visit_null_coalesce. Branches use | |
| 25 | // the long forms — either arm can hold an arbitrarily large | |
| 26 | // expression. | |
| 27 | class NULL_COALESCE_VALUE: Value is | |
| 28 | receiver: Value; | |
| 29 | presence_test: Value; | |
| 30 | value_extract: Value; | |
| 31 | present_arm: Value; | |
| 32 | absent_arm: Value; | |
| 33 | _result_type: Type; | |
| 34 | ||
| 35 | type: Type => _result_type; | |
| 36 | is_lightweight_pure: bool => false; | |
| 37 | ||
| 38 | init( | |
| 39 | receiver: Value, | |
| 40 | presence_test: Value, | |
| 41 | value_extract: Value, | |
| 42 | present_arm: Value, | |
| 43 | absent_arm: Value, | |
| 44 | result_type: Type | |
| 45 | ) is | |
| 46 | super.init(); | |
| 47 | ||
| 48 | self.receiver = receiver; | |
| 49 | self.presence_test = presence_test; | |
| 50 | self.value_extract = value_extract; | |
| 51 | self.present_arm = present_arm; | |
| 52 | self.absent_arm = absent_arm; | |
| 53 | self._result_type = result_type; | |
| 54 | si | |
| 55 | ||
| 56 | gen(context: IR.CONTEXT) is | |
| 57 | let id = TEMP.get_next_id(); | |
| 58 | let absent_label = IR.LABEL(); | |
| 59 | let end_label = IR.LABEL(); | |
| 60 | ||
| 61 | context.write_line(".locals init ({receiver.type!.get_il_type()} '.coalesce.{id}')"); | |
| 62 | gen(receiver, context); | |
| 63 | context.write_line("stloc '.coalesce.{id}'"); | |
| 64 | context.write_line("ldloca '.coalesce.{id}'"); | |
| 65 | gen(presence_test, context); | |
| 66 | context.write_line("brfalse {absent_label}"); | |
| 67 | context.write_line("ldloca '.coalesce.{id}'"); | |
| 68 | gen(value_extract, context); | |
| 69 | gen(present_arm, context); | |
| 70 | context.write_line("br {end_label}"); | |
| 71 | context.write_line("{absent_label}:"); | |
| 72 | gen(absent_arm, context); | |
| 73 | context.write_line("{end_label}:"); | |
| 74 | si | |
| 75 | ||
| 76 | to_string() -> string => | |
| 77 | "null-coalesce-value:[{type}]({receiver},{absent_arm})"; | |
| 78 | si | |
| 79 | si |