authorgravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2023-11-22 15:01:18+11:00
committergravatar for 4678790+dweiller@users.noreply.github.comDominic <4678790+dweiller@users.noreply.github.com> 2024-01-09 14:42:12+11:00
logae19f699ab3a831d48a18c75d062fff17ab9268e
tree9ddce11182bf0c758c1f3fe2c7d8d77b5c7d5b55
parent2cf648fba7f00bb42df1c8dad213a23427d528da

sema: implement switch_block_err_union on comptime operands


1 files changed, 190 insertions(+), 1 deletions(-)

src/Sema.zig+190-1
...@@ -1097,7 +1097,7 @@ fn analyzeBodyInner(...@@ -1097,7 +1097,7 @@ fn analyzeBodyInner(
1097 .str => try sema.zirStr(inst),1097 .str => try sema.zirStr(inst),
1098 .switch_block => try sema.zirSwitchBlock(block, inst, false),1098 .switch_block => try sema.zirSwitchBlock(block, inst, false),
1099 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),1099 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
1100 .switch_block_err_union => @panic("TODO: implement lowering of switch_block_err_union"),1100 .switch_block_err_union => try sema.zirSwitchBlockErrUnion(block, inst),
1101 .type_info => try sema.zirTypeInfo(block, inst),1101 .type_info => try sema.zirTypeInfo(block, inst),
1102 .size_of => try sema.zirSizeOf(block, inst),1102 .size_of => try sema.zirSizeOf(block, inst),
1103 .bit_size_of => try sema.zirBitSizeOf(block, inst),1103 .bit_size_of => try sema.zirBitSizeOf(block, inst),
...@@ -11160,6 +11160,195 @@ fn switchCond(...@@ -11160,6 +11160,195 @@ fn switchCond(
1116011160
11161const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc);11161const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc);
1116211162
11163fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
11164 const tracy = trace(@src());
11165 defer tracy.end();
11166
11167 const mod = sema.mod;
11168 const gpa = sema.gpa;
11169 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
11170 const src = inst_data.src();
11171 const src_node_offset = inst_data.src_node;
11172 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
11173 const else_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
11174 const extra = sema.code.extraData(Zir.Inst.SwitchBlockErrUnion, inst_data.payload_index);
11175
11176 const raw_operand_val = try sema.resolveInst(extra.data.operand);
11177 assert(sema.typeOf(raw_operand_val).zigTypeTag(mod) == .ErrorUnion);
11178
11179 // AstGen guarantees that the instruction immediately preceding
11180 // switch_block_err_union is a dbg_stmt
11181 const cond_dbg_node_index: Zir.Inst.Index = @enumFromInt(@intFromEnum(inst) - 1);
11182 _ = cond_dbg_node_index;
11183
11184 var header_extra_index: usize = extra.end;
11185
11186 const scalar_cases_len = extra.data.bits.scalar_cases_len;
11187 const multi_cases_len = if (extra.data.bits.has_multi_cases) blk: {
11188 const multi_cases_len = sema.code.extra[header_extra_index];
11189 header_extra_index += 1;
11190 break :blk multi_cases_len;
11191 } else 0;
11192
11193 var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
11194 defer case_vals.deinit(gpa);
11195
11196 const NonError = struct {
11197 body: []const Zir.Inst.Index,
11198 end: usize,
11199 };
11200
11201 const non_error_case: NonError = non_error: {
11202 const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[header_extra_index]);
11203 const extra_body_start = header_extra_index + 1;
11204 break :non_error .{
11205 .body = sema.code.bodySlice(extra_body_start, info.body_len),
11206 .end = extra_body_start + info.body_len,
11207 };
11208 };
11209
11210 const Else = struct {
11211 body: []const Zir.Inst.Index,
11212 end: usize,
11213 is_inline: bool,
11214 has_capture: bool,
11215 };
11216
11217 const else_case: Else = if (!extra.data.bits.has_else) .{
11218 .body = &.{},
11219 .end = non_error_case.end,
11220 .is_inline = false,
11221 .has_capture = false,
11222 } else special: {
11223 const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[non_error_case.end]);
11224 const extra_body_start = non_error_case.end + 1;
11225 assert(info.capture != .by_ref);
11226 assert(!info.has_tag_capture);
11227 break :special .{
11228 .body = sema.code.bodySlice(extra_body_start, info.body_len),
11229 .end = extra_body_start + info.body_len,
11230 .is_inline = info.is_inline,
11231 .has_capture = info.capture == .by_val,
11232 };
11233 };
11234
11235 var seen_errors = SwitchErrorSet.init(gpa);
11236 defer seen_errors.deinit();
11237
11238 const operand_ty = sema.typeOf(raw_operand_val);
11239 const operand_err_set_ty = operand_ty.errorUnionSet(mod);
11240
11241 const else_error_ty: ?Type = try validateErrSetSwitch(
11242 sema,
11243 block,
11244 &seen_errors,
11245 &case_vals,
11246 operand_err_set_ty,
11247 inst_data,
11248 scalar_cases_len,
11249 multi_cases_len,
11250 .{ .body = else_case.body, .end = else_case.end, .src = else_prong_src },
11251 extra.data.bits.has_else,
11252 );
11253
11254 var spa: SwitchProngAnalysis = .{
11255 .sema = sema,
11256 .parent_block = block,
11257 .operand = raw_operand_val,
11258 .operand_ptr = .none,
11259 .cond = raw_operand_val,
11260 .else_error_ty = else_error_ty,
11261 .switch_block_inst = inst,
11262 .tag_capture_inst = undefined,
11263 };
11264
11265 const block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
11266 try sema.air_instructions.append(gpa, .{
11267 .tag = .block,
11268 .data = undefined,
11269 });
11270 var label: Block.Label = .{
11271 .zir_block = inst,
11272 .merges = .{
11273 .src_locs = .{},
11274 .results = .{},
11275 .br_list = .{},
11276 .block_inst = block_inst,
11277 },
11278 };
11279
11280 var child_block: Block = .{
11281 .parent = block,
11282 .sema = sema,
11283 .src_decl = block.src_decl,
11284 .namespace = block.namespace,
11285 .wip_capture_scope = block.wip_capture_scope,
11286 .instructions = .{},
11287 .label = &label,
11288 .inlining = block.inlining,
11289 .is_comptime = block.is_comptime,
11290 .comptime_reason = block.comptime_reason,
11291 .is_typeof = block.is_typeof,
11292 .c_import_buf = block.c_import_buf,
11293 .runtime_cond = block.runtime_cond,
11294 .runtime_loop = block.runtime_loop,
11295 .runtime_index = block.runtime_index,
11296 .error_return_trace_index = block.error_return_trace_index,
11297 };
11298 const merges = &child_block.label.?.merges;
11299 defer child_block.instructions.deinit(gpa);
11300 defer merges.deinit(gpa);
11301
11302 if (try sema.resolveDefinedValue(&child_block, src, raw_operand_val)) |operand_val| {
11303 if (operand_val.errorUnionIsPayload(mod)) {
11304 return sema.resolveBlockBody(block, operand_src, &child_block, non_error_case.body, inst, merges);
11305 } else {
11306 const err_val = Value.fromInterned(try mod.intern(.{
11307 .err = .{
11308 .ty = operand_err_set_ty.toIntern(),
11309 .name = operand_val.getErrorName(mod).unwrap().?,
11310 },
11311 }));
11312 spa.operand = try sema.analyzeErrUnionCode(block, operand_src, raw_operand_val);
11313 return resolveSwitchComptime(
11314 sema,
11315 spa,
11316 &child_block,
11317 try sema.switchCond(block, operand_src, spa.operand),
11318 err_val,
11319 operand_err_set_ty,
11320 .{
11321 .body = else_case.body,
11322 .end = else_case.end,
11323 .capture = if (else_case.has_capture) .by_val else .none,
11324 .is_inline = else_case.is_inline,
11325 .has_tag_capture = false,
11326 },
11327 case_vals,
11328 scalar_cases_len,
11329 multi_cases_len,
11330 true,
11331 false,
11332 );
11333 }
11334 }
11335
11336 if (scalar_cases_len + multi_cases_len == 0) {
11337 if (else_error_ty) |ty| if (ty.errorSetIsEmpty(mod)) {
11338 return sema.resolveBlockBody(block, operand_src, &child_block, non_error_case.body, inst, merges);
11339 };
11340 }
11341
11342 if (child_block.is_comptime) {
11343 _ = try sema.resolveConstDefinedValue(&child_block, operand_src, operand, .{
11344 .needed_comptime_reason = "condition in comptime switch must be comptime-known",
11345 .block_comptime_reason = child_block.comptime_reason,
11346 });
11347 unreachable;
11348 }
11349 return sema.fail(block, src, "TODO: implement more of switch_block_err_union", .{});
11350}
11351
11163fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_ref: bool) CompileError!Air.Inst.Ref {11352fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_ref: bool) CompileError!Air.Inst.Ref {
11164 const tracy = trace(@src());11353 const tracy = trace(@src());
11165 defer tracy.end();11354 defer tracy.end();