| ... | ... | @@ -59,6 +59,8 @@ pub const ResultLoc = union(enum) { |
| 59 | 59 | |
| 60 | 60 | pub fn typeExpr(mod: *Module, scope: *Scope, type_node: ast.Node.Index) InnerError!*zir.Inst { |
| 61 | 61 | const tree = scope.tree(); |
| 62 | const token_starts = tree.tokens.items(.start); |
| 63 | |
| 62 | 64 | const type_src = token_starts[tree.firstToken(type_node)]; |
| 63 | 65 | const type_type = try addZIRInstConst(mod, scope, type_src, .{ |
| 64 | 66 | .ty = Type.initTag(.type), |
| ... | ... | @@ -76,13 +78,17 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.I |
| 76 | 78 | .root => unreachable, |
| 77 | 79 | .@"usingnamespace" => unreachable, |
| 78 | 80 | .test_decl => unreachable, |
| 79 | | .doc_comment => unreachable, |
| 80 | | .var_decl => unreachable, |
| 81 | .global_var_decl => unreachable, |
| 82 | .local_var_decl => unreachable, |
| 83 | .simple_var_decl => unreachable, |
| 84 | .aligned_var_decl => unreachable, |
| 81 | 85 | .switch_case => unreachable, |
| 82 | | .switch_else => unreachable, |
| 86 | .switch_case_one => unreachable, |
| 83 | 87 | .container_field_init => unreachable, |
| 84 | 88 | .container_field_align => unreachable, |
| 85 | 89 | .container_field => unreachable, |
| 90 | .asm_output => unreachable, |
| 91 | .asm_input => unreachable, |
| 86 | 92 | |
| 87 | 93 | .assign, |
| 88 | 94 | .assign_bit_and, |
| ... | ... | @@ -122,58 +128,107 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.I |
| 122 | 128 | .bool_and, |
| 123 | 129 | .bool_or, |
| 124 | 130 | .@"asm", |
| 131 | .asm_simple, |
| 125 | 132 | .string_literal, |
| 126 | 133 | .integer_literal, |
| 127 | 134 | .call, |
| 128 | | .@"unreachable", |
| 135 | .call_comma, |
| 136 | .async_call, |
| 137 | .async_call_comma, |
| 138 | .call_one, |
| 139 | .call_one_comma, |
| 140 | .async_call_one, |
| 141 | .async_call_one_comma, |
| 142 | .unreachable_literal, |
| 129 | 143 | .@"return", |
| 130 | 144 | .@"if", |
| 145 | .if_simple, |
| 131 | 146 | .@"while", |
| 147 | .while_simple, |
| 148 | .while_cont, |
| 132 | 149 | .bool_not, |
| 133 | 150 | .address_of, |
| 134 | 151 | .float_literal, |
| 135 | 152 | .undefined_literal, |
| 136 | | .bool_literal, |
| 153 | .true_literal, |
| 154 | .false_literal, |
| 137 | 155 | .null_literal, |
| 138 | 156 | .optional_type, |
| 139 | 157 | .block, |
| 140 | | .labeled_block, |
| 158 | .block_semicolon, |
| 159 | .block_two, |
| 160 | .block_two_semicolon, |
| 141 | 161 | .@"break", |
| 142 | | .PtrType, |
| 162 | .ptr_type_aligned, |
| 163 | .ptr_type_sentinel, |
| 164 | .ptr_type, |
| 165 | .ptr_type_bit_range, |
| 143 | 166 | .array_type, |
| 144 | 167 | .array_type_sentinel, |
| 145 | 168 | .enum_literal, |
| 146 | | .MultilineStringLiteral, |
| 169 | .multiline_string_literal, |
| 147 | 170 | .char_literal, |
| 148 | 171 | .@"defer", |
| 172 | .@"errdefer", |
| 149 | 173 | .@"catch", |
| 150 | 174 | .error_union, |
| 151 | 175 | .merge_error_sets, |
| 152 | | .range, |
| 176 | .switch_range, |
| 153 | 177 | .@"await", |
| 154 | 178 | .bit_not, |
| 155 | 179 | .negation, |
| 156 | 180 | .negation_wrap, |
| 157 | 181 | .@"resume", |
| 158 | 182 | .@"try", |
| 159 | | .slice_type, |
| 160 | 183 | .slice, |
| 161 | | .ArrayInitializer, |
| 162 | | .ArrayInitializerDot, |
| 163 | | .StructInitializer, |
| 164 | | .StructInitializerDot, |
| 184 | .slice_open, |
| 185 | .slice_sentinel, |
| 186 | .array_init_one, |
| 187 | .array_init_one_comma, |
| 188 | .array_init_dot_two, |
| 189 | .array_init_dot_two_comma, |
| 190 | .array_init_dot, |
| 191 | .array_init_dot_comma, |
| 192 | .array_init, |
| 193 | .array_init_comma, |
| 194 | .struct_init_one, |
| 195 | .struct_init_one_comma, |
| 196 | .struct_init_dot_two, |
| 197 | .struct_init_dot_two_comma, |
| 198 | .struct_init_dot, |
| 199 | .struct_init_dot_comma, |
| 200 | .struct_init, |
| 201 | .struct_init_comma, |
| 165 | 202 | .@"switch", |
| 203 | .switch_comma, |
| 166 | 204 | .@"for", |
| 205 | .for_simple, |
| 167 | 206 | .@"suspend", |
| 168 | 207 | .@"continue", |
| 169 | 208 | .@"anytype", |
| 170 | | .error_type, |
| 171 | | .FnProto, |
| 209 | .fn_proto_simple, |
| 210 | .fn_proto_multi, |
| 211 | .fn_proto_one, |
| 212 | .fn_proto, |
| 213 | .fn_decl, |
| 172 | 214 | .anyframe_type, |
| 215 | .anyframe_literal, |
| 173 | 216 | .error_set_decl, |
| 174 | | .ContainerDecl, |
| 217 | .container_decl, |
| 218 | .container_decl_comma, |
| 219 | .container_decl_two, |
| 220 | .container_decl_two_comma, |
| 221 | .container_decl_arg, |
| 222 | .container_decl_arg_comma, |
| 223 | .tagged_union, |
| 224 | .tagged_union_comma, |
| 225 | .tagged_union_two, |
| 226 | .tagged_union_two_comma, |
| 227 | .tagged_union_enum_tag, |
| 228 | .tagged_union_enum_tag_comma, |
| 175 | 229 | .@"comptime", |
| 176 | 230 | .@"nosuspend", |
| 231 | .error_value, |
| 177 | 232 | => return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}), |
| 178 | 233 | |
| 179 | 234 | .builtin_call, |
| ... | ... | @@ -192,10 +247,10 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.I |
| 192 | 247 | } |
| 193 | 248 | }, |
| 194 | 249 | |
| 195 | | // can be assigned to |
| 250 | // These can be assigned to. |
| 196 | 251 | .unwrap_optional, |
| 197 | 252 | .deref, |
| 198 | | .period, |
| 253 | .field_access, |
| 199 | 254 | .array_access, |
| 200 | 255 | .identifier, |
| 201 | 256 | .grouped_expression, |
| ... | ... | @@ -210,22 +265,33 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.I |
| 210 | 265 | /// result instruction can be used to inspect whether it is isNoReturn() but that is it, |
| 211 | 266 | /// it must otherwise not be used. |
| 212 | 267 | pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!*zir.Inst { |
| 213 | | switch (node.tag) { |
| 268 | const tree = scope.tree(); |
| 269 | const main_tokens = tree.nodes.items(.main_token); |
| 270 | const token_tags = tree.tokens.items(.tag); |
| 271 | const node_datas = tree.nodes.items(.data); |
| 272 | const node_tags = tree.nodes.items(.tag); |
| 273 | const token_starts = tree.tokens.items(.start); |
| 274 | |
| 275 | switch (node_tags[node]) { |
| 214 | 276 | .root => unreachable, // Top-level declaration. |
| 215 | 277 | .@"usingnamespace" => unreachable, // Top-level declaration. |
| 216 | 278 | .test_decl => unreachable, // Top-level declaration. |
| 217 | | .doc_comment => unreachable, // Top-level declaration. |
| 218 | | .var_decl => unreachable, // Handled in `blockExpr`. |
| 279 | .container_field_init => unreachable, // Top-level declaration. |
| 280 | .container_field_align => unreachable, // Top-level declaration. |
| 281 | .container_field => unreachable, // Top-level declaration. |
| 282 | .fn_decl => unreachable, // Top-level declaration. |
| 283 | |
| 284 | .global_var_decl => unreachable, // Handled in `blockExpr`. |
| 285 | .local_var_decl => unreachable, // Handled in `blockExpr`. |
| 286 | .simple_var_decl => unreachable, // Handled in `blockExpr`. |
| 287 | .aligned_var_decl => unreachable, // Handled in `blockExpr`. |
| 288 | |
| 219 | 289 | .switch_case => unreachable, // Handled in `switchExpr`. |
| 220 | | .switch_else => unreachable, // Handled in `switchExpr`. |
| 221 | | .range => unreachable, // Handled in `switchExpr`. |
| 222 | | .Else => unreachable, // Handled explicitly the control flow expression functions. |
| 223 | | .Payload => unreachable, // Handled explicitly. |
| 224 | | .PointerPayload => unreachable, // Handled explicitly. |
| 225 | | .PointerIndexPayload => unreachable, // Handled explicitly. |
| 226 | | .ErrorTag => unreachable, // Handled explicitly. |
| 227 | | .FieldInitializer => unreachable, // Handled explicitly. |
| 228 | | .ContainerField => unreachable, // Handled explicitly. |
| 290 | .switch_case_one => unreachable, // Handled in `switchExpr`. |
| 291 | .switch_range => unreachable, // Handled in `switchExpr`. |
| 292 | |
| 293 | .asm_output => unreachable, // Handled in `asmExpr`. |
| 294 | .asm_input => unreachable, // Handled in `asmExpr`. |
| 229 | 295 | |
| 230 | 296 | .assign => return rvalueVoid(mod, scope, rl, node, try assign(mod, scope, node)), |
| 231 | 297 | .assign_bit_and => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .bit_and)), |
| ... | ... | @@ -276,30 +342,28 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In |
| 276 | 342 | |
| 277 | 343 | .identifier => return identifier(mod, scope, rl, node), |
| 278 | 344 | |
| 279 | | .asm_simple => return assembly(mod, scope, rl, tree.asmSimple(node)), |
| 280 | | .@"asm" => return assembly(mod, scope, rl, tree.asmFull(node)), |
| 345 | .asm_simple => return asmExpr(mod, scope, rl, tree.asmSimple(node)), |
| 346 | .@"asm" => return asmExpr(mod, scope, rl, tree.asmFull(node)), |
| 281 | 347 | |
| 282 | 348 | .string_literal => return stringLiteral(mod, scope, rl, node), |
| 283 | 349 | .multiline_string_literal => return multilineStringLiteral(mod, scope, rl, node), |
| 284 | 350 | |
| 285 | 351 | .integer_literal => return integerLiteral(mod, scope, rl, node), |
| 286 | 352 | |
| 287 | | .builtin_call => return builtinCall(mod, scope, rl, node), |
| 288 | | |
| 289 | 353 | .builtin_call_two, .builtin_call_two_comma => { |
| 290 | | if (datas[node].lhs == 0) { |
| 354 | if (node_datas[node].lhs == 0) { |
| 291 | 355 | const params = [_]ast.Node.Index{}; |
| 292 | 356 | return builtinCall(mod, scope, rl, node, &params); |
| 293 | | } else if (datas[node].rhs == 0) { |
| 294 | | const params = [_]ast.Node.Index{datas[node].lhs}; |
| 357 | } else if (node_datas[node].rhs == 0) { |
| 358 | const params = [_]ast.Node.Index{node_datas[node].lhs}; |
| 295 | 359 | return builtinCall(mod, scope, rl, node, &params); |
| 296 | 360 | } else { |
| 297 | | const params = [_]ast.Node.Index{ datas[node].lhs, datas[node].rhs }; |
| 361 | const params = [_]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; |
| 298 | 362 | return builtinCall(mod, scope, rl, node, &params); |
| 299 | 363 | } |
| 300 | 364 | }, |
| 301 | 365 | .builtin_call, .builtin_call_comma => { |
| 302 | | const params = tree.extra_data[datas[node].lhs..datas[node].rhs]; |
| 366 | const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; |
| 303 | 367 | return builtinCall(mod, scope, rl, node, params); |
| 304 | 368 | }, |
| 305 | 369 | |
| ... | ... | @@ -311,20 +375,20 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In |
| 311 | 375 | return callExpr(mod, scope, rl, tree.callFull(node)); |
| 312 | 376 | }, |
| 313 | 377 | |
| 314 | | .@"unreachable" => { |
| 378 | .unreachable_literal => { |
| 315 | 379 | const main_token = main_tokens[node]; |
| 316 | 380 | const src = token_starts[main_token]; |
| 317 | 381 | return addZIRNoOp(mod, scope, src, .unreachable_safe); |
| 318 | 382 | }, |
| 319 | 383 | .@"return" => return ret(mod, scope, node), |
| 320 | | .period => return field(mod, scope, rl, node), |
| 384 | .field_access => return field(mod, scope, rl, node), |
| 321 | 385 | .float_literal => return floatLiteral(mod, scope, rl, node), |
| 322 | 386 | |
| 323 | 387 | .if_simple => return ifExpr(mod, scope, rl, tree.ifSimple(node)), |
| 324 | | .@"if" => return ifExpr(mode, scope, rl, tree.ifFull(node)), |
| 388 | .@"if" => return ifExpr(mod, scope, rl, tree.ifFull(node)), |
| 325 | 389 | |
| 326 | 390 | .while_simple => return whileExpr(mod, scope, rl, tree.whileSimple(node)), |
| 327 | | .while_cont => return whileExpr(mod, scope, tree.whileCont(node)), |
| 391 | .while_cont => return whileExpr(mod, scope, rl, tree.whileCont(node)), |
| 328 | 392 | .@"while" => return whileExpr(mod, scope, rl, tree.whileFull(node)), |
| 329 | 393 | |
| 330 | 394 | .for_simple => return forExpr(mod, scope, rl, tree.forSimple(node)), |
| ... | ... | @@ -389,7 +453,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In |
| 389 | 453 | return rvalue(mod, scope, rl, result); |
| 390 | 454 | }, |
| 391 | 455 | .unwrap_optional => { |
| 392 | | const operand = try expr(mod, scope, rl, node.lhs); |
| 456 | const operand = try expr(mod, scope, rl, node_datas[node].lhs); |
| 393 | 457 | const op: zir.Inst.Tag = switch (rl) { |
| 394 | 458 | .ref => .optional_payload_safe_ptr, |
| 395 | 459 | else => .optional_payload_safe, |
| ... | ... | @@ -449,7 +513,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In |
| 449 | 513 | }, |
| 450 | 514 | .@"catch" => { |
| 451 | 515 | const catch_token = main_tokens[node]; |
| 452 | | const payload_token: ?TokenIndex = if (token_tags[catch_token + 1] == .pipe) |
| 516 | const payload_token: ?ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) |
| 453 | 517 | catch_token + 2 |
| 454 | 518 | else |
| 455 | 519 | null; |
| ... | ... | @@ -506,6 +570,34 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In |
| 506 | 570 | null, |
| 507 | 571 | ), |
| 508 | 572 | }, |
| 573 | |
| 574 | .ptr_type_aligned => return ptrType(mod, scope, rl, tree.ptrTypeAligned(node)), |
| 575 | .ptr_type_sentinel => return ptrType(mod, scope, rl, tree.ptrTypeSentinel(node)), |
| 576 | .ptr_type => return ptrType(mod, scope, rl, tree.ptrType(node)), |
| 577 | .ptr_type_bit_range => return ptrType(mod, scope, rl, tree.ptrTypeBitRange(node)), |
| 578 | |
| 579 | .container_decl, |
| 580 | .container_decl_comma, |
| 581 | => return containerDecl(mod, scope, rl, tree.containerDecl(node)), |
| 582 | .container_decl_two, .container_decl_two_comma => { |
| 583 | var buffer: [2]ast.Node.Index = undefined; |
| 584 | return containerDecl(mod, scope, rl, tree.containerDeclTwo(&buffer, node)); |
| 585 | }, |
| 586 | .container_decl_arg, |
| 587 | .container_decl_arg_comma, |
| 588 | => return containerDecl(mod, scope, rl, tree.containerDeclArg(node)), |
| 589 | |
| 590 | .tagged_union, |
| 591 | .tagged_union_comma, |
| 592 | => return containerDecl(mod, scope, rl, tree.taggedUnion(node)), |
| 593 | .tagged_union_two, .tagged_union_two_comma => { |
| 594 | var buffer: [2]ast.Node.Index = undefined; |
| 595 | return containerDecl(mod, scope, rl, tree.taggedUnionTwo(&buffer, node)); |
| 596 | }, |
| 597 | .tagged_union_enum_tag, |
| 598 | .tagged_union_enum_tag_comma, |
| 599 | => return containerDecl(mod, scope, rl, tree.taggedUnionEnumTag(node)), |
| 600 | |
| 509 | 601 | .@"break" => return breakExpr(mod, scope, rl, node), |
| 510 | 602 | .@"continue" => return continueExpr(mod, scope, rl, node), |
| 511 | 603 | .grouped_expression => return expr(mod, scope, rl, node_datas[node].lhs), |
| ... | ... | @@ -518,12 +610,41 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In |
| 518 | 610 | .@"switch", .switch_comma => return switchExpr(mod, scope, rl, node), |
| 519 | 611 | |
| 520 | 612 | .@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}), |
| 613 | .@"errdefer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .errdefer", .{}), |
| 521 | 614 | .@"await" => return mod.failNode(scope, node, "TODO implement astgen.expr for .await", .{}), |
| 522 | 615 | .@"resume" => return mod.failNode(scope, node, "TODO implement astgen.expr for .resume", .{}), |
| 523 | 616 | .@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), |
| 617 | |
| 618 | .array_init_one, |
| 619 | .array_init_one_comma, |
| 620 | .array_init_dot_two, |
| 621 | .array_init_dot_two_comma, |
| 622 | .array_init_dot, |
| 623 | .array_init_dot_comma, |
| 624 | .array_init, |
| 625 | .array_init_comma, |
| 626 | => return mod.failNode(scope, node, "TODO implement astgen.expr for array literals", .{}), |
| 627 | |
| 628 | .struct_init_one, |
| 629 | .struct_init_one_comma, |
| 630 | .struct_init_dot_two, |
| 631 | .struct_init_dot_two_comma, |
| 632 | .struct_init_dot, |
| 633 | .struct_init_dot_comma, |
| 634 | .struct_init, |
| 635 | .struct_init_comma, |
| 636 | => return mod.failNode(scope, node, "TODO implement astgen.expr for struct literals", .{}), |
| 637 | |
| 524 | 638 | .@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}), |
| 525 | 639 | .@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}), |
| 640 | .fn_proto_simple, |
| 641 | .fn_proto_multi, |
| 642 | .fn_proto_one, |
| 643 | .fn_proto, |
| 644 | => return mod.failNode(scope, node, "TODO implement astgen.expr for function prototypes", .{}), |
| 645 | |
| 526 | 646 | .@"nosuspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .nosuspend", .{}), |
| 647 | .error_value => return mod.failNode(scope, node, "TODO implement astgen.expr for .error_value", .{}), |
| 527 | 648 | } |
| 528 | 649 | } |
| 529 | 650 | |
| ... | ... | @@ -572,6 +693,8 @@ fn breakExpr( |
| 572 | 693 | const tree = parent_scope.tree(); |
| 573 | 694 | const node_datas = tree.nodes.items(.data); |
| 574 | 695 | const main_tokens = tree.nodes.items(.main_token); |
| 696 | const token_starts = tree.tokens.items(.start); |
| 697 | |
| 575 | 698 | const src = token_starts[main_tokens[node]]; |
| 576 | 699 | const break_label = node_datas[node].lhs; |
| 577 | 700 | const rhs = node_datas[node].rhs; |
| ... | ... | @@ -646,6 +769,8 @@ fn continueExpr( |
| 646 | 769 | const tree = parent_scope.tree(); |
| 647 | 770 | const node_datas = tree.nodes.items(.data); |
| 648 | 771 | const main_tokens = tree.nodes.items(.main_token); |
| 772 | const token_starts = tree.tokens.items(.start); |
| 773 | |
| 649 | 774 | const src = token_starts[main_tokens[node]]; |
| 650 | 775 | const break_label = node_datas[node].lhs; |
| 651 | 776 | |
| ... | ... | @@ -702,7 +827,7 @@ pub fn blockExpr( |
| 702 | 827 | const main_tokens = tree.nodes.items(.main_token); |
| 703 | 828 | const token_tags = tree.tokens.items(.tag); |
| 704 | 829 | |
| 705 | | const lbrace = main_tokens[node]; |
| 830 | const lbrace = main_tokens[block_node]; |
| 706 | 831 | if (token_tags[lbrace - 1] == .colon) { |
| 707 | 832 | return labeledBlockExpr(mod, scope, rl, block_node, statements, .block); |
| 708 | 833 | } |
| ... | ... | @@ -721,8 +846,9 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn |
| 721 | 846 | if (gen_zir.label) |prev_label| { |
| 722 | 847 | if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) { |
| 723 | 848 | const tree = parent_scope.tree(); |
| 724 | | const node_datas = tree.nodes.items(.data); |
| 725 | 849 | const main_tokens = tree.nodes.items(.main_token); |
| 850 | const token_starts = tree.tokens.items(.start); |
| 851 | |
| 726 | 852 | const label_src = token_starts[label]; |
| 727 | 853 | const prev_label_src = token_starts[prev_label.token]; |
| 728 | 854 | |
| ... | ... | @@ -770,9 +896,9 @@ fn labeledBlockExpr( |
| 770 | 896 | assert(zir_tag == .block or zir_tag == .block_comptime); |
| 771 | 897 | |
| 772 | 898 | const tree = parent_scope.tree(); |
| 773 | | const node_datas = tree.nodes.items(.data); |
| 774 | 899 | const main_tokens = tree.nodes.items(.main_token); |
| 775 | 900 | const token_starts = tree.tokens.items(.start); |
| 901 | const token_tags = tree.tokens.items(.tag); |
| 776 | 902 | |
| 777 | 903 | const lbrace = main_tokens[block_node]; |
| 778 | 904 | const label_token = lbrace - 1; |
| ... | ... | @@ -813,10 +939,10 @@ fn labeledBlockExpr( |
| 813 | 939 | defer block_scope.labeled_breaks.deinit(mod.gpa); |
| 814 | 940 | defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa); |
| 815 | 941 | |
| 816 | | try blockExprStmts(mod, &block_scope.base, block_node, block_node.statements()); |
| 942 | try blockExprStmts(mod, &block_scope.base, block_node, statements); |
| 817 | 943 | |
| 818 | 944 | if (!block_scope.label.?.used) { |
| 819 | | return mod.fail(parent_scope, token_starts[block_node.label], "unused block label", .{}); |
| 945 | return mod.failTok(parent_scope, label_token, "unused block label", .{}); |
| 820 | 946 | } |
| 821 | 947 | |
| 822 | 948 | try gen_zir.instructions.append(mod.gpa, &block_inst.base); |
| ... | ... | @@ -860,21 +986,23 @@ fn blockExprStmts( |
| 860 | 986 | statements: []const ast.Node.Index, |
| 861 | 987 | ) !void { |
| 862 | 988 | const tree = parent_scope.tree(); |
| 863 | | const node_datas = tree.nodes.items(.data); |
| 864 | 989 | const main_tokens = tree.nodes.items(.main_token); |
| 990 | const token_starts = tree.tokens.items(.start); |
| 991 | const node_tags = tree.nodes.items(.tag); |
| 865 | 992 | |
| 866 | 993 | var block_arena = std.heap.ArenaAllocator.init(mod.gpa); |
| 867 | 994 | defer block_arena.deinit(); |
| 868 | 995 | |
| 869 | 996 | var scope = parent_scope; |
| 870 | 997 | for (statements) |statement| { |
| 871 | | const src = token_starts[statement.firstToken()]; |
| 998 | const src = token_starts[tree.firstToken(statement)]; |
| 872 | 999 | _ = try addZIRNoOp(mod, scope, src, .dbg_stmt); |
| 873 | | switch (statement.tag) { |
| 874 | | .var_decl => { |
| 875 | | const var_decl_node = statement.castTag(.var_decl).?; |
| 876 | | scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator); |
| 877 | | }, |
| 1000 | switch (node_tags[statement]) { |
| 1001 | .global_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.globalVarDecl(statement)), |
| 1002 | .local_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.localVarDecl(statement)), |
| 1003 | .simple_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.simpleVarDecl(statement)), |
| 1004 | .aligned_var_decl => scope = try varDecl(mod, scope, &block_arena.allocator, tree.alignedVarDecl(statement)), |
| 1005 | |
| 878 | 1006 | .assign => try assign(mod, scope, statement), |
| 879 | 1007 | .assign_bit_and => try assignOp(mod, scope, statement, .bit_and), |
| 880 | 1008 | .assign_bit_or => try assignOp(mod, scope, statement, .bit_or), |
| ... | ... | @@ -903,20 +1031,23 @@ fn blockExprStmts( |
| 903 | 1031 | fn varDecl( |
| 904 | 1032 | mod: *Module, |
| 905 | 1033 | scope: *Scope, |
| 906 | | node: *ast.Node.var_decl, |
| 907 | 1034 | block_arena: *Allocator, |
| 1035 | var_decl: ast.full.VarDecl, |
| 908 | 1036 | ) InnerError!*Scope { |
| 909 | | if (node.getComptimeToken()) |comptime_token| { |
| 1037 | if (var_decl.comptime_token) |comptime_token| { |
| 910 | 1038 | return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{}); |
| 911 | 1039 | } |
| 912 | | if (node.getAlignNode()) |align_node| { |
| 913 | | return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{}); |
| 1040 | if (var_decl.ast.align_node != 0) { |
| 1041 | return mod.failNode(scope, var_decl.ast.align_node, "TODO implement alignment on locals", .{}); |
| 914 | 1042 | } |
| 915 | 1043 | const tree = scope.tree(); |
| 916 | | const node_datas = tree.nodes.items(.data); |
| 917 | 1044 | const main_tokens = tree.nodes.items(.main_token); |
| 918 | | const name_src = token_starts[node.name_token]; |
| 919 | | const ident_name = try mod.identifierTokenString(scope, node.name_token); |
| 1045 | const token_starts = tree.tokens.items(.start); |
| 1046 | const token_tags = tree.tokens.items(.tag); |
| 1047 | |
| 1048 | const name_token = var_decl.ast.mut_token + 1; |
| 1049 | const name_src = token_starts[name_token]; |
| 1050 | const ident_name = try mod.identifierTokenString(scope, name_token); |
| 920 | 1051 | |
| 921 | 1052 | // Local variables shadowing detection, including function parameters. |
| 922 | 1053 | { |
| ... | ... | @@ -962,20 +1093,21 @@ fn varDecl( |
| 962 | 1093 | // TODO add note for other definition |
| 963 | 1094 | return mod.fail(scope, name_src, "redefinition of '{s}'", .{ident_name}); |
| 964 | 1095 | } |
| 965 | | const init_node = node.getInitNode() orelse |
| 1096 | if (var_decl.ast.init_node == 0) { |
| 966 | 1097 | return mod.fail(scope, name_src, "variables must be initialized", .{}); |
| 1098 | } |
| 967 | 1099 | |
| 968 | | switch (tree.token_ids[node.mut_token]) { |
| 1100 | switch (token_tags[var_decl.ast.mut_token]) { |
| 969 | 1101 | .keyword_const => { |
| 970 | 1102 | // Depending on the type of AST the initialization expression is, we may need an lvalue |
| 971 | 1103 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as |
| 972 | 1104 | // the variable, no memory location needed. |
| 973 | | if (!nodeMayNeedMemoryLocation(init_node, scope)) { |
| 974 | | const result_loc: ResultLoc = if (node.getTypeNode()) |type_node| |
| 975 | | .{ .ty = try typeExpr(mod, scope, type_node) } |
| 1105 | if (!nodeMayNeedMemoryLocation(scope, var_decl.ast.init_node)) { |
| 1106 | const result_loc: ResultLoc = if (var_decl.ast.type_node != 0) |
| 1107 | .{ .ty = try typeExpr(mod, scope, var_decl.ast.type_node) } |
| 976 | 1108 | else |
| 977 | 1109 | .none; |
| 978 | | const init_inst = try expr(mod, scope, result_loc, init_node); |
| 1110 | const init_inst = try expr(mod, scope, result_loc, var_decl.ast.init_node); |
| 979 | 1111 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 980 | 1112 | sub_scope.* = .{ |
| 981 | 1113 | .parent = scope, |
| ... | ... | @@ -999,8 +1131,8 @@ fn varDecl( |
| 999 | 1131 | |
| 1000 | 1132 | var resolve_inferred_alloc: ?*zir.Inst = null; |
| 1001 | 1133 | var opt_type_inst: ?*zir.Inst = null; |
| 1002 | | if (node.getTypeNode()) |type_node| { |
| 1003 | | const type_inst = try typeExpr(mod, &init_scope.base, type_node); |
| 1134 | if (var_decl.ast.type_node != 0) { |
| 1135 | const type_inst = try typeExpr(mod, &init_scope.base, var_decl.ast.type_node); |
| 1004 | 1136 | opt_type_inst = type_inst; |
| 1005 | 1137 | init_scope.rl_ptr = try addZIRUnOp(mod, &init_scope.base, name_src, .alloc, type_inst); |
| 1006 | 1138 | } else { |
| ... | ... | @@ -1009,7 +1141,7 @@ fn varDecl( |
| 1009 | 1141 | init_scope.rl_ptr = &alloc.base; |
| 1010 | 1142 | } |
| 1011 | 1143 | const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope }; |
| 1012 | | const init_inst = try expr(mod, &init_scope.base, init_result_loc, init_node); |
| 1144 | const init_inst = try expr(mod, &init_scope.base, init_result_loc, var_decl.ast.init_node); |
| 1013 | 1145 | const parent_zir = &scope.getGenZIR().instructions; |
| 1014 | 1146 | if (init_scope.rvalue_rl_count == 1) { |
| 1015 | 1147 | // Result location pointer not used. We don't need an alloc for this |
| ... | ... | @@ -1069,8 +1201,11 @@ fn varDecl( |
| 1069 | 1201 | }, |
| 1070 | 1202 | .keyword_var => { |
| 1071 | 1203 | var resolve_inferred_alloc: ?*zir.Inst = null; |
| 1072 | | const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTypeNode()) |type_node| a: { |
| 1073 | | const type_inst = try typeExpr(mod, scope, type_node); |
| 1204 | const var_data: struct { |
| 1205 | result_loc: ResultLoc, |
| 1206 | alloc: *zir.Inst, |
| 1207 | } = if (var_decl.ast.type_node != 0) a: { |
| 1208 | const type_inst = try typeExpr(mod, scope, var_decl.ast.type_node); |
| 1074 | 1209 | const alloc = try addZIRUnOp(mod, scope, name_src, .alloc_mut, type_inst); |
| 1075 | 1210 | break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } }; |
| 1076 | 1211 | } else a: { |
| ... | ... | @@ -1078,7 +1213,7 @@ fn varDecl( |
| 1078 | 1213 | resolve_inferred_alloc = &alloc.base; |
| 1079 | 1214 | break :a .{ .alloc = &alloc.base, .result_loc = .{ .inferred_ptr = alloc } }; |
| 1080 | 1215 | }; |
| 1081 | | const init_inst = try expr(mod, scope, var_data.result_loc, init_node); |
| 1216 | const init_inst = try expr(mod, scope, var_data.result_loc, var_decl.ast.init_node); |
| 1082 | 1217 | if (resolve_inferred_alloc) |inst| { |
| 1083 | 1218 | _ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst); |
| 1084 | 1219 | } |
| ... | ... | @@ -1099,13 +1234,15 @@ fn assign(mod: *Module, scope: *Scope, infix_node: ast.Node.Index) InnerError!vo |
| 1099 | 1234 | const tree = scope.tree(); |
| 1100 | 1235 | const node_datas = tree.nodes.items(.data); |
| 1101 | 1236 | const main_tokens = tree.nodes.items(.main_token); |
| 1237 | const node_tags = tree.nodes.items(.tag); |
| 1238 | |
| 1102 | 1239 | const lhs = node_datas[infix_node].lhs; |
| 1103 | 1240 | const rhs = node_datas[infix_node].rhs; |
| 1104 | 1241 | if (node_tags[lhs] == .identifier) { |
| 1105 | 1242 | // This intentionally does not support `@"_"` syntax. |
| 1106 | 1243 | const ident_name = tree.tokenSlice(main_tokens[lhs]); |
| 1107 | 1244 | if (mem.eql(u8, ident_name, "_")) { |
| 1108 | | _ = try expr(mod, scope, .discard, infix_node.rhs); |
| 1245 | _ = try expr(mod, scope, .discard, rhs); |
| 1109 | 1246 | return; |
| 1110 | 1247 | } |
| 1111 | 1248 | } |
| ... | ... | @@ -1122,6 +1259,7 @@ fn assignOp( |
| 1122 | 1259 | const tree = scope.tree(); |
| 1123 | 1260 | const node_datas = tree.nodes.items(.data); |
| 1124 | 1261 | const main_tokens = tree.nodes.items(.main_token); |
| 1262 | const token_starts = tree.tokens.items(.start); |
| 1125 | 1263 | |
| 1126 | 1264 | const lhs_ptr = try lvalExpr(mod, scope, node_datas[infix_node].lhs); |
| 1127 | 1265 | const lhs = try addZIRUnOp(mod, scope, lhs_ptr.src, .deref, lhs_ptr); |
| ... | ... | @@ -1136,6 +1274,7 @@ fn boolNot(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.In |
| 1136 | 1274 | const tree = scope.tree(); |
| 1137 | 1275 | const node_datas = tree.nodes.items(.data); |
| 1138 | 1276 | const main_tokens = tree.nodes.items(.main_token); |
| 1277 | const token_starts = tree.tokens.items(.start); |
| 1139 | 1278 | |
| 1140 | 1279 | const src = token_starts[main_tokens[node]]; |
| 1141 | 1280 | const bool_type = try addZIRInstConst(mod, scope, src, .{ |
| ... | ... | @@ -1150,6 +1289,7 @@ fn bitNot(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Ins |
| 1150 | 1289 | const tree = scope.tree(); |
| 1151 | 1290 | const node_datas = tree.nodes.items(.data); |
| 1152 | 1291 | const main_tokens = tree.nodes.items(.main_token); |
| 1292 | const token_starts = tree.tokens.items(.start); |
| 1153 | 1293 | |
| 1154 | 1294 | const src = token_starts[main_tokens[node]]; |
| 1155 | 1295 | const operand = try expr(mod, scope, .none, node_datas[node].lhs); |
| ... | ... | @@ -1165,6 +1305,7 @@ fn negation( |
| 1165 | 1305 | const tree = scope.tree(); |
| 1166 | 1306 | const node_datas = tree.nodes.items(.data); |
| 1167 | 1307 | const main_tokens = tree.nodes.items(.main_token); |
| 1308 | const token_starts = tree.tokens.items(.start); |
| 1168 | 1309 | |
| 1169 | 1310 | const src = token_starts[main_tokens[node]]; |
| 1170 | 1311 | const lhs = try addZIRInstConst(mod, scope, src, .{ |
| ... | ... | @@ -1175,53 +1316,61 @@ fn negation( |
| 1175 | 1316 | return addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs); |
| 1176 | 1317 | } |
| 1177 | 1318 | |
| 1178 | | fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst { |
| 1319 | fn ptrType( |
| 1320 | mod: *Module, |
| 1321 | scope: *Scope, |
| 1322 | rl: ResultLoc, |
| 1323 | ptr_info: ast.full.PtrType, |
| 1324 | ) InnerError!*zir.Inst { |
| 1325 | const tree = scope.tree(); |
| 1326 | const token_starts = tree.tokens.items(.start); |
| 1327 | |
| 1328 | const src = token_starts[ptr_info.ast.main_token]; |
| 1329 | |
| 1179 | 1330 | const simple = ptr_info.allowzero_token == null and |
| 1180 | | ptr_info.align_info == null and |
| 1331 | ptr_info.ast.align_node == 0 and |
| 1181 | 1332 | ptr_info.volatile_token == null and |
| 1182 | | ptr_info.sentinel == null; |
| 1333 | ptr_info.ast.sentinel == 0; |
| 1183 | 1334 | |
| 1184 | 1335 | if (simple) { |
| 1185 | | const child_type = try typeExpr(mod, scope, rhs); |
| 1336 | const child_type = try typeExpr(mod, scope, ptr_info.ast.child_type); |
| 1186 | 1337 | const mutable = ptr_info.const_token == null; |
| 1187 | | // TODO stage1 type inference bug |
| 1188 | 1338 | const T = zir.Inst.Tag; |
| 1189 | | return addZIRUnOp(mod, scope, src, switch (size) { |
| 1339 | const result = try addZIRUnOp(mod, scope, src, switch (ptr_info.size) { |
| 1190 | 1340 | .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, |
| 1191 | 1341 | .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, |
| 1192 | 1342 | .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, |
| 1193 | 1343 | .Slice => if (mutable) T.mut_slice_type else T.const_slice_type, |
| 1194 | 1344 | }, child_type); |
| 1345 | return rvalue(mod, scope, rl, result); |
| 1195 | 1346 | } |
| 1196 | 1347 | |
| 1197 | 1348 | var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, .kw_args).field_type = .{}; |
| 1198 | | kw_args.size = size; |
| 1349 | kw_args.size = ptr_info.size; |
| 1199 | 1350 | kw_args.@"allowzero" = ptr_info.allowzero_token != null; |
| 1200 | | if (ptr_info.align_info) |some| { |
| 1201 | | kw_args.@"align" = try expr(mod, scope, .none, some.node); |
| 1202 | | if (some.bit_range) |bit_range| { |
| 1203 | | kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start); |
| 1204 | | kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); |
| 1351 | if (ptr_info.ast.align_node != 0) { |
| 1352 | kw_args.@"align" = try expr(mod, scope, .none, ptr_info.ast.align_node); |
| 1353 | if (ptr_info.ast.bit_range_start != 0) { |
| 1354 | kw_args.align_bit_start = try expr(mod, scope, .none, ptr_info.ast.bit_range_start); |
| 1355 | kw_args.align_bit_end = try expr(mod, scope, .none, ptr_info.ast.bit_range_end); |
| 1205 | 1356 | } |
| 1206 | 1357 | } |
| 1207 | 1358 | kw_args.mutable = ptr_info.const_token == null; |
| 1208 | 1359 | kw_args.@"volatile" = ptr_info.volatile_token != null; |
| 1209 | | if (ptr_info.sentinel) |some| { |
| 1210 | | kw_args.sentinel = try expr(mod, scope, .none, some); |
| 1211 | | } |
| 1212 | | |
| 1213 | | const child_type = try typeExpr(mod, scope, rhs); |
| 1214 | | if (kw_args.sentinel) |some| { |
| 1215 | | kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some); |
| 1360 | const child_type = try typeExpr(mod, scope, ptr_info.ast.child_type); |
| 1361 | if (ptr_info.ast.sentinel != 0) { |
| 1362 | kw_args.sentinel = try expr(mod, scope, .{ .ty = child_type }, ptr_info.ast.sentinel); |
| 1216 | 1363 | } |
| 1217 | | |
| 1218 | | return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args); |
| 1364 | const result = try addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args); |
| 1365 | return rvalue(mod, scope, rl, result); |
| 1219 | 1366 | } |
| 1220 | 1367 | |
| 1221 | 1368 | fn arrayType(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst { |
| 1222 | 1369 | const tree = scope.tree(); |
| 1223 | 1370 | const main_tokens = tree.nodes.items(.main_token); |
| 1224 | 1371 | const node_datas = tree.nodes.items(.data); |
| 1372 | const token_starts = tree.tokens.items(.start); |
| 1373 | |
| 1225 | 1374 | const src = token_starts[main_tokens[node]]; |
| 1226 | 1375 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| 1227 | 1376 | .ty = Type.initTag(.type), |
| ... | ... | @@ -1246,6 +1395,9 @@ fn arrayType(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) ! |
| 1246 | 1395 | fn arrayTypeSentinel(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst { |
| 1247 | 1396 | const tree = scope.tree(); |
| 1248 | 1397 | const main_tokens = tree.nodes.items(.main_token); |
| 1398 | const token_starts = tree.tokens.items(.start); |
| 1399 | const node_datas = tree.nodes.items(.data); |
| 1400 | |
| 1249 | 1401 | const len_node = node_datas[node].lhs; |
| 1250 | 1402 | const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel); |
| 1251 | 1403 | const src = token_starts[main_tokens[node]]; |
| ... | ... | @@ -1274,6 +1426,8 @@ fn containerField( |
| 1274 | 1426 | node: *ast.Node.ContainerField, |
| 1275 | 1427 | ) InnerError!*zir.Inst { |
| 1276 | 1428 | const tree = scope.tree(); |
| 1429 | const token_starts = tree.tokens.items(.start); |
| 1430 | |
| 1277 | 1431 | const src = token_starts[tree.firstToken(node)]; |
| 1278 | 1432 | const name = try mod.identifierTokenString(scope, node.name_token); |
| 1279 | 1433 | |
| ... | ... | @@ -1305,9 +1459,18 @@ fn containerField( |
| 1305 | 1459 | }); |
| 1306 | 1460 | } |
| 1307 | 1461 | |
| 1308 | | fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ContainerDecl) InnerError!*zir.Inst { |
| 1462 | fn containerDecl( |
| 1463 | mod: *Module, |
| 1464 | scope: *Scope, |
| 1465 | rl: ResultLoc, |
| 1466 | container_decl: ast.full.ContainerDecl, |
| 1467 | ) InnerError!*zir.Inst { |
| 1309 | 1468 | const tree = scope.tree(); |
| 1310 | | const src = token_starts[node.kind_token]; |
| 1469 | const token_starts = tree.tokens.items(.start); |
| 1470 | const node_tags = tree.nodes.items(.tag); |
| 1471 | const token_tags = tree.tokens.items(.tag); |
| 1472 | |
| 1473 | const src = token_starts[container_decl.ast.main_token]; |
| 1311 | 1474 | |
| 1312 | 1475 | var gen_scope: Scope.GenZIR = .{ |
| 1313 | 1476 | .parent = scope, |
| ... | ... | @@ -1321,9 +1484,12 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con |
| 1321 | 1484 | var fields = std.ArrayList(*zir.Inst).init(mod.gpa); |
| 1322 | 1485 | defer fields.deinit(); |
| 1323 | 1486 | |
| 1324 | | for (node.fieldsAndDecls()) |fd| { |
| 1325 | | if (fd.castTag(.ContainerField)) |f| { |
| 1326 | | try fields.append(try containerField(mod, &gen_scope.base, f)); |
| 1487 | for (container_decl.ast.members) |member| { |
| 1488 | switch (node_tags[member]) { |
| 1489 | .container_field_init, .container_field_align, .container_field => { |
| 1490 | try fields.append(try containerField(mod, &gen_scope.base, member)); |
| 1491 | }, |
| 1492 | else => continue, |
| 1327 | 1493 | } |
| 1328 | 1494 | } |
| 1329 | 1495 | |
| ... | ... | @@ -1332,19 +1498,22 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con |
| 1332 | 1498 | const arena = &decl_arena.allocator; |
| 1333 | 1499 | |
| 1334 | 1500 | var layout: std.builtin.TypeInfo.ContainerLayout = .Auto; |
| 1335 | | if (node.layout_token) |some| switch (tree.token_ids[some]) { |
| 1501 | if (container_decl.layout_token) |some| switch (token_tags[some]) { |
| 1336 | 1502 | .keyword_extern => layout = .Extern, |
| 1337 | 1503 | .keyword_packed => layout = .Packed, |
| 1338 | 1504 | else => unreachable, |
| 1339 | 1505 | }; |
| 1340 | 1506 | |
| 1341 | | const container_type = switch (tree.token_ids[node.kind_token]) { |
| 1507 | // TODO this implementation is incorrect. The types must be created in semantic |
| 1508 | // analysis, not astgen, because the same ZIR is re-used for multiple inline function calls, |
| 1509 | // comptime function calls, and generic function instantiations, and these |
| 1510 | // must result in different instances of container types. |
| 1511 | const container_type = switch (token_tags[container_decl.ast.main_token]) { |
| 1342 | 1512 | .keyword_enum => blk: { |
| 1343 | | const tag_type: ?*zir.Inst = switch (node.init_arg_expr) { |
| 1344 | | .Type => |t| try typeExpr(mod, &gen_scope.base, t), |
| 1345 | | .None => null, |
| 1346 | | .Enum => unreachable, |
| 1347 | | }; |
| 1513 | const tag_type: ?*zir.Inst = if (container_decl.ast.arg != 0) |
| 1514 | try typeExpr(mod, &gen_scope.base, container_decl.ast.arg) |
| 1515 | else |
| 1516 | null; |
| 1348 | 1517 | const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.EnumType, .{ |
| 1349 | 1518 | .fields = try arena.dupe(*zir.Inst, fields.items), |
| 1350 | 1519 | }, .{ |
| ... | ... | @@ -1367,7 +1536,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con |
| 1367 | 1536 | break :blk Type.initPayload(&enum_type.base); |
| 1368 | 1537 | }, |
| 1369 | 1538 | .keyword_struct => blk: { |
| 1370 | | assert(node.init_arg_expr == .None); |
| 1539 | assert(container_decl.ast.arg == 0); |
| 1371 | 1540 | const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.StructType, .{ |
| 1372 | 1541 | .fields = try arena.dupe(*zir.Inst, fields.items), |
| 1373 | 1542 | }, .{ |
| ... | ... | @@ -1389,21 +1558,16 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con |
| 1389 | 1558 | break :blk Type.initPayload(&struct_type.base); |
| 1390 | 1559 | }, |
| 1391 | 1560 | .keyword_union => blk: { |
| 1392 | | const init_inst = switch (node.init_arg_expr) { |
| 1393 | | .Enum => |e| if (e) |t| try typeExpr(mod, &gen_scope.base, t) else null, |
| 1394 | | .None => null, |
| 1395 | | .Type => |t| try typeExpr(mod, &gen_scope.base, t), |
| 1396 | | }; |
| 1397 | | const init_kind: zir.Inst.UnionType.InitKind = switch (node.init_arg_expr) { |
| 1398 | | .Enum => .enum_type, |
| 1399 | | .None => .none, |
| 1400 | | .Type => .tag_type, |
| 1401 | | }; |
| 1561 | const init_inst: ?*zir.Inst = if (container_decl.ast.arg != 0) |
| 1562 | try typeExpr(mod, &gen_scope.base, container_decl.ast.arg) |
| 1563 | else |
| 1564 | null; |
| 1565 | const has_enum_token = container_decl.ast.enum_token != null; |
| 1402 | 1566 | const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.UnionType, .{ |
| 1403 | 1567 | .fields = try arena.dupe(*zir.Inst, fields.items), |
| 1404 | 1568 | }, .{ |
| 1405 | 1569 | .layout = layout, |
| 1406 | | .init_kind = init_kind, |
| 1570 | .has_enum_token = has_enum_token, |
| 1407 | 1571 | .init_inst = init_inst, |
| 1408 | 1572 | }); |
| 1409 | 1573 | const union_type = try arena.create(Type.Payload.Union); |
| ... | ... | @@ -1437,7 +1601,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con |
| 1437 | 1601 | else => unreachable, |
| 1438 | 1602 | }; |
| 1439 | 1603 | const val = try Value.Tag.ty.create(arena, container_type); |
| 1440 | | const decl = try mod.createContainerDecl(scope, node.kind_token, &decl_arena, .{ |
| 1604 | const decl = try mod.createContainerDecl(scope, container_decl.ast.main_token, &decl_arena, .{ |
| 1441 | 1605 | .ty = Type.initTag(.type), |
| 1442 | 1606 | .val = val, |
| 1443 | 1607 | }); |
| ... | ... | @@ -1459,6 +1623,7 @@ fn errorSetDecl( |
| 1459 | 1623 | const tree = scope.tree(); |
| 1460 | 1624 | const main_tokens = tree.nodes.items(.main_token); |
| 1461 | 1625 | const token_tags = tree.tokens.items(.tag); |
| 1626 | const token_starts = tree.tokens.items(.start); |
| 1462 | 1627 | |
| 1463 | 1628 | // Count how many fields there are. |
| 1464 | 1629 | const error_token = main_tokens[node]; |
| ... | ... | @@ -1500,15 +1665,17 @@ fn orelseCatchExpr( |
| 1500 | 1665 | mod: *Module, |
| 1501 | 1666 | scope: *Scope, |
| 1502 | 1667 | rl: ResultLoc, |
| 1503 | | lhs: *ast.Node, |
| 1668 | lhs: ast.Node.Index, |
| 1504 | 1669 | op_token: ast.TokenIndex, |
| 1505 | 1670 | cond_op: zir.Inst.Tag, |
| 1506 | 1671 | unwrap_op: zir.Inst.Tag, |
| 1507 | 1672 | unwrap_code_op: zir.Inst.Tag, |
| 1508 | | rhs: *ast.Node, |
| 1509 | | payload_node: ?*ast.Node, |
| 1673 | rhs: ast.Node.Index, |
| 1674 | payload_token: ?ast.TokenIndex, |
| 1510 | 1675 | ) InnerError!*zir.Inst { |
| 1511 | 1676 | const tree = scope.tree(); |
| 1677 | const token_starts = tree.tokens.items(.start); |
| 1678 | |
| 1512 | 1679 | const src = token_starts[op_token]; |
| 1513 | 1680 | |
| 1514 | 1681 | var block_scope: Scope.GenZIR = .{ |
| ... | ... | @@ -1547,12 +1714,11 @@ fn orelseCatchExpr( |
| 1547 | 1714 | |
| 1548 | 1715 | var err_val_scope: Scope.LocalVal = undefined; |
| 1549 | 1716 | const then_sub_scope = blk: { |
| 1550 | | const payload = payload_node orelse break :blk &then_scope.base; |
| 1551 | | |
| 1552 | | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); |
| 1553 | | if (mem.eql(u8, err_name, "_")) |
| 1554 | | break :blk &then_scope.base; |
| 1555 | | |
| 1717 | const payload = payload_token orelse break :blk &then_scope.base; |
| 1718 | if (mem.eql(u8, tree.tokenSlice(payload), "_")) { |
| 1719 | return mod.failTok(&then_scope.base, payload, "discard of error capture; omit it instead", .{}); |
| 1720 | } |
| 1721 | const err_name = try mod.identifierTokenString(scope, payload); |
| 1556 | 1722 | err_val_scope = .{ |
| 1557 | 1723 | .parent = &then_scope.base, |
| 1558 | 1724 | .gen_zir = &then_scope, |
| ... | ... | @@ -1685,18 +1851,20 @@ pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) I |
| 1685 | 1851 | const tree = scope.tree(); |
| 1686 | 1852 | const token_starts = tree.tokens.items(.start); |
| 1687 | 1853 | const main_tokens = tree.nodes.items(.main_token); |
| 1854 | const node_datas = tree.nodes.items(.data); |
| 1855 | |
| 1688 | 1856 | const dot_token = main_tokens[node]; |
| 1689 | 1857 | const src = token_starts[dot_token]; |
| 1690 | 1858 | const field_ident = dot_token + 1; |
| 1691 | 1859 | const field_name = try mod.identifierTokenString(scope, field_ident); |
| 1692 | 1860 | if (rl == .ref) { |
| 1693 | 1861 | return addZirInstTag(mod, scope, src, .field_ptr, .{ |
| 1694 | | .object = try expr(mod, scope, .ref, node.lhs), |
| 1862 | .object = try expr(mod, scope, .ref, node_datas[node].lhs), |
| 1695 | 1863 | .field_name = field_name, |
| 1696 | 1864 | }); |
| 1697 | 1865 | } else { |
| 1698 | 1866 | return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val, .{ |
| 1699 | | .object = try expr(mod, scope, .none, node.lhs), |
| 1867 | .object = try expr(mod, scope, .none, node_datas[node].lhs), |
| 1700 | 1868 | .field_name = field_name, |
| 1701 | 1869 | })); |
| 1702 | 1870 | } |
| ... | ... | @@ -1711,6 +1879,8 @@ fn arrayAccess( |
| 1711 | 1879 | const tree = scope.tree(); |
| 1712 | 1880 | const main_tokens = tree.nodes.items(.main_token); |
| 1713 | 1881 | const token_starts = tree.tokens.items(.start); |
| 1882 | const node_datas = tree.nodes.items(.data); |
| 1883 | |
| 1714 | 1884 | const src = token_starts[main_tokens[node]]; |
| 1715 | 1885 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| 1716 | 1886 | .ty = Type.initTag(.type), |
| ... | ... | @@ -1737,6 +1907,7 @@ fn sliceExpr( |
| 1737 | 1907 | ) InnerError!*zir.Inst { |
| 1738 | 1908 | const tree = scope.tree(); |
| 1739 | 1909 | const token_starts = tree.tokens.items(.start); |
| 1910 | |
| 1740 | 1911 | const src = token_starts[slice.ast.lbracket]; |
| 1741 | 1912 | |
| 1742 | 1913 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| ... | ... | @@ -1786,6 +1957,7 @@ fn simpleBinOp( |
| 1786 | 1957 | const tree = scope.tree(); |
| 1787 | 1958 | const node_datas = tree.nodes.items(.data); |
| 1788 | 1959 | const main_tokens = tree.nodes.items(.main_token); |
| 1960 | const token_starts = tree.tokens.items(.start); |
| 1789 | 1961 | |
| 1790 | 1962 | const lhs = try expr(mod, scope, .none, node_datas[infix_node].lhs); |
| 1791 | 1963 | const rhs = try expr(mod, scope, .none, node_datas[infix_node].rhs); |
| ... | ... | @@ -1804,6 +1976,7 @@ fn boolBinOp( |
| 1804 | 1976 | const tree = scope.tree(); |
| 1805 | 1977 | const node_datas = tree.nodes.items(.data); |
| 1806 | 1978 | const main_tokens = tree.nodes.items(.main_token); |
| 1979 | const token_starts = tree.tokens.items(.start); |
| 1807 | 1980 | |
| 1808 | 1981 | const src = token_starts[main_tokens[infix_node]]; |
| 1809 | 1982 | const bool_type = try addZIRInstConst(mod, scope, src, .{ |
| ... | ... | @@ -1899,13 +2072,14 @@ fn ifExpr( |
| 1899 | 2072 | defer block_scope.instructions.deinit(mod.gpa); |
| 1900 | 2073 | |
| 1901 | 2074 | const tree = scope.tree(); |
| 1902 | | const node_datas = tree.nodes.items(.data); |
| 1903 | 2075 | const main_tokens = tree.nodes.items(.main_token); |
| 2076 | const token_starts = tree.tokens.items(.start); |
| 2077 | |
| 1904 | 2078 | const if_src = token_starts[if_full.ast.if_token]; |
| 1905 | 2079 | |
| 1906 | 2080 | const cond = c: { |
| 1907 | 2081 | // TODO https://github.com/ziglang/zig/issues/7929 |
| 1908 | | if (if_full.ast.error_token) |error_token| { |
| 2082 | if (if_full.error_token) |error_token| { |
| 1909 | 2083 | return mod.failTok(scope, error_token, "TODO implement if error union", .{}); |
| 1910 | 2084 | } else if (if_full.payload_token) |payload_token| { |
| 1911 | 2085 | return mod.failTok(scope, payload_token, "TODO implement if optional", .{}); |
| ... | ... | @@ -1966,7 +2140,7 @@ fn ifExpr( |
| 1966 | 2140 | }; |
| 1967 | 2141 | } else |
| 1968 | 2142 | .{ |
| 1969 | | .src = token_starts[tree.lastToken(if_full.then_expr)], |
| 2143 | .src = token_starts[tree.lastToken(if_full.ast.then_expr)], |
| 1970 | 2144 | .result = null, |
| 1971 | 2145 | }; |
| 1972 | 2146 | |
| ... | ... | @@ -2042,8 +2216,9 @@ fn whileExpr( |
| 2042 | 2216 | defer continue_scope.instructions.deinit(mod.gpa); |
| 2043 | 2217 | |
| 2044 | 2218 | const tree = scope.tree(); |
| 2045 | | const node_datas = tree.nodes.items(.data); |
| 2046 | 2219 | const main_tokens = tree.nodes.items(.main_token); |
| 2220 | const token_starts = tree.tokens.items(.start); |
| 2221 | |
| 2047 | 2222 | const while_src = token_starts[while_full.ast.while_token]; |
| 2048 | 2223 | const void_type = try addZIRInstConst(mod, scope, while_src, .{ |
| 2049 | 2224 | .ty = Type.initTag(.type), |
| ... | ... | @@ -2051,16 +2226,16 @@ fn whileExpr( |
| 2051 | 2226 | }); |
| 2052 | 2227 | const cond = c: { |
| 2053 | 2228 | // TODO https://github.com/ziglang/zig/issues/7929 |
| 2054 | | if (while_full.ast.error_token) |error_token| { |
| 2229 | if (while_full.error_token) |error_token| { |
| 2055 | 2230 | return mod.failTok(scope, error_token, "TODO implement while error union", .{}); |
| 2056 | 2231 | } else if (while_full.payload_token) |payload_token| { |
| 2057 | 2232 | return mod.failTok(scope, payload_token, "TODO implement while optional", .{}); |
| 2058 | 2233 | } else { |
| 2059 | | const bool_type = try addZIRInstConst(mod, &block_scope.base, while_src, .{ |
| 2234 | const bool_type = try addZIRInstConst(mod, &continue_scope.base, while_src, .{ |
| 2060 | 2235 | .ty = Type.initTag(.type), |
| 2061 | 2236 | .val = Value.initTag(.bool_type), |
| 2062 | 2237 | }); |
| 2063 | | break :c try expr(mod, &block_scope.base, .{ .ty = bool_type }, while_full.ast.cond_expr); |
| 2238 | break :c try expr(mod, &continue_scope.base, .{ .ty = bool_type }, while_full.ast.cond_expr); |
| 2064 | 2239 | } |
| 2065 | 2240 | }; |
| 2066 | 2241 | |
| ... | ... | @@ -2128,7 +2303,7 @@ fn whileExpr( |
| 2128 | 2303 | }; |
| 2129 | 2304 | defer else_scope.instructions.deinit(mod.gpa); |
| 2130 | 2305 | |
| 2131 | | const else_node = if_full.ast.else_expr; |
| 2306 | const else_node = while_full.ast.else_expr; |
| 2132 | 2307 | const else_info: struct { src: usize, result: ?*zir.Inst } = if (else_node != 0) blk: { |
| 2133 | 2308 | loop_scope.break_count += 1; |
| 2134 | 2309 | const sub_scope = &else_scope.base; |
| ... | ... | @@ -2138,7 +2313,7 @@ fn whileExpr( |
| 2138 | 2313 | }; |
| 2139 | 2314 | } else |
| 2140 | 2315 | .{ |
| 2141 | | .src = token_starts[tree.lastToken(then_node)], |
| 2316 | .src = token_starts[tree.lastToken(while_full.ast.then_expr)], |
| 2142 | 2317 | .result = null, |
| 2143 | 2318 | }; |
| 2144 | 2319 | |
| ... | ... | @@ -2181,8 +2356,10 @@ fn forExpr( |
| 2181 | 2356 | |
| 2182 | 2357 | // Set up variables and constants. |
| 2183 | 2358 | const tree = scope.tree(); |
| 2184 | | const node_datas = tree.nodes.items(.data); |
| 2185 | 2359 | const main_tokens = tree.nodes.items(.main_token); |
| 2360 | const token_starts = tree.tokens.items(.start); |
| 2361 | const token_tags = tree.tokens.items(.tag); |
| 2362 | |
| 2186 | 2363 | const for_src = token_starts[for_full.ast.while_token]; |
| 2187 | 2364 | const index_ptr = blk: { |
| 2188 | 2365 | const usize_type = try addZIRInstConst(mod, scope, for_src, .{ |
| ... | ... | @@ -2299,7 +2476,7 @@ fn forExpr( |
| 2299 | 2476 | else |
| 2300 | 2477 | break :blk &then_scope.base; |
| 2301 | 2478 | if (mem.eql(u8, tree.tokenSlice(index_token), "_")) { |
| 2302 | | return mod.failTok(&then_scope.base, index_token, "discard of index capture not allowed; omit it instead", .{}); |
| 2479 | return mod.failTok(&then_scope.base, index_token, "discard of index capture; omit it instead", .{}); |
| 2303 | 2480 | } |
| 2304 | 2481 | const index_name = try mod.identifierTokenString(&then_scope.base, index_token); |
| 2305 | 2482 | index_scope = .{ |
| ... | ... | @@ -2334,7 +2511,7 @@ fn forExpr( |
| 2334 | 2511 | }; |
| 2335 | 2512 | } else |
| 2336 | 2513 | .{ |
| 2337 | | .src = token_starts[tree.lastToken(then_node)], |
| 2514 | .src = token_starts[tree.lastToken(for_full.ast.then_expr)], |
| 2338 | 2515 | .result = null, |
| 2339 | 2516 | }; |
| 2340 | 2517 | |
| ... | ... | @@ -2386,10 +2563,12 @@ fn switchExpr( |
| 2386 | 2563 | const node_datas = tree.nodes.items(.data); |
| 2387 | 2564 | const main_tokens = tree.nodes.items(.main_token); |
| 2388 | 2565 | const token_tags = tree.tokens.items(.tag); |
| 2566 | const token_starts = tree.tokens.items(.start); |
| 2567 | const node_tags = tree.nodes.items(.tag); |
| 2389 | 2568 | |
| 2390 | 2569 | const switch_token = main_tokens[switch_node]; |
| 2391 | | const target_node = datas[switch_node].lhs; |
| 2392 | | const extra = tree.extraData(datas[switch_node].rhs, ast.switch_node.SubRange); |
| 2570 | const target_node = node_datas[switch_node].lhs; |
| 2571 | const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); |
| 2393 | 2572 | const case_nodes = tree.extra_data[extra.start..extra.end]; |
| 2394 | 2573 | |
| 2395 | 2574 | const switch_src = token_starts[switch_token]; |
| ... | ... | @@ -2552,7 +2731,7 @@ fn switchExpr( |
| 2552 | 2731 | defer else_scope.instructions.deinit(mod.gpa); |
| 2553 | 2732 | |
| 2554 | 2733 | // Now generate all but the special cases. |
| 2555 | | var special_case: ?ast.Node.Index = null; |
| 2734 | var special_case: ?ast.full.SwitchCase = null; |
| 2556 | 2735 | var items_index: usize = 0; |
| 2557 | 2736 | var case_index: usize = 0; |
| 2558 | 2737 | for (case_nodes) |case_node| { |
| ... | ... | @@ -2582,7 +2761,7 @@ fn switchExpr( |
| 2582 | 2761 | { |
| 2583 | 2762 | const item = items.items[items_index]; |
| 2584 | 2763 | items_index += 1; |
| 2585 | | try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target, target_ptr); |
| 2764 | try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target); |
| 2586 | 2765 | |
| 2587 | 2766 | cases[case_index] = .{ |
| 2588 | 2767 | .item = item, |
| ... | ... | @@ -2638,7 +2817,7 @@ fn switchExpr( |
| 2638 | 2817 | |
| 2639 | 2818 | // reset cond_scope for then_body |
| 2640 | 2819 | case_scope.instructions.items.len = 0; |
| 2641 | | try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target, target_ptr); |
| 2820 | try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target); |
| 2642 | 2821 | condbr.positionals.then_body = .{ |
| 2643 | 2822 | .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items), |
| 2644 | 2823 | }; |
| ... | ... | @@ -2655,7 +2834,7 @@ fn switchExpr( |
| 2655 | 2834 | |
| 2656 | 2835 | // Finally generate else block or a break. |
| 2657 | 2836 | if (special_case) |case| { |
| 2658 | | try switchCaseExpr(mod, &else_scope.base, block_scope.break_result_loc, block, case, target, target_ptr); |
| 2837 | try switchCaseExpr(mod, &else_scope.base, block_scope.break_result_loc, block, case, target); |
| 2659 | 2838 | } else { |
| 2660 | 2839 | // Not handling all possible cases is a compile error. |
| 2661 | 2840 | _ = try addZIRNoOp(mod, &else_scope.base, switch_src, .unreachable_unsafe); |
| ... | ... | @@ -2674,11 +2853,13 @@ fn switchCaseExpr( |
| 2674 | 2853 | block: *zir.Inst.Block, |
| 2675 | 2854 | case: ast.full.SwitchCase, |
| 2676 | 2855 | target: *zir.Inst, |
| 2677 | | target_ptr: ?*zir.Inst, |
| 2678 | 2856 | ) !void { |
| 2679 | 2857 | const tree = scope.tree(); |
| 2680 | 2858 | const node_datas = tree.nodes.items(.data); |
| 2681 | 2859 | const main_tokens = tree.nodes.items(.main_token); |
| 2860 | const token_starts = tree.tokens.items(.start); |
| 2861 | const token_tags = tree.tokens.items(.tag); |
| 2862 | |
| 2682 | 2863 | const case_src = token_starts[case.ast.arrow_token]; |
| 2683 | 2864 | const sub_scope = blk: { |
| 2684 | 2865 | const payload_token = case.payload_token orelse break :blk scope; |
| ... | ... | @@ -2690,11 +2871,11 @@ fn switchCaseExpr( |
| 2690 | 2871 | const value_name = tree.tokenSlice(ident); |
| 2691 | 2872 | if (mem.eql(u8, value_name, "_")) { |
| 2692 | 2873 | if (is_ptr) { |
| 2693 | | return mod.failTok(scope, payload.ptr_token.?, "pointer modifier invalid on discard", .{}); |
| 2874 | return mod.failTok(scope, payload_token, "pointer modifier invalid on discard", .{}); |
| 2694 | 2875 | } |
| 2695 | 2876 | break :blk scope; |
| 2696 | 2877 | } |
| 2697 | | return mod.failNode(scope, payload.value_symbol, "TODO implement switch value payload", .{}); |
| 2878 | return mod.failTok(scope, ident, "TODO implement switch value payload", .{}); |
| 2698 | 2879 | }; |
| 2699 | 2880 | |
| 2700 | 2881 | const case_body = try expr(mod, sub_scope, rl, case.ast.target_expr); |
| ... | ... | @@ -2710,10 +2891,12 @@ fn ret(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst { |
| 2710 | 2891 | const tree = scope.tree(); |
| 2711 | 2892 | const node_datas = tree.nodes.items(.data); |
| 2712 | 2893 | const main_tokens = tree.nodes.items(.main_token); |
| 2894 | const token_starts = tree.tokens.items(.start); |
| 2895 | |
| 2713 | 2896 | const src = token_starts[main_tokens[node]]; |
| 2714 | 2897 | const rhs_node = node_datas[node].lhs; |
| 2715 | 2898 | if (rhs_node != 0) { |
| 2716 | | if (nodeMayNeedMemoryLocation(rhs_node, scope)) { |
| 2899 | if (nodeMayNeedMemoryLocation(scope, rhs_node)) { |
| 2717 | 2900 | const ret_ptr = try addZIRNoOp(mod, scope, src, .ret_ptr); |
| 2718 | 2901 | const operand = try expr(mod, scope, .{ .ptr = ret_ptr }, rhs_node); |
| 2719 | 2902 | return addZIRUnOp(mod, scope, src, .@"return", operand); |
| ... | ... | @@ -2737,8 +2920,8 @@ fn identifier( |
| 2737 | 2920 | defer tracy.end(); |
| 2738 | 2921 | |
| 2739 | 2922 | const tree = scope.tree(); |
| 2740 | | const node_datas = tree.nodes.items(.data); |
| 2741 | 2923 | const main_tokens = tree.nodes.items(.main_token); |
| 2924 | const token_starts = tree.tokens.items(.start); |
| 2742 | 2925 | |
| 2743 | 2926 | const ident_token = main_tokens[ident]; |
| 2744 | 2927 | const ident_name = try mod.identifierTokenString(scope, ident_token); |
| ... | ... | @@ -2826,6 +3009,27 @@ fn identifier( |
| 2826 | 3009 | return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name}); |
| 2827 | 3010 | } |
| 2828 | 3011 | |
| 3012 | fn parseStringLiteral(mod: *Module, scope: *Scope, token: ast.TokenIndex) ![]u8 { |
| 3013 | const tree = scope.tree(); |
| 3014 | const token_tags = tree.tokens.items(.tag); |
| 3015 | const token_starts = tree.tokens.items(.start); |
| 3016 | assert(token_tags[token] == .string_literal); |
| 3017 | const unparsed = tree.tokenSlice(token); |
| 3018 | const arena = scope.arena(); |
| 3019 | var bad_index: usize = undefined; |
| 3020 | const bytes = std.zig.parseStringLiteral(arena, unparsed, &bad_index) catch |err| switch (err) { |
| 3021 | error.InvalidCharacter => { |
| 3022 | const bad_byte = unparsed[bad_index]; |
| 3023 | const src = token_starts[token]; |
| 3024 | return mod.fail(scope, src + bad_index, "invalid string literal character: '{c}'", .{ |
| 3025 | bad_byte, |
| 3026 | }); |
| 3027 | }, |
| 3028 | else => |e| return e, |
| 3029 | }; |
| 3030 | return bytes; |
| 3031 | } |
| 3032 | |
| 2829 | 3033 | fn stringLiteral( |
| 2830 | 3034 | mod: *Module, |
| 2831 | 3035 | scope: *Scope, |
| ... | ... | @@ -2833,23 +3037,11 @@ fn stringLiteral( |
| 2833 | 3037 | str_lit: ast.Node.Index, |
| 2834 | 3038 | ) InnerError!*zir.Inst { |
| 2835 | 3039 | const tree = scope.tree(); |
| 2836 | | const node_datas = tree.nodes.items(.data); |
| 2837 | 3040 | const main_tokens = tree.nodes.items(.main_token); |
| 3041 | const token_starts = tree.tokens.items(.start); |
| 2838 | 3042 | |
| 2839 | 3043 | const str_lit_token = main_tokens[str_lit]; |
| 2840 | | const unparsed_bytes = tree.tokenSlice(str_lit_token); |
| 2841 | | const arena = scope.arena(); |
| 2842 | | |
| 2843 | | var bad_index: usize = undefined; |
| 2844 | | const bytes = std.zig.parseStringLiteral(arena, unparsed_bytes, &bad_index) catch |err| switch (err) { |
| 2845 | | error.InvalidCharacter => { |
| 2846 | | const bad_byte = unparsed_bytes[bad_index]; |
| 2847 | | const src = token_starts[str_lit_token]; |
| 2848 | | return mod.fail(scope, src + bad_index, "invalid string literal character: '{c}'\n", .{bad_byte}); |
| 2849 | | }, |
| 2850 | | else => |e| return e, |
| 2851 | | }; |
| 2852 | | |
| 3044 | const bytes = try parseStringLiteral(mod, scope, str_lit_token); |
| 2853 | 3045 | const src = token_starts[str_lit_token]; |
| 2854 | 3046 | const str_inst = try addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); |
| 2855 | 3047 | return rvalue(mod, scope, rl, str_inst); |
| ... | ... | @@ -2864,9 +3056,10 @@ fn multilineStringLiteral( |
| 2864 | 3056 | const tree = scope.tree(); |
| 2865 | 3057 | const node_datas = tree.nodes.items(.data); |
| 2866 | 3058 | const main_tokens = tree.nodes.items(.main_token); |
| 3059 | const token_starts = tree.tokens.items(.start); |
| 2867 | 3060 | |
| 2868 | | const start = node_datas[node].lhs; |
| 2869 | | const end = node_datas[node].rhs; |
| 3061 | const start = node_datas[str_lit].lhs; |
| 3062 | const end = node_datas[str_lit].rhs; |
| 2870 | 3063 | |
| 2871 | 3064 | // Count the number of bytes to allocate. |
| 2872 | 3065 | const len: usize = len: { |
| ... | ... | @@ -2905,9 +3098,10 @@ fn multilineStringLiteral( |
| 2905 | 3098 | |
| 2906 | 3099 | fn charLiteral(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst { |
| 2907 | 3100 | const tree = scope.tree(); |
| 2908 | | const node_datas = tree.nodes.items(.data); |
| 2909 | 3101 | const main_tokens = tree.nodes.items(.main_token); |
| 2910 | 3102 | const main_token = main_tokens[node]; |
| 3103 | const token_starts = tree.tokens.items(.start); |
| 3104 | |
| 2911 | 3105 | const src = token_starts[main_token]; |
| 2912 | 3106 | const slice = tree.tokenSlice(main_token); |
| 2913 | 3107 | |
| ... | ... | @@ -2934,6 +3128,7 @@ fn integerLiteral( |
| 2934 | 3128 | const arena = scope.arena(); |
| 2935 | 3129 | const tree = scope.tree(); |
| 2936 | 3130 | const main_tokens = tree.nodes.items(.main_token); |
| 3131 | const token_starts = tree.tokens.items(.start); |
| 2937 | 3132 | |
| 2938 | 3133 | const int_token = main_tokens[int_lit]; |
| 2939 | 3134 | const prefixed_bytes = tree.tokenSlice(int_token); |
| ... | ... | @@ -2972,6 +3167,8 @@ fn floatLiteral( |
| 2972 | 3167 | const arena = scope.arena(); |
| 2973 | 3168 | const tree = scope.tree(); |
| 2974 | 3169 | const main_tokens = tree.nodes.items(.main_token); |
| 3170 | const token_starts = tree.tokens.items(.start); |
| 3171 | |
| 2975 | 3172 | const main_token = main_tokens[float_lit]; |
| 2976 | 3173 | const bytes = tree.tokenSlice(main_token); |
| 2977 | 3174 | if (bytes.len > 2 and bytes[1] == 'x') { |
| ... | ... | @@ -2988,17 +3185,18 @@ fn floatLiteral( |
| 2988 | 3185 | return rvalue(mod, scope, rl, result); |
| 2989 | 3186 | } |
| 2990 | 3187 | |
| 2991 | | fn assembly(mod: *Module, scope: *Scope, rl: ResultLoc, full: ast.full.Asm) InnerError!*zir.Inst { |
| 3188 | fn asmExpr(mod: *Module, scope: *Scope, rl: ResultLoc, full: ast.full.Asm) InnerError!*zir.Inst { |
| 2992 | 3189 | const arena = scope.arena(); |
| 2993 | 3190 | const tree = scope.tree(); |
| 2994 | | const node_datas = tree.nodes.items(.data); |
| 2995 | 3191 | const main_tokens = tree.nodes.items(.main_token); |
| 3192 | const token_starts = tree.tokens.items(.start); |
| 3193 | const node_datas = tree.nodes.items(.data); |
| 2996 | 3194 | |
| 2997 | 3195 | if (full.outputs.len != 0) { |
| 2998 | 3196 | return mod.failTok(scope, full.ast.asm_token, "TODO implement asm with an output", .{}); |
| 2999 | 3197 | } |
| 3000 | 3198 | |
| 3001 | | const inputs = try arena.alloc(*zir.Inst, full.inputs.len); |
| 3199 | const inputs = try arena.alloc([]const u8, full.inputs.len); |
| 3002 | 3200 | const args = try arena.alloc(*zir.Inst, full.inputs.len); |
| 3003 | 3201 | |
| 3004 | 3202 | const src = token_starts[full.ast.asm_token]; |
| ... | ... | @@ -3010,15 +3208,16 @@ fn assembly(mod: *Module, scope: *Scope, rl: ResultLoc, full: ast.full.Asm) Inne |
| 3010 | 3208 | |
| 3011 | 3209 | for (full.inputs) |input, i| { |
| 3012 | 3210 | // TODO semantically analyze constraints |
| 3013 | | inputs[i] = try expr(mod, scope, str_type_rl, input.constraint); |
| 3014 | | args[i] = try expr(mod, scope, .none, input.expr); |
| 3211 | const constraint_token = main_tokens[input] + 2; |
| 3212 | inputs[i] = try parseStringLiteral(mod, scope, constraint_token); |
| 3213 | args[i] = try expr(mod, scope, .none, node_datas[input].lhs); |
| 3015 | 3214 | } |
| 3016 | 3215 | |
| 3017 | 3216 | const return_type = try addZIRInstConst(mod, scope, src, .{ |
| 3018 | 3217 | .ty = Type.initTag(.type), |
| 3019 | 3218 | .val = Value.initTag(.void_type), |
| 3020 | 3219 | }); |
| 3021 | | const asm_inst = try addZIRInst(mod, scope, src, zir.Inst.@"asm", .{ |
| 3220 | const asm_inst = try addZIRInst(mod, scope, src, zir.Inst.Asm, .{ |
| 3022 | 3221 | .asm_source = try expr(mod, scope, str_type_rl, full.ast.template), |
| 3023 | 3222 | .return_type = return_type, |
| 3024 | 3223 | }, .{ |
| ... | ... | @@ -3185,8 +3384,9 @@ fn builtinCall( |
| 3185 | 3384 | params: []const ast.Node.Index, |
| 3186 | 3385 | ) InnerError!*zir.Inst { |
| 3187 | 3386 | const tree = scope.tree(); |
| 3188 | | const node_datas = tree.nodes.items(.data); |
| 3189 | 3387 | const main_tokens = tree.nodes.items(.main_token); |
| 3388 | const token_starts = tree.tokens.items(.start); |
| 3389 | |
| 3190 | 3390 | const builtin_token = main_tokens[call]; |
| 3191 | 3391 | const builtin_name = tree.tokenSlice(builtin_token); |
| 3192 | 3392 | |
| ... | ... | @@ -3200,11 +3400,13 @@ fn builtinCall( |
| 3200 | 3400 | builtin_name, |
| 3201 | 3401 | }); |
| 3202 | 3402 | }; |
| 3203 | | if (info.param_count != params.len) { |
| 3204 | | const s = if (params.len == 1) "" else "s"; |
| 3205 | | return mod.failTok(scope, builtin_token, "expected {d} parameter{s}, found {d}", .{ |
| 3206 | | expected, s, found, |
| 3207 | | }); |
| 3403 | if (info.param_count) |expected| { |
| 3404 | if (expected != params.len) { |
| 3405 | const s = if (expected == 1) "" else "s"; |
| 3406 | return mod.failTok(scope, builtin_token, "expected {d} parameter{s}, found {d}", .{ |
| 3407 | expected, s, params.len, |
| 3408 | }); |
| 3409 | } |
| 3208 | 3410 | } |
| 3209 | 3411 | const src = token_starts[builtin_token]; |
| 3210 | 3412 | |
| ... | ... | @@ -3237,7 +3439,7 @@ fn builtinCall( |
| 3237 | 3439 | }, |
| 3238 | 3440 | .compile_error => { |
| 3239 | 3441 | const target = try expr(mod, scope, .none, params[0]); |
| 3240 | | const result = addZIRUnOp(mod, scope, src, .compile_error, target); |
| 3442 | const result = try addZIRUnOp(mod, scope, src, .compile_error, target); |
| 3241 | 3443 | return rvalue(mod, scope, rl, result); |
| 3242 | 3444 | }, |
| 3243 | 3445 | .set_eval_branch_quota => { |
| ... | ... | @@ -3386,8 +3588,9 @@ fn callExpr( |
| 3386 | 3588 | } |
| 3387 | 3589 | |
| 3388 | 3590 | const tree = scope.tree(); |
| 3389 | | const node_datas = tree.nodes.items(.data); |
| 3390 | 3591 | const main_tokens = tree.nodes.items(.main_token); |
| 3592 | const token_starts = tree.tokens.items(.start); |
| 3593 | |
| 3391 | 3594 | const lhs = try expr(mod, scope, .none, call.ast.fn_expr); |
| 3392 | 3595 | |
| 3393 | 3596 | const args = try scope.getGenZIR().arena.alloc(*zir.Inst, call.ast.params.len); |
| ... | ... | @@ -3446,23 +3649,26 @@ fn getSimplePrimitiveValue(name: []const u8) ?TypedValue { |
| 3446 | 3649 | return null; |
| 3447 | 3650 | } |
| 3448 | 3651 | |
| 3449 | | fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { |
| 3652 | fn nodeMayNeedMemoryLocation(scope: *Scope, start_node: ast.Node.Index) bool { |
| 3653 | const tree = scope.tree(); |
| 3654 | const node_tags = tree.nodes.items(.tag); |
| 3655 | const node_datas = tree.nodes.items(.data); |
| 3656 | const main_tokens = tree.nodes.items(.main_token); |
| 3657 | const token_tags = tree.tokens.items(.tag); |
| 3658 | |
| 3450 | 3659 | var node = start_node; |
| 3451 | 3660 | while (true) { |
| 3452 | | switch (node.tag) { |
| 3453 | | .Root, |
| 3661 | switch (node_tags[node]) { |
| 3662 | .root, |
| 3454 | 3663 | .@"usingnamespace", |
| 3455 | 3664 | .test_decl, |
| 3456 | | .doc_comment, |
| 3457 | 3665 | .switch_case, |
| 3458 | | .switch_else, |
| 3459 | | .Else, |
| 3460 | | .Payload, |
| 3461 | | .PointerPayload, |
| 3462 | | .PointerIndexPayload, |
| 3463 | | .ContainerField, |
| 3464 | | .ErrorTag, |
| 3465 | | .FieldInitializer, |
| 3666 | .switch_case_one, |
| 3667 | .container_field_init, |
| 3668 | .container_field_align, |
| 3669 | .container_field, |
| 3670 | .asm_output, |
| 3671 | .asm_input, |
| 3466 | 3672 | => unreachable, |
| 3467 | 3673 | |
| 3468 | 3674 | .@"return", |
| ... | ... | @@ -3470,8 +3676,12 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { |
| 3470 | 3676 | .@"continue", |
| 3471 | 3677 | .bit_not, |
| 3472 | 3678 | .bool_not, |
| 3473 | | .var_decl, |
| 3679 | .global_var_decl, |
| 3680 | .local_var_decl, |
| 3681 | .simple_var_decl, |
| 3682 | .aligned_var_decl, |
| 3474 | 3683 | .@"defer", |
| 3684 | .@"errdefer", |
| 3475 | 3685 | .address_of, |
| 3476 | 3686 | .optional_type, |
| 3477 | 3687 | .negation, |
| ... | ... | @@ -3479,27 +3689,46 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { |
| 3479 | 3689 | .@"resume", |
| 3480 | 3690 | .array_type, |
| 3481 | 3691 | .array_type_sentinel, |
| 3482 | | .PtrType, |
| 3483 | | .slice_type, |
| 3692 | .ptr_type_aligned, |
| 3693 | .ptr_type_sentinel, |
| 3694 | .ptr_type, |
| 3695 | .ptr_type_bit_range, |
| 3484 | 3696 | .@"suspend", |
| 3485 | 3697 | .@"anytype", |
| 3486 | | .error_type, |
| 3487 | | .FnProto, |
| 3698 | .fn_proto_simple, |
| 3699 | .fn_proto_multi, |
| 3700 | .fn_proto_one, |
| 3701 | .fn_proto, |
| 3702 | .fn_decl, |
| 3488 | 3703 | .anyframe_type, |
| 3704 | .anyframe_literal, |
| 3489 | 3705 | .integer_literal, |
| 3490 | 3706 | .float_literal, |
| 3491 | 3707 | .enum_literal, |
| 3492 | 3708 | .string_literal, |
| 3493 | | .MultilineStringLiteral, |
| 3709 | .multiline_string_literal, |
| 3494 | 3710 | .char_literal, |
| 3495 | | .bool_literal, |
| 3711 | .true_literal, |
| 3712 | .false_literal, |
| 3496 | 3713 | .null_literal, |
| 3497 | 3714 | .undefined_literal, |
| 3498 | | .@"unreachable", |
| 3715 | .unreachable_literal, |
| 3499 | 3716 | .identifier, |
| 3500 | 3717 | .error_set_decl, |
| 3501 | | .ContainerDecl, |
| 3718 | .container_decl, |
| 3719 | .container_decl_comma, |
| 3720 | .container_decl_two, |
| 3721 | .container_decl_two_comma, |
| 3722 | .container_decl_arg, |
| 3723 | .container_decl_arg_comma, |
| 3724 | .tagged_union, |
| 3725 | .tagged_union_comma, |
| 3726 | .tagged_union_two, |
| 3727 | .tagged_union_two_comma, |
| 3728 | .tagged_union_enum_tag, |
| 3729 | .tagged_union_enum_tag_comma, |
| 3502 | 3730 | .@"asm", |
| 3731 | .asm_simple, |
| 3503 | 3732 | .add, |
| 3504 | 3733 | .add_wrap, |
| 3505 | 3734 | .array_cat, |
| ... | ... | @@ -3537,14 +3766,16 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { |
| 3537 | 3766 | .mod, |
| 3538 | 3767 | .mul, |
| 3539 | 3768 | .mul_wrap, |
| 3540 | | .range, |
| 3541 | | .period, |
| 3769 | .switch_range, |
| 3770 | .field_access, |
| 3542 | 3771 | .sub, |
| 3543 | 3772 | .sub_wrap, |
| 3544 | 3773 | .slice, |
| 3774 | .slice_open, |
| 3775 | .slice_sentinel, |
| 3545 | 3776 | .deref, |
| 3546 | 3777 | .array_access, |
| 3547 | | .block, |
| 3778 | .error_value, |
| 3548 | 3779 | .while_simple, // This variant cannot have an else expression. |
| 3549 | 3780 | .while_cont, // This variant cannot have an else expression. |
| 3550 | 3781 | .for_simple, // This variant cannot have an else expression. |
| ... | ... | @@ -3558,18 +3789,30 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { |
| 3558 | 3789 | .@"comptime", |
| 3559 | 3790 | .@"nosuspend", |
| 3560 | 3791 | .unwrap_optional, |
| 3561 | | => node = datas[node].lhs, |
| 3792 | => node = node_datas[node].lhs, |
| 3562 | 3793 | |
| 3563 | 3794 | // Forward the question to the RHS sub-expression. |
| 3564 | 3795 | .@"catch", |
| 3565 | 3796 | .@"orelse", |
| 3566 | | => node = datas[node].rhs, |
| 3797 | => node = node_datas[node].rhs, |
| 3567 | 3798 | |
| 3568 | 3799 | // True because these are exactly the expressions we need memory locations for. |
| 3569 | | .ArrayInitializer, |
| 3570 | | .ArrayInitializerDot, |
| 3571 | | .StructInitializer, |
| 3572 | | .StructInitializerDot, |
| 3800 | .array_init_one, |
| 3801 | .array_init_one_comma, |
| 3802 | .array_init_dot_two, |
| 3803 | .array_init_dot_two_comma, |
| 3804 | .array_init_dot, |
| 3805 | .array_init_dot_comma, |
| 3806 | .array_init, |
| 3807 | .array_init_comma, |
| 3808 | .struct_init_one, |
| 3809 | .struct_init_one_comma, |
| 3810 | .struct_init_dot_two, |
| 3811 | .struct_init_dot_two_comma, |
| 3812 | .struct_init_dot, |
| 3813 | .struct_init_dot_comma, |
| 3814 | .struct_init, |
| 3815 | .struct_init_comma, |
| 3573 | 3816 | => return true, |
| 3574 | 3817 | |
| 3575 | 3818 | // True because depending on comptime conditions, sub-expressions |
| ... | ... | @@ -3578,6 +3821,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { |
| 3578 | 3821 | .@"if", // This variant always has an else expression. |
| 3579 | 3822 | .@"for", // This variant always has an else expression. |
| 3580 | 3823 | .@"switch", |
| 3824 | .switch_comma, |
| 3581 | 3825 | .call_one, |
| 3582 | 3826 | .call_one_comma, |
| 3583 | 3827 | .async_call_one, |
| ... | ... | @@ -3588,10 +3832,10 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { |
| 3588 | 3832 | .async_call_comma, |
| 3589 | 3833 | => return true, |
| 3590 | 3834 | |
| 3591 | | block_two, |
| 3592 | | block_two_semicolon, |
| 3593 | | block, |
| 3594 | | block_semicolon, |
| 3835 | .block_two, |
| 3836 | .block_two_semicolon, |
| 3837 | .block, |
| 3838 | .block_semicolon, |
| 3595 | 3839 | => { |
| 3596 | 3840 | const lbrace = main_tokens[node]; |
| 3597 | 3841 | if (token_tags[lbrace - 1] == .colon) { |
| ... | ... | @@ -3603,7 +3847,11 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { |
| 3603 | 3847 | } |
| 3604 | 3848 | }, |
| 3605 | 3849 | |
| 3606 | | .builtin_call => { |
| 3850 | .builtin_call, |
| 3851 | .builtin_call_comma, |
| 3852 | .builtin_call_two, |
| 3853 | .builtin_call_two_comma, |
| 3854 | => { |
| 3607 | 3855 | const builtin_token = main_tokens[node]; |
| 3608 | 3856 | const builtin_name = tree.tokenSlice(builtin_token); |
| 3609 | 3857 | // If the builtin is an invalid name, we don't cause an error here; instead |
| ... | ... | @@ -3661,7 +3909,6 @@ fn rvalueVoid( |
| 3661 | 3909 | result: void, |
| 3662 | 3910 | ) InnerError!*zir.Inst { |
| 3663 | 3911 | const tree = scope.tree(); |
| 3664 | | const node_datas = tree.nodes.items(.data); |
| 3665 | 3912 | const main_tokens = tree.nodes.items(.main_token); |
| 3666 | 3913 | const src = tree.tokens.items(.start)[tree.firstToken(node)]; |
| 3667 | 3914 | const void_inst = try addZIRInstConst(mod, scope, src, .{ |
| ... | ... | @@ -3765,7 +4012,7 @@ pub fn addZirInstT( |
| 3765 | 4012 | src: usize, |
| 3766 | 4013 | comptime T: type, |
| 3767 | 4014 | tag: zir.Inst.Tag, |
| 3768 | | positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type, |
| 4015 | positionals: std.meta.fieldInfo(T, .positionals).field_type, |
| 3769 | 4016 | ) !*T { |
| 3770 | 4017 | const gen_zir = scope.getGenZIR(); |
| 3771 | 4018 | try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); |