Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use System.Exception; | |
| 3 | ||
| 4 | use Logging; | |
| 5 | ||
| 6 | use Semantic.LEAST_UPPER_BOUND_MAP; | |
| 7 | use Semantic.Types.Type; | |
| 8 | ||
| 9 | use IR.Values; | |
| 10 | use IR.VALUE_BOXER; | |
| 11 | ||
| 12 | use Ghul.Pipes; | |
| 13 | ||
| 14 | // Compiles tuple and list/array (`SEQUENCE`) literal expressions. | |
| 15 | // Split out of COMPILE_EXPRESSIONS, which delegates pre(tuple), | |
| 16 | // visit(tuple) and the inner sequence compile here. The | |
| 17 | // exception-handling and walk orchestration for visit(sequence) | |
| 18 | // stays on the visitor; visit_sequence is the enclosed logic. | |
| 19 | class COMPILE_TUPLES is | |
| 20 | _logger: Logger; | |
| 21 | _innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup; | |
| 22 | _value_boxer: VALUE_BOXER; | |
| 23 | _visitor: Syntax.Visitor; | |
| 24 | _placeholder_resolver: Semantic.SETTLED_PLACEHOLDER_RESOLVER; | |
| 25 | ||
| 26 | init( | |
| 27 | logger: Logger, | |
| 28 | innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup, | |
| 29 | value_boxer: VALUE_BOXER, | |
| 30 | visitor: Syntax.Visitor | |
| 31 | ) is | |
| 32 | super.init(); | |
| 33 | ||
| 34 | _logger = logger; | |
| 35 | _innate_symbol_lookup = innate_symbol_lookup; | |
| 36 | _value_boxer = value_boxer; | |
| 37 | _visitor = visitor; | |
| 38 | _placeholder_resolver = Semantic.SETTLED_PLACEHOLDER_RESOLVER(); | |
| 39 | si | |
| 40 | ||
| 41 | pre_tuple(tuple: Trees.Expressions.TUPLE) -> bool is | |
| 42 | if tuple.elements.expressions.count == 1 then | |
| 43 | // Single-element TUPLE is a parenthesised expression | |
| 44 | // (TUPLE.visit unwraps its value). Forward whatever | |
| 45 | // constraint applies to the outer expression directly | |
| 46 | // to the inner one — splitting a value-tuple constraint | |
| 47 | // across a phantom 1-tuple slot would push the wrong | |
| 48 | // element type down into the inner expression. | |
| 49 | if tuple.expected_type? then | |
| 50 | tuple.elements.expressions[0].set_expected_type(tuple.expected_type, tuple.expected_type_error_message); | |
| 51 | else | |
| 52 | tuple.elements.expressions[0].clear_expected_type(); | |
| 53 | fi | |
| 54 | elif let tuple.expected_type? /\ expected_type.is_value_tuple then | |
| 55 | for (element, type) in tuple.elements |> zip(expected_type.arguments) do | |
| 56 | element.set_expected_type(type, tuple.expected_type_error_message); | |
| 57 | od | |
| 58 | else | |
| 59 | for element in tuple.elements do | |
| 60 | element.clear_expected_type(); | |
| 61 | od | |
| 62 | fi | |
| 63 | ||
| 64 | return false; | |
| 65 | si | |
| 66 | ||
| 67 | visit_tuple(tuple: Trees.Expressions.TUPLE) is | |
| 68 | // A type ascription on a parenthesised group only means | |
| 69 | // something when the group turns out to be a lambda's | |
| 70 | // destructured parameter, which consumes it before any | |
| 71 | // value is compiled. Reaching here with one still attached | |
| 72 | // means the group is an ordinary tuple value, where the | |
| 73 | // ascription has no effect and would otherwise be dropped | |
| 74 | // in silence. | |
| 75 | if let tuple.type_expression? then | |
| 76 | _logger.error(type_expression.location, "type not allowed here"); | |
| 77 | fi | |
| 78 | ||
| 79 | let names: Collections.LIST[string]? mut = Collections.LIST[string](); | |
| 80 | let values = Collections.LIST[Value](); | |
| 81 | let types = Collections.LIST[Type](); | |
| 82 | ||
| 83 | let element_constraints: Collections.List[Type]? mut = null; | |
| 84 | let expected_type_error_message: string? mut = null; | |
| 85 | ||
| 86 | if let tuple.expected_type? /\ expected_type.is_value_tuple then | |
| 87 | element_constraints = expected_type.arguments; | |
| 88 | expected_type_error_message = tuple.expected_type_error_message; | |
| 89 | fi; | |
| 90 | ||
| 91 | if tuple.elements.expressions.count == 1 then | |
| 92 | // A single parenthesised element is a grouped expression, | |
| 93 | // not a tuple — there are no single-element tuples (a bare | |
| 94 | // `(x)` is just `x`). A named/typed sole element (`(x = 1)` | |
| 95 | // / `(x: int)`) is an attempt at one; report it rather than | |
| 96 | // collapsing to the element's unset value, which would | |
| 97 | // poison to ERROR and crash IL emission far downstream. | |
| 98 | if let element: Trees.Expressions.TUPLE_ELEMENT = tuple.elements.expressions[0] then | |
| 99 | _logger.error(element.location, "single-element tuples are not supported; a tuple needs two or more elements"); | |
| 100 | tuple.compile_expressions_state.value = IR.Values.DUMMY(Semantic.Types.ERROR(), tuple.location); | |
| 101 | else | |
| 102 | tuple.compile_expressions_state.value = tuple.elements.expressions[0].value; | |
| 103 | fi | |
| 104 | return; | |
| 105 | elif tuple.elements.expressions.count == 0 then | |
| 106 | tuple.compile_expressions_state.value = IR.Values.DUMMY(Semantic.Types.ERROR(), tuple.location); | |
| 107 | ||
| 108 | _logger.error(tuple.location, "empty tuple"); | |
| 109 | return; | |
| 110 | fi | |
| 111 | ||
| 112 | let seen_any_named mut = false; | |
| 113 | ||
| 114 | for (index, v) in tuple.elements |> index() do | |
| 115 | let element_type_constraint = | |
| 116 | if element_constraints? then | |
| 117 | element_constraints[index]; | |
| 118 | else | |
| 119 | null; | |
| 120 | fi; | |
| 121 | ||
| 122 | if isa Trees.Expressions.TUPLE_ELEMENT(v) then | |
| 123 | let element = v; | |
| 124 | ||
| 125 | seen_any_named = true; | |
| 126 | names.add(element.name.name); | |
| 127 | ||
| 128 | // An attribute pragma only makes sense on a lambda | |
| 129 | // parameter — reaching here means the parenthesised | |
| 130 | // list was never rewritten into one (no `->`/`=>`/ | |
| 131 | // `is`/`rec` followed), so this is a genuine tuple | |
| 132 | // literal instead. | |
| 133 | if element.pragmas? then | |
| 134 | for pragma in element.pragmas do | |
| 135 | _logger.error(pragma.location, "attribute is not allowed here"); | |
| 136 | od | |
| 137 | fi | |
| 138 | ||
| 139 | if element.initializer? then | |
| 140 | if Value.check_is_consumable(_logger, element.initializer.location, element.initializer.value) then | |
| 141 | if element.type_expression.type? then | |
| 142 | let expr_type = element.type_expression.type!; | |
| 143 | let type = | |
| 144 | if element_type_constraint? then | |
| 145 | element_type_constraint | |
| 146 | else | |
| 147 | expr_type | |
| 148 | fi; | |
| 149 | ||
| 150 | let init_value = element.initializer!.value!; | |
| 151 | ||
| 152 | if element.type_expression.check_is_not_reference(_logger, "tuple element cannot be a reference") then | |
| 153 | if !type.is_assignable_from(init_value.type!) then | |
| 154 | _logger.error(element.location, "{init_value.type} is not assignable to {type}"); | |
| 155 | elif element_type_constraint? /\ !element_type_constraint.is_assignable_from(expr_type) then | |
| 156 | _logger.error( | |
| 157 | element.type_expression.location, | |
| 158 | string.format(expected_type_error_message!, [expr_type, element_type_constraint]:object)); | |
| 159 | fi | |
| 160 | fi | |
| 161 | ||
| 162 | types.add(type); | |
| 163 | values.add(_value_boxer.box_if_needed(init_value, type)); | |
| 164 | ||
| 165 | elif element_type_constraint? then | |
| 166 | let type = element_type_constraint; | |
| 167 | let init_value = element.initializer!.value!; | |
| 168 | ||
| 169 | if !type.is_assignable_from(init_value.type!) then | |
| 170 | _logger.error( | |
| 171 | element.location, | |
| 172 | string.format(expected_type_error_message!, [init_value.type!, type]:object)); | |
| 173 | fi | |
| 174 | ||
| 175 | types.add(type); | |
| 176 | values.add(_value_boxer.box_if_needed(init_value, type)); | |
| 177 | else | |
| 178 | let init_value = element.initializer!.value!; | |
| 179 | types.add(init_value.type!); | |
| 180 | values.add(init_value); | |
| 181 | fi | |
| 182 | ||
| 183 | continue; | |
| 184 | fi | |
| 185 | else | |
| 186 | _logger.error(element.location, "tuple element must have a value"); | |
| 187 | fi | |
| 188 | ||
| 189 | values.add(IR.Values.DUMMY(Semantic.Types.ERROR(), element.location)); | |
| 190 | types.add(Semantic.Types.ERROR()); | |
| 191 | ||
| 192 | elif Value.check_is_consumable(_logger, v.location, v.value) then | |
| 193 | let v_value = v.value!; | |
| 194 | ||
| 195 | if v.is_identifier then | |
| 196 | // An unnamed element that is a plain identifier | |
| 197 | // takes its name from that identifier: `(a, b)` | |
| 198 | // is `(a = a, b = b)`. TUPLE_ELEMENT_NAME owns | |
| 199 | // the underscore-strip corner cases. | |
| 200 | let identifier_name = v.try_copy_as_identifer()!.name; | |
| 201 | let is_field_symbol = | |
| 202 | isa IR.Values.Load.SYMBOL(v_value) /\ | |
| 203 | v_value.has_symbol /\ | |
| 204 | v_value.symbol.is_field; | |
| 205 | ||
| 206 | names.add(TUPLE_ELEMENT_NAME.infer(identifier_name, is_field_symbol)); | |
| 207 | seen_any_named = true; | |
| 208 | else | |
| 209 | names.add("{index}"); | |
| 210 | fi | |
| 211 | ||
| 212 | if element_type_constraint? then | |
| 213 | let type = element_type_constraint; | |
| 214 | ||
| 215 | if !type.is_assignable_from(v_value.type!) then | |
| 216 | _logger.error( | |
| 217 | v.location, | |
| 218 | string.format(expected_type_error_message!, [v_value.type!, type]:object)); | |
| 219 | fi | |
| 220 | ||
| 221 | types.add(type); | |
| 222 | values.add(_value_boxer.box_if_needed(v_value, type)); | |
| 223 | else | |
| 224 | types.add(v_value.type!); | |
| 225 | values.add(v_value); | |
| 226 | fi | |
| 227 | else | |
| 228 | values.add(IR.Values.DUMMY(Semantic.Types.ERROR(), v.location)); | |
| 229 | types.add(Semantic.Types.ERROR()); | |
| 230 | fi | |
| 231 | ||
| 232 | debug_unindent(); | |
| 233 | od | |
| 234 | ||
| 235 | if !seen_any_named then | |
| 236 | names = null; | |
| 237 | fi | |
| 238 | ||
| 239 | let type = _innate_symbol_lookup.get_tuple_type(_placeholder_resolver.resolve_all(types), names); | |
| 240 | tuple.compile_expressions_state.value = TUPLE(type, values); | |
| 241 | si | |
| 242 | ||
| 243 | visit_sequence(sequence: Trees.Expressions.SEQUENCE) is | |
| 244 | let type: Type? mut = _; | |
| 245 | let have_explicit_type: bool mut = _; | |
| 246 | ||
| 247 | let elements = Collections.LIST[Trees.Expressions.Expression](sequence.elements); | |
| 248 | ||
| 249 | let constraint_type: Type? mut = _; | |
| 250 | if let sequence.expected_type? then | |
| 251 | constraint_type = expected_type.get_element_type(); | |
| 252 | fi | |
| 253 | ||
| 254 | if !isa Trees.TypeExpressions.INFER(sequence.type_expression) then | |
| 255 | if sequence.type_expression.type? then | |
| 256 | type = sequence.type_expression.type; | |
| 257 | ||
| 258 | have_explicit_type = true; | |
| 259 | else | |
| 260 | // FIXME probably not needed - type pass will have given an error | |
| 261 | _logger.error(sequence.type_expression.location, "bad explicit type expression"); | |
| 262 | return; | |
| 263 | fi | |
| 264 | elif elements.count == 0 then | |
| 265 | if constraint_type? then | |
| 266 | type = constraint_type; | |
| 267 | have_explicit_type = true; | |
| 268 | else | |
| 269 | // No elements to infer from and no constraint pushed by | |
| 270 | // the surrounding context: fall back to an object | |
| 271 | // element type, the same as a literal whose elements | |
| 272 | // are all null. | |
| 273 | _logger.hint(sequence.location, "infer-object-from-list-literal", "specify explicit list literal type to avoid inferring object type here"); | |
| 274 | ||
| 275 | type = _innate_symbol_lookup.get_object_type(); | |
| 276 | fi | |
| 277 | else | |
| 278 | let seen_any mut = false; | |
| 279 | let seen_error mut = false; | |
| 280 | let all_tuple_literals mut = elements.count > 0; // assume all tuples until proved otherwise | |
| 281 | let tuples_element_count mut = -1; | |
| 282 | let lub = LEAST_UPPER_BOUND_MAP(); | |
| 283 | ||
| 284 | for v in elements do | |
| 285 | if !v.is_tuple_literal then | |
| 286 | all_tuple_literals = false; | |
| 287 | fi | |
| 288 | ||
| 289 | if let v.value? /\ value.type? then | |
| 290 | if value.check_is_consumable(_logger, v.location) then | |
| 291 | if !value.type!.is_null then | |
| 292 | seen_any = true; | |
| 293 | lub.add(value.type!); | |
| 294 | elif value.type!.is_error then | |
| 295 | seen_error = true; | |
| 296 | fi | |
| 297 | ||
| 298 | if v.is_tuple_literal then | |
| 299 | if tuples_element_count == -1 then | |
| 300 | tuples_element_count = value.type!.arguments.count; | |
| 301 | elif value.type!.arguments.count != tuples_element_count then | |
| 302 | all_tuple_literals = false; | |
| 303 | fi | |
| 304 | fi | |
| 305 | else | |
| 306 | seen_error = true; | |
| 307 | fi | |
| 308 | else | |
| 309 | seen_error = true; | |
| 310 | fi | |
| 311 | od | |
| 312 | ||
| 313 | if !type? then | |
| 314 | type = lub.get_result(); | |
| 315 | ||
| 316 | if all_tuple_literals /\ (!type? \/ !type.is_value_tuple) then | |
| 317 | let tuple_types = Collections.LIST[Type](); | |
| 318 | ||
| 319 | for element in elements do | |
| 320 | if let element.value? /\ value.type? then | |
| 321 | tuple_types.add(value.type!); | |
| 322 | fi | |
| 323 | od | |
| 324 | ||
| 325 | type = Semantic.TUPLE_ELEMENT_LUB(_innate_symbol_lookup).combine(tuple_types, lub.element_names); | |
| 326 | ||
| 327 | // going to walk the elements again, so roll back | |
| 328 | // and re-speculate to avoid duplicate / misleading | |
| 329 | // error messages | |
| 330 | _logger.roll_back(); | |
| 331 | _logger.speculate(); | |
| 332 | ||
| 333 | // re-walk the type expression if present, to avoid | |
| 334 | // hiding any error message it may generate | |
| 335 | ||
| 336 | sequence.type_expression.walk(_visitor); | |
| 337 | ||
| 338 | for e in sequence.elements do | |
| 339 | e.set_expected_type(type, "element type {{0}} not compatible with inferred list type {{1}}"); | |
| 340 | e.walk(_visitor); | |
| 341 | od | |
| 342 | fi | |
| 343 | fi | |
| 344 | ||
| 345 | // Reconcile bottom-up LUB with any constraint pushed | |
| 346 | // by the parent context. Prefer the more-specific | |
| 347 | // bottom-up type when it satisfies the constraint — | |
| 348 | // that preserves the runtime allocation precision the | |
| 349 | // covariance idiom relies on (e.g. `let ao: object[] | |
| 350 | // = ["a", "b"];` should produce a string[] at run | |
| 351 | // time, even though the variable is declared | |
| 352 | // object[]). When the LUB doesn't satisfy the | |
| 353 | // constraint, fall back to the constraint's element | |
| 354 | // type and drive per-element mismatch errors via the | |
| 355 | // post-walk assignability check. | |
| 356 | if constraint_type? then | |
| 357 | if !type? \/ !constraint_type.is_assignable_from(type) then | |
| 358 | type = constraint_type; | |
| 359 | have_explicit_type = true; | |
| 360 | fi | |
| 361 | fi | |
| 362 | ||
| 363 | if !type? then | |
| 364 | if seen_error then | |
| 365 | sequence.compile_expressions_state.value = DUMMY(_innate_symbol_lookup.get_array_type(Semantic.Types.ERROR()), sequence.location); | |
| 366 | return; | |
| 367 | elif seen_any then | |
| 368 | _logger.hint(sequence.location, "specify explicit list literal type to avoid inferring object type here"); | |
| 369 | type = _innate_symbol_lookup.get_object_type(); | |
| 370 | else | |
| 371 | _logger.error(sequence.location, "cannot infer type of list literal with only null elements"); | |
| 372 | ||
| 373 | sequence.compile_expressions_state.value = DUMMY(_innate_symbol_lookup.get_array_type(Semantic.Types.ERROR()), sequence.location); | |
| 374 | return; | |
| 375 | fi | |
| 376 | fi | |
| 377 | fi | |
| 378 | ||
| 379 | let values = Collections.LIST[Value](sequence.elements.expressions.count); | |
| 380 | ||
| 381 | for v in sequence.elements do | |
| 382 | if let v.value? /\ value.type? then | |
| 383 | let u = value.type; | |
| 384 | ||
| 385 | // FIXME should push explicit type into element as constraint and retry | |
| 386 | if have_explicit_type /\ !type!.is_assignable_from(value.type!) then | |
| 387 | _logger.error(v.location, "element not compatible with explicit type"); | |
| 388 | fi | |
| 389 | ||
| 390 | values.add(v.value!); | |
| 391 | else | |
| 392 | values.add(DUMMY(Semantic.Types.ERROR(), v.location)); | |
| 393 | fi | |
| 394 | od | |
| 395 | ||
| 396 | sequence.compile_expressions_state.value = | |
| 397 | SEQUENCE(_innate_symbol_lookup.get_array_type(type!), type, values); | |
| 398 | si | |
| 399 | si | |
| 400 | si |