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[Symbol,Type]
24
25
type_map: Collections.Map[Symbol,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[Symbol,Type]()
158
159
for i in 0..length do
160
if let parameter = cast GenericArgument?(symbol.type_parameter_at(i)) then
161
tm[parameter] = arguments[i]
162
fi
163
od
164
165
_type_map = tm
166
167
is_unsafe_constraints = symbol.is_unsafe_constraints
168
si
169
170
try_create_from(location: LOCATION, symbol: Classy, type_map: Collections.Map[Symbol,Type]) -> GENERIC? static is
171
let arguments = Collections.LIST[Type]()
172
173
for i in 0..symbol.argument_names.count do
174
let parameter = cast GenericArgument?(symbol.type_parameter_at(i))
175
176
if !parameter? then
177
return null
178
fi
179
180
let t: Type mut
181
182
if !type_map.try_get_value(parameter, t ref) then
183
return null
184
fi
185
186
arguments.add(t)
187
od
188
189
return GENERIC(location, symbol, arguments)
190
si
191
192
add_member(symbol: Symbol) -> bool is
193
IoC.CONTAINER.instance.logger.warn(location, "inherit-into-specialized-generic", "cannot inherit {symbol} into specialized generic {self}")
194
return true
195
si
196
197
add_implementor(implementor: Symbol) is
198
symbol.add_implementor(implementor)
199
si
200
201
assert_symbols_pulled_down() is
202
symbol.assert_symbols_pulled_down()
203
si
204
205
pull_down_super_symbols() is
206
symbol.pull_down_super_symbols()
207
si
208
209
get_ancestor(i: int) -> Type
210
=> ancestors[i].specialize(type_map)
211
212
// Declared: the loop over each argument's `matches` is
213
// genuinely store-free, but the store-free walk disqualifies
214
// any function containing a `for` loop unconditionally rather
215
// than reasoning about the loop body.
216
=~(other: Symbol) -> bool pure is
217
if !isa GENERIC(other) then
218
return false
219
fi
220
221
let other_generic = other
222
223
if other_generic.symbol != symbol then
224
return false
225
fi
226
227
assert
228
other_generic.arguments.count == arguments.count
229
else
230
"generics with the same symbol should have same number of arguments"
231
232
for i in 0..arguments.count do
233
if !arguments[i].matches(other_generic.arguments[i]) then
234
return false
235
fi
236
od
237
238
return true
239
si
240
241
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => symbol.load(location, from, loader)
242
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => symbol.store(location, from, value, loader, is_initialize)
243
call(location: Source.LOCATION, from: Value?, arguments: Collections.List[Value], type: Type?, caller: FUNCTION_CALLER) -> Value => symbol.call(location, from, arguments, type, caller)
244
// given a member of the class, trait or struct that this generic wraps, we want to get a copy of it
245
// with all references to formal type parameters replaced with the corresponding actual type arguments
246
_specialize(member: Symbols.Symbol?) -> Symbols.Symbol? =>
247
if !member? then
248
null
249
elif !member.is_specializable then
250
member
251
elif member.can_accept_actual_type_arguments then
252
member.specialize(arguments)
253
else
254
member.specialize(type_map, self)
255
fi
256
257
find_direct(name: string) -> Symbol? is
258
assert_symbols_pulled_down()
259
260
return _specialize(symbol.find_direct(name))
261
si
262
263
find_member(name: string) -> Symbol? =>
264
let result = symbol.find_member(name) in
265
if result? then
266
_specialize(result)
267
else
268
null
269
fi
270
271
find_specialized_function(function: Symbol) -> Function? is
272
let result = find_member(function.name)
273
274
if !result? then
275
let results = Collections.MAP[string, Symbols.Symbol]()
276
277
symbol.find_member_matches("", results)
278
279
return null
280
fi
281
282
let function_result = cast Function?(result)
283
284
if function_result? /\ function_result.specialized_from == function then
285
return function_result
286
fi
287
288
let function_group_result = cast FUNCTION_GROUP?(result)
289
290
if !function_group_result? then
291
return null
292
fi
293
294
for f in function_group_result.functions do
295
if f.specialized_from == function then
296
return f
297
fi
298
od
299
300
return null
301
si
302
303
get_destructure_member_name(index: int) -> string? =>
304
symbol.get_destructure_member_name(index)
305
306
find_enclosing(name: string) -> Symbol? =>
307
let unspecialized = symbol.find_enclosing(name) in
308
309
if unspecialized? /\ unspecialized.owner == symbol then
310
_specialize(unspecialized)
311
else
312
unspecialized
313
fi
314
315
find_direct_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is
316
let m = Collections.MAP[string, Symbols.Symbol]()
317
318
symbol.find_direct_matches(prefix, m)
319
320
for p in m.iterator do
321
if !matches.contains_key(p.key) then
322
if let specialized = _specialize(p.value) then
323
matches[p.key] = specialized.collapse_group_if_single_member()
324
fi
325
fi
326
od
327
si
328
329
find_member_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is
330
find_direct_matches(prefix, matches)
331
symbol.find_ancestor_matches(prefix, matches)
332
si
333
334
find_enclosing_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is
335
si
336
337
get_hash_code() -> int is
338
let result mut = symbol.get_hash_code()
339
340
for a in arguments do
341
result = result + a.get_hash_code()
342
od
343
344
return result
345
si
346
347
to_string() -> string => "{IoC.CONTAINER.instance.name_display.bare_name_for(symbol)}[{arguments_string}]"
348
si
349
si