Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use Logging | |
| 3 | use Source | |
| 4 | ||
| 5 | use Semantic.Types.Type | |
| 6 | ||
| 7 | use IR.Values | |
| 8 | ||
| 9 | use Ghul.Pipes | |
| 10 | ||
| 11 | // Compiles the type-argument-application family of expressions: | |
| 12 | // ambiguous expressions and generic applications (the | |
| 13 | // resolved-to-type / resolved-to-function forms). Split out of | |
| 14 | // COMPILE_EXPRESSIONS, which delegates the matching visit / pre | |
| 15 | // methods here. The bodies live in their `pre` methods — they | |
| 16 | // re-walk children and suppress the default traversal — so the | |
| 17 | // visitor's `visit` overrides for those stay empty. | |
| 18 | class COMPILE_GENERIC_APPLICATION is | |
| 19 | _logger: Logger | |
| 20 | _symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS | |
| 21 | _symbol_loader: Semantic.SYMBOL_LOADER | |
| 22 | _unit_variant_constructor: Semantic.UNIT_VARIANT_CONSTRUCTOR | |
| 23 | _visitor: ScopedVisitor | |
| 24 | _function_reference_resolver: Semantic.FUNCTION_REFERENCE_RESOLVER | |
| 25 | _shadowed_callable_finder: Semantic.SHADOWED_CALLABLE_FINDER | |
| 26 | ||
| 27 | init( | |
| 28 | logger: Logger, | |
| 29 | symbol_table: Semantic.SYMBOL_TABLE, | |
| 30 | symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS, | |
| 31 | symbol_loader: Semantic.SYMBOL_LOADER, | |
| 32 | innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup, | |
| 33 | overload_resolver: Semantic.OVERLOAD_RESOLVER, | |
| 34 | unit_variant_constructor: Semantic.UNIT_VARIANT_CONSTRUCTOR, | |
| 35 | visitor: ScopedVisitor | |
| 36 | ) is | |
| 37 | super.init() | |
| 38 | ||
| 39 | _logger = logger | |
| 40 | _symbol_use_locations = symbol_use_locations | |
| 41 | _symbol_loader = symbol_loader | |
| 42 | _unit_variant_constructor = unit_variant_constructor | |
| 43 | _visitor = visitor | |
| 44 | ||
| 45 | _shadowed_callable_finder = Semantic.SHADOWED_CALLABLE_FINDER(logger, symbol_table) | |
| 46 | ||
| 47 | _function_reference_resolver = | |
| 48 | Semantic.FUNCTION_REFERENCE_RESOLVER( | |
| 49 | logger, | |
| 50 | symbol_table, | |
| 51 | symbol_loader, | |
| 52 | innate_symbol_lookup, | |
| 53 | overload_resolver | |
| 54 | ) | |
| 55 | si | |
| 56 | ||
| 57 | pre_ambiguous_expression(ambiguous_expression: Trees.Expressions.AMBIGUOUS_EXPRESSION) -> bool is | |
| 58 | if ambiguous_expression.result == Trees.Expressions.AmbiguousExpressionResult.INDEX then | |
| 59 | if let ambiguous_expression.value? /\ value.is_need_store then | |
| 60 | ambiguous_expression.index.compile_expressions_state.value = value | |
| 61 | fi | |
| 62 | ||
| 63 | ambiguous_expression.index.walk(_visitor) | |
| 64 | ||
| 65 | ambiguous_expression.compile_expressions_state.value = ambiguous_expression.index.value | |
| 66 | ||
| 67 | return true | |
| 68 | fi | |
| 69 | ||
| 70 | let arg = ambiguous_expression.type_arguments.elements[0] | |
| 71 | ||
| 72 | arg.walk(_visitor) | |
| 73 | ||
| 74 | let symbol: Semantic.Symbols.Symbol? mut = _ | |
| 75 | ||
| 76 | if ambiguous_expression.left? then | |
| 77 | ambiguous_expression.left.walk(_visitor) | |
| 78 | ||
| 79 | if ambiguous_expression.left!.value? then | |
| 80 | symbol = ambiguous_expression.left!.value!.type!.find_member(ambiguous_expression.identifier.name) | |
| 81 | ||
| 82 | // find member will not report an error for not found | |
| 83 | if !symbol? then | |
| 84 | _logger.error(ambiguous_expression.identifier.location, "member {ambiguous_expression.identifier.name} not found in {ambiguous_expression.left!.value!.type}") | |
| 85 | fi | |
| 86 | fi | |
| 87 | else | |
| 88 | symbol = _find_applicable(ambiguous_expression.identifier) | |
| 89 | fi | |
| 90 | ||
| 91 | if !symbol? then | |
| 92 | return true | |
| 93 | fi | |
| 94 | ||
| 95 | _symbol_use_locations.add_symbol_use(ambiguous_expression.identifier.location, symbol) | |
| 96 | ||
| 97 | let result_type: Semantic.Types.Type? mut = _ | |
| 98 | let result_symbol: Semantic.Symbols.Symbol? mut = _ | |
| 99 | ||
| 100 | if symbol.is_type then | |
| 101 | ambiguous_expression.result = Trees.Expressions.AmbiguousExpressionResult.TYPE | |
| 102 | result_type = | |
| 103 | specialize_type( | |
| 104 | ambiguous_expression.location, | |
| 105 | symbol, | |
| 106 | ambiguous_expression.type_arguments | |
| 107 | ) | |
| 108 | elif symbol.is_function \/ symbol.is_function_group then | |
| 109 | ambiguous_expression.result = Trees.Expressions.AmbiguousExpressionResult.FUNCTION | |
| 110 | result_symbol = | |
| 111 | specialize_symbol( | |
| 112 | ambiguous_expression.location, | |
| 113 | symbol, | |
| 114 | ambiguous_expression.type_arguments | |
| 115 | ) | |
| 116 | else | |
| 117 | _logger.error(ambiguous_expression.location, "cannot apply type arguments here") | |
| 118 | return true | |
| 119 | fi | |
| 120 | ||
| 121 | let result = ambiguous_expression.result | |
| 122 | ||
| 123 | if result == Trees.Expressions.AmbiguousExpressionResult.UNKNOWN then | |
| 124 | // we didn't resolve what this was in the resolve type expressions phase | |
| 125 | // don't report another error here, just produce a propagating error value: | |
| 126 | ambiguous_expression.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), ambiguous_expression.location) | |
| 127 | elif result == Trees.Expressions.AmbiguousExpressionResult.INDEX then | |
| 128 | // if the ambiguous expression resolved to an indexer | |
| 129 | // call then walk that | |
| 130 | ambiguous_expression.index.walk(_visitor) | |
| 131 | ||
| 132 | // our value is whatever value the index expression produced | |
| 133 | ambiguous_expression.compile_expressions_state.value = ambiguous_expression.index.value | |
| 134 | elif result == Trees.Expressions.AmbiguousExpressionResult.TYPE then | |
| 135 | if symbol.is_unit_variant then | |
| 136 | let lowered = _unit_variant_constructor.try_load(ambiguous_expression.location, symbol, result_type, ambiguous_expression) | |
| 137 | ||
| 138 | if lowered? then | |
| 139 | _symbol_use_locations.add_symbol_use(ambiguous_expression.identifier.location, lowered.constructor) | |
| 140 | ambiguous_expression.compile_expressions_state.value = lowered.value | |
| 141 | return true | |
| 142 | fi | |
| 143 | fi | |
| 144 | ||
| 145 | ambiguous_expression.compile_expressions_state.value = TYPE_EXPRESSION(result_type!, ambiguous_expression.location) | |
| 146 | elif result == Trees.Expressions.AmbiguousExpressionResult.FUNCTION then | |
| 147 | if !result_symbol? then | |
| 148 | // try_specialize already reported why; propagate an error value | |
| 149 | ambiguous_expression.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), ambiguous_expression.location) | |
| 150 | return true | |
| 151 | fi | |
| 152 | ||
| 153 | let left_value: Value? = | |
| 154 | if ambiguous_expression.left? then | |
| 155 | ambiguous_expression.left.value | |
| 156 | else | |
| 157 | null | |
| 158 | fi | |
| 159 | ||
| 160 | // A name applied to type arguments and then used as a | |
| 161 | // value is a function reference at that instantiation, | |
| 162 | // so it takes the same route to a function value as a | |
| 163 | // bare name does. A call target declines, and its own | |
| 164 | // path calls the symbol directly. | |
| 165 | ambiguous_expression.compile_expressions_state.value = | |
| 166 | _function_reference_resolver.try_load( | |
| 167 | ambiguous_expression.location, | |
| 168 | result_symbol, | |
| 169 | left_value, | |
| 170 | ambiguous_expression.expected_type, | |
| 171 | ambiguous_expression.is_call_target | |
| 172 | ) ?? | |
| 173 | result_symbol.load(ambiguous_expression.location, left_value, _symbol_loader) | |
| 174 | else | |
| 175 | assert false else "result variant is something unexpected {result}" | |
| 176 | fi | |
| 177 | ||
| 178 | return true | |
| 179 | si | |
| 180 | ||
| 181 | pre_generic_application(generic_application: Trees.Expressions.GENERIC_APPLICATION) -> bool is | |
| 182 | generic_application.type_arguments.walk(_visitor) | |
| 183 | ||
| 184 | let symbol: Semantic.Symbols.Symbol? mut = _ | |
| 185 | ||
| 186 | if generic_application.left? then | |
| 187 | generic_application.left.walk(_visitor) | |
| 188 | ||
| 189 | if generic_application.left!.value? then | |
| 190 | symbol = generic_application.left!.value!.type!.find_member(generic_application.identifier.name) | |
| 191 | ||
| 192 | // find member will not report an error for not found | |
| 193 | if !symbol? then | |
| 194 | _logger.error(generic_application.identifier.location, "member {generic_application.identifier.name} not found in {generic_application.left!.value!.type}") | |
| 195 | fi | |
| 196 | fi | |
| 197 | else | |
| 198 | // find will report an error for not found | |
| 199 | symbol = _find_applicable(generic_application.identifier) | |
| 200 | fi | |
| 201 | ||
| 202 | if !symbol? then | |
| 203 | return true | |
| 204 | fi | |
| 205 | ||
| 206 | _symbol_use_locations.add_symbol_use(generic_application.identifier.location, symbol) | |
| 207 | ||
| 208 | let result_type: Semantic.Types.Type? mut = _ | |
| 209 | let result_symbol: Semantic.Symbols.Symbol? mut = _ | |
| 210 | ||
| 211 | if symbol.is_type then | |
| 212 | generic_application.result = Trees.Expressions.AmbiguousExpressionResult.TYPE | |
| 213 | ||
| 214 | result_type = | |
| 215 | specialize_type( | |
| 216 | generic_application.location, | |
| 217 | symbol, | |
| 218 | generic_application.type_arguments | |
| 219 | ) | |
| 220 | elif symbol.is_function \/ symbol.is_function_group then | |
| 221 | generic_application.result = Trees.Expressions.AmbiguousExpressionResult.FUNCTION | |
| 222 | ||
| 223 | result_symbol = | |
| 224 | specialize_symbol( | |
| 225 | generic_application.location, | |
| 226 | symbol, | |
| 227 | generic_application.type_arguments | |
| 228 | ) | |
| 229 | else | |
| 230 | _logger.error(generic_application.location, "cannot apply type arguments here") | |
| 231 | return true | |
| 232 | fi | |
| 233 | ||
| 234 | let result = generic_application.result | |
| 235 | ||
| 236 | if result == Trees.Expressions.AmbiguousExpressionResult.UNKNOWN then | |
| 237 | // we didn't resolve what this was in the resolve type expressions phase | |
| 238 | // don't report another error here, just produce a propagating error value: | |
| 239 | generic_application.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), generic_application.location) | |
| 240 | elif result == Trees.Expressions.AmbiguousExpressionResult.TYPE then | |
| 241 | if symbol.is_unit_variant then | |
| 242 | let lowered = _unit_variant_constructor.try_load(generic_application.location, symbol, result_type, generic_application) | |
| 243 | ||
| 244 | if lowered? then | |
| 245 | _symbol_use_locations.add_symbol_use(generic_application.identifier.location, lowered.constructor) | |
| 246 | generic_application.compile_expressions_state.value = lowered.value | |
| 247 | return true | |
| 248 | fi | |
| 249 | fi | |
| 250 | ||
| 251 | generic_application.compile_expressions_state.value = TYPE_EXPRESSION(result_type!, generic_application.location) | |
| 252 | elif result == Trees.Expressions.AmbiguousExpressionResult.FUNCTION then | |
| 253 | if !result_symbol? then | |
| 254 | // try_specialize already reported why; propagate an error value | |
| 255 | generic_application.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), generic_application.location) | |
| 256 | return true | |
| 257 | fi | |
| 258 | ||
| 259 | let left_value: Value? = | |
| 260 | if generic_application.left? then | |
| 261 | generic_application.left.value | |
| 262 | else | |
| 263 | null | |
| 264 | fi | |
| 265 | ||
| 266 | // A name applied to type arguments and then used as a | |
| 267 | // value is a function reference at that instantiation, | |
| 268 | // so it takes the same route to a function value as a | |
| 269 | // bare name does. A call target declines, and its own | |
| 270 | // path calls the symbol directly. | |
| 271 | generic_application.compile_expressions_state.value = | |
| 272 | _function_reference_resolver.try_load( | |
| 273 | generic_application.location, | |
| 274 | result_symbol, | |
| 275 | left_value, | |
| 276 | generic_application.expected_type, | |
| 277 | generic_application.is_call_target | |
| 278 | ) ?? | |
| 279 | result_symbol.load(generic_application.location, left_value, _symbol_loader) | |
| 280 | else | |
| 281 | assert false else "result is something unexpected {result}" | |
| 282 | fi | |
| 283 | ||
| 284 | return true | |
| 285 | si | |
| 286 | ||
| 287 | _expand_alias(location: Source.LOCATION, alias: Semantic.Symbols.TYPE_ALIAS, arguments: Trees.TypeExpressions.LIST) -> Semantic.Types.Type is | |
| 288 | if alias.argument_count != arguments.elements.count then | |
| 289 | if alias.argument_count == 0 then | |
| 290 | _logger.error(location, "type alias {alias.name} takes no type arguments") | |
| 291 | else | |
| 292 | _logger.error(location, "expected {alias.argument_count} type arguments but found {arguments.elements.count}") | |
| 293 | fi | |
| 294 | ||
| 295 | return Semantic.Types.ERROR() | |
| 296 | fi | |
| 297 | ||
| 298 | let target = alias.target_type | |
| 299 | ||
| 300 | if !target? then | |
| 301 | return Semantic.Types.ERROR() | |
| 302 | fi | |
| 303 | ||
| 304 | let actual_arguments = Collections.LIST[Semantic.Types.Type]() | |
| 305 | ||
| 306 | for a in arguments do | |
| 307 | a.check_is_not_void(_logger, "cannot use void type here") | |
| 308 | ||
| 309 | actual_arguments.add(a.type ?? Semantic.Types.ERROR()) | |
| 310 | od | |
| 311 | ||
| 312 | return target.specialize(alias.argument_map(actual_arguments)) | |
| 313 | si | |
| 314 | ||
| 315 | specialize_type(location: Source.LOCATION, symbol: Semantic.Symbols.Symbol, arguments: Trees.TypeExpressions.LIST) -> Semantic.Types.Type is | |
| 316 | let resolved_symbol: Semantic.Symbols.Symbol mut = symbol | |
| 317 | let group = cast Semantic.Symbols.TYPE_GROUP?(symbol) | |
| 318 | ||
| 319 | if group? then | |
| 320 | let match = group.find_by_generic_arguments_count(arguments.elements.count) | |
| 321 | ||
| 322 | if !match? then | |
| 323 | let counts = group.generic_arguments_counts |> map(a -> string => "{a}") |> join(" or ") | |
| 324 | _logger.error(location, "expected {counts} type arguments but found {arguments.elements.count}") | |
| 325 | return Semantic.Types.ERROR() | |
| 326 | fi | |
| 327 | ||
| 328 | resolved_symbol = match | |
| 329 | fi | |
| 330 | ||
| 331 | // An alias stands for its target, so applying one to type | |
| 332 | // arguments is applying its target to them, substituted the | |
| 333 | // way resolve-type-expressions substitutes them where the | |
| 334 | // alias is written as a type. | |
| 335 | if let alias = cast Semantic.Symbols.TYPE_ALIAS?(resolved_symbol) then | |
| 336 | return _expand_alias(location, alias, arguments) | |
| 337 | fi | |
| 338 | ||
| 339 | if !isa Semantic.Symbols.Classy(resolved_symbol) then | |
| 340 | _logger.error(location, "cannot supply type arguments here") | |
| 341 | return Semantic.Types.ERROR() | |
| 342 | fi | |
| 343 | ||
| 344 | for a in arguments do | |
| 345 | a.check_is_not_void(_logger, "cannot use void type here") | |
| 346 | ||
| 347 | let t = a.type | |
| 348 | ||
| 349 | if t? /\ t.is_named /\ cast Semantic.Types.NAMED?(t)!.symbol.is_unsafe_constraints then | |
| 350 | _logger.warn(a.location, "unchecked-constraints", "type {t} has unchecked constraints") | |
| 351 | fi | |
| 352 | od | |
| 353 | ||
| 354 | let classy = resolved_symbol | |
| 355 | ||
| 356 | let actual_arguments = arguments |> map( | |
| 357 | // FIXME type inference issue | |
| 358 | a -> Type => if a.type? then a.type else Semantic.Types.ERROR() fi | |
| 359 | ) |> collect() | |
| 360 | ||
| 361 | let result = Semantic.Types.GENERIC(location, classy, actual_arguments) | |
| 362 | ||
| 363 | classy.check_argument_constraints(location, _logger, actual_arguments) | |
| 364 | ||
| 365 | if resolved_symbol.is_unsafe_constraints then | |
| 366 | _logger.warn(location, "unchecked-constraints", "type {result} has unchecked constraints") | |
| 367 | fi | |
| 368 | ||
| 369 | return result | |
| 370 | si | |
| 371 | ||
| 372 | // A name applied to type arguments can only mean a type or a function. | |
| 373 | // When the nearest symbol by that name is neither - a local variable, | |
| 374 | // say - the callable one further out is what the application means, | |
| 375 | // as it is for a bare call, and the same warning says so. | |
| 376 | _find_applicable(identifier: Trees.Identifiers.Identifier) -> Semantic.Symbols.Symbol? is | |
| 377 | let symbol = _visitor.find(identifier) | |
| 378 | ||
| 379 | if !symbol? \/ symbol.is_type \/ identifier.qualifier? then | |
| 380 | return symbol | |
| 381 | fi | |
| 382 | ||
| 383 | return _shadowed_callable_finder.find(identifier.location, identifier.name, symbol) ?? symbol | |
| 384 | si | |
| 385 | ||
| 386 | specialize_symbol(location: Source.LOCATION, symbol: Semantic.Symbols.Symbol, arguments: Trees.TypeExpressions.LIST) -> Semantic.Symbols.Symbol? is | |
| 387 | return | |
| 388 | symbol.try_specialize( | |
| 389 | location, | |
| 390 | _logger, | |
| 391 | arguments.elements |> | |
| 392 | map(t => t.type!) |> collect() | |
| 393 | ) | |
| 394 | si | |
| 395 | si | |
| 396 | si |