Skip to content
← Back

src/semantic/symbols/property.ghul

1
namespace Semantic.Symbols is
2
use System.Exception
3
use System.Text.StringBuilder
4
5
use Logging
6
use Source
7
8
use IR.Values.Value
9
10
use Types.Type
11
12
class Property: Symbol, Types.SettableTyped abstract is
13
_overriders: Collections.MutableList[Symbol]?
14
_overridees: Collections.MutableList[Symbol]?
15
16
span: LOCATION
17
type: Type?
18
19
// Incremental body re-walk override: also shift the declaration
20
// span when the retained interface symbol is relocated.
21
set_span(span_location: LOCATION) is
22
span = span_location
23
si
24
25
set_type(value: Type) is type = value; si
26
27
short_description: string => "{name}: {if type? then type.short_description else "?" fi}"
28
symbol_kind: SymbolKind => SymbolKind.PROPERTY
29
completion_kind: CompletionKind => CompletionKind.PROPERTY
30
is_private: bool
31
is_assignable: bool public
32
is_workspace_visible: bool => !name.starts_with('_')
33
34
read_function: Function? public
35
read_function_il_name_override: string? public
36
37
assign_function: Function? public
38
assign_function_il_name_override: string? public
39
40
overriders: Collections.Iterable[Symbol]? => _overriders
41
overridees: Collections.Iterable[Symbol]? => _overridees
42
43
has_overriders: bool => _overriders? /\ _overriders.count > 0
44
45
// Set for a property whose accessors were synthesized over a
46
// backing field. The getter of one reads only that field, by
47
// construction, which is what lets it narrow without any
48
// whole-program analysis.
49
is_auto: bool public
50
51
// Declared `stable` on a property with no getter to carry the
52
// mark — a body-less trait requirement. A property with a
53
// read accessor reports the accessor's mark instead; the two
54
// are set together where both exist.
55
_is_declared_stable: bool
56
57
mark_declared_stable() is
58
let rsf = root_specialized_from
59
60
if rsf != self then
61
(cast Property?(rsf)!).mark_declared_stable()
62
return
63
fi
64
65
_is_declared_stable = true
66
si
67
68
// Whether the property is declared stable — trusted, not
69
// verified — so facts narrowed through it count as backed
70
// and every override must honour the contract.
71
is_declared_stable: bool is
72
let rsf = root_specialized_from
73
74
if rsf != self then
75
return (cast Property?(rsf)!).is_declared_stable
76
fi
77
78
if read_function? then
79
return read_function.is_declared_stable \/ _is_declared_stable
80
fi
81
82
return _is_declared_stable
83
si
84
85
// Whether a fact can narrow through this property: its getter
86
// must re-read to the same answer under an unchanged heap,
87
// provable from the symbol alone - the getter is declared
88
// pure or stable (checked contracts that bind overriders), is
89
// on the curated store-free import whitelist, or is a
90
// synthesized backing-field read; and every property
91
// overriding it must qualify the same way, since a call
92
// through this one can dispatch to any of them, with nothing
93
// outside the assembly able to add one.
94
narrowable_getter: bool is
95
let getter = read_function
96
97
if !getter? then
98
return false
99
fi
100
101
// a pure or stable declaration is a contract every
102
// override must honour, checked wherever the override
103
// appears, so there is nothing further to ask of the
104
// dispatch
105
if getter.is_declared_pure \/ getter.is_declared_stable \/ STORE_FREE_IMPORTS.is_store_free(getter) then
106
return true
107
fi
108
109
if !is_auto \/ _openly_dispatchable(getter) then
110
return false
111
fi
112
113
let overriders = self.overriders
114
115
if !overriders? then
116
return true
117
fi
118
119
for overrider in overriders do
120
if !isa Property(overrider) then
121
return false
122
fi
123
124
if !(cast Property(overrider)).narrowable_getter then
125
return false
126
fi
127
od
128
129
return true
130
si
131
132
// Whether an override outside this compilation could stand
133
// behind a call to `getter`: an instance method of anything
134
// but a closed class. Mirrors the dispatch-shadow rule the
135
// store-free solvers apply, restated here from symbol shape
136
// alone.
137
_openly_dispatchable(getter: Function) -> bool static is
138
if isa STRUCT_METHOD(getter) then
139
return false
140
fi
141
142
if !isa INSTANCE_METHOD(getter) then
143
return false
144
fi
145
146
let owner = getter.owner
147
148
if !owner? \/ !isa Classy(owner) then
149
return true
150
fi
151
152
let owner_classy = cast Classy(owner)
153
154
return owner_classy.is_open
155
si
156
157
// Prefixes the description's trailing kind comment when the
158
// getter is proven store-free — diagnostic surfacing only,
159
// deliberately inside the comment so it does not read as
160
// source syntax.
161
pure_prefix: string =>
162
if read_function? /\ read_function.is_proven_store_free then
163
"pure "
164
else
165
""
166
fi
167
168
// Shared body for the three concrete Property kinds. Delegates
169
// to Symbol._describe_typed so a narrowed property (path
170
// narrowing over a `T?` getter) surfaces the same
171
// `declared → narrowed` display a variable use gets.
172
_describe_property(context: DESCRIBE_CONTEXT) -> SignaturePart =>
173
_describe_typed(context, PARTS.name(self), type)
174
175
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool, is_private: bool) is
176
super.init(location, owner, name)
177
178
self.span = span
179
self.is_assignable = is_assignable
180
self.is_private = is_private
181
si
182
183
add_overrider(overrider: Symbol mut) is
184
let rsf = root_specialized_from
185
if rsf != self then
186
rsf.add_overrider(overrider)
187
return
188
fi
189
190
let overriders mut = _overriders
191
192
if !overriders? then
193
overriders = Collections.LIST[Symbol]()
194
_overriders = overriders
195
fi
196
197
overrider = overrider.root_specialized_from
198
199
if overriders.contains(overrider) then
200
return
201
fi
202
203
overriders.add(overrider)
204
205
if let journal = INHERITANCE_JOURNAL.current then
206
journal.record(InheritanceOp.PROPERTY_OVERRIDER_ADDED(self, overrider))
207
fi
208
si
209
210
remove_overrider(overrider: Symbol) is
211
let rsf = root_specialized_from
212
if rsf != self then
213
rsf.remove_overrider(overrider)
214
return
215
fi
216
217
let overriders = _overriders
218
219
if overriders? then
220
overriders.remove(overrider.root_specialized_from)
221
fi
222
si
223
224
add_overridee(overridee: Symbol mut) is
225
let rsf = root_specialized_from
226
if rsf != self then
227
rsf.add_overridee(overridee)
228
return
229
fi
230
231
let overridees mut = _overridees
232
233
if !overridees? then
234
overridees = Collections.LIST[Symbol]()
235
_overridees = overridees
236
fi
237
238
overridee = overridee.root_specialized_from
239
240
if overridees.contains(overridee) then
241
return
242
fi
243
244
overridees.add(overridee)
245
246
if let journal = INHERITANCE_JOURNAL.current then
247
journal.record(InheritanceOp.PROPERTY_OVERRIDEE_ADDED(self, overridee))
248
fi
249
si
250
251
remove_overridee(overridee: Symbol) is
252
let rsf = root_specialized_from
253
if rsf != self then
254
rsf.remove_overridee(overridee)
255
return
256
fi
257
258
let overridees = _overridees
259
260
if overridees? then
261
overridees.remove(overridee.root_specialized_from)
262
fi
263
si
264
265
specialize(type_map: Collections.Map[Symbol,Type], owner: GENERIC) -> Symbol is
266
let result = cast Property?(self.memberwise_clone())!
267
268
result.specialized_from = self
269
270
if type? then
271
result.type = type.specialize(type_map)
272
fi
273
274
if read_function? then
275
result.read_function = read_function.specialize_function(type_map, owner)
276
fi
277
278
if assign_function? then
279
result.assign_function = assign_function.specialize_function(type_map, owner)
280
fi
281
282
// Attribute the specialized property to the constructed generic so
283
// its owner renders with the actual type arguments
284
// (`Iterator[char].current`, not `Iterator[T].current`), matching
285
// how fields and methods specialize.
286
result.owner = owner
287
288
return result
289
si
290
291
to_string() -> string is
292
let result = System.Text.StringBuilder()
293
294
try
295
result.append(IoC.CONTAINER.instance.name_display.name_for(self))
296
result.append(": ")
297
result.append(type)
298
299
return result.to_string()
300
catch ex: Exception
301
return "[garbled property: {result}]"
302
yrt
303
si
304
si
305
306
class INSTANCE_PROPERTY: Property is
307
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
308
_describe_property(context)
309
310
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
311
"{pure_prefix}instance property"
312
313
is_instance: bool => true
314
315
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool, is_private: bool) is
316
super.init(location, span, owner, name, is_assignable, is_private)
317
si
318
319
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_instance_property(location, from, self)
320
321
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => loader.store_instance_property(location, from, self, value)
322
323
si
324
325
class STATIC_PROPERTY: Property is
326
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
327
_describe_property(context)
328
329
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
330
"{pure_prefix}class property"
331
332
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool, is_private: bool) is
333
super.init(location, span, owner, name, is_assignable, is_private)
334
si
335
336
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_static_property(location, self)
337
338
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => loader.store_static_property(location, self, value)
339
340
si
341
342
class GLOBAL_PROPERTY: Property is
343
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
344
_describe_property(context)
345
346
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
347
"{pure_prefix}global property"
348
349
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool) is
350
super.init(location, span, owner, name, is_assignable, false)
351
si
352
353
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_global_property(location, self)
354
355
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => loader.store_global_property(location, self, value)
356
357
si
358
si