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 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