| author | |
| committer | |
| log | dfb3231959bb340d260ddbec2b8eabfb5063c1bf |
| tree | 1f91b36fc9ed4b0aaa35fd8f8657efb365f3ec74 |
| parent | 4a76523b92bcf0e9b48438cb22f49e67e0ab3fa1 |
* AstGen: Move `refToIndex` and `indexToRef` to Zir
* ZIR: the switch_block_*_* instruction tags are collapsed into one
switch_block tag which uses 4 bits for flags, and reduces the
scalar_cases_len field from 32 to 28 bits.
This freed up more ZIR tags, 2 of which are now used for
`switch_cond` and `switch_cond_ref` for producing the switch
condition value. For example, for union values it returns the
corresponding enum value.
* switching with multiple cases and ranges is not yet supported because
I want to change the ZIR encoding to store index pointers into the
extra array rather than storing prong indexes. This will avoid O(N^2)
iteration over prongs.
* AstGen now adds a `switch_cond` on the operand and then passes the
result of that to the `switch_block` instruction.
* Sema: partially implement `switch_capture_*` instructions.
* Sema: `unionToTag` notices if the enum type has only one possible value.8 files changed, 422 insertions(+), 474 deletions(-)
src/AstGen.zig+36-66| ... | @@ -11,6 +11,8 @@ const StringIndexAdapter = std.hash_map.StringIndexAdapter; | ... | @@ -11,6 +11,8 @@ const StringIndexAdapter = std.hash_map.StringIndexAdapter; |
| 11 | const StringIndexContext = std.hash_map.StringIndexContext; | 11 | const StringIndexContext = std.hash_map.StringIndexContext; |
| 12 | 12 | ||
| 13 | const Zir = @import("Zir.zig"); | 13 | const Zir = @import("Zir.zig"); |
| 14 | const refToIndex = Zir.refToIndex; | ||
| 15 | const indexToRef = Zir.indexToRef; | ||
| 14 | const trace = @import("tracy.zig").trace; | 16 | const trace = @import("tracy.zig").trace; |
| 15 | const BuiltinFn = @import("BuiltinFn.zig"); | 17 | const BuiltinFn = @import("BuiltinFn.zig"); |
| 16 | 18 | ||
| ... | @@ -57,6 +59,7 @@ fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { | ... | @@ -57,6 +59,7 @@ fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { |
| 57 | Zir.Inst.Ref => @enumToInt(@field(extra, field.name)), | 59 | Zir.Inst.Ref => @enumToInt(@field(extra, field.name)), |
| 58 | i32 => @bitCast(u32, @field(extra, field.name)), | 60 | i32 => @bitCast(u32, @field(extra, field.name)), |
| 59 | Zir.Inst.Call.Flags => @bitCast(u32, @field(extra, field.name)), | 61 | Zir.Inst.Call.Flags => @bitCast(u32, @field(extra, field.name)), |
| 62 | Zir.Inst.SwitchBlock.Bits => @bitCast(u32, @field(extra, field.name)), | ||
| 60 | else => @compileError("bad field type"), | 63 | else => @compileError("bad field type"), |
| 61 | }); | 64 | }); |
| 62 | } | 65 | } |
| ... | @@ -2133,17 +2136,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner | ... | @@ -2133,17 +2136,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2133 | .slice_sentinel, | 2136 | .slice_sentinel, |
| 2134 | .import, | 2137 | .import, |
| 2135 | .switch_block, | 2138 | .switch_block, |
| 2136 | .switch_block_multi, | 2139 | .switch_cond, |
| 2137 | .switch_block_else, | 2140 | .switch_cond_ref, |
| 2138 | .switch_block_else_multi, | ||
| 2139 | .switch_block_under, | ||
| 2140 | .switch_block_under_multi, | ||
| 2141 | .switch_block_ref, | ||
| 2142 | .switch_block_ref_multi, | ||
| 2143 | .switch_block_ref_else, | ||
| 2144 | .switch_block_ref_else_multi, | ||
| 2145 | .switch_block_ref_under, | ||
| 2146 | .switch_block_ref_under_multi, | ||
| 2147 | .switch_capture, | 2141 | .switch_capture, |
| 2148 | .switch_capture_ref, | 2142 | .switch_capture_ref, |
| 2149 | .switch_capture_multi, | 2143 | .switch_capture_multi, |
| ... | @@ -5127,11 +5121,12 @@ fn fieldAccess( | ... | @@ -5127,11 +5121,12 @@ fn fieldAccess( |
| 5127 | rl: ResultLoc, | 5121 | rl: ResultLoc, |
| 5128 | node: Ast.Node.Index, | 5122 | node: Ast.Node.Index, |
| 5129 | ) InnerError!Zir.Inst.Ref { | 5123 | ) InnerError!Zir.Inst.Ref { |
| 5130 | if (rl == .ref) { | 5124 | switch (rl) { |
| 5131 | return addFieldAccess(.field_ptr, gz, scope, .ref, node); | 5125 | .ref => return addFieldAccess(.field_ptr, gz, scope, .ref, node), |
| 5132 | } else { | 5126 | else => { |
| 5133 | const access = try addFieldAccess(.field_val, gz, scope, .none, node); | 5127 | const access = try addFieldAccess(.field_val, gz, scope, .none, node); |
| 5134 | return rvalue(gz, rl, access, node); | 5128 | return rvalue(gz, rl, access, node); |
| 5129 | }, | ||
| 5135 | } | 5130 | } |
| 5136 | } | 5131 | } |
| 5137 | 5132 | ||
| ... | @@ -6028,11 +6023,13 @@ fn switchExpr( | ... | @@ -6028,11 +6023,13 @@ fn switchExpr( |
| 6028 | } | 6023 | } |
| 6029 | 6024 | ||
| 6030 | const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none; | 6025 | const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none; |
| 6031 | const operand = try expr(parent_gz, scope, operand_rl, operand_node); | 6026 | const raw_operand = try expr(parent_gz, scope, operand_rl, operand_node); |
| 6027 | const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond; | ||
| 6028 | const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node); | ||
| 6032 | // We need the type of the operand to use as the result location for all the prong items. | 6029 | // We need the type of the operand to use as the result location for all the prong items. |
| 6033 | const typeof_tag: Zir.Inst.Tag = if (any_payload_is_ref) .typeof_elem else .typeof; | 6030 | const typeof_tag: Zir.Inst.Tag = if (any_payload_is_ref) .typeof_elem else .typeof; |
| 6034 | const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node); | 6031 | const cond_ty_inst = try parent_gz.addUnNode(typeof_tag, cond, operand_node); |
| 6035 | const item_rl: ResultLoc = .{ .ty = operand_ty_inst }; | 6032 | const item_rl: ResultLoc = .{ .ty = cond_ty_inst }; |
| 6036 | 6033 | ||
| 6037 | // These contain the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti. | 6034 | // These contain the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti. |
| 6038 | // This is the optional else prong body. | 6035 | // This is the optional else prong body. |
| ... | @@ -6050,7 +6047,7 @@ fn switchExpr( | ... | @@ -6050,7 +6047,7 @@ fn switchExpr( |
| 6050 | defer block_scope.instructions.deinit(gpa); | 6047 | defer block_scope.instructions.deinit(gpa); |
| 6051 | 6048 | ||
| 6052 | // This gets added to the parent block later, after the item expressions. | 6049 | // This gets added to the parent block later, after the item expressions. |
| 6053 | const switch_block = try parent_gz.addBlock(undefined, switch_node); | 6050 | const switch_block = try parent_gz.addBlock(.switch_block, switch_node); |
| 6054 | 6051 | ||
| 6055 | // We re-use this same scope for all cases, including the special prong, if any. | 6052 | // We re-use this same scope for all cases, including the special prong, if any. |
| 6056 | var case_scope = parent_gz.makeSubBlock(&block_scope.base); | 6053 | var case_scope = parent_gz.makeSubBlock(&block_scope.base); |
| ... | @@ -6203,44 +6200,32 @@ fn switchExpr( | ... | @@ -6203,44 +6200,32 @@ fn switchExpr( |
| 6203 | // Now that the item expressions are generated we can add this. | 6200 | // Now that the item expressions are generated we can add this. |
| 6204 | try parent_gz.instructions.append(gpa, switch_block); | 6201 | try parent_gz.instructions.append(gpa, switch_block); |
| 6205 | 6202 | ||
| 6206 | const ref_bit: u4 = @boolToInt(any_payload_is_ref); | 6203 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len + |
| 6207 | const multi_bit: u4 = @boolToInt(multi_cases_len != 0); | ||
| 6208 | const special_prong_bits: u4 = @enumToInt(special_prong); | ||
| 6209 | comptime { | ||
| 6210 | assert(@enumToInt(Zir.SpecialProng.none) == 0b00); | ||
| 6211 | assert(@enumToInt(Zir.SpecialProng.@"else") == 0b01); | ||
| 6212 | assert(@enumToInt(Zir.SpecialProng.under) == 0b10); | ||
| 6213 | } | ||
| 6214 | const zir_tags = astgen.instructions.items(.tag); | ||
| 6215 | zir_tags[switch_block] = switch ((ref_bit << 3) | (special_prong_bits << 1) | multi_bit) { | ||
| 6216 | 0b0_00_0 => .switch_block, | ||
| 6217 | 0b0_00_1 => .switch_block_multi, | ||
| 6218 | 0b0_01_0 => .switch_block_else, | ||
| 6219 | 0b0_01_1 => .switch_block_else_multi, | ||
| 6220 | 0b0_10_0 => .switch_block_under, | ||
| 6221 | 0b0_10_1 => .switch_block_under_multi, | ||
| 6222 | 0b1_00_0 => .switch_block_ref, | ||
| 6223 | 0b1_00_1 => .switch_block_ref_multi, | ||
| 6224 | 0b1_01_0 => .switch_block_ref_else, | ||
| 6225 | 0b1_01_1 => .switch_block_ref_else_multi, | ||
| 6226 | 0b1_10_0 => .switch_block_ref_under, | ||
| 6227 | 0b1_10_1 => .switch_block_ref_under_multi, | ||
| 6228 | else => unreachable, | ||
| 6229 | }; | ||
| 6230 | const payload_index = astgen.extra.items.len; | ||
| 6231 | const zir_datas = astgen.instructions.items(.data); | ||
| 6232 | zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index); | ||
| 6233 | // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`. | ||
| 6234 | try astgen.extra.ensureUnusedCapacity(gpa, @as(usize, 2) + // operand, scalar_cases_len | ||
| 6235 | @boolToInt(multi_cases_len != 0) + | 6204 | @boolToInt(multi_cases_len != 0) + |
| 6236 | special_case_payload.items.len + | 6205 | special_case_payload.items.len + |
| 6237 | scalar_cases_payload.items.len + | 6206 | scalar_cases_payload.items.len + |
| 6238 | multi_cases_payload.items.len); | 6207 | multi_cases_payload.items.len); |
| 6239 | astgen.extra.appendAssumeCapacity(@enumToInt(operand)); | 6208 | |
| 6240 | astgen.extra.appendAssumeCapacity(scalar_cases_len); | 6209 | const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{ |
| 6210 | .operand = cond, | ||
| 6211 | .bits = Zir.Inst.SwitchBlock.Bits{ | ||
| 6212 | .is_ref = any_payload_is_ref, | ||
| 6213 | .has_multi_cases = multi_cases_len != 0, | ||
| 6214 | .has_else = special_prong == .@"else", | ||
| 6215 | .has_under = special_prong == .under, | ||
| 6216 | .scalar_cases_len = @intCast(u28, scalar_cases_len), | ||
| 6217 | }, | ||
| 6218 | }); | ||
| 6219 | |||
| 6220 | const zir_datas = astgen.instructions.items(.data); | ||
| 6221 | const zir_tags = astgen.instructions.items(.tag); | ||
| 6222 | |||
| 6223 | zir_datas[switch_block].pl_node.payload_index = payload_index; | ||
| 6224 | |||
| 6241 | if (multi_cases_len != 0) { | 6225 | if (multi_cases_len != 0) { |
| 6242 | astgen.extra.appendAssumeCapacity(multi_cases_len); | 6226 | astgen.extra.appendAssumeCapacity(multi_cases_len); |
| 6243 | } | 6227 | } |
| 6228 | |||
| 6244 | const strat = rl.strategy(&block_scope); | 6229 | const strat = rl.strategy(&block_scope); |
| 6245 | switch (strat.tag) { | 6230 | switch (strat.tag) { |
| 6246 | .break_operand => { | 6231 | .break_operand => { |
| ... | @@ -10622,21 +10607,6 @@ fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void { | ... | @@ -10622,21 +10607,6 @@ fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void { |
| 10622 | astgen.source_column = column; | 10607 | astgen.source_column = column; |
| 10623 | } | 10608 | } |
| 10624 | 10609 | ||
| 10625 | const ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len; | ||
| 10626 | |||
| 10627 | fn indexToRef(inst: Zir.Inst.Index) Zir.Inst.Ref { | ||
| 10628 | return @intToEnum(Zir.Inst.Ref, ref_start_index + inst); | ||
| 10629 | } | ||
| 10630 | |||
| 10631 | fn refToIndex(inst: Zir.Inst.Ref) ?Zir.Inst.Index { | ||
| 10632 | const ref_int = @enumToInt(inst); | ||
| 10633 | if (ref_int >= ref_start_index) { | ||
| 10634 | return ref_int - ref_start_index; | ||
| 10635 | } else { | ||
| 10636 | return null; | ||
| 10637 | } | ||
| 10638 | } | ||
| 10639 | |||
| 10640 | fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.Node.Index) !void { | 10610 | fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.Node.Index) !void { |
| 10641 | const gpa = astgen.gpa; | 10611 | const gpa = astgen.gpa; |
| 10642 | const tree = astgen.tree; | 10612 | const tree = astgen.tree; |
src/Sema.zig+206-125| ... | @@ -550,18 +550,9 @@ pub fn analyzeBody( | ... | @@ -550,18 +550,9 @@ pub fn analyzeBody( |
| 550 | .slice_sentinel => try sema.zirSliceSentinel(block, inst), | 550 | .slice_sentinel => try sema.zirSliceSentinel(block, inst), |
| 551 | .slice_start => try sema.zirSliceStart(block, inst), | 551 | .slice_start => try sema.zirSliceStart(block, inst), |
| 552 | .str => try sema.zirStr(block, inst), | 552 | .str => try sema.zirStr(block, inst), |
| 553 | .switch_block => try sema.zirSwitchBlock(block, inst, false, .none), | 553 | .switch_block => try sema.zirSwitchBlock(block, inst), |
| 554 | .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none), | 554 | .switch_cond => try sema.zirSwitchCond(block, inst, false), |
| 555 | .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"), | 555 | .switch_cond_ref => try sema.zirSwitchCond(block, inst, true), |
| 556 | .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"), | ||
| 557 | .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under), | ||
| 558 | .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under), | ||
| 559 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none), | ||
| 560 | .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none), | ||
| 561 | .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"), | ||
| 562 | .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"), | ||
| 563 | .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under), | ||
| 564 | .switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under), | ||
| 565 | .switch_capture => try sema.zirSwitchCapture(block, inst, false, false), | 556 | .switch_capture => try sema.zirSwitchCapture(block, inst, false, false), |
| 566 | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), | 557 | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), |
| 567 | .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), | 558 | .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), |
| ... | @@ -5433,11 +5424,80 @@ fn zirSwitchCapture( | ... | @@ -5433,11 +5424,80 @@ fn zirSwitchCapture( |
| 5433 | const zir_datas = sema.code.instructions.items(.data); | 5424 | const zir_datas = sema.code.instructions.items(.data); |
| 5434 | const capture_info = zir_datas[inst].switch_capture; | 5425 | const capture_info = zir_datas[inst].switch_capture; |
| 5435 | const switch_info = zir_datas[capture_info.switch_inst].pl_node; | 5426 | const switch_info = zir_datas[capture_info.switch_inst].pl_node; |
| 5436 | const src = switch_info.src(); | 5427 | const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index); |
| 5428 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node }; | ||
| 5429 | const switch_src = switch_info.src(); | ||
| 5430 | const operand_is_ref = switch_extra.data.bits.is_ref; | ||
| 5431 | const cond_inst = Zir.refToIndex(switch_extra.data.operand).?; | ||
| 5432 | const cond_info = sema.code.instructions.items(.data)[cond_inst].un_node; | ||
| 5433 | const operand_ptr = sema.resolveInst(cond_info.operand); | ||
| 5434 | const operand_ptr_ty = sema.typeOf(operand_ptr); | ||
| 5435 | const operand_ty = if (operand_is_ref) operand_ptr_ty.childType() else operand_ptr_ty; | ||
| 5436 | |||
| 5437 | if (is_multi) { | ||
| 5438 | return sema.fail(block, switch_src, "TODO implement Sema for switch capture multi", .{}); | ||
| 5439 | } | ||
| 5440 | const scalar_prong = switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index); | ||
| 5441 | const item = sema.resolveInst(scalar_prong.item); | ||
| 5442 | // Previous switch validation ensured this will succeed | ||
| 5443 | const item_val = sema.resolveConstValue(block, .unneeded, item) catch unreachable; | ||
| 5437 | 5444 | ||
| 5438 | _ = is_ref; | 5445 | switch (operand_ty.zigTypeTag()) { |
| 5439 | _ = is_multi; | 5446 | .Union => { |
| 5440 | return sema.fail(block, src, "TODO implement Sema for zirSwitchCapture", .{}); | 5447 | const union_obj = operand_ty.cast(Type.Payload.Union).?.data; |
| 5448 | const enum_ty = union_obj.tag_ty; | ||
| 5449 | |||
| 5450 | const field_index_usize = enum_ty.enumTagFieldIndex(item_val).?; | ||
| 5451 | const field_index = @intCast(u32, field_index_usize); | ||
| 5452 | const field = union_obj.fields.values()[field_index]; | ||
| 5453 | |||
| 5454 | // TODO handle multiple union tags which have compatible types | ||
| 5455 | |||
| 5456 | if (is_ref) { | ||
| 5457 | assert(operand_is_ref); | ||
| 5458 | |||
| 5459 | const field_ty_ptr = try Type.ptr(sema.arena, .{ | ||
| 5460 | .pointee_type = field.ty, | ||
| 5461 | .@"addrspace" = .generic, | ||
| 5462 | .mutable = operand_ptr_ty.ptrIsMutable(), | ||
| 5463 | }); | ||
| 5464 | |||
| 5465 | if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| { | ||
| 5466 | return sema.addConstant( | ||
| 5467 | field_ty_ptr, | ||
| 5468 | try Value.Tag.field_ptr.create(sema.arena, .{ | ||
| 5469 | .container_ptr = op_ptr_val, | ||
| 5470 | .field_index = field_index, | ||
| 5471 | }), | ||
| 5472 | ); | ||
| 5473 | } | ||
| 5474 | try sema.requireRuntimeBlock(block, operand_src); | ||
| 5475 | return block.addStructFieldPtr(operand_ptr, field_index, field.ty); | ||
| 5476 | } | ||
| 5477 | |||
| 5478 | const operand = if (operand_is_ref) | ||
| 5479 | try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src) | ||
| 5480 | else | ||
| 5481 | operand_ptr; | ||
| 5482 | |||
| 5483 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| { | ||
| 5484 | return sema.addConstant( | ||
| 5485 | field.ty, | ||
| 5486 | operand_val.castTag(.@"union").?.data.val, | ||
| 5487 | ); | ||
| 5488 | } | ||
| 5489 | try sema.requireRuntimeBlock(block, operand_src); | ||
| 5490 | return block.addStructFieldVal(operand, field_index, field.ty); | ||
| 5491 | }, | ||
| 5492 | .ErrorSet => { | ||
| 5493 | return sema.fail(block, operand_src, "TODO implement Sema for zirSwitchCapture for error sets", .{}); | ||
| 5494 | }, | ||
| 5495 | else => { | ||
| 5496 | return sema.fail(block, operand_src, "switch on type '{}' provides no capture value", .{ | ||
| 5497 | operand_ty, | ||
| 5498 | }); | ||
| 5499 | }, | ||
| 5500 | } | ||
| 5441 | } | 5501 | } |
| 5442 | 5502 | ||
| 5443 | fn zirSwitchCaptureElse( | 5503 | fn zirSwitchCaptureElse( |
| ... | @@ -5452,96 +5512,108 @@ fn zirSwitchCaptureElse( | ... | @@ -5452,96 +5512,108 @@ fn zirSwitchCaptureElse( |
| 5452 | const zir_datas = sema.code.instructions.items(.data); | 5512 | const zir_datas = sema.code.instructions.items(.data); |
| 5453 | const capture_info = zir_datas[inst].switch_capture; | 5513 | const capture_info = zir_datas[inst].switch_capture; |
| 5454 | const switch_info = zir_datas[capture_info.switch_inst].pl_node; | 5514 | const switch_info = zir_datas[capture_info.switch_inst].pl_node; |
| 5515 | const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index).data; | ||
| 5455 | const src = switch_info.src(); | 5516 | const src = switch_info.src(); |
| 5517 | const operand_is_ref = switch_extra.bits.is_ref; | ||
| 5518 | assert(!is_ref or operand_is_ref); | ||
| 5456 | 5519 | ||
| 5457 | _ = is_ref; | ||
| 5458 | return sema.fail(block, src, "TODO implement Sema for zirSwitchCaptureElse", .{}); | 5520 | return sema.fail(block, src, "TODO implement Sema for zirSwitchCaptureElse", .{}); |
| 5459 | } | 5521 | } |
| 5460 | 5522 | ||
| 5461 | fn zirSwitchBlock( | 5523 | fn zirSwitchCond( |
| 5462 | sema: *Sema, | 5524 | sema: *Sema, |
| 5463 | block: *Block, | 5525 | block: *Block, |
| 5464 | inst: Zir.Inst.Index, | 5526 | inst: Zir.Inst.Index, |
| 5465 | is_ref: bool, | 5527 | is_ref: bool, |
| 5466 | special_prong: Zir.SpecialProng, | ||
| 5467 | ) CompileError!Air.Inst.Ref { | 5528 | ) CompileError!Air.Inst.Ref { |
| 5468 | const tracy = trace(@src()); | 5529 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 5469 | defer tracy.end(); | ||
| 5470 | |||
| 5471 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 5472 | const src = inst_data.src(); | 5530 | const src = inst_data.src(); |
| 5473 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; | 5531 | const operand_ptr = sema.resolveInst(inst_data.operand); |
| 5474 | const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); | 5532 | const operand = if (is_ref) try sema.analyzeLoad(block, src, operand_ptr, src) else operand_ptr; |
| 5533 | const operand_ty = sema.typeOf(operand); | ||
| 5475 | 5534 | ||
| 5476 | const operand_ptr = sema.resolveInst(extra.data.operand); | 5535 | switch (operand_ty.zigTypeTag()) { |
| 5477 | const operand = if (is_ref) | 5536 | .Type, |
| 5478 | try sema.analyzeLoad(block, src, operand_ptr, operand_src) | 5537 | .Void, |
| 5479 | else | 5538 | .Bool, |
| 5480 | operand_ptr; | 5539 | .Int, |
| 5540 | .Float, | ||
| 5541 | .ComptimeFloat, | ||
| 5542 | .ComptimeInt, | ||
| 5543 | .EnumLiteral, | ||
| 5544 | .Pointer, | ||
| 5545 | .Fn, | ||
| 5546 | .ErrorSet, | ||
| 5547 | .Enum, | ||
| 5548 | => { | ||
| 5549 | if ((try sema.typeHasOnePossibleValue(block, src, operand_ty))) |opv| { | ||
| 5550 | return sema.addConstant(operand_ty, opv); | ||
| 5551 | } | ||
| 5552 | return operand; | ||
| 5553 | }, | ||
| 5481 | 5554 | ||
| 5482 | return sema.analyzeSwitch( | 5555 | .Union => { |
| 5483 | block, | 5556 | const enum_ty = operand_ty.unionTagType() orelse { |
| 5484 | operand, | 5557 | const msg = msg: { |
| 5485 | extra.end, | 5558 | const msg = try sema.errMsg(block, src, "switch on untagged union", .{}); |
| 5486 | special_prong, | 5559 | errdefer msg.destroy(sema.gpa); |
| 5487 | extra.data.cases_len, | 5560 | try sema.addDeclaredHereNote(msg, operand_ty); |
| 5488 | 0, | 5561 | break :msg msg; |
| 5489 | inst, | 5562 | }; |
| 5490 | inst_data.src_node, | 5563 | return sema.failWithOwnedErrorMsg(msg); |
| 5491 | ); | 5564 | }; |
| 5565 | return sema.unionToTag(block, enum_ty, operand, src); | ||
| 5566 | }, | ||
| 5567 | |||
| 5568 | .ErrorUnion, | ||
| 5569 | .NoReturn, | ||
| 5570 | .Array, | ||
| 5571 | .Struct, | ||
| 5572 | .Undefined, | ||
| 5573 | .Null, | ||
| 5574 | .Optional, | ||
| 5575 | .BoundFn, | ||
| 5576 | .Opaque, | ||
| 5577 | .Vector, | ||
| 5578 | .Frame, | ||
| 5579 | .AnyFrame, | ||
| 5580 | => return sema.fail(block, src, "switch on type '{}'", .{operand_ty}), | ||
| 5581 | } | ||
| 5492 | } | 5582 | } |
| 5493 | 5583 | ||
| 5494 | fn zirSwitchBlockMulti( | 5584 | fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 5495 | sema: *Sema, | ||
| 5496 | block: *Block, | ||
| 5497 | inst: Zir.Inst.Index, | ||
| 5498 | is_ref: bool, | ||
| 5499 | special_prong: Zir.SpecialProng, | ||
| 5500 | ) CompileError!Air.Inst.Ref { | ||
| 5501 | const tracy = trace(@src()); | 5585 | const tracy = trace(@src()); |
| 5502 | defer tracy.end(); | 5586 | defer tracy.end(); |
| 5503 | 5587 | ||
| 5588 | const gpa = sema.gpa; | ||
| 5504 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 5589 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 5505 | const src = inst_data.src(); | 5590 | const src = inst_data.src(); |
| 5506 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; | 5591 | const src_node_offset = inst_data.src_node; |
| 5507 | const extra = sema.code.extraData(Zir.Inst.SwitchBlockMulti, inst_data.payload_index); | 5592 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset }; |
| 5593 | const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset }; | ||
| 5594 | const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); | ||
| 5508 | 5595 | ||
| 5509 | const operand_ptr = sema.resolveInst(extra.data.operand); | 5596 | const operand_ptr = sema.resolveInst(extra.data.operand); |
| 5510 | const operand = if (is_ref) | 5597 | const operand = if (extra.data.bits.is_ref) |
| 5511 | try sema.analyzeLoad(block, src, operand_ptr, operand_src) | 5598 | try sema.analyzeLoad(block, src, operand_ptr, operand_src) |
| 5512 | else | 5599 | else |
| 5513 | operand_ptr; | 5600 | operand_ptr; |
| 5514 | 5601 | ||
| 5515 | return sema.analyzeSwitch( | 5602 | var header_extra_index: usize = extra.end; |
| 5516 | block, | ||
| 5517 | operand, | ||
| 5518 | extra.end, | ||
| 5519 | special_prong, | ||
| 5520 | extra.data.scalar_cases_len, | ||
| 5521 | extra.data.multi_cases_len, | ||
| 5522 | inst, | ||
| 5523 | inst_data.src_node, | ||
| 5524 | ); | ||
| 5525 | } | ||
| 5526 | 5603 | ||
| 5527 | fn analyzeSwitch( | 5604 | const scalar_cases_len = extra.data.bits.scalar_cases_len; |
| 5528 | sema: *Sema, | 5605 | const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: { |
| 5529 | block: *Block, | 5606 | const multi_cases_len = sema.code.extra[header_extra_index]; |
| 5530 | operand: Air.Inst.Ref, | 5607 | header_extra_index += 1; |
| 5531 | extra_end: usize, | 5608 | break :blk multi_cases_len; |
| 5532 | special_prong: Zir.SpecialProng, | 5609 | } else 0; |
| 5533 | scalar_cases_len: usize, | ||
| 5534 | multi_cases_len: usize, | ||
| 5535 | switch_inst: Zir.Inst.Index, | ||
| 5536 | src_node_offset: i32, | ||
| 5537 | ) CompileError!Air.Inst.Ref { | ||
| 5538 | const gpa = sema.gpa; | ||
| 5539 | 5610 | ||
| 5611 | const special_prong = extra.data.bits.specialProng(); | ||
| 5540 | const special: struct { body: []const Zir.Inst.Index, end: usize } = switch (special_prong) { | 5612 | const special: struct { body: []const Zir.Inst.Index, end: usize } = switch (special_prong) { |
| 5541 | .none => .{ .body = &.{}, .end = extra_end }, | 5613 | .none => .{ .body = &.{}, .end = header_extra_index }, |
| 5542 | .under, .@"else" => blk: { | 5614 | .under, .@"else" => blk: { |
| 5543 | const body_len = sema.code.extra[extra_end]; | 5615 | const body_len = sema.code.extra[header_extra_index]; |
| 5544 | const extra_body_start = extra_end + 1; | 5616 | const extra_body_start = header_extra_index + 1; |
| 5545 | break :blk .{ | 5617 | break :blk .{ |
| 5546 | .body = sema.code.extra[extra_body_start..][0..body_len], | 5618 | .body = sema.code.extra[extra_body_start..][0..body_len], |
| 5547 | .end = extra_body_start + body_len, | 5619 | .end = extra_body_start + body_len, |
| ... | @@ -5549,9 +5621,6 @@ fn analyzeSwitch( | ... | @@ -5549,9 +5621,6 @@ fn analyzeSwitch( |
| 5549 | }, | 5621 | }, |
| 5550 | }; | 5622 | }; |
| 5551 | 5623 | ||
| 5552 | const src: LazySrcLoc = .{ .node_offset = src_node_offset }; | ||
| 5553 | const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset }; | ||
| 5554 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset }; | ||
| 5555 | const operand_ty = sema.typeOf(operand); | 5624 | const operand_ty = sema.typeOf(operand); |
| 5556 | 5625 | ||
| 5557 | // Validate usage of '_' prongs. | 5626 | // Validate usage of '_' prongs. |
| ... | @@ -5945,7 +6014,7 @@ fn analyzeSwitch( | ... | @@ -5945,7 +6014,7 @@ fn analyzeSwitch( |
| 5945 | .data = undefined, | 6014 | .data = undefined, |
| 5946 | }); | 6015 | }); |
| 5947 | var label: Block.Label = .{ | 6016 | var label: Block.Label = .{ |
| 5948 | .zir_block = switch_inst, | 6017 | .zir_block = inst, |
| 5949 | .merges = .{ | 6018 | .merges = .{ |
| 5950 | .results = .{}, | 6019 | .results = .{}, |
| 5951 | .br_list = .{}, | 6020 | .br_list = .{}, |
| ... | @@ -8934,8 +9003,9 @@ fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) | ... | @@ -8934,8 +9003,9 @@ fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) |
| 8934 | const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node }; | 9003 | const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node }; |
| 8935 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; | 9004 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; |
| 8936 | const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); | 9005 | const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); |
| 8937 | const field_index = union_obj.fields.getIndex(field_name) orelse | 9006 | const field_index_usize = union_obj.fields.getIndex(field_name) orelse |
| 8938 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); | 9007 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); |
| 9008 | const field_index = @intCast(u32, field_index_usize); | ||
| 8939 | 9009 | ||
| 8940 | if (is_ref) { | 9010 | if (is_ref) { |
| 8941 | return sema.fail(block, src, "TODO: Sema.zirStructInit is_ref=true union", .{}); | 9011 | return sema.fail(block, src, "TODO: Sema.zirStructInit is_ref=true union", .{}); |
| ... | @@ -8943,12 +9013,10 @@ fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) | ... | @@ -8943,12 +9013,10 @@ fn zirStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) |
| 8943 | 9013 | ||
| 8944 | const init_inst = sema.resolveInst(item.data.init); | 9014 | const init_inst = sema.resolveInst(item.data.init); |
| 8945 | if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| { | 9015 | if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| { |
| 9016 | const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); | ||
| 8946 | return sema.addConstant( | 9017 | return sema.addConstant( |
| 8947 | resolved_ty, | 9018 | resolved_ty, |
| 8948 | try Value.Tag.@"union".create(sema.arena, .{ | 9019 | try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = val }), |
| 8949 | .tag = try Value.Tag.int_u64.create(sema.arena, field_index), | ||
| 8950 | .val = val, | ||
| 8951 | }), | ||
| 8952 | ); | 9020 | ); |
| 8953 | } | 9021 | } |
| 8954 | return sema.fail(block, src, "TODO: Sema.zirStructInit for runtime-known union values", .{}); | 9022 | return sema.fail(block, src, "TODO: Sema.zirStructInit for runtime-known union values", .{}); |
| ... | @@ -9152,8 +9220,8 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -9152,8 +9220,8 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 9152 | const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); | 9220 | const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); |
| 9153 | const val = try sema.resolveConstValue(block, operand_src, type_info); | 9221 | const val = try sema.resolveConstValue(block, operand_src, type_info); |
| 9154 | const union_val = val.cast(Value.Payload.Union).?.data; | 9222 | const union_val = val.cast(Value.Payload.Union).?.data; |
| 9155 | const TypeInfoTag = std.meta.Tag(std.builtin.TypeInfo); | 9223 | const tag_ty = type_info_ty.unionTagType().?; |
| 9156 | const tag_index = @intCast(std.meta.Tag(TypeInfoTag), union_val.tag.toUnsignedInt()); | 9224 | const tag_index = tag_ty.enumTagFieldIndex(union_val.tag).?; |
| 9157 | switch (@intToEnum(std.builtin.TypeId, tag_index)) { | 9225 | switch (@intToEnum(std.builtin.TypeId, tag_index)) { |
| 9158 | .Type => return Air.Inst.Ref.type_type, | 9226 | .Type => return Air.Inst.Ref.type_type, |
| 9159 | .Void => return Air.Inst.Ref.void_type, | 9227 | .Void => return Air.Inst.Ref.void_type, |
| ... | @@ -10819,10 +10887,39 @@ fn fieldVal( | ... | @@ -10819,10 +10887,39 @@ fn fieldVal( |
| 10819 | try Value.Tag.@"error".create(arena, .{ .name = name }), | 10887 | try Value.Tag.@"error".create(arena, .{ .name = name }), |
| 10820 | ); | 10888 | ); |
| 10821 | }, | 10889 | }, |
| 10822 | .Struct, .Opaque, .Union => { | 10890 | .Union => { |
| 10823 | if (child_type.getNamespace()) |namespace| { | 10891 | if (child_type.getNamespace()) |namespace| { |
| 10824 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { | 10892 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { |
| 10825 | return sema.analyzeLoad(block, src, inst, src); | 10893 | return inst; |
| 10894 | } | ||
| 10895 | } | ||
| 10896 | if (child_type.unionTagType()) |enum_ty| { | ||
| 10897 | if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| { | ||
| 10898 | const field_index = @intCast(u32, field_index_usize); | ||
| 10899 | return sema.addConstant( | ||
| 10900 | enum_ty, | ||
| 10901 | try Value.Tag.enum_field_index.create(sema.arena, field_index), | ||
| 10902 | ); | ||
| 10903 | } | ||
| 10904 | } | ||
| 10905 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | ||
| 10906 | }, | ||
| 10907 | .Enum => { | ||
| 10908 | if (child_type.getNamespace()) |namespace| { | ||
| 10909 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { | ||
| 10910 | return inst; | ||
| 10911 | } | ||
| 10912 | } | ||
| 10913 | const field_index_usize = child_type.enumFieldIndex(field_name) orelse | ||
| 10914 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | ||
| 10915 | const field_index = @intCast(u32, field_index_usize); | ||
| 10916 | const enum_val = try Value.Tag.enum_field_index.create(arena, field_index); | ||
| 10917 | return sema.addConstant(try child_type.copy(arena), enum_val); | ||
| 10918 | }, | ||
| 10919 | .Struct, .Opaque => { | ||
| 10920 | if (child_type.getNamespace()) |namespace| { | ||
| 10921 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { | ||
| 10922 | return inst; | ||
| 10826 | } | 10923 | } |
| 10827 | } | 10924 | } |
| 10828 | // TODO add note: declared here | 10925 | // TODO add note: declared here |
| ... | @@ -10836,35 +10933,6 @@ fn fieldVal( | ... | @@ -10836,35 +10933,6 @@ fn fieldVal( |
| 10836 | kw_name, child_type, field_name, | 10933 | kw_name, child_type, field_name, |
| 10837 | }); | 10934 | }); |
| 10838 | }, | 10935 | }, |
| 10839 | .Enum => { | ||
| 10840 | if (child_type.getNamespace()) |namespace| { | ||
| 10841 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { | ||
| 10842 | return sema.analyzeLoad(block, src, inst, src); | ||
| 10843 | } | ||
| 10844 | } | ||
| 10845 | const field_index = child_type.enumFieldIndex(field_name) orelse { | ||
| 10846 | const msg = msg: { | ||
| 10847 | const msg = try sema.errMsg( | ||
| 10848 | block, | ||
| 10849 | src, | ||
| 10850 | "enum '{}' has no member named '{s}'", | ||
| 10851 | .{ child_type, field_name }, | ||
| 10852 | ); | ||
| 10853 | errdefer msg.destroy(sema.gpa); | ||
| 10854 | try sema.mod.errNoteNonLazy( | ||
| 10855 | child_type.declSrcLoc(), | ||
| 10856 | msg, | ||
| 10857 | "enum declared here", | ||
| 10858 | .{}, | ||
| 10859 | ); | ||
| 10860 | break :msg msg; | ||
| 10861 | }; | ||
| 10862 | return sema.failWithOwnedErrorMsg(msg); | ||
| 10863 | }; | ||
| 10864 | const field_index_u32 = @intCast(u32, field_index); | ||
| 10865 | const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32); | ||
| 10866 | return sema.addConstant(try child_type.copy(arena), enum_val); | ||
| 10867 | }, | ||
| 10868 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), | 10936 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type}), |
| 10869 | } | 10937 | } |
| 10870 | }, | 10938 | }, |
| ... | @@ -11244,6 +11312,17 @@ fn namespaceLookupRef( | ... | @@ -11244,6 +11312,17 @@ fn namespaceLookupRef( |
| 11244 | return try sema.analyzeDeclRef(decl); | 11312 | return try sema.analyzeDeclRef(decl); |
| 11245 | } | 11313 | } |
| 11246 | 11314 | ||
| 11315 | fn namespaceLookupVal( | ||
| 11316 | sema: *Sema, | ||
| 11317 | block: *Block, | ||
| 11318 | src: LazySrcLoc, | ||
| 11319 | namespace: *Namespace, | ||
| 11320 | decl_name: []const u8, | ||
| 11321 | ) CompileError!?Air.Inst.Ref { | ||
| 11322 | const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; | ||
| 11323 | return try sema.analyzeDeclVal(block, src, decl); | ||
| 11324 | } | ||
| 11325 | |||
| 11247 | fn structFieldPtr( | 11326 | fn structFieldPtr( |
| 11248 | sema: *Sema, | 11327 | sema: *Sema, |
| 11249 | block: *Block, | 11328 | block: *Block, |
| ... | @@ -11370,10 +11449,9 @@ fn unionFieldVal( | ... | @@ -11370,10 +11449,9 @@ fn unionFieldVal( |
| 11370 | const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty); | 11449 | const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty); |
| 11371 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 11450 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; |
| 11372 | 11451 | ||
| 11373 | const field_index_big = union_obj.fields.getIndex(field_name) orelse | 11452 | const field_index_usize = union_obj.fields.getIndex(field_name) orelse |
| 11374 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name); | 11453 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name); |
| 11375 | const field_index = @intCast(u32, field_index_big); | 11454 | const field_index = @intCast(u32, field_index_usize); |
| 11376 | |||
| 11377 | const field = union_obj.fields.values()[field_index]; | 11455 | const field = union_obj.fields.values()[field_index]; |
| 11378 | 11456 | ||
| 11379 | if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| { | 11457 | if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| { |
| ... | @@ -12960,15 +13038,18 @@ fn wrapErrorUnion( | ... | @@ -12960,15 +13038,18 @@ fn wrapErrorUnion( |
| 12960 | fn unionToTag( | 13038 | fn unionToTag( |
| 12961 | sema: *Sema, | 13039 | sema: *Sema, |
| 12962 | block: *Block, | 13040 | block: *Block, |
| 12963 | dest_ty: Type, | 13041 | enum_ty: Type, |
| 12964 | un: Air.Inst.Ref, | 13042 | un: Air.Inst.Ref, |
| 12965 | un_src: LazySrcLoc, | 13043 | un_src: LazySrcLoc, |
| 12966 | ) !Air.Inst.Ref { | 13044 | ) !Air.Inst.Ref { |
| 13045 | if ((try sema.typeHasOnePossibleValue(block, un_src, enum_ty))) |opv| { | ||
| 13046 | return sema.addConstant(enum_ty, opv); | ||
| 13047 | } | ||
| 12967 | if (try sema.resolveMaybeUndefVal(block, un_src, un)) |un_val| { | 13048 | if (try sema.resolveMaybeUndefVal(block, un_src, un)) |un_val| { |
| 12968 | return sema.addConstant(dest_ty, un_val.unionTag()); | 13049 | return sema.addConstant(enum_ty, un_val.unionTag()); |
| 12969 | } | 13050 | } |
| 12970 | try sema.requireRuntimeBlock(block, un_src); | 13051 | try sema.requireRuntimeBlock(block, un_src); |
| 12971 | return block.addTyOp(.get_union_tag, dest_ty, un); | 13052 | return block.addTyOp(.get_union_tag, enum_ty, un); |
| 12972 | } | 13053 | } |
| 12973 | 13054 | ||
| 12974 | fn resolvePeerTypes( | 13055 | fn resolvePeerTypes( |
src/Zir.zig+123-149| ... | @@ -72,6 +72,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, en | ... | @@ -72,6 +72,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, en |
| 72 | Inst.Ref => @intToEnum(Inst.Ref, code.extra[i]), | 72 | Inst.Ref => @intToEnum(Inst.Ref, code.extra[i]), |
| 73 | i32 => @bitCast(i32, code.extra[i]), | 73 | i32 => @bitCast(i32, code.extra[i]), |
| 74 | Inst.Call.Flags => @bitCast(Inst.Call.Flags, code.extra[i]), | 74 | Inst.Call.Flags => @bitCast(Inst.Call.Flags, code.extra[i]), |
| 75 | Inst.SwitchBlock.Bits => @bitCast(Inst.SwitchBlock.Bits, code.extra[i]), | ||
| 75 | else => @compileError("bad field type"), | 76 | else => @compileError("bad field type"), |
| 76 | }; | 77 | }; |
| 77 | i += 1; | 78 | i += 1; |
| ... | @@ -618,39 +619,16 @@ pub const Inst = struct { | ... | @@ -618,39 +619,16 @@ pub const Inst = struct { |
| 618 | enum_literal, | 619 | enum_literal, |
| 619 | /// A switch expression. Uses the `pl_node` union field. | 620 | /// A switch expression. Uses the `pl_node` union field. |
| 620 | /// AST node is the switch, payload is `SwitchBlock`. | 621 | /// AST node is the switch, payload is `SwitchBlock`. |
| 621 | /// All prongs of target handled. | ||
| 622 | switch_block, | 622 | switch_block, |
| 623 | /// Same as switch_block, except one or more prongs have multiple items. | 623 | /// Produces the value that will be switched on. For example, for |
| 624 | /// Payload is `SwitchBlockMulti` | 624 | /// integers, it returns the integer with no modifications. For tagged unions, it |
| 625 | switch_block_multi, | 625 | /// returns the active enum tag. |
| 626 | /// Same as switch_block, except has an else prong. | 626 | /// Uses the `un_node` union field. |
| 627 | switch_block_else, | 627 | switch_cond, |
| 628 | /// Same as switch_block_else, except one or more prongs have multiple items. | 628 | /// Same as `switch_cond`, except the input operand is a pointer to |
| 629 | /// Payload is `SwitchBlockMulti` | 629 | /// what will be switched on. |
| 630 | switch_block_else_multi, | 630 | /// Uses the `un_node` union field. |
| 631 | /// Same as switch_block, except has an underscore prong. | 631 | switch_cond_ref, |
| 632 | switch_block_under, | ||
| 633 | /// Same as switch_block, except one or more prongs have multiple items. | ||
| 634 | /// Payload is `SwitchBlockMulti` | ||
| 635 | switch_block_under_multi, | ||
| 636 | /// Same as `switch_block` but the target is a pointer to the value being switched on. | ||
| 637 | switch_block_ref, | ||
| 638 | /// Same as `switch_block_multi` but the target is a pointer to the value being switched on. | ||
| 639 | /// Payload is `SwitchBlockMulti` | ||
| 640 | switch_block_ref_multi, | ||
| 641 | /// Same as `switch_block_else` but the target is a pointer to the value being switched on. | ||
| 642 | switch_block_ref_else, | ||
| 643 | /// Same as `switch_block_else_multi` but the target is a pointer to the | ||
| 644 | /// value being switched on. | ||
| 645 | /// Payload is `SwitchBlockMulti` | ||
| 646 | switch_block_ref_else_multi, | ||
| 647 | /// Same as `switch_block_under` but the target is a pointer to the value | ||
| 648 | /// being switched on. | ||
| 649 | switch_block_ref_under, | ||
| 650 | /// Same as `switch_block_under_multi` but the target is a pointer to | ||
| 651 | /// the value being switched on. | ||
| 652 | /// Payload is `SwitchBlockMulti` | ||
| 653 | switch_block_ref_under_multi, | ||
| 654 | /// Produces the capture value for a switch prong. | 632 | /// Produces the capture value for a switch prong. |
| 655 | /// Uses the `switch_capture` field. | 633 | /// Uses the `switch_capture` field. |
| 656 | switch_capture, | 634 | switch_capture, |
| ... | @@ -1109,17 +1087,8 @@ pub const Inst = struct { | ... | @@ -1109,17 +1087,8 @@ pub const Inst = struct { |
| 1109 | .switch_capture_else, | 1087 | .switch_capture_else, |
| 1110 | .switch_capture_else_ref, | 1088 | .switch_capture_else_ref, |
| 1111 | .switch_block, | 1089 | .switch_block, |
| 1112 | .switch_block_multi, | 1090 | .switch_cond, |
| 1113 | .switch_block_else, | 1091 | .switch_cond_ref, |
| 1114 | .switch_block_else_multi, | ||
| 1115 | .switch_block_under, | ||
| 1116 | .switch_block_under_multi, | ||
| 1117 | .switch_block_ref, | ||
| 1118 | .switch_block_ref_multi, | ||
| 1119 | .switch_block_ref_else, | ||
| 1120 | .switch_block_ref_else_multi, | ||
| 1121 | .switch_block_ref_under, | ||
| 1122 | .switch_block_ref_under_multi, | ||
| 1123 | .validate_struct_init, | 1092 | .validate_struct_init, |
| 1124 | .validate_array_init, | 1093 | .validate_array_init, |
| 1125 | .struct_init_empty, | 1094 | .struct_init_empty, |
| ... | @@ -1367,17 +1336,8 @@ pub const Inst = struct { | ... | @@ -1367,17 +1336,8 @@ pub const Inst = struct { |
| 1367 | .ensure_err_payload_void = .un_tok, | 1336 | .ensure_err_payload_void = .un_tok, |
| 1368 | .enum_literal = .str_tok, | 1337 | .enum_literal = .str_tok, |
| 1369 | .switch_block = .pl_node, | 1338 | .switch_block = .pl_node, |
| 1370 | .switch_block_multi = .pl_node, | 1339 | .switch_cond = .un_node, |
| 1371 | .switch_block_else = .pl_node, | 1340 | .switch_cond_ref = .un_node, |
| 1372 | .switch_block_else_multi = .pl_node, | ||
| 1373 | .switch_block_under = .pl_node, | ||
| 1374 | .switch_block_under_multi = .pl_node, | ||
| 1375 | .switch_block_ref = .pl_node, | ||
| 1376 | .switch_block_ref_multi = .pl_node, | ||
| 1377 | .switch_block_ref_else = .pl_node, | ||
| 1378 | .switch_block_ref_else_multi = .pl_node, | ||
| 1379 | .switch_block_ref_under = .pl_node, | ||
| 1380 | .switch_block_ref_under_multi = .pl_node, | ||
| 1381 | .switch_capture = .switch_capture, | 1341 | .switch_capture = .switch_capture, |
| 1382 | .switch_capture_ref = .switch_capture, | 1342 | .switch_capture_ref = .switch_capture, |
| 1383 | .switch_capture_multi = .switch_capture, | 1343 | .switch_capture_multi = .switch_capture, |
| ... | @@ -2466,37 +2426,17 @@ pub const Inst = struct { | ... | @@ -2466,37 +2426,17 @@ pub const Inst = struct { |
| 2466 | index: u32, | 2426 | index: u32, |
| 2467 | }; | 2427 | }; |
| 2468 | 2428 | ||
| 2469 | /// This form is supported when there are no ranges, and exactly 1 item per block. | 2429 | /// 0. multi_cases_len: u32 // If has_multi_cases is set. |
| 2470 | /// Depending on zir tag and len fields, extra fields trail | 2430 | /// 1. else_body { // If has_else or has_under is set. |
| 2471 | /// this one in the extra array. | ||
| 2472 | /// 0. else_body { // If the tag has "_else" or "_under" in it. | ||
| 2473 | /// body_len: u32, | ||
| 2474 | /// body member Index for every body_len | ||
| 2475 | /// } | ||
| 2476 | /// 1. cases: { | ||
| 2477 | /// item: Ref, | ||
| 2478 | /// body_len: u32, | ||
| 2479 | /// body member Index for every body_len | ||
| 2480 | /// } for every cases_len | ||
| 2481 | pub const SwitchBlock = struct { | ||
| 2482 | operand: Ref, | ||
| 2483 | cases_len: u32, | ||
| 2484 | }; | ||
| 2485 | |||
| 2486 | /// This form is required when there exists a block which has more than one item, | ||
| 2487 | /// or a range. | ||
| 2488 | /// Depending on zir tag and len fields, extra fields trail | ||
| 2489 | /// this one in the extra array. | ||
| 2490 | /// 0. else_body { // If the tag has "_else" or "_under" in it. | ||
| 2491 | /// body_len: u32, | 2431 | /// body_len: u32, |
| 2492 | /// body member Index for every body_len | 2432 | /// body member Index for every body_len |
| 2493 | /// } | 2433 | /// } |
| 2494 | /// 1. scalar_cases: { // for every scalar_cases_len | 2434 | /// 2. scalar_cases: { // for every scalar_cases_len |
| 2495 | /// item: Ref, | 2435 | /// item: Ref, |
| 2496 | /// body_len: u32, | 2436 | /// body_len: u32, |
| 2497 | /// body member Index for every body_len | 2437 | /// body member Index for every body_len |
| 2498 | /// } | 2438 | /// } |
| 2499 | /// 2. multi_cases: { // for every multi_cases_len | 2439 | /// 3. multi_cases: { // for every multi_cases_len |
| 2500 | /// items_len: u32, | 2440 | /// items_len: u32, |
| 2501 | /// ranges_len: u32, | 2441 | /// ranges_len: u32, |
| 2502 | /// body_len: u32, | 2442 | /// body_len: u32, |
| ... | @@ -2507,10 +2447,78 @@ pub const Inst = struct { | ... | @@ -2507,10 +2447,78 @@ pub const Inst = struct { |
| 2507 | /// } | 2447 | /// } |
| 2508 | /// body member Index for every body_len | 2448 | /// body member Index for every body_len |
| 2509 | /// } | 2449 | /// } |
| 2510 | pub const SwitchBlockMulti = struct { | 2450 | pub const SwitchBlock = struct { |
| 2511 | operand: Ref, | 2451 | operand: Ref, |
| 2512 | scalar_cases_len: u32, | 2452 | bits: Bits, |
| 2513 | multi_cases_len: u32, | 2453 | |
| 2454 | pub const Bits = packed struct { | ||
| 2455 | /// If true, one or more prongs have multiple items. | ||
| 2456 | has_multi_cases: bool, | ||
| 2457 | /// If true, there is an else prong. This is mutually exclusive with `has_under`. | ||
| 2458 | has_else: bool, | ||
| 2459 | /// If true, there is an underscore prong. This is mutually exclusive with `has_else`. | ||
| 2460 | has_under: bool, | ||
| 2461 | /// If true, the `operand` is a pointer to the value being switched on. | ||
| 2462 | is_ref: bool, | ||
| 2463 | scalar_cases_len: u28, | ||
| 2464 | |||
| 2465 | pub fn specialProng(bits: Bits) SpecialProng { | ||
| 2466 | const has_else: u2 = @boolToInt(bits.has_else); | ||
| 2467 | const has_under: u2 = @boolToInt(bits.has_under); | ||
| 2468 | return switch ((has_else << 1) | has_under) { | ||
| 2469 | 0b00 => .none, | ||
| 2470 | 0b01 => .under, | ||
| 2471 | 0b10 => .@"else", | ||
| 2472 | 0b11 => unreachable, | ||
| 2473 | }; | ||
| 2474 | } | ||
| 2475 | }; | ||
| 2476 | |||
| 2477 | pub const ScalarProng = struct { | ||
| 2478 | item: Ref, | ||
| 2479 | body: []const Index, | ||
| 2480 | }; | ||
| 2481 | |||
| 2482 | /// TODO performance optimization: instead of having this helper method | ||
| 2483 | /// change the definition of switch_capture instruction to store extra_index | ||
| 2484 | /// instead of prong_index. This way, Sema won't be doing O(N^2) iterations | ||
| 2485 | /// over the switch prongs. | ||
| 2486 | pub fn getScalarProng( | ||
| 2487 | self: SwitchBlock, | ||
| 2488 | zir: Zir, | ||
| 2489 | extra_end: usize, | ||
| 2490 | prong_index: usize, | ||
| 2491 | ) ScalarProng { | ||
| 2492 | var extra_index: usize = extra_end; | ||
| 2493 | |||
| 2494 | if (self.bits.has_multi_cases) { | ||
| 2495 | extra_index += 1; | ||
| 2496 | } | ||
| 2497 | |||
| 2498 | if (self.bits.specialProng() != .none) { | ||
| 2499 | const body_len = zir.extra[extra_index]; | ||
| 2500 | extra_index += 1; | ||
| 2501 | const body = zir.extra[extra_index..][0..body_len]; | ||
| 2502 | extra_index += body.len; | ||
| 2503 | } | ||
| 2504 | |||
| 2505 | var scalar_i: usize = 0; | ||
| 2506 | while (true) : (scalar_i += 1) { | ||
| 2507 | const item = @intToEnum(Ref, zir.extra[extra_index]); | ||
| 2508 | extra_index += 1; | ||
| 2509 | const body_len = zir.extra[extra_index]; | ||
| 2510 | extra_index += 1; | ||
| 2511 | const body = zir.extra[extra_index..][0..body_len]; | ||
| 2512 | extra_index += body.len; | ||
| 2513 | |||
| 2514 | if (scalar_i < prong_index) continue; | ||
| 2515 | |||
| 2516 | return .{ | ||
| 2517 | .item = item, | ||
| 2518 | .body = body, | ||
| 2519 | }; | ||
| 2520 | } | ||
| 2521 | } | ||
| 2514 | }; | 2522 | }; |
| 2515 | 2523 | ||
| 2516 | pub const Field = struct { | 2524 | pub const Field = struct { |
| ... | @@ -2934,7 +2942,7 @@ pub const Inst = struct { | ... | @@ -2934,7 +2942,7 @@ pub const Inst = struct { |
| 2934 | 2942 | ||
| 2935 | /// Trailing: for each `imports_len` there is an Item | 2943 | /// Trailing: for each `imports_len` there is an Item |
| 2936 | pub const Imports = struct { | 2944 | pub const Imports = struct { |
| 2937 | imports_len: Zir.Inst.Index, | 2945 | imports_len: Inst.Index, |
| 2938 | 2946 | ||
| 2939 | pub const Item = struct { | 2947 | pub const Item = struct { |
| 2940 | /// null terminated string index | 2948 | /// null terminated string index |
| ... | @@ -3077,7 +3085,7 @@ pub fn declIteratorInner(zir: Zir, extra_index: usize, decls_len: u32) DeclItera | ... | @@ -3077,7 +3085,7 @@ pub fn declIteratorInner(zir: Zir, extra_index: usize, decls_len: u32) DeclItera |
| 3077 | 3085 | ||
| 3078 | /// The iterator would have to allocate memory anyway to iterate. So here we populate | 3086 | /// The iterator would have to allocate memory anyway to iterate. So here we populate |
| 3079 | /// an ArrayList as the result. | 3087 | /// an ArrayList as the result. |
| 3080 | pub fn findDecls(zir: Zir, list: *std.ArrayList(Zir.Inst.Index), decl_sub_index: u32) !void { | 3088 | pub fn findDecls(zir: Zir, list: *std.ArrayList(Inst.Index), decl_sub_index: u32) !void { |
| 3081 | const block_inst = zir.extra[decl_sub_index + 6]; | 3089 | const block_inst = zir.extra[decl_sub_index + 6]; |
| 3082 | list.clearRetainingCapacity(); | 3090 | list.clearRetainingCapacity(); |
| 3083 | 3091 | ||
| ... | @@ -3086,8 +3094,8 @@ pub fn findDecls(zir: Zir, list: *std.ArrayList(Zir.Inst.Index), decl_sub_index: | ... | @@ -3086,8 +3094,8 @@ pub fn findDecls(zir: Zir, list: *std.ArrayList(Zir.Inst.Index), decl_sub_index: |
| 3086 | 3094 | ||
| 3087 | fn findDeclsInner( | 3095 | fn findDeclsInner( |
| 3088 | zir: Zir, | 3096 | zir: Zir, |
| 3089 | list: *std.ArrayList(Zir.Inst.Index), | 3097 | list: *std.ArrayList(Inst.Index), |
| 3090 | inst: Zir.Inst.Index, | 3098 | inst: Inst.Index, |
| 3091 | ) Allocator.Error!void { | 3099 | ) Allocator.Error!void { |
| 3092 | const tags = zir.instructions.items(.tag); | 3100 | const tags = zir.instructions.items(.tag); |
| 3093 | const datas = zir.instructions.items(.data); | 3101 | const datas = zir.instructions.items(.data); |
| ... | @@ -3148,19 +3156,7 @@ fn findDeclsInner( | ... | @@ -3148,19 +3156,7 @@ fn findDeclsInner( |
| 3148 | try zir.findDeclsBody(list, then_body); | 3156 | try zir.findDeclsBody(list, then_body); |
| 3149 | try zir.findDeclsBody(list, else_body); | 3157 | try zir.findDeclsBody(list, else_body); |
| 3150 | }, | 3158 | }, |
| 3151 | .switch_block => return findDeclsSwitch(zir, list, inst, .none), | 3159 | .switch_block => return findDeclsSwitch(zir, list, inst), |
| 3152 | .switch_block_else => return findDeclsSwitch(zir, list, inst, .@"else"), | ||
| 3153 | .switch_block_under => return findDeclsSwitch(zir, list, inst, .under), | ||
| 3154 | .switch_block_ref => return findDeclsSwitch(zir, list, inst, .none), | ||
| 3155 | .switch_block_ref_else => return findDeclsSwitch(zir, list, inst, .@"else"), | ||
| 3156 | .switch_block_ref_under => return findDeclsSwitch(zir, list, inst, .under), | ||
| 3157 | |||
| 3158 | .switch_block_multi => return findDeclsSwitchMulti(zir, list, inst, .none), | ||
| 3159 | .switch_block_else_multi => return findDeclsSwitchMulti(zir, list, inst, .@"else"), | ||
| 3160 | .switch_block_under_multi => return findDeclsSwitchMulti(zir, list, inst, .under), | ||
| 3161 | .switch_block_ref_multi => return findDeclsSwitchMulti(zir, list, inst, .none), | ||
| 3162 | .switch_block_ref_else_multi => return findDeclsSwitchMulti(zir, list, inst, .@"else"), | ||
| 3163 | .switch_block_ref_under_multi => return findDeclsSwitchMulti(zir, list, inst, .under), | ||
| 3164 | 3160 | ||
| 3165 | .suspend_block => @panic("TODO iterate suspend block"), | 3161 | .suspend_block => @panic("TODO iterate suspend block"), |
| 3166 | 3162 | ||
| ... | @@ -3170,71 +3166,34 @@ fn findDeclsInner( | ... | @@ -3170,71 +3166,34 @@ fn findDeclsInner( |
| 3170 | 3166 | ||
| 3171 | fn findDeclsSwitch( | 3167 | fn findDeclsSwitch( |
| 3172 | zir: Zir, | 3168 | zir: Zir, |
| 3173 | list: *std.ArrayList(Zir.Inst.Index), | 3169 | list: *std.ArrayList(Inst.Index), |
| 3174 | inst: Zir.Inst.Index, | 3170 | inst: Inst.Index, |
| 3175 | special_prong: SpecialProng, | ||
| 3176 | ) Allocator.Error!void { | 3171 | ) Allocator.Error!void { |
| 3177 | const inst_data = zir.instructions.items(.data)[inst].pl_node; | 3172 | const inst_data = zir.instructions.items(.data)[inst].pl_node; |
| 3178 | const extra = zir.extraData(Inst.SwitchBlock, inst_data.payload_index); | 3173 | const extra = zir.extraData(Inst.SwitchBlock, inst_data.payload_index); |
| 3179 | const special: struct { | ||
| 3180 | body: []const Inst.Index, | ||
| 3181 | end: usize, | ||
| 3182 | } = switch (special_prong) { | ||
| 3183 | .none => .{ .body = &.{}, .end = extra.end }, | ||
| 3184 | .under, .@"else" => blk: { | ||
| 3185 | const body_len = zir.extra[extra.end]; | ||
| 3186 | const extra_body_start = extra.end + 1; | ||
| 3187 | break :blk .{ | ||
| 3188 | .body = zir.extra[extra_body_start..][0..body_len], | ||
| 3189 | .end = extra_body_start + body_len, | ||
| 3190 | }; | ||
| 3191 | }, | ||
| 3192 | }; | ||
| 3193 | 3174 | ||
| 3194 | try zir.findDeclsBody(list, special.body); | 3175 | var extra_index: usize = extra.end; |
| 3195 | 3176 | ||
| 3196 | var extra_index: usize = special.end; | 3177 | const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: { |
| 3197 | var scalar_i: usize = 0; | 3178 | const multi_cases_len = zir.extra[extra_index]; |
| 3198 | while (scalar_i < extra.data.cases_len) : (scalar_i += 1) { | ||
| 3199 | extra_index += 1; | 3179 | extra_index += 1; |
| 3180 | break :blk multi_cases_len; | ||
| 3181 | } else 0; | ||
| 3182 | |||
| 3183 | const special_prong = extra.data.bits.specialProng(); | ||
| 3184 | if (special_prong != .none) { | ||
| 3200 | const body_len = zir.extra[extra_index]; | 3185 | const body_len = zir.extra[extra_index]; |
| 3201 | extra_index += 1; | 3186 | extra_index += 1; |
| 3202 | const body = zir.extra[extra_index..][0..body_len]; | 3187 | const body = zir.extra[extra_index..][0..body_len]; |
| 3203 | extra_index += body_len; | 3188 | extra_index += body.len; |
| 3204 | 3189 | ||
| 3205 | try zir.findDeclsBody(list, body); | 3190 | try zir.findDeclsBody(list, body); |
| 3206 | } | 3191 | } |
| 3207 | } | ||
| 3208 | 3192 | ||
| 3209 | fn findDeclsSwitchMulti( | ||
| 3210 | zir: Zir, | ||
| 3211 | list: *std.ArrayList(Zir.Inst.Index), | ||
| 3212 | inst: Zir.Inst.Index, | ||
| 3213 | special_prong: SpecialProng, | ||
| 3214 | ) Allocator.Error!void { | ||
| 3215 | const inst_data = zir.instructions.items(.data)[inst].pl_node; | ||
| 3216 | const extra = zir.extraData(Inst.SwitchBlockMulti, inst_data.payload_index); | ||
| 3217 | const special: struct { | ||
| 3218 | body: []const Inst.Index, | ||
| 3219 | end: usize, | ||
| 3220 | } = switch (special_prong) { | ||
| 3221 | .none => .{ .body = &.{}, .end = extra.end }, | ||
| 3222 | .under, .@"else" => blk: { | ||
| 3223 | const body_len = zir.extra[extra.end]; | ||
| 3224 | const extra_body_start = extra.end + 1; | ||
| 3225 | break :blk .{ | ||
| 3226 | .body = zir.extra[extra_body_start..][0..body_len], | ||
| 3227 | .end = extra_body_start + body_len, | ||
| 3228 | }; | ||
| 3229 | }, | ||
| 3230 | }; | ||
| 3231 | |||
| 3232 | try zir.findDeclsBody(list, special.body); | ||
| 3233 | |||
| 3234 | var extra_index: usize = special.end; | ||
| 3235 | { | 3193 | { |
| 3194 | const scalar_cases_len = extra.data.bits.scalar_cases_len; | ||
| 3236 | var scalar_i: usize = 0; | 3195 | var scalar_i: usize = 0; |
| 3237 | while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) { | 3196 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 3238 | extra_index += 1; | 3197 | extra_index += 1; |
| 3239 | const body_len = zir.extra[extra_index]; | 3198 | const body_len = zir.extra[extra_index]; |
| 3240 | extra_index += 1; | 3199 | extra_index += 1; |
| ... | @@ -3246,7 +3205,7 @@ fn findDeclsSwitchMulti( | ... | @@ -3246,7 +3205,7 @@ fn findDeclsSwitchMulti( |
| 3246 | } | 3205 | } |
| 3247 | { | 3206 | { |
| 3248 | var multi_i: usize = 0; | 3207 | var multi_i: usize = 0; |
| 3249 | while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) { | 3208 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 3250 | const items_len = zir.extra[extra_index]; | 3209 | const items_len = zir.extra[extra_index]; |
| 3251 | extra_index += 1; | 3210 | extra_index += 1; |
| 3252 | const ranges_len = zir.extra[extra_index]; | 3211 | const ranges_len = zir.extra[extra_index]; |
| ... | @@ -3353,3 +3312,18 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { | ... | @@ -3353,3 +3312,18 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { |
| 3353 | .total_params_len = total_params_len, | 3312 | .total_params_len = total_params_len, |
| 3354 | }; | 3313 | }; |
| 3355 | } | 3314 | } |
| 3315 | |||
| 3316 | const ref_start_index: u32 = Inst.Ref.typed_value_map.len; | ||
| 3317 | |||
| 3318 | pub fn indexToRef(inst: Inst.Index) Inst.Ref { | ||
| 3319 | return @intToEnum(Inst.Ref, ref_start_index + inst); | ||
| 3320 | } | ||
| 3321 | |||
| 3322 | pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { | ||
| 3323 | const ref_int = @enumToInt(inst); | ||
| 3324 | if (ref_int >= ref_start_index) { | ||
| 3325 | return ref_int - ref_start_index; | ||
| 3326 | } else { | ||
| 3327 | return null; | ||
| 3328 | } | ||
| 3329 | } |
src/print_zir.zig+24-101| ... | @@ -234,6 +234,8 @@ const Writer = struct { | ... | @@ -234,6 +234,8 @@ const Writer = struct { |
| 234 | .@"await", | 234 | .@"await", |
| 235 | .await_nosuspend, | 235 | .await_nosuspend, |
| 236 | .fence, | 236 | .fence, |
| 237 | .switch_cond, | ||
| 238 | .switch_cond_ref, | ||
| 237 | => try self.writeUnNode(stream, inst), | 239 | => try self.writeUnNode(stream, inst), |
| 238 | 240 | ||
| 239 | .ref, | 241 | .ref, |
| ... | @@ -379,19 +381,7 @@ const Writer = struct { | ... | @@ -379,19 +381,7 @@ const Writer = struct { |
| 379 | .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon), | 381 | .error_set_decl_anon => try self.writeErrorSetDecl(stream, inst, .anon), |
| 380 | .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func), | 382 | .error_set_decl_func => try self.writeErrorSetDecl(stream, inst, .func), |
| 381 | 383 | ||
| 382 | .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none), | 384 | .switch_block => try self.writePlNodeSwitchBlock(stream, inst), |
| 383 | .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), | ||
| 384 | .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under), | ||
| 385 | .switch_block_ref => try self.writePlNodeSwitchBr(stream, inst, .none), | ||
| 386 | .switch_block_ref_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), | ||
| 387 | .switch_block_ref_under => try self.writePlNodeSwitchBr(stream, inst, .under), | ||
| 388 | |||
| 389 | .switch_block_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none), | ||
| 390 | .switch_block_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"), | ||
| 391 | .switch_block_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under), | ||
| 392 | .switch_block_ref_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none), | ||
| 393 | .switch_block_ref_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"), | ||
| 394 | .switch_block_ref_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under), | ||
| 395 | 385 | ||
| 396 | .field_ptr, | 386 | .field_ptr, |
| 397 | .field_val, | 387 | .field_val, |
| ... | @@ -1649,113 +1639,46 @@ const Writer = struct { | ... | @@ -1649,113 +1639,46 @@ const Writer = struct { |
| 1649 | try self.writeSrc(stream, inst_data.src()); | 1639 | try self.writeSrc(stream, inst_data.src()); |
| 1650 | } | 1640 | } |
| 1651 | 1641 | ||
| 1652 | fn writePlNodeSwitchBr( | 1642 | fn writePlNodeSwitchBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { |
| 1653 | self: *Writer, | ||
| 1654 | stream: anytype, | ||
| 1655 | inst: Zir.Inst.Index, | ||
| 1656 | special_prong: Zir.SpecialProng, | ||
| 1657 | ) !void { | ||
| 1658 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | 1643 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 1659 | const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); | 1644 | const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); |
| 1660 | const special: struct { | ||
| 1661 | body: []const Zir.Inst.Index, | ||
| 1662 | end: usize, | ||
| 1663 | } = switch (special_prong) { | ||
| 1664 | .none => .{ .body = &.{}, .end = extra.end }, | ||
| 1665 | .under, .@"else" => blk: { | ||
| 1666 | const body_len = self.code.extra[extra.end]; | ||
| 1667 | const extra_body_start = extra.end + 1; | ||
| 1668 | break :blk .{ | ||
| 1669 | .body = self.code.extra[extra_body_start..][0..body_len], | ||
| 1670 | .end = extra_body_start + body_len, | ||
| 1671 | }; | ||
| 1672 | }, | ||
| 1673 | }; | ||
| 1674 | |||
| 1675 | try self.writeInstRef(stream, extra.data.operand); | ||
| 1676 | |||
| 1677 | self.indent += 2; | ||
| 1678 | |||
| 1679 | if (special.body.len != 0) { | ||
| 1680 | const prong_name = switch (special_prong) { | ||
| 1681 | .@"else" => "else", | ||
| 1682 | .under => "_", | ||
| 1683 | else => unreachable, | ||
| 1684 | }; | ||
| 1685 | try stream.writeAll(",\n"); | ||
| 1686 | try stream.writeByteNTimes(' ', self.indent); | ||
| 1687 | try stream.print("{s} => ", .{prong_name}); | ||
| 1688 | try self.writeBracedBody(stream, special.body); | ||
| 1689 | } | ||
| 1690 | |||
| 1691 | var extra_index: usize = special.end; | ||
| 1692 | { | ||
| 1693 | var scalar_i: usize = 0; | ||
| 1694 | while (scalar_i < extra.data.cases_len) : (scalar_i += 1) { | ||
| 1695 | const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); | ||
| 1696 | extra_index += 1; | ||
| 1697 | const body_len = self.code.extra[extra_index]; | ||
| 1698 | extra_index += 1; | ||
| 1699 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 1700 | extra_index += body_len; | ||
| 1701 | |||
| 1702 | try stream.writeAll(",\n"); | ||
| 1703 | try stream.writeByteNTimes(' ', self.indent); | ||
| 1704 | try self.writeInstRef(stream, item_ref); | ||
| 1705 | try stream.writeAll(" => "); | ||
| 1706 | try self.writeBracedBody(stream, body); | ||
| 1707 | } | ||
| 1708 | } | ||
| 1709 | |||
| 1710 | self.indent -= 2; | ||
| 1711 | 1645 | ||
| 1712 | try stream.writeAll(") "); | 1646 | var extra_index: usize = extra.end; |
| 1713 | try self.writeSrc(stream, inst_data.src()); | ||
| 1714 | } | ||
| 1715 | 1647 | ||
| 1716 | fn writePlNodeSwitchBlockMulti( | 1648 | const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: { |
| 1717 | self: *Writer, | 1649 | const multi_cases_len = self.code.extra[extra_index]; |
| 1718 | stream: anytype, | 1650 | extra_index += 1; |
| 1719 | inst: Zir.Inst.Index, | 1651 | break :blk multi_cases_len; |
| 1720 | special_prong: Zir.SpecialProng, | 1652 | } else 0; |
| 1721 | ) !void { | ||
| 1722 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 1723 | const extra = self.code.extraData(Zir.Inst.SwitchBlockMulti, inst_data.payload_index); | ||
| 1724 | const special: struct { | ||
| 1725 | body: []const Zir.Inst.Index, | ||
| 1726 | end: usize, | ||
| 1727 | } = switch (special_prong) { | ||
| 1728 | .none => .{ .body = &.{}, .end = extra.end }, | ||
| 1729 | .under, .@"else" => blk: { | ||
| 1730 | const body_len = self.code.extra[extra.end]; | ||
| 1731 | const extra_body_start = extra.end + 1; | ||
| 1732 | break :blk .{ | ||
| 1733 | .body = self.code.extra[extra_body_start..][0..body_len], | ||
| 1734 | .end = extra_body_start + body_len, | ||
| 1735 | }; | ||
| 1736 | }, | ||
| 1737 | }; | ||
| 1738 | 1653 | ||
| 1739 | try self.writeInstRef(stream, extra.data.operand); | 1654 | try self.writeInstRef(stream, extra.data.operand); |
| 1655 | try self.writeFlag(stream, ", ref", extra.data.bits.is_ref); | ||
| 1740 | 1656 | ||
| 1741 | self.indent += 2; | 1657 | self.indent += 2; |
| 1742 | 1658 | ||
| 1743 | if (special.body.len != 0) { | 1659 | else_prong: { |
| 1660 | const special_prong = extra.data.bits.specialProng(); | ||
| 1744 | const prong_name = switch (special_prong) { | 1661 | const prong_name = switch (special_prong) { |
| 1745 | .@"else" => "else", | 1662 | .@"else" => "else", |
| 1746 | .under => "_", | 1663 | .under => "_", |
| 1747 | else => unreachable, | 1664 | else => break :else_prong, |
| 1748 | }; | 1665 | }; |
| 1666 | |||
| 1667 | const body_len = self.code.extra[extra_index]; | ||
| 1668 | extra_index += 1; | ||
| 1669 | const body = self.code.extra[extra_index..][0..body_len]; | ||
| 1670 | extra_index += body.len; | ||
| 1671 | |||
| 1749 | try stream.writeAll(",\n"); | 1672 | try stream.writeAll(",\n"); |
| 1750 | try stream.writeByteNTimes(' ', self.indent); | 1673 | try stream.writeByteNTimes(' ', self.indent); |
| 1751 | try stream.print("{s} => ", .{prong_name}); | 1674 | try stream.print("{s} => ", .{prong_name}); |
| 1752 | try self.writeBracedBody(stream, special.body); | 1675 | try self.writeBracedBody(stream, body); |
| 1753 | } | 1676 | } |
| 1754 | 1677 | ||
| 1755 | var extra_index: usize = special.end; | ||
| 1756 | { | 1678 | { |
| 1679 | const scalar_cases_len = extra.data.bits.scalar_cases_len; | ||
| 1757 | var scalar_i: usize = 0; | 1680 | var scalar_i: usize = 0; |
| 1758 | while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) { | 1681 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 1759 | const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); | 1682 | const item_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); |
| 1760 | extra_index += 1; | 1683 | extra_index += 1; |
| 1761 | const body_len = self.code.extra[extra_index]; | 1684 | const body_len = self.code.extra[extra_index]; |
| ... | @@ -1772,7 +1695,7 @@ const Writer = struct { | ... | @@ -1772,7 +1695,7 @@ const Writer = struct { |
| 1772 | } | 1695 | } |
| 1773 | { | 1696 | { |
| 1774 | var multi_i: usize = 0; | 1697 | var multi_i: usize = 0; |
| 1775 | while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) { | 1698 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 1776 | const items_len = self.code.extra[extra_index]; | 1699 | const items_len = self.code.extra[extra_index]; |
| 1777 | extra_index += 1; | 1700 | extra_index += 1; |
| 1778 | const ranges_len = self.code.extra[extra_index]; | 1701 | const ranges_len = self.code.extra[extra_index]; |
src/value.zig+1-1| ... | @@ -116,7 +116,7 @@ pub const Value = extern union { | ... | @@ -116,7 +116,7 @@ pub const Value = extern union { |
| 116 | decl_ref_mut, | 116 | decl_ref_mut, |
| 117 | /// Pointer to a specific element of an array. | 117 | /// Pointer to a specific element of an array. |
| 118 | elem_ptr, | 118 | elem_ptr, |
| 119 | /// Pointer to a specific field of a struct. | 119 | /// Pointer to a specific field of a struct or union. |
| 120 | field_ptr, | 120 | field_ptr, |
| 121 | /// A slice of u8 whose memory is managed externally. | 121 | /// A slice of u8 whose memory is managed externally. |
| 122 | bytes, | 122 | bytes, |
test/behavior/union.zig+31| ... | @@ -71,3 +71,34 @@ test "0-sized extern union definition" { | ... | @@ -71,3 +71,34 @@ test "0-sized extern union definition" { |
| 71 | 71 | ||
| 72 | try expect(U.f == 1); | 72 | try expect(U.f == 1); |
| 73 | } | 73 | } |
| 74 | |||
| 75 | const Value = union(enum) { | ||
| 76 | Int: u64, | ||
| 77 | Array: [9]u8, | ||
| 78 | }; | ||
| 79 | |||
| 80 | const Agg = struct { | ||
| 81 | val1: Value, | ||
| 82 | val2: Value, | ||
| 83 | }; | ||
| 84 | |||
| 85 | const v1 = Value{ .Int = 1234 }; | ||
| 86 | const v2 = Value{ .Array = [_]u8{3} ** 9 }; | ||
| 87 | |||
| 88 | const err = @as(anyerror!Agg, Agg{ | ||
| 89 | .val1 = v1, | ||
| 90 | .val2 = v2, | ||
| 91 | }); | ||
| 92 | |||
| 93 | const array = [_]Value{ v1, v2, v1, v2 }; | ||
| 94 | |||
| 95 | test "unions embedded in aggregate types" { | ||
| 96 | switch (array[1]) { | ||
| 97 | Value.Array => |arr| try expect(arr[4] == 3), | ||
| 98 | else => unreachable, | ||
| 99 | } | ||
| 100 | switch ((err catch unreachable).val1) { | ||
| 101 | Value.Int => |x| try expect(x == 1234), | ||
| 102 | else => unreachable, | ||
| 103 | } | ||
| 104 | } |
test/behavior/union_stage1.zig-31| ... | @@ -3,37 +3,6 @@ const expect = std.testing.expect; | ... | @@ -3,37 +3,6 @@ const expect = std.testing.expect; |
| 3 | const expectEqual = std.testing.expectEqual; | 3 | const expectEqual = std.testing.expectEqual; |
| 4 | const Tag = std.meta.Tag; | 4 | const Tag = std.meta.Tag; |
| 5 | 5 | ||
| 6 | const Value = union(enum) { | ||
| 7 | Int: u64, | ||
| 8 | Array: [9]u8, | ||
| 9 | }; | ||
| 10 | |||
| 11 | const Agg = struct { | ||
| 12 | val1: Value, | ||
| 13 | val2: Value, | ||
| 14 | }; | ||
| 15 | |||
| 16 | const v1 = Value{ .Int = 1234 }; | ||
| 17 | const v2 = Value{ .Array = [_]u8{3} ** 9 }; | ||
| 18 | |||
| 19 | const err = @as(anyerror!Agg, Agg{ | ||
| 20 | .val1 = v1, | ||
| 21 | .val2 = v2, | ||
| 22 | }); | ||
| 23 | |||
| 24 | const array = [_]Value{ v1, v2, v1, v2 }; | ||
| 25 | |||
| 26 | test "unions embedded in aggregate types" { | ||
| 27 | switch (array[1]) { | ||
| 28 | Value.Array => |arr| try expect(arr[4] == 3), | ||
| 29 | else => unreachable, | ||
| 30 | } | ||
| 31 | switch ((err catch unreachable).val1) { | ||
| 32 | Value.Int => |x| try expect(x == 1234), | ||
| 33 | else => unreachable, | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | const Letter = enum { A, B, C }; | 6 | const Letter = enum { A, B, C }; |
| 38 | const Payload = union(Letter) { | 7 | const Payload = union(Letter) { |
| 39 | A: i32, | 8 | A: i32, |
test/stage2/cbe.zig+1-1| ... | @@ -852,7 +852,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -852,7 +852,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 852 | \\ _ = E.d; | 852 | \\ _ = E.d; |
| 853 | \\} | 853 | \\} |
| 854 | , &.{ | 854 | , &.{ |
| 855 | ":3:10: error: enum 'tmp.E' has no member named 'd'", | 855 | ":3:11: error: enum 'tmp.E' has no member named 'd'", |
| 856 | ":1:11: note: enum declared here", | 856 | ":1:11: note: enum declared here", |
| 857 | }); | 857 | }); |
| 858 | 858 |