| ... | @@ -9309,8 +9309,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9309,8 +9309,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9309 | break :blk sema.typeOf(raw_operand); | 9309 | break :blk sema.typeOf(raw_operand); |
| 9310 | }; | 9310 | }; |
| 9311 | const union_originally = maybe_union_ty.zigTypeTag() == .Union; | 9311 | const union_originally = maybe_union_ty.zigTypeTag() == .Union; |
| 9312 | var seen_union_fields: []?Module.SwitchProngSrc = &.{}; | 9312 | |
| 9313 | defer gpa.free(seen_union_fields); | 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 | var empty_enum = false; | 9326 | var empty_enum = false; |
| 9316 | | 9327 | |
| ... | @@ -9347,15 +9358,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9347,15 +9358,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9347 | switch (operand_ty.zigTypeTag()) { | 9358 | switch (operand_ty.zigTypeTag()) { |
| 9348 | .Union => unreachable, // handled in zirSwitchCond | 9359 | .Union => unreachable, // handled in zirSwitchCond |
| 9349 | .Enum => { | 9360 | .Enum => { |
| 9350 | var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); | 9361 | seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); |
| 9351 | empty_enum = seen_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(); | 9362 | empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(); |
| 9352 | defer if (!union_originally) gpa.free(seen_fields); | 9363 | mem.set(?Module.SwitchProngSrc, seen_enum_fields, null); |
| 9353 | if (union_originally) seen_union_fields = seen_fields; | 9364 | // `range_set` is used for non-exhaustive enum values that do not correspond to any tags. |
| 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(); | | |
| 9359 | | 9365 | |
| 9360 | var extra_index: usize = special.end; | 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,7 +9375,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9369 | | 9375 | |
| 9370 | try sema.validateSwitchItemEnum( | 9376 | try sema.validateSwitchItemEnum( |
| 9371 | block, | 9377 | block, |
| 9372 | seen_fields, | 9378 | seen_enum_fields, |
| 9373 | &range_set, | 9379 | &range_set, |
| 9374 | item_ref, | 9380 | item_ref, |
| 9375 | src_node_offset, | 9381 | src_node_offset, |
| ... | @@ -9392,7 +9398,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9392,7 +9398,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9392 | for (items) |item_ref, item_i| { | 9398 | for (items) |item_ref, item_i| { |
| 9393 | try sema.validateSwitchItemEnum( | 9399 | try sema.validateSwitchItemEnum( |
| 9394 | block, | 9400 | block, |
| 9395 | seen_fields, | 9401 | seen_enum_fields, |
| 9396 | &range_set, | 9402 | &range_set, |
| 9397 | item_ref, | 9403 | item_ref, |
| 9398 | src_node_offset, | 9404 | src_node_offset, |
| ... | @@ -9403,7 +9409,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9403,7 +9409,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9403 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); | 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 | if (seen_src == null) break false; | 9413 | if (seen_src == null) break false; |
| 9408 | } else true; | 9414 | } else true; |
| 9409 | | 9415 | |
| ... | @@ -9423,7 +9429,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9423,7 +9429,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9423 | .{}, | 9429 | .{}, |
| 9424 | ); | 9430 | ); |
| 9425 | errdefer msg.destroy(sema.gpa); | 9431 | errdefer msg.destroy(sema.gpa); |
| 9426 | for (seen_fields) |seen_src, i| { | 9432 | for (seen_enum_fields) |seen_src, i| { |
| 9427 | if (seen_src != null) continue; | 9433 | if (seen_src != null) continue; |
| 9428 | | 9434 | |
| 9429 | const field_name = operand_ty.enumFieldName(i); | 9435 | const field_name = operand_ty.enumFieldName(i); |
| ... | @@ -9454,9 +9460,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9454,9 +9460,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9454 | } | 9460 | } |
| 9455 | }, | 9461 | }, |
| 9456 | .ErrorSet => { | 9462 | .ErrorSet => { |
| 9457 | var seen_errors = SwitchErrorSet.init(gpa); | | |
| 9458 | defer seen_errors.deinit(); | | |
| 9459 | | | |
| 9460 | var extra_index: usize = special.end; | 9463 | var extra_index: usize = special.end; |
| 9461 | { | 9464 | { |
| 9462 | var scalar_i: u32 = 0; | 9465 | var scalar_i: u32 = 0; |
| ... | @@ -9596,9 +9599,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9596,9 +9599,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9596 | } | 9599 | } |
| 9597 | }, | 9600 | }, |
| 9598 | .Int, .ComptimeInt => { | 9601 | .Int, .ComptimeInt => { |
| 9599 | var range_set = RangeSet.init(gpa, sema.mod); | | |
| 9600 | defer range_set.deinit(); | | |
| 9601 | | | |
| 9602 | var extra_index: usize = special.end; | 9602 | var extra_index: usize = special.end; |
| 9603 | { | 9603 | { |
| 9604 | var scalar_i: u32 = 0; | 9604 | var scalar_i: u32 = 0; |
| ... | @@ -9694,9 +9694,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9694,9 +9694,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9694 | } | 9694 | } |
| 9695 | }, | 9695 | }, |
| 9696 | .Bool => { | 9696 | .Bool => { |
| 9697 | var true_count: u8 = 0; | | |
| 9698 | var false_count: u8 = 0; | | |
| 9699 | | | |
| 9700 | var extra_index: usize = special.end; | 9697 | var extra_index: usize = special.end; |
| 9701 | { | 9698 | { |
| 9702 | var scalar_i: u32 = 0; | 9699 | var scalar_i: u32 = 0; |
| ... | @@ -9950,16 +9947,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9950,16 +9947,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9950 | return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); | 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 | if (empty_enum) { | 9951 | if (empty_enum) { |
| 9955 | return Air.Inst.Ref.void_value; | 9952 | return Air.Inst.Ref.void_value; |
| 9956 | } | 9953 | } |
| 9957 | if (special_prong == .none) { | 9954 | if (special_prong == .none) { |
| 9958 | return sema.fail(block, src, "switch must handle all possibilities", .{}); | 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 | if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { | 9957 | if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { |
| 9964 | return Air.Inst.Ref.unreachable_value; | 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,16 +10317,181 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10323 | if (special.body.len != 0 or !is_first or case_block.wantSafety()) { | 10317 | if (special.body.len != 0 or !is_first or case_block.wantSafety()) { |
| 10324 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); | 10318 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); |
| 10325 | defer wip_captures.deinit(); | 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 | case_block.instructions.shrinkRetainingCapacity(0); | 10489 | case_block.instructions.shrinkRetainingCapacity(0); |
| 10328 | case_block.wip_capture_scope = wip_captures.scope; | 10490 | case_block.wip_capture_scope = wip_captures.scope; |
| 10329 | case_block.inline_case_capture = .none; | 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) | 10493 | const analyze_body = if (union_originally and !special.is_inline) |
| 10335 | for (seen_union_fields) |seen_field, index| { | 10494 | for (seen_enum_fields) |seen_field, index| { |
| 10336 | if (seen_field != null) continue; | 10495 | if (seen_field != null) continue; |
| 10337 | const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data; | 10496 | const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data; |
| 10338 | const field_ty = union_obj.fields.values()[index].ty; | 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,7 +10503,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10344 | try sema.maybeErrorUnwrap(&case_block, special.body, operand)) | 10503 | try sema.maybeErrorUnwrap(&case_block, special.body, operand)) |
| 10345 | { | 10504 | { |
| 10346 | // nothing to do here | 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 | _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) { | 10507 | _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) { |
| 10349 | error.ComptimeBreak => { | 10508 | error.ComptimeBreak => { |
| 10350 | const zir_datas = sema.code.instructions.items(.data); | 10509 | const zir_datas = sema.code.instructions.items(.data); |