| ... | ... | @@ -277,12 +277,6 @@ pub const Block = struct { |
| 277 | 277 | |
| 278 | 278 | c_import_buf: ?*std.ArrayList(u8) = null, |
| 279 | 279 | |
| 280 | | /// type of `err` in `else => |err|` |
| 281 | | switch_else_err_ty: ?Type = null, |
| 282 | | |
| 283 | | /// Value for switch_capture in an inline case |
| 284 | | inline_case_capture: Air.Inst.Ref = .none, |
| 285 | | |
| 286 | 280 | const ComptimeReason = union(enum) { |
| 287 | 281 | c_import: struct { |
| 288 | 282 | block: *Block, |
| ... | ... | @@ -397,7 +391,6 @@ pub const Block = struct { |
| 397 | 391 | .want_safety = parent.want_safety, |
| 398 | 392 | .float_mode = parent.float_mode, |
| 399 | 393 | .c_import_buf = parent.c_import_buf, |
| 400 | | .switch_else_err_ty = parent.switch_else_err_ty, |
| 401 | 394 | .error_return_trace_index = parent.error_return_trace_index, |
| 402 | 395 | }; |
| 403 | 396 | } |
| ... | ... | @@ -1014,14 +1007,8 @@ fn analyzeBodyInner( |
| 1014 | 1007 | .slice_start => try sema.zirSliceStart(block, inst), |
| 1015 | 1008 | .slice_length => try sema.zirSliceLength(block, inst), |
| 1016 | 1009 | .str => try sema.zirStr(block, inst), |
| 1017 | | .switch_block => try sema.zirSwitchBlock(block, inst), |
| 1018 | | .switch_cond => try sema.zirSwitchCond(block, inst, false), |
| 1019 | | .switch_cond_ref => try sema.zirSwitchCond(block, inst, true), |
| 1020 | | .switch_capture => try sema.zirSwitchCapture(block, inst, false, false), |
| 1021 | | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), |
| 1022 | | .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), |
| 1023 | | .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), |
| 1024 | | .switch_capture_tag => try sema.zirSwitchCaptureTag(block, inst), |
| 1010 | .switch_block => try sema.zirSwitchBlock(block, inst, false), |
| 1011 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true), |
| 1025 | 1012 | .type_info => try sema.zirTypeInfo(block, inst), |
| 1026 | 1013 | .size_of => try sema.zirSizeOf(block, inst), |
| 1027 | 1014 | .bit_size_of => try sema.zirBitSizeOf(block, inst), |
| ... | ... | @@ -1225,7 +1212,7 @@ fn analyzeBodyInner( |
| 1225 | 1212 | i += 1; |
| 1226 | 1213 | continue; |
| 1227 | 1214 | }, |
| 1228 | | .errdefer_err_code => unreachable, // never appears in a body |
| 1215 | .value_placeholder => unreachable, // never appears in a body |
| 1229 | 1216 | }; |
| 1230 | 1217 | }, |
| 1231 | 1218 | |
| ... | ... | @@ -2405,6 +2392,34 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 2405 | 2392 | return error.AnalysisFail; |
| 2406 | 2393 | } |
| 2407 | 2394 | |
| 2395 | /// Given an ErrorMsg, modify its message and source location to the given values, turning the |
| 2396 | /// original message into a note. Notes on the original message are preserved as further notes. |
| 2397 | /// Reference trace is preserved. |
| 2398 | fn reparentOwnedErrorMsg( |
| 2399 | sema: *Sema, |
| 2400 | block: *Block, |
| 2401 | src: LazySrcLoc, |
| 2402 | msg: *Module.ErrorMsg, |
| 2403 | comptime format: []const u8, |
| 2404 | args: anytype, |
| 2405 | ) !void { |
| 2406 | const mod = sema.mod; |
| 2407 | const src_decl = mod.declPtr(block.src_decl); |
| 2408 | const resolved_src = src.toSrcLoc(src_decl, mod); |
| 2409 | const msg_str = try std.fmt.allocPrint(mod.gpa, format, args); |
| 2410 | |
| 2411 | const orig_notes = msg.notes.len; |
| 2412 | msg.notes = try sema.gpa.realloc(msg.notes, orig_notes + 1); |
| 2413 | std.mem.copyBackwards(Module.ErrorMsg, msg.notes[1..], msg.notes[0..orig_notes]); |
| 2414 | msg.notes[0] = .{ |
| 2415 | .src_loc = msg.src_loc, |
| 2416 | .msg = msg.msg, |
| 2417 | }; |
| 2418 | |
| 2419 | msg.src_loc = resolved_src; |
| 2420 | msg.msg = msg_str; |
| 2421 | } |
| 2422 | |
| 2408 | 2423 | const align_ty = Type.u29; |
| 2409 | 2424 | |
| 2410 | 2425 | fn analyzeAsAlign( |
| ... | ... | @@ -10085,251 +10100,544 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10085 | 10100 | return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true); |
| 10086 | 10101 | } |
| 10087 | 10102 | |
| 10088 | | fn zirSwitchCapture( |
| 10103 | /// Holds common data used when analyzing or resolving switch prong bodies, |
| 10104 | /// including setting up captures. |
| 10105 | const SwitchProngAnalysis = struct { |
| 10089 | 10106 | sema: *Sema, |
| 10090 | | block: *Block, |
| 10091 | | inst: Zir.Inst.Index, |
| 10092 | | is_multi: bool, |
| 10093 | | is_ref: bool, |
| 10094 | | ) CompileError!Air.Inst.Ref { |
| 10095 | | const tracy = trace(@src()); |
| 10096 | | defer tracy.end(); |
| 10107 | /// The block containing the `switch_block` itself. |
| 10108 | parent_block: *Block, |
| 10109 | /// The raw switch operand value (*not* the condition). Always defined. |
| 10110 | operand: Air.Inst.Ref, |
| 10111 | /// May be `undefined` if no prong has a by-ref capture. |
| 10112 | operand_ptr: Air.Inst.Ref, |
| 10113 | /// The switch condition value. For unions, `operand` is the union and `cond` is its tag. |
| 10114 | cond: Air.Inst.Ref, |
| 10115 | /// If this switch is on an error set, this is the type to assign to the |
| 10116 | /// `else` prong. If `null`, the prong should be unreachable. |
| 10117 | else_error_ty: ?Type, |
| 10118 | /// The index of the `switch_block` instruction itself. |
| 10119 | switch_block_inst: Zir.Inst.Index, |
| 10120 | /// The dummy index into which inline tag captures should be placed. May be |
| 10121 | /// undefined if no prong has a tag capture. |
| 10122 | tag_capture_inst: Zir.Inst.Index, |
| 10123 | |
| 10124 | /// Resolve a switch prong which is determined at comptime to have no peers. |
| 10125 | /// Uses `resolveBlockBody`. Sets up captures as needed. |
| 10126 | fn resolveProngComptime( |
| 10127 | spa: SwitchProngAnalysis, |
| 10128 | child_block: *Block, |
| 10129 | prong_type: enum { normal, special }, |
| 10130 | prong_body: []const Zir.Inst.Index, |
| 10131 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, |
| 10132 | /// Must use the `scalar_capture`, `special_capture`, or `multi_capture` union field. |
| 10133 | raw_capture_src: Module.SwitchProngSrc, |
| 10134 | /// The set of all values which can reach this prong. May be undefined |
| 10135 | /// if the prong is special or contains ranges. |
| 10136 | case_vals: []const Air.Inst.Ref, |
| 10137 | /// The inline capture of this prong. If this is not an inline prong, |
| 10138 | /// this is `.none`. |
| 10139 | inline_case_capture: Air.Inst.Ref, |
| 10140 | /// Whether this prong has an inline tag capture. If `true`, then |
| 10141 | /// `inline_case_capture` cannot be `.none`. |
| 10142 | has_tag_capture: bool, |
| 10143 | merges: *Block.Merges, |
| 10144 | ) CompileError!Air.Inst.Ref { |
| 10145 | const sema = spa.sema; |
| 10146 | const src = sema.code.instructions.items(.data)[spa.switch_block_inst].pl_node.src(); |
| 10147 | |
| 10148 | if (has_tag_capture) { |
| 10149 | const tag_ref = try spa.analyzeTagCapture(child_block, raw_capture_src, inline_case_capture); |
| 10150 | sema.inst_map.putAssumeCapacity(spa.tag_capture_inst, tag_ref); |
| 10151 | } |
| 10152 | defer if (has_tag_capture) assert(sema.inst_map.remove(spa.tag_capture_inst)); |
| 10153 | |
| 10154 | switch (capture) { |
| 10155 | .none => { |
| 10156 | return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges); |
| 10157 | }, |
| 10158 | |
| 10159 | .by_val, .by_ref => { |
| 10160 | const capture_ref = try spa.analyzeCapture( |
| 10161 | child_block, |
| 10162 | capture == .by_ref, |
| 10163 | prong_type == .special, |
| 10164 | raw_capture_src, |
| 10165 | case_vals, |
| 10166 | inline_case_capture, |
| 10167 | ); |
| 10097 | 10168 | |
| 10098 | | const mod = sema.mod; |
| 10099 | | const gpa = sema.gpa; |
| 10100 | | const zir_datas = sema.code.instructions.items(.data); |
| 10101 | | const capture_info = zir_datas[inst].switch_capture; |
| 10102 | | const switch_info = zir_datas[capture_info.switch_inst].pl_node; |
| 10103 | | const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index); |
| 10104 | | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node }; |
| 10105 | | const cond_inst = Zir.refToIndex(switch_extra.data.operand).?; |
| 10106 | | const cond_info = zir_datas[cond_inst].un_node; |
| 10107 | | const cond_tag = sema.code.instructions.items(.tag)[cond_inst]; |
| 10108 | | const operand_is_ref = cond_tag == .switch_cond_ref; |
| 10109 | | const operand_ptr = try sema.resolveInst(cond_info.operand); |
| 10110 | | const operand_ptr_ty = sema.typeOf(operand_ptr); |
| 10111 | | const operand_ty = if (operand_is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty; |
| 10112 | | |
| 10113 | | if (block.inline_case_capture != .none) { |
| 10114 | | const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable; |
| 10115 | | const resolved_item_val = try sema.resolveLazyValue(item_val); |
| 10116 | | if (operand_ty.zigTypeTag(mod) == .Union) { |
| 10117 | | const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(resolved_item_val, mod).?); |
| 10118 | | const union_obj = mod.typeToUnion(operand_ty).?; |
| 10119 | | const field_ty = union_obj.fields.values()[field_index].ty; |
| 10120 | | if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| { |
| 10121 | | if (is_ref) { |
| 10169 | if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) { |
| 10170 | // This prong should be unreachable! |
| 10171 | return Air.Inst.Ref.unreachable_value; |
| 10172 | } |
| 10173 | |
| 10174 | sema.inst_map.putAssumeCapacity(spa.switch_block_inst, capture_ref); |
| 10175 | defer assert(sema.inst_map.remove(spa.switch_block_inst)); |
| 10176 | |
| 10177 | return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges); |
| 10178 | }, |
| 10179 | } |
| 10180 | } |
| 10181 | |
| 10182 | /// Analyze a switch prong which may have peers at runtime. |
| 10183 | /// Uses `analyzeBodyRuntimeBreak`. Sets up captures as needed. |
| 10184 | fn analyzeProngRuntime( |
| 10185 | spa: SwitchProngAnalysis, |
| 10186 | case_block: *Block, |
| 10187 | prong_type: enum { normal, special }, |
| 10188 | prong_body: []const Zir.Inst.Index, |
| 10189 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, |
| 10190 | /// Must use the `scalar`, `special`, or `multi_capture` union field. |
| 10191 | raw_capture_src: Module.SwitchProngSrc, |
| 10192 | /// The set of all values which can reach this prong. May be undefined |
| 10193 | /// if the prong is special or contains ranges. |
| 10194 | case_vals: []const Air.Inst.Ref, |
| 10195 | /// The inline capture of this prong. If this is not an inline prong, |
| 10196 | /// this is `.none`. |
| 10197 | inline_case_capture: Air.Inst.Ref, |
| 10198 | /// Whether this prong has an inline tag capture. If `true`, then |
| 10199 | /// `inline_case_capture` cannot be `.none`. |
| 10200 | has_tag_capture: bool, |
| 10201 | ) CompileError!void { |
| 10202 | const sema = spa.sema; |
| 10203 | |
| 10204 | if (has_tag_capture) { |
| 10205 | const tag_ref = try spa.analyzeTagCapture(case_block, raw_capture_src, inline_case_capture); |
| 10206 | sema.inst_map.putAssumeCapacity(spa.tag_capture_inst, tag_ref); |
| 10207 | } |
| 10208 | defer if (has_tag_capture) assert(sema.inst_map.remove(spa.tag_capture_inst)); |
| 10209 | |
| 10210 | switch (capture) { |
| 10211 | .none => { |
| 10212 | return sema.analyzeBodyRuntimeBreak(case_block, prong_body); |
| 10213 | }, |
| 10214 | |
| 10215 | .by_val, .by_ref => { |
| 10216 | const capture_ref = try spa.analyzeCapture( |
| 10217 | case_block, |
| 10218 | capture == .by_ref, |
| 10219 | prong_type == .special, |
| 10220 | raw_capture_src, |
| 10221 | case_vals, |
| 10222 | inline_case_capture, |
| 10223 | ); |
| 10224 | |
| 10225 | if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) { |
| 10226 | // No need to analyze any further, the prong is unreachable |
| 10227 | return; |
| 10228 | } |
| 10229 | |
| 10230 | sema.inst_map.putAssumeCapacity(spa.switch_block_inst, capture_ref); |
| 10231 | defer assert(sema.inst_map.remove(spa.switch_block_inst)); |
| 10232 | |
| 10233 | return sema.analyzeBodyRuntimeBreak(case_block, prong_body); |
| 10234 | }, |
| 10235 | } |
| 10236 | } |
| 10237 | |
| 10238 | fn analyzeTagCapture( |
| 10239 | spa: SwitchProngAnalysis, |
| 10240 | block: *Block, |
| 10241 | raw_capture_src: Module.SwitchProngSrc, |
| 10242 | inline_case_capture: Air.Inst.Ref, |
| 10243 | ) CompileError!Air.Inst.Ref { |
| 10244 | const sema = spa.sema; |
| 10245 | const mod = sema.mod; |
| 10246 | const operand_ty = sema.typeOf(spa.operand); |
| 10247 | if (operand_ty.zigTypeTag(mod) != .Union) { |
| 10248 | const zir_datas = sema.code.instructions.items(.data); |
| 10249 | const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node; |
| 10250 | const raw_tag_capture_src: Module.SwitchProngSrc = switch (raw_capture_src) { |
| 10251 | .scalar_capture => |i| .{ .scalar_tag_capture = i }, |
| 10252 | .multi_capture => |i| .{ .multi_tag_capture = i }, |
| 10253 | .special_capture => .special_tag_capture, |
| 10254 | else => unreachable, |
| 10255 | }; |
| 10256 | const capture_src = raw_tag_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none); |
| 10257 | const msg = msg: { |
| 10258 | const msg = try sema.errMsg(block, capture_src, "cannot capture tag of non-union type '{}'", .{ |
| 10259 | operand_ty.fmt(mod), |
| 10260 | }); |
| 10261 | errdefer msg.destroy(sema.gpa); |
| 10262 | try sema.addDeclaredHereNote(msg, operand_ty); |
| 10263 | break :msg msg; |
| 10264 | }; |
| 10265 | return sema.failWithOwnedErrorMsg(msg); |
| 10266 | } |
| 10267 | assert(inline_case_capture != .none); |
| 10268 | return inline_case_capture; |
| 10269 | } |
| 10270 | |
| 10271 | fn analyzeCapture( |
| 10272 | spa: SwitchProngAnalysis, |
| 10273 | block: *Block, |
| 10274 | capture_byref: bool, |
| 10275 | is_special_prong: bool, |
| 10276 | raw_capture_src: Module.SwitchProngSrc, |
| 10277 | case_vals: []const Air.Inst.Ref, |
| 10278 | inline_case_capture: Air.Inst.Ref, |
| 10279 | ) CompileError!Air.Inst.Ref { |
| 10280 | const sema = spa.sema; |
| 10281 | const mod = sema.mod; |
| 10282 | |
| 10283 | const zir_datas = sema.code.instructions.items(.data); |
| 10284 | const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node; |
| 10285 | |
| 10286 | const operand_ty = sema.typeOf(spa.operand); |
| 10287 | const operand_ptr_ty = if (capture_byref) sema.typeOf(spa.operand_ptr) else undefined; |
| 10288 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_node_offset }; |
| 10289 | |
| 10290 | if (inline_case_capture != .none) { |
| 10291 | const item_val = sema.resolveConstValue(block, .unneeded, inline_case_capture, "") catch unreachable; |
| 10292 | if (operand_ty.zigTypeTag(mod) == .Union) { |
| 10293 | const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, mod).?); |
| 10294 | const union_obj = mod.typeToUnion(operand_ty).?; |
| 10295 | const field_ty = union_obj.fields.values()[field_index].ty; |
| 10296 | if (capture_byref) { |
| 10122 | 10297 | const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ |
| 10123 | 10298 | .pointee_type = field_ty, |
| 10124 | 10299 | .mutable = operand_ptr_ty.ptrIsMutable(mod), |
| 10125 | 10300 | .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), |
| 10126 | 10301 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), |
| 10127 | 10302 | }); |
| 10128 | | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ |
| 10129 | | .ty = ptr_field_ty.toIntern(), |
| 10130 | | .addr = .{ .field = .{ |
| 10131 | | .base = union_val.toIntern(), |
| 10132 | | .index = field_index, |
| 10133 | | } }, |
| 10134 | | } })).toValue()); |
| 10303 | if (try sema.resolveDefinedValue(block, sema.src, spa.operand_ptr)) |union_ptr| { |
| 10304 | return sema.addConstant( |
| 10305 | ptr_field_ty, |
| 10306 | (try mod.intern(.{ .ptr = .{ |
| 10307 | .ty = ptr_field_ty.toIntern(), |
| 10308 | .addr = .{ .field = .{ |
| 10309 | .base = union_ptr.toIntern(), |
| 10310 | .index = field_index, |
| 10311 | } }, |
| 10312 | } })).toValue(), |
| 10313 | ); |
| 10314 | } |
| 10315 | return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty); |
| 10316 | } else { |
| 10317 | if (try sema.resolveDefinedValue(block, sema.src, spa.operand)) |union_val| { |
| 10318 | const tag_and_val = mod.intern_pool.indexToKey(union_val.toIntern()).un; |
| 10319 | return sema.addConstant(field_ty, tag_and_val.val.toValue()); |
| 10320 | } |
| 10321 | return block.addStructFieldVal(spa.operand, field_index, field_ty); |
| 10135 | 10322 | } |
| 10136 | | return sema.addConstant( |
| 10137 | | field_ty, |
| 10138 | | mod.intern_pool.indexToKey(union_val.toIntern()).un.val.toValue(), |
| 10139 | | ); |
| 10140 | | } |
| 10141 | | if (is_ref) { |
| 10142 | | const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ |
| 10143 | | .pointee_type = field_ty, |
| 10144 | | .mutable = operand_ptr_ty.ptrIsMutable(mod), |
| 10145 | | .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), |
| 10146 | | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), |
| 10147 | | }); |
| 10148 | | return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty); |
| 10323 | } else if (capture_byref) { |
| 10324 | return sema.addConstantMaybeRef(block, operand_ty, item_val, true); |
| 10149 | 10325 | } else { |
| 10150 | | return block.addStructFieldVal(operand_ptr, field_index, field_ty); |
| 10326 | return inline_case_capture; |
| 10151 | 10327 | } |
| 10152 | | } else if (is_ref) { |
| 10153 | | return sema.addConstantMaybeRef(block, operand_ty, resolved_item_val, true); |
| 10154 | | } else { |
| 10155 | | return block.inline_case_capture; |
| 10156 | 10328 | } |
| 10157 | | } |
| 10158 | 10329 | |
| 10159 | | const operand = if (operand_is_ref) |
| 10160 | | try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src) |
| 10161 | | else |
| 10162 | | operand_ptr; |
| 10330 | if (is_special_prong) { |
| 10331 | if (capture_byref) { |
| 10332 | return spa.operand_ptr; |
| 10333 | } |
| 10163 | 10334 | |
| 10164 | | if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) { |
| 10165 | | // It is the else/`_` prong. |
| 10166 | | if (is_ref) { |
| 10167 | | return operand_ptr; |
| 10335 | switch (operand_ty.zigTypeTag(mod)) { |
| 10336 | .ErrorSet => if (spa.else_error_ty) |ty| { |
| 10337 | return sema.bitCast(block, ty, spa.operand, operand_src, null); |
| 10338 | } else { |
| 10339 | try block.addUnreachable(false); |
| 10340 | return Air.Inst.Ref.unreachable_value; |
| 10341 | }, |
| 10342 | else => return spa.operand, |
| 10343 | } |
| 10168 | 10344 | } |
| 10169 | 10345 | |
| 10170 | 10346 | switch (operand_ty.zigTypeTag(mod)) { |
| 10171 | | .ErrorSet => if (block.switch_else_err_ty) |some| { |
| 10172 | | return sema.bitCast(block, some, operand, operand_src, null); |
| 10173 | | } else { |
| 10174 | | try block.addUnreachable(false); |
| 10175 | | return Air.Inst.Ref.unreachable_value; |
| 10176 | | }, |
| 10177 | | else => return operand, |
| 10178 | | } |
| 10179 | | } |
| 10347 | .Union => { |
| 10348 | const union_obj = mod.typeToUnion(operand_ty).?; |
| 10349 | const first_item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable; |
| 10180 | 10350 | |
| 10181 | | const items = if (is_multi) |
| 10182 | | switch_extra.data.getMultiProng(sema.code, switch_extra.end, capture_info.prong_index).items |
| 10183 | | else |
| 10184 | | &[_]Zir.Inst.Ref{ |
| 10185 | | switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item, |
| 10186 | | }; |
| 10351 | const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?); |
| 10352 | const first_field = union_obj.fields.values()[first_field_index]; |
| 10187 | 10353 | |
| 10188 | | switch (operand_ty.zigTypeTag(mod)) { |
| 10189 | | .Union => { |
| 10190 | | const union_obj = mod.typeToUnion(operand_ty).?; |
| 10191 | | const first_item = try sema.resolveInst(items[0]); |
| 10192 | | // Previous switch validation ensured this will succeed |
| 10193 | | const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable; |
| 10194 | | |
| 10195 | | const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?); |
| 10196 | | const first_field = union_obj.fields.values()[first_field_index]; |
| 10197 | | |
| 10198 | | for (items[1..], 0..) |item, i| { |
| 10199 | | const item_ref = try sema.resolveInst(item); |
| 10200 | | // Previous switch validation ensured this will succeed |
| 10201 | | const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; |
| 10202 | | |
| 10203 | | const field_index = operand_ty.unionTagFieldIndex(item_val, mod).?; |
| 10204 | | const field = union_obj.fields.values()[field_index]; |
| 10205 | | if (!field.ty.eql(first_field.ty, mod)) { |
| 10206 | | const msg = msg: { |
| 10207 | | const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index }; |
| 10208 | | const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); |
| 10354 | const field_tys = try sema.arena.alloc(Type, case_vals.len); |
| 10355 | for (case_vals, field_tys) |item, *field_ty| { |
| 10356 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; |
| 10357 | const field_idx = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?); |
| 10358 | field_ty.* = union_obj.fields.values()[field_idx].ty; |
| 10359 | } |
| 10209 | 10360 | |
| 10210 | | const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{}); |
| 10211 | | errdefer msg.destroy(gpa); |
| 10361 | // Fast path: if all the operands are the same type already, we don't need to hit |
| 10362 | // PTR! This will also allow us to emit simpler code. |
| 10363 | const same_types = for (field_tys[1..]) |field_ty| { |
| 10364 | if (!field_ty.eql(field_tys[0], sema.mod)) break false; |
| 10365 | } else true; |
| 10212 | 10366 | |
| 10213 | | const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } }; |
| 10214 | | const first_item_src = raw_first_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); |
| 10215 | | const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } }; |
| 10216 | | const item_src = raw_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); |
| 10217 | | try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(mod)}); |
| 10218 | | try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(mod)}); |
| 10219 | | break :msg msg; |
| 10367 | const capture_ty = if (same_types) field_tys[0] else capture_ty: { |
| 10368 | // We need values to run PTR on, so make a bunch of undef constants. |
| 10369 | const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len); |
| 10370 | for (dummy_captures, field_tys) |*dummy, field_ty| { |
| 10371 | dummy.* = try sema.addConstUndef(field_ty); |
| 10372 | } |
| 10373 | |
| 10374 | const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len); |
| 10375 | @memset(case_srcs, .unneeded); |
| 10376 | |
| 10377 | break :capture_ty sema.resolvePeerTypes(block, .unneeded, dummy_captures, .{ .override = case_srcs }) catch |err| switch (err) { |
| 10378 | error.NeededSourceLocation => { |
| 10379 | // This must be a multi-prong so this must be a `multi_capture` src |
| 10380 | const multi_idx = raw_capture_src.multi_capture; |
| 10381 | const src_decl_ptr = sema.mod.declPtr(block.src_decl); |
| 10382 | for (case_srcs, 0..) |*case_src, i| { |
| 10383 | const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(u32, i) } }; |
| 10384 | case_src.* = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none); |
| 10385 | } |
| 10386 | const capture_src = raw_capture_src.resolve(mod, src_decl_ptr, switch_node_offset, .none); |
| 10387 | _ = sema.resolvePeerTypes(block, capture_src, dummy_captures, .{ .override = case_srcs }) catch |err1| switch (err1) { |
| 10388 | error.AnalysisFail => { |
| 10389 | const msg = sema.err orelse return error.AnalysisFail; |
| 10390 | try sema.reparentOwnedErrorMsg(block, capture_src, msg, "capture group with incompatible types", .{}); |
| 10391 | return error.AnalysisFail; |
| 10392 | }, |
| 10393 | else => |e| return e, |
| 10394 | }; |
| 10395 | unreachable; |
| 10396 | }, |
| 10397 | else => |e| return e, |
| 10220 | 10398 | }; |
| 10221 | | return sema.failWithOwnedErrorMsg(msg); |
| 10222 | | } |
| 10223 | | } |
| 10399 | }; |
| 10224 | 10400 | |
| 10225 | | if (is_ref) { |
| 10226 | | const field_ty_ptr = try Type.ptr(sema.arena, mod, .{ |
| 10227 | | .pointee_type = first_field.ty, |
| 10228 | | .@"addrspace" = .generic, |
| 10229 | | .mutable = operand_ptr_ty.ptrIsMutable(mod), |
| 10230 | | }); |
| 10401 | // By-reference captures have some further restrictions which make them easier to emit |
| 10402 | if (capture_byref) { |
| 10403 | const operand_ptr_info = operand_ptr_ty.ptrInfo(mod); |
| 10404 | const capture_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 10405 | .pointee_type = capture_ty, |
| 10406 | .@"addrspace" = operand_ptr_info.@"addrspace", |
| 10407 | .mutable = operand_ptr_info.mutable, |
| 10408 | .@"volatile" = operand_ptr_info.@"volatile", |
| 10409 | // TODO: alignment! |
| 10410 | }); |
| 10231 | 10411 | |
| 10232 | | if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| { |
| 10233 | | return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{ |
| 10234 | | .ty = field_ty_ptr.toIntern(), |
| 10235 | | .addr = .{ .field = .{ |
| 10236 | | .base = op_ptr_val.toIntern(), |
| 10237 | | .index = first_field_index, |
| 10238 | | } }, |
| 10239 | | } })).toValue()); |
| 10412 | // By-ref captures of hetereogeneous types are only allowed if each field |
| 10413 | // pointer type is in-memory coercible to the capture pointer type. |
| 10414 | if (!same_types) { |
| 10415 | for (field_tys, 0..) |field_ty, i| { |
| 10416 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 10417 | .pointee_type = field_ty, |
| 10418 | .@"addrspace" = operand_ptr_info.@"addrspace", |
| 10419 | .mutable = operand_ptr_info.mutable, |
| 10420 | .@"volatile" = operand_ptr_info.@"volatile", |
| 10421 | // TODO: alignment! |
| 10422 | }); |
| 10423 | if (.ok != try sema.coerceInMemoryAllowed(block, capture_ptr_ty, field_ptr_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) { |
| 10424 | const multi_idx = raw_capture_src.multi_capture; |
| 10425 | const src_decl_ptr = sema.mod.declPtr(block.src_decl); |
| 10426 | const capture_src = raw_capture_src.resolve(mod, src_decl_ptr, switch_node_offset, .none); |
| 10427 | const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(u32, i) } }; |
| 10428 | const case_src = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none); |
| 10429 | const msg = msg: { |
| 10430 | const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{}); |
| 10431 | errdefer msg.destroy(sema.gpa); |
| 10432 | try sema.errNote(block, case_src, msg, "pointer type child '{}' cannot cast into resolved pointer type child '{}'", .{ |
| 10433 | field_ty.fmt(sema.mod), |
| 10434 | capture_ty.fmt(sema.mod), |
| 10435 | }); |
| 10436 | try sema.errNote(block, capture_src, msg, "this coercion is only possible when capturing by value", .{}); |
| 10437 | break :msg msg; |
| 10438 | }; |
| 10439 | return sema.failWithOwnedErrorMsg(msg); |
| 10440 | } |
| 10441 | } |
| 10442 | } |
| 10443 | |
| 10444 | if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |op_ptr_val| { |
| 10445 | if (op_ptr_val.isUndef(mod)) return sema.addConstUndef(capture_ptr_ty); |
| 10446 | return sema.addConstant( |
| 10447 | capture_ptr_ty, |
| 10448 | (try mod.intern(.{ .ptr = .{ |
| 10449 | .ty = capture_ptr_ty.toIntern(), |
| 10450 | .addr = .{ .field = .{ |
| 10451 | .base = op_ptr_val.toIntern(), |
| 10452 | .index = first_field_index, |
| 10453 | } }, |
| 10454 | } })).toValue(), |
| 10455 | ); |
| 10456 | } |
| 10457 | |
| 10458 | try sema.requireRuntimeBlock(block, operand_src, null); |
| 10459 | return block.addStructFieldPtr(spa.operand_ptr, first_field_index, capture_ptr_ty); |
| 10460 | } |
| 10461 | |
| 10462 | if (try sema.resolveDefinedValue(block, operand_src, spa.operand)) |operand_val| { |
| 10463 | if (operand_val.isUndef(mod)) return sema.addConstUndef(capture_ty); |
| 10464 | const union_val = mod.intern_pool.indexToKey(operand_val.toIntern()).un; |
| 10465 | if (union_val.tag.toValue().isUndef(mod)) return sema.addConstUndef(capture_ty); |
| 10466 | const active_field_idx = @intCast(u32, operand_ty.unionTagFieldIndex(union_val.tag.toValue(), sema.mod).?); |
| 10467 | const field_ty = union_obj.fields.values()[active_field_idx].ty; |
| 10468 | const uncoerced = try sema.addConstant(field_ty, union_val.val.toValue()); |
| 10469 | return sema.coerce(block, capture_ty, uncoerced, operand_src); |
| 10240 | 10470 | } |
| 10471 | |
| 10241 | 10472 | try sema.requireRuntimeBlock(block, operand_src, null); |
| 10242 | | return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr); |
| 10243 | | } |
| 10244 | 10473 | |
| 10245 | | if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| { |
| 10246 | | return sema.addConstant( |
| 10247 | | first_field.ty, |
| 10248 | | mod.intern_pool.indexToKey(operand_val.toIntern()).un.val.toValue(), |
| 10249 | | ); |
| 10250 | | } |
| 10251 | | try sema.requireRuntimeBlock(block, operand_src, null); |
| 10252 | | return block.addStructFieldVal(operand, first_field_index, first_field.ty); |
| 10253 | | }, |
| 10254 | | .ErrorSet => { |
| 10255 | | if (is_multi) { |
| 10256 | | var names: Module.Fn.InferredErrorSet.NameMap = .{}; |
| 10257 | | try names.ensureUnusedCapacity(sema.arena, items.len); |
| 10258 | | for (items) |item| { |
| 10259 | | const item_ref = try sema.resolveInst(item); |
| 10260 | | // Previous switch validation ensured this will succeed |
| 10261 | | const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable; |
| 10262 | | names.putAssumeCapacityNoClobber(item_val.getErrorName(mod).unwrap().?, {}); |
| 10474 | if (same_types) { |
| 10475 | return block.addStructFieldVal(spa.operand, first_field_index, capture_ty); |
| 10263 | 10476 | } |
| 10264 | | const else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); |
| 10265 | 10477 | |
| 10266 | | return sema.bitCast(block, else_error_ty, operand, operand_src, null); |
| 10267 | | } else { |
| 10268 | | const item_ref = try sema.resolveInst(items[0]); |
| 10269 | | // Previous switch validation ensured this will succeed |
| 10270 | | const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable; |
| 10478 | // We may have to emit a switch block which coerces the operand to the capture type. |
| 10479 | // If we can, try to avoid that using in-memory coercions. |
| 10480 | const first_non_imc = in_mem: { |
| 10481 | for (field_tys, 0..) |field_ty, i| { |
| 10482 | if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) { |
| 10483 | break :in_mem i; |
| 10484 | } |
| 10485 | } |
| 10486 | // All fields are in-memory coercible to the resolved type! |
| 10487 | // Just take the first field and bitcast the result. |
| 10488 | const uncoerced = try block.addStructFieldVal(spa.operand, first_field_index, first_field.ty); |
| 10489 | return block.addBitCast(capture_ty, uncoerced); |
| 10490 | }; |
| 10271 | 10491 | |
| 10272 | | const item_ty = try mod.singleErrorSetType(item_val.getErrorName(mod).unwrap().?); |
| 10273 | | return sema.bitCast(block, item_ty, operand, operand_src, null); |
| 10274 | | } |
| 10275 | | }, |
| 10276 | | else => { |
| 10277 | | // In this case the capture value is just the passed-through value of the |
| 10278 | | // switch condition. |
| 10279 | | if (is_ref) { |
| 10280 | | return operand_ptr; |
| 10281 | | } else { |
| 10282 | | return operand; |
| 10283 | | } |
| 10284 | | }, |
| 10285 | | } |
| 10286 | | } |
| 10492 | // By-val capture with heterogeneous types which are not all in-memory coercible to |
| 10493 | // the resolved capture type. We finally have to fall back to the ugly method. |
| 10287 | 10494 | |
| 10288 | | fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 10289 | | const mod = sema.mod; |
| 10290 | | const zir_datas = sema.code.instructions.items(.data); |
| 10291 | | const inst_data = zir_datas[inst].un_tok; |
| 10292 | | const src = inst_data.src(); |
| 10495 | // However, let's first track which operands are in-memory coercible. There may well |
| 10496 | // be several, and we can squash all of these cases into the same switch prong using |
| 10497 | // a simple bitcast. We'll make this the 'else' prong. |
| 10293 | 10498 | |
| 10294 | | const switch_tag = sema.code.instructions.items(.tag)[Zir.refToIndex(inst_data.operand).?]; |
| 10295 | | const is_ref = switch_tag == .switch_cond_ref; |
| 10296 | | const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node; |
| 10297 | | const operand_ptr = try sema.resolveInst(cond_data.operand); |
| 10298 | | const operand_ptr_ty = sema.typeOf(operand_ptr); |
| 10299 | | const operand_ty = if (is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty; |
| 10499 | var in_mem_coercible = try std.DynamicBitSet.initFull(sema.arena, field_tys.len); |
| 10500 | in_mem_coercible.unset(first_non_imc); |
| 10501 | { |
| 10502 | const next = first_non_imc + 1; |
| 10503 | for (field_tys[next..], next..) |field_ty, i| { |
| 10504 | if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) { |
| 10505 | in_mem_coercible.unset(i); |
| 10506 | } |
| 10507 | } |
| 10508 | } |
| 10300 | 10509 | |
| 10301 | | if (operand_ty.zigTypeTag(mod) != .Union) { |
| 10302 | | const msg = msg: { |
| 10303 | | const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{ |
| 10304 | | operand_ty.fmt(mod), |
| 10305 | | }); |
| 10306 | | errdefer msg.destroy(sema.gpa); |
| 10307 | | try sema.addDeclaredHereNote(msg, operand_ty); |
| 10308 | | break :msg msg; |
| 10309 | | }; |
| 10310 | | return sema.failWithOwnedErrorMsg(msg); |
| 10311 | | } |
| 10510 | const capture_block_inst = try block.addInstAsIndex(.{ |
| 10511 | .tag = .block, |
| 10512 | .data = .{ |
| 10513 | .ty_pl = .{ |
| 10514 | .ty = try sema.addType(capture_ty), |
| 10515 | .payload = undefined, // updated below |
| 10516 | }, |
| 10517 | }, |
| 10518 | }); |
| 10312 | 10519 | |
| 10313 | | return block.inline_case_capture; |
| 10314 | | } |
| 10520 | const prong_count = field_tys.len - in_mem_coercible.count(); |
| 10521 | |
| 10522 | const estimated_extra = prong_count * 6; // 2 for Case, 1 item, probably 3 insts |
| 10523 | var cases_extra = try std.ArrayList(u32).initCapacity(sema.gpa, estimated_extra); |
| 10524 | defer cases_extra.deinit(); |
| 10525 | |
| 10526 | { |
| 10527 | // Non-bitcast cases |
| 10528 | var it = in_mem_coercible.iterator(.{ .kind = .unset }); |
| 10529 | while (it.next()) |idx| { |
| 10530 | var coerce_block = block.makeSubBlock(); |
| 10531 | defer coerce_block.instructions.deinit(sema.gpa); |
| 10532 | |
| 10533 | const uncoerced = try coerce_block.addStructFieldVal(spa.operand, @intCast(u32, idx), field_tys[idx]); |
| 10534 | const coerced = sema.coerce(&coerce_block, capture_ty, uncoerced, .unneeded) catch |err| switch (err) { |
| 10535 | error.NeededSourceLocation => { |
| 10536 | const multi_idx = raw_capture_src.multi_capture; |
| 10537 | const src_decl_ptr = sema.mod.declPtr(block.src_decl); |
| 10538 | const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(u32, idx) } }; |
| 10539 | const case_src = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none); |
| 10540 | _ = try sema.coerce(&coerce_block, capture_ty, uncoerced, case_src); |
| 10541 | unreachable; |
| 10542 | }, |
| 10543 | else => |e| return e, |
| 10544 | }; |
| 10545 | _ = try coerce_block.addBr(capture_block_inst, coerced); |
| 10546 | |
| 10547 | try cases_extra.ensureUnusedCapacity(3 + coerce_block.instructions.items.len); |
| 10548 | cases_extra.appendAssumeCapacity(1); // items_len |
| 10549 | cases_extra.appendAssumeCapacity(@intCast(u32, coerce_block.instructions.items.len)); // body_len |
| 10550 | cases_extra.appendAssumeCapacity(@enumToInt(case_vals[idx])); // item |
| 10551 | cases_extra.appendSliceAssumeCapacity(coerce_block.instructions.items); // body |
| 10552 | } |
| 10553 | } |
| 10554 | const else_body_len = len: { |
| 10555 | // 'else' prong uses a bitcast |
| 10556 | var coerce_block = block.makeSubBlock(); |
| 10557 | defer coerce_block.instructions.deinit(sema.gpa); |
| 10558 | |
| 10559 | const first_imc = in_mem_coercible.findFirstSet().?; |
| 10560 | const uncoerced = try coerce_block.addStructFieldVal(spa.operand, @intCast(u32, first_imc), field_tys[first_imc]); |
| 10561 | const coerced = try coerce_block.addBitCast(capture_ty, uncoerced); |
| 10562 | _ = try coerce_block.addBr(capture_block_inst, coerced); |
| 10563 | |
| 10564 | try cases_extra.appendSlice(coerce_block.instructions.items); |
| 10565 | break :len coerce_block.instructions.items.len; |
| 10566 | }; |
| 10567 | |
| 10568 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.SwitchBr).Struct.fields.len + |
| 10569 | cases_extra.items.len + |
| 10570 | @typeInfo(Air.Block).Struct.fields.len + |
| 10571 | 1); |
| 10572 | |
| 10573 | const switch_br_inst = @intCast(u32, sema.air_instructions.len); |
| 10574 | try sema.air_instructions.append(sema.gpa, .{ |
| 10575 | .tag = .switch_br, |
| 10576 | .data = .{ .pl_op = .{ |
| 10577 | .operand = spa.cond, |
| 10578 | .payload = sema.addExtraAssumeCapacity(Air.SwitchBr{ |
| 10579 | .cases_len = @intCast(u32, prong_count), |
| 10580 | .else_body_len = @intCast(u32, else_body_len), |
| 10581 | }), |
| 10582 | } }, |
| 10583 | }); |
| 10584 | sema.air_extra.appendSliceAssumeCapacity(cases_extra.items); |
| 10585 | |
| 10586 | // Set up block body |
| 10587 | sema.air_instructions.items(.data)[capture_block_inst].ty_pl.payload = sema.addExtraAssumeCapacity(Air.Block{ |
| 10588 | .body_len = 1, |
| 10589 | }); |
| 10590 | sema.air_extra.appendAssumeCapacity(switch_br_inst); |
| 10591 | |
| 10592 | return Air.indexToRef(capture_block_inst); |
| 10593 | }, |
| 10594 | .ErrorSet => { |
| 10595 | if (capture_byref) { |
| 10596 | const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none); |
| 10597 | return sema.fail( |
| 10598 | block, |
| 10599 | capture_src, |
| 10600 | "error set cannot be captured by reference", |
| 10601 | .{}, |
| 10602 | ); |
| 10603 | } |
| 10604 | |
| 10605 | if (case_vals.len == 1) { |
| 10606 | const item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable; |
| 10607 | const item_ty = try mod.singleErrorSetType(item_val.getErrorName(mod).unwrap().?); |
| 10608 | return sema.bitCast(block, item_ty, spa.operand, operand_src, null); |
| 10609 | } |
| 10610 | |
| 10611 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; |
| 10612 | try names.ensureUnusedCapacity(sema.arena, case_vals.len); |
| 10613 | for (case_vals) |err| { |
| 10614 | const err_val = sema.resolveConstValue(block, .unneeded, err, "") catch unreachable; |
| 10615 | names.putAssumeCapacityNoClobber(err_val.getErrorName(mod).unwrap().?, {}); |
| 10616 | } |
| 10617 | const error_ty = try mod.errorSetFromUnsortedNames(names.keys()); |
| 10618 | return sema.bitCast(block, error_ty, spa.operand, operand_src, null); |
| 10619 | }, |
| 10620 | else => { |
| 10621 | // In this case the capture value is just the passed-through value |
| 10622 | // of the switch condition. |
| 10623 | if (capture_byref) { |
| 10624 | return spa.operand_ptr; |
| 10625 | } else { |
| 10626 | return spa.operand; |
| 10627 | } |
| 10628 | }, |
| 10629 | } |
| 10630 | } |
| 10631 | }; |
| 10315 | 10632 | |
| 10316 | | fn zirSwitchCond( |
| 10633 | fn switchCond( |
| 10317 | 10634 | sema: *Sema, |
| 10318 | 10635 | block: *Block, |
| 10319 | | inst: Zir.Inst.Index, |
| 10320 | | is_ref: bool, |
| 10636 | src: LazySrcLoc, |
| 10637 | operand: Air.Inst.Ref, |
| 10321 | 10638 | ) CompileError!Air.Inst.Ref { |
| 10322 | 10639 | const mod = sema.mod; |
| 10323 | | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 10324 | | const src = inst_data.src(); |
| 10325 | | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; |
| 10326 | | const operand_ptr = try sema.resolveInst(inst_data.operand); |
| 10327 | | const operand = if (is_ref) |
| 10328 | | try sema.analyzeLoad(block, src, operand_ptr, operand_src) |
| 10329 | | else |
| 10330 | | operand_ptr; |
| 10331 | 10640 | const operand_ty = sema.typeOf(operand); |
| 10332 | | |
| 10333 | 10641 | switch (operand_ty.zigTypeTag(mod)) { |
| 10334 | 10642 | .Type, |
| 10335 | 10643 | .Void, |
| ... | ... | @@ -10386,7 +10694,7 @@ fn zirSwitchCond( |
| 10386 | 10694 | |
| 10387 | 10695 | const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc); |
| 10388 | 10696 | |
| 10389 | | fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 10697 | fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_ref: bool) CompileError!Air.Inst.Ref { |
| 10390 | 10698 | const tracy = trace(@src()); |
| 10391 | 10699 | defer tracy.end(); |
| 10392 | 10700 | |
| ... | ... | @@ -10400,10 +10708,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10400 | 10708 | const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset }; |
| 10401 | 10709 | const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); |
| 10402 | 10710 | |
| 10403 | | const operand = try sema.resolveInst(extra.data.operand); |
| 10404 | | // AstGen guarantees that the instruction immediately following |
| 10405 | | // switch_cond(_ref) is a dbg_stmt |
| 10406 | | const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1; |
| 10711 | const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: { |
| 10712 | const maybe_ptr = try sema.resolveInst(extra.data.operand); |
| 10713 | if (operand_is_ref) { |
| 10714 | const val = try sema.analyzeLoad(block, src, maybe_ptr, operand_src); |
| 10715 | break :blk .{ .val = val, .ptr = maybe_ptr }; |
| 10716 | } else { |
| 10717 | break :blk .{ .val = maybe_ptr, .ptr = undefined }; |
| 10718 | } |
| 10719 | }; |
| 10720 | |
| 10721 | const operand = try sema.switchCond(block, operand_src, raw_operand.val); |
| 10722 | |
| 10723 | // AstGen guarantees that the instruction immediately preceding |
| 10724 | // switch_block(_ref) is a dbg_stmt |
| 10725 | const cond_dbg_node_index = inst - 1; |
| 10407 | 10726 | |
| 10408 | 10727 | var header_extra_index: usize = extra.end; |
| 10409 | 10728 | |
| ... | ... | @@ -10414,28 +10733,50 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10414 | 10733 | break :blk multi_cases_len; |
| 10415 | 10734 | } else 0; |
| 10416 | 10735 | |
| 10736 | const tag_capture_inst: Zir.Inst.Index = if (extra.data.bits.any_has_tag_capture) blk: { |
| 10737 | const tag_capture_inst = sema.code.extra[header_extra_index]; |
| 10738 | header_extra_index += 1; |
| 10739 | // SwitchProngAnalysis wants inst_map to have space for the tag capture. |
| 10740 | // Note that the normal capture is referred to via the switch block |
| 10741 | // index, which there is already necessarily space for. |
| 10742 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{tag_capture_inst}); |
| 10743 | break :blk tag_capture_inst; |
| 10744 | } else undefined; |
| 10745 | |
| 10746 | var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len); |
| 10747 | defer case_vals.deinit(gpa); |
| 10748 | |
| 10749 | const Special = struct { |
| 10750 | body: []const Zir.Inst.Index, |
| 10751 | end: usize, |
| 10752 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, |
| 10753 | is_inline: bool, |
| 10754 | has_tag_capture: bool, |
| 10755 | }; |
| 10756 | |
| 10417 | 10757 | const special_prong = extra.data.bits.specialProng(); |
| 10418 | | const special: struct { body: []const Zir.Inst.Index, end: usize, is_inline: bool } = switch (special_prong) { |
| 10419 | | .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false }, |
| 10758 | const special: Special = switch (special_prong) { |
| 10759 | .none => .{ |
| 10760 | .body = &.{}, |
| 10761 | .end = header_extra_index, |
| 10762 | .capture = .none, |
| 10763 | .is_inline = false, |
| 10764 | .has_tag_capture = false, |
| 10765 | }, |
| 10420 | 10766 | .under, .@"else" => blk: { |
| 10421 | | const body_len = @truncate(u31, sema.code.extra[header_extra_index]); |
| 10767 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[header_extra_index]); |
| 10422 | 10768 | const extra_body_start = header_extra_index + 1; |
| 10423 | 10769 | break :blk .{ |
| 10424 | | .body = sema.code.extra[extra_body_start..][0..body_len], |
| 10425 | | .end = extra_body_start + body_len, |
| 10426 | | .is_inline = sema.code.extra[header_extra_index] >> 31 != 0, |
| 10770 | .body = sema.code.extra[extra_body_start..][0..info.body_len], |
| 10771 | .end = extra_body_start + info.body_len, |
| 10772 | .capture = info.capture, |
| 10773 | .is_inline = info.is_inline, |
| 10774 | .has_tag_capture = info.has_tag_capture, |
| 10427 | 10775 | }; |
| 10428 | 10776 | }, |
| 10429 | 10777 | }; |
| 10430 | 10778 | |
| 10431 | | const maybe_union_ty = blk: { |
| 10432 | | const zir_tags = sema.code.instructions.items(.tag); |
| 10433 | | const zir_data = sema.code.instructions.items(.data); |
| 10434 | | const cond_index = Zir.refToIndex(extra.data.operand).?; |
| 10435 | | const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable; |
| 10436 | | const target_ty = sema.typeOf(raw_operand); |
| 10437 | | break :blk if (zir_tags[cond_index] == .switch_cond_ref) target_ty.childType(mod) else target_ty; |
| 10438 | | }; |
| 10779 | const maybe_union_ty = sema.typeOf(raw_operand.val); |
| 10439 | 10780 | const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union; |
| 10440 | 10781 | |
| 10441 | 10782 | // Duplicate checking variables later also used for `inline else`. |
| ... | ... | @@ -10495,18 +10836,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10495 | 10836 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10496 | 10837 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10497 | 10838 | extra_index += 1; |
| 10498 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10499 | | extra_index += 1; |
| 10500 | | extra_index += body_len; |
| 10839 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10840 | extra_index += 1 + info.body_len; |
| 10501 | 10841 | |
| 10502 | | try sema.validateSwitchItemEnum( |
| 10842 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum( |
| 10503 | 10843 | block, |
| 10504 | 10844 | seen_enum_fields, |
| 10505 | 10845 | &range_set, |
| 10506 | 10846 | item_ref, |
| 10847 | operand_ty, |
| 10507 | 10848 | src_node_offset, |
| 10508 | 10849 | .{ .scalar = scalar_i }, |
| 10509 | | ); |
| 10850 | )); |
| 10510 | 10851 | } |
| 10511 | 10852 | } |
| 10512 | 10853 | { |
| ... | ... | @@ -10516,20 +10857,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10516 | 10857 | extra_index += 1; |
| 10517 | 10858 | const ranges_len = sema.code.extra[extra_index]; |
| 10518 | 10859 | extra_index += 1; |
| 10519 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10860 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10520 | 10861 | extra_index += 1; |
| 10521 | 10862 | const items = sema.code.refSlice(extra_index, items_len); |
| 10522 | | extra_index += items_len + body_len; |
| 10863 | extra_index += items_len + info.body_len; |
| 10523 | 10864 | |
| 10865 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10524 | 10866 | for (items, 0..) |item_ref, item_i| { |
| 10525 | | try sema.validateSwitchItemEnum( |
| 10867 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum( |
| 10526 | 10868 | block, |
| 10527 | 10869 | seen_enum_fields, |
| 10528 | 10870 | &range_set, |
| 10529 | 10871 | item_ref, |
| 10872 | operand_ty, |
| 10530 | 10873 | src_node_offset, |
| 10531 | 10874 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10532 | | ); |
| 10875 | )); |
| 10533 | 10876 | } |
| 10534 | 10877 | |
| 10535 | 10878 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); |
| ... | ... | @@ -10592,17 +10935,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10592 | 10935 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10593 | 10936 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10594 | 10937 | extra_index += 1; |
| 10595 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10596 | | extra_index += 1; |
| 10597 | | extra_index += body_len; |
| 10938 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10939 | extra_index += 1 + info.body_len; |
| 10598 | 10940 | |
| 10599 | | try sema.validateSwitchItemError( |
| 10941 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 10600 | 10942 | block, |
| 10601 | 10943 | &seen_errors, |
| 10602 | 10944 | item_ref, |
| 10945 | operand_ty, |
| 10603 | 10946 | src_node_offset, |
| 10604 | 10947 | .{ .scalar = scalar_i }, |
| 10605 | | ); |
| 10948 | )); |
| 10606 | 10949 | } |
| 10607 | 10950 | } |
| 10608 | 10951 | { |
| ... | ... | @@ -10612,19 +10955,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10612 | 10955 | extra_index += 1; |
| 10613 | 10956 | const ranges_len = sema.code.extra[extra_index]; |
| 10614 | 10957 | extra_index += 1; |
| 10615 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10958 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10616 | 10959 | extra_index += 1; |
| 10617 | 10960 | const items = sema.code.refSlice(extra_index, items_len); |
| 10618 | | extra_index += items_len + body_len; |
| 10961 | extra_index += items_len + info.body_len; |
| 10619 | 10962 | |
| 10963 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10620 | 10964 | for (items, 0..) |item_ref, item_i| { |
| 10621 | | try sema.validateSwitchItemError( |
| 10965 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 10622 | 10966 | block, |
| 10623 | 10967 | &seen_errors, |
| 10624 | 10968 | item_ref, |
| 10969 | operand_ty, |
| 10625 | 10970 | src_node_offset, |
| 10626 | 10971 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10627 | | ); |
| 10972 | )); |
| 10628 | 10973 | } |
| 10629 | 10974 | |
| 10630 | 10975 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); |
| ... | ... | @@ -10687,7 +11032,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10687 | 11032 | .dbg_block_end, |
| 10688 | 11033 | .dbg_stmt, |
| 10689 | 11034 | .dbg_var_val, |
| 10690 | | .switch_capture, |
| 10691 | 11035 | .ret_type, |
| 10692 | 11036 | .as_node, |
| 10693 | 11037 | .ret_node, |
| ... | ... | @@ -10732,17 +11076,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10732 | 11076 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10733 | 11077 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10734 | 11078 | extra_index += 1; |
| 10735 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10736 | | extra_index += 1; |
| 10737 | | extra_index += body_len; |
| 11079 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11080 | extra_index += 1 + info.body_len; |
| 10738 | 11081 | |
| 10739 | | try sema.validateSwitchItem( |
| 11082 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt( |
| 10740 | 11083 | block, |
| 10741 | 11084 | &range_set, |
| 10742 | 11085 | item_ref, |
| 11086 | operand_ty, |
| 10743 | 11087 | src_node_offset, |
| 10744 | 11088 | .{ .scalar = scalar_i }, |
| 10745 | | ); |
| 11089 | )); |
| 10746 | 11090 | } |
| 10747 | 11091 | } |
| 10748 | 11092 | { |
| ... | ... | @@ -10752,21 +11096,24 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10752 | 11096 | extra_index += 1; |
| 10753 | 11097 | const ranges_len = sema.code.extra[extra_index]; |
| 10754 | 11098 | extra_index += 1; |
| 10755 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11099 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10756 | 11100 | extra_index += 1; |
| 10757 | 11101 | const items = sema.code.refSlice(extra_index, items_len); |
| 10758 | 11102 | extra_index += items_len; |
| 10759 | 11103 | |
| 11104 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10760 | 11105 | for (items, 0..) |item_ref, item_i| { |
| 10761 | | try sema.validateSwitchItem( |
| 11106 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt( |
| 10762 | 11107 | block, |
| 10763 | 11108 | &range_set, |
| 10764 | 11109 | item_ref, |
| 11110 | operand_ty, |
| 10765 | 11111 | src_node_offset, |
| 10766 | 11112 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10767 | | ); |
| 11113 | )); |
| 10768 | 11114 | } |
| 10769 | 11115 | |
| 11116 | try case_vals.ensureUnusedCapacity(gpa, 2 * ranges_len); |
| 10770 | 11117 | var range_i: u32 = 0; |
| 10771 | 11118 | while (range_i < ranges_len) : (range_i += 1) { |
| 10772 | 11119 | const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| ... | ... | @@ -10774,17 +11121,20 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10774 | 11121 | const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10775 | 11122 | extra_index += 1; |
| 10776 | 11123 | |
| 10777 | | try sema.validateSwitchRange( |
| 11124 | const vals = try sema.validateSwitchRange( |
| 10778 | 11125 | block, |
| 10779 | 11126 | &range_set, |
| 10780 | 11127 | item_first, |
| 10781 | 11128 | item_last, |
| 11129 | operand_ty, |
| 10782 | 11130 | src_node_offset, |
| 10783 | 11131 | .{ .range = .{ .prong = multi_i, .item = range_i } }, |
| 10784 | 11132 | ); |
| 11133 | case_vals.appendAssumeCapacity(vals[0]); |
| 11134 | case_vals.appendAssumeCapacity(vals[1]); |
| 10785 | 11135 | } |
| 10786 | 11136 | |
| 10787 | | extra_index += body_len; |
| 11137 | extra_index += info.body_len; |
| 10788 | 11138 | } |
| 10789 | 11139 | } |
| 10790 | 11140 | |
| ... | ... | @@ -10821,18 +11171,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10821 | 11171 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10822 | 11172 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10823 | 11173 | extra_index += 1; |
| 10824 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 10825 | | extra_index += 1; |
| 10826 | | extra_index += body_len; |
| 11174 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11175 | extra_index += 1 + info.body_len; |
| 10827 | 11176 | |
| 10828 | | try sema.validateSwitchItemBool( |
| 11177 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool( |
| 10829 | 11178 | block, |
| 10830 | 11179 | &true_count, |
| 10831 | 11180 | &false_count, |
| 10832 | 11181 | item_ref, |
| 10833 | 11182 | src_node_offset, |
| 10834 | 11183 | .{ .scalar = scalar_i }, |
| 10835 | | ); |
| 11184 | )); |
| 10836 | 11185 | } |
| 10837 | 11186 | } |
| 10838 | 11187 | { |
| ... | ... | @@ -10842,20 +11191,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10842 | 11191 | extra_index += 1; |
| 10843 | 11192 | const ranges_len = sema.code.extra[extra_index]; |
| 10844 | 11193 | extra_index += 1; |
| 10845 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11194 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10846 | 11195 | extra_index += 1; |
| 10847 | 11196 | const items = sema.code.refSlice(extra_index, items_len); |
| 10848 | | extra_index += items_len + body_len; |
| 11197 | extra_index += items_len + info.body_len; |
| 10849 | 11198 | |
| 11199 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10850 | 11200 | for (items, 0..) |item_ref, item_i| { |
| 10851 | | try sema.validateSwitchItemBool( |
| 11201 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool( |
| 10852 | 11202 | block, |
| 10853 | 11203 | &true_count, |
| 10854 | 11204 | &false_count, |
| 10855 | 11205 | item_ref, |
| 10856 | 11206 | src_node_offset, |
| 10857 | 11207 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10858 | | ); |
| 11208 | )); |
| 10859 | 11209 | } |
| 10860 | 11210 | |
| 10861 | 11211 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); |
| ... | ... | @@ -10903,17 +11253,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10903 | 11253 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10904 | 11254 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10905 | 11255 | extra_index += 1; |
| 10906 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11256 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10907 | 11257 | extra_index += 1; |
| 10908 | | extra_index += body_len; |
| 11258 | extra_index += info.body_len; |
| 10909 | 11259 | |
| 10910 | | try sema.validateSwitchItemSparse( |
| 11260 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse( |
| 10911 | 11261 | block, |
| 10912 | 11262 | &seen_values, |
| 10913 | 11263 | item_ref, |
| 11264 | operand_ty, |
| 10914 | 11265 | src_node_offset, |
| 10915 | 11266 | .{ .scalar = scalar_i }, |
| 10916 | | ); |
| 11267 | )); |
| 10917 | 11268 | } |
| 10918 | 11269 | } |
| 10919 | 11270 | { |
| ... | ... | @@ -10923,19 +11274,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10923 | 11274 | extra_index += 1; |
| 10924 | 11275 | const ranges_len = sema.code.extra[extra_index]; |
| 10925 | 11276 | extra_index += 1; |
| 10926 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11277 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10927 | 11278 | extra_index += 1; |
| 10928 | 11279 | const items = sema.code.refSlice(extra_index, items_len); |
| 10929 | | extra_index += items_len + body_len; |
| 11280 | extra_index += items_len + info.body_len; |
| 10930 | 11281 | |
| 11282 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10931 | 11283 | for (items, 0..) |item_ref, item_i| { |
| 10932 | | try sema.validateSwitchItemSparse( |
| 11284 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse( |
| 10933 | 11285 | block, |
| 10934 | 11286 | &seen_values, |
| 10935 | 11287 | item_ref, |
| 11288 | operand_ty, |
| 10936 | 11289 | src_node_offset, |
| 10937 | 11290 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10938 | | ); |
| 11291 | )); |
| 10939 | 11292 | } |
| 10940 | 11293 | |
| 10941 | 11294 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); |
| ... | ... | @@ -10961,6 +11314,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10961 | 11314 | }), |
| 10962 | 11315 | } |
| 10963 | 11316 | |
| 11317 | const spa: SwitchProngAnalysis = .{ |
| 11318 | .sema = sema, |
| 11319 | .parent_block = block, |
| 11320 | .operand = raw_operand.val, |
| 11321 | .operand_ptr = raw_operand.ptr, |
| 11322 | .cond = operand, |
| 11323 | .else_error_ty = else_error_ty, |
| 11324 | .switch_block_inst = inst, |
| 11325 | .tag_capture_inst = tag_capture_inst, |
| 11326 | }; |
| 11327 | |
| 10964 | 11328 | const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); |
| 10965 | 11329 | try sema.air_instructions.append(gpa, .{ |
| 10966 | 11330 | .tag = .block, |
| ... | ... | @@ -10988,7 +11352,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10988 | 11352 | .is_comptime = block.is_comptime, |
| 10989 | 11353 | .comptime_reason = block.comptime_reason, |
| 10990 | 11354 | .is_typeof = block.is_typeof, |
| 10991 | | .switch_else_err_ty = else_error_ty, |
| 10992 | 11355 | .c_import_buf = block.c_import_buf, |
| 10993 | 11356 | .runtime_cond = block.runtime_cond, |
| 10994 | 11357 | .runtime_loop = block.runtime_loop, |
| ... | ... | @@ -11005,79 +11368,110 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11005 | 11368 | { |
| 11006 | 11369 | var scalar_i: usize = 0; |
| 11007 | 11370 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 11008 | | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 11009 | 11371 | extra_index += 1; |
| 11010 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11011 | | const is_inline = sema.code.extra[extra_index] >> 31 != 0; |
| 11372 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11012 | 11373 | extra_index += 1; |
| 11013 | | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11014 | | extra_index += body_len; |
| 11015 | | |
| 11016 | | const item = try sema.resolveInst(item_ref); |
| 11017 | | // Validation above ensured these will succeed. |
| 11018 | | const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11019 | | if (resolved_operand_val.eql(item_val, operand_ty, mod)) { |
| 11020 | | if (is_inline) child_block.inline_case_capture = operand; |
| 11374 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11375 | extra_index += info.body_len; |
| 11021 | 11376 | |
| 11377 | const item = case_vals.items[scalar_i]; |
| 11378 | const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11379 | if (operand_val.eql(item_val, operand_ty, sema.mod)) { |
| 11022 | 11380 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| 11023 | | return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); |
| 11381 | return spa.resolveProngComptime( |
| 11382 | &child_block, |
| 11383 | .normal, |
| 11384 | body, |
| 11385 | info.capture, |
| 11386 | .{ .scalar_capture = @intCast(u32, scalar_i) }, |
| 11387 | &.{item}, |
| 11388 | if (info.is_inline) operand else .none, |
| 11389 | info.has_tag_capture, |
| 11390 | merges, |
| 11391 | ); |
| 11024 | 11392 | } |
| 11025 | 11393 | } |
| 11026 | 11394 | } |
| 11027 | 11395 | { |
| 11028 | 11396 | var multi_i: usize = 0; |
| 11397 | var case_val_idx: usize = scalar_cases_len; |
| 11029 | 11398 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 11030 | 11399 | const items_len = sema.code.extra[extra_index]; |
| 11031 | 11400 | extra_index += 1; |
| 11032 | 11401 | const ranges_len = sema.code.extra[extra_index]; |
| 11033 | 11402 | extra_index += 1; |
| 11034 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11035 | | const is_inline = sema.code.extra[extra_index] >> 31 != 0; |
| 11036 | | extra_index += 1; |
| 11037 | | const items = sema.code.refSlice(extra_index, items_len); |
| 11038 | | extra_index += items_len; |
| 11039 | | const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len]; |
| 11403 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11404 | extra_index += 1 + items_len; |
| 11405 | const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..info.body_len]; |
| 11040 | 11406 | |
| 11041 | | for (items) |item_ref| { |
| 11042 | | const item = try sema.resolveInst(item_ref); |
| 11043 | | // Validation above ensured these will succeed. |
| 11044 | | const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11045 | | if (resolved_operand_val.eql(item_val, operand_ty, mod)) { |
| 11046 | | if (is_inline) child_block.inline_case_capture = operand; |
| 11407 | const items = case_vals.items[case_val_idx..][0..items_len]; |
| 11408 | case_val_idx += items_len; |
| 11047 | 11409 | |
| 11410 | for (items) |item| { |
| 11411 | // Validation above ensured these will succeed. |
| 11412 | const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11413 | if (operand_val.eql(item_val, operand_ty, sema.mod)) { |
| 11048 | 11414 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| 11049 | | return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); |
| 11415 | return spa.resolveProngComptime( |
| 11416 | &child_block, |
| 11417 | .normal, |
| 11418 | body, |
| 11419 | info.capture, |
| 11420 | .{ .multi_capture = @intCast(u32, multi_i) }, |
| 11421 | items, |
| 11422 | if (info.is_inline) operand else .none, |
| 11423 | info.has_tag_capture, |
| 11424 | merges, |
| 11425 | ); |
| 11050 | 11426 | } |
| 11051 | 11427 | } |
| 11052 | 11428 | |
| 11053 | 11429 | var range_i: usize = 0; |
| 11054 | 11430 | while (range_i < ranges_len) : (range_i += 1) { |
| 11055 | | const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 11056 | | extra_index += 1; |
| 11057 | | const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 11058 | | extra_index += 1; |
| 11431 | const range_items = case_vals.items[case_val_idx..][0..2]; |
| 11432 | extra_index += 2; |
| 11433 | case_val_idx += 2; |
| 11059 | 11434 | |
| 11060 | 11435 | // Validation above ensured these will succeed. |
| 11061 | | const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable; |
| 11062 | | const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable; |
| 11063 | | if ((try sema.compareAll(resolved_operand_val, .gte, first_tv.val, operand_ty)) and |
| 11064 | | (try sema.compareAll(resolved_operand_val, .lte, last_tv.val, operand_ty))) |
| 11436 | const first_val = sema.resolveConstValue(&child_block, .unneeded, range_items[0], "") catch unreachable; |
| 11437 | const last_val = sema.resolveConstValue(&child_block, .unneeded, range_items[1], "") catch unreachable; |
| 11438 | if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and |
| 11439 | (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty))) |
| 11065 | 11440 | { |
| 11066 | | if (is_inline) child_block.inline_case_capture = operand; |
| 11067 | 11441 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| 11068 | | return sema.resolveBlockBody(block, src, &child_block, body, inst, merges); |
| 11442 | return spa.resolveProngComptime( |
| 11443 | &child_block, |
| 11444 | .normal, |
| 11445 | body, |
| 11446 | info.capture, |
| 11447 | .{ .multi_capture = @intCast(u32, multi_i) }, |
| 11448 | undefined, // case_vals may be undefined for ranges |
| 11449 | if (info.is_inline) operand else .none, |
| 11450 | info.has_tag_capture, |
| 11451 | merges, |
| 11452 | ); |
| 11069 | 11453 | } |
| 11070 | 11454 | } |
| 11071 | 11455 | |
| 11072 | | extra_index += body_len; |
| 11456 | extra_index += info.body_len; |
| 11073 | 11457 | } |
| 11074 | 11458 | } |
| 11075 | 11459 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand); |
| 11076 | | if (special.is_inline) child_block.inline_case_capture = operand; |
| 11077 | 11460 | if (empty_enum) { |
| 11078 | 11461 | return Air.Inst.Ref.void_value; |
| 11079 | 11462 | } |
| 11080 | | return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); |
| 11463 | |
| 11464 | return spa.resolveProngComptime( |
| 11465 | &child_block, |
| 11466 | .special, |
| 11467 | special.body, |
| 11468 | special.capture, |
| 11469 | .special_capture, |
| 11470 | undefined, // case_vals may be undefined for special prongs |
| 11471 | if (special.is_inline) operand else .none, |
| 11472 | special.has_tag_capture, |
| 11473 | merges, |
| 11474 | ); |
| 11081 | 11475 | } |
| 11082 | 11476 | |
| 11083 | 11477 | if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) { |
| ... | ... | @@ -11097,7 +11491,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11097 | 11491 | const ok = try block.addUnOp(.is_named_enum_value, operand); |
| 11098 | 11492 | try sema.addSafetyCheck(block, ok, .corrupt_switch); |
| 11099 | 11493 | } |
| 11100 | | return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); |
| 11494 | |
| 11495 | return spa.resolveProngComptime( |
| 11496 | &child_block, |
| 11497 | .special, |
| 11498 | special.body, |
| 11499 | special.capture, |
| 11500 | .special_capture, |
| 11501 | undefined, // case_vals may be undefined for special prongs |
| 11502 | .none, |
| 11503 | false, |
| 11504 | merges, |
| 11505 | ); |
| 11101 | 11506 | } |
| 11102 | 11507 | |
| 11103 | 11508 | if (child_block.is_comptime) { |
| ... | ... | @@ -11123,23 +11528,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11123 | 11528 | |
| 11124 | 11529 | var scalar_i: usize = 0; |
| 11125 | 11530 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 11126 | | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 11127 | 11531 | extra_index += 1; |
| 11128 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11129 | | const is_inline = sema.code.extra[extra_index] >> 31 != 0; |
| 11532 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11130 | 11533 | extra_index += 1; |
| 11131 | | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11132 | | extra_index += body_len; |
| 11534 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11535 | extra_index += info.body_len; |
| 11133 | 11536 | |
| 11134 | 11537 | var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope); |
| 11135 | 11538 | defer wip_captures.deinit(); |
| 11136 | 11539 | |
| 11137 | 11540 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11138 | 11541 | case_block.wip_capture_scope = wip_captures.scope; |
| 11139 | | case_block.inline_case_capture = .none; |
| 11140 | 11542 | |
| 11141 | | const item = try sema.resolveInst(item_ref); |
| 11142 | | if (is_inline) case_block.inline_case_capture = item; |
| 11543 | const item = case_vals.items[scalar_i]; |
| 11143 | 11544 | // `item` is already guaranteed to be constant known. |
| 11144 | 11545 | |
| 11145 | 11546 | const analyze_body = if (union_originally) blk: { |
| ... | ... | @@ -11151,7 +11552,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11151 | 11552 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { |
| 11152 | 11553 | // nothing to do here |
| 11153 | 11554 | } else if (analyze_body) { |
| 11154 | | try sema.analyzeBodyRuntimeBreak(&case_block, body); |
| 11555 | try spa.analyzeProngRuntime( |
| 11556 | &case_block, |
| 11557 | .normal, |
| 11558 | body, |
| 11559 | info.capture, |
| 11560 | .{ .scalar_capture = @intCast(u32, scalar_i) }, |
| 11561 | &.{item}, |
| 11562 | if (info.is_inline) item else .none, |
| 11563 | info.has_tag_capture, |
| 11564 | ); |
| 11155 | 11565 | } else { |
| 11156 | 11566 | _ = try case_block.addNoOp(.unreach); |
| 11157 | 11567 | } |
| ... | ... | @@ -11173,38 +11583,38 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11173 | 11583 | defer gpa.free(prev_then_body); |
| 11174 | 11584 | |
| 11175 | 11585 | var cases_len = scalar_cases_len; |
| 11586 | var case_val_idx: usize = scalar_cases_len; |
| 11176 | 11587 | var multi_i: u32 = 0; |
| 11177 | 11588 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 11178 | 11589 | const items_len = sema.code.extra[extra_index]; |
| 11179 | 11590 | extra_index += 1; |
| 11180 | 11591 | const ranges_len = sema.code.extra[extra_index]; |
| 11181 | 11592 | extra_index += 1; |
| 11182 | | const body_len = @truncate(u31, sema.code.extra[extra_index]); |
| 11183 | | const is_inline = sema.code.extra[extra_index] >> 31 != 0; |
| 11184 | | extra_index += 1; |
| 11185 | | const items = sema.code.refSlice(extra_index, items_len); |
| 11186 | | extra_index += items_len; |
| 11593 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11594 | extra_index += 1 + items_len; |
| 11595 | |
| 11596 | const items = case_vals.items[case_val_idx..][0..items_len]; |
| 11597 | case_val_idx += items_len; |
| 11187 | 11598 | |
| 11188 | 11599 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11189 | 11600 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 11190 | | case_block.inline_case_capture = .none; |
| 11191 | 11601 | |
| 11192 | 11602 | // Generate all possible cases as scalar prongs. |
| 11193 | | if (is_inline) { |
| 11603 | if (info.is_inline) { |
| 11194 | 11604 | const body_start = extra_index + 2 * ranges_len; |
| 11195 | | const body = sema.code.extra[body_start..][0..body_len]; |
| 11605 | const body = sema.code.extra[body_start..][0..info.body_len]; |
| 11196 | 11606 | var emit_bb = false; |
| 11197 | 11607 | |
| 11198 | 11608 | var range_i: u32 = 0; |
| 11199 | 11609 | while (range_i < ranges_len) : (range_i += 1) { |
| 11200 | | const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 11201 | | extra_index += 1; |
| 11202 | | const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 11203 | | extra_index += 1; |
| 11610 | const range_items = case_vals.items[case_val_idx..][0..2]; |
| 11611 | extra_index += 2; |
| 11612 | case_val_idx += 2; |
| 11613 | |
| 11614 | const item_first_ref = range_items[0]; |
| 11615 | const item_last_ref = range_items[1]; |
| 11204 | 11616 | |
| 11205 | | const item_first_ref = try sema.resolveInst(first_ref); |
| 11206 | 11617 | var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable; |
| 11207 | | const item_last_ref = try sema.resolveInst(last_ref); |
| 11208 | 11618 | const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable; |
| 11209 | 11619 | |
| 11210 | 11620 | while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({ |
| ... | ... | @@ -11217,7 +11627,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11217 | 11627 | cases_len += 1; |
| 11218 | 11628 | |
| 11219 | 11629 | const item_ref = try sema.addConstant(operand_ty, item); |
| 11220 | | case_block.inline_case_capture = item_ref; |
| 11221 | 11630 | |
| 11222 | 11631 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11223 | 11632 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| ... | ... | @@ -11233,22 +11642,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11233 | 11642 | }; |
| 11234 | 11643 | emit_bb = true; |
| 11235 | 11644 | |
| 11236 | | try sema.analyzeBodyRuntimeBreak(&case_block, body); |
| 11645 | try spa.analyzeProngRuntime( |
| 11646 | &case_block, |
| 11647 | .normal, |
| 11648 | body, |
| 11649 | info.capture, |
| 11650 | .{ .multi_capture = multi_i }, |
| 11651 | undefined, // case_vals may be undefined for ranges |
| 11652 | item_ref, |
| 11653 | info.has_tag_capture, |
| 11654 | ); |
| 11237 | 11655 | |
| 11238 | 11656 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11239 | 11657 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11240 | 11658 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 11241 | | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 11659 | cases_extra.appendAssumeCapacity(@enumToInt(item_ref)); |
| 11242 | 11660 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11243 | 11661 | } |
| 11244 | 11662 | } |
| 11245 | 11663 | |
| 11246 | | for (items, 0..) |item_ref, item_i| { |
| 11664 | for (items, 0..) |item, item_i| { |
| 11247 | 11665 | cases_len += 1; |
| 11248 | 11666 | |
| 11249 | | const item = try sema.resolveInst(item_ref); |
| 11250 | | case_block.inline_case_capture = item; |
| 11251 | | |
| 11252 | 11667 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11253 | 11668 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 11254 | 11669 | |
| ... | ... | @@ -11270,7 +11685,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11270 | 11685 | emit_bb = true; |
| 11271 | 11686 | |
| 11272 | 11687 | if (analyze_body) { |
| 11273 | | try sema.analyzeBodyRuntimeBreak(&case_block, body); |
| 11688 | try spa.analyzeProngRuntime( |
| 11689 | &case_block, |
| 11690 | .normal, |
| 11691 | body, |
| 11692 | info.capture, |
| 11693 | .{ .multi_capture = multi_i }, |
| 11694 | &.{item}, |
| 11695 | item, |
| 11696 | info.has_tag_capture, |
| 11697 | ); |
| 11274 | 11698 | } else { |
| 11275 | 11699 | _ = try case_block.addNoOp(.unreach); |
| 11276 | 11700 | } |
| ... | ... | @@ -11278,11 +11702,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11278 | 11702 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11279 | 11703 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11280 | 11704 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 11281 | | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 11705 | cases_extra.appendAssumeCapacity(@enumToInt(item)); |
| 11282 | 11706 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11283 | 11707 | } |
| 11284 | 11708 | |
| 11285 | | extra_index += body_len; |
| 11709 | extra_index += info.body_len; |
| 11286 | 11710 | continue; |
| 11287 | 11711 | } |
| 11288 | 11712 | |
| ... | ... | @@ -11295,8 +11719,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11295 | 11719 | cases_len += 1; |
| 11296 | 11720 | |
| 11297 | 11721 | const analyze_body = if (union_originally) |
| 11298 | | for (items) |item_ref| { |
| 11299 | | const item = try sema.resolveInst(item_ref); |
| 11722 | for (items) |item| { |
| 11300 | 11723 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; |
| 11301 | 11724 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); |
| 11302 | 11725 | if (field_ty.zigTypeTag(mod) != .NoReturn) break true; |
| ... | ... | @@ -11304,12 +11727,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11304 | 11727 | else |
| 11305 | 11728 | true; |
| 11306 | 11729 | |
| 11307 | | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11308 | | extra_index += body_len; |
| 11730 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11731 | extra_index += info.body_len; |
| 11309 | 11732 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { |
| 11310 | 11733 | // nothing to do here |
| 11311 | 11734 | } else if (analyze_body) { |
| 11312 | | try sema.analyzeBodyRuntimeBreak(&case_block, body); |
| 11735 | try spa.analyzeProngRuntime( |
| 11736 | &case_block, |
| 11737 | .normal, |
| 11738 | body, |
| 11739 | info.capture, |
| 11740 | .{ .multi_capture = multi_i }, |
| 11741 | items, |
| 11742 | .none, |
| 11743 | false, |
| 11744 | ); |
| 11313 | 11745 | } else { |
| 11314 | 11746 | _ = try case_block.addNoOp(.unreach); |
| 11315 | 11747 | } |
| ... | ... | @@ -11320,15 +11752,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11320 | 11752 | cases_extra.appendAssumeCapacity(@intCast(u32, items.len)); |
| 11321 | 11753 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 11322 | 11754 | |
| 11323 | | for (items) |item_ref| { |
| 11324 | | const item = try sema.resolveInst(item_ref); |
| 11755 | for (items) |item| { |
| 11325 | 11756 | cases_extra.appendAssumeCapacity(@enumToInt(item)); |
| 11326 | 11757 | } |
| 11327 | 11758 | |
| 11328 | 11759 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11329 | 11760 | } else { |
| 11330 | | for (items) |item_ref| { |
| 11331 | | const item = try sema.resolveInst(item_ref); |
| 11761 | for (items) |item| { |
| 11332 | 11762 | const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item); |
| 11333 | 11763 | if (any_ok != .none) { |
| 11334 | 11764 | any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok); |
| ... | ... | @@ -11339,13 +11769,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11339 | 11769 | |
| 11340 | 11770 | var range_i: usize = 0; |
| 11341 | 11771 | while (range_i < ranges_len) : (range_i += 1) { |
| 11342 | | const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 11343 | | extra_index += 1; |
| 11344 | | const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 11345 | | extra_index += 1; |
| 11772 | const range_items = case_vals.items[case_val_idx..][0..2]; |
| 11773 | extra_index += 2; |
| 11774 | case_val_idx += 2; |
| 11346 | 11775 | |
| 11347 | | const item_first = try sema.resolveInst(first_ref); |
| 11348 | | const item_last = try sema.resolveInst(last_ref); |
| 11776 | const item_first = range_items[0]; |
| 11777 | const item_last = range_items[1]; |
| 11349 | 11778 | |
| 11350 | 11779 | // operand >= first and operand <= last |
| 11351 | 11780 | const range_first_ok = try case_block.addBinOp( |
| ... | ... | @@ -11385,12 +11814,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11385 | 11814 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11386 | 11815 | case_block.wip_capture_scope = wip_captures.scope; |
| 11387 | 11816 | |
| 11388 | | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11389 | | extra_index += body_len; |
| 11817 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11818 | extra_index += info.body_len; |
| 11390 | 11819 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { |
| 11391 | 11820 | // nothing to do here |
| 11392 | 11821 | } else { |
| 11393 | | try sema.analyzeBodyRuntimeBreak(&case_block, body); |
| 11822 | try spa.analyzeProngRuntime( |
| 11823 | &case_block, |
| 11824 | .normal, |
| 11825 | body, |
| 11826 | info.capture, |
| 11827 | .{ .multi_capture = multi_i }, |
| 11828 | items, |
| 11829 | .none, |
| 11830 | false, |
| 11831 | ); |
| 11394 | 11832 | } |
| 11395 | 11833 | |
| 11396 | 11834 | try wip_captures.finalize(); |
| ... | ... | @@ -11435,7 +11873,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11435 | 11873 | |
| 11436 | 11874 | const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i)); |
| 11437 | 11875 | const item_ref = try sema.addConstant(operand_ty, item_val); |
| 11438 | | case_block.inline_case_capture = item_ref; |
| 11439 | 11876 | |
| 11440 | 11877 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11441 | 11878 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| ... | ... | @@ -11449,7 +11886,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11449 | 11886 | emit_bb = true; |
| 11450 | 11887 | |
| 11451 | 11888 | if (analyze_body) { |
| 11452 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 11889 | try spa.analyzeProngRuntime( |
| 11890 | &case_block, |
| 11891 | .special, |
| 11892 | special.body, |
| 11893 | special.capture, |
| 11894 | .special_capture, |
| 11895 | &.{item_ref}, |
| 11896 | item_ref, |
| 11897 | special.has_tag_capture, |
| 11898 | ); |
| 11453 | 11899 | } else { |
| 11454 | 11900 | _ = try case_block.addNoOp(.unreach); |
| 11455 | 11901 | } |
| ... | ... | @@ -11457,7 +11903,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11457 | 11903 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11458 | 11904 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11459 | 11905 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 11460 | | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 11906 | cases_extra.appendAssumeCapacity(@enumToInt(item_ref)); |
| 11461 | 11907 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11462 | 11908 | } |
| 11463 | 11909 | }, |
| ... | ... | @@ -11477,7 +11923,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11477 | 11923 | .name = error_name, |
| 11478 | 11924 | } }); |
| 11479 | 11925 | const item_ref = try sema.addConstant(operand_ty, item_val.toValue()); |
| 11480 | | case_block.inline_case_capture = item_ref; |
| 11481 | 11926 | |
| 11482 | 11927 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11483 | 11928 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| ... | ... | @@ -11485,12 +11930,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11485 | 11930 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11486 | 11931 | emit_bb = true; |
| 11487 | 11932 | |
| 11488 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 11933 | try spa.analyzeProngRuntime( |
| 11934 | &case_block, |
| 11935 | .special, |
| 11936 | special.body, |
| 11937 | special.capture, |
| 11938 | .special_capture, |
| 11939 | &.{item_ref}, |
| 11940 | item_ref, |
| 11941 | special.has_tag_capture, |
| 11942 | ); |
| 11489 | 11943 | |
| 11490 | 11944 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11491 | 11945 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11492 | 11946 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 11493 | | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 11947 | cases_extra.appendAssumeCapacity(@enumToInt(item_ref)); |
| 11494 | 11948 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11495 | 11949 | } |
| 11496 | 11950 | }, |
| ... | ... | @@ -11500,7 +11954,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11500 | 11954 | cases_len += 1; |
| 11501 | 11955 | |
| 11502 | 11956 | const item_ref = try sema.addConstant(operand_ty, cur.toValue()); |
| 11503 | | case_block.inline_case_capture = item_ref; |
| 11504 | 11957 | |
| 11505 | 11958 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11506 | 11959 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| ... | ... | @@ -11508,19 +11961,27 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11508 | 11961 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11509 | 11962 | emit_bb = true; |
| 11510 | 11963 | |
| 11511 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 11964 | try spa.analyzeProngRuntime( |
| 11965 | &case_block, |
| 11966 | .special, |
| 11967 | special.body, |
| 11968 | special.capture, |
| 11969 | .special_capture, |
| 11970 | &.{item_ref}, |
| 11971 | item_ref, |
| 11972 | special.has_tag_capture, |
| 11973 | ); |
| 11512 | 11974 | |
| 11513 | 11975 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11514 | 11976 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11515 | 11977 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 11516 | | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 11978 | cases_extra.appendAssumeCapacity(@enumToInt(item_ref)); |
| 11517 | 11979 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11518 | 11980 | } |
| 11519 | 11981 | }, |
| 11520 | 11982 | .Bool => { |
| 11521 | 11983 | if (true_count == 0) { |
| 11522 | 11984 | cases_len += 1; |
| 11523 | | case_block.inline_case_capture = Air.Inst.Ref.bool_true; |
| 11524 | 11985 | |
| 11525 | 11986 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11526 | 11987 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| ... | ... | @@ -11528,17 +11989,25 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11528 | 11989 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11529 | 11990 | emit_bb = true; |
| 11530 | 11991 | |
| 11531 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 11992 | try spa.analyzeProngRuntime( |
| 11993 | &case_block, |
| 11994 | .special, |
| 11995 | special.body, |
| 11996 | special.capture, |
| 11997 | .special_capture, |
| 11998 | &.{Air.Inst.Ref.bool_true}, |
| 11999 | Air.Inst.Ref.bool_true, |
| 12000 | special.has_tag_capture, |
| 12001 | ); |
| 11532 | 12002 | |
| 11533 | 12003 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11534 | 12004 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11535 | 12005 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 11536 | | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 12006 | cases_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.bool_true)); |
| 11537 | 12007 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11538 | 12008 | } |
| 11539 | 12009 | if (false_count == 0) { |
| 11540 | 12010 | cases_len += 1; |
| 11541 | | case_block.inline_case_capture = Air.Inst.Ref.bool_false; |
| 11542 | 12011 | |
| 11543 | 12012 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11544 | 12013 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| ... | ... | @@ -11546,12 +12015,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11546 | 12015 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11547 | 12016 | emit_bb = true; |
| 11548 | 12017 | |
| 11549 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 12018 | try spa.analyzeProngRuntime( |
| 12019 | &case_block, |
| 12020 | .special, |
| 12021 | special.body, |
| 12022 | special.capture, |
| 12023 | .special_capture, |
| 12024 | &.{Air.Inst.Ref.bool_false}, |
| 12025 | Air.Inst.Ref.bool_false, |
| 12026 | special.has_tag_capture, |
| 12027 | ); |
| 11550 | 12028 | |
| 11551 | 12029 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11552 | 12030 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11553 | 12031 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 11554 | | cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture)); |
| 12032 | cases_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.bool_false)); |
| 11555 | 12033 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11556 | 12034 | } |
| 11557 | 12035 | }, |
| ... | ... | @@ -11565,7 +12043,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11565 | 12043 | |
| 11566 | 12044 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11567 | 12045 | case_block.wip_capture_scope = wip_captures.scope; |
| 11568 | | case_block.inline_case_capture = .none; |
| 11569 | 12046 | |
| 11570 | 12047 | if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and |
| 11571 | 12048 | operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) |
| ... | ... | @@ -11589,7 +12066,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11589 | 12066 | { |
| 11590 | 12067 | // nothing to do here |
| 11591 | 12068 | } else if (special.body.len != 0 and analyze_body and !special.is_inline) { |
| 11592 | | try sema.analyzeBodyRuntimeBreak(&case_block, special.body); |
| 12069 | try spa.analyzeProngRuntime( |
| 12070 | &case_block, |
| 12071 | .special, |
| 12072 | special.body, |
| 12073 | special.capture, |
| 12074 | .special_capture, |
| 12075 | undefined, // case_vals may be undefined for special prongs |
| 12076 | .none, |
| 12077 | false, |
| 12078 | ); |
| 11593 | 12079 | } else { |
| 11594 | 12080 | // We still need a terminator in this block, but we have proven |
| 11595 | 12081 | // that it is unreachable. |
| ... | ... | @@ -11704,29 +12190,51 @@ const RangeSetUnhandledIterator = struct { |
| 11704 | 12190 | } |
| 11705 | 12191 | }; |
| 11706 | 12192 | |
| 12193 | const ResolvedSwitchItem = struct { |
| 12194 | ref: Air.Inst.Ref, |
| 12195 | val: InternPool.Index, |
| 12196 | }; |
| 11707 | 12197 | fn resolveSwitchItemVal( |
| 11708 | 12198 | sema: *Sema, |
| 11709 | 12199 | block: *Block, |
| 11710 | 12200 | item_ref: Zir.Inst.Ref, |
| 12201 | /// Coerce `item_ref` to this type. |
| 12202 | coerce_ty: Type, |
| 11711 | 12203 | switch_node_offset: i32, |
| 11712 | 12204 | switch_prong_src: Module.SwitchProngSrc, |
| 11713 | 12205 | range_expand: Module.SwitchProngSrc.RangeExpand, |
| 11714 | | ) CompileError!InternPool.Index { |
| 12206 | ) CompileError!ResolvedSwitchItem { |
| 11715 | 12207 | const mod = sema.mod; |
| 11716 | | const item = try sema.resolveInst(item_ref); |
| 12208 | const uncoerced_item = try sema.resolveInst(item_ref); |
| 12209 | |
| 11717 | 12210 | // Constructing a LazySrcLoc is costly because we only have the switch AST node. |
| 11718 | 12211 | // Only if we know for sure we need to report a compile error do we resolve the |
| 11719 | 12212 | // full source locations. |
| 11720 | | if (sema.resolveConstLazyValue(block, .unneeded, item, "")) |val| { |
| 11721 | | return val.toIntern(); |
| 11722 | | } else |err| switch (err) { |
| 12213 | |
| 12214 | const item = sema.coerce(block, coerce_ty, uncoerced_item, .unneeded) catch |err| switch (err) { |
| 12215 | error.NeededSourceLocation => { |
| 12216 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand); |
| 12217 | _ = try sema.coerce(block, coerce_ty, uncoerced_item, src); |
| 12218 | unreachable; |
| 12219 | }, |
| 12220 | else => |e| return e, |
| 12221 | }; |
| 12222 | |
| 12223 | const maybe_lazy = sema.resolveConstValue(block, .unneeded, item, "") catch |err| switch (err) { |
| 11723 | 12224 | error.NeededSourceLocation => { |
| 11724 | 12225 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand); |
| 11725 | 12226 | _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known"); |
| 11726 | 12227 | unreachable; |
| 11727 | 12228 | }, |
| 11728 | 12229 | else => |e| return e, |
| 11729 | | } |
| 12230 | }; |
| 12231 | |
| 12232 | const val = try sema.resolveLazyValue(maybe_lazy); |
| 12233 | const new_item = if (val.toIntern() != maybe_lazy.toIntern()) blk: { |
| 12234 | break :blk try sema.addConstant(coerce_ty, val); |
| 12235 | } else item; |
| 12236 | |
| 12237 | return .{ .ref = new_item, .val = val.toIntern() }; |
| 11730 | 12238 | } |
| 11731 | 12239 | |
| 11732 | 12240 | fn validateSwitchRange( |
| ... | ... | @@ -11735,31 +12243,35 @@ fn validateSwitchRange( |
| 11735 | 12243 | range_set: *RangeSet, |
| 11736 | 12244 | first_ref: Zir.Inst.Ref, |
| 11737 | 12245 | last_ref: Zir.Inst.Ref, |
| 12246 | operand_ty: Type, |
| 11738 | 12247 | src_node_offset: i32, |
| 11739 | 12248 | switch_prong_src: Module.SwitchProngSrc, |
| 11740 | | ) CompileError!void { |
| 12249 | ) CompileError![2]Air.Inst.Ref { |
| 11741 | 12250 | const mod = sema.mod; |
| 11742 | | const first = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first); |
| 11743 | | const last = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last); |
| 11744 | | if (first.toValue().compareScalar(.gt, last.toValue(), mod.intern_pool.typeOf(first).toType(), mod)) { |
| 12251 | const first = try sema.resolveSwitchItemVal(block, first_ref, operand_ty, src_node_offset, switch_prong_src, .first); |
| 12252 | const last = try sema.resolveSwitchItemVal(block, last_ref, operand_ty, src_node_offset, switch_prong_src, .last); |
| 12253 | if (try first.val.toValue().compareAll(.gt, last.val.toValue(), operand_ty, mod)) { |
| 11745 | 12254 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first); |
| 11746 | 12255 | return sema.fail(block, src, "range start value is greater than the end value", .{}); |
| 11747 | 12256 | } |
| 11748 | | const maybe_prev_src = try range_set.add(first, last, switch_prong_src); |
| 11749 | | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 12257 | const maybe_prev_src = try range_set.add(first.val, last.val, switch_prong_src); |
| 12258 | try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 12259 | return .{ first.ref, last.ref }; |
| 11750 | 12260 | } |
| 11751 | 12261 | |
| 11752 | | fn validateSwitchItem( |
| 12262 | fn validateSwitchItemInt( |
| 11753 | 12263 | sema: *Sema, |
| 11754 | 12264 | block: *Block, |
| 11755 | 12265 | range_set: *RangeSet, |
| 11756 | 12266 | item_ref: Zir.Inst.Ref, |
| 12267 | operand_ty: Type, |
| 11757 | 12268 | src_node_offset: i32, |
| 11758 | 12269 | switch_prong_src: Module.SwitchProngSrc, |
| 11759 | | ) CompileError!void { |
| 11760 | | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 11761 | | const maybe_prev_src = try range_set.add(item, item, switch_prong_src); |
| 11762 | | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 12270 | ) CompileError!Air.Inst.Ref { |
| 12271 | const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none); |
| 12272 | const maybe_prev_src = try range_set.add(item.val, item.val, switch_prong_src); |
| 12273 | try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 12274 | return item.ref; |
| 11763 | 12275 | } |
| 11764 | 12276 | |
| 11765 | 12277 | fn validateSwitchItemEnum( |
| ... | ... | @@ -11768,19 +12280,22 @@ fn validateSwitchItemEnum( |
| 11768 | 12280 | seen_fields: []?Module.SwitchProngSrc, |
| 11769 | 12281 | range_set: *RangeSet, |
| 11770 | 12282 | item_ref: Zir.Inst.Ref, |
| 12283 | operand_ty: Type, |
| 11771 | 12284 | src_node_offset: i32, |
| 11772 | 12285 | switch_prong_src: Module.SwitchProngSrc, |
| 11773 | | ) CompileError!void { |
| 12286 | ) CompileError!Air.Inst.Ref { |
| 11774 | 12287 | const ip = &sema.mod.intern_pool; |
| 11775 | | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 11776 | | const int = ip.indexToKey(item).enum_tag.int; |
| 11777 | | const field_index = ip.indexToKey(ip.typeOf(item)).enum_type.tagValueIndex(ip, int) orelse { |
| 12288 | const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none); |
| 12289 | const int = ip.indexToKey(item.val).enum_tag.int; |
| 12290 | const field_index = ip.indexToKey(ip.typeOf(item.val)).enum_type.tagValueIndex(ip, int) orelse { |
| 11778 | 12291 | const maybe_prev_src = try range_set.add(int, int, switch_prong_src); |
| 11779 | | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 12292 | try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 12293 | return item.ref; |
| 11780 | 12294 | }; |
| 11781 | 12295 | const maybe_prev_src = seen_fields[field_index]; |
| 11782 | 12296 | seen_fields[field_index] = switch_prong_src; |
| 11783 | | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 12297 | try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 12298 | return item.ref; |
| 11784 | 12299 | } |
| 11785 | 12300 | |
| 11786 | 12301 | fn validateSwitchItemError( |
| ... | ... | @@ -11788,18 +12303,19 @@ fn validateSwitchItemError( |
| 11788 | 12303 | block: *Block, |
| 11789 | 12304 | seen_errors: *SwitchErrorSet, |
| 11790 | 12305 | item_ref: Zir.Inst.Ref, |
| 12306 | operand_ty: Type, |
| 11791 | 12307 | src_node_offset: i32, |
| 11792 | 12308 | switch_prong_src: Module.SwitchProngSrc, |
| 11793 | | ) CompileError!void { |
| 12309 | ) CompileError!Air.Inst.Ref { |
| 11794 | 12310 | const ip = &sema.mod.intern_pool; |
| 11795 | | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 11796 | | // TODO: Do i need to typecheck here? |
| 11797 | | const error_name = ip.indexToKey(item).err.name; |
| 12311 | const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none); |
| 12312 | const error_name = ip.indexToKey(item.val).err.name; |
| 11798 | 12313 | const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev| |
| 11799 | 12314 | prev.value |
| 11800 | 12315 | else |
| 11801 | 12316 | null; |
| 11802 | | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 12317 | try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 12318 | return item.ref; |
| 11803 | 12319 | } |
| 11804 | 12320 | |
| 11805 | 12321 | fn validateSwitchDupe( |
| ... | ... | @@ -11842,19 +12358,20 @@ fn validateSwitchItemBool( |
| 11842 | 12358 | item_ref: Zir.Inst.Ref, |
| 11843 | 12359 | src_node_offset: i32, |
| 11844 | 12360 | switch_prong_src: Module.SwitchProngSrc, |
| 11845 | | ) CompileError!void { |
| 12361 | ) CompileError!Air.Inst.Ref { |
| 11846 | 12362 | const mod = sema.mod; |
| 11847 | | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 11848 | | if (item.toValue().toBool()) { |
| 12363 | const item = try sema.resolveSwitchItemVal(block, item_ref, Type.bool, src_node_offset, switch_prong_src, .none); |
| 12364 | if (item.val.toValue().toBool()) { |
| 11849 | 12365 | true_count.* += 1; |
| 11850 | 12366 | } else { |
| 11851 | 12367 | false_count.* += 1; |
| 11852 | 12368 | } |
| 11853 | | if (true_count.* + false_count.* > 2) { |
| 11854 | | const block_src_decl = mod.declPtr(block.src_decl); |
| 12369 | if (true_count.* > 1 or false_count.* > 1) { |
| 12370 | const block_src_decl = sema.mod.declPtr(block.src_decl); |
| 11855 | 12371 | const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); |
| 11856 | 12372 | return sema.fail(block, src, "duplicate switch value", .{}); |
| 11857 | 12373 | } |
| 12374 | return item.ref; |
| 11858 | 12375 | } |
| 11859 | 12376 | |
| 11860 | 12377 | const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc); |
| ... | ... | @@ -11864,12 +12381,14 @@ fn validateSwitchItemSparse( |
| 11864 | 12381 | block: *Block, |
| 11865 | 12382 | seen_values: *ValueSrcMap, |
| 11866 | 12383 | item_ref: Zir.Inst.Ref, |
| 12384 | operand_ty: Type, |
| 11867 | 12385 | src_node_offset: i32, |
| 11868 | 12386 | switch_prong_src: Module.SwitchProngSrc, |
| 11869 | | ) CompileError!void { |
| 11870 | | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 11871 | | const kv = (try seen_values.fetchPut(sema.gpa, item, switch_prong_src)) orelse return; |
| 11872 | | return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset); |
| 12387 | ) CompileError!Air.Inst.Ref { |
| 12388 | const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none); |
| 12389 | const kv = (try seen_values.fetchPut(sema.gpa, item.val, switch_prong_src)) orelse return item.ref; |
| 12390 | try sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset); |
| 12391 | unreachable; |
| 11873 | 12392 | } |
| 11874 | 12393 | |
| 11875 | 12394 | fn validateSwitchNoRange( |