Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use System.Exception | |
| 3 | ||
| 4 | use IO.Std | |
| 5 | ||
| 6 | use Logging | |
| 7 | use Source | |
| 8 | ||
| 9 | use IR.Values | |
| 10 | use IR.VALUE_CONVERTER | |
| 11 | use IR.VALUE_BOXER | |
| 12 | ||
| 13 | use Semantic.LEAST_UPPER_BOUND_MAP | |
| 14 | use Semantic.Types.Type | |
| 15 | ||
| 16 | use Syntax.Trees.Definitions.PRAGMA | |
| 17 | ||
| 18 | use Ghul.Pipes | |
| 19 | ||
| 20 | ||
| 21 | // Variable-left walks: simple, destructuring and literal leaves, variable visits and | |
| 22 | // symbol type assignment for destructuring. | |
| 23 | partial COMPILE_EXPRESSIONS is | |
| 24 | pre(left: Trees.Variables.SIMPLE_VARIABLE_LEFT) -> bool => false | |
| 25 | visit(left: Trees.Variables.SIMPLE_VARIABLE_LEFT) is | |
| 26 | let symbol = find(left.name) | |
| 27 | ||
| 28 | if symbol? /\ isa Semantic.Types.SettableTyped(symbol) then | |
| 29 | let typed_symbol = cast Semantic.Types.SettableTyped(symbol) | |
| 30 | let left_state = _variable_left_state.get_or_add(left) | |
| 31 | ||
| 32 | symbol.define() | |
| 33 | ||
| 34 | let right_location = | |
| 35 | if left_state.right_location? then | |
| 36 | left_state.right_location | |
| 37 | else | |
| 38 | left.location | |
| 39 | fi | |
| 40 | ||
| 41 | // Iterative-inference re-narrowing: an iter-N type | |
| 42 | // that's a sentinel or contains a placeholder may | |
| 43 | // be overwritten on iter N+1 with the now-narrower | |
| 44 | // value (e.g. Function[placeholder, int] → | |
| 45 | // Function[int, int] once the lambda arg resolves). | |
| 46 | // | |
| 47 | // is_settled alone isn't enough: an overload candidate | |
| 48 | // that loses to a sibling can still leave its own | |
| 49 | // still-unbound method type-parameter committed as | |
| 50 | // the right-hand value's type on an earlier iter - | |
| 51 | // e.g. C from a losing >>[A,B,C] candidate that | |
| 52 | // failed to bind C. That's a real, non-sentinel type, | |
| 53 | // so is_settled reports it as final - but the | |
| 54 | // parameter isn't one of this function's own generic | |
| 55 | // parameters, so it can never mean anything here and | |
| 56 | // must be re-derived rather than kept. | |
| 57 | let current_type = typed_symbol.type | |
| 58 | ||
| 59 | let needs_set mut = | |
| 60 | !current_type? \/ | |
| 61 | !current_type.is_settled \/ | |
| 62 | current_type.has_function_generic_argument_foreign_to(current_function) | |
| 63 | ||
| 64 | // An inferred local is typed by its initializer on every | |
| 65 | // walk: a settled type left on the symbol by an earlier | |
| 66 | // walk of this body may be narrower than what the | |
| 67 | // initializer now yields, and a placeholder the | |
| 68 | // initializer now carries has to be installed for its | |
| 69 | // uses to back-feed it. | |
| 70 | if !needs_set /\ !left_state.explicit_type? /\ left_state.right_value? then | |
| 71 | needs_set = true | |
| 72 | fi | |
| 73 | ||
| 74 | if | |
| 75 | !needs_set /\ | |
| 76 | REFUTABLE_LEAF_RETYPE.needs_retype( | |
| 77 | left.is_refutable, | |
| 78 | left_state.explicit_type?, | |
| 79 | left_state.right_value? | |
| 80 | ) | |
| 81 | then | |
| 82 | needs_set = true | |
| 83 | fi | |
| 84 | ||
| 85 | if needs_set then | |
| 86 | if left_state.explicit_type? then | |
| 87 | typed_symbol.set_type(left_state.explicit_type) | |
| 88 | elif left_state.right_value? then | |
| 89 | let right_value = left_state.right_value | |
| 90 | ||
| 91 | if left_state.awaits_later_use /\ isa Semantic.Symbols.Variable(symbol) then | |
| 92 | let variable = symbol | |
| 93 | let placeholder = Semantic.Types.INFERRED_VARIABLE_TYPE(variable) | |
| 94 | ||
| 95 | typed_symbol.set_type(placeholder) | |
| 96 | ||
| 97 | let rule = | |
| 98 | if left_state.awaits_empty_literal then | |
| 99 | Semantic.OBLIGATIONS.EMPTY_LITERAL | |
| 100 | else | |
| 101 | "later_use" | |
| 102 | fi | |
| 103 | ||
| 104 | Semantic.OBLIGATIONS.defer(rule, placeholder, left.location) | |
| 105 | elif !Value.check_is_consumable(_logger, right_location, right_value) then | |
| 106 | typed_symbol.set_type(Semantic.Types.ERROR()) | |
| 107 | elif | |
| 108 | _logger.is_clean /\ | |
| 109 | right_value.type!.has_function_generic_argument_foreign_to(current_function) /\ | |
| 110 | !left.is_refutable /\ | |
| 111 | isa Semantic.Symbols.Variable(symbol) /\ | |
| 112 | !(cast Semantic.Symbols.Variable(symbol)).is_mutable_marked | |
| 113 | then | |
| 114 | // The initializer resolved to a call whose own | |
| 115 | // type parameter nothing bound. An immutable | |
| 116 | // local waits on its later uses for the type, | |
| 117 | // and the call is typed from that on later walks. | |
| 118 | let variable = cast Semantic.Symbols.Variable(symbol) | |
| 119 | let placeholder = Semantic.Types.INFERRED_VARIABLE_TYPE(variable) | |
| 120 | ||
| 121 | left_state.typed_by_later_use = true | |
| 122 | ||
| 123 | typed_symbol.set_type(placeholder) | |
| 124 | ||
| 125 | Semantic.OBLIGATIONS.defer("later_use", placeholder, left.location) | |
| 126 | elif | |
| 127 | _logger.is_clean /\ | |
| 128 | right_value.type!.has_function_generic_argument_foreign_to(current_function) | |
| 129 | then | |
| 130 | // The initializer resolved to a call whose | |
| 131 | // own type parameter nothing bound: neither | |
| 132 | // its arguments nor any type the context | |
| 133 | // supplied. There is no type to settle to, | |
| 134 | // and keeping the parameter would write an | |
| 135 | // unbound !!N as this variable's type. | |
| 136 | // | |
| 137 | // Reported only on an otherwise clean walk: | |
| 138 | // an unbound parameter reaching here after | |
| 139 | // some other diagnostic is that diagnostic's | |
| 140 | // consequence, not a separate fault. | |
| 141 | _logger.error(right_location, "cannot infer type here") | |
| 142 | ||
| 143 | typed_symbol.set_type(Semantic.Types.ERROR()) | |
| 144 | elif | |
| 145 | right_value.type!.is_null /\ | |
| 146 | !right_value.type!.is_error /\ | |
| 147 | isa Semantic.Symbols.Variable(symbol) | |
| 148 | then | |
| 149 | // A `null` initializer says only that the | |
| 150 | // local can be absent; what is later | |
| 151 | // assigned to it gives the type. | |
| 152 | let variable = symbol | |
| 153 | ||
| 154 | if Semantic.INFERENCE_TRACE.add_lower_bound("variables.null_initializer", variable, right_value.type!) then | |
| 155 | _logger.mark_consumed_any() | |
| 156 | fi | |
| 157 | ||
| 158 | let inferred = variable.try_get_inferred_type() | |
| 159 | ||
| 160 | if inferred? /\ !inferred.is_sentinel then | |
| 161 | typed_symbol.set_type(inferred) | |
| 162 | else | |
| 163 | typed_symbol.set_type(Semantic.Types.INFERRED_VARIABLE_TYPE(variable)) | |
| 164 | fi | |
| 165 | elif let variable: Semantic.Symbols.Variable = symbol /\ variable.is_mutable_marked then | |
| 166 | // A `mut` local holds what is assigned to it | |
| 167 | // later as well as its initializer: its type is | |
| 168 | // their join, floored so an unrelated assignment | |
| 169 | // is still reported where it is written. | |
| 170 | variable.joins_assignments = true | |
| 171 | ||
| 172 | if Semantic.INFERENCE_TRACE.add_lower_bound("variables.mut_initializer", variable, right_value.type!) then | |
| 173 | _logger.mark_consumed_any() | |
| 174 | fi | |
| 175 | ||
| 176 | typed_symbol.set_type( | |
| 177 | Semantic.MUT_LOCAL_JOIN().type_for( | |
| 178 | right_value.type!, | |
| 179 | variable.try_get_inferred_type(), | |
| 180 | variable.lower_bounds | |
| 181 | ) | |
| 182 | ) | |
| 183 | elif Semantic.Types.NULL_ELEMENT.within(right_value.type!) then | |
| 184 | // A tuple with a `null` element and nothing to say | |
| 185 | // what that element holds has no type a variable | |
| 186 | // can take. | |
| 187 | _logger.error(right_location, "cannot infer type here") | |
| 188 | ||
| 189 | typed_symbol.set_type(Semantic.Types.ERROR()) | |
| 190 | else | |
| 191 | typed_symbol.set_type(right_value.type!) | |
| 192 | fi | |
| 193 | else | |
| 194 | // No explicit type and no initializer | |
| 195 | // (`let l;`). Try the LUB accumulated from | |
| 196 | // later assignments; otherwise stand-in with | |
| 197 | // an INFERRED_VARIABLE_TYPE placeholder so | |
| 198 | // subsequent assignments can attach | |
| 199 | // constraints and the body retry loop | |
| 200 | // resolves on iteration N+1. | |
| 201 | // | |
| 202 | // !is_sentinel deliberate (not is_settled): | |
| 203 | // if try_get_inferred_type returns a | |
| 204 | // composite-with-placeholder LUB, we commit | |
| 205 | // it on iter N. The needs_set path above | |
| 206 | // uses is_settled, so iter N+1 picks the | |
| 207 | // slot up again and may refresh with a | |
| 208 | // more-resolved value. !is_sentinel accepts | |
| 209 | // a one-iter delayed convergence in exchange | |
| 210 | // for not re-deriving the LUB every iter | |
| 211 | // while it's stable. | |
| 212 | if isa Semantic.Symbols.Variable(symbol) then | |
| 213 | let variable = symbol | |
| 214 | let inferred = variable.try_get_inferred_type() | |
| 215 | ||
| 216 | if inferred? /\ !inferred.is_sentinel then | |
| 217 | typed_symbol.set_type(inferred) | |
| 218 | else | |
| 219 | typed_symbol.set_type(Semantic.Types.INFERRED_VARIABLE_TYPE(variable)) | |
| 220 | fi | |
| 221 | fi | |
| 222 | fi | |
| 223 | elif | |
| 224 | left_state.explicit_type? /\ | |
| 225 | left_state.right_value? /\ | |
| 226 | Value.check_is_consumable(_logger, right_location, left_state.right_value) | |
| 227 | then | |
| 228 | let explicit_type = left_state.explicit_type! | |
| 229 | let right_value = left_state.right_value! | |
| 230 | ||
| 231 | // A value still holding placeholders - a local whose | |
| 232 | // function literal left a parameter to later use - | |
| 233 | // learns their types from the declared type, as an | |
| 234 | // argument learns them from its formal. | |
| 235 | if right_value.type!.contains_inferred then | |
| 236 | _overload_resolver.match_propagator.propagate_match(explicit_type, right_value.type) | |
| 237 | fi | |
| 238 | ||
| 239 | if | |
| 240 | !left.is_refutable /\ | |
| 241 | !explicit_type.is_assignable_from(right_value.type!) | |
| 242 | then | |
| 243 | // Refutable bindings (`if let p: T = e`) skip | |
| 244 | // this check: the type ascription is a | |
| 245 | // runtime narrowing test, the scrutinee is | |
| 246 | // typically wider than `T`, and the cast may | |
| 247 | // fail — that's the whole point of the | |
| 248 | // construct. | |
| 249 | _logger.error( | |
| 250 | left_state.variable_location!, | |
| 251 | "{right_value.type} is not assignable to {explicit_type}") | |
| 252 | fi | |
| 253 | fi | |
| 254 | ||
| 255 | if left_state.right_value? then | |
| 256 | left_state.value = symbol.store(left.location, null, left_state.right_value, _symbol_loader, true) | |
| 257 | ||
| 258 | // A non-optional initializer leaves the local | |
| 259 | // known to hold a value — even where its declared | |
| 260 | // type is `T?` — so a following dereference does | |
| 261 | // not warn. Skipped when the local's declared | |
| 262 | // type is already non-optional (the presence bit | |
| 263 | // is redundant and the hint would be noise). | |
| 264 | if | |
| 265 | isa Semantic.Symbols.Variable(symbol) /\ | |
| 266 | is_non_optional_value(left_state.right_value) | |
| 267 | then | |
| 268 | let variable = cast Semantic.Symbols.Variable(symbol) | |
| 269 | let variable_type = variable.type | |
| 270 | ||
| 271 | if variable_type? /\ variable_type.is_optional then | |
| 272 | _flow.mark_non_null(variable) | |
| 273 | _flow.report_narrowing_site( | |
| 274 | left.location, | |
| 275 | "narrowing-assign", | |
| 276 | "►", | |
| 277 | INLAY_TYPE.render(variable_type.as_non_optional()) | |
| 278 | ) | |
| 279 | fi | |
| 280 | fi | |
| 281 | fi | |
| 282 | else | |
| 283 | _logger.error(left.name.location, "couldn't find typed symbol for variable {left.name}") | |
| 284 | fi | |
| 285 | si | |
| 286 | ||
| 287 | pre(left: Trees.Variables.DESTRUCTURING_VARIABLE_LEFT) -> bool is | |
| 288 | // A destructured formal argument has no initializer to walk | |
| 289 | // a value from - its leaves' types are already assigned by | |
| 290 | // resolve-explicit-types from the parameter's aggregate | |
| 291 | // type, and generate-il sources the unpack directly from | |
| 292 | // the synthesised parameter symbol. Nothing here applies. | |
| 293 | if left.is_argument_left then | |
| 294 | return true | |
| 295 | fi | |
| 296 | ||
| 297 | // Per-element type ascription: each element of a destructure | |
| 298 | // pattern can carry its own `: T` (e.g. `(c: Cat, d: Dog)`, | |
| 299 | // or recursively `((x: int, y: int): Point, c: Color)`). | |
| 300 | // Walk the type_expression and pin the element's | |
| 301 | // `explicit_type` so the bound symbol gets the declared | |
| 302 | // type rather than the raw source-member type. The runtime | |
| 303 | // narrowing test for the refutable path is emitted later | |
| 304 | // by `gen_destructuring_initialize` in generate_il. | |
| 305 | for e in left.elements do | |
| 306 | if let e.type_expression? then | |
| 307 | type_expression.walk(self) | |
| 308 | ||
| 309 | if let type_expression.type? then | |
| 310 | _variable_left_state.get_or_add(e).explicit_type = type | |
| 311 | fi | |
| 312 | fi | |
| 313 | od | |
| 314 | ||
| 315 | let left_state = _variable_left_state.get_or_add(left) | |
| 316 | ||
| 317 | let from mut = left_state.right_value | |
| 318 | ||
| 319 | if !from? then | |
| 320 | _logger.error(left.location, "cannot destructure without initializer") | |
| 321 | return true | |
| 322 | fi | |
| 323 | ||
| 324 | let from_type mut = | |
| 325 | if left_state.explicit_type? then | |
| 326 | left_state.explicit_type | |
| 327 | else | |
| 328 | from.type | |
| 329 | fi | |
| 330 | ||
| 331 | if !from_type? then | |
| 332 | _logger.error(left.location, "oops: null type") | |
| 333 | ||
| 334 | from_type = Semantic.Types.ERROR() | |
| 335 | fi | |
| 336 | ||
| 337 | // Refutable destructure on an optional source: the `if let` | |
| 338 | // presence test has already excluded null at this point, so | |
| 339 | // resolve members against the unwrapped type and load them | |
| 340 | // from the unwrapped value. A value-type `T?` unwraps via | |
| 341 | // its synthesised `value` member; a reference `T?` keeps | |
| 342 | // the same backing value and just drops the optional flag. | |
| 343 | if left.is_refutable /\ from_type.is_optional then | |
| 344 | if from_type.is_value_type then | |
| 345 | let value_member = from_type.find_member("value") | |
| 346 | ||
| 347 | if value_member? then | |
| 348 | from = value_member.load(LOCATION.internal, from, _symbol_loader) | |
| 349 | from_type = from.type! | |
| 350 | fi | |
| 351 | else | |
| 352 | from_type = from_type.as_non_optional() | |
| 353 | from = IR.Values.TYPE_WRAPPER(from_type, from) | |
| 354 | fi | |
| 355 | fi | |
| 356 | ||
| 357 | // Destructure on a still-unresolved placeholder: emit a | |
| 358 | // DESTRUCTURE_CONSTRAINT(member_count) on the | |
| 359 | // placeholder's origin so the body-retry loop can filter | |
| 360 | // candidate types against it, then defer rather than | |
| 361 | // hard-erroring "cannot destructure". Without this the | |
| 362 | // body-retry never gets a useful signal — the destructure | |
| 363 | // type is fixed and the lambda's RHS placeholder is | |
| 364 | // forced to resolve via some other use. | |
| 365 | if isa Semantic.Types.INFERRED_VARIABLE_TYPE(from_type) then | |
| 366 | let placeholder = from_type | |
| 367 | let constraint = Semantic.DESTRUCTURE_CONSTRAINT(left.elements.count) | |
| 368 | ||
| 369 | _logger.mark_consumed_any_if(Semantic.INFERENCE_TRACE.add_constraint("variables.destructure", placeholder.origin, constraint)) | |
| 370 | ||
| 371 | _defer_destructure_leaves(left, from_type) | |
| 372 | ||
| 373 | return true | |
| 374 | fi | |
| 375 | ||
| 376 | // Any other placeholder - a join still waiting on an operand - | |
| 377 | // has no origin to constrain and is not an error either: an | |
| 378 | // obligation of this walk, for a later one to settle. | |
| 379 | if from_type.is_inferred then | |
| 380 | Semantic.OBLIGATIONS.defer("destructure", from_type, left.location) | |
| 381 | ||
| 382 | _defer_destructure_leaves(left, from_type) | |
| 383 | ||
| 384 | return true | |
| 385 | fi | |
| 386 | ||
| 387 | let elements = left.elements | |
| 388 | ||
| 389 | // A group is either all named or all positional: the | |
| 390 | // parser reports one that mixes the two. It yields the | |
| 391 | // group anyway, so that the rest of the statement is | |
| 392 | // still walked, which is the one case where an element | |
| 393 | // here carries no name while its neighbour does - and | |
| 394 | // the mixing is already reported, so there is nothing | |
| 395 | // left to resolve. | |
| 396 | let is_named_group = elements.count > 0 /\ elements[0].source_field_name? | |
| 397 | ||
| 398 | let field_names: Collections.List[string?]? mut = null | |
| 399 | if is_named_group then | |
| 400 | if elements |> any(element => !element.source_field_name?) then | |
| 401 | return true | |
| 402 | fi | |
| 403 | ||
| 404 | let names = Collections.LIST[string?]() | |
| 405 | for element in elements do | |
| 406 | names.add(element.source_field_name!.name) | |
| 407 | od | |
| 408 | field_names = names | |
| 409 | fi | |
| 410 | ||
| 411 | let strategy = resolve_destructure_strategy(left.location, from_type, elements.count, field_names) | |
| 412 | ||
| 413 | let block = IR.Values.BLOCK(_innate_symbol_lookup.get_void_type()) | |
| 414 | ||
| 415 | if strategy.is_deconstruct then | |
| 416 | let deconstruct = strategy.deconstruct_function! | |
| 417 | ||
| 418 | for i in 0..elements.count do | |
| 419 | let element = elements[i] | |
| 420 | let element_type = deconstruct.arguments[i].get_element_type()! | |
| 421 | ||
| 422 | let element_state = _variable_left_state.get_or_add(element) | |
| 423 | ||
| 424 | element_state.right_value = IR.Values.DUMMY(element_type, element.location) | |
| 425 | ||
| 426 | element_state.variable_location = left_state.variable_location | |
| 427 | element_state.right_location = left_state.right_location | |
| 428 | ||
| 429 | element.walk(self) | |
| 430 | ||
| 431 | if element_state.value? then | |
| 432 | block.add(element_state.value) | |
| 433 | fi | |
| 434 | od | |
| 435 | else | |
| 436 | let members = strategy.members | |
| 437 | let get_from = from.get_temp_copier(block, "destructure") | |
| 438 | ||
| 439 | for i in 0..elements.count do | |
| 440 | let element = elements[i] | |
| 441 | let member = members[i] | |
| 442 | ||
| 443 | if member? then | |
| 444 | let element_state = _variable_left_state.get_or_add(element) | |
| 445 | ||
| 446 | element_state.right_value = member.load(LOCATION.internal, get_from(), _symbol_loader) | |
| 447 | ||
| 448 | element_state.variable_location = left_state.variable_location | |
| 449 | element_state.right_location = left_state.right_location | |
| 450 | ||
| 451 | element.walk(self) | |
| 452 | ||
| 453 | if element_state.value? then | |
| 454 | block.add(element_state.value) | |
| 455 | fi | |
| 456 | fi | |
| 457 | od | |
| 458 | fi | |
| 459 | ||
| 460 | block.close() | |
| 461 | ||
| 462 | left_state.value = block | |
| 463 | ||
| 464 | return true | |
| 465 | si | |
| 466 | ||
| 467 | // While the source of a destructure is still being inferred, each | |
| 468 | // name it declares stands as a placeholder of its own, so its uses | |
| 469 | // bound it rather than finding it undefined. It waits on the source, | |
| 470 | // which is what a later walk types it from, and what is reported if | |
| 471 | // nothing does. | |
| 472 | _defer_destructure_leaves(left: Trees.Variables.VariableLeft, source: Type) is | |
| 473 | let elements = left.elements | |
| 474 | ||
| 475 | if !elements? then | |
| 476 | return | |
| 477 | fi | |
| 478 | ||
| 479 | for element in elements do | |
| 480 | if element.is_simple_name then | |
| 481 | if let variable: Semantic.Symbols.Variable = find(element.name!) then | |
| 482 | variable.define() | |
| 483 | ||
| 484 | if let explicit_type = _variable_left_state.get_or_add(element).explicit_type then | |
| 485 | variable.set_type(explicit_type) | |
| 486 | elif !variable.type? \/ !variable.type.is_settled then | |
| 487 | let placeholder = Semantic.Types.INFERRED_VARIABLE_TYPE(variable) | |
| 488 | ||
| 489 | variable.set_type(placeholder) | |
| 490 | ||
| 491 | Semantic.OBLIGATIONS.defer("destructure", source, element.location) | |
| 492 | fi | |
| 493 | fi | |
| 494 | else | |
| 495 | _defer_destructure_leaves(element, source) | |
| 496 | fi | |
| 497 | od | |
| 498 | si | |
| 499 | ||
| 500 | visit(destructure_left: Trees.Variables.DESTRUCTURING_VARIABLE_LEFT) is | |
| 501 | si | |
| 502 | ||
| 503 | // A literal leaf inside a destructure pattern — a runtime | |
| 504 | // equality test, not a binding. The expression carries its | |
| 505 | // own type (literal kinds map to fixed types; an enum-member | |
| 506 | // name expression types to its enum). The expression is | |
| 507 | // walked via default descent; the source position's type is | |
| 508 | // pushed down as a constraint so a `null` leaf picks up the | |
| 509 | // source position's nullable type (other literal kinds | |
| 510 | // inherit the constraint as a no-op, since their type is | |
| 511 | // fixed by their token kind). Literal-vs-source mismatches | |
| 512 | // are diagnosed eagerly by `visit(LITERAL_VARIABLE_LEFT)` | |
| 513 | // below, not via the constraint message. | |
| 514 | pre(left: Trees.Variables.LITERAL_VARIABLE_LEFT) -> bool is | |
| 515 | let right_value = _variable_left_state.get_or_add(left).right_value | |
| 516 | ||
| 517 | if right_value? /\ right_value.type? then | |
| 518 | left.expression.set_expected_type( | |
| 519 | right_value.type, | |
| 520 | "literal pattern type {{0}} is not comparable to source position type {{1}}" | |
| 521 | ) | |
| 522 | fi | |
| 523 | return false | |
| 524 | si | |
| 525 | ||
| 526 | visit(left: Trees.Variables.LITERAL_VARIABLE_LEFT) is | |
| 527 | // State survives between walks of the same node, so drop any | |
| 528 | // test a previous walk built before deciding to build one. | |
| 529 | let leaf_state = _variable_left_state.get_or_add(left) | |
| 530 | ||
| 531 | leaf_state.match_test = null | |
| 532 | leaf_state.match_operand = null | |
| 533 | ||
| 534 | // A matching leaf in a non-refutable context (plain `let`) | |
| 535 | // is a silent no-op at runtime — the pattern would never | |
| 536 | // actually test the source value, so subsequent bindings | |
| 537 | // run as if the leaf were a wildcard. Reject it loudly | |
| 538 | // here so the user is forced to write either `if let` | |
| 539 | // / `case`-when (where the leaf becomes an actual | |
| 540 | // equality test) or remove the leaf. | |
| 541 | if !left.is_refutable then | |
| 542 | _logger.error( | |
| 543 | left.location, | |
| 544 | "a matching leaf is only allowed inside a refutable binding (if let or case-when arm)" | |
| 545 | ) | |
| 546 | ||
| 547 | return | |
| 548 | fi | |
| 549 | ||
| 550 | // A leaf whose type is incompatible with the source | |
| 551 | // position's type can never match — the runtime equality | |
| 552 | // test is statically dead. Reject with a clear diagnostic | |
| 553 | // here rather than letting the IL emit and surface as a | |
| 554 | // less helpful comparison-operator error later. | |
| 555 | if let | |
| 556 | rv = leaf_state.right_value, source_type = rv.type, | |
| 557 | ev = left.expression.value, literal_type = ev.type | |
| 558 | then | |
| 559 | if | |
| 560 | !source_type.is_assignable_from(literal_type) /\ | |
| 561 | !literal_type.is_assignable_from(source_type) | |
| 562 | then | |
| 563 | _logger.error( | |
| 564 | left.location, | |
| 565 | "a leaf of type {literal_type} cannot match source position of type {source_type}" | |
| 566 | ) | |
| 567 | ||
| 568 | return | |
| 569 | fi | |
| 570 | ||
| 571 | _build_literal_leaf_test(left, source_type, ev) | |
| 572 | fi | |
| 573 | si | |
| 574 | ||
| 575 | // Build the runtime test a literal leaf performs against its | |
| 576 | // source position, the way `=~` (falling back to `<>`) would, so | |
| 577 | // a leaf whose type declares an equality operator matches by | |
| 578 | // value rather than by reference. Shares the `case` `when` | |
| 579 | // label builder, so the two refutable constructs agree on what | |
| 580 | // a literal matches. | |
| 581 | // | |
| 582 | // The source position's value does not exist until IL | |
| 583 | // generation walks the pattern, so the test is built against a | |
| 584 | // hole that generation fills in. Leaving the test unbuilt is | |
| 585 | // always safe: generation falls back to the raw compare, which | |
| 586 | // is what a bare `==` does too. | |
| 587 | _build_literal_leaf_test( | |
| 588 | left: Trees.Variables.LITERAL_VARIABLE_LEFT, | |
| 589 | source_type: Semantic.Types.Type, | |
| 590 | literal_value: IR.Values.Value | |
| 591 | ) is | |
| 592 | // A `null` leaf is a presence test rather than a value | |
| 593 | // comparison; a null operand would build a null-typed temp | |
| 594 | // the back end cannot encode. Generation matches absence. | |
| 595 | if literal_value.type?.is_null ?? false then | |
| 596 | return | |
| 597 | fi | |
| 598 | ||
| 599 | let operand = IR.Values.WRAPPER(IR.Values.DUMMY(source_type, left.location)) | |
| 600 | ||
| 601 | let test = | |
| 602 | build_equality_test(operand, literal_value, "=~", left.location) ?? | |
| 603 | build_equality_test(operand, literal_value, "<>", left.location) | |
| 604 | ||
| 605 | if !test? then | |
| 606 | return | |
| 607 | fi | |
| 608 | ||
| 609 | let state = _variable_left_state.get_or_add(left) | |
| 610 | ||
| 611 | state.match_operand = operand | |
| 612 | state.match_test = test | |
| 613 | si | |
| 614 | ||
| 615 | // The local an initializer `[]` would type, when the literal has | |
| 616 | // no context of its own: no written type on the literal or the | |
| 617 | // local, nothing pushed into the literal, and a plain immutable | |
| 618 | // local to bind. A mutable local joins its later assignments | |
| 619 | // instead. | |
| 620 | _empty_literal_awaiting_use(variable: Trees.Variables.VARIABLE, init: Trees.Expressions.Expression) -> Semantic.Symbols.Variable? is | |
| 621 | if variable.is_explicit_type \/ variable.is_refutable \/ variable.is_argument then | |
| 622 | return null | |
| 623 | fi | |
| 624 | ||
| 625 | let sequence = cast Trees.Expressions.SEQUENCE?(init) | |
| 626 | ||
| 627 | if | |
| 628 | !sequence? \/ | |
| 629 | sequence.elements.expressions.count != 0 \/ | |
| 630 | !isa Trees.TypeExpressions.INFER(sequence.type_expression) \/ | |
| 631 | sequence.expected_type? | |
| 632 | then | |
| 633 | return null | |
| 634 | fi | |
| 635 | ||
| 636 | if let simple: Trees.Variables.SIMPLE_VARIABLE_LEFT = variable.left then | |
| 637 | if let local: Semantic.Symbols.Variable = find(simple.name) /\ !local.is_mutable_marked then | |
| 638 | return local | |
| 639 | fi | |
| 640 | fi | |
| 641 | ||
| 642 | return null | |
| 643 | si | |
| 644 | ||
| 645 | // The plain immutable local an initializer with no type of its own | |
| 646 | // is typed from: a `_()` with nothing pushed into it, or a call a | |
| 647 | // previous walk found leaving a type parameter of its own unbound. | |
| 648 | _typed_by_later_use(variable: Trees.Variables.VARIABLE, init: Trees.Expressions.Expression) -> Semantic.Symbols.Variable? is | |
| 649 | if variable.is_explicit_type \/ variable.is_refutable \/ variable.is_argument then | |
| 650 | return null | |
| 651 | fi | |
| 652 | ||
| 653 | if let simple: Trees.Variables.SIMPLE_VARIABLE_LEFT = variable.left then | |
| 654 | if let local: Semantic.Symbols.Variable = find(simple.name) /\ !local.is_mutable_marked then | |
| 655 | let state = _variable_left_state.get_or_add(simple) | |
| 656 | ||
| 657 | if isa Trees.Expressions.CONSTRUCT(init) /\ !init.expected_type? then | |
| 658 | state.typed_by_later_use = true | |
| 659 | fi | |
| 660 | ||
| 661 | if state.typed_by_later_use then | |
| 662 | return local | |
| 663 | fi | |
| 664 | fi | |
| 665 | fi | |
| 666 | ||
| 667 | return null | |
| 668 | si | |
| 669 | ||
| 670 | pre(variable: Trees.Variables.VARIABLE) -> bool is | |
| 671 | // Attribute pragmas on a formal-argument parameter — walk | |
| 672 | // their argument expressions here since this override | |
| 673 | // suppresses VARIABLE's own default child walk (returns | |
| 674 | // true below). | |
| 675 | if variable.pragmas? then | |
| 676 | for pragma in variable.pragmas do | |
| 677 | pragma.walk(self) | |
| 678 | od | |
| 679 | fi | |
| 680 | ||
| 681 | variable.type_expression.walk(self) | |
| 682 | ||
| 683 | // push explicit type down into the variable left | |
| 684 | if let te_type = variable.type_expression.type /\ variable.is_explicit_type then | |
| 685 | _variable_left_state.get_or_add(variable.left).explicit_type = te_type | |
| 686 | fi | |
| 687 | ||
| 688 | if variable.is_refutable then | |
| 689 | variable.left.mark_refutable_recursive() | |
| 690 | fi | |
| 691 | ||
| 692 | // A bare `_` initializer of a simple local with no | |
| 693 | // explicit type is treated exactly like a no-initializer | |
| 694 | // `let`: the type is inferred from later assignments. | |
| 695 | // `_` only contributes the definite-assignment fact — the | |
| 696 | // LET deferred-init tracking keys off `initializer?`, | |
| 697 | // which is true here, so the variable is not warned. | |
| 698 | let bare_default = | |
| 699 | isa Trees.Expressions.DEFAULT(variable.initializer) /\ | |
| 700 | !(cast Trees.Expressions.DEFAULT(variable.initializer)).type_expression? /\ | |
| 701 | !variable.is_explicit_type /\ | |
| 702 | variable.left.is_simple_name | |
| 703 | ||
| 704 | if let init = variable.initializer /\ !bare_default /\ !variable.is_argument then | |
| 705 | if let te = variable.type_expression, te_type = te.type /\ !isa Trees.TypeExpressions.INFER(te) then | |
| 706 | // if we have both an explicit type and an initializer, we | |
| 707 | // can push a type constraint down into the initializer | |
| 708 | init.set_expected_type(te_type, "{{0}} is not assignable to {{1}}") | |
| 709 | fi | |
| 710 | ||
| 711 | // An untyped local initialized with `[]` takes its type | |
| 712 | // from its later uses: once a walk has settled the local, | |
| 713 | // the literal is typed from it, and until then the local | |
| 714 | // waits as a placeholder its uses can bound. The local | |
| 715 | // whose uses never settle it is defaulted by the fixing | |
| 716 | // step once the walks have stopped, and this walk is the | |
| 717 | // one after that: the literal then has no constraint | |
| 718 | // pushed into it and takes its own object element type. | |
| 719 | let waits_on_use = _empty_literal_awaiting_use(variable, init) | |
| 720 | ||
| 721 | let awaits mut = false | |
| 722 | let empty_literal mut = false | |
| 723 | ||
| 724 | if let waiting = waits_on_use /\ !Semantic.OBLIGATIONS.has_default_for(waiting) then | |
| 725 | let inferred = waiting.try_get_inferred_type() | |
| 726 | ||
| 727 | if Semantic.EMPTY_LITERAL_LOCAL.decide(inferred) == Semantic.EmptyLiteralLocal.TYPE_FROM_USE then | |
| 728 | init.set_expected_type(inferred!, "{{0}} is not assignable to {{1}}") | |
| 729 | else | |
| 730 | awaits = true | |
| 731 | empty_literal = true | |
| 732 | fi | |
| 733 | elif let later = _typed_by_later_use(variable, init) then | |
| 734 | // No default to fall back to: the local waits until its | |
| 735 | // uses settle it, and is reported if nothing does. | |
| 736 | let inferred = later.try_get_inferred_type() | |
| 737 | ||
| 738 | if inferred? /\ inferred.is_settled then | |
| 739 | init.set_expected_type(inferred, "{{0}} is not assignable to {{1}}") | |
| 740 | elif isa Trees.Expressions.CONSTRUCT(init) then | |
| 741 | init.set_expected_type(Semantic.Types.INFERRED_VARIABLE_TYPE(later), "{{0}} is not assignable to {{1}}") | |
| 742 | awaits = true | |
| 743 | fi | |
| 744 | fi | |
| 745 | ||
| 746 | let await_state = _variable_left_state.get_or_add(variable.left) | |
| 747 | ||
| 748 | await_state.awaits_later_use = awaits | |
| 749 | await_state.awaits_empty_literal = empty_literal | |
| 750 | ||
| 751 | init.walk(self) | |
| 752 | ||
| 753 | // push the initializer value down into the variable left | |
| 754 | let left_state = _variable_left_state.get_or_add(variable.left) | |
| 755 | ||
| 756 | if let init_value = init.value then | |
| 757 | left_state.right_value = init_value | |
| 758 | else | |
| 759 | left_state.right_value = IR.Values.DUMMY(Semantic.Types.ERROR(), init.location) | |
| 760 | fi | |
| 761 | ||
| 762 | left_state.variable_location = variable.location | |
| 763 | left_state.right_location = init.location | |
| 764 | fi | |
| 765 | ||
| 766 | // No-type, no-initializer is now allowed: the variable's | |
| 767 | // type is inferred from later assignments via the | |
| 768 | // INFERRED_VARIABLE_TYPE placeholder + LUB accumulator | |
| 769 | // (#1174 — see visit(SIMPLE_VARIABLE_LEFT) below). If | |
| 770 | // no assignment ever fires, the placeholder remains | |
| 771 | // and the variable's first use will produce a | |
| 772 | // "cannot infer" error. | |
| 773 | ||
| 774 | variable.left.walk(self) | |
| 775 | ||
| 776 | // Generator: register the new local on the state-machine | |
| 777 | // frame so a closure later in the body that captures it | |
| 778 | // references the frame field rather than a | |
| 779 | // CLR-local slot that doesn't exist inside MoveNext. | |
| 780 | // No-op outside a generator function; idempotent on the | |
| 781 | // field (declare_local_field returns the existing field | |
| 782 | // and only refreshes its type on subsequent calls). | |
| 783 | declare_state_machine_local_fields(variable.left) | |
| 784 | ||
| 785 | return true | |
| 786 | si | |
| 787 | ||
| 788 | visit(variable: Trees.Variables.VARIABLE) is | |
| 789 | // A typed `let x: T = e` — check the initializer against | |
| 790 | // the declared type. An untyped `let` infers its type | |
| 791 | // from the initializer, so there is no slot to violate. | |
| 792 | let type_expression = variable.type_expression | |
| 793 | let initializer = variable.initializer | |
| 794 | ||
| 795 | if initializer? then | |
| 796 | check_non_optional( | |
| 797 | type_expression.type, | |
| 798 | initializer, | |
| 799 | initializer.location | |
| 800 | ) | |
| 801 | ||
| 802 | _pure_slots.check_store(initializer.location, type_expression.type, initializer.value) | |
| 803 | fi | |
| 804 | ||
| 805 | if let pragmas = variable.pragmas then | |
| 806 | let target = symbol_for(variable) | |
| 807 | ||
| 808 | for pragma in pragmas do | |
| 809 | _attribute_resolver.resolve(pragma, target) | |
| 810 | od | |
| 811 | fi | |
| 812 | si | |
| 813 | ||
| 814 | // TODO used by for loop - needs removing | |
| 815 | set_symbol_type(left: Trees.Variables.VariableLeft, type: Type) is | |
| 816 | ||
| 817 | if left.is_simple_name then | |
| 818 | // is_simple_name => SIMPLE_VARIABLE_LEFT, whose name is non-null | |
| 819 | let symbol = find(left.name!) | |
| 820 | ||
| 821 | if symbol? /\ isa Semantic.Types.SettableTyped(symbol) then | |
| 822 | let typed_symbol = cast Semantic.Types.SettableTyped(symbol) | |
| 823 | ||
| 824 | symbol.define() | |
| 825 | ||
| 826 | typed_symbol.set_type(type) | |
| 827 | else | |
| 828 | _logger.error(left.location, "couldn't find typed symbol for variable {left.name}") | |
| 829 | fi | |
| 830 | else | |
| 831 | set_symbol_destructure_types(left, type) | |
| 832 | fi | |
| 833 | si | |
| 834 | ||
| 835 | // TODO used by for loop - needs removing | |
| 836 | set_symbol_destructure_types(left: Trees.Variables.VariableLeft, from_type: Type) is | |
| 837 | let elements = left.elements | |
| 838 | ||
| 839 | if !elements? then | |
| 840 | return | |
| 841 | fi | |
| 842 | ||
| 843 | let is_named_group = elements.count > 0 /\ elements[0].source_field_name? | |
| 844 | ||
| 845 | let field_names: Collections.List[string?]? mut = null | |
| 846 | if is_named_group then | |
| 847 | let names = Collections.LIST[string?]() | |
| 848 | for element in elements do | |
| 849 | // is_named_group: the parser enforces all-or-nothing | |
| 850 | // source field names per destructure group | |
| 851 | names.add(element.source_field_name!.name) | |
| 852 | od | |
| 853 | field_names = names | |
| 854 | fi | |
| 855 | ||
| 856 | let strategy = resolve_destructure_strategy(left.location, from_type, elements.count, field_names) | |
| 857 | ||
| 858 | if strategy.is_deconstruct then | |
| 859 | let deconstruct = strategy.deconstruct_function! | |
| 860 | ||
| 861 | for i in 0..elements.count do | |
| 862 | let element = elements[i] | |
| 863 | ||
| 864 | let element_type = deconstruct.arguments[i].get_element_type()! | |
| 865 | ||
| 866 | if element.is_simple_name then | |
| 867 | let symbol = find(element.name!) | |
| 868 | ||
| 869 | if symbol? /\ isa Semantic.Types.SettableTyped(symbol) then | |
| 870 | let typed_symbol = cast Semantic.Types.SettableTyped(symbol) | |
| 871 | ||
| 872 | symbol.define() | |
| 873 | ||
| 874 | typed_symbol.set_type(element_type) | |
| 875 | else | |
| 876 | _logger.error(element.location, "couldn't find typed symbol for destructuring element {element.name}") | |
| 877 | fi | |
| 878 | else | |
| 879 | set_symbol_destructure_types(element, element_type) | |
| 880 | fi | |
| 881 | od | |
| 882 | ||
| 883 | return | |
| 884 | fi | |
| 885 | ||
| 886 | let members = strategy.members | |
| 887 | ||
| 888 | for i in 0..elements.count do | |
| 889 | let element = elements[i] | |
| 890 | let member = members[i] | |
| 891 | ||
| 892 | if member? then | |
| 893 | let member_type = member.type | |
| 894 | ||
| 895 | if element.is_simple_name then | |
| 896 | let symbol = find(element.name!) | |
| 897 | ||
| 898 | if symbol? /\ isa Semantic.Types.SettableTyped(symbol) then | |
| 899 | let typed_symbol = cast Semantic.Types.SettableTyped(symbol) | |
| 900 | ||
| 901 | symbol.define() | |
| 902 | ||
| 903 | if member_type? then | |
| 904 | typed_symbol.set_type(member_type) | |
| 905 | fi | |
| 906 | else | |
| 907 | _logger.error(element.location, "couldn't find typed symbol for destructuring element {element.name}") | |
| 908 | fi | |
| 909 | elif member_type? then | |
| 910 | set_symbol_destructure_types(element, member_type) | |
| 911 | fi | |
| 912 | fi | |
| 913 | od | |
| 914 | si | |
| 915 | ||
| 916 | // TODO used by for loop - needs removing | |
| 917 | get_destructure_types(type: Type?) -> Collections.List[Type] is | |
| 918 | let result = Collections.LIST[Type]() | |
| 919 | ||
| 920 | if !type? \/ !type.is_value_tuple then | |
| 921 | return result | |
| 922 | fi | |
| 923 | ||
| 924 | get_destructure_types_into(type, result) | |
| 925 | ||
| 926 | return result | |
| 927 | si | |
| 928 | ||
| 929 | // TODO used by for loop - needs removing | |
| 930 | get_destructure_types_into(type: Type, into: Collections.MutableList[Type]) is | |
| 931 | let result = Collections.LIST[Type]() | |
| 932 | ||
| 933 | for t in type.arguments do | |
| 934 | if t.is_value_tuple then | |
| 935 | get_destructure_types_into(t, into) | |
| 936 | else | |
| 937 | into.add(t) | |
| 938 | fi | |
| 939 | od | |
| 940 | si | |
| 941 | ||
| 942 | si | |
| 943 | si |