Skip to content
← Back

src/syntax/process/resolve_uses.ghul

1
namespace Syntax.Process is
2
use Logging
3
use Source
4
use Trees
5
6
use Ghul.Pipes
7
8
// Resolves use clauses into their namespace block's scope. Runs
9
// twice: a first round after declare-symbols binds every import that
10
// refers to a type - classes, structs, unions, variants, enums - and
11
// namespaces, which is everything resolve-type-expressions needs. A
12
// name that fails to bind is left for the second round (`_final`
13
// unset marks the first-round instance), which runs after
14
// declare-members, so an import can also name a static method, a
15
// global function or an enum member - including one an impl or
16
// partial block injects; anything still unresolved then is an error.
17
class RESOLVE_USES: ScopeVisitorBase is
18
_logger: Logger
19
_symbol_table: Semantic.SYMBOL_TABLE
20
_symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS
21
_final: bool
22
23
init(
24
logger: Logger,
25
symbol_table: Semantic.SYMBOL_TABLE,
26
namespaces: Semantic.NAMESPACES,
27
symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS,
28
final: bool
29
) is
30
super.init(symbol_table, namespaces)
31
_logger = logger
32
_symbol_table = symbol_table
33
_symbol_use_locations = symbol_use_locations
34
_final = final
35
si
36
37
apply(node: Node) is
38
node.walk(self)
39
si
40
41
pre(`namespace: Definitions.NAMESPACE) -> bool is
42
let namespace_scope = enter_namespace(`namespace)
43
44
// FIXME: these searches probably should start at the scope immediately enclosing the namespace
45
for u in `namespace.body.uses do
46
if u.is_alias then
47
if !_final then
48
_declare_alias(u, namespace_scope)
49
u.is_import_resolved = true
50
fi
51
52
continue
53
fi
54
55
if u.is_default then
56
_resolve_default_uses(u, namespace_scope)
57
58
continue
59
fi
60
61
if u.is_all then
62
if !_final then
63
u.is_import_resolved = _resolve_use_all(u, namespace_scope)
64
elif !u.is_import_resolved then
65
_resolve_use_all(u, namespace_scope)
66
fi
67
68
continue
69
fi
70
71
if !u.`use? then
72
continue
73
fi
74
75
if !_final then
76
u.is_import_resolved = _resolve_use(u, namespace_scope)
77
elif !u.is_import_resolved then
78
_resolve_use(u, namespace_scope)
79
fi
80
od
81
return false
82
si
83
84
visit(`namespace: Definitions.NAMESPACE) is
85
leave_namespace(`namespace)
86
si
87
88
89
// Declares the symbol for a type alias clause. The target type
90
// expression is left for resolve-type-expressions, which is the
91
// pass that can resolve it; all that is needed here is a symbol
92
// for the name to bind to, carrying its type parameters.
93
_declare_alias(u: Definitions.USE, namespace_scope: Semantic.NAMESPACE_SCOPE) is
94
let name = u.name
95
96
if !name? then
97
return
98
fi
99
100
let existing = namespace_scope.get_used_symbol(name.name)
101
102
if existing? then
103
// Re-running the pass over a block whose scope already
104
// carries this clause's symbol is a no-op; any other
105
// symbol under the name is a genuine collision.
106
if let previous = u.alias_symbol /\ existing == cast Semantic.Symbols.Symbol(previous) then
107
return
108
fi
109
110
_logger.error(name.location, "duplicate use")
111
112
return
113
fi
114
115
let declared = namespace_scope.find_direct(name.name)
116
117
if declared? then
118
_logger.error(
119
name.location,
120
"type alias {name.name} has the same name as a symbol declared in this namespace",
121
declared.location,
122
"symbol declared here"
123
)
124
125
return
126
fi
127
128
let alias =
129
Semantic.Symbols.TYPE_ALIAS(
130
name.location,
131
namespace_scope,
132
name.name,
133
namespace_scope
134
)
135
136
if let arguments = u.arguments then
137
for a in arguments do
138
if isa TypeExpressions.NAMED(a) then
139
let argument = a
140
141
alias.declare_argument(argument.name.location, argument.name.name, null)
142
elif !a.is_poisoned then
143
_logger.error(a.location, "a type alias type parameter must be a plain identifier")
144
fi
145
od
146
fi
147
148
u.alias_symbol = alias
149
150
_symbol_use_locations.add_symbol_use(name.right_location, alias)
151
152
namespace_scope.add(name.name, alias)
153
si
154
155
// Imports each name `use default` stands for. Every name is
156
// attempted in both rounds: a namespace binds in the first, a
157
// global function or static method only once members exist, and
158
// one already imported by an explicit clause is left alone rather
159
// than reported as a duplicate - writing both is how a file adds
160
// to the set rather than a mistake to point at.
161
// Every synthesised identifier below carries `use default`'s own
162
// location, since there is no real per-name token in source to
163
// attach a use to. Recording them would leave the `use default`
164
// clause itself hovering and colouring as whichever imported
165
// symbol resolved uses last, so the whole round is suppressed.
166
_resolve_default_uses(u: Definitions.USE, namespace_scope: Semantic.NAMESPACE_SCOPE) is
167
_symbol_use_locations.begin_suppress()
168
169
try
170
for name in Compiler.DEFAULT_USES.names(IoC.CONTAINER.instance.build_flags) do
171
let identifier = _default_use_identifier(u.location, name)
172
173
if namespace_scope.contains_used_symbol(identifier.name) then
174
continue
175
fi
176
177
if !find_enclosing(identifier)? then
178
if _final then
179
_logger.error(u.location, "the default use set names {name}, which is not defined")
180
fi
181
182
continue
183
fi
184
185
let clause = Definitions.USE(u.location, null, identifier)
186
187
_resolve_use(clause, namespace_scope)
188
od
189
finally
190
_symbol_use_locations.end_suppress()
191
yrt
192
si
193
194
// The qualified identifier a dotted name in the set spells.
195
_default_use_identifier(location: LOCATION, name: string) -> Identifiers.Identifier is
196
let parts = name.split(['.'])
197
198
let result mut = Identifiers.Identifier(location, parts[0])
199
200
for i in 1..parts.count do
201
result = Identifiers.QUALIFIED(location, result, parts[i], location, location)
202
od
203
204
return result
205
si
206
207
// Returns true when the clause was definitively handled - a
208
// successful import or, in the final round, a reported error.
209
_resolve_use(u: Definitions.USE, namespace_scope: Semantic.NAMESPACE_SCOPE) -> bool is
210
let used_name = u.`use
211
212
if !used_name? then
213
return true
214
fi
215
216
let used_symbol = find_enclosing(used_name) ?? _find_attribute_type(used_name)
217
218
if !used_symbol? then
219
if _final then
220
_logger.error(used_name.location, "used identifier {used_name} is not defined ")
221
fi
222
223
return false
224
fi
225
226
_import_symbol(used_symbol, used_name, u.name, namespace_scope)
227
228
return true
229
si
230
231
// A pragma names an attribute type in the short form, so a use
232
// clause written to bring one into scope is written the same way.
233
// The suffixed type is imported under its own name, which is what
234
// the pragma's own short-form lookup then finds. Ancestors are not
235
// resolved yet, so the name is the only evidence available that
236
// the type is an attribute.
237
_find_attribute_type(used_name: Identifiers.Identifier) -> Semantic.Symbols.Symbol? is
238
if used_name.name.ends_with("Attribute") then
239
return null
240
fi
241
242
let suffixed_name = "{used_name.name}Attribute"
243
244
let suffixed =
245
if let qualifier = used_name.qualifier then
246
Identifiers.QUALIFIED(
247
used_name.location,
248
qualifier,
249
suffixed_name,
250
used_name.location,
251
used_name.location)
252
else
253
Identifiers.Identifier(used_name.location, suffixed_name)
254
fi
255
256
let found = find_enclosing(suffixed)
257
258
if isa Semantic.Symbols.Classy(found) then
259
return found
260
fi
261
262
return null
263
si
264
265
// Resolves `use X.*`. A namespace target is handled exactly like a
266
// plain `use X;` - its members are already reachable through the
267
// existing per-scope namespace fallback, so there is nothing extra
268
// to enumerate. A class, struct, union or enum target has no
269
// members to enumerate until declare-members has run, so the first
270
// round only resolves and records the container; the second round
271
// - the same one that lets an ordinary use clause resolve a static
272
// method or enum member - enumerates and imports them.
273
_resolve_use_all(u: Definitions.USE, namespace_scope: Semantic.NAMESPACE_SCOPE) -> bool is
274
let used_name = u.`use
275
276
if !used_name? then
277
return true
278
fi
279
280
let container = u.wildcard_target ?? find_enclosing(used_name)
281
282
if !container? then
283
if _final then
284
_logger.error(used_name.location, "used identifier {used_name} is not defined ")
285
fi
286
287
return false
288
fi
289
290
if isa Semantic.Symbols.NAMESPACE(container) then
291
return _resolve_use(u, namespace_scope)
292
fi
293
294
if !isa Semantic.Symbols.Classy(container) then
295
_logger.error(used_name.location, "cannot use all members of {used_name}")
296
297
return true
298
fi
299
300
u.wildcard_target = container
301
302
if !_final then
303
return false
304
fi
305
306
let classy = cast Semantic.Symbols.Classy?(container)!
307
308
// `used_name` names the container, not any one member - the
309
// `.*` has no per-member token to attach a use to. Record
310
// the container itself once, then suppress the per-member
311
// imports below so they don't pile more uses onto the same
312
// span and win the hover / colouring tie-break.
313
_symbol_use_locations.add_symbol_use(used_name.right_location, container)
314
315
_symbol_use_locations.begin_suppress()
316
317
try
318
for member in classy.symbols do
319
if _is_wildcard_importable(member) then
320
_import_symbol(member, used_name, null, namespace_scope)
321
fi
322
od
323
finally
324
_symbol_use_locations.end_suppress()
325
yrt
326
327
return true
328
si
329
330
// Whether a directly-declared member is something `use X.*` may
331
// import: the same shapes a hand-written `use X.member;` succeeds
332
// on, minus a constructor and a synthesized member (an
333
// auto-property's backing field), neither of which anything
334
// sensibly imports by name. Accessibility is left to the ordinary
335
// reference-site check, exactly as it is for an explicit `use
336
// X.member;` - importing does not itself require the name to be
337
// usable from here, only reaching it later does.
338
_is_wildcard_importable(symbol: Semantic.Symbols.Symbol) -> bool is
339
if symbol.is_internal \/ symbol.is_constructor \/ symbol.is_static_constructor then
340
return false
341
fi
342
343
if symbol.is_function_group then
344
let fg = cast Semantic.Symbols.FUNCTION_GROUP?(symbol)!
345
346
return fg.functions |> any(f => !f.is_instance /\ !f.is_constructor /\ !f.is_static_constructor)
347
fi
348
349
return !symbol.is_instance
350
si
351
352
// Imports a single resolved symbol into the namespace's scope,
353
// under `alias`'s name when given and the symbol's own name
354
// otherwise. Shared by an explicit `use X.member;` and, per member,
355
// by `use X.*`'s expansion, so a wildcard import reports the same
356
// diagnostics for the same shapes of symbol that the explicit
357
// imports it stands for would.
358
_import_symbol(
359
used_symbol: Semantic.Symbols.Symbol,
360
used_name: Identifiers.Identifier,
361
alias: Identifiers.Identifier?,
362
namespace_scope: Semantic.NAMESPACE_SCOPE
363
) is
364
let use_name mut = used_symbol.name
365
366
if alias? then
367
use_name = alias.name
368
fi
369
370
if isa Semantic.Symbols.NAMESPACE(used_symbol) then
371
_symbol_use_locations.add_symbol_use(used_name.right_location, used_symbol)
372
373
if namespace_scope.contains_used_symbol(use_name) then
374
if alias? then
375
_logger.error(alias.location, "duplicate use")
376
else
377
_logger.error(used_name.location, "duplicate use")
378
fi
379
elif alias? then
380
namespace_scope.add(alias.name, used_symbol)
381
else
382
namespace_scope.add(used_symbol)
383
fi
384
elif used_symbol.is_function_group then
385
let fg = cast Semantic.Symbols.FUNCTION_GROUP?(used_symbol)!
386
387
if !(fg.functions |> any(f => !f.is_instance)) then
388
if fg.functions.count == 1 then
389
_logger.error(used_name.location, "cannot use instance function")
390
else
391
_logger.error(used_name.location, "cannot use function group comprising only instance functions")
392
fi
393
fi
394
395
_symbol_use_locations.add_symbol_use(used_name.right_location, used_symbol.collapse_group_if_single_member())
396
397
let existing_used_symbol = namespace_scope.get_used_symbol(use_name)
398
399
let use_function_group: Semantic.Symbols.FUNCTION_GROUP mut
400
401
if existing_used_symbol? then
402
use_function_group = cast Semantic.Symbols.FUNCTION_GROUP?(existing_used_symbol)!
403
else
404
use_function_group = Semantic.Symbols.FUNCTION_GROUP(LOCATION.unknown, namespace_scope, use_name)
405
namespace_scope.add(use_name, use_function_group)
406
fi
407
408
use_function_group.add(fg)
409
elif !used_symbol.is_instance then
410
if namespace_scope.contains_used_symbol(use_name) then
411
if alias? then
412
_logger.error(alias.location, "duplicate use")
413
else
414
_logger.error(used_name.location, "duplicate use")
415
fi
416
else
417
_symbol_use_locations.add_symbol_use(used_name.right_location, used_symbol)
418
namespace_scope.add(use_name, used_symbol)
419
fi
420
else
421
_logger.error(used_name.location, "cannot use instance member")
422
fi
423
si
424
si
425
si