| author | |
| committer | |
| log | 0e77259f44307a5d9b1e91723a226f8da6fe97d5 |
| tree | d1dcc77e23fbb38985431b871ecf67ccb2da256c |
| parent | 5baaf90e3c10d197131eaf5908da4401b9a07e7b |
12 files changed, 186 insertions(+), 59 deletions(-)
lib/std/zig/parse.zig+2-2| ... | @@ -3100,7 +3100,7 @@ const Parser = struct { | ... | @@ -3100,7 +3100,7 @@ const Parser = struct { |
| 3100 | return identifier; | 3100 | return identifier; |
| 3101 | } | 3101 | } |
| 3102 | 3102 | ||
| 3103 | /// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrPayload? AssignExpr | 3103 | /// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? AssignExpr |
| 3104 | /// SwitchCase | 3104 | /// SwitchCase |
| 3105 | /// <- SwitchItem (COMMA SwitchItem)* COMMA? | 3105 | /// <- SwitchItem (COMMA SwitchItem)* COMMA? |
| 3106 | /// / KEYWORD_else | 3106 | /// / KEYWORD_else |
| ... | @@ -3123,7 +3123,7 @@ const Parser = struct { | ... | @@ -3123,7 +3123,7 @@ const Parser = struct { |
| 3123 | } | 3123 | } |
| 3124 | } | 3124 | } |
| 3125 | const arrow_token = try p.expectToken(.equal_angle_bracket_right); | 3125 | const arrow_token = try p.expectToken(.equal_angle_bracket_right); |
| 3126 | _ = try p.parsePtrPayload(); | 3126 | _ = try p.parsePtrIndexPayload(); |
| 3127 | 3127 | ||
| 3128 | const items = p.scratch.items[scratch_top..]; | 3128 | const items = p.scratch.items[scratch_top..]; |
| 3129 | switch (items.len) { | 3129 | switch (items.len) { |
lib/std/zig/parser_test.zig+2| ... | @@ -3276,6 +3276,8 @@ test "zig fmt: switch" { | ... | @@ -3276,6 +3276,8 @@ test "zig fmt: switch" { |
| 3276 | \\ switch (u) { | 3276 | \\ switch (u) { |
| 3277 | \\ Union.Int => |int| {}, | 3277 | \\ Union.Int => |int| {}, |
| 3278 | \\ Union.Float => |*float| unreachable, | 3278 | \\ Union.Float => |*float| unreachable, |
| 3279 | \\ 1 => |a, b| unreachable, | ||
| 3280 | \\ 2 => |*a, b| unreachable, | ||
| 3279 | \\ } | 3281 | \\ } |
| 3280 | \\} | 3282 | \\} |
| 3281 | \\ | 3283 | \\ |
lib/std/zig/render.zig+8-4| ... | @@ -1541,13 +1541,17 @@ fn renderSwitchCase( | ... | @@ -1541,13 +1541,17 @@ fn renderSwitchCase( |
| 1541 | 1541 | ||
| 1542 | if (switch_case.payload_token) |payload_token| { | 1542 | if (switch_case.payload_token) |payload_token| { |
| 1543 | try renderToken(ais, tree, payload_token - 1, .none); // pipe | 1543 | try renderToken(ais, tree, payload_token - 1, .none); // pipe |
| 1544 | const ident = payload_token + @boolToInt(token_tags[payload_token] == .asterisk); | ||
| 1544 | if (token_tags[payload_token] == .asterisk) { | 1545 | if (token_tags[payload_token] == .asterisk) { |
| 1545 | try renderToken(ais, tree, payload_token, .none); // asterisk | 1546 | try renderToken(ais, tree, payload_token, .none); // asterisk |
| 1546 | try renderToken(ais, tree, payload_token + 1, .none); // identifier | 1547 | } |
| 1547 | try renderToken(ais, tree, payload_token + 2, pre_target_space); // pipe | 1548 | try renderToken(ais, tree, ident, .none); // identifier |
| 1549 | if (token_tags[ident + 1] == .comma) { | ||
| 1550 | try renderToken(ais, tree, ident + 1, .space); // , | ||
| 1551 | try renderToken(ais, tree, ident + 2, .none); // identifier | ||
| 1552 | try renderToken(ais, tree, ident + 3, pre_target_space); // pipe | ||
| 1548 | } else { | 1553 | } else { |
| 1549 | try renderToken(ais, tree, payload_token, .none); // identifier | 1554 | try renderToken(ais, tree, ident + 1, pre_target_space); // pipe |
| 1550 | try renderToken(ais, tree, payload_token + 1, pre_target_space); // pipe | ||
| 1551 | } | 1555 | } |
| 1552 | } | 1556 | } |
| 1553 | 1557 |
src/AstGen.zig+92-45| ... | @@ -2373,6 +2373,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2373,6 +2373,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2373 | .switch_capture_ref, | 2373 | .switch_capture_ref, |
| 2374 | .switch_capture_multi, | 2374 | .switch_capture_multi, |
| 2375 | .switch_capture_multi_ref, | 2375 | .switch_capture_multi_ref, |
| 2376 | .switch_capture_tag, | ||
| 2376 | .struct_init_empty, | 2377 | .struct_init_empty, |
| 2377 | .struct_init, | 2378 | .struct_init, |
| 2378 | .struct_init_ref, | 2379 | .struct_init_ref, |
| ... | @@ -6378,8 +6379,12 @@ fn switchExpr( | ... | @@ -6378,8 +6379,12 @@ fn switchExpr( |
| 6378 | 6379 | ||
| 6379 | var dbg_var_name: ?u32 = null; | 6380 | var dbg_var_name: ?u32 = null; |
| 6380 | var dbg_var_inst: Zir.Inst.Ref = undefined; | 6381 | var dbg_var_inst: Zir.Inst.Ref = undefined; |
| 6382 | var dbg_var_tag_name: ?u32 = null; | ||
| 6383 | var dbg_var_tag_inst: Zir.Inst.Ref = undefined; | ||
| 6381 | var capture_inst: Zir.Inst.Index = 0; | 6384 | var capture_inst: Zir.Inst.Index = 0; |
| 6385 | var tag_inst: Zir.Inst.Index = 0; | ||
| 6382 | var capture_val_scope: Scope.LocalVal = undefined; | 6386 | var capture_val_scope: Scope.LocalVal = undefined; |
| 6387 | var tag_scope: Scope.LocalVal = undefined; | ||
| 6383 | const sub_scope = blk: { | 6388 | const sub_scope = blk: { |
| 6384 | const payload_token = case.payload_token orelse break :blk &case_scope.base; | 6389 | const payload_token = case.payload_token orelse break :blk &case_scope.base; |
| 6385 | const ident = if (token_tags[payload_token] == .asterisk) | 6390 | const ident = if (token_tags[payload_token] == .asterisk) |
| ... | @@ -6387,59 +6392,96 @@ fn switchExpr( | ... | @@ -6387,59 +6392,96 @@ fn switchExpr( |
| 6387 | else | 6392 | else |
| 6388 | payload_token; | 6393 | payload_token; |
| 6389 | const is_ptr = ident != payload_token; | 6394 | const is_ptr = ident != payload_token; |
| 6390 | if (mem.eql(u8, tree.tokenSlice(ident), "_")) { | 6395 | const ident_slice = tree.tokenSlice(ident); |
| 6396 | var payload_sub_scope: *Scope = undefined; | ||
| 6397 | if (mem.eql(u8, ident_slice, "_")) { | ||
| 6391 | if (is_ptr) { | 6398 | if (is_ptr) { |
| 6392 | return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); | 6399 | return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); |
| 6393 | } | 6400 | } |
| 6394 | break :blk &case_scope.base; | 6401 | payload_sub_scope = &case_scope.base; |
| 6395 | } | ||
| 6396 | if (case_node == special_node) { | ||
| 6397 | const capture_tag: Zir.Inst.Tag = if (is_ptr) | ||
| 6398 | .switch_capture_ref | ||
| 6399 | else | ||
| 6400 | .switch_capture; | ||
| 6401 | capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); | ||
| 6402 | try astgen.instructions.append(gpa, .{ | ||
| 6403 | .tag = capture_tag, | ||
| 6404 | .data = .{ | ||
| 6405 | .switch_capture = .{ | ||
| 6406 | .switch_inst = switch_block, | ||
| 6407 | // Max int communicates that this is the else/underscore prong. | ||
| 6408 | .prong_index = std.math.maxInt(u32), | ||
| 6409 | }, | ||
| 6410 | }, | ||
| 6411 | }); | ||
| 6412 | } else { | 6402 | } else { |
| 6413 | const is_multi_case_bits: u2 = @boolToInt(is_multi_case); | 6403 | if (case_node == special_node) { |
| 6414 | const is_ptr_bits: u2 = @boolToInt(is_ptr); | 6404 | const capture_tag: Zir.Inst.Tag = if (is_ptr) |
| 6415 | const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { | 6405 | .switch_capture_ref |
| 6416 | 0b00 => .switch_capture, | 6406 | else |
| 6417 | 0b01 => .switch_capture_ref, | 6407 | .switch_capture; |
| 6418 | 0b10 => .switch_capture_multi, | 6408 | capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); |
| 6419 | 0b11 => .switch_capture_multi_ref, | 6409 | try astgen.instructions.append(gpa, .{ |
| 6410 | .tag = capture_tag, | ||
| 6411 | .data = .{ | ||
| 6412 | .switch_capture = .{ | ||
| 6413 | .switch_inst = switch_block, | ||
| 6414 | // Max int communicates that this is the else/underscore prong. | ||
| 6415 | .prong_index = std.math.maxInt(u32), | ||
| 6416 | }, | ||
| 6417 | }, | ||
| 6418 | }); | ||
| 6419 | } else { | ||
| 6420 | const is_multi_case_bits: u2 = @boolToInt(is_multi_case); | ||
| 6421 | const is_ptr_bits: u2 = @boolToInt(is_ptr); | ||
| 6422 | const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { | ||
| 6423 | 0b00 => .switch_capture, | ||
| 6424 | 0b01 => .switch_capture_ref, | ||
| 6425 | 0b10 => .switch_capture_multi, | ||
| 6426 | 0b11 => .switch_capture_multi_ref, | ||
| 6427 | }; | ||
| 6428 | const capture_index = if (is_multi_case) multi_case_index else scalar_case_index; | ||
| 6429 | capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); | ||
| 6430 | try astgen.instructions.append(gpa, .{ | ||
| 6431 | .tag = capture_tag, | ||
| 6432 | .data = .{ .switch_capture = .{ | ||
| 6433 | .switch_inst = switch_block, | ||
| 6434 | .prong_index = capture_index, | ||
| 6435 | } }, | ||
| 6436 | }); | ||
| 6437 | } | ||
| 6438 | const capture_name = try astgen.identAsString(ident); | ||
| 6439 | try astgen.detectLocalShadowing(&case_scope.base, capture_name, ident, ident_slice); | ||
| 6440 | capture_val_scope = .{ | ||
| 6441 | .parent = &case_scope.base, | ||
| 6442 | .gen_zir = &case_scope, | ||
| 6443 | .name = capture_name, | ||
| 6444 | .inst = indexToRef(capture_inst), | ||
| 6445 | .token_src = payload_token, | ||
| 6446 | .id_cat = .@"capture", | ||
| 6420 | }; | 6447 | }; |
| 6421 | const capture_index = if (is_multi_case) multi_case_index else scalar_case_index; | 6448 | dbg_var_name = capture_name; |
| 6422 | capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); | 6449 | dbg_var_inst = indexToRef(capture_inst); |
| 6423 | try astgen.instructions.append(gpa, .{ | 6450 | payload_sub_scope = &capture_val_scope.base; |
| 6424 | .tag = capture_tag, | ||
| 6425 | .data = .{ .switch_capture = .{ | ||
| 6426 | .switch_inst = switch_block, | ||
| 6427 | .prong_index = capture_index, | ||
| 6428 | } }, | ||
| 6429 | }); | ||
| 6430 | } | 6451 | } |
| 6431 | const capture_name = try astgen.identAsString(ident); | 6452 | |
| 6432 | capture_val_scope = .{ | 6453 | const tag_token = if (token_tags[ident + 1] == .comma) |
| 6433 | .parent = &case_scope.base, | 6454 | ident + 2 |
| 6455 | else | ||
| 6456 | break :blk payload_sub_scope; | ||
| 6457 | const tag_slice = tree.tokenSlice(tag_token); | ||
| 6458 | if (mem.eql(u8, tag_slice, "_")) { | ||
| 6459 | return astgen.failTok(tag_token, "discard of tag capture; omit it instead", .{}); | ||
| 6460 | } else if (case.inline_token == null) { | ||
| 6461 | return astgen.failTok(tag_token, "tag capture on non-inline prong", .{}); | ||
| 6462 | } | ||
| 6463 | const tag_name = try astgen.identAsString(tag_token); | ||
| 6464 | try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice); | ||
| 6465 | tag_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); | ||
| 6466 | try astgen.instructions.append(gpa, .{ | ||
| 6467 | .tag = .switch_capture_tag, | ||
| 6468 | .data = .{ .un_tok = .{ | ||
| 6469 | .operand = cond, | ||
| 6470 | .src_tok = case_scope.tokenIndexToRelative(tag_token), | ||
| 6471 | } }, | ||
| 6472 | }); | ||
| 6473 | |||
| 6474 | tag_scope = .{ | ||
| 6475 | .parent = payload_sub_scope, | ||
| 6434 | .gen_zir = &case_scope, | 6476 | .gen_zir = &case_scope, |
| 6435 | .name = capture_name, | 6477 | .name = tag_name, |
| 6436 | .inst = indexToRef(capture_inst), | 6478 | .inst = indexToRef(tag_inst), |
| 6437 | .token_src = payload_token, | 6479 | .token_src = tag_token, |
| 6438 | .id_cat = .@"capture", | 6480 | .id_cat = .@"switch tag capture", |
| 6439 | }; | 6481 | }; |
| 6440 | dbg_var_name = capture_name; | 6482 | dbg_var_tag_name = tag_name; |
| 6441 | dbg_var_inst = indexToRef(capture_inst); | 6483 | dbg_var_tag_inst = indexToRef(tag_inst); |
| 6442 | break :blk &capture_val_scope.base; | 6484 | break :blk &tag_scope.base; |
| 6443 | }; | 6485 | }; |
| 6444 | 6486 | ||
| 6445 | const header_index = @intCast(u32, payloads.items.len); | 6487 | const header_index = @intCast(u32, payloads.items.len); |
| ... | @@ -6494,10 +6536,14 @@ fn switchExpr( | ... | @@ -6494,10 +6536,14 @@ fn switchExpr( |
| 6494 | defer case_scope.unstack(); | 6536 | defer case_scope.unstack(); |
| 6495 | 6537 | ||
| 6496 | if (capture_inst != 0) try case_scope.instructions.append(gpa, capture_inst); | 6538 | if (capture_inst != 0) try case_scope.instructions.append(gpa, capture_inst); |
| 6539 | if (tag_inst != 0) try case_scope.instructions.append(gpa, tag_inst); | ||
| 6497 | try case_scope.addDbgBlockBegin(); | 6540 | try case_scope.addDbgBlockBegin(); |
| 6498 | if (dbg_var_name) |some| { | 6541 | if (dbg_var_name) |some| { |
| 6499 | try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); | 6542 | try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); |
| 6500 | } | 6543 | } |
| 6544 | if (dbg_var_tag_name) |some| { | ||
| 6545 | try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_tag_inst); | ||
| 6546 | } | ||
| 6501 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | 6547 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); |
| 6502 | try checkUsed(parent_gz, &case_scope.base, sub_scope); | 6548 | try checkUsed(parent_gz, &case_scope.base, sub_scope); |
| 6503 | try case_scope.addDbgBlockEnd(); | 6549 | try case_scope.addDbgBlockEnd(); |
| ... | @@ -10073,6 +10119,7 @@ const Scope = struct { | ... | @@ -10073,6 +10119,7 @@ const Scope = struct { |
| 10073 | @"local constant", | 10119 | @"local constant", |
| 10074 | @"local variable", | 10120 | @"local variable", |
| 10075 | @"loop index capture", | 10121 | @"loop index capture", |
| 10122 | @"switch tag capture", | ||
| 10076 | @"capture", | 10123 | @"capture", |
| 10077 | }; | 10124 | }; |
| 10078 | 10125 |
src/Sema.zig+28| ... | @@ -799,6 +799,7 @@ fn analyzeBodyInner( | ... | @@ -799,6 +799,7 @@ fn analyzeBodyInner( |
| 799 | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), | 799 | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), |
| 800 | .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), | 800 | .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), |
| 801 | .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), | 801 | .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), |
| 802 | .switch_capture_tag => try sema.zirSwitchCaptureTag(block, inst), | ||
| 802 | .type_info => try sema.zirTypeInfo(block, inst), | 803 | .type_info => try sema.zirTypeInfo(block, inst), |
| 803 | .size_of => try sema.zirSizeOf(block, inst), | 804 | .size_of => try sema.zirSizeOf(block, inst), |
| 804 | .bit_size_of => try sema.zirBitSizeOf(block, inst), | 805 | .bit_size_of => try sema.zirBitSizeOf(block, inst), |
| ... | @@ -9164,6 +9165,33 @@ fn zirSwitchCapture( | ... | @@ -9164,6 +9165,33 @@ fn zirSwitchCapture( |
| 9164 | } | 9165 | } |
| 9165 | } | 9166 | } |
| 9166 | 9167 | ||
| 9168 | fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | ||
| 9169 | const zir_datas = sema.code.instructions.items(.data); | ||
| 9170 | const inst_data = zir_datas[inst].un_tok; | ||
| 9171 | const src = inst_data.src(); | ||
| 9172 | |||
| 9173 | const switch_tag = sema.code.instructions.items(.tag)[Zir.refToIndex(inst_data.operand).?]; | ||
| 9174 | const is_ref = switch_tag == .switch_cond_ref; | ||
| 9175 | const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node; | ||
| 9176 | const operand_ptr = try sema.resolveInst(cond_data.operand); | ||
| 9177 | const operand_ptr_ty = sema.typeOf(operand_ptr); | ||
| 9178 | const operand_ty = if (is_ref) operand_ptr_ty.childType() else operand_ptr_ty; | ||
| 9179 | |||
| 9180 | if (operand_ty.zigTypeTag() != .Union) { | ||
| 9181 | const msg = msg: { | ||
| 9182 | const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{ | ||
| 9183 | operand_ty.fmt(sema.mod), | ||
| 9184 | }); | ||
| 9185 | errdefer msg.destroy(sema.gpa); | ||
| 9186 | try sema.addDeclaredHereNote(msg, operand_ty); | ||
| 9187 | break :msg msg; | ||
| 9188 | }; | ||
| 9189 | return sema.failWithOwnedErrorMsg(msg); | ||
| 9190 | } | ||
| 9191 | |||
| 9192 | return block.inline_case_capture; | ||
| 9193 | } | ||
| 9194 | |||
| 9167 | fn zirSwitchCond( | 9195 | fn zirSwitchCond( |
| 9168 | sema: *Sema, | 9196 | sema: *Sema, |
| 9169 | block: *Block, | 9197 | block: *Block, |
src/Zir.zig+6| ... | @@ -683,6 +683,9 @@ pub const Inst = struct { | ... | @@ -683,6 +683,9 @@ pub const Inst = struct { |
| 683 | /// Result is a pointer to the value. | 683 | /// Result is a pointer to the value. |
| 684 | /// Uses the `switch_capture` field. | 684 | /// Uses the `switch_capture` field. |
| 685 | switch_capture_multi_ref, | 685 | switch_capture_multi_ref, |
| 686 | /// Produces the capture value for an inline switch prong tag capture. | ||
| 687 | /// Uses the `un_tok` field. | ||
| 688 | switch_capture_tag, | ||
| 686 | /// Given a | 689 | /// Given a |
| 687 | /// *A returns *A | 690 | /// *A returns *A |
| 688 | /// *E!A returns *A | 691 | /// *E!A returns *A |
| ... | @@ -1128,6 +1131,7 @@ pub const Inst = struct { | ... | @@ -1128,6 +1131,7 @@ pub const Inst = struct { |
| 1128 | .switch_capture_ref, | 1131 | .switch_capture_ref, |
| 1129 | .switch_capture_multi, | 1132 | .switch_capture_multi, |
| 1130 | .switch_capture_multi_ref, | 1133 | .switch_capture_multi_ref, |
| 1134 | .switch_capture_tag, | ||
| 1131 | .switch_block, | 1135 | .switch_block, |
| 1132 | .switch_cond, | 1136 | .switch_cond, |
| 1133 | .switch_cond_ref, | 1137 | .switch_cond_ref, |
| ... | @@ -1422,6 +1426,7 @@ pub const Inst = struct { | ... | @@ -1422,6 +1426,7 @@ pub const Inst = struct { |
| 1422 | .switch_capture_ref, | 1426 | .switch_capture_ref, |
| 1423 | .switch_capture_multi, | 1427 | .switch_capture_multi, |
| 1424 | .switch_capture_multi_ref, | 1428 | .switch_capture_multi_ref, |
| 1429 | .switch_capture_tag, | ||
| 1425 | .switch_block, | 1430 | .switch_block, |
| 1426 | .switch_cond, | 1431 | .switch_cond, |
| 1427 | .switch_cond_ref, | 1432 | .switch_cond_ref, |
| ... | @@ -1681,6 +1686,7 @@ pub const Inst = struct { | ... | @@ -1681,6 +1686,7 @@ pub const Inst = struct { |
| 1681 | .switch_capture_ref = .switch_capture, | 1686 | .switch_capture_ref = .switch_capture, |
| 1682 | .switch_capture_multi = .switch_capture, | 1687 | .switch_capture_multi = .switch_capture, |
| 1683 | .switch_capture_multi_ref = .switch_capture, | 1688 | .switch_capture_multi_ref = .switch_capture, |
| 1689 | .switch_capture_tag = .un_tok, | ||
| 1684 | .array_base_ptr = .un_node, | 1690 | .array_base_ptr = .un_node, |
| 1685 | .field_base_ptr = .un_node, | 1691 | .field_base_ptr = .un_node, |
| 1686 | .validate_array_init_ty = .pl_node, | 1692 | .validate_array_init_ty = .pl_node, |
src/arch/x86_64/Emit.zig+1-1| ... | @@ -2159,7 +2159,7 @@ const RegisterOrMemory = union(enum) { | ... | @@ -2159,7 +2159,7 @@ const RegisterOrMemory = union(enum) { |
| 2159 | /// Returns size in bits. | 2159 | /// Returns size in bits. |
| 2160 | fn size(reg_or_mem: RegisterOrMemory) u64 { | 2160 | fn size(reg_or_mem: RegisterOrMemory) u64 { |
| 2161 | return switch (reg_or_mem) { | 2161 | return switch (reg_or_mem) { |
| 2162 | .register => |reg| reg.size(), | 2162 | .register => |register| register.size(), |
| 2163 | .memory => |memory| memory.size(), | 2163 | .memory => |memory| memory.size(), |
| 2164 | }; | 2164 | }; |
| 2165 | } | 2165 | } |
src/print_zir.zig+1| ... | @@ -237,6 +237,7 @@ const Writer = struct { | ... | @@ -237,6 +237,7 @@ const Writer = struct { |
| 237 | .ret_tok, | 237 | .ret_tok, |
| 238 | .ensure_err_payload_void, | 238 | .ensure_err_payload_void, |
| 239 | .closure_capture, | 239 | .closure_capture, |
| 240 | .switch_capture_tag, | ||
| 240 | => try self.writeUnTok(stream, inst), | 241 | => try self.writeUnTok(stream, inst), |
| 241 | 242 | ||
| 242 | .bool_br_and, | 243 | .bool_br_and, |
src/stage1/parser.cpp+3-3| ... | @@ -2306,17 +2306,17 @@ static Optional<PtrIndexPayload> ast_parse_ptr_index_payload(ParseContext *pc) { | ... | @@ -2306,17 +2306,17 @@ static Optional<PtrIndexPayload> ast_parse_ptr_index_payload(ParseContext *pc) { |
| 2306 | return Optional<PtrIndexPayload>::some(res); | 2306 | return Optional<PtrIndexPayload>::some(res); |
| 2307 | } | 2307 | } |
| 2308 | 2308 | ||
| 2309 | // SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrPayload? AssignExpr | 2309 | // SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? AssignExpr |
| 2310 | static AstNode *ast_parse_switch_prong(ParseContext *pc) { | 2310 | static AstNode *ast_parse_switch_prong(ParseContext *pc) { |
| 2311 | AstNode *res = ast_parse_switch_case(pc); | 2311 | AstNode *res = ast_parse_switch_case(pc); |
| 2312 | if (res == nullptr) | 2312 | if (res == nullptr) |
| 2313 | return nullptr; | 2313 | return nullptr; |
| 2314 | 2314 | ||
| 2315 | expect_token(pc, TokenIdFatArrow); | 2315 | expect_token(pc, TokenIdFatArrow); |
| 2316 | Optional<PtrPayload> opt_payload = ast_parse_ptr_payload(pc); | 2316 | Optional<PtrIndexPayload> opt_payload = ast_parse_ptr_index_payload(pc); |
| 2317 | AstNode *expr = ast_expect(pc, ast_parse_assign_expr); | 2317 | AstNode *expr = ast_expect(pc, ast_parse_assign_expr); |
| 2318 | 2318 | ||
| 2319 | PtrPayload payload; | 2319 | PtrIndexPayload payload; |
| 2320 | assert(res->type == NodeTypeSwitchProng); | 2320 | assert(res->type == NodeTypeSwitchProng); |
| 2321 | res->data.switch_prong.expr = expr; | 2321 | res->data.switch_prong.expr = expr; |
| 2322 | if (opt_payload.unwrap(&payload)) { | 2322 | if (opt_payload.unwrap(&payload)) { |
test/behavior/inline_switch.zig+14-4| ... | @@ -47,11 +47,21 @@ test "inline switch unions" { | ... | @@ -47,11 +47,21 @@ test "inline switch unions" { |
| 47 | 47 | ||
| 48 | var x: U = .a; | 48 | var x: U = .a; |
| 49 | switch (x) { | 49 | switch (x) { |
| 50 | inline .a, .b => |aorb| { | 50 | inline .a, .b => |aorb, tag| { |
| 51 | try expect(@TypeOf(aorb) == void or @TypeOf(aorb) == u2); | 51 | if (tag == .a) { |
| 52 | try expect(@TypeOf(aorb) == void); | ||
| 53 | } else { | ||
| 54 | try expect(tag == .b); | ||
| 55 | try expect(@TypeOf(aorb) == u2); | ||
| 56 | } | ||
| 52 | }, | 57 | }, |
| 53 | inline .c, .d => |cord| { | 58 | inline .c, .d => |cord, tag| { |
| 54 | try expect(@TypeOf(cord) == u3 or @TypeOf(cord) == u4); | 59 | if (tag == .c) { |
| 60 | try expect(@TypeOf(cord) == u3); | ||
| 61 | } else { | ||
| 62 | try expect(tag == .d); | ||
| 63 | try expect(@TypeOf(cord) == u4); | ||
| 64 | } | ||
| 55 | }, | 65 | }, |
| 56 | } | 66 | } |
| 57 | } | 67 | } |
test/cases/compile_errors/invalid_tag_capture.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const E = enum { a, b, c, d }; | ||
| 2 | pub export fn entry() void { | ||
| 3 | var x: E = .a; | ||
| 4 | switch (x) { | ||
| 5 | inline .a, .b => |aorb, d| @compileLog(aorb, d), | ||
| 6 | inline .c, .d => |*cord| @compileLog(cord), | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :5:33: error: cannot capture tag of non-union type 'tmp.E' | ||
| 15 | // :1:11: note: enum declared here | ||
test/cases/compile_errors/tag_capture_on_non_inline_prong.zig created+14| ... | @@ -0,0 +1,14 @@ | ||
| 1 | const E = enum { a, b, c, d }; | ||
| 2 | pub export fn entry() void { | ||
| 3 | var x: E = .a; | ||
| 4 | switch (x) { | ||
| 5 | .a, .b => |aorb, d| @compileLog(aorb, d), | ||
| 6 | inline .c, .d => |*cord| @compileLog(cord), | ||
| 7 | } | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :5:26: error: tag capture on non-inline prong | ||