authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-17 20:59:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-17 20:59:21-07:00
logc66481f9bcc5c08b92ccfd5d38d9d72be83479c0
treecfdd4f52046d5b29a2f97078883592a44ddf1ec2
parent4b226286e88d9b10f720c949d1241299af0d6c3f

astgen: finish updating expressions to new mem layout

Now all that is left is compile errors and whatever regressions this branch introduced.

6 files changed, 455 insertions(+), 325 deletions(-)

lib/std/zig/ast.zig+4-3
...@@ -1528,8 +1528,9 @@ pub const Tree = struct {...@@ -1528,8 +1528,9 @@ pub const Tree = struct {
15281528
1529 pub fn switchCaseOne(tree: Tree, node: Node.Index) full.SwitchCase {1529 pub fn switchCaseOne(tree: Tree, node: Node.Index) full.SwitchCase {
1530 const data = &tree.nodes.items(.data)[node];1530 const data = &tree.nodes.items(.data)[node];
1531 const values: *[1]Node.Index = &data.lhs;
1531 return tree.fullSwitchCase(.{1532 return tree.fullSwitchCase(.{
1532 .values = if (data.lhs == 0) &.{} else @ptrCast([*]Node.Index, &data.lhs)[0..1],1533 .values = if (data.lhs == 0) values[0..0] else values[0..1],
1533 .arrow_token = tree.nodes.items(.main_token)[node],1534 .arrow_token = tree.nodes.items(.main_token)[node],
1534 .target_expr = data.rhs,1535 .target_expr = data.rhs,
1535 });1536 });
...@@ -2532,8 +2533,8 @@ pub const Node = struct {...@@ -2532,8 +2533,8 @@ pub const Node = struct {
2532 @"defer",2533 @"defer",
2533 /// lhs catch rhs2534 /// lhs catch rhs
2534 /// lhs catch |err| rhs2535 /// lhs catch |err| rhs
2535 /// main_token is the catch2536 /// main_token is the `catch` keyword.
2536 /// payload is determined by looking at the prev tokens before rhs.2537 /// payload is determined by looking at the next token after the `catch` keyword.
2537 @"catch",2538 @"catch",
2538 /// `lhs.a`. main_token is the dot. rhs is the identifier token index.2539 /// `lhs.a`. main_token is the dot. rhs is the identifier token index.
2539 field_access,2540 field_access,
lib/std/zig/render.zig+3-3
...@@ -416,9 +416,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -416,9 +416,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
416 return renderToken(ais, tree, rbracket, space); // ]416 return renderToken(ais, tree, rbracket, space); // ]
417 },417 },
418418
419 .slice_open => try renderSlice(ais, tree, tree.sliceOpen(node), space),419 .slice_open => return renderSlice(ais, tree, tree.sliceOpen(node), space),
420 .slice => try renderSlice(ais, tree, tree.slice(node), space),420 .slice => return renderSlice(ais, tree, tree.slice(node), space),
421 .slice_sentinel => try renderSlice(ais, tree, tree.sliceSentinel(node), space),421 .slice_sentinel => return renderSlice(ais, tree, tree.sliceSentinel(node), space),
422422
423 .deref => {423 .deref => {
424 try renderExpression(ais, tree, datas[node].lhs, .none);424 try renderExpression(ais, tree, datas[node].lhs, .none);
src/Module.zig+8-8
...@@ -1163,16 +1163,16 @@ fn astgenAndSemaFn(...@@ -1163,16 +1163,16 @@ fn astgenAndSemaFn(
1163 }1163 }
1164 assert(param_type_i == param_count);1164 assert(param_type_i == param_count);
1165 }1165 }
1166 if (fn_proto.lib_name) |lib_name| blk: {1166 if (fn_proto.lib_name) |lib_name_token| blk: {
1167 // TODO call std.zig.parseStringLiteral1167 // TODO call std.zig.parseStringLiteral
1168 const lib_name_str = mem.trim(u8, tree.tokenSlice(lib_name), "\"");1168 const lib_name_str = mem.trim(u8, tree.tokenSlice(lib_name_token), "\"");
1169 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});1169 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
1170 const target = mod.comp.getTarget();1170 const target = mod.comp.getTarget();
1171 if (target_util.is_libc_lib_name(target, lib_name_str)) {1171 if (target_util.is_libc_lib_name(target, lib_name_str)) {
1172 if (!mod.comp.bin_file.options.link_libc) {1172 if (!mod.comp.bin_file.options.link_libc) {
1173 return mod.failTok(1173 return mod.failTok(
1174 &fn_type_scope.base,1174 &fn_type_scope.base,
1175 lib_name,1175 lib_name_token,
1176 "dependency on libc must be explicitly specified in the build command",1176 "dependency on libc must be explicitly specified in the build command",
1177 .{},1177 .{},
1178 );1178 );
...@@ -1183,7 +1183,7 @@ fn astgenAndSemaFn(...@@ -1183,7 +1183,7 @@ fn astgenAndSemaFn(
1183 if (!mod.comp.bin_file.options.link_libcpp) {1183 if (!mod.comp.bin_file.options.link_libcpp) {
1184 return mod.failTok(1184 return mod.failTok(
1185 &fn_type_scope.base,1185 &fn_type_scope.base,
1186 lib_name,1186 lib_name_token,
1187 "dependency on libc++ must be explicitly specified in the build command",1187 "dependency on libc++ must be explicitly specified in the build command",
1188 .{},1188 .{},
1189 );1189 );
...@@ -1193,17 +1193,17 @@ fn astgenAndSemaFn(...@@ -1193,17 +1193,17 @@ fn astgenAndSemaFn(
1193 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {1193 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
1194 return mod.failTok(1194 return mod.failTok(
1195 &fn_type_scope.base,1195 &fn_type_scope.base,
1196 lib_name,1196 lib_name_token,
1197 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",1197 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
1198 .{ lib_name, lib_name },1198 .{ lib_name_str, lib_name_str },
1199 );1199 );
1200 }1200 }
1201 mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {1201 mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
1202 return mod.failTok(1202 return mod.failTok(
1203 &fn_type_scope.base,1203 &fn_type_scope.base,
1204 lib_name,1204 lib_name_token,
1205 "unable to add link lib '{s}': {s}",1205 "unable to add link lib '{s}': {s}",
1206 .{ lib_name, @errorName(err) },1206 .{ lib_name_str, @errorName(err) },
1207 );1207 );
1208 };1208 };
1209 }1209 }
src/astgen.zig+421-300
...@@ -327,6 +327,15 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In...@@ -327,6 +327,15 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
327 .while_cont => return whileExpr(mod, scope, tree.whileCont(node)),327 .while_cont => return whileExpr(mod, scope, tree.whileCont(node)),
328 .@"while" => return whileExpr(mod, scope, rl, tree.whileFull(node)),328 .@"while" => return whileExpr(mod, scope, rl, tree.whileFull(node)),
329329
330 .for_simple => return forExpr(mod, scope, rl, tree.forSimple(node)),
331 .@"for" => return forExpr(mod, scope, rl, tree.forFull(node)),
332
333 // TODO handling these separately would actually be simpler & have fewer branches
334 // once we have a ZIR instruction for each of these 3 cases.
335 .slice_open => return sliceExpr(mod, scope, rl, tree.sliceOpen(node)),
336 .slice => return sliceExpr(mod, scope, rl, tree.slice(node)),
337 .slice_sentinel => return sliceExpr(mod, scope, rl, tree.sliceSentinel(node)),
338
330 .deref => {339 .deref => {
331 const lhs = try expr(mod, scope, .none, node_datas[node].lhs);340 const lhs = try expr(mod, scope, .none, node_datas[node].lhs);
332 const src = token_starts[main_tokens[node]];341 const src = token_starts[main_tokens[node]];
...@@ -402,51 +411,122 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In...@@ -402,51 +411,122 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
402 const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];411 const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
403 return blockExpr(mod, scope, rl, node, statements);412 return blockExpr(mod, scope, rl, node, statements);
404 },413 },
405414 .enum_literal => {
406 .@"break" => return rvalue(mod, scope, rl, try breakExpr(mod, scope, node)),415 const ident_token = main_tokens[node];
407 .@"continue" => return rvalue(mod, scope, rl, try continueExpr(mod, scope, node)),416 const name = try mod.identifierTokenString(scope, ident_token);
408 .grouped_expression => return expr(mod, scope, rl, node.expr),417 const src = token_starts[ident_token];
409 .array_type => return rvalue(mod, scope, rl, try arrayType(mod, scope, node)),418 const result = try addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});
410 .array_type_sentinel => return rvalue(mod, scope, rl, try arrayTypeSentinel(mod, scope, node)),419 return rvalue(mod, scope, rl, result);
411 .enum_literal => return rvalue(mod, scope, rl, try enumLiteral(mod, scope, node)),420 },
412 .char_literal => return rvalue(mod, scope, rl, try charLiteral(mod, scope, node)),421 .error_union => {
413 .slice_type => return rvalue(mod, scope, rl, try sliceType(mod, scope, node)),422 const error_set = try typeExpr(mod, scope, node_datas[node].lhs);
414 .error_union => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node, .error_union_type)),423 const payload = try typeExpr(mod, scope, node_datas[node].rhs);
415 .merge_error_sets => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node, .merge_error_sets)),424 const src = token_starts[main_tokens[node]];
416 .anyframe_type => return rvalue(mod, scope, rl, try anyFrameType(mod, scope, node)),425 const result = try addZIRBinOp(mod, scope, src, .error_union_type, error_set, payload);
417 .error_set_decl => return rvalue(mod, scope, rl, try errorSetDecl(mod, scope, node)),426 return rvalue(mod, scope, rl, result);
418 .error_type => return rvalue(mod, scope, rl, try errorType(mod, scope, node)),427 },
419 .@"for" => return forExpr(mod, scope, rl, node),428 .merge_error_sets => {
429 const lhs = try typeExpr(mod, scope, node_datas[node].lhs);
430 const rhs = try typeExpr(mod, scope, node_datas[node].rhs);
431 const src = token_starts[main_tokens[node]];
432 const result = try addZIRBinOp(mod, scope, src, .merge_error_sets, lhs, rhs);
433 return rvalue(mod, scope, rl, result);
434 },
435 .anyframe_literal => {
436 const main_token = main_tokens[node];
437 const src = token_starts[main_token];
438 const result = try addZIRInstConst(mod, scope, src, .{
439 .ty = Type.initTag(.type),
440 .val = Value.initTag(.anyframe_type),
441 });
442 return rvalue(mod, scope, rl, result);
443 },
444 .anyframe_type => {
445 const src = token_starts[node_datas[node].lhs];
446 const return_type = try typeExpr(mod, scope, node_datas[node].rhs);
447 const result = try addZIRUnOp(mod, scope, src, .anyframe_type, return_type);
448 return rvalue(mod, scope, rl, result);
449 },
450 .@"catch" => {
451 const catch_token = main_tokens[node];
452 const payload_token: ?TokenIndex = if (token_tags[catch_token + 1] == .pipe)
453 catch_token + 2
454 else
455 null;
456 switch (rl) {
457 .ref => return orelseCatchExpr(
458 mod,
459 scope,
460 rl,
461 node_datas[node].lhs,
462 main_tokens[node],
463 .is_err_ptr,
464 .err_union_payload_unsafe_ptr,
465 .err_union_code_ptr,
466 node_datas[node].rhs,
467 payload_token,
468 ),
469 else => return orelseCatchExpr(
470 mod,
471 scope,
472 rl,
473 node_datas[node].lhs,
474 main_tokens[node],
475 .is_err,
476 .err_union_payload_unsafe,
477 .err_union_code,
478 node_datas[node].rhs,
479 payload_token,
480 ),
481 }
482 },
483 .@"orelse" => switch (rl) {
484 .ref => return orelseCatchExpr(
485 mod,
486 scope,
487 rl,
488 node_datas[node].lhs,
489 main_tokens[node],
490 .is_null_ptr,
491 .optional_payload_unsafe_ptr,
492 undefined,
493 node_datas[node].rhs,
494 null,
495 ),
496 else => return orelseCatchExpr(
497 mod,
498 scope,
499 rl,
500 node_datas[node].lhs,
501 main_tokens[node],
502 .is_null,
503 .optional_payload_unsafe,
504 undefined,
505 node_datas[node].rhs,
506 null,
507 ),
508 },
509 .@"break" => return breakExpr(mod, scope, rl, node),
510 .@"continue" => return continueExpr(mod, scope, rl, node),
511 .grouped_expression => return expr(mod, scope, rl, node_datas[node].lhs),
512 .array_type => return arrayType(mod, scope, rl, node),
513 .array_type_sentinel => return arrayTypeSentinel(mod, scope, rl, node),
514 .char_literal => return charLiteral(mod, scope, rl, node),
515 .error_set_decl => return errorSetDecl(mod, scope, rl, node),
420 .array_access => return arrayAccess(mod, scope, rl, node),516 .array_access => return arrayAccess(mod, scope, rl, node),
421 .slice => return rvalue(mod, scope, rl, try sliceExpr(mod, scope, node)),517 .@"comptime" => return comptimeExpr(mod, scope, rl, node_datas[node].lhs),
422 .@"catch" => return catchExpr(mod, scope, rl, node),518 .@"switch", .switch_comma => return switchExpr(mod, scope, rl, node),
423 .@"comptime" => return comptimeKeyword(mod, scope, rl, node),
424 .@"orelse" => return orelseExpr(mod, scope, rl, node),
425 .@"switch" => return switchExpr(mod, scope, rl, node),
426 .ContainerDecl => return containerDecl(mod, scope, rl, node),
427519
428 .@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}),520 .@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}),
429 .@"await" => return mod.failNode(scope, node, "TODO implement astgen.expr for .await", .{}),521 .@"await" => return mod.failNode(scope, node, "TODO implement astgen.expr for .await", .{}),
430 .@"resume" => return mod.failNode(scope, node, "TODO implement astgen.expr for .resume", .{}),522 .@"resume" => return mod.failNode(scope, node, "TODO implement astgen.expr for .resume", .{}),
431 .@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),523 .@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
432 .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),
433 .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}),
434 .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}),
435 .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}),
436 .@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}),524 .@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}),
437 .@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}),525 .@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}),
438 .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
439 .@"nosuspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .nosuspend", .{}),526 .@"nosuspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .nosuspend", .{}),
440 }527 }
441}528}
442529
443fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.@"comptime") InnerError!*zir.Inst {
444 const tracy = trace(@src());
445 defer tracy.end();
446
447 return comptimeExpr(mod, scope, rl, node.expr);
448}
449
450pub fn comptimeExpr(530pub fn comptimeExpr(
451 mod: *Module,531 mod: *Module,
452 parent_scope: *Scope,532 parent_scope: *Scope,
...@@ -493,7 +573,12 @@ pub fn comptimeExpr(...@@ -493,7 +573,12 @@ pub fn comptimeExpr(
493 return &block.base;573 return &block.base;
494}574}
495575
496fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst {576fn breakExpr(
577 mod: *Module,
578 parent_scope: *Scope,
579 rl: ResultLoc,
580 node: ast.Node.Index,
581) InnerError!*zir.Inst {
497 const tree = parent_scope.tree();582 const tree = parent_scope.tree();
498 const node_datas = tree.nodes.items(.data);583 const node_datas = tree.nodes.items(.data);
499 const main_tokens = tree.nodes.items(.main_token);584 const main_tokens = tree.nodes.items(.main_token);
...@@ -524,9 +609,10 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro...@@ -524,9 +609,10 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro
524 };609 };
525610
526 if (rhs == 0) {611 if (rhs == 0) {
527 return addZirInstTag(mod, parent_scope, src, .break_void, .{612 const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{
528 .block = block_inst,613 .block = block_inst,
529 });614 });
615 return rvalue(mod, parent_scope, rl, result);
530 }616 }
531 gen_zir.break_count += 1;617 gen_zir.break_count += 1;
532 const prev_rvalue_rl_count = gen_zir.rvalue_rl_count;618 const prev_rvalue_rl_count = gen_zir.rvalue_rl_count;
...@@ -547,7 +633,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro...@@ -547,7 +633,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro
547 try gen_zir.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst);633 try gen_zir.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst);
548 }634 }
549 }635 }
550 return br;636 return rvalue(mod, parent_scope, rl, br);
551 },637 },
552 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,638 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
553 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,639 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
...@@ -561,7 +647,12 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro...@@ -561,7 +647,12 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro
561 }647 }
562}648}
563649
564fn continueExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst {650fn continueExpr(
651 mod: *Module,
652 parent_scope: *Scope,
653 rl: ResultLoc,
654 node: ast.Node.Index,
655) InnerError!*zir.Inst {
565 const tree = parent_scope.tree();656 const tree = parent_scope.tree();
566 const node_datas = tree.nodes.items(.data);657 const node_datas = tree.nodes.items(.data);
567 const main_tokens = tree.nodes.items(.main_token);658 const main_tokens = tree.nodes.items(.main_token);
...@@ -590,9 +681,10 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerE...@@ -590,9 +681,10 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerE
590 continue;681 continue;
591 }682 }
592683
593 return addZirInstTag(mod, parent_scope, src, .break_void, .{684 const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{
594 .block = continue_block,685 .block = continue_block,
595 });686 });
687 return rvalue(mod, parent_scope, rl, result);
596 },688 },
597 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,689 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
598 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,690 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
...@@ -1083,12 +1175,6 @@ fn negation(...@@ -1083,12 +1175,6 @@ fn negation(
1083 return addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs);1175 return addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs);
1084}1176}
10851177
1086fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.slice_type) InnerError!*zir.Inst {
1087 const tree = scope.tree();
1088 const src = token_starts[node.op_token];
1089 return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice);
1090}
1091
1092fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst {1178fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst {
1093 const tree = scope.tree();1179 const tree = scope.tree();
1094 const src = token_starts[node.op_token];1180 const src = token_starts[node.op_token];
...@@ -1146,70 +1232,54 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo,...@@ -1146,70 +1232,54 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo,
1146 return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);1232 return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);
1147}1233}
11481234
1149fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.array_type) !*zir.Inst {1235fn arrayType(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst {
1150 const tree = scope.tree();1236 const tree = scope.tree();
1151 const src = token_starts[node.op_token];1237 const main_tokens = tree.nodes.items(.main_token);
1238 const node_datas = tree.nodes.items(.data);
1239 const src = token_starts[main_tokens[node]];
1152 const usize_type = try addZIRInstConst(mod, scope, src, .{1240 const usize_type = try addZIRInstConst(mod, scope, src, .{
1153 .ty = Type.initTag(.type),1241 .ty = Type.initTag(.type),
1154 .val = Value.initTag(.usize_type),1242 .val = Value.initTag(.usize_type),
1155 });1243 });
1244 const len_node = node_datas[node].lhs;
1245 const elem_node = node_datas[node].rhs;
1246 if (len_node == 0) {
1247 const elem_type = try typeExpr(mod, scope, elem_node);
1248 const result = try addZIRUnOp(mod, scope, src, .mut_slice_type, elem_type);
1249 return rvalue(mod, scope, rl, result);
1250 } else {
1251 // TODO check for [_]T
1252 const len = try expr(mod, scope, .{ .ty = usize_type }, len_node);
1253 const elem_type = try typeExpr(mod, scope, elem_node);
11561254
1157 // TODO check for [_]T1255 const result = try addZIRBinOp(mod, scope, src, .array_type, len, elem_type);
1158 const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);1256 return rvalue(mod, scope, rl, result);
1159 const elem_type = try typeExpr(mod, scope, node.rhs);1257 }
1160
1161 return addZIRBinOp(mod, scope, src, .array_type, len, elem_type);
1162}1258}
11631259
1164fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.array_type_sentinel) !*zir.Inst {1260fn arrayTypeSentinel(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst {
1165 const tree = scope.tree();1261 const tree = scope.tree();
1166 const src = token_starts[node.op_token];1262 const main_tokens = tree.nodes.items(.main_token);
1263 const len_node = node_datas[node].lhs;
1264 const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel);
1265 const src = token_starts[main_tokens[node]];
1167 const usize_type = try addZIRInstConst(mod, scope, src, .{1266 const usize_type = try addZIRInstConst(mod, scope, src, .{
1168 .ty = Type.initTag(.type),1267 .ty = Type.initTag(.type),
1169 .val = Value.initTag(.usize_type),1268 .val = Value.initTag(.usize_type),
1170 });1269 });
11711270
1172 // TODO check for [_]T1271 // TODO check for [_]T
1173 const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);1272 const len = try expr(mod, scope, .{ .ty = usize_type }, len_node);
1174 const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel);1273 const sentinel_uncasted = try expr(mod, scope, .none, extra.sentinel);
1175 const elem_type = try typeExpr(mod, scope, node.rhs);1274 const elem_type = try typeExpr(mod, scope, extra.elem_type);
1176 const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted);1275 const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted);
11771276
1178 return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{1277 const result = try addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{
1179 .len = len,1278 .len = len,
1180 .sentinel = sentinel,1279 .sentinel = sentinel,
1181 .elem_type = elem_type,1280 .elem_type = elem_type,
1182 }, .{});1281 }, .{});
1183}1282 return rvalue(mod, scope, rl, result);
1184
1185fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.anyframe_type) InnerError!*zir.Inst {
1186 const tree = scope.tree();
1187 const src = token_starts[node.anyframe_token];
1188 if (node.result) |some| {
1189 const return_type = try typeExpr(mod, scope, some.return_type);
1190 return addZIRUnOp(mod, scope, src, .anyframe_type, return_type);
1191 } else {
1192 return addZIRInstConst(mod, scope, src, .{
1193 .ty = Type.initTag(.type),
1194 .val = Value.initTag(.anyframe_type),
1195 });
1196 }
1197}
1198
1199fn typeInixOp(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst {
1200 const tree = scope.tree();
1201 const src = token_starts[node.op_token];
1202 const error_set = try typeExpr(mod, scope, node.lhs);
1203 const payload = try typeExpr(mod, scope, node.rhs);
1204 return addZIRBinOp(mod, scope, src, op_inst_tag, error_set, payload);
1205}
1206
1207fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.enum_literal) !*zir.Inst {
1208 const tree = scope.tree();
1209 const src = token_starts[node.name];
1210 const name = try mod.identifierTokenString(scope, node.name);
1211
1212 return addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});
1213}1283}
12141284
1215fn containerField(1285fn containerField(
...@@ -1394,85 +1464,50 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con...@@ -1394,85 +1464,50 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
1394 }1464 }
1395}1465}
13961466
1397fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.error_set_decl) InnerError!*zir.Inst {1467fn errorSetDecl(
1468 mod: *Module,
1469 scope: *Scope,
1470 rl: ResultLoc,
1471 node: ast.Node.Index,
1472) InnerError!*zir.Inst {
1398 const tree = scope.tree();1473 const tree = scope.tree();
1399 const src = token_starts[node.error_token];1474 const main_tokens = tree.nodes.items(.main_token);
1400 const decls = node.decls();1475 const token_tags = tree.tokens.items(.tag);
1401 const fields = try scope.arena().alloc([]const u8, decls.len);
1402
1403 for (decls) |decl, i| {
1404 const tag = decl.castTag(.ErrorTag).?;
1405 fields[i] = try mod.identifierTokenString(scope, tag.name_token);
1406 }
1407
1408 return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{});
1409}
14101476
1411fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {1477 // Count how many fields there are.
1412 const tree = scope.tree();1478 const error_token = main_tokens[node];
1413 const src = token_starts[node.token];1479 const count: usize = count: {
1414 return addZIRInstConst(mod, scope, src, .{1480 var tok_i = error_token + 2;
1415 .ty = Type.initTag(.type),1481 var count: usize = 0;
1416 .val = Value.initTag(.anyerror_type),1482 while (true) : (tok_i += 1) {
1417 });1483 switch (token_tags[tok_i]) {
1418}1484 .doc_comment, .comma => {},
1485 .identifier => count += 1,
1486 .r_paren => break :count count,
1487 else => unreachable,
1488 }
1489 } else unreachable; // TODO should not need else unreachable here
1490 };
14191491
1420fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.@"catch") InnerError!*zir.Inst {1492 const fields = try scope.arena().alloc([]const u8, count);
1421 switch (rl) {1493 {
1422 .ref => return orelseCatchExpr(1494 var tok_i = error_token + 2;
1423 mod,1495 var field_i: usize = 0;
1424 scope,1496 while (true) : (tok_i += 1) {
1425 rl,1497 switch (token_tags[tok_i]) {
1426 node.lhs,1498 .doc_comment, .comma => {},
1427 node.op_token,1499 .identifier => {
1428 .is_err_ptr,1500 fields[field_i] = try mod.identifierTokenString(scope, tok_i);
1429 .err_union_payload_unsafe_ptr,1501 field_i += 1;
1430 .err_union_code_ptr,1502 },
1431 node.rhs,1503 .r_paren => break,
1432 node.payload,1504 else => unreachable,
1433 ),1505 }
1434 else => return orelseCatchExpr(1506 }
1435 mod,
1436 scope,
1437 rl,
1438 node.lhs,
1439 node.op_token,
1440 .is_err,
1441 .err_union_payload_unsafe,
1442 .err_union_code,
1443 node.rhs,
1444 node.payload,
1445 ),
1446 }
1447}
1448
1449fn orelseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
1450 switch (rl) {
1451 .ref => return orelseCatchExpr(
1452 mod,
1453 scope,
1454 rl,
1455 node.lhs,
1456 node.op_token,
1457 .is_null_ptr,
1458 .optional_payload_unsafe_ptr,
1459 undefined,
1460 node.rhs,
1461 null,
1462 ),
1463 else => return orelseCatchExpr(
1464 mod,
1465 scope,
1466 rl,
1467 node.lhs,
1468 node.op_token,
1469 .is_null,
1470 .optional_payload_unsafe,
1471 undefined,
1472 node.rhs,
1473 null,
1474 ),
1475 }1507 }
1508 const src = token_starts[error_token];
1509 const result = try addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{});
1510 return rvalue(mod, scope, rl, result);
1476}1511}
14771512
1478fn orelseCatchExpr(1513fn orelseCatchExpr(
...@@ -1681,55 +1716,78 @@ pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) I...@@ -1681,55 +1716,78 @@ pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) I
1681 }1716 }
1682}1717}
16831718
1684fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.array_access) InnerError!*zir.Inst {1719fn arrayAccess(
1720 mod: *Module,
1721 scope: *Scope,
1722 rl: ResultLoc,
1723 node: ast.Node.Index,
1724) InnerError!*zir.Inst {
1685 const tree = scope.tree();1725 const tree = scope.tree();
1686 const src = token_starts[node.rtoken];1726 const main_tokens = tree.nodes.items(.main_token);
1727 const token_starts = tree.tokens.items(.start);
1728 const src = token_starts[main_tokens[node]];
1687 const usize_type = try addZIRInstConst(mod, scope, src, .{1729 const usize_type = try addZIRInstConst(mod, scope, src, .{
1688 .ty = Type.initTag(.type),1730 .ty = Type.initTag(.type),
1689 .val = Value.initTag(.usize_type),1731 .val = Value.initTag(.usize_type),
1690 });1732 });
1691 const index_rl: ResultLoc = .{ .ty = usize_type };1733 const index_rl: ResultLoc = .{ .ty = usize_type };
16921734 switch (rl) {
1693 if (rl == .ref) {1735 .ref => return addZirInstTag(mod, scope, src, .elem_ptr, .{
1694 return addZirInstTag(mod, scope, src, .elem_ptr, .{1736 .array = try expr(mod, scope, .ref, node_datas[node].lhs),
1695 .array = try expr(mod, scope, .ref, node.lhs),1737 .index = try expr(mod, scope, index_rl, node_datas[node].rhs),
1696 .index = try expr(mod, scope, index_rl, node.index_expr),1738 }),
1697 });1739 else => return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{
1740 .array = try expr(mod, scope, .none, node_datas[node].lhs),
1741 .index = try expr(mod, scope, index_rl, node_datas[node].rhs),
1742 })),
1698 }1743 }
1699 return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{
1700 .array = try expr(mod, scope, .none, node.lhs),
1701 .index = try expr(mod, scope, index_rl, node.index_expr),
1702 }));
1703}1744}
17041745
1705fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.slice) InnerError!*zir.Inst {1746fn sliceExpr(
1747 mod: *Module,
1748 scope: *Scope,
1749 rl: ResultLoc,
1750 slice: ast.full.Slice,
1751) InnerError!*zir.Inst {
1706 const tree = scope.tree();1752 const tree = scope.tree();
1707 const src = token_starts[node.rtoken];1753 const token_starts = tree.tokens.items(.start);
1754 const src = token_starts[slice.ast.lbracket];
17081755
1709 const usize_type = try addZIRInstConst(mod, scope, src, .{1756 const usize_type = try addZIRInstConst(mod, scope, src, .{
1710 .ty = Type.initTag(.type),1757 .ty = Type.initTag(.type),
1711 .val = Value.initTag(.usize_type),1758 .val = Value.initTag(.usize_type),
1712 });1759 });
17131760
1714 const array_ptr = try expr(mod, scope, .ref, node.lhs);1761 const array_ptr = try expr(mod, scope, .ref, slice.ast.sliced);
1715 const start = try expr(mod, scope, .{ .ty = usize_type }, node.start);1762 const start = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.start);
17161763
1717 if (node.end == null and node.sentinel == null) {1764 if (slice.ast.sentinel == 0) {
1718 return try addZIRBinOp(mod, scope, src, .slice_start, array_ptr, start);1765 if (slice.ast.end == 0) {
1766 const result = try addZIRBinOp(mod, scope, src, .slice_start, array_ptr, start);
1767 return rvalue(mod, scope, rl, result);
1768 } else {
1769 const end = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.end);
1770 // TODO a ZIR slice_open instruction
1771 const result = try addZIRInst(mod, scope, src, zir.Inst.Slice, .{
1772 .array_ptr = array_ptr,
1773 .start = start,
1774 }, .{ .end = end });
1775 return rvalue(mod, scope, rl, result);
1776 }
1719 }1777 }
17201778
1721 const end = if (node.end) |end| try expr(mod, scope, .{ .ty = usize_type }, end) else null;1779 const end = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.end);
1722 // we could get the child type here, but it is easier to just do it in semantic analysis.1780 // TODO pass the proper result loc to this expression using a ZIR instruction
1723 const sentinel = if (node.sentinel) |sentinel| try expr(mod, scope, .none, sentinel) else null;1781 // "get the child element type for a slice target".
17241782 const sentinel = try expr(mod, scope, .none, slice.ast.sentinel);
1725 return try addZIRInst(1783 const result = try addZIRInst(mod, scope, src, zir.Inst.Slice, .{
1726 mod,1784 .array_ptr = array_ptr,
1727 scope,1785 .start = start,
1728 src,1786 }, .{
1729 zir.Inst.Slice,1787 .end = end,
1730 .{ .array_ptr = array_ptr, .start = start },1788 .sentinel = sentinel,
1731 .{ .end = end, .sentinel = sentinel },1789 });
1732 );1790 return rvalue(mod, scope, rl, result);
1733}1791}
17341792
1735fn simpleBinOp(1793fn simpleBinOp(
...@@ -2070,7 +2128,6 @@ fn whileExpr(...@@ -2070,7 +2128,6 @@ fn whileExpr(
2070 };2128 };
2071 defer then_scope.instructions.deinit(mod.gpa);2129 defer then_scope.instructions.deinit(mod.gpa);
20722130
2073 // declare payload to the then_scope
2074 const then_sub_scope = &then_scope.base;2131 const then_sub_scope = &then_scope.base;
20752132
2076 loop_scope.break_count += 1;2133 loop_scope.break_count += 1;
...@@ -2101,7 +2158,7 @@ fn whileExpr(...@@ -2101,7 +2158,7 @@ fn whileExpr(
21012158
2102 if (loop_scope.label) |some| {2159 if (loop_scope.label) |some| {
2103 if (!some.used) {2160 if (!some.used) {
2104 return mod.fail(scope, token_starts[some.token], "unused while label", .{});2161 return mod.fail(scope, token_starts[some.token], "unused while loop label", .{});
2105 }2162 }
2106 }2163 }
2107 return finishThenElseBlock(2164 return finishThenElseBlock(
...@@ -2126,20 +2183,21 @@ fn forExpr(...@@ -2126,20 +2183,21 @@ fn forExpr(
2126 mod: *Module,2183 mod: *Module,
2127 scope: *Scope,2184 scope: *Scope,
2128 rl: ResultLoc,2185 rl: ResultLoc,
2129 for_node: *ast.Node.@"for",2186 for_full: ast.full.While,
2130) InnerError!*zir.Inst {2187) InnerError!*zir.Inst {
2131 if (for_node.label) |label| {2188 if (for_full.label_token) |label_token| {
2132 try checkLabelRedefinition(mod, scope, label);2189 try checkLabelRedefinition(mod, scope, label_token);
2133 }2190 }
21342191
2135 if (for_node.inline_token) |tok|2192 if (for_full.inline_token) |inline_token| {
2136 return mod.failTok(scope, tok, "TODO inline for", .{});2193 return mod.failTok(scope, inline_token, "TODO inline for", .{});
2194 }
21372195
2138 // setup variables and constants2196 // Set up variables and constants.
2139 const tree = scope.tree();2197 const tree = scope.tree();
2140 const node_datas = tree.nodes.items(.data);2198 const node_datas = tree.nodes.items(.data);
2141 const main_tokens = tree.nodes.items(.main_token);2199 const main_tokens = tree.nodes.items(.main_token);
2142 const for_src = token_starts[for_node.for_token];2200 const for_src = token_starts[for_full.ast.while_token];
2143 const index_ptr = blk: {2201 const index_ptr = blk: {
2144 const usize_type = try addZIRInstConst(mod, scope, for_src, .{2202 const usize_type = try addZIRInstConst(mod, scope, for_src, .{
2145 .ty = Type.initTag(.type),2203 .ty = Type.initTag(.type),
...@@ -2154,8 +2212,8 @@ fn forExpr(...@@ -2154,8 +2212,8 @@ fn forExpr(
2154 _ = try addZIRBinOp(mod, scope, for_src, .store, index_ptr, zero);2212 _ = try addZIRBinOp(mod, scope, for_src, .store, index_ptr, zero);
2155 break :blk index_ptr;2213 break :blk index_ptr;
2156 };2214 };
2157 const array_ptr = try expr(mod, scope, .ref, for_node.array_expr);2215 const array_ptr = try expr(mod, scope, .ref, for_full.ast.cond_expr);
2158 const cond_src = token_starts[for_node.array_expr.firstToken()];2216 const cond_src = token_starts[tree.firstToken(for_full.ast.cond_expr)];
2159 const len = try addZIRUnOp(mod, scope, cond_src, .indexable_ptr_len, array_ptr);2217 const len = try addZIRUnOp(mod, scope, cond_src, .indexable_ptr_len, array_ptr);
21602218
2161 var loop_scope: Scope.GenZIR = .{2219 var loop_scope: Scope.GenZIR = .{
...@@ -2217,15 +2275,15 @@ fn forExpr(...@@ -2217,15 +2275,15 @@ fn forExpr(
2217 });2275 });
2218 loop_scope.break_block = for_block;2276 loop_scope.break_block = for_block;
2219 loop_scope.continue_block = cond_block;2277 loop_scope.continue_block = cond_block;
2220 if (for_node.label) |some| {2278 if (for_full.label_token) |label_token| {
2221 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{2279 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
2222 .token = some,2280 .token = label_token,
2223 .block_inst = for_block,2281 .block_inst = for_block,
2224 });2282 });
2225 }2283 }
22262284
2227 // while body2285 // while body
2228 const then_src = token_starts[for_node.body.lastToken()];2286 const then_src = token_starts[tree.lastToken(for_full.ast.then_expr)];
2229 var then_scope: Scope.GenZIR = .{2287 var then_scope: Scope.GenZIR = .{
2230 .parent = &cond_scope.base,2288 .parent = &cond_scope.base,
2231 .decl = cond_scope.decl,2289 .decl = cond_scope.decl,
...@@ -2237,23 +2295,27 @@ fn forExpr(...@@ -2237,23 +2295,27 @@ fn forExpr(
22372295
2238 var index_scope: Scope.LocalPtr = undefined;2296 var index_scope: Scope.LocalPtr = undefined;
2239 const then_sub_scope = blk: {2297 const then_sub_scope = blk: {
2240 const payload = for_node.payload.castTag(.PointerIndexPayload).?;2298 const payload_token = for_full.payload_token.?;
2241 const is_ptr = payload.ptr_token != null;2299 const ident = if (token_tags[payload_token] == .asterisk)
2242 const value_name = tree.tokenSlice(payload.value_symbol.firstToken());2300 payload_token + 1
2301 else
2302 payload_token;
2303 const is_ptr = ident != payload_token;
2304 const value_name = tree.tokenSlice(ident);
2243 if (!mem.eql(u8, value_name, "_")) {2305 if (!mem.eql(u8, value_name, "_")) {
2244 return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement for value payload", .{});2306 return mod.failNode(&then_scope.base, ident, "TODO implement for loop value payload", .{});
2245 } else if (is_ptr) {2307 } else if (is_ptr) {
2246 return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{});2308 return mod.failTok(&then_scope.base, payload_token, "pointer modifier invalid on discard", .{});
2247 }2309 }
22482310
2249 const index_symbol_node = payload.index_symbol orelse2311 const index_token = if (token_tags[ident + 1] == .comma)
2250 break :blk &then_scope.base;2312 ident + 2
22512313 else
2252 const index_name = tree.tokenSlice(tree.firstToken(index_symbol_node));
2253 if (mem.eql(u8, index_name, "_")) {
2254 break :blk &then_scope.base;2314 break :blk &then_scope.base;
2315 if (mem.eql(u8, tree.tokenSlice(index_token), "_")) {
2316 return mod.failTok(&then_scope.base, index_token, "discard of index capture not allowed; omit it instead", .{});
2255 }2317 }
2256 // TODO make this const without an extra copy?2318 const index_name = try mod.identifierTokenString(&then_scope.base, index_token);
2257 index_scope = .{2319 index_scope = .{
2258 .parent = &then_scope.base,2320 .parent = &then_scope.base,
2259 .gen_zir = &then_scope,2321 .gen_zir = &then_scope,
...@@ -2264,7 +2326,7 @@ fn forExpr(...@@ -2264,7 +2326,7 @@ fn forExpr(
2264 };2326 };
22652327
2266 loop_scope.break_count += 1;2328 loop_scope.break_count += 1;
2267 const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_node.body);2329 const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
22682330
2269 // else branch2331 // else branch
2270 var else_scope: Scope.GenZIR = .{2332 var else_scope: Scope.GenZIR = .{
...@@ -2276,18 +2338,23 @@ fn forExpr(...@@ -2276,18 +2338,23 @@ fn forExpr(
2276 };2338 };
2277 defer else_scope.instructions.deinit(mod.gpa);2339 defer else_scope.instructions.deinit(mod.gpa);
22782340
2279 var else_src: usize = undefined;2341 const else_node = for_full.ast.else_expr;
2280 const else_result: ?*zir.Inst = if (for_node.@"else") |else_node| blk: {2342 const else_info: struct { src: usize, result: ?*zir.Inst } = if (else_node != 0) blk: {
2281 else_src = token_starts[else_node.body.lastToken()];
2282 loop_scope.break_count += 1;2343 loop_scope.break_count += 1;
2283 break :blk try expr(mod, &else_scope.base, loop_scope.break_result_loc, else_node.body);2344 const sub_scope = &else_scope.base;
2284 } else blk: {2345 break :blk .{
2285 else_src = token_starts[for_node.lastToken()];2346 .src = token_starts[tree.lastToken(else_node)],
2286 break :blk null;2347 .result = try expr(mod, sub_scope, loop_scope.break_result_loc, else_node),
2287 };2348 };
2349 } else
2350 .{
2351 .src = token_starts[tree.lastToken(then_node)],
2352 .result = null,
2353 };
2354
2288 if (loop_scope.label) |some| {2355 if (loop_scope.label) |some| {
2289 if (!some.used) {2356 if (!some.used) {
2290 return mod.fail(scope, token_starts[some.token], "unused for label", .{});2357 return mod.fail(scope, token_starts[some.token], "unused for loop label", .{});
2291 }2358 }
2292 }2359 }
2293 return finishThenElseBlock(2360 return finishThenElseBlock(
...@@ -2300,41 +2367,46 @@ fn forExpr(...@@ -2300,41 +2367,46 @@ fn forExpr(
2300 &condbr.positionals.then_body,2367 &condbr.positionals.then_body,
2301 &condbr.positionals.else_body,2368 &condbr.positionals.else_body,
2302 then_src,2369 then_src,
2303 else_src,2370 else_info.src,
2304 then_result,2371 then_result,
2305 else_result,2372 else_info.result,
2306 for_block,2373 for_block,
2307 cond_block,2374 cond_block,
2308 );2375 );
2309}2376}
23102377
2311fn switchCaseUsesRef(node: *ast.Node.@"switch") bool {2378fn getRangeNode(
2312 for (node.cases()) |uncasted_case| {2379 node_tags: []const ast.Node.Tag,
2313 const case = uncasted_case.castTag(.switch_case).?;2380 node_datas: []const ast.Node.Data,
2314 const uncasted_payload = case.payload orelse continue;2381 start_node: ast.Node.Index,
2315 const payload = uncasted_payload.castTag(.PointerPayload).?;2382) ?ast.Node.Index {
2316 if (payload.ptr_token) |_| return true;2383 var node = start_node;
2317 }
2318 return false;
2319}
2320
2321fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp {
2322 var cur = node;
2323 while (true) {2384 while (true) {
2324 switch (cur.tag) {2385 switch (node_tags[node]) {
2325 .range => return @fieldParentPtr(ast.Node.SimpleInfixOp, "base", cur),2386 .switch_range => return node,
2326 .grouped_expression => cur = @fieldParentPtr(ast.Node.grouped_expression, "base", cur).expr,2387 .grouped_expression => node = node_datas[node].lhs,
2327 else => return null,2388 else => return null,
2328 }2389 }
2329 }2390 }
2330}2391}
23312392
2332fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.@"switch") InnerError!*zir.Inst {2393fn switchExpr(
2394 mod: *Module,
2395 scope: *Scope,
2396 rl: ResultLoc,
2397 switch_node: ast.Node.Index,
2398) InnerError!*zir.Inst {
2333 const tree = scope.tree();2399 const tree = scope.tree();
2334 const node_datas = tree.nodes.items(.data);2400 const node_datas = tree.nodes.items(.data);
2335 const main_tokens = tree.nodes.items(.main_token);2401 const main_tokens = tree.nodes.items(.main_token);
2336 const switch_src = token_starts[switch_node.switch_token];2402 const token_tags = tree.tokens.items(.tag);
2337 const use_ref = switchCaseUsesRef(switch_node);2403
2404 const switch_token = main_tokens[switch_node];
2405 const target_node = datas[switch_node].lhs;
2406 const extra = tree.extraData(datas[switch_node].rhs, ast.switch_node.SubRange);
2407 const case_nodes = tree.extra_data[extra.start..extra.end];
2408
2409 const switch_src = token_starts[switch_token];
23382410
2339 var block_scope: Scope.GenZIR = .{2411 var block_scope: Scope.GenZIR = .{
2340 .parent = scope,2412 .parent = scope,
...@@ -2349,18 +2421,26 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -2349,18 +2421,26 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
2349 var items = std.ArrayList(*zir.Inst).init(mod.gpa);2421 var items = std.ArrayList(*zir.Inst).init(mod.gpa);
2350 defer items.deinit();2422 defer items.deinit();
23512423
2352 // first we gather all the switch items and check else/'_' prongs2424 // First we gather all the switch items and check else/'_' prongs.
2353 var else_src: ?usize = null;2425 var else_src: ?usize = null;
2354 var underscore_src: ?usize = null;2426 var underscore_src: ?usize = null;
2355 var first_range: ?*zir.Inst = null;2427 var first_range: ?*zir.Inst = null;
2356 var simple_case_count: usize = 0;2428 var simple_case_count: usize = 0;
2357 for (switch_node.cases()) |uncasted_case| {2429 var any_payload_is_ref = false;
2358 const case = uncasted_case.castTag(.switch_case).?;2430 for (case_nodes) |case_node| {
2359 const case_src = token_starts[case.firstToken()];2431 const case = switch (node_tags[case_node]) {
2360 assert(case.items_len != 0);2432 .switch_case_one => tree.switchCaseOne(case_node),
23612433 .switch_case => tree.switchCase(case_node),
2434 else => unreachable,
2435 };
2436 if (case.payload_token) |payload_token| {
2437 if (token_tags[payload_token] == .asterisk) {
2438 any_payload_is_ref = true;
2439 }
2440 }
2362 // Check for else/_ prong, those are handled last.2441 // Check for else/_ prong, those are handled last.
2363 if (case.items_len == 1 and case.items()[0].tag == .switch_else) {2442 if (case.ast.values.len == 0) {
2443 const case_src = token_starts[case.ast.arrow_token - 1];
2364 if (else_src) |src| {2444 if (else_src) |src| {
2365 const msg = msg: {2445 const msg = msg: {
2366 const msg = try mod.errMsg(2446 const msg = try mod.errMsg(
...@@ -2377,9 +2457,11 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -2377,9 +2457,11 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
2377 }2457 }
2378 else_src = case_src;2458 else_src = case_src;
2379 continue;2459 continue;
2380 } else if (case.items_len == 1 and case.items()[0].tag == .identifier and2460 } else if (case.ast.values.len == 1 and
2381 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))2461 node_tags[case.ast.values[0]] == .identifier and
2462 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
2382 {2463 {
2464 const case_src = token_starts[case.ast.arrow_token - 1];
2383 if (underscore_src) |src| {2465 if (underscore_src) |src| {
2384 const msg = msg: {2466 const msg = msg: {
2385 const msg = try mod.errMsg(2467 const msg = try mod.errMsg(
...@@ -2416,14 +2498,18 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -2416,14 +2498,18 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
2416 }2498 }
2417 }2499 }
24182500
2419 if (case.items_len == 1 and getRangeNode(case.items()[0]) == null) simple_case_count += 1;2501 if (case.ast.values.len == 1 and
2502 getRangeNode(node_tags, node_datas, case.ast.values[0]) == null)
2503 {
2504 simple_case_count += 1;
2505 }
24202506
2421 // generate all the switch items as comptime expressions2507 // Generate all the switch items as comptime expressions.
2422 for (case.items()) |item| {2508 for (case.ast.values) |item| {
2423 if (getRangeNode(item)) |range| {2509 if (getRangeNode(node_tags, node_datas, item)) |range| {
2424 const start = try comptimeExpr(mod, &block_scope.base, .none, range.lhs);2510 const start = try comptimeExpr(mod, &block_scope.base, .none, node_datas[range].lhs);
2425 const end = try comptimeExpr(mod, &block_scope.base, .none, range.rhs);2511 const end = try comptimeExpr(mod, &block_scope.base, .none, node_datas[range].rhs);
2426 const range_src = token_starts[range.op_token];2512 const range_src = token_starts[main_tokens[range]];
2427 const range_inst = try addZIRBinOp(mod, &block_scope.base, range_src, .switch_range, start, end);2513 const range_inst = try addZIRBinOp(mod, &block_scope.base, range_src, .switch_range, start, end);
2428 try items.append(range_inst);2514 try items.append(range_inst);
2429 } else {2515 } else {
...@@ -2438,21 +2524,25 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -2438,21 +2524,25 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
2438 if (underscore_src != null) special_prong = .underscore;2524 if (underscore_src != null) special_prong = .underscore;
2439 var cases = try block_scope.arena.alloc(zir.Inst.SwitchBr.Case, simple_case_count);2525 var cases = try block_scope.arena.alloc(zir.Inst.SwitchBr.Case, simple_case_count);
24402526
2441 const target_ptr = if (use_ref) try expr(mod, &block_scope.base, .ref, switch_node.expr) else null;2527 const rl_and_tag: struct { rl: ResultLoc, tag: zir.Inst.Tag } = if (any_payload_is_ref)
2442 const target = if (target_ptr) |some|2528 .{
2443 try addZIRUnOp(mod, &block_scope.base, some.src, .deref, some)2529 .rl = .ref,
2530 .tag = .switchbr_ref,
2531 }
2444 else2532 else
2445 try expr(mod, &block_scope.base, .none, switch_node.expr);2533 .{
2446 const switch_inst = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{2534 .rl = .none,
2535 .tag = .switchbr,
2536 };
2537 const target = try expr(mod, &block_scope.base, rl_and_tag.rl, target_node);
2538 const switch_inst = try addZirInstT(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, rl_and_tag.tag, .{
2447 .target = target,2539 .target = target,
2448 .cases = cases,2540 .cases = cases,
2449 .items = try block_scope.arena.dupe(*zir.Inst, items.items),2541 .items = try block_scope.arena.dupe(*zir.Inst, items.items),
2450 .else_body = undefined, // populated below2542 .else_body = undefined, // populated below
2451 }, .{
2452 .range = first_range,2543 .range = first_range,
2453 .special_prong = special_prong,2544 .special_prong = special_prong,
2454 });2545 });
2455
2456 const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{2546 const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{
2457 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),2547 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
2458 });2548 });
...@@ -2475,29 +2565,35 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -2475,29 +2565,35 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
2475 };2565 };
2476 defer else_scope.instructions.deinit(mod.gpa);2566 defer else_scope.instructions.deinit(mod.gpa);
24772567
2478 // Now generate all but the special cases2568 // Now generate all but the special cases.
2479 var special_case: ?*ast.Node.switch_case = null;2569 var special_case: ?ast.Node.Index = null;
2480 var items_index: usize = 0;2570 var items_index: usize = 0;
2481 var case_index: usize = 0;2571 var case_index: usize = 0;
2482 for (switch_node.cases()) |uncasted_case| {2572 for (case_nodes) |case_node| {
2483 const case = uncasted_case.castTag(.switch_case).?;2573 const case = switch (node_tags[case_node]) {
2484 const case_src = token_starts[case.firstToken()];2574 .switch_case_one => tree.switchCaseOne(case_node),
2485 // reset without freeing to reduce allocations.2575 .switch_case => tree.switchCase(case_node),
2486 case_scope.instructions.items.len = 0;2576 else => unreachable,
2577 };
2578 const case_src = token_starts[main_tokens[case_node]];
2579 case_scope.instructions.shrinkRetainingCapacity(0);
24872580
2488 // Check for else/_ prong, those are handled last.2581 // Check for else/_ prong, those are handled last.
2489 if (case.items_len == 1 and case.items()[0].tag == .switch_else) {2582 if (case.ast.values.len == 0) {
2490 special_case = case;2583 special_case = case;
2491 continue;2584 continue;
2492 } else if (case.items_len == 1 and case.items()[0].tag == .identifier and2585 } else if (case.ast.values.len == 1 and
2493 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))2586 node_tags[case.ast.values[0]] == .identifier and
2587 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
2494 {2588 {
2495 special_case = case;2589 special_case = case;
2496 continue;2590 continue;
2497 }2591 }
24982592
2499 // If this is a simple one item prong then it is handled by the switchbr.2593 // If this is a simple one item prong then it is handled by the switchbr.
2500 if (case.items_len == 1 and getRangeNode(case.items()[0]) == null) {2594 if (case.ast.values.len == 1 and
2595 getRangeNode(node_tags, node_datas, case.ast.values[0]) == null)
2596 {
2501 const item = items.items[items_index];2597 const item = items.items[items_index];
2502 items_index += 1;2598 items_index += 1;
2503 try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target, target_ptr);2599 try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target, target_ptr);
...@@ -2510,16 +2606,14 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -2510,16 +2606,14 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
2510 continue;2606 continue;
2511 }2607 }
25122608
2513 // TODO if the case has few items and no ranges it might be better
2514 // to just handle them as switch prongs.
2515
2516 // Check if the target matches any of the items.2609 // Check if the target matches any of the items.
2517 // 1, 2, 3..6 will result in2610 // 1, 2, 3..6 will result in
2518 // target == 1 or target == 2 or (target >= 3 and target <= 6)2611 // target == 1 or target == 2 or (target >= 3 and target <= 6)
2612 // TODO handle multiple items as switch prongs rather than along with ranges.
2519 var any_ok: ?*zir.Inst = null;2613 var any_ok: ?*zir.Inst = null;
2520 for (case.items()) |item| {2614 for (case.ast.values) |item| {
2521 if (getRangeNode(item)) |range| {2615 if (getRangeNode(node_tags, node_datas, item)) |range| {
2522 const range_src = token_starts[range.op_token];2616 const range_src = token_starts[main_tokens[range]];
2523 const range_inst = items.items[items_index].castTag(.switch_range).?;2617 const range_inst = items.items[items_index].castTag(.switch_range).?;
2524 items_index += 1;2618 items_index += 1;
25252619
...@@ -2580,7 +2674,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -2580,7 +2674,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
2580 // Not handling all possible cases is a compile error.2674 // Not handling all possible cases is a compile error.
2581 _ = try addZIRNoOp(mod, &else_scope.base, switch_src, .unreachable_unsafe);2675 _ = try addZIRNoOp(mod, &else_scope.base, switch_src, .unreachable_unsafe);
2582 }2676 }
2583 switch_inst.castTag(.switchbr).?.positionals.else_body = .{2677 switch_inst.positionals.else_body = .{
2584 .instructions = try block_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),2678 .instructions = try block_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
2585 };2679 };
25862680
...@@ -2592,19 +2686,22 @@ fn switchCaseExpr(...@@ -2592,19 +2686,22 @@ fn switchCaseExpr(
2592 scope: *Scope,2686 scope: *Scope,
2593 rl: ResultLoc,2687 rl: ResultLoc,
2594 block: *zir.Inst.Block,2688 block: *zir.Inst.Block,
2595 case: *ast.Node.switch_case,2689 case: ast.full.SwitchCase,
2596 target: *zir.Inst,2690 target: *zir.Inst,
2597 target_ptr: ?*zir.Inst,2691 target_ptr: ?*zir.Inst,
2598) !void {2692) !void {
2599 const tree = scope.tree();2693 const tree = scope.tree();
2600 const node_datas = tree.nodes.items(.data);2694 const node_datas = tree.nodes.items(.data);
2601 const main_tokens = tree.nodes.items(.main_token);2695 const main_tokens = tree.nodes.items(.main_token);
2602 const case_src = token_starts[case.firstToken()];2696 const case_src = token_starts[case.ast.arrow_token];
2603 const sub_scope = blk: {2697 const sub_scope = blk: {
2604 const uncasted_payload = case.payload orelse break :blk scope;2698 const payload_token = case.payload_token orelse break :blk scope;
2605 const payload = uncasted_payload.castTag(.PointerPayload).?;2699 const ident = if (token_tags[payload_token] == .asterisk)
2606 const is_ptr = payload.ptr_token != null;2700 payload_token + 1
2607 const value_name = tree.tokenSlice(payload.value_symbol.firstToken());2701 else
2702 payload_token;
2703 const is_ptr = ident != payload_token;
2704 const value_name = tree.tokenSlice(ident);
2608 if (mem.eql(u8, value_name, "_")) {2705 if (mem.eql(u8, value_name, "_")) {
2609 if (is_ptr) {2706 if (is_ptr) {
2610 return mod.failTok(scope, payload.ptr_token.?, "pointer modifier invalid on discard", .{});2707 return mod.failTok(scope, payload.ptr_token.?, "pointer modifier invalid on discard", .{});
...@@ -2614,7 +2711,7 @@ fn switchCaseExpr(...@@ -2614,7 +2711,7 @@ fn switchCaseExpr(
2614 return mod.failNode(scope, payload.value_symbol, "TODO implement switch value payload", .{});2711 return mod.failNode(scope, payload.value_symbol, "TODO implement switch value payload", .{});
2615 };2712 };
26162713
2617 const case_body = try expr(mod, sub_scope, rl, case.expr);2714 const case_body = try expr(mod, sub_scope, rl, case.ast.target_expr);
2618 if (!case_body.tag.isNoReturn()) {2715 if (!case_body.tag.isNoReturn()) {
2619 _ = try addZIRInst(mod, sub_scope, case_src, zir.Inst.Break, .{2716 _ = try addZIRInst(mod, sub_scope, case_src, zir.Inst.Break, .{
2620 .block = block,2717 .block = block,
...@@ -2820,12 +2917,13 @@ fn multilineStringLiteral(...@@ -2820,12 +2917,13 @@ fn multilineStringLiteral(
2820 return rvalue(mod, scope, rl, str_inst);2917 return rvalue(mod, scope, rl, str_inst);
2821}2918}
28222919
2823fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst {2920fn charLiteral(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst {
2824 const tree = scope.tree();2921 const tree = scope.tree();
2825 const node_datas = tree.nodes.items(.data);2922 const node_datas = tree.nodes.items(.data);
2826 const main_tokens = tree.nodes.items(.main_token);2923 const main_tokens = tree.nodes.items(.main_token);
2827 const src = token_starts[node.token];2924 const main_token = main_tokens[node];
2828 const slice = tree.tokenSlice(node.token);2925 const src = token_starts[main_token];
2926 const slice = tree.tokenSlice(main_token);
28292927
2830 var bad_index: usize = undefined;2928 var bad_index: usize = undefined;
2831 const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) {2929 const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) {
...@@ -2834,11 +2932,11 @@ fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst...@@ -2834,11 +2932,11 @@ fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst
2834 return mod.fail(scope, src + bad_index, "invalid character: '{c}'\n", .{bad_byte});2932 return mod.fail(scope, src + bad_index, "invalid character: '{c}'\n", .{bad_byte});
2835 },2933 },
2836 };2934 };
28372935 const result = try addZIRInstConst(mod, scope, src, .{
2838 return addZIRInstConst(mod, scope, src, .{
2839 .ty = Type.initTag(.comptime_int),2936 .ty = Type.initTag(.comptime_int),
2840 .val = try Value.Tag.int_u64.create(scope.arena(), value),2937 .val = try Value.Tag.int_u64.create(scope.arena(), value),
2841 });2938 });
2939 return rvalue(mod, scope, rl, result);
2842}2940}
28432941
2844fn integerLiteral(2942fn integerLiteral(
...@@ -3675,6 +3773,29 @@ pub fn addZirInstTag(...@@ -3675,6 +3773,29 @@ pub fn addZirInstTag(
3675 return &inst.base;3773 return &inst.base;
3676}3774}
36773775
3776pub fn addZirInstT(
3777 mod: *Module,
3778 scope: *Scope,
3779 src: usize,
3780 comptime T: type,
3781 tag: zir.Inst.Tag,
3782 positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type,
3783) !*T {
3784 const gen_zir = scope.getGenZIR();
3785 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
3786 const inst = try gen_zir.arena.create(T);
3787 inst.* = .{
3788 .base = .{
3789 .tag = tag,
3790 .src = src,
3791 },
3792 .positionals = positionals,
3793 .kw_args = .{},
3794 };
3795 gen_zir.instructions.appendAssumeCapacity(&inst.base);
3796 return inst;
3797}
3798
3678pub fn addZIRInstSpecial(3799pub fn addZIRInstSpecial(
3679 mod: *Module,3800 mod: *Module,
3680 scope: *Scope,3801 scope: *Scope,
src/zir.zig+10-8
...@@ -343,6 +343,8 @@ pub const Inst = struct {...@@ -343,6 +343,8 @@ pub const Inst = struct {
343 void_value,343 void_value,
344 /// A switch expression.344 /// A switch expression.
345 switchbr,345 switchbr,
346 /// Same as `switchbr` but the target is a pointer to the value being switched on.
347 switchbr_ref,
346 /// A range in a switch case, `lhs...rhs`.348 /// A range in a switch case, `lhs...rhs`.
347 /// Only checks that `lhs >= rhs` if they are ints, everything else is349 /// Only checks that `lhs >= rhs` if they are ints, everything else is
348 /// validated by the .switch instruction.350 /// validated by the .switch instruction.
...@@ -453,6 +455,8 @@ pub const Inst = struct {...@@ -453,6 +455,8 @@ pub const Inst = struct {
453 .block_comptime_flat,455 .block_comptime_flat,
454 => Block,456 => Block,
455457
458 .switchbr, .switchbr_ref => SwitchBr,
459
456 .arg => Arg,460 .arg => Arg,
457 .array_type_sentinel => ArrayTypeSentinel,461 .array_type_sentinel => ArrayTypeSentinel,
458 .@"break" => Break,462 .@"break" => Break,
...@@ -488,7 +492,6 @@ pub const Inst = struct {...@@ -488,7 +492,6 @@ pub const Inst = struct {
488 .enum_type => EnumType,492 .enum_type => EnumType,
489 .union_type => UnionType,493 .union_type => UnionType,
490 .struct_type => StructType,494 .struct_type => StructType,
491 .switchbr => SwitchBr,
492 };495 };
493 }496 }
494497
...@@ -617,7 +620,6 @@ pub const Inst = struct {...@@ -617,7 +620,6 @@ pub const Inst = struct {
617 .struct_type,620 .struct_type,
618 .void_value,621 .void_value,
619 .switch_range,622 .switch_range,
620 .switchbr,
621 => false,623 => false,
622624
623 .@"break",625 .@"break",
...@@ -632,6 +634,8 @@ pub const Inst = struct {...@@ -632,6 +634,8 @@ pub const Inst = struct {
632 .container_field_named,634 .container_field_named,
633 .container_field_typed,635 .container_field_typed,
634 .container_field,636 .container_field,
637 .switchbr,
638 .switchbr_ref,
635 => true,639 => true,
636 };640 };
637 }641 }
...@@ -730,6 +734,8 @@ pub const Inst = struct {...@@ -730,6 +734,8 @@ pub const Inst = struct {
730 kw_args: struct {},734 kw_args: struct {},
731 };735 };
732736
737 // TODO break this into multiple call instructions to avoid paying the cost
738 // of the calling convention field most of the time.
733 pub const Call = struct {739 pub const Call = struct {
734 pub const base_tag = Tag.call;740 pub const base_tag = Tag.call;
735 base: Inst,741 base: Inst,
...@@ -737,10 +743,9 @@ pub const Inst = struct {...@@ -737,10 +743,9 @@ pub const Inst = struct {
737 positionals: struct {743 positionals: struct {
738 func: *Inst,744 func: *Inst,
739 args: []*Inst,745 args: []*Inst,
740 },
741 kw_args: struct {
742 modifier: std.builtin.CallOptions.Modifier = .auto,746 modifier: std.builtin.CallOptions.Modifier = .auto,
743 },747 },
748 kw_args: struct {},
744 };749 };
745750
746 pub const DeclRef = struct {751 pub const DeclRef = struct {
...@@ -1185,7 +1190,6 @@ pub const Inst = struct {...@@ -1185,7 +1190,6 @@ pub const Inst = struct {
1185 };1190 };
11861191
1187 pub const SwitchBr = struct {1192 pub const SwitchBr = struct {
1188 pub const base_tag = Tag.switchbr;
1189 base: Inst,1193 base: Inst,
11901194
1191 positionals: struct {1195 positionals: struct {
...@@ -1194,14 +1198,12 @@ pub const Inst = struct {...@@ -1194,14 +1198,12 @@ pub const Inst = struct {
1194 items: []*Inst,1198 items: []*Inst,
1195 cases: []Case,1199 cases: []Case,
1196 else_body: Body,1200 else_body: Body,
1197 },
1198 kw_args: struct {
1199 /// Pointer to first range if such exists.1201 /// Pointer to first range if such exists.
1200 range: ?*Inst = null,1202 range: ?*Inst = null,
1201 special_prong: SpecialProng = .none,1203 special_prong: SpecialProng = .none,
1202 },1204 },
1205 kw_args: struct {},
12031206
1204 // Not anonymous due to stage1 limitations
1205 pub const SpecialProng = enum {1207 pub const SpecialProng = enum {
1206 none,1208 none,
1207 @"else",1209 @"else",
src/zir_sema.zig+9-3
...@@ -154,7 +154,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -154,7 +154,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
154 .bool_and => return zirBoolOp(mod, scope, old_inst.castTag(.bool_and).?),154 .bool_and => return zirBoolOp(mod, scope, old_inst.castTag(.bool_and).?),
155 .bool_or => return zirBoolOp(mod, scope, old_inst.castTag(.bool_or).?),155 .bool_or => return zirBoolOp(mod, scope, old_inst.castTag(.bool_or).?),
156 .void_value => return mod.constVoid(scope, old_inst.src),156 .void_value => return mod.constVoid(scope, old_inst.src),
157 .switchbr => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?),157 .switchbr => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, false),
158 .switchbr_ref => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, true),
158 .switch_range => return zirSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),159 .switch_range => return zirSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),
159160
160 .container_field_named,161 .container_field_named,
...@@ -1554,10 +1555,15 @@ fn zirSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError...@@ -1554,10 +1555,15 @@ fn zirSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError
1554 return mod.constVoid(scope, inst.base.src);1555 return mod.constVoid(scope, inst.base.src);
1555}1556}
15561557
1557fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) InnerError!*Inst {1558fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool) InnerError!*Inst {
1558 const tracy = trace(@src());1559 const tracy = trace(@src());
1559 defer tracy.end();1560 defer tracy.end();
1560 const target = try resolveInst(mod, scope, inst.positionals.target);1561
1562 const target_ptr = try resolveInst(mod, scope, inst.positionals.target);
1563 const target = if (ref)
1564 try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target.src)
1565 else
1566 target_ptr;
1561 try validateSwitch(mod, scope, target, inst);1567 try validateSwitch(mod, scope, target, inst);
15621568
1563 if (try mod.resolveDefinedValue(scope, target)) |target_val| {1569 if (try mod.resolveDefinedValue(scope, target)) |target_val| {