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 open 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 function pointer that must be obtained with | |
| 22 | // `ldvirtftn` rather than `ldftn` — consulted by DELEGATE.gen | |
| 23 | // to `dup` the receiver first, since `ldvirtftn` consumes it. | |
| 24 | is_virtual_dispatch: bool => false; | |
| 25 | is_consumable: bool => true; | |
| 26 | is_need_store: bool => false; | |
| 27 | is_block: bool => false; | |
| 28 | is_lightweight_pure: bool => false; | |
| 29 | is_type_expression: bool => false; | |
| 30 | ||
| 31 | // The function this value produces a callable reference to, | |
| 32 | // seen through any wrapper that binds it to a receiver or | |
| 33 | // caches it. Null for everything that is not such a | |
| 34 | // reference. Lets a caller reach the callee's own properties | |
| 35 | // without knowing which wrappers a given reference shape | |
| 36 | // acquired on the way. | |
| 37 | referenced_function: Semantic.Symbols.Function? => null; | |
| 38 | ||
| 39 | // Ambient location captured at construction time, if the | |
| 40 | // active COMPILE_EXPRESSIONS walk pushed one onto | |
| 41 | // IoC.CONTAINER.instance.location_stack. Subclasses that | |
| 42 | // carry an explicit location of their own (DUMMY, | |
| 43 | // TYPE_EXPRESSION) shadow these. | |
| 44 | _ambient_location: Source.LOCATION?; | |
| 45 | ||
| 46 | has_location: bool => _ambient_location?; | |
| 47 | location: Source.LOCATION => | |
| 48 | if _ambient_location? then | |
| 49 | _ambient_location; | |
| 50 | else | |
| 51 | Source.LOCATION.internal; | |
| 52 | fi; | |
| 53 | ||
| 54 | non_consumable_message: string => "cannot use this here"; | |
| 55 | ||
| 56 | type: Type? => null; | |
| 57 | symbol: Symbol => throw NotImplementedException("value has no symbol"); | |
| 58 | check_is_consumable(logger: Logging.Logger, location: Source.LOCATION, value: Value?) -> bool static => | |
| 59 | value? /\ | |
| 60 | value.check_is_consumable(logger, location); | |
| 61 | ||
| 62 | check_is_consumable(logger: Logging.Logger, location: Source.LOCATION) -> bool is | |
| 63 | if !is_consumable then | |
| 64 | logger.error(location, non_consumable_message); | |
| 65 | return false; | |
| 66 | fi | |
| 67 | ||
| 68 | let value_type = type; | |
| 69 | ||
| 70 | if !value_type? then | |
| 71 | logger.mark_consumed_error(); | |
| 72 | return false; | |
| 73 | elif value_type.is_error then | |
| 74 | logger.mark_consumed_error(); | |
| 75 | return true; | |
| 76 | elif value_type.is_sentinel \/ value_type.contains_inferred then | |
| 77 | // Nested placeholder counts too — a value of type | |
| 78 | // `Func<placeholder, int>` is consumable only after the | |
| 79 | // retry loop resolves the inner slot. Marking | |
| 80 | // consumed_any drives that retry. | |
| 81 | logger.mark_consumed_any(); | |
| 82 | return true; | |
| 83 | elif value_type.is_void then | |
| 84 | logger.error(location, "cannot use void value here"); | |
| 85 | return false; | |
| 86 | fi | |
| 87 | ||
| 88 | return true; | |
| 89 | si | |
| 90 | ||
| 91 | check_is_consumable_allow_void(logger: Logging.Logger, location: Source.LOCATION, value: Value?) -> bool static => | |
| 92 | value? /\ | |
| 93 | value.check_is_consumable_allow_void(logger, location); | |
| 94 | ||
| 95 | check_is_consumable_allow_void(logger: Logging.Logger, location: Source.LOCATION) -> bool is | |
| 96 | if !is_consumable then | |
| 97 | logger.error(location, non_consumable_message); | |
| 98 | return false; | |
| 99 | fi | |
| 100 | ||
| 101 | let value_type = type; | |
| 102 | ||
| 103 | if !value_type? then | |
| 104 | logger.mark_consumed_error(); | |
| 105 | return false; | |
| 106 | elif value_type.is_error then | |
| 107 | logger.mark_consumed_error(); | |
| 108 | elif value_type.is_sentinel \/ value_type.contains_inferred then | |
| 109 | logger.mark_consumed_any(); | |
| 110 | fi | |
| 111 | ||
| 112 | return true; | |
| 113 | si | |
| 114 | ||
| 115 | get_temp_copier(block: IR.Values.BLOCK, prefix: string) -> (() -> Value) => | |
| 116 | if is_lightweight_pure then | |
| 117 | () => self; | |
| 118 | elif type!.is_error then | |
| 119 | () => DUMMY(type!, location); | |
| 120 | else | |
| 121 | let temp = TEMP(block, prefix, self); | |
| 122 | () => temp.load(); | |
| 123 | fi; | |
| 124 | ||
| 125 | gen(context: IR.CONTEXT) => throw NotImplementedException("value gen: {get_type()} {self}"); | |
| 126 | gen_address(context: IR.CONTEXT) is | |
| 127 | throw NotImplementedException("value gen address: {get_type()} {self}"); | |
| 128 | si | |
| 129 | ||
| 130 | gen(value: Value?, context: IR.CONTEXT) static is | |
| 131 | if value? then | |
| 132 | value.gen(context); | |
| 133 | else | |
| 134 | context.fixme("null value"); | |
| 135 | fi | |
| 136 | si | |
| 137 | ||
| 138 | freeze() -> Value is | |
| 139 | let context = IR.CONTEXT(IoC.CONTAINER.instance.logger, null); | |
| 140 | ||
| 141 | context.enter_buffer(false); | |
| 142 | ||
| 143 | gen(context); | |
| 144 | ||
| 145 | let result = context.leave_buffer(); | |
| 146 | ||
| 147 | return RAW(type!, result); | |
| 148 | si | |
| 149 | ||
| 150 | init() is | |
| 151 | _ambient_location = IoC.CONTAINER.instance.location_stack.current; | |
| 152 | si | |
| 153 | ||
| 154 | to_string() -> string => "IR.Value {get_type()}"; | |
| 155 | si | |
| 156 | si |