Appearance
| 1 | namespace IR.Values is | |
| 2 | use System.NotImplementedException | |
| 3 | ||
| 4 | use TypeTyped = Semantic.Types.Typed | |
| 5 | use Semantic.Types.Type | |
| 6 | use Semantic.Symbols.Symbol | |
| 7 | ||
| 8 | class Value abstract is | |
| 9 | has_symbol: bool => false | |
| 10 | is_value_type: bool => let t = type in t? /\ t.is_value_type | |
| 11 | is_self: bool => false | |
| 12 | is_super: bool => false | |
| 13 | is_deref: bool => false | |
| 14 | has_address: bool => false | |
| 15 | // True for a value whose evaluation transfers control to user | |
| 16 | // or reflected code — a real call or a construction — which can | |
| 17 | // reassign a field through an aliased receiver. Intrinsic | |
| 18 | // (INNATE) operations and plain loads stay false. The flow pass | |
| 19 | // drops field narrows after such a value; see NARROWING_FLOW.on_call. | |
| 20 | is_state_changing_call: bool => false | |
| 21 | // True for a state-changing call whose callee writes only its | |
| 22 | // own receiver's internal state and reaches no user code. The | |
| 23 | // flow pass applies the heap-store transfer rather than the | |
| 24 | // full call transfer for one of these, keeping field narrows | |
| 25 | // and dropping property ones; see NARROWING_FLOW.on_call. | |
| 26 | is_receiver_interior_call: bool => false | |
| 27 | // True for a function pointer that must be obtained with | |
| 28 | // `ldvirtftn` rather than `ldftn` — consulted by DELEGATE.gen | |
| 29 | // to `dup` the receiver first, since `ldvirtftn` consumes it. | |
| 30 | is_virtual_dispatch: bool => false | |
| 31 | is_consumable: bool => true | |
| 32 | is_need_store: bool => false | |
| 33 | is_block: bool => false | |
| 34 | is_lightweight_pure: bool => false | |
| 35 | is_type_expression: bool => false | |
| 36 | ||
| 37 | // The function this value produces a callable reference to, | |
| 38 | // seen through any wrapper that binds it to a receiver or | |
| 39 | // caches it. Null for everything that is not such a | |
| 40 | // reference. Lets a caller reach the callee's own properties | |
| 41 | // without knowing which wrappers a given reference shape | |
| 42 | // acquired on the way. | |
| 43 | referenced_function: Semantic.Symbols.Function? => null | |
| 44 | ||
| 45 | // Ambient location captured at construction time, if the | |
| 46 | // active COMPILE_EXPRESSIONS walk pushed one onto | |
| 47 | // IoC.CONTAINER.instance.location_stack. Subclasses that | |
| 48 | // carry an explicit location of their own (DUMMY, | |
| 49 | // TYPE_EXPRESSION) shadow these. | |
| 50 | _ambient_location: Source.LOCATION? | |
| 51 | ||
| 52 | has_location: bool => _ambient_location? | |
| 53 | location: Source.LOCATION => | |
| 54 | if _ambient_location? then | |
| 55 | _ambient_location | |
| 56 | else | |
| 57 | Source.LOCATION.internal | |
| 58 | fi | |
| 59 | ||
| 60 | non_consumable_message: string => "cannot use this here" | |
| 61 | ||
| 62 | type: Type? pure => null | |
| 63 | symbol: Symbol => throw NotImplementedException("value has no symbol") | |
| 64 | check_is_consumable(logger: Logging.Logger, location: Source.LOCATION, value: Value?) -> bool static => | |
| 65 | value? /\ | |
| 66 | value.check_is_consumable(logger, location) | |
| 67 | ||
| 68 | check_is_consumable(logger: Logging.Logger, location: Source.LOCATION) -> bool is | |
| 69 | if !is_consumable then | |
| 70 | logger.error(location, non_consumable_message) | |
| 71 | return false | |
| 72 | fi | |
| 73 | ||
| 74 | let value_type = type | |
| 75 | ||
| 76 | if !value_type? then | |
| 77 | logger.mark_consumed_error() | |
| 78 | return false | |
| 79 | elif value_type.is_error then | |
| 80 | logger.mark_consumed_error() | |
| 81 | return true | |
| 82 | elif value_type.is_sentinel \/ value_type.contains_inferred then | |
| 83 | // Nested placeholder counts too — a value of type | |
| 84 | // `Func<placeholder, int>` is consumable only after the | |
| 85 | // retry loop resolves the inner slot. Marking | |
| 86 | // consumed_any drives that retry. | |
| 87 | logger.mark_consumed_any() | |
| 88 | return true | |
| 89 | elif value_type.is_void then | |
| 90 | logger.error(location, "cannot use void value here") | |
| 91 | return false | |
| 92 | fi | |
| 93 | ||
| 94 | return true | |
| 95 | si | |
| 96 | ||
| 97 | check_is_consumable_allow_void(logger: Logging.Logger, location: Source.LOCATION, value: Value?) -> bool static => | |
| 98 | value? /\ | |
| 99 | value.check_is_consumable_allow_void(logger, location) | |
| 100 | ||
| 101 | check_is_consumable_allow_void(logger: Logging.Logger, location: Source.LOCATION) -> bool is | |
| 102 | if !is_consumable then | |
| 103 | logger.error(location, non_consumable_message) | |
| 104 | return false | |
| 105 | fi | |
| 106 | ||
| 107 | let value_type = type | |
| 108 | ||
| 109 | if !value_type? then | |
| 110 | logger.mark_consumed_error() | |
| 111 | return false | |
| 112 | elif value_type.is_error then | |
| 113 | logger.mark_consumed_error() | |
| 114 | elif value_type.is_sentinel \/ value_type.contains_inferred then | |
| 115 | logger.mark_consumed_any() | |
| 116 | fi | |
| 117 | ||
| 118 | return true | |
| 119 | si | |
| 120 | ||
| 121 | get_temp_copier(block: IR.Values.BLOCK, prefix: string) -> (() -> Value) => | |
| 122 | if is_lightweight_pure then | |
| 123 | () => self | |
| 124 | elif type!.is_error then | |
| 125 | () => DUMMY(type!, location) | |
| 126 | else | |
| 127 | let temp = TEMP(block, prefix, self) | |
| 128 | () => temp.load() | |
| 129 | fi | |
| 130 | ||
| 131 | gen(context: IR.CONTEXT) => throw NotImplementedException("value gen: {get_type()} {self}") | |
| 132 | gen_address(context: IR.CONTEXT) is | |
| 133 | throw NotImplementedException("value gen address: {get_type()} {self}") | |
| 134 | si | |
| 135 | ||
| 136 | gen(value: Value?, context: IR.CONTEXT) static is | |
| 137 | if value? then | |
| 138 | value.gen(context) | |
| 139 | else | |
| 140 | context.fixme("null value") | |
| 141 | fi | |
| 142 | si | |
| 143 | ||
| 144 | init() is | |
| 145 | _ambient_location = IoC.CONTAINER.instance.location_stack.current | |
| 146 | si | |
| 147 | ||
| 148 | to_string() -> string => "IR.Value {get_type()}" | |
| 149 | si | |
| 150 | si |