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_extends_closed_imported(a, ancestor_type);
51
52
seen_class_ancestor = true;
53
fi
54
55
a.check_is_not_void(_logger, "cannot use void type here");
56
57
class_symbol.add_ancestor(ancestor_type);
58
59
is_first = false;
60
else
61
_logger.error(a.location, "cannot inherit from this");
62
fi
63
fi
64
od
65
fi
66
67
if !seen_class_ancestor then
68
let object_type = _innate_symbol_lookup.get_object_type();
69
70
if class_symbol != object_type.symbol then
71
class_symbol.push_ancestor(_innate_symbol_lookup.get_object_type());
72
fi
73
fi
74
si
75
76
// A class declared in this compilation can only extend a
77
// ghūl-declared closed class that lives in the same assembly.
78
// An imported (reflected) class carrying the CLOSED_ATTRIBUTE
79
// marker is closed from another assembly — extending it from
80
// this one would violate the closure that the consumer can
81
// rely on for narrowing soundness.
82
_check_extends_closed_imported(
83
ancestor_node: Trees.TypeExpressions.TypeExpression,
84
ancestor_type: Semantic.Types.Type?
85
) is
86
if !ancestor_type? then
87
return;
88
fi
89
90
let ancestor_symbol = ancestor_type.symbol;
91
92
if !isa Semantic.Symbols.Classy(ancestor_symbol) then
93
return;
94
fi
95
96
let ancestor_classy = cast Semantic.Symbols.Classy(ancestor_symbol);
97
98
if !ancestor_classy.is_reflected then
99
return;
100
fi
101
102
if ancestor_classy.is_open then
103
return;
104
fi
105
106
_logger.error(
107
ancestor_node.location,
108
"cannot extend closed class {ancestor_classy.name} from outside its assembly"
109
);
110
si
111
112
// An `impl <Interface> for <Target>` block attaches the interface to
113
// the target's own symbol - this node's scope is an injection scope
114
// standing in for the target, which class_or_trait_for unwraps. The
115
// target then implements the interface exactly as a header-declared
116
// one would; the members filling its slots are declared as the
117
// target's own.
118
pre(`impl: Trees.Definitions.IMPL) -> bool => true;
119
120
visit(`impl: Trees.Definitions.IMPL) is
121
let target_symbol = class_or_trait_for(`impl);
122
123
if !target_symbol? then
124
return;
125
fi
126
127
if `impl.ancestors? then
128
for a in `impl.ancestors do
129
let ancestor_type = a.type;
130
131
if ancestor_type? then
132
if isa Semantic.Types.NAMED(ancestor_type) then
133
let ancestor_named_type = ancestor_type;
134
135
if ancestor_named_type.symbol.is_trait then
136
target_symbol.add_ancestor(ancestor_named_type);
137
138
a.check_is_not_void(_logger, "cannot use void type here");
139
140
continue;
141
fi
142
fi
143
144
_logger.error(a.location, "impl can only implement a trait");
145
fi
146
od
147
fi
148
si
149
150
pre(`trait: Trees.Definitions.TRAIT) -> bool => true;
151
152
visit(`trait: Trees.Definitions.TRAIT) is
153
let trait_symbol = cast Semantic.Symbols.TRAIT?(scope_for(`trait))!;
154
155
let seen_valid_ancestor mut = false;
156
157
if `trait.ancestors? then
158
for a in `trait.ancestors do
159
let ancestor_type = a.type;
160
161
if ancestor_type? then
162
if isa Semantic.Types.NAMED(ancestor_type) then
163
let ancestor_named_type = ancestor_type;
164
165
if ancestor_named_type.symbol.is_trait then
166
trait_symbol.add_ancestor(ancestor_named_type);
167
seen_valid_ancestor = true;
168
169
a.check_is_not_void(_logger, "cannot use void type here");
170
else
171
_logger.error(a.location, "trait cannot inherit from class");
172
fi
173
else
174
_logger.error(a.location, "cannot inherit from this");
175
fi
176
else
177
Std.error.write_line("refusing to add ancestor with null type {a} to trait {trait_symbol}");
178
fi
179
od
180
fi
181
182
let object_type = _innate_symbol_lookup.get_object_type();
183
184
trait_symbol.push_ancestor(object_type);
185
si
186
187
pre(`struct: Trees.Definitions.STRUCT) -> bool => true;
188
189
visit(`struct: Trees.Definitions.STRUCT) is
190
let struct_symbol = cast Semantic.Symbols.STRUCT?(scope_for(`struct))!;
191
192
if `struct.ancestors? then
193
for a in `struct.ancestors do
194
let ancestor_type = a.type;
195
196
if ancestor_type? then
197
if isa Semantic.Types.NAMED(ancestor_type) then
198
let ancestor_named_type = ancestor_type;
199
200
if ancestor_named_type.symbol.is_trait then
201
struct_symbol.add_ancestor(ancestor_named_type);
202
203
a.check_is_not_void(_logger, "cannot use void type here");
204
205
continue;
206
fi
207
fi
208
209
_logger.error(a.location, "structs can only inherit from traits");
210
fi
211
od
212
fi
213
214
struct_symbol.push_ancestor(_innate_symbol_lookup.get_value_type());
215
si
216
217
pre(`union: Trees.Definitions.UNION) -> bool => super.pre(`union);
218
219
visit(`union: Trees.Definitions.UNION) is
220
let union_symbol = cast Semantic.Symbols.UNION?(scope_for(`union))!;
221
222
if `union.ancestors? then
223
for a in `union.ancestors do
224
let ancestor_type = a.type;
225
226
if ancestor_type? then
227
if isa Semantic.Types.NAMED(ancestor_type) then
228
let ancestor_named_type = ancestor_type;
229
230
if ancestor_named_type.symbol.is_trait then
231
union_symbol.add_ancestor(ancestor_named_type);
232
233
a.check_is_not_void(_logger, "cannot use void type here");
234
235
continue;
236
fi
237
fi
238
239
_logger.error(a.location, "unions can only inherit from traits");
240
fi
241
od
242
fi
243
244
union_symbol.push_ancestor(_innate_symbol_lookup.get_object_type());
245
246
super.visit(`union);
247
si
248
249
pre(`variant: Trees.Definitions.VARIANT) -> bool => true;
250
251
visit(`variant: Trees.Definitions.VARIANT) is
252
let variant_symbol = cast Semantic.Symbols.VARIANT?(scope_for(`variant))!;
253
// a variant is always resolved inside its union's scope
254
let union_symbol = current_union_context!;
255
let arguments = Collections.LIST[Semantic.Types.Type]();
256
257
let union_type =
258
if let union_symbol.argument_names? /\ argument_names.count > 0 then
259
for argument_name in argument_names do
260
let argument_symbol = variant_symbol.find_direct(argument_name);
261
let argument_symbol_type = if argument_symbol? then argument_symbol.type else null fi;
262
263
if argument_symbol_type? then
264
arguments.add(argument_symbol_type)
265
else
266
arguments.add(Semantic.Types.ERROR());
267
fi
268
od
269
270
Semantic.Types.GENERIC(
271
Source.LOCATION.internal,
272
union_symbol,
273
arguments);
274
else
275
Semantic.Types.NAMED(
276
union_symbol);
277
fi;
278
279
variant_symbol.push_ancestor(union_type);
280
si
281
282
pre(`enum: Trees.Definitions.ENUM) -> bool => true;
283
284
visit(`enum: Trees.Definitions.ENUM) is
285
let enum_symbol = cast Semantic.Symbols.ENUM_STRUCT?(scope_for(`enum))!;
286
287
enum_symbol.push_ancestor(_innate_symbol_lookup.get_enum_type());
288
si
289
si
290
si