| ... | ... | @@ -162,6 +162,9 @@ pub const Block = struct { |
| 162 | 162 | /// type of `err` in `else => |err|` |
| 163 | 163 | switch_else_err_ty: ?Type = null, |
| 164 | 164 | |
| 165 | /// Value for switch_capture in an inline case |
| 166 | inline_case_capture: Air.Inst.Ref = .none, |
| 167 | |
| 165 | 168 | const Param = struct { |
| 166 | 169 | /// `noreturn` means `anytype`. |
| 167 | 170 | ty: Type, |
| ... | ... | @@ -9002,6 +9005,30 @@ fn zirSwitchCapture( |
| 9002 | 9005 | const operand_ptr_ty = sema.typeOf(operand_ptr); |
| 9003 | 9006 | const operand_ty = if (operand_is_ref) operand_ptr_ty.childType() else operand_ptr_ty; |
| 9004 | 9007 | |
| 9008 | if (block.inline_case_capture != .none) { |
| 9009 | const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable; |
| 9010 | if (operand_ty.zigTypeTag() == .Union) { |
| 9011 | const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?); |
| 9012 | const union_obj = operand_ty.cast(Type.Payload.Union).?.data; |
| 9013 | const field_ty = union_obj.fields.values()[field_index].ty; |
| 9014 | if (is_ref) { |
| 9015 | const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 9016 | .pointee_type = field_ty, |
| 9017 | .mutable = operand_ptr_ty.ptrIsMutable(), |
| 9018 | .@"volatile" = operand_ptr_ty.isVolatilePtr(), |
| 9019 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(), |
| 9020 | }); |
| 9021 | return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty); |
| 9022 | } else { |
| 9023 | return block.addStructFieldVal(operand_ptr, field_index, field_ty); |
| 9024 | } |
| 9025 | } else if (is_ref) { |
| 9026 | return sema.addConstantMaybeRef(block, operand_src, operand_ty, item_val, true); |
| 9027 | } else { |
| 9028 | return block.inline_case_capture; |
| 9029 | } |
| 9030 | } |
| 9031 | |
| 9005 | 9032 | const operand = if (operand_is_ref) |
| 9006 | 9033 | try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src) |
| 9007 | 9034 | else |
| ... | ... | @@ -9234,14 +9261,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9234 | 9261 | } else 0; |
| 9235 | 9262 | |
| 9236 | 9263 | const special_prong = extra.data.bits.specialProng(); |
| 9237 | | const special: struct { body: []const Zir.Inst.Index, end: usize } = switch (special_prong) { |
| 9238 | | .none => .{ .body = &.{}, .end = header_extra_index }, |
| 9264 | const special: struct { body: []const Zir.Inst.Index, end: usize, is_inline: bool } = switch (special_prong) { |
| 9265 | .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false }, |
| 9239 | 9266 | .under, .@"else" => blk: { |
| 9240 | 9267 | const body_len = @truncate(u31, sema.code.extra[header_extra_index]); |
| 9241 | 9268 | const extra_body_start = header_extra_index + 1; |
| 9242 | 9269 | break :blk .{ |
| 9243 | 9270 | .body = sema.code.extra[extra_body_start..][0..body_len], |
| 9244 | 9271 | .end = extra_body_start + body_len, |
| 9272 | .is_inline = sema.code.extra[header_extra_index] >> 31 != 0, |
| 9245 | 9273 | }; |
| 9246 | 9274 | }, |
| 9247 | 9275 | }; |
| ... | ... | @@ -9901,6 +9929,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9901 | 9929 | if (special_prong == .none) { |
| 9902 | 9930 | return sema.fail(block, src, "switch must handle all possibilities", .{}); |
| 9903 | 9931 | } |
| 9932 | if (special.is_inline) { |
| 9933 | return sema.fail(block, src, "TODO special.is_inline", .{}); |
| 9934 | } |
| 9904 | 9935 | if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { |
| 9905 | 9936 | return Air.Inst.Ref.unreachable_value; |
| 9906 | 9937 | } |
| ... | ... | @@ -9927,6 +9958,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9927 | 9958 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 9928 | 9959 | extra_index += 1; |
| 9929 | 9960 | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 9961 | const is_inline = sema.code.extra[extra_index] >> 31 != 0; |
| 9930 | 9962 | extra_index += 1; |
| 9931 | 9963 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 9932 | 9964 | extra_index += body_len; |
| ... | ... | @@ -9936,8 +9968,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9936 | 9968 | |
| 9937 | 9969 | case_block.instructions.shrinkRetainingCapacity(0); |
| 9938 | 9970 | case_block.wip_capture_scope = wip_captures.scope; |
| 9971 | case_block.inline_case_capture = .none; |
| 9939 | 9972 | |
| 9940 | 9973 | const item = try sema.resolveInst(item_ref); |
| 9974 | if (is_inline) case_block.inline_case_capture = item; |
| 9941 | 9975 | // `item` is already guaranteed to be constant known. |
| 9942 | 9976 | |
| 9943 | 9977 | const analyze_body = if (union_originally) blk: { |
| ... | ... | @@ -9989,12 +10023,118 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9989 | 10023 | const ranges_len = sema.code.extra[extra_index]; |
| 9990 | 10024 | extra_index += 1; |
| 9991 | 10025 | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10026 | const is_inline = sema.code.extra[extra_index] >> 31 != 0; |
| 9992 | 10027 | extra_index += 1; |
| 9993 | 10028 | const items = sema.code.refSlice(extra_index, items_len); |
| 9994 | 10029 | extra_index += items_len; |
| 9995 | 10030 | |
| 9996 | 10031 | case_block.instructions.shrinkRetainingCapacity(0); |
| 9997 | 10032 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 10033 | case_block.inline_case_capture = .none; |
| 10034 | |
| 10035 | // Generate all possible cases as scalar prongs. |
| 10036 | if (is_inline) { |
| 10037 | const body_start = extra_index + 2 * ranges_len; |
| 10038 | const body = sema.code.extra[body_start..][0..body_len]; |
| 10039 | const case_src = src; // TODO better source location |
| 10040 | var emit_bb = false; |
| 10041 | |
| 10042 | var range_i: usize = 0; |
| 10043 | while (range_i < ranges_len) : (range_i += 1) { |
| 10044 | const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10045 | extra_index += 1; |
| 10046 | const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10047 | extra_index += 1; |
| 10048 | |
| 10049 | const item_first_ref = try sema.resolveInst(first_ref); |
| 10050 | var item_first = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable; |
| 10051 | const item_last_ref = try sema.resolveInst(last_ref); |
| 10052 | const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable; |
| 10053 | |
| 10054 | while (item_first.compare(.lte, item_last, operand_ty, sema.mod)) : ({ |
| 10055 | item_first = try sema.intAddScalar(block, case_src, item_first, Value.one); |
| 10056 | }) { |
| 10057 | cases_len += 1; |
| 10058 | |
| 10059 | const item_ref = try sema.addConstant(operand_ty, item_first); |
| 10060 | case_block.inline_case_capture = item_ref; |
| 10061 | |
| 10062 | case_block.instructions.shrinkRetainingCapacity(0); |
| 10063 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 10064 | |
| 10065 | if (emit_bb) try sema.emitBackwardBranch(block, case_src); |
| 10066 | emit_bb = true; |
| 10067 | |
| 10068 | _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { |
| 10069 | error.ComptimeBreak => { |
| 10070 | const zir_datas = sema.code.instructions.items(.data); |
| 10071 | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 10072 | try sema.addRuntimeBreak(&case_block, .{ |
| 10073 | .block_inst = break_data.block_inst, |
| 10074 | .operand = break_data.operand, |
| 10075 | .inst = sema.comptime_break_inst, |
| 10076 | }); |
| 10077 | }, |
| 10078 | else => |e| return e, |
| 10079 | }; |
| 10080 | |
| 10081 | // try wip_captures.finalize(); |
| 10082 | |
| 10083 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 10084 | cases_extra.appendAssumeCapacity(1); // items_len |
| 10085 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 10086 | cases_extra.appendAssumeCapacity(@enumToInt(item_ref)); |
| 10087 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 10088 | } |
| 10089 | } |
| 10090 | |
| 10091 | for (items) |item_ref| { |
| 10092 | cases_len += 1; |
| 10093 | |
| 10094 | const item = try sema.resolveInst(item_ref); |
| 10095 | case_block.inline_case_capture = item; |
| 10096 | |
| 10097 | case_block.instructions.shrinkRetainingCapacity(0); |
| 10098 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 10099 | |
| 10100 | const analyze_body = if (union_originally) blk: { |
| 10101 | const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; |
| 10102 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); |
| 10103 | break :blk field_ty.zigTypeTag() != .NoReturn; |
| 10104 | } else true; |
| 10105 | |
| 10106 | if (emit_bb) try sema.emitBackwardBranch(block, case_src); |
| 10107 | emit_bb = true; |
| 10108 | |
| 10109 | if (analyze_body) { |
| 10110 | _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) { |
| 10111 | error.ComptimeBreak => { |
| 10112 | const zir_datas = sema.code.instructions.items(.data); |
| 10113 | const break_data = zir_datas[sema.comptime_break_inst].@"break"; |
| 10114 | try sema.addRuntimeBreak(&case_block, .{ |
| 10115 | .block_inst = break_data.block_inst, |
| 10116 | .operand = break_data.operand, |
| 10117 | .inst = sema.comptime_break_inst, |
| 10118 | }); |
| 10119 | }, |
| 10120 | else => |e| return e, |
| 10121 | }; |
| 10122 | } else { |
| 10123 | _ = try case_block.addNoOp(.unreach); |
| 10124 | } |
| 10125 | |
| 10126 | // try wip_captures.finalize(); |
| 10127 | |
| 10128 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 10129 | cases_extra.appendAssumeCapacity(1); // items_len |
| 10130 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 10131 | cases_extra.appendAssumeCapacity(@enumToInt(item)); |
| 10132 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 10133 | } |
| 10134 | |
| 10135 | extra_index += body_len; |
| 10136 | continue; |
| 10137 | } |
| 9998 | 10138 | |
| 9999 | 10139 | var any_ok: Air.Inst.Ref = .none; |
| 10000 | 10140 | |
| ... | ... | @@ -10158,6 +10298,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10158 | 10298 | |
| 10159 | 10299 | case_block.instructions.shrinkRetainingCapacity(0); |
| 10160 | 10300 | case_block.wip_capture_scope = wip_captures.scope; |
| 10301 | case_block.inline_case_capture = .none; |
| 10302 | if (special.is_inline) { |
| 10303 | return sema.fail(block, src, "TODO special.is_inline", .{}); |
| 10304 | } |
| 10161 | 10305 | |
| 10162 | 10306 | const analyze_body = if (union_originally) |
| 10163 | 10307 | for (seen_union_fields) |seen_field, index| { |