Skip to content
← Back

src/semantic/symbols/generic.ghul

1
namespace Semantic.Symbols is
2
use IO.Std;
3
4
use System.Text.StringBuilder;
5
6
use Collections.List;
7
use Collections.Map;
8
9
use IoC;
10
use Logging;
11
use Source;
12
13
use IR.Values.Value;
14
use Types.Type;
15
16
use Ghul.Pipes;
17
18
// A GENERIC represents a particular specialization of a generic class, trait or struct - i.e. a version of that symbol
19
// with actual type arguments specified for its formal type parameters, and all its member symbols' signatures rewritten
20
// with all instances of each formal type parameter replaced with the corresponding actual type argument
21
class GENERIC: Symbol, Types.Typed is
22
_symbol: Classy;
23
_type_map: Collections.Map[string,Type];
24
25
type_map: Collections.Map[string,Type] => _type_map;
26
arguments: Collections.List[Type];
27
ancestors: Collections.List[Type] => symbol.ancestors;
28
29
implementors: Collections.Iterable[Symbol]? => symbol.implementors;
30
31
symbol: Classy => _symbol;
32
33
symbols: Collections.Iterable[Symbol] is
34
let result = Collections.LIST[Symbol]();
35
36
for s in symbol.symbols do
37
if let specialized = _specialize(s) then
38
result.add(specialized);
39
fi
40
od
41
42
return result;
43
si
44
45
owner: Scope? public => symbol.owner, = value is si
46
47
unspecialized_symbol: Symbols.Symbol => symbol;
48
root_unspecialized_symbol: Symbols.Symbol => symbol.root_unspecialized_symbol;
49
50
location: LOCATION => symbol.location;
51
name: string => symbol.name;
52
53
access: ACCESS => symbol.access;
54
55
is_type: bool => symbol.is_type;
56
is_generic_type_specialization: bool => true;
57
is_value_type: bool => symbol.is_value_type;
58
is_inheritable: bool => symbol.is_inheritable;
59
is_class: bool => symbol.is_class;
60
is_trait: bool => symbol.is_trait;
61
is_union: bool => symbol.is_union;
62
is_variant: bool => symbol.is_variant;
63
is_unit_variant: bool => symbol.is_unit_variant;
64
is_closed_root: bool => symbol.is_closed_root;
65
is_specializable: bool => false; // type parameters already applied
66
67
qualified_name: string => "{symbol.qualified_name}[{arguments_string}]";
68
69
// Only the head shortens; the type arguments stay. (Type rendering
70
// reaches the head directly and adds the arguments itself, so this
71
// is only used when a constructed generic is named on its own - as
72
// the owner of a member, say.)
73
render_name(scope: Scope?) -> string =>
74
if !scope? then
75
qualified_name;
76
else
77
"{symbol._render_scope_relative_name(scope)}[{arguments_string}]";
78
fi;
79
80
arguments_string: string is
81
let result = System.Text.StringBuilder();
82
83
let seen_any mut = false;
84
85
for a in arguments do
86
if seen_any then
87
result.append(',');
88
fi
89
90
result.append(a);
91
92
seen_any = true;
93
od
94
95
return result.to_string();
96
si
97
98
short_description: string is
99
let result = System.Text.StringBuilder();
100
101
result
102
.append(name)
103
.append('[');
104
105
let seen_any mut = false;
106
107
for a in arguments do
108
if seen_any then
109
result.append(',');
110
fi
111
112
result.append(a.short_description);
113
114
seen_any = true;
115
od
116
117
result
118
.append(']');
119
120
return result.to_string();
121
si
122
123
symbol_kind: SymbolKind => symbol.symbol_kind;
124
completion_kind: CompletionKind => symbol.completion_kind;
125
126
// TODO we could probably cache this rather than creating
127
// a new one every time
128
type: Type => Types.GENERIC(location, symbol, arguments);
129
130
depth: int => symbol.depth;
131
132
init(location: LOCATION, symbol: Classy, arguments: Collections.List[Type]) is
133
assert arguments |> all(a => a?) else "type argument is null for {symbol.name}";
134
135
super.init(
136
symbol.location,
137
symbol,
138
symbol.name);
139
140
_symbol = symbol;
141
142
assert arguments.count > 0 else "generic has 0 arguments";
143
assert arguments |> all(a => a?) else "at least one null argument";
144
assert symbol.is_generic else "symbol is not generic";
145
146
let length mut = arguments.count;
147
148
if arguments.count != symbol.argument_names.count then
149
if length > symbol.argument_names.count then
150
length = symbol.argument_names.count;
151
fi
152
153
IoC.CONTAINER.instance.logger.error(location, "expected {symbol.argument_names.count} type arguments");
154
fi
155
156
self.arguments = arguments;
157
let tm = Collections.MAP[string,Type]();
158
159
for i in 0..length do
160
tm[symbol.argument_names[i]] = arguments[i];
161
od
162
163
_type_map = tm;
164
165
is_unsafe_constraints = symbol.is_unsafe_constraints;
166
si
167
168
try_create_from(location: LOCATION, symbol: Classy, type_map: Collections.Map[string,Type]) -> GENERIC? static is
169
let arguments = Collections.LIST[Type]();
170
171
for name in symbol.argument_names do
172
if !type_map.contains_key(name) then
173
return null;
174
fi
175
176
let t = type_map[name];
177
178
arguments.add(t);
179
od
180
181
return GENERIC(location, symbol, arguments);
182
si
183
184
add_member(symbol: Symbol) -> bool is
185
IoC.CONTAINER.instance.logger.warn(location, "inherit-into-specialized-generic", "cannot inherit {symbol} into specialized generic {self}");
186
return true;
187
si
188
189
add_implementor(implementor: Symbol) is
190
symbol.add_implementor(implementor);
191
si
192
193
assert_symbols_pulled_down() is
194
symbol.assert_symbols_pulled_down();
195
si
196
197
pull_down_super_symbols() is
198
symbol.pull_down_super_symbols();
199
si
200
201
get_ancestor(i: int) -> Type
202
=> ancestors[i].specialize(type_map);
203
204
=~(other: Symbol) -> bool is
205
if !isa GENERIC(other) then
206
return false;
207
fi
208
209
let other_generic = other;
210
211
if other_generic.symbol != symbol then
212
return false;
213
fi
214
215
assert
216
other_generic.arguments.count == arguments.count
217
else
218
"generics with the same symbol should have same number of arguments";
219
220
for i in 0..arguments.count do
221
if !arguments[i].matches(other_generic.arguments[i]) then
222
return false;
223
fi
224
od
225
226
return true;
227
si
228
229
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => symbol.load(location, from, loader);
230
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => symbol.store(location, from, value, loader, is_initialize);
231
call(location: Source.LOCATION, from: Value?, arguments: Collections.List[Value], type: Type?, caller: FUNCTION_CALLER) -> Value => symbol.call(location, from, arguments, type, caller);
232
// given a member of the class, trait or struct that this generic wraps, we want to get a copy of it
233
// with all references to formal type parameters replaced with the corresponding actual type arguments
234
_specialize(member: Symbols.Symbol?) -> Symbols.Symbol? =>
235
if !member? then
236
null;
237
elif !member.is_specializable then
238
member;
239
elif member.can_accept_actual_type_arguments then
240
member.specialize(arguments);
241
else
242
member.specialize(type_map, self);
243
fi;
244
245
find_direct(name: string) -> Symbol? is
246
assert_symbols_pulled_down();
247
248
return _specialize(symbol.find_direct(name));
249
si
250
251
find_member(name: string) -> Symbol? =>
252
let result = symbol.find_member(name) in
253
if result? then
254
_specialize(result);
255
else
256
null;
257
fi;
258
259
find_specialized_function(function: Symbol) -> Function? is
260
let result = find_member(function.name);
261
262
if !result? then
263
let results = Collections.MAP[string, Symbols.Symbol]();
264
265
symbol.find_member_matches("", results);
266
267
return null;
268
fi
269
270
let function_result = cast Function?(result);
271
272
if function_result? /\ function_result.specialized_from == function then
273
return function_result;
274
fi
275
276
let function_group_result = cast FUNCTION_GROUP?(result);
277
278
if !function_group_result? then
279
return null;
280
fi
281
282
for f in function_group_result.functions do
283
if f.specialized_from == function then
284
return f;
285
fi
286
od
287
288
return null;
289
si
290
291
get_destructure_member_name(index: int) -> string? =>
292
symbol.get_destructure_member_name(index);
293
294
find_enclosing(name: string) -> Symbol? =>
295
let unspecialized = symbol.find_enclosing(name) in
296
297
if unspecialized? /\ unspecialized.owner == symbol then
298
_specialize(unspecialized);
299
else
300
unspecialized;
301
fi;
302
303
find_direct_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is
304
let m = Collections.MAP[string, Symbols.Symbol]();
305
306
symbol.find_direct_matches(prefix, m);
307
308
for p in m.iterator do
309
if !matches.contains_key(p.key) then
310
if let specialized = _specialize(p.value) then
311
matches[p.key] = specialized.collapse_group_if_single_member();
312
fi
313
fi
314
od
315
si
316
317
find_member_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is
318
find_direct_matches(prefix, matches);
319
symbol.find_ancestor_matches(prefix, matches);
320
si
321
322
find_enclosing_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is
323
si
324
325
get_hash_code() -> int is
326
let result mut = symbol.get_hash_code();
327
328
for a in arguments do
329
result = result + a.get_hash_code();
330
od
331
332
return result;
333
si
334
335
gen_reference(buffer: StringBuilder) is
336
gen_type(buffer);
337
si
338
339
gen_class_name(buffer: StringBuilder) is
340
// class name == type for generics - i.e. they must always be prefixed with 'class' or 'valuetype'
341
gen_type(buffer);
342
si
343
344
gen_type(buffer: StringBuilder) is
345
symbol.gen_type(buffer);
346
347
buffer.append('<');
348
349
gen_actual_type_arguments(buffer);
350
351
buffer.append("> ");
352
si
353
354
gen_actual_type_arguments(buffer: StringBuilder) is
355
let seen_any mut = false;
356
for argument in arguments do
357
if seen_any then
358
buffer.append(',');
359
fi
360
361
argument.gen_type(buffer);
362
363
seen_any = true;
364
od
365
si
366
367
to_string() -> string => "{IoC.CONTAINER.instance.name_display.bare_name_for(symbol)}[{arguments_string}]";
368
si
369
si