| ... | ... | @@ -9309,8 +9309,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9309 | 9309 | break :blk sema.typeOf(raw_operand); |
| 9310 | 9310 | }; |
| 9311 | 9311 | const union_originally = maybe_union_ty.zigTypeTag() == .Union; |
| 9312 | | var seen_union_fields: []?Module.SwitchProngSrc = &.{}; |
| 9313 | | defer gpa.free(seen_union_fields); |
| 9312 | |
| 9313 | // Duplicate checking variables later also used for `inline else`. |
| 9314 | var seen_enum_fields: []?Module.SwitchProngSrc = &.{}; |
| 9315 | var seen_errors = SwitchErrorSet.init(gpa); |
| 9316 | var range_set = RangeSet.init(gpa, sema.mod); |
| 9317 | var true_count: u8 = 0; |
| 9318 | var false_count: u8 = 0; |
| 9319 | |
| 9320 | defer { |
| 9321 | range_set.deinit(); |
| 9322 | gpa.free(seen_enum_fields); |
| 9323 | seen_errors.deinit(); |
| 9324 | } |
| 9314 | 9325 | |
| 9315 | 9326 | var empty_enum = false; |
| 9316 | 9327 | |
| ... | ... | @@ -9347,15 +9358,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9347 | 9358 | switch (operand_ty.zigTypeTag()) { |
| 9348 | 9359 | .Union => unreachable, // handled in zirSwitchCond |
| 9349 | 9360 | .Enum => { |
| 9350 | | var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); |
| 9351 | | empty_enum = seen_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(); |
| 9352 | | defer if (!union_originally) gpa.free(seen_fields); |
| 9353 | | if (union_originally) seen_union_fields = seen_fields; |
| 9354 | | mem.set(?Module.SwitchProngSrc, seen_fields, null); |
| 9355 | | |
| 9356 | | // This is used for non-exhaustive enum values that do not correspond to any tags. |
| 9357 | | var range_set = RangeSet.init(gpa, sema.mod); |
| 9358 | | defer range_set.deinit(); |
| 9361 | seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); |
| 9362 | empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(); |
| 9363 | mem.set(?Module.SwitchProngSrc, seen_enum_fields, null); |
| 9364 | // `range_set` is used for non-exhaustive enum values that do not correspond to any tags. |
| 9359 | 9365 | |
| 9360 | 9366 | var extra_index: usize = special.end; |
| 9361 | 9367 | { |
| ... | ... | @@ -9369,7 +9375,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9369 | 9375 | |
| 9370 | 9376 | try sema.validateSwitchItemEnum( |
| 9371 | 9377 | block, |
| 9372 | | seen_fields, |
| 9378 | seen_enum_fields, |
| 9373 | 9379 | &range_set, |
| 9374 | 9380 | item_ref, |
| 9375 | 9381 | src_node_offset, |
| ... | ... | @@ -9392,7 +9398,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9392 | 9398 | for (items) |item_ref, item_i| { |
| 9393 | 9399 | try sema.validateSwitchItemEnum( |
| 9394 | 9400 | block, |
| 9395 | | seen_fields, |
| 9401 | seen_enum_fields, |
| 9396 | 9402 | &range_set, |
| 9397 | 9403 | item_ref, |
| 9398 | 9404 | src_node_offset, |
| ... | ... | @@ -9403,7 +9409,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9403 | 9409 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); |
| 9404 | 9410 | } |
| 9405 | 9411 | } |
| 9406 | | const all_tags_handled = for (seen_fields) |seen_src| { |
| 9412 | const all_tags_handled = for (seen_enum_fields) |seen_src| { |
| 9407 | 9413 | if (seen_src == null) break false; |
| 9408 | 9414 | } else true; |
| 9409 | 9415 | |
| ... | ... | @@ -9423,7 +9429,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9423 | 9429 | .{}, |
| 9424 | 9430 | ); |
| 9425 | 9431 | errdefer msg.destroy(sema.gpa); |
| 9426 | | for (seen_fields) |seen_src, i| { |
| 9432 | for (seen_enum_fields) |seen_src, i| { |
| 9427 | 9433 | if (seen_src != null) continue; |
| 9428 | 9434 | |
| 9429 | 9435 | const field_name = operand_ty.enumFieldName(i); |
| ... | ... | @@ -9454,9 +9460,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9454 | 9460 | } |
| 9455 | 9461 | }, |
| 9456 | 9462 | .ErrorSet => { |
| 9457 | | var seen_errors = SwitchErrorSet.init(gpa); |
| 9458 | | defer seen_errors.deinit(); |
| 9459 | | |
| 9460 | 9463 | var extra_index: usize = special.end; |
| 9461 | 9464 | { |
| 9462 | 9465 | var scalar_i: u32 = 0; |
| ... | ... | @@ -9596,9 +9599,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9596 | 9599 | } |
| 9597 | 9600 | }, |
| 9598 | 9601 | .Int, .ComptimeInt => { |
| 9599 | | var range_set = RangeSet.init(gpa, sema.mod); |
| 9600 | | defer range_set.deinit(); |
| 9601 | | |
| 9602 | 9602 | var extra_index: usize = special.end; |
| 9603 | 9603 | { |
| 9604 | 9604 | var scalar_i: u32 = 0; |
| ... | ... | @@ -9694,9 +9694,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9694 | 9694 | } |
| 9695 | 9695 | }, |
| 9696 | 9696 | .Bool => { |
| 9697 | | var true_count: u8 = 0; |
| 9698 | | var false_count: u8 = 0; |
| 9699 | | |
| 9700 | 9697 | var extra_index: usize = special.end; |
| 9701 | 9698 | { |
| 9702 | 9699 | var scalar_i: u32 = 0; |
| ... | ... | @@ -9950,16 +9947,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9950 | 9947 | return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); |
| 9951 | 9948 | } |
| 9952 | 9949 | |
| 9953 | | if (scalar_cases_len + multi_cases_len == 0) { |
| 9950 | if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) { |
| 9954 | 9951 | if (empty_enum) { |
| 9955 | 9952 | return Air.Inst.Ref.void_value; |
| 9956 | 9953 | } |
| 9957 | 9954 | if (special_prong == .none) { |
| 9958 | 9955 | return sema.fail(block, src, "switch must handle all possibilities", .{}); |
| 9959 | 9956 | } |
| 9960 | | if (special.is_inline) { |
| 9961 | | return sema.fail(block, src, "TODO special.is_inline", .{}); |
| 9962 | | } |
| 9963 | 9957 | if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { |
| 9964 | 9958 | return Air.Inst.Ref.unreachable_value; |
| 9965 | 9959 | } |
| ... | ... | @@ -10323,16 +10317,181 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10323 | 10317 | if (special.body.len != 0 or !is_first or case_block.wantSafety()) { |
| 10324 | 10318 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); |
| 10325 | 10319 | defer wip_captures.deinit(); |
| 10320 | if (special.is_inline) switch (operand_ty.zigTypeTag()) { |
| 10321 | .Enum => { |
| 10322 | if (operand_ty.isNonexhaustiveEnum() and !union_originally) { |
| 10323 | return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ |
| 10324 | operand_ty.fmt(sema.mod), |
| 10325 | }); |
| 10326 | } |
| 10327 | var emit_bb = false; |
| 10328 | for (seen_enum_fields) |f, i| { |
| 10329 | if (f != null) continue; |
| 10330 | cases_len += 1; |
| 10331 | |
| 10332 | const item_val = try Value.Tag.enum_field_index.create(sema.arena, @intCast(u32, i)); |
| 10333 | const item_ref = try sema.addConstant(operand_ty, item_val); |
| 10334 | case_block.inline_case_capture = item_ref; |
| 10335 | |
| 10336 | case_block.instructions.shrinkRetainingCapacity(0); |
| 10337 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 10338 | |
| 10339 | const analyze_body = if (union_originally) blk: { |
| 10340 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); |
| 10341 | break :blk field_ty.zigTypeTag() != .NoReturn; |
| 10342 | } else true; |
| 10343 | |
| 10344 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 10345 | emit_bb = true; |
| 10346 | |
| 10347 | if (analyze_body) { |
| 10348 | _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) { |
| 10349 | error.ComptimeBreak => { |
| 10350 | const zir_datas = sema.code.instructions.items(.data); |
| 10351 | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 10352 | try sema.addRuntimeBreak(&case_block, .{ |
| 10353 | .block_inst = break_data.block_inst, |
| 10354 | .operand = break_data.operand, |
| 10355 | .inst = sema.comptime_break_inst, |
| 10356 | }); |
| 10357 | }, |
| 10358 | else => |e| return e, |
| 10359 | }; |
| 10360 | } else { |
| 10361 | _ = try case_block.addNoOp(.unreach); |
| 10362 | } |
| 10363 | |
| 10364 | // try wip_captures.finalize(); |
| 10365 | |
| 10366 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 10367 | cases_extra.appendAssumeCapacity(1); // items_len |
| 10368 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 10369 | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 10370 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 10371 | } |
| 10372 | }, |
| 10373 | .ErrorSet => { |
| 10374 | if (operand_ty.isAnyError()) { |
| 10375 | return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ |
| 10376 | operand_ty.fmt(sema.mod), |
| 10377 | }); |
| 10378 | } |
| 10379 | var emit_bb = false; |
| 10380 | for (operand_ty.errorSetNames()) |error_name| { |
| 10381 | if (seen_errors.contains(error_name)) continue; |
| 10382 | cases_len += 1; |
| 10383 | |
| 10384 | const item_val = try Value.Tag.@"error".create(sema.arena, .{ .name = error_name }); |
| 10385 | const item_ref = try sema.addConstant(operand_ty, item_val); |
| 10386 | case_block.inline_case_capture = item_ref; |
| 10387 | |
| 10388 | case_block.instructions.shrinkRetainingCapacity(0); |
| 10389 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 10390 | |
| 10391 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 10392 | emit_bb = true; |
| 10393 | |
| 10394 | _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) { |
| 10395 | error.ComptimeBreak => { |
| 10396 | const zir_datas = sema.code.instructions.items(.data); |
| 10397 | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 10398 | try sema.addRuntimeBreak(&case_block, .{ |
| 10399 | .block_inst = break_data.block_inst, |
| 10400 | .operand = break_data.operand, |
| 10401 | .inst = sema.comptime_break_inst, |
| 10402 | }); |
| 10403 | }, |
| 10404 | else => |e| return e, |
| 10405 | }; |
| 10406 | |
| 10407 | // try wip_captures.finalize(); |
| 10408 | |
| 10409 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 10410 | cases_extra.appendAssumeCapacity(1); // items_len |
| 10411 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 10412 | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 10413 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 10414 | } |
| 10415 | }, |
| 10416 | .Int => { |
| 10417 | return sema.fail(block, special_prong_src, "TODO 'inline else' Int", .{}); |
| 10418 | }, |
| 10419 | .Bool => { |
| 10420 | var emit_bb = false; |
| 10421 | if (true_count == 0) { |
| 10422 | cases_len += 1; |
| 10423 | case_block.inline_case_capture = Air.Inst.Ref.bool_true; |
| 10424 | |
| 10425 | case_block.instructions.shrinkRetainingCapacity(0); |
| 10426 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 10427 | |
| 10428 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 10429 | emit_bb = true; |
| 10430 | |
| 10431 | _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) { |
| 10432 | error.ComptimeBreak => { |
| 10433 | const zir_datas = sema.code.instructions.items(.data); |
| 10434 | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 10435 | try sema.addRuntimeBreak(&case_block, .{ |
| 10436 | .block_inst = break_data.block_inst, |
| 10437 | .operand = break_data.operand, |
| 10438 | .inst = sema.comptime_break_inst, |
| 10439 | }); |
| 10440 | }, |
| 10441 | else => |e| return e, |
| 10442 | }; |
| 10443 | |
| 10444 | // try wip_captures.finalize(); |
| 10445 | |
| 10446 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 10447 | cases_extra.appendAssumeCapacity(1); // items_len |
| 10448 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 10449 | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 10450 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 10451 | } |
| 10452 | if (false_count == 0) { |
| 10453 | cases_len += 1; |
| 10454 | case_block.inline_case_capture = Air.Inst.Ref.bool_false; |
| 10455 | |
| 10456 | case_block.instructions.shrinkRetainingCapacity(0); |
| 10457 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 10458 | |
| 10459 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 10460 | emit_bb = true; |
| 10461 | |
| 10462 | _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) { |
| 10463 | error.ComptimeBreak => { |
| 10464 | const zir_datas = sema.code.instructions.items(.data); |
| 10465 | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 10466 | try sema.addRuntimeBreak(&case_block, .{ |
| 10467 | .block_inst = break_data.block_inst, |
| 10468 | .operand = break_data.operand, |
| 10469 | .inst = sema.comptime_break_inst, |
| 10470 | }); |
| 10471 | }, |
| 10472 | else => |e| return e, |
| 10473 | }; |
| 10474 | |
| 10475 | // try wip_captures.finalize(); |
| 10476 | |
| 10477 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 10478 | cases_extra.appendAssumeCapacity(1); // items_len |
| 10479 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 10480 | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 10481 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 10482 | } |
| 10483 | }, |
| 10484 | else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ |
| 10485 | operand_ty.fmt(sema.mod), |
| 10486 | }), |
| 10487 | }; |
| 10326 | 10488 | |
| 10327 | 10489 | case_block.instructions.shrinkRetainingCapacity(0); |
| 10328 | 10490 | case_block.wip_capture_scope = wip_captures.scope; |
| 10329 | 10491 | case_block.inline_case_capture = .none; |
| 10330 | | if (special.is_inline) { |
| 10331 | | return sema.fail(block, src, "TODO special.is_inline", .{}); |
| 10332 | | } |
| 10333 | 10492 | |
| 10334 | | const analyze_body = if (union_originally) |
| 10335 | | for (seen_union_fields) |seen_field, index| { |
| 10493 | const analyze_body = if (union_originally and !special.is_inline) |
| 10494 | for (seen_enum_fields) |seen_field, index| { |
| 10336 | 10495 | if (seen_field != null) continue; |
| 10337 | 10496 | const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data; |
| 10338 | 10497 | const field_ty = union_obj.fields.values()[index].ty; |
| ... | ... | @@ -10344,7 +10503,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10344 | 10503 | try sema.maybeErrorUnwrap(&case_block, special.body, operand)) |
| 10345 | 10504 | { |
| 10346 | 10505 | // nothing to do here |
| 10347 | | } else if (special.body.len != 0 and analyze_body) { |
| 10506 | } else if (special.body.len != 0 and analyze_body and !special.is_inline) { |
| 10348 | 10507 | _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) { |
| 10349 | 10508 | error.ComptimeBreak => { |
| 10350 | 10509 | const zir_datas = sema.code.instructions.items(.data); |