Skip to content
← Back

src/ir/values/value.ghul

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