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 {
15281528
15291529 pub fn switchCaseOne(tree: Tree, node: Node.Index) full.SwitchCase {
15301530 const data = &tree.nodes.items(.data)[node];
1531 const values: *[1]Node.Index = &data.lhs;
15311532 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],
15331534 .arrow_token = tree.nodes.items(.main_token)[node],
15341535 .target_expr = data.rhs,
15351536 });
......@@ -2532,8 +2533,8 @@ pub const Node = struct {
25322533 @"defer",
25332534 /// lhs catch rhs
25342535 /// lhs catch |err| rhs
2535 /// main_token is the catch
2536 /// payload is determined by looking at the prev tokens before rhs.
2536 /// main_token is the `catch` keyword.
2537 /// payload is determined by looking at the next token after the `catch` keyword.
25372538 @"catch",
25382539 /// `lhs.a`. main_token is the dot. rhs is the identifier token index.
25392540 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
416416 return renderToken(ais, tree, rbracket, space); // ]
417417 },
418418
419 .slice_open => try renderSlice(ais, tree, tree.sliceOpen(node), space),
420 .slice => try renderSlice(ais, tree, tree.slice(node), space),
421 .slice_sentinel => try renderSlice(ais, tree, tree.sliceSentinel(node), space),
419 .slice_open => return renderSlice(ais, tree, tree.sliceOpen(node), space),
420 .slice => return renderSlice(ais, tree, tree.slice(node), space),
421 .slice_sentinel => return renderSlice(ais, tree, tree.sliceSentinel(node), space),
422422
423423 .deref => {
424424 try renderExpression(ais, tree, datas[node].lhs, .none);
src/Module.zig+8-8
......@@ -1163,16 +1163,16 @@ fn astgenAndSemaFn(
11631163 }
11641164 assert(param_type_i == param_count);
11651165 }
1166 if (fn_proto.lib_name) |lib_name| blk: {
1166 if (fn_proto.lib_name) |lib_name_token| blk: {
11671167 // 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), "\"");
11691169 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
11701170 const target = mod.comp.getTarget();
11711171 if (target_util.is_libc_lib_name(target, lib_name_str)) {
11721172 if (!mod.comp.bin_file.options.link_libc) {
11731173 return mod.failTok(
11741174 &fn_type_scope.base,
1175 lib_name,
1175 lib_name_token,
11761176 "dependency on libc must be explicitly specified in the build command",
11771177 .{},
11781178 );
......@@ -1183,7 +1183,7 @@ fn astgenAndSemaFn(
11831183 if (!mod.comp.bin_file.options.link_libcpp) {
11841184 return mod.failTok(
11851185 &fn_type_scope.base,
1186 lib_name,
1186 lib_name_token,
11871187 "dependency on libc++ must be explicitly specified in the build command",
11881188 .{},
11891189 );
......@@ -1193,17 +1193,17 @@ fn astgenAndSemaFn(
11931193 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
11941194 return mod.failTok(
11951195 &fn_type_scope.base,
1196 lib_name,
1196 lib_name_token,
11971197 "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 },
11991199 );
12001200 }
12011201 mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
12021202 return mod.failTok(
12031203 &fn_type_scope.base,
1204 lib_name,
1204 lib_name_token,
12051205 "unable to add link lib '{s}': {s}",
1206 .{ lib_name, @errorName(err) },
1206 .{ lib_name_str, @errorName(err) },
12071207 );
12081208 };
12091209 }
src/astgen.zig+421-300
......@@ -327,6 +327,15 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
327327 .while_cont => return whileExpr(mod, scope, tree.whileCont(node)),
328328 .@"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
330339 .deref => {
331340 const lhs = try expr(mod, scope, .none, node_datas[node].lhs);
332341 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
402411 const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
403412 return blockExpr(mod, scope, rl, node, statements);
404413 },
405
406 .@"break" => return rvalue(mod, scope, rl, try breakExpr(mod, scope, node)),
407 .@"continue" => return rvalue(mod, scope, rl, try continueExpr(mod, scope, node)),
408 .grouped_expression => return expr(mod, scope, rl, node.expr),
409 .array_type => return rvalue(mod, scope, rl, try arrayType(mod, scope, node)),
410 .array_type_sentinel => return rvalue(mod, scope, rl, try arrayTypeSentinel(mod, scope, node)),
411 .enum_literal => return rvalue(mod, scope, rl, try enumLiteral(mod, scope, node)),
412 .char_literal => return rvalue(mod, scope, rl, try charLiteral(mod, scope, node)),
413 .slice_type => return rvalue(mod, scope, rl, try sliceType(mod, scope, node)),
414 .error_union => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node, .error_union_type)),
415 .merge_error_sets => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node, .merge_error_sets)),
416 .anyframe_type => return rvalue(mod, scope, rl, try anyFrameType(mod, scope, node)),
417 .error_set_decl => return rvalue(mod, scope, rl, try errorSetDecl(mod, scope, node)),
418 .error_type => return rvalue(mod, scope, rl, try errorType(mod, scope, node)),
419 .@"for" => return forExpr(mod, scope, rl, node),
414 .enum_literal => {
415 const ident_token = main_tokens[node];
416 const name = try mod.identifierTokenString(scope, ident_token);
417 const src = token_starts[ident_token];
418 const result = try addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});
419 return rvalue(mod, scope, rl, result);
420 },
421 .error_union => {
422 const error_set = try typeExpr(mod, scope, node_datas[node].lhs);
423 const payload = try typeExpr(mod, scope, node_datas[node].rhs);
424 const src = token_starts[main_tokens[node]];
425 const result = try addZIRBinOp(mod, scope, src, .error_union_type, error_set, payload);
426 return rvalue(mod, scope, rl, result);
427 },
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),
420516 .array_access => return arrayAccess(mod, scope, rl, node),
421 .slice => return rvalue(mod, scope, rl, try sliceExpr(mod, scope, node)),
422 .@"catch" => return catchExpr(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),
517 .@"comptime" => return comptimeExpr(mod, scope, rl, node_datas[node].lhs),
518 .@"switch", .switch_comma => return switchExpr(mod, scope, rl, node),
427519
428520 .@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}),
429521 .@"await" => return mod.failNode(scope, node, "TODO implement astgen.expr for .await", .{}),
430522 .@"resume" => return mod.failNode(scope, node, "TODO implement astgen.expr for .resume", .{}),
431523 .@"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", .{}),
436524 .@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}),
437525 .@"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", .{}),
439526 .@"nosuspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .nosuspend", .{}),
440527 }
441528}
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
450530pub fn comptimeExpr(
451531 mod: *Module,
452532 parent_scope: *Scope,
......@@ -493,7 +573,12 @@ pub fn comptimeExpr(
493573 return &block.base;
494574}
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 {
497582 const tree = parent_scope.tree();
498583 const node_datas = tree.nodes.items(.data);
499584 const main_tokens = tree.nodes.items(.main_token);
......@@ -524,9 +609,10 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro
524609 };
525610
526611 if (rhs == 0) {
527 return addZirInstTag(mod, parent_scope, src, .break_void, .{
612 const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{
528613 .block = block_inst,
529614 });
615 return rvalue(mod, parent_scope, rl, result);
530616 }
531617 gen_zir.break_count += 1;
532618 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
547633 try gen_zir.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst);
548634 }
549635 }
550 return br;
636 return rvalue(mod, parent_scope, rl, br);
551637 },
552638 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
553639 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
......@@ -561,7 +647,12 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro
561647 }
562648}
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 {
565656 const tree = parent_scope.tree();
566657 const node_datas = tree.nodes.items(.data);
567658 const main_tokens = tree.nodes.items(.main_token);
......@@ -590,9 +681,10 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerE
590681 continue;
591682 }
592683
593 return addZirInstTag(mod, parent_scope, src, .break_void, .{
684 const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{
594685 .block = continue_block,
595686 });
687 return rvalue(mod, parent_scope, rl, result);
596688 },
597689 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
598690 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
......@@ -1083,12 +1175,6 @@ fn negation(
10831175 return addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs);
10841176}
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
10921178fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst {
10931179 const tree = scope.tree();
10941180 const src = token_starts[node.op_token];
......@@ -1146,70 +1232,54 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo,
11461232 return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);
11471233}
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 {
11501236 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]];
11521240 const usize_type = try addZIRInstConst(mod, scope, src, .{
11531241 .ty = Type.initTag(.type),
11541242 .val = Value.initTag(.usize_type),
11551243 });
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 [_]T
1158 const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
1159 const elem_type = try typeExpr(mod, scope, node.rhs);
1160
1161 return addZIRBinOp(mod, scope, src, .array_type, len, elem_type);
1255 const result = try addZIRBinOp(mod, scope, src, .array_type, len, elem_type);
1256 return rvalue(mod, scope, rl, result);
1257 }
11621258}
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 {
11651261 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]];
11671266 const usize_type = try addZIRInstConst(mod, scope, src, .{
11681267 .ty = Type.initTag(.type),
11691268 .val = Value.initTag(.usize_type),
11701269 });
11711270
11721271 // TODO check for [_]T
1173 const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
1174 const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel);
1175 const elem_type = try typeExpr(mod, scope, node.rhs);
1272 const len = try expr(mod, scope, .{ .ty = usize_type }, len_node);
1273 const sentinel_uncasted = try expr(mod, scope, .none, extra.sentinel);
1274 const elem_type = try typeExpr(mod, scope, extra.elem_type);
11761275 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, .{
11791278 .len = len,
11801279 .sentinel = sentinel,
11811280 .elem_type = elem_type,
11821281 }, .{});
1183}
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 }, .{});
1282 return rvalue(mod, scope, rl, result);
12131283}
12141284
12151285fn containerField(
......@@ -1394,85 +1464,50 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
13941464 }
13951465}
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 {
13981473 const tree = scope.tree();
1399 const src = token_starts[node.error_token];
1400 const decls = node.decls();
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}
1474 const main_tokens = tree.nodes.items(.main_token);
1475 const token_tags = tree.tokens.items(.tag);
14101476
1411fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
1412 const tree = scope.tree();
1413 const src = token_starts[node.token];
1414 return addZIRInstConst(mod, scope, src, .{
1415 .ty = Type.initTag(.type),
1416 .val = Value.initTag(.anyerror_type),
1417 });
1418}
1477 // Count how many fields there are.
1478 const error_token = main_tokens[node];
1479 const count: usize = count: {
1480 var tok_i = error_token + 2;
1481 var count: usize = 0;
1482 while (true) : (tok_i += 1) {
1483 switch (token_tags[tok_i]) {
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 {
1421 switch (rl) {
1422 .ref => return orelseCatchExpr(
1423 mod,
1424 scope,
1425 rl,
1426 node.lhs,
1427 node.op_token,
1428 .is_err_ptr,
1429 .err_union_payload_unsafe_ptr,
1430 .err_union_code_ptr,
1431 node.rhs,
1432 node.payload,
1433 ),
1434 else => return orelseCatchExpr(
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 ),
1492 const fields = try scope.arena().alloc([]const u8, count);
1493 {
1494 var tok_i = error_token + 2;
1495 var field_i: usize = 0;
1496 while (true) : (tok_i += 1) {
1497 switch (token_tags[tok_i]) {
1498 .doc_comment, .comma => {},
1499 .identifier => {
1500 fields[field_i] = try mod.identifierTokenString(scope, tok_i);
1501 field_i += 1;
1502 },
1503 .r_paren => break,
1504 else => unreachable,
1505 }
1506 }
14751507 }
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);
14761511}
14771512
14781513fn orelseCatchExpr(
......@@ -1681,55 +1716,78 @@ pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) I
16811716 }
16821717}
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 {
16851725 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]];
16871729 const usize_type = try addZIRInstConst(mod, scope, src, .{
16881730 .ty = Type.initTag(.type),
16891731 .val = Value.initTag(.usize_type),
16901732 });
16911733 const index_rl: ResultLoc = .{ .ty = usize_type };
1692
1693 if (rl == .ref) {
1694 return addZirInstTag(mod, scope, src, .elem_ptr, .{
1695 .array = try expr(mod, scope, .ref, node.lhs),
1696 .index = try expr(mod, scope, index_rl, node.index_expr),
1697 });
1734 switch (rl) {
1735 .ref => return addZirInstTag(mod, scope, src, .elem_ptr, .{
1736 .array = try expr(mod, scope, .ref, node_datas[node].lhs),
1737 .index = try expr(mod, scope, index_rl, node_datas[node].rhs),
1738 }),
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 })),
16981743 }
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 }));
17031744}
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 {
17061752 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
17091756 const usize_type = try addZIRInstConst(mod, scope, src, .{
17101757 .ty = Type.initTag(.type),
17111758 .val = Value.initTag(.usize_type),
17121759 });
17131760
1714 const array_ptr = try expr(mod, scope, .ref, node.lhs);
1715 const start = try expr(mod, scope, .{ .ty = usize_type }, node.start);
1761 const array_ptr = try expr(mod, scope, .ref, slice.ast.sliced);
1762 const start = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.start);
17161763
1717 if (node.end == null and node.sentinel == null) {
1718 return try addZIRBinOp(mod, scope, src, .slice_start, array_ptr, start);
1764 if (slice.ast.sentinel == 0) {
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 }
17191777 }
17201778
1721 const end = if (node.end) |end| try expr(mod, scope, .{ .ty = usize_type }, end) else null;
1722 // we could get the child type here, but it is easier to just do it in semantic analysis.
1723 const sentinel = if (node.sentinel) |sentinel| try expr(mod, scope, .none, sentinel) else null;
1724
1725 return try addZIRInst(
1726 mod,
1727 scope,
1728 src,
1729 zir.Inst.Slice,
1730 .{ .array_ptr = array_ptr, .start = start },
1731 .{ .end = end, .sentinel = sentinel },
1732 );
1779 const end = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.end);
1780 // TODO pass the proper result loc to this expression using a ZIR instruction
1781 // "get the child element type for a slice target".
1782 const sentinel = try expr(mod, scope, .none, slice.ast.sentinel);
1783 const result = try addZIRInst(mod, scope, src, zir.Inst.Slice, .{
1784 .array_ptr = array_ptr,
1785 .start = start,
1786 }, .{
1787 .end = end,
1788 .sentinel = sentinel,
1789 });
1790 return rvalue(mod, scope, rl, result);
17331791}
17341792
17351793fn simpleBinOp(
......@@ -2070,7 +2128,6 @@ fn whileExpr(
20702128 };
20712129 defer then_scope.instructions.deinit(mod.gpa);
20722130
2073 // declare payload to the then_scope
20742131 const then_sub_scope = &then_scope.base;
20752132
20762133 loop_scope.break_count += 1;
......@@ -2101,7 +2158,7 @@ fn whileExpr(
21012158
21022159 if (loop_scope.label) |some| {
21032160 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", .{});
21052162 }
21062163 }
21072164 return finishThenElseBlock(
......@@ -2126,20 +2183,21 @@ fn forExpr(
21262183 mod: *Module,
21272184 scope: *Scope,
21282185 rl: ResultLoc,
2129 for_node: *ast.Node.@"for",
2186 for_full: ast.full.While,
21302187) InnerError!*zir.Inst {
2131 if (for_node.label) |label| {
2132 try checkLabelRedefinition(mod, scope, label);
2188 if (for_full.label_token) |label_token| {
2189 try checkLabelRedefinition(mod, scope, label_token);
21332190 }
21342191
2135 if (for_node.inline_token) |tok|
2136 return mod.failTok(scope, tok, "TODO inline for", .{});
2192 if (for_full.inline_token) |inline_token| {
2193 return mod.failTok(scope, inline_token, "TODO inline for", .{});
2194 }
21372195
2138 // setup variables and constants
2196 // Set up variables and constants.
21392197 const tree = scope.tree();
21402198 const node_datas = tree.nodes.items(.data);
21412199 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];
21432201 const index_ptr = blk: {
21442202 const usize_type = try addZIRInstConst(mod, scope, for_src, .{
21452203 .ty = Type.initTag(.type),
......@@ -2154,8 +2212,8 @@ fn forExpr(
21542212 _ = try addZIRBinOp(mod, scope, for_src, .store, index_ptr, zero);
21552213 break :blk index_ptr;
21562214 };
2157 const array_ptr = try expr(mod, scope, .ref, for_node.array_expr);
2158 const cond_src = token_starts[for_node.array_expr.firstToken()];
2215 const array_ptr = try expr(mod, scope, .ref, for_full.ast.cond_expr);
2216 const cond_src = token_starts[tree.firstToken(for_full.ast.cond_expr)];
21592217 const len = try addZIRUnOp(mod, scope, cond_src, .indexable_ptr_len, array_ptr);
21602218
21612219 var loop_scope: Scope.GenZIR = .{
......@@ -2217,15 +2275,15 @@ fn forExpr(
22172275 });
22182276 loop_scope.break_block = for_block;
22192277 loop_scope.continue_block = cond_block;
2220 if (for_node.label) |some| {
2278 if (for_full.label_token) |label_token| {
22212279 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
2222 .token = some,
2280 .token = label_token,
22232281 .block_inst = for_block,
22242282 });
22252283 }
22262284
22272285 // 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)];
22292287 var then_scope: Scope.GenZIR = .{
22302288 .parent = &cond_scope.base,
22312289 .decl = cond_scope.decl,
......@@ -2237,23 +2295,27 @@ fn forExpr(
22372295
22382296 var index_scope: Scope.LocalPtr = undefined;
22392297 const then_sub_scope = blk: {
2240 const payload = for_node.payload.castTag(.PointerIndexPayload).?;
2241 const is_ptr = payload.ptr_token != null;
2242 const value_name = tree.tokenSlice(payload.value_symbol.firstToken());
2298 const payload_token = for_full.payload_token.?;
2299 const ident = if (token_tags[payload_token] == .asterisk)
2300 payload_token + 1
2301 else
2302 payload_token;
2303 const is_ptr = ident != payload_token;
2304 const value_name = tree.tokenSlice(ident);
22432305 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", .{});
22452307 } 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", .{});
22472309 }
22482310
2249 const index_symbol_node = payload.index_symbol orelse
2250 break :blk &then_scope.base;
2251
2252 const index_name = tree.tokenSlice(tree.firstToken(index_symbol_node));
2253 if (mem.eql(u8, index_name, "_")) {
2311 const index_token = if (token_tags[ident + 1] == .comma)
2312 ident + 2
2313 else
22542314 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", .{});
22552317 }
2256 // TODO make this const without an extra copy?
2318 const index_name = try mod.identifierTokenString(&then_scope.base, index_token);
22572319 index_scope = .{
22582320 .parent = &then_scope.base,
22592321 .gen_zir = &then_scope,
......@@ -2264,7 +2326,7 @@ fn forExpr(
22642326 };
22652327
22662328 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
22692331 // else branch
22702332 var else_scope: Scope.GenZIR = .{
......@@ -2276,18 +2338,23 @@ fn forExpr(
22762338 };
22772339 defer else_scope.instructions.deinit(mod.gpa);
22782340
2279 var else_src: usize = undefined;
2280 const else_result: ?*zir.Inst = if (for_node.@"else") |else_node| blk: {
2281 else_src = token_starts[else_node.body.lastToken()];
2341 const else_node = for_full.ast.else_expr;
2342 const else_info: struct { src: usize, result: ?*zir.Inst } = if (else_node != 0) blk: {
22822343 loop_scope.break_count += 1;
2283 break :blk try expr(mod, &else_scope.base, loop_scope.break_result_loc, else_node.body);
2284 } else blk: {
2285 else_src = token_starts[for_node.lastToken()];
2286 break :blk null;
2287 };
2344 const sub_scope = &else_scope.base;
2345 break :blk .{
2346 .src = token_starts[tree.lastToken(else_node)],
2347 .result = try expr(mod, sub_scope, loop_scope.break_result_loc, else_node),
2348 };
2349 } else
2350 .{
2351 .src = token_starts[tree.lastToken(then_node)],
2352 .result = null,
2353 };
2354
22882355 if (loop_scope.label) |some| {
22892356 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", .{});
22912358 }
22922359 }
22932360 return finishThenElseBlock(
......@@ -2300,41 +2367,46 @@ fn forExpr(
23002367 &condbr.positionals.then_body,
23012368 &condbr.positionals.else_body,
23022369 then_src,
2303 else_src,
2370 else_info.src,
23042371 then_result,
2305 else_result,
2372 else_info.result,
23062373 for_block,
23072374 cond_block,
23082375 );
23092376}
23102377
2311fn switchCaseUsesRef(node: *ast.Node.@"switch") bool {
2312 for (node.cases()) |uncasted_case| {
2313 const case = uncasted_case.castTag(.switch_case).?;
2314 const uncasted_payload = case.payload orelse continue;
2315 const payload = uncasted_payload.castTag(.PointerPayload).?;
2316 if (payload.ptr_token) |_| return true;
2317 }
2318 return false;
2319}
2320
2321fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp {
2322 var cur = node;
2378fn getRangeNode(
2379 node_tags: []const ast.Node.Tag,
2380 node_datas: []const ast.Node.Data,
2381 start_node: ast.Node.Index,
2382) ?ast.Node.Index {
2383 var node = start_node;
23232384 while (true) {
2324 switch (cur.tag) {
2325 .range => return @fieldParentPtr(ast.Node.SimpleInfixOp, "base", cur),
2326 .grouped_expression => cur = @fieldParentPtr(ast.Node.grouped_expression, "base", cur).expr,
2385 switch (node_tags[node]) {
2386 .switch_range => return node,
2387 .grouped_expression => node = node_datas[node].lhs,
23272388 else => return null,
23282389 }
23292390 }
23302391}
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 {
23332399 const tree = scope.tree();
23342400 const node_datas = tree.nodes.items(.data);
23352401 const main_tokens = tree.nodes.items(.main_token);
2336 const switch_src = token_starts[switch_node.switch_token];
2337 const use_ref = switchCaseUsesRef(switch_node);
2402 const token_tags = tree.tokens.items(.tag);
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
23392411 var block_scope: Scope.GenZIR = .{
23402412 .parent = scope,
......@@ -2349,18 +2421,26 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
23492421 var items = std.ArrayList(*zir.Inst).init(mod.gpa);
23502422 defer items.deinit();
23512423
2352 // first we gather all the switch items and check else/'_' prongs
2424 // First we gather all the switch items and check else/'_' prongs.
23532425 var else_src: ?usize = null;
23542426 var underscore_src: ?usize = null;
23552427 var first_range: ?*zir.Inst = null;
23562428 var simple_case_count: usize = 0;
2357 for (switch_node.cases()) |uncasted_case| {
2358 const case = uncasted_case.castTag(.switch_case).?;
2359 const case_src = token_starts[case.firstToken()];
2360 assert(case.items_len != 0);
2361
2429 var any_payload_is_ref = false;
2430 for (case_nodes) |case_node| {
2431 const case = switch (node_tags[case_node]) {
2432 .switch_case_one => tree.switchCaseOne(case_node),
2433 .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 }
23622441 // 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];
23642444 if (else_src) |src| {
23652445 const msg = msg: {
23662446 const msg = try mod.errMsg(
......@@ -2377,9 +2457,11 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
23772457 }
23782458 else_src = case_src;
23792459 continue;
2380 } else if (case.items_len == 1 and case.items()[0].tag == .identifier and
2381 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))
2460 } else if (case.ast.values.len == 1 and
2461 node_tags[case.ast.values[0]] == .identifier and
2462 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
23822463 {
2464 const case_src = token_starts[case.ast.arrow_token - 1];
23832465 if (underscore_src) |src| {
23842466 const msg = msg: {
23852467 const msg = try mod.errMsg(
......@@ -2416,14 +2498,18 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
24162498 }
24172499 }
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 expressions
2422 for (case.items()) |item| {
2423 if (getRangeNode(item)) |range| {
2424 const start = try comptimeExpr(mod, &block_scope.base, .none, range.lhs);
2425 const end = try comptimeExpr(mod, &block_scope.base, .none, range.rhs);
2426 const range_src = token_starts[range.op_token];
2507 // Generate all the switch items as comptime expressions.
2508 for (case.ast.values) |item| {
2509 if (getRangeNode(node_tags, node_datas, item)) |range| {
2510 const start = try comptimeExpr(mod, &block_scope.base, .none, node_datas[range].lhs);
2511 const end = try comptimeExpr(mod, &block_scope.base, .none, node_datas[range].rhs);
2512 const range_src = token_starts[main_tokens[range]];
24272513 const range_inst = try addZIRBinOp(mod, &block_scope.base, range_src, .switch_range, start, end);
24282514 try items.append(range_inst);
24292515 } else {
......@@ -2438,21 +2524,25 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
24382524 if (underscore_src != null) special_prong = .underscore;
24392525 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;
2442 const target = if (target_ptr) |some|
2443 try addZIRUnOp(mod, &block_scope.base, some.src, .deref, some)
2527 const rl_and_tag: struct { rl: ResultLoc, tag: zir.Inst.Tag } = if (any_payload_is_ref)
2528 .{
2529 .rl = .ref,
2530 .tag = .switchbr_ref,
2531 }
24442532 else
2445 try expr(mod, &block_scope.base, .none, switch_node.expr);
2446 const switch_inst = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{
2533 .{
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, .{
24472539 .target = target,
24482540 .cases = cases,
24492541 .items = try block_scope.arena.dupe(*zir.Inst, items.items),
24502542 .else_body = undefined, // populated below
2451 }, .{
24522543 .range = first_range,
24532544 .special_prong = special_prong,
24542545 });
2455
24562546 const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{
24572547 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
24582548 });
......@@ -2475,29 +2565,35 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
24752565 };
24762566 defer else_scope.instructions.deinit(mod.gpa);
24772567
2478 // Now generate all but the special cases
2479 var special_case: ?*ast.Node.switch_case = null;
2568 // Now generate all but the special cases.
2569 var special_case: ?ast.Node.Index = null;
24802570 var items_index: usize = 0;
24812571 var case_index: usize = 0;
2482 for (switch_node.cases()) |uncasted_case| {
2483 const case = uncasted_case.castTag(.switch_case).?;
2484 const case_src = token_starts[case.firstToken()];
2485 // reset without freeing to reduce allocations.
2486 case_scope.instructions.items.len = 0;
2572 for (case_nodes) |case_node| {
2573 const case = switch (node_tags[case_node]) {
2574 .switch_case_one => tree.switchCaseOne(case_node),
2575 .switch_case => tree.switchCase(case_node),
2576 else => unreachable,
2577 };
2578 const case_src = token_starts[main_tokens[case_node]];
2579 case_scope.instructions.shrinkRetainingCapacity(0);
24872580
24882581 // 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) {
24902583 special_case = case;
24912584 continue;
2492 } else if (case.items_len == 1 and case.items()[0].tag == .identifier and
2493 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))
2585 } else if (case.ast.values.len == 1 and
2586 node_tags[case.ast.values[0]] == .identifier and
2587 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
24942588 {
24952589 special_case = case;
24962590 continue;
24972591 }
24982592
24992593 // 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 {
25012597 const item = items.items[items_index];
25022598 items_index += 1;
25032599 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
25102606 continue;
25112607 }
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
25162609 // Check if the target matches any of the items.
25172610 // 1, 2, 3..6 will result in
25182611 // target == 1 or target == 2 or (target >= 3 and target <= 6)
2612 // TODO handle multiple items as switch prongs rather than along with ranges.
25192613 var any_ok: ?*zir.Inst = null;
2520 for (case.items()) |item| {
2521 if (getRangeNode(item)) |range| {
2522 const range_src = token_starts[range.op_token];
2614 for (case.ast.values) |item| {
2615 if (getRangeNode(node_tags, node_datas, item)) |range| {
2616 const range_src = token_starts[main_tokens[range]];
25232617 const range_inst = items.items[items_index].castTag(.switch_range).?;
25242618 items_index += 1;
25252619
......@@ -2580,7 +2674,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
25802674 // Not handling all possible cases is a compile error.
25812675 _ = try addZIRNoOp(mod, &else_scope.base, switch_src, .unreachable_unsafe);
25822676 }
2583 switch_inst.castTag(.switchbr).?.positionals.else_body = .{
2677 switch_inst.positionals.else_body = .{
25842678 .instructions = try block_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
25852679 };
25862680
......@@ -2592,19 +2686,22 @@ fn switchCaseExpr(
25922686 scope: *Scope,
25932687 rl: ResultLoc,
25942688 block: *zir.Inst.Block,
2595 case: *ast.Node.switch_case,
2689 case: ast.full.SwitchCase,
25962690 target: *zir.Inst,
25972691 target_ptr: ?*zir.Inst,
25982692) !void {
25992693 const tree = scope.tree();
26002694 const node_datas = tree.nodes.items(.data);
26012695 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];
26032697 const sub_scope = blk: {
2604 const uncasted_payload = case.payload orelse break :blk scope;
2605 const payload = uncasted_payload.castTag(.PointerPayload).?;
2606 const is_ptr = payload.ptr_token != null;
2607 const value_name = tree.tokenSlice(payload.value_symbol.firstToken());
2698 const payload_token = case.payload_token orelse break :blk scope;
2699 const ident = if (token_tags[payload_token] == .asterisk)
2700 payload_token + 1
2701 else
2702 payload_token;
2703 const is_ptr = ident != payload_token;
2704 const value_name = tree.tokenSlice(ident);
26082705 if (mem.eql(u8, value_name, "_")) {
26092706 if (is_ptr) {
26102707 return mod.failTok(scope, payload.ptr_token.?, "pointer modifier invalid on discard", .{});
......@@ -2614,7 +2711,7 @@ fn switchCaseExpr(
26142711 return mod.failNode(scope, payload.value_symbol, "TODO implement switch value payload", .{});
26152712 };
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);
26182715 if (!case_body.tag.isNoReturn()) {
26192716 _ = try addZIRInst(mod, sub_scope, case_src, zir.Inst.Break, .{
26202717 .block = block,
......@@ -2820,12 +2917,13 @@ fn multilineStringLiteral(
28202917 return rvalue(mod, scope, rl, str_inst);
28212918}
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 {
28242921 const tree = scope.tree();
28252922 const node_datas = tree.nodes.items(.data);
28262923 const main_tokens = tree.nodes.items(.main_token);
2827 const src = token_starts[node.token];
2828 const slice = tree.tokenSlice(node.token);
2924 const main_token = main_tokens[node];
2925 const src = token_starts[main_token];
2926 const slice = tree.tokenSlice(main_token);
28292927
28302928 var bad_index: usize = undefined;
28312929 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
28342932 return mod.fail(scope, src + bad_index, "invalid character: '{c}'\n", .{bad_byte});
28352933 },
28362934 };
2837
2838 return addZIRInstConst(mod, scope, src, .{
2935 const result = try addZIRInstConst(mod, scope, src, .{
28392936 .ty = Type.initTag(.comptime_int),
28402937 .val = try Value.Tag.int_u64.create(scope.arena(), value),
28412938 });
2939 return rvalue(mod, scope, rl, result);
28422940}
28432941
28442942fn integerLiteral(
......@@ -3675,6 +3773,29 @@ pub fn addZirInstTag(
36753773 return &inst.base;
36763774}
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
36783799pub fn addZIRInstSpecial(
36793800 mod: *Module,
36803801 scope: *Scope,
src/zir.zig+10-8
......@@ -343,6 +343,8 @@ pub const Inst = struct {
343343 void_value,
344344 /// A switch expression.
345345 switchbr,
346 /// Same as `switchbr` but the target is a pointer to the value being switched on.
347 switchbr_ref,
346348 /// A range in a switch case, `lhs...rhs`.
347349 /// Only checks that `lhs >= rhs` if they are ints, everything else is
348350 /// validated by the .switch instruction.
......@@ -453,6 +455,8 @@ pub const Inst = struct {
453455 .block_comptime_flat,
454456 => Block,
455457
458 .switchbr, .switchbr_ref => SwitchBr,
459
456460 .arg => Arg,
457461 .array_type_sentinel => ArrayTypeSentinel,
458462 .@"break" => Break,
......@@ -488,7 +492,6 @@ pub const Inst = struct {
488492 .enum_type => EnumType,
489493 .union_type => UnionType,
490494 .struct_type => StructType,
491 .switchbr => SwitchBr,
492495 };
493496 }
494497
......@@ -617,7 +620,6 @@ pub const Inst = struct {
617620 .struct_type,
618621 .void_value,
619622 .switch_range,
620 .switchbr,
621623 => false,
622624
623625 .@"break",
......@@ -632,6 +634,8 @@ pub const Inst = struct {
632634 .container_field_named,
633635 .container_field_typed,
634636 .container_field,
637 .switchbr,
638 .switchbr_ref,
635639 => true,
636640 };
637641 }
......@@ -730,6 +734,8 @@ pub const Inst = struct {
730734 kw_args: struct {},
731735 };
732736
737 // TODO break this into multiple call instructions to avoid paying the cost
738 // of the calling convention field most of the time.
733739 pub const Call = struct {
734740 pub const base_tag = Tag.call;
735741 base: Inst,
......@@ -737,10 +743,9 @@ pub const Inst = struct {
737743 positionals: struct {
738744 func: *Inst,
739745 args: []*Inst,
740 },
741 kw_args: struct {
742746 modifier: std.builtin.CallOptions.Modifier = .auto,
743747 },
748 kw_args: struct {},
744749 };
745750
746751 pub const DeclRef = struct {
......@@ -1185,7 +1190,6 @@ pub const Inst = struct {
11851190 };
11861191
11871192 pub const SwitchBr = struct {
1188 pub const base_tag = Tag.switchbr;
11891193 base: Inst,
11901194
11911195 positionals: struct {
......@@ -1194,14 +1198,12 @@ pub const Inst = struct {
11941198 items: []*Inst,
11951199 cases: []Case,
11961200 else_body: Body,
1197 },
1198 kw_args: struct {
11991201 /// Pointer to first range if such exists.
12001202 range: ?*Inst = null,
12011203 special_prong: SpecialProng = .none,
12021204 },
1205 kw_args: struct {},
12031206
1204 // Not anonymous due to stage1 limitations
12051207 pub const SpecialProng = enum {
12061208 none,
12071209 @"else",
src/zir_sema.zig+9-3
......@@ -154,7 +154,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
154154 .bool_and => return zirBoolOp(mod, scope, old_inst.castTag(.bool_and).?),
155155 .bool_or => return zirBoolOp(mod, scope, old_inst.castTag(.bool_or).?),
156156 .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),
158159 .switch_range => return zirSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),
159160
160161 .container_field_named,
......@@ -1554,10 +1555,15 @@ fn zirSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError
15541555 return mod.constVoid(scope, inst.base.src);
15551556}
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 {
15581559 const tracy = trace(@src());
15591560 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;
15611567 try validateSwitch(mod, scope, target, inst);
15621568
15631569 if (try mod.resolveDefinedValue(scope, target)) |target_val| {