Appearance
| 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 |