Skip to content
← Back

src/syntax/process/resolve_ancestors.ghul

1
namespace Syntax.Process is
2
use IO.Std
3
4
use Logging
5
6
class RESOLVE_ANCESTORS: ScopedVisitor is
7
_logger: Logger
8
_symbol_table: Semantic.SYMBOL_TABLE
9
_innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup
10
11
init(
12
logger: Logger,
13
symbol_table: Semantic.SYMBOL_TABLE,
14
namespaces: Semantic.NAMESPACES,
15
innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup
16
)
17
is
18
super.init(logger, symbol_table, namespaces)
19
20
_logger = logger
21
_symbol_table = symbol_table
22
_innate_symbol_lookup = innate_symbol_lookup
23
si
24
25
apply(root: Trees.Node) is
26
root.walk(self)
27
si
28
29
pre(`class: Trees.Definitions.CLASS) -> bool => true
30
31
visit(`class: Trees.Definitions.CLASS) is
32
let class_symbol = cast Semantic.Symbols.CLASS?(scope_for(`class))!
33
34
let seen_class_ancestor mut = false
35
let is_first mut = true
36
37
if `class.ancestors? then
38
for a in `class.ancestors do
39
let ancestor_type = a.type
40
41
if !a.is_poisoned /\ ancestor_type? then
42
if ancestor_type.is_inheritable then
43
if ancestor_type.is_class then
44
if seen_class_ancestor then
45
_logger.error(a.location, "multiple superclasses")
46
elif !is_first then
47
_logger.error(a.location, "superclass must be first")
48
fi
49
50
_check_extension_of_closed_imported(a, ancestor_type, "extend")
51
52
seen_class_ancestor = true
53
else
54
_check_extension_of_closed_imported(a, ancestor_type, "implement")
55
fi
56
57
a.check_is_not_void(_logger, "cannot use void type here")
58
59
class_symbol.add_ancestor(ancestor_type)
60
61
is_first = false
62
else
63
_logger.error(a.location, "cannot inherit from this")
64
fi
65
fi
66
od
67
fi
68
69
if !seen_class_ancestor then
70
let object_type = _innate_symbol_lookup.get_object_type()
71
72
if class_symbol != object_type.symbol then
73
class_symbol.push_ancestor(_innate_symbol_lookup.get_object_type())
74
fi
75
fi
76
si
77
78
// A class or trait carrying the CLOSED_ATTRIBUTE marker is closed
79
// to the assembly it was declared in. Extending an imported one
80
// from here would break the closure its own assembly relies on -
81
// for a class, the enumerability of its subclass set that
82
// narrowing rests on; for a trait, the author's decision not to
83
// hand out an extension point.
84
_check_extension_of_closed_imported(
85
ancestor_node: Trees.TypeExpressions.TypeExpression,
86
ancestor_type: Semantic.Types.Type?,
87
verb: string
88
) is
89
if !ancestor_type? then
90
return
91
fi
92
93
let ancestor_symbol = ancestor_type.symbol
94
95
if !isa Semantic.Symbols.Classy(ancestor_symbol) then
96
return
97
fi
98
99
let ancestor_classy = cast Semantic.Symbols.Classy(ancestor_symbol)
100
101
if !ancestor_classy.is_reflected then
102
return
103
fi
104
105
if ancestor_classy.is_open then
106
return
107
fi
108
109
// An earlier cell of this session is the same program as
110
// far as the user is concerned: they wrote it a moment ago
111
// and are extending it now. Closure is what makes a
112
// session's exhaustive case and else-edge narrowing work at
113
// all, so the two are reconciled by letting a later cell
114
// through rather than by leaving every hierarchy open. What
115
// that costs an earlier cell's compiled code is paid for by
116
// the guards a submission build emits.
117
if IoC.CONTAINER.instance.assemblies.is_session_cell_named(ancestor_classy.il_assembly_name) then
118
return
119
fi
120
121
let kind = if ancestor_classy.is_trait then "trait" else "class" fi
122
123
_logger.error(
124
ancestor_node.location,
125
"cannot {verb} closed {kind} {ancestor_classy.name} from outside its assembly"
126
)
127
si
128
129
// An `impl <Interface> for <Target>` block attaches the interface to
130
// the target's own symbol - this node's scope is an injection scope
131
// standing in for the target, which class_or_trait_for unwraps. The
132
// target then implements the interface exactly as a header-declared
133
// one would; the members filling its slots are declared as the
134
// target's own.
135
pre(`impl: Trees.Definitions.IMPL) -> bool => true
136
137
visit(`impl: Trees.Definitions.IMPL) is
138
let target_symbol = class_or_trait_for(`impl)
139
140
if !target_symbol? then
141
return
142
fi
143
144
if `impl.ancestors? then
145
for a in `impl.ancestors do
146
let ancestor_type = a.type
147
148
if ancestor_type? then
149
if isa Semantic.Types.NAMED(ancestor_type) then
150
let ancestor_named_type = ancestor_type
151
152
if ancestor_named_type.symbol.is_trait then
153
_check_extension_of_closed_imported(a, ancestor_named_type, "implement")
154
155
target_symbol.add_ancestor(ancestor_named_type)
156
157
a.check_is_not_void(_logger, "cannot use void type here")
158
159
continue
160
fi
161
fi
162
163
_logger.error(a.location, "impl can only implement a trait")
164
fi
165
od
166
fi
167
si
168
169
pre(`trait: Trees.Definitions.TRAIT) -> bool => true
170
171
visit(`trait: Trees.Definitions.TRAIT) is
172
let trait_symbol = cast Semantic.Symbols.TRAIT?(scope_for(`trait))!
173
174
let seen_valid_ancestor mut = false
175
176
if `trait.ancestors? then
177
for a in `trait.ancestors do
178
let ancestor_type = a.type
179
180
if ancestor_type? then
181
if isa Semantic.Types.NAMED(ancestor_type) then
182
let ancestor_named_type = ancestor_type
183
184
if ancestor_named_type.symbol.is_trait then
185
_check_extension_of_closed_imported(a, ancestor_named_type, "extend")
186
187
trait_symbol.add_ancestor(ancestor_named_type)
188
seen_valid_ancestor = true
189
190
a.check_is_not_void(_logger, "cannot use void type here")
191
else
192
_logger.error(a.location, "trait cannot inherit from class")
193
fi
194
else
195
_logger.error(a.location, "cannot inherit from this")
196
fi
197
else
198
Std.error.write_line("refusing to add ancestor with null type {a} to trait {trait_symbol}")
199
fi
200
od
201
fi
202
203
let object_type = _innate_symbol_lookup.get_object_type()
204
205
trait_symbol.push_ancestor(object_type)
206
si
207
208
pre(`struct: Trees.Definitions.STRUCT) -> bool => true
209
210
visit(`struct: Trees.Definitions.STRUCT) is
211
let struct_symbol = cast Semantic.Symbols.STRUCT?(scope_for(`struct))!
212
213
if `struct.ancestors? then
214
for a in `struct.ancestors do
215
let ancestor_type = a.type
216
217
if ancestor_type? then
218
if isa Semantic.Types.NAMED(ancestor_type) then
219
let ancestor_named_type = ancestor_type
220
221
if ancestor_named_type.symbol.is_trait then
222
_check_extension_of_closed_imported(a, ancestor_named_type, "implement")
223
224
struct_symbol.add_ancestor(ancestor_named_type)
225
226
a.check_is_not_void(_logger, "cannot use void type here")
227
228
continue
229
fi
230
fi
231
232
_logger.error(a.location, "structs can only inherit from traits")
233
fi
234
od
235
fi
236
237
struct_symbol.push_ancestor(_innate_symbol_lookup.get_value_type())
238
si
239
240
pre(`union: Trees.Definitions.UNION) -> bool => super.pre(`union)
241
242
visit(`union: Trees.Definitions.UNION) is
243
let union_symbol = cast Semantic.Symbols.UNION?(scope_for(`union))!
244
245
if `union.ancestors? then
246
for a in `union.ancestors do
247
let ancestor_type = a.type
248
249
if ancestor_type? then
250
if isa Semantic.Types.NAMED(ancestor_type) then
251
let ancestor_named_type = ancestor_type
252
253
if ancestor_named_type.symbol.is_trait then
254
_check_extension_of_closed_imported(a, ancestor_named_type, "implement")
255
256
union_symbol.add_ancestor(ancestor_named_type)
257
258
a.check_is_not_void(_logger, "cannot use void type here")
259
260
continue
261
fi
262
fi
263
264
_logger.error(a.location, "unions can only inherit from traits")
265
fi
266
od
267
fi
268
269
union_symbol.push_ancestor(_innate_symbol_lookup.get_object_type())
270
271
super.visit(`union)
272
si
273
274
pre(`variant: Trees.Definitions.VARIANT) -> bool => true
275
276
visit(`variant: Trees.Definitions.VARIANT) is
277
let variant_symbol = cast Semantic.Symbols.VARIANT?(scope_for(`variant))!
278
// a variant is always resolved inside its union's scope
279
let union_symbol = current_union_context!
280
let arguments = Collections.LIST[Semantic.Types.Type]()
281
282
let union_type =
283
if let union_symbol.argument_names? /\ argument_names.count > 0 then
284
for argument_name in argument_names do
285
let argument_symbol = variant_symbol.find_direct(argument_name)
286
let argument_symbol_type = if argument_symbol? then argument_symbol.type else null fi
287
288
if argument_symbol_type? then
289
arguments.add(argument_symbol_type)
290
else
291
arguments.add(Semantic.Types.ERROR())
292
fi
293
od
294
295
Semantic.Types.GENERIC(
296
Source.LOCATION.internal,
297
union_symbol,
298
arguments)
299
else
300
Semantic.Types.NAMED(
301
union_symbol)
302
fi
303
304
variant_symbol.push_ancestor(union_type)
305
si
306
307
pre(`enum: Trees.Definitions.ENUM) -> bool => true
308
309
visit(`enum: Trees.Definitions.ENUM) is
310
let enum_symbol = cast Semantic.Symbols.ENUM_STRUCT?(scope_for(`enum))!
311
312
enum_symbol.push_ancestor(_innate_symbol_lookup.get_enum_type())
313
si
314
si
315
si