| ... | @@ -277,12 +277,6 @@ pub const Block = struct { | ... | @@ -277,12 +277,6 @@ pub const Block = struct { |
| 277 | | 277 | |
| 278 | c_import_buf: ?*std.ArrayList(u8) = null, | 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 | const ComptimeReason = union(enum) { | 280 | const ComptimeReason = union(enum) { |
| 287 | c_import: struct { | 281 | c_import: struct { |
| 288 | block: *Block, | 282 | block: *Block, |
| ... | @@ -397,7 +391,6 @@ pub const Block = struct { | ... | @@ -397,7 +391,6 @@ pub const Block = struct { |
| 397 | .want_safety = parent.want_safety, | 391 | .want_safety = parent.want_safety, |
| 398 | .float_mode = parent.float_mode, | 392 | .float_mode = parent.float_mode, |
| 399 | .c_import_buf = parent.c_import_buf, | 393 | .c_import_buf = parent.c_import_buf, |
| 400 | .switch_else_err_ty = parent.switch_else_err_ty, | | |
| 401 | .error_return_trace_index = parent.error_return_trace_index, | 394 | .error_return_trace_index = parent.error_return_trace_index, |
| 402 | }; | 395 | }; |
| 403 | } | 396 | } |
| ... | @@ -1014,14 +1007,8 @@ fn analyzeBodyInner( | ... | @@ -1014,14 +1007,8 @@ fn analyzeBodyInner( |
| 1014 | .slice_start => try sema.zirSliceStart(block, inst), | 1007 | .slice_start => try sema.zirSliceStart(block, inst), |
| 1015 | .slice_length => try sema.zirSliceLength(block, inst), | 1008 | .slice_length => try sema.zirSliceLength(block, inst), |
| 1016 | .str => try sema.zirStr(block, inst), | 1009 | .str => try sema.zirStr(block, inst), |
| 1017 | .switch_block => try sema.zirSwitchBlock(block, inst), | 1010 | .switch_block => try sema.zirSwitchBlock(block, inst, false), |
| 1018 | .switch_cond => try sema.zirSwitchCond(block, inst, false), | 1011 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true), |
| 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), | | |
| 1025 | .type_info => try sema.zirTypeInfo(block, inst), | 1012 | .type_info => try sema.zirTypeInfo(block, inst), |
| 1026 | .size_of => try sema.zirSizeOf(block, inst), | 1013 | .size_of => try sema.zirSizeOf(block, inst), |
| 1027 | .bit_size_of => try sema.zirBitSizeOf(block, inst), | 1014 | .bit_size_of => try sema.zirBitSizeOf(block, inst), |
| ... | @@ -1225,7 +1212,7 @@ fn analyzeBodyInner( | ... | @@ -1225,7 +1212,7 @@ fn analyzeBodyInner( |
| 1225 | i += 1; | 1212 | i += 1; |
| 1226 | continue; | 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,6 +2392,34 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 2405 | return error.AnalysisFail; | 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 | const align_ty = Type.u29; | 2423 | const align_ty = Type.u29; |
| 2409 | | 2424 | |
| 2410 | fn analyzeAsAlign( | 2425 | fn analyzeAsAlign( |
| ... | @@ -10085,251 +10100,544 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10085,251 +10100,544 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10085 | return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true); | 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 | sema: *Sema, | 10106 | sema: *Sema, |
| 10090 | block: *Block, | 10107 | /// The block containing the `switch_block` itself. |
| 10091 | inst: Zir.Inst.Index, | 10108 | parent_block: *Block, |
| 10092 | is_multi: bool, | 10109 | /// The raw switch operand value (*not* the condition). Always defined. |
| 10093 | is_ref: bool, | 10110 | operand: Air.Inst.Ref, |
| 10094 | ) CompileError!Air.Inst.Ref { | 10111 | /// May be `undefined` if no prong has a by-ref capture. |
| 10095 | const tracy = trace(@src()); | 10112 | operand_ptr: Air.Inst.Ref, |
| 10096 | defer tracy.end(); | 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; | 10169 | if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) { |
| 10099 | const gpa = sema.gpa; | 10170 | // This prong should be unreachable! |
| 10100 | const zir_datas = sema.code.instructions.items(.data); | 10171 | return Air.Inst.Ref.unreachable_value; |
| 10101 | const capture_info = zir_datas[inst].switch_capture; | 10172 | } |
| 10102 | const switch_info = zir_datas[capture_info.switch_inst].pl_node; | 10173 | |
| 10103 | const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index); | 10174 | sema.inst_map.putAssumeCapacity(spa.switch_block_inst, capture_ref); |
| 10104 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node }; | 10175 | defer assert(sema.inst_map.remove(spa.switch_block_inst)); |
| 10105 | const cond_inst = Zir.refToIndex(switch_extra.data.operand).?; | 10176 | |
| 10106 | const cond_info = zir_datas[cond_inst].un_node; | 10177 | return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges); |
| 10107 | const cond_tag = sema.code.instructions.items(.tag)[cond_inst]; | 10178 | }, |
| 10108 | const operand_is_ref = cond_tag == .switch_cond_ref; | 10179 | } |
| 10109 | const operand_ptr = try sema.resolveInst(cond_info.operand); | 10180 | } |
| 10110 | const operand_ptr_ty = sema.typeOf(operand_ptr); | 10181 | |
| 10111 | const operand_ty = if (operand_is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty; | 10182 | /// Analyze a switch prong which may have peers at runtime. |
| 10112 | | 10183 | /// Uses `analyzeBodyRuntimeBreak`. Sets up captures as needed. |
| 10113 | if (block.inline_case_capture != .none) { | 10184 | fn analyzeProngRuntime( |
| 10114 | const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable; | 10185 | spa: SwitchProngAnalysis, |
| 10115 | const resolved_item_val = try sema.resolveLazyValue(item_val); | 10186 | case_block: *Block, |
| 10116 | if (operand_ty.zigTypeTag(mod) == .Union) { | 10187 | prong_type: enum { normal, special }, |
| 10117 | const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(resolved_item_val, mod).?); | 10188 | prong_body: []const Zir.Inst.Index, |
| 10118 | const union_obj = mod.typeToUnion(operand_ty).?; | 10189 | capture: Zir.Inst.SwitchBlock.ProngInfo.Capture, |
| 10119 | const field_ty = union_obj.fields.values()[field_index].ty; | 10190 | /// Must use the `scalar`, `special`, or `multi_capture` union field. |
| 10120 | if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| { | 10191 | raw_capture_src: Module.SwitchProngSrc, |
| 10121 | if (is_ref) { | 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 | const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ | 10297 | const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ |
| 10123 | .pointee_type = field_ty, | 10298 | .pointee_type = field_ty, |
| 10124 | .mutable = operand_ptr_ty.ptrIsMutable(mod), | 10299 | .mutable = operand_ptr_ty.ptrIsMutable(mod), |
| 10125 | .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), | 10300 | .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), |
| 10126 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), | 10301 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), |
| 10127 | }); | 10302 | }); |
| 10128 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | 10303 | if (try sema.resolveDefinedValue(block, sema.src, spa.operand_ptr)) |union_ptr| { |
| 10129 | .ty = ptr_field_ty.toIntern(), | 10304 | return sema.addConstant( |
| 10130 | .addr = .{ .field = .{ | 10305 | ptr_field_ty, |
| 10131 | .base = union_val.toIntern(), | 10306 | (try mod.intern(.{ .ptr = .{ |
| 10132 | .index = field_index, | 10307 | .ty = ptr_field_ty.toIntern(), |
| 10133 | } }, | 10308 | .addr = .{ .field = .{ |
| 10134 | } })).toValue()); | 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( | 10323 | } else if (capture_byref) { |
| 10137 | field_ty, | 10324 | return sema.addConstantMaybeRef(block, operand_ty, item_val, true); |
| 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); | | |
| 10149 | } else { | 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) | 10330 | if (is_special_prong) { |
| 10160 | try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src) | 10331 | if (capture_byref) { |
| 10161 | else | 10332 | return spa.operand_ptr; |
| 10162 | operand_ptr; | 10333 | } |
| 10163 | | 10334 | |
| 10164 | if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) { | 10335 | switch (operand_ty.zigTypeTag(mod)) { |
| 10165 | // It is the else/`_` prong. | 10336 | .ErrorSet => if (spa.else_error_ty) |ty| { |
| 10166 | if (is_ref) { | 10337 | return sema.bitCast(block, ty, spa.operand, operand_src, null); |
| 10167 | return operand_ptr; | 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 | switch (operand_ty.zigTypeTag(mod)) { | 10346 | switch (operand_ty.zigTypeTag(mod)) { |
| 10171 | .ErrorSet => if (block.switch_else_err_ty) |some| { | 10347 | .Union => { |
| 10172 | return sema.bitCast(block, some, operand, operand_src, null); | 10348 | const union_obj = mod.typeToUnion(operand_ty).?; |
| 10173 | } else { | 10349 | const first_item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable; |
| 10174 | try block.addUnreachable(false); | | |
| 10175 | return Air.Inst.Ref.unreachable_value; | | |
| 10176 | }, | | |
| 10177 | else => return operand, | | |
| 10178 | } | | |
| 10179 | } | | |
| 10180 | | 10350 | |
| 10181 | const items = if (is_multi) | 10351 | const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?); |
| 10182 | switch_extra.data.getMultiProng(sema.code, switch_extra.end, capture_info.prong_index).items | 10352 | const first_field = union_obj.fields.values()[first_field_index]; |
| 10183 | else | | |
| 10184 | &[_]Zir.Inst.Ref{ | | |
| 10185 | switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item, | | |
| 10186 | }; | | |
| 10187 | | 10353 | |
| 10188 | switch (operand_ty.zigTypeTag(mod)) { | 10354 | const field_tys = try sema.arena.alloc(Type, case_vals.len); |
| 10189 | .Union => { | 10355 | for (case_vals, field_tys) |item, *field_ty| { |
| 10190 | const union_obj = mod.typeToUnion(operand_ty).?; | 10356 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; |
| 10191 | const first_item = try sema.resolveInst(items[0]); | 10357 | const field_idx = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?); |
| 10192 | // Previous switch validation ensured this will succeed | 10358 | field_ty.* = union_obj.fields.values()[field_idx].ty; |
| 10193 | const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable; | 10359 | } |
| 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); | | |
| 10209 | | 10360 | |
| 10210 | const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{}); | 10361 | // Fast path: if all the operands are the same type already, we don't need to hit |
| 10211 | errdefer msg.destroy(gpa); | 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 } }; | 10367 | const capture_ty = if (same_types) field_tys[0] else capture_ty: { |
| 10214 | const first_item_src = raw_first_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); | 10368 | // We need values to run PTR on, so make a bunch of undef constants. |
| 10215 | const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } }; | 10369 | const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len); |
| 10216 | const item_src = raw_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); | 10370 | for (dummy_captures, field_tys) |*dummy, field_ty| { |
| 10217 | try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(mod)}); | 10371 | dummy.* = try sema.addConstUndef(field_ty); |
| 10218 | try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(mod)}); | 10372 | } |
| 10219 | break :msg msg; | 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); | 10399 | }; |
| 10222 | } | | |
| 10223 | } | | |
| 10224 | | 10400 | |
| 10225 | if (is_ref) { | 10401 | // By-reference captures have some further restrictions which make them easier to emit |
| 10226 | const field_ty_ptr = try Type.ptr(sema.arena, mod, .{ | 10402 | if (capture_byref) { |
| 10227 | .pointee_type = first_field.ty, | 10403 | const operand_ptr_info = operand_ptr_ty.ptrInfo(mod); |
| 10228 | .@"addrspace" = .generic, | 10404 | const capture_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 10229 | .mutable = operand_ptr_ty.ptrIsMutable(mod), | 10405 | .pointee_type = capture_ty, |
| 10230 | }); | 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| { | 10412 | // By-ref captures of hetereogeneous types are only allowed if each field |
| 10233 | return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{ | 10413 | // pointer type is in-memory coercible to the capture pointer type. |
| 10234 | .ty = field_ty_ptr.toIntern(), | 10414 | if (!same_types) { |
| 10235 | .addr = .{ .field = .{ | 10415 | for (field_tys, 0..) |field_ty, i| { |
| 10236 | .base = op_ptr_val.toIntern(), | 10416 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 10237 | .index = first_field_index, | 10417 | .pointee_type = field_ty, |
| 10238 | } }, | 10418 | .@"addrspace" = operand_ptr_info.@"addrspace", |
| 10239 | } })).toValue()); | 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 | try sema.requireRuntimeBlock(block, operand_src, null); | 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| { | 10474 | if (same_types) { |
| 10246 | return sema.addConstant( | 10475 | return block.addStructFieldVal(spa.operand, first_field_index, capture_ty); |
| 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().?, {}); | | |
| 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); | 10478 | // We may have to emit a switch block which coerces the operand to the capture type. |
| 10267 | } else { | 10479 | // If we can, try to avoid that using in-memory coercions. |
| 10268 | const item_ref = try sema.resolveInst(items[0]); | 10480 | const first_non_imc = in_mem: { |
| 10269 | // Previous switch validation ensured this will succeed | 10481 | for (field_tys, 0..) |field_ty, i| { |
| 10270 | const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable; | 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().?); | 10492 | // By-val capture with heterogeneous types which are not all in-memory coercible to |
| 10273 | return sema.bitCast(block, item_ty, operand, operand_src, null); | 10493 | // the resolved capture type. We finally have to fall back to the ugly method. |
| 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 | } | | |
| 10287 | | 10494 | |
| 10288 | fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 10495 | // However, let's first track which operands are in-memory coercible. There may well |
| 10289 | const mod = sema.mod; | 10496 | // be several, and we can squash all of these cases into the same switch prong using |
| 10290 | const zir_datas = sema.code.instructions.items(.data); | 10497 | // a simple bitcast. We'll make this the 'else' prong. |
| 10291 | const inst_data = zir_datas[inst].un_tok; | | |
| 10292 | const src = inst_data.src(); | | |
| 10293 | | 10498 | |
| 10294 | const switch_tag = sema.code.instructions.items(.tag)[Zir.refToIndex(inst_data.operand).?]; | 10499 | var in_mem_coercible = try std.DynamicBitSet.initFull(sema.arena, field_tys.len); |
| 10295 | const is_ref = switch_tag == .switch_cond_ref; | 10500 | in_mem_coercible.unset(first_non_imc); |
| 10296 | const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node; | 10501 | { |
| 10297 | const operand_ptr = try sema.resolveInst(cond_data.operand); | 10502 | const next = first_non_imc + 1; |
| 10298 | const operand_ptr_ty = sema.typeOf(operand_ptr); | 10503 | for (field_tys[next..], next..) |field_ty, i| { |
| 10299 | const operand_ty = if (is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty; | 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) { | 10510 | const capture_block_inst = try block.addInstAsIndex(.{ |
| 10302 | const msg = msg: { | 10511 | .tag = .block, |
| 10303 | const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{ | 10512 | .data = .{ |
| 10304 | operand_ty.fmt(mod), | 10513 | .ty_pl = .{ |
| 10305 | }); | 10514 | .ty = try sema.addType(capture_ty), |
| 10306 | errdefer msg.destroy(sema.gpa); | 10515 | .payload = undefined, // updated below |
| 10307 | try sema.addDeclaredHereNote(msg, operand_ty); | 10516 | }, |
| 10308 | break :msg msg; | 10517 | }, |
| 10309 | }; | 10518 | }); |
| 10310 | return sema.failWithOwnedErrorMsg(msg); | | |
| 10311 | } | | |
| 10312 | | 10519 | |
| 10313 | return block.inline_case_capture; | 10520 | const prong_count = field_tys.len - in_mem_coercible.count(); |
| 10314 | } | 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 | sema: *Sema, | 10634 | sema: *Sema, |
| 10318 | block: *Block, | 10635 | block: *Block, |
| 10319 | inst: Zir.Inst.Index, | 10636 | src: LazySrcLoc, |
| 10320 | is_ref: bool, | 10637 | operand: Air.Inst.Ref, |
| 10321 | ) CompileError!Air.Inst.Ref { | 10638 | ) CompileError!Air.Inst.Ref { |
| 10322 | const mod = sema.mod; | 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 | const operand_ty = sema.typeOf(operand); | 10640 | const operand_ty = sema.typeOf(operand); |
| 10332 | | | |
| 10333 | switch (operand_ty.zigTypeTag(mod)) { | 10641 | switch (operand_ty.zigTypeTag(mod)) { |
| 10334 | .Type, | 10642 | .Type, |
| 10335 | .Void, | 10643 | .Void, |
| ... | @@ -10386,7 +10694,7 @@ fn zirSwitchCond( | ... | @@ -10386,7 +10694,7 @@ fn zirSwitchCond( |
| 10386 | | 10694 | |
| 10387 | const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc); | 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 | const tracy = trace(@src()); | 10698 | const tracy = trace(@src()); |
| 10391 | defer tracy.end(); | 10699 | defer tracy.end(); |
| 10392 | | 10700 | |
| ... | @@ -10400,10 +10708,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10400,10 +10708,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10400 | const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset }; | 10708 | const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset }; |
| 10401 | const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); | 10709 | const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); |
| 10402 | | 10710 | |
| 10403 | const operand = try sema.resolveInst(extra.data.operand); | 10711 | const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: { |
| 10404 | // AstGen guarantees that the instruction immediately following | 10712 | const maybe_ptr = try sema.resolveInst(extra.data.operand); |
| 10405 | // switch_cond(_ref) is a dbg_stmt | 10713 | if (operand_is_ref) { |
| 10406 | const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1; | 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 | var header_extra_index: usize = extra.end; | 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,28 +10733,50 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10414 | break :blk multi_cases_len; | 10733 | break :blk multi_cases_len; |
| 10415 | } else 0; | 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 | const special_prong = extra.data.bits.specialProng(); | 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) { | 10758 | const special: Special = switch (special_prong) { |
| 10419 | .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false }, | 10759 | .none => .{ |
| | 10760 | .body = &.{}, |
| | 10761 | .end = header_extra_index, |
| | 10762 | .capture = .none, |
| | 10763 | .is_inline = false, |
| | 10764 | .has_tag_capture = false, |
| | 10765 | }, |
| 10420 | .under, .@"else" => blk: { | 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 | const extra_body_start = header_extra_index + 1; | 10768 | const extra_body_start = header_extra_index + 1; |
| 10423 | break :blk .{ | 10769 | break :blk .{ |
| 10424 | .body = sema.code.extra[extra_body_start..][0..body_len], | 10770 | .body = sema.code.extra[extra_body_start..][0..info.body_len], |
| 10425 | .end = extra_body_start + body_len, | 10771 | .end = extra_body_start + info.body_len, |
| 10426 | .is_inline = sema.code.extra[header_extra_index] >> 31 != 0, | 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: { | 10779 | const maybe_union_ty = sema.typeOf(raw_operand.val); |
| 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 | }; | | |
| 10439 | const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union; | 10780 | const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union; |
| 10440 | | 10781 | |
| 10441 | // Duplicate checking variables later also used for `inline else`. | 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,18 +10836,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10495 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 10836 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10496 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 10837 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10497 | extra_index += 1; | 10838 | extra_index += 1; |
| 10498 | const body_len = @truncate(u31, sema.code.extra[extra_index]); | 10839 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10499 | extra_index += 1; | 10840 | extra_index += 1 + info.body_len; |
| 10500 | extra_index += body_len; | | |
| 10501 | | 10841 | |
| 10502 | try sema.validateSwitchItemEnum( | 10842 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum( |
| 10503 | block, | 10843 | block, |
| 10504 | seen_enum_fields, | 10844 | seen_enum_fields, |
| 10505 | &range_set, | 10845 | &range_set, |
| 10506 | item_ref, | 10846 | item_ref, |
| | 10847 | operand_ty, |
| 10507 | src_node_offset, | 10848 | src_node_offset, |
| 10508 | .{ .scalar = scalar_i }, | 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,20 +10857,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10516 | extra_index += 1; | 10857 | extra_index += 1; |
| 10517 | const ranges_len = sema.code.extra[extra_index]; | 10858 | const ranges_len = sema.code.extra[extra_index]; |
| 10518 | extra_index += 1; | 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 | extra_index += 1; | 10861 | extra_index += 1; |
| 10521 | const items = sema.code.refSlice(extra_index, items_len); | 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 | for (items, 0..) |item_ref, item_i| { | 10866 | for (items, 0..) |item_ref, item_i| { |
| 10525 | try sema.validateSwitchItemEnum( | 10867 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum( |
| 10526 | block, | 10868 | block, |
| 10527 | seen_enum_fields, | 10869 | seen_enum_fields, |
| 10528 | &range_set, | 10870 | &range_set, |
| 10529 | item_ref, | 10871 | item_ref, |
| | 10872 | operand_ty, |
| 10530 | src_node_offset, | 10873 | src_node_offset, |
| 10531 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, | 10874 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10532 | ); | 10875 | )); |
| 10533 | } | 10876 | } |
| 10534 | | 10877 | |
| 10535 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); | 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,17 +10935,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10592 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 10935 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10593 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 10936 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10594 | extra_index += 1; | 10937 | extra_index += 1; |
| 10595 | const body_len = @truncate(u31, sema.code.extra[extra_index]); | 10938 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10596 | extra_index += 1; | 10939 | extra_index += 1 + info.body_len; |
| 10597 | extra_index += body_len; | | |
| 10598 | | 10940 | |
| 10599 | try sema.validateSwitchItemError( | 10941 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 10600 | block, | 10942 | block, |
| 10601 | &seen_errors, | 10943 | &seen_errors, |
| 10602 | item_ref, | 10944 | item_ref, |
| | 10945 | operand_ty, |
| 10603 | src_node_offset, | 10946 | src_node_offset, |
| 10604 | .{ .scalar = scalar_i }, | 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,19 +10955,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10612 | extra_index += 1; | 10955 | extra_index += 1; |
| 10613 | const ranges_len = sema.code.extra[extra_index]; | 10956 | const ranges_len = sema.code.extra[extra_index]; |
| 10614 | extra_index += 1; | 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 | extra_index += 1; | 10959 | extra_index += 1; |
| 10617 | const items = sema.code.refSlice(extra_index, items_len); | 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 | for (items, 0..) |item_ref, item_i| { | 10964 | for (items, 0..) |item_ref, item_i| { |
| 10621 | try sema.validateSwitchItemError( | 10965 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemError( |
| 10622 | block, | 10966 | block, |
| 10623 | &seen_errors, | 10967 | &seen_errors, |
| 10624 | item_ref, | 10968 | item_ref, |
| | 10969 | operand_ty, |
| 10625 | src_node_offset, | 10970 | src_node_offset, |
| 10626 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, | 10971 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10627 | ); | 10972 | )); |
| 10628 | } | 10973 | } |
| 10629 | | 10974 | |
| 10630 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); | 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,7 +11032,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10687 | .dbg_block_end, | 11032 | .dbg_block_end, |
| 10688 | .dbg_stmt, | 11033 | .dbg_stmt, |
| 10689 | .dbg_var_val, | 11034 | .dbg_var_val, |
| 10690 | .switch_capture, | | |
| 10691 | .ret_type, | 11035 | .ret_type, |
| 10692 | .as_node, | 11036 | .as_node, |
| 10693 | .ret_node, | 11037 | .ret_node, |
| ... | @@ -10732,17 +11076,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10732,17 +11076,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10732 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 11076 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10733 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 11077 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10734 | extra_index += 1; | 11078 | extra_index += 1; |
| 10735 | const body_len = @truncate(u31, sema.code.extra[extra_index]); | 11079 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10736 | extra_index += 1; | 11080 | extra_index += 1 + info.body_len; |
| 10737 | extra_index += body_len; | | |
| 10738 | | 11081 | |
| 10739 | try sema.validateSwitchItem( | 11082 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt( |
| 10740 | block, | 11083 | block, |
| 10741 | &range_set, | 11084 | &range_set, |
| 10742 | item_ref, | 11085 | item_ref, |
| | 11086 | operand_ty, |
| 10743 | src_node_offset, | 11087 | src_node_offset, |
| 10744 | .{ .scalar = scalar_i }, | 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,21 +11096,24 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10752 | extra_index += 1; | 11096 | extra_index += 1; |
| 10753 | const ranges_len = sema.code.extra[extra_index]; | 11097 | const ranges_len = sema.code.extra[extra_index]; |
| 10754 | extra_index += 1; | 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 | extra_index += 1; | 11100 | extra_index += 1; |
| 10757 | const items = sema.code.refSlice(extra_index, items_len); | 11101 | const items = sema.code.refSlice(extra_index, items_len); |
| 10758 | extra_index += items_len; | 11102 | extra_index += items_len; |
| 10759 | | 11103 | |
| | 11104 | try case_vals.ensureUnusedCapacity(gpa, items.len); |
| 10760 | for (items, 0..) |item_ref, item_i| { | 11105 | for (items, 0..) |item_ref, item_i| { |
| 10761 | try sema.validateSwitchItem( | 11106 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt( |
| 10762 | block, | 11107 | block, |
| 10763 | &range_set, | 11108 | &range_set, |
| 10764 | item_ref, | 11109 | item_ref, |
| | 11110 | operand_ty, |
| 10765 | src_node_offset, | 11111 | src_node_offset, |
| 10766 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, | 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 | var range_i: u32 = 0; | 11117 | var range_i: u32 = 0; |
| 10771 | while (range_i < ranges_len) : (range_i += 1) { | 11118 | while (range_i < ranges_len) : (range_i += 1) { |
| 10772 | const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 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,17 +11121,20 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10774 | const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 11121 | const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10775 | extra_index += 1; | 11122 | extra_index += 1; |
| 10776 | | 11123 | |
| 10777 | try sema.validateSwitchRange( | 11124 | const vals = try sema.validateSwitchRange( |
| 10778 | block, | 11125 | block, |
| 10779 | &range_set, | 11126 | &range_set, |
| 10780 | item_first, | 11127 | item_first, |
| 10781 | item_last, | 11128 | item_last, |
| | 11129 | operand_ty, |
| 10782 | src_node_offset, | 11130 | src_node_offset, |
| 10783 | .{ .range = .{ .prong = multi_i, .item = range_i } }, | 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,18 +11171,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10821 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 11171 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10822 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 11172 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10823 | extra_index += 1; | 11173 | extra_index += 1; |
| 10824 | const body_len = @truncate(u31, sema.code.extra[extra_index]); | 11174 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 10825 | extra_index += 1; | 11175 | extra_index += 1 + info.body_len; |
| 10826 | extra_index += body_len; | | |
| 10827 | | 11176 | |
| 10828 | try sema.validateSwitchItemBool( | 11177 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool( |
| 10829 | block, | 11178 | block, |
| 10830 | &true_count, | 11179 | &true_count, |
| 10831 | &false_count, | 11180 | &false_count, |
| 10832 | item_ref, | 11181 | item_ref, |
| 10833 | src_node_offset, | 11182 | src_node_offset, |
| 10834 | .{ .scalar = scalar_i }, | 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,20 +11191,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10842 | extra_index += 1; | 11191 | extra_index += 1; |
| 10843 | const ranges_len = sema.code.extra[extra_index]; | 11192 | const ranges_len = sema.code.extra[extra_index]; |
| 10844 | extra_index += 1; | 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 | extra_index += 1; | 11195 | extra_index += 1; |
| 10847 | const items = sema.code.refSlice(extra_index, items_len); | 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 | for (items, 0..) |item_ref, item_i| { | 11200 | for (items, 0..) |item_ref, item_i| { |
| 10851 | try sema.validateSwitchItemBool( | 11201 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool( |
| 10852 | block, | 11202 | block, |
| 10853 | &true_count, | 11203 | &true_count, |
| 10854 | &false_count, | 11204 | &false_count, |
| 10855 | item_ref, | 11205 | item_ref, |
| 10856 | src_node_offset, | 11206 | src_node_offset, |
| 10857 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, | 11207 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10858 | ); | 11208 | )); |
| 10859 | } | 11209 | } |
| 10860 | | 11210 | |
| 10861 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); | 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,17 +11253,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10903 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 11253 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 10904 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 11254 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 10905 | extra_index += 1; | 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 | extra_index += 1; | 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 | block, | 11261 | block, |
| 10912 | &seen_values, | 11262 | &seen_values, |
| 10913 | item_ref, | 11263 | item_ref, |
| | 11264 | operand_ty, |
| 10914 | src_node_offset, | 11265 | src_node_offset, |
| 10915 | .{ .scalar = scalar_i }, | 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,19 +11274,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10923 | extra_index += 1; | 11274 | extra_index += 1; |
| 10924 | const ranges_len = sema.code.extra[extra_index]; | 11275 | const ranges_len = sema.code.extra[extra_index]; |
| 10925 | extra_index += 1; | 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 | extra_index += 1; | 11278 | extra_index += 1; |
| 10928 | const items = sema.code.refSlice(extra_index, items_len); | 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 | for (items, 0..) |item_ref, item_i| { | 11283 | for (items, 0..) |item_ref, item_i| { |
| 10932 | try sema.validateSwitchItemSparse( | 11284 | case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse( |
| 10933 | block, | 11285 | block, |
| 10934 | &seen_values, | 11286 | &seen_values, |
| 10935 | item_ref, | 11287 | item_ref, |
| | 11288 | operand_ty, |
| 10936 | src_node_offset, | 11289 | src_node_offset, |
| 10937 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, | 11290 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10938 | ); | 11291 | )); |
| 10939 | } | 11292 | } |
| 10940 | | 11293 | |
| 10941 | try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset); | 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,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 | const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); | 11328 | const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); |
| 10965 | try sema.air_instructions.append(gpa, .{ | 11329 | try sema.air_instructions.append(gpa, .{ |
| 10966 | .tag = .block, | 11330 | .tag = .block, |
| ... | @@ -10988,7 +11352,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10988,7 +11352,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10988 | .is_comptime = block.is_comptime, | 11352 | .is_comptime = block.is_comptime, |
| 10989 | .comptime_reason = block.comptime_reason, | 11353 | .comptime_reason = block.comptime_reason, |
| 10990 | .is_typeof = block.is_typeof, | 11354 | .is_typeof = block.is_typeof, |
| 10991 | .switch_else_err_ty = else_error_ty, | | |
| 10992 | .c_import_buf = block.c_import_buf, | 11355 | .c_import_buf = block.c_import_buf, |
| 10993 | .runtime_cond = block.runtime_cond, | 11356 | .runtime_cond = block.runtime_cond, |
| 10994 | .runtime_loop = block.runtime_loop, | 11357 | .runtime_loop = block.runtime_loop, |
| ... | @@ -11005,79 +11368,110 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11005,79 +11368,110 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11005 | { | 11368 | { |
| 11006 | var scalar_i: usize = 0; | 11369 | var scalar_i: usize = 0; |
| 11007 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 11370 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 11008 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | | |
| 11009 | extra_index += 1; | 11371 | extra_index += 1; |
| 11010 | const body_len = @truncate(u31, sema.code.extra[extra_index]); | 11372 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11011 | const is_inline = sema.code.extra[extra_index] >> 31 != 0; | | |
| 11012 | extra_index += 1; | 11373 | extra_index += 1; |
| 11013 | const body = sema.code.extra[extra_index..][0..body_len]; | 11374 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11014 | extra_index += body_len; | 11375 | extra_index += info.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; | | |
| 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 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); | 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 | var multi_i: usize = 0; | 11396 | var multi_i: usize = 0; |
| | 11397 | var case_val_idx: usize = scalar_cases_len; |
| 11029 | while (multi_i < multi_cases_len) : (multi_i += 1) { | 11398 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 11030 | const items_len = sema.code.extra[extra_index]; | 11399 | const items_len = sema.code.extra[extra_index]; |
| 11031 | extra_index += 1; | 11400 | extra_index += 1; |
| 11032 | const ranges_len = sema.code.extra[extra_index]; | 11401 | const ranges_len = sema.code.extra[extra_index]; |
| 11033 | extra_index += 1; | 11402 | extra_index += 1; |
| 11034 | const body_len = @truncate(u31, sema.code.extra[extra_index]); | 11403 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11035 | const is_inline = sema.code.extra[extra_index] >> 31 != 0; | 11404 | extra_index += 1 + items_len; |
| 11036 | extra_index += 1; | 11405 | const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..info.body_len]; |
| 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]; | | |
| 11040 | | 11406 | |
| 11041 | for (items) |item_ref| { | 11407 | const items = case_vals.items[case_val_idx..][0..items_len]; |
| 11042 | const item = try sema.resolveInst(item_ref); | 11408 | case_val_idx += items_len; |
| 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; | | |
| 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 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); | 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 | var range_i: usize = 0; | 11429 | var range_i: usize = 0; |
| 11054 | while (range_i < ranges_len) : (range_i += 1) { | 11430 | while (range_i < ranges_len) : (range_i += 1) { |
| 11055 | const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 11431 | const range_items = case_vals.items[case_val_idx..][0..2]; |
| 11056 | extra_index += 1; | 11432 | extra_index += 2; |
| 11057 | const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 11433 | case_val_idx += 2; |
| 11058 | extra_index += 1; | | |
| 11059 | | 11434 | |
| 11060 | // Validation above ensured these will succeed. | 11435 | // Validation above ensured these will succeed. |
| 11061 | const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable; | 11436 | const first_val = sema.resolveConstValue(&child_block, .unneeded, range_items[0], "") catch unreachable; |
| 11062 | const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable; | 11437 | const last_val = sema.resolveConstValue(&child_block, .unneeded, range_items[1], "") catch unreachable; |
| 11063 | if ((try sema.compareAll(resolved_operand_val, .gte, first_tv.val, operand_ty)) and | 11438 | if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and |
| 11064 | (try sema.compareAll(resolved_operand_val, .lte, last_tv.val, operand_ty))) | 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 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); | 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 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand); | 11459 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand); |
| 11076 | if (special.is_inline) child_block.inline_case_capture = operand; | | |
| 11077 | if (empty_enum) { | 11460 | if (empty_enum) { |
| 11078 | return Air.Inst.Ref.void_value; | 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 | if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) { | 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,7 +11491,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11097 | const ok = try block.addUnOp(.is_named_enum_value, operand); | 11491 | const ok = try block.addUnOp(.is_named_enum_value, operand); |
| 11098 | try sema.addSafetyCheck(block, ok, .corrupt_switch); | 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 | if (child_block.is_comptime) { | 11508 | if (child_block.is_comptime) { |
| ... | @@ -11123,23 +11528,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11123,23 +11528,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11123 | | 11528 | |
| 11124 | var scalar_i: usize = 0; | 11529 | var scalar_i: usize = 0; |
| 11125 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 11530 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 11126 | const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | | |
| 11127 | extra_index += 1; | 11531 | extra_index += 1; |
| 11128 | const body_len = @truncate(u31, sema.code.extra[extra_index]); | 11532 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11129 | const is_inline = sema.code.extra[extra_index] >> 31 != 0; | | |
| 11130 | extra_index += 1; | 11533 | extra_index += 1; |
| 11131 | const body = sema.code.extra[extra_index..][0..body_len]; | 11534 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11132 | extra_index += body_len; | 11535 | extra_index += info.body_len; |
| 11133 | | 11536 | |
| 11134 | var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope); | 11537 | var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope); |
| 11135 | defer wip_captures.deinit(); | 11538 | defer wip_captures.deinit(); |
| 11136 | | 11539 | |
| 11137 | case_block.instructions.shrinkRetainingCapacity(0); | 11540 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11138 | case_block.wip_capture_scope = wip_captures.scope; | 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); | 11543 | const item = case_vals.items[scalar_i]; |
| 11142 | if (is_inline) case_block.inline_case_capture = item; | | |
| 11143 | // `item` is already guaranteed to be constant known. | 11544 | // `item` is already guaranteed to be constant known. |
| 11144 | | 11545 | |
| 11145 | const analyze_body = if (union_originally) blk: { | 11546 | const analyze_body = if (union_originally) blk: { |
| ... | @@ -11151,7 +11552,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11151,7 +11552,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11151 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { | 11552 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { |
| 11152 | // nothing to do here | 11553 | // nothing to do here |
| 11153 | } else if (analyze_body) { | 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 | } else { | 11565 | } else { |
| 11156 | _ = try case_block.addNoOp(.unreach); | 11566 | _ = try case_block.addNoOp(.unreach); |
| 11157 | } | 11567 | } |
| ... | @@ -11173,38 +11583,38 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11173,38 +11583,38 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11173 | defer gpa.free(prev_then_body); | 11583 | defer gpa.free(prev_then_body); |
| 11174 | | 11584 | |
| 11175 | var cases_len = scalar_cases_len; | 11585 | var cases_len = scalar_cases_len; |
| | 11586 | var case_val_idx: usize = scalar_cases_len; |
| 11176 | var multi_i: u32 = 0; | 11587 | var multi_i: u32 = 0; |
| 11177 | while (multi_i < multi_cases_len) : (multi_i += 1) { | 11588 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 11178 | const items_len = sema.code.extra[extra_index]; | 11589 | const items_len = sema.code.extra[extra_index]; |
| 11179 | extra_index += 1; | 11590 | extra_index += 1; |
| 11180 | const ranges_len = sema.code.extra[extra_index]; | 11591 | const ranges_len = sema.code.extra[extra_index]; |
| 11181 | extra_index += 1; | 11592 | extra_index += 1; |
| 11182 | const body_len = @truncate(u31, sema.code.extra[extra_index]); | 11593 | const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]); |
| 11183 | const is_inline = sema.code.extra[extra_index] >> 31 != 0; | 11594 | extra_index += 1 + items_len; |
| 11184 | extra_index += 1; | 11595 | |
| 11185 | const items = sema.code.refSlice(extra_index, items_len); | 11596 | const items = case_vals.items[case_val_idx..][0..items_len]; |
| 11186 | extra_index += items_len; | 11597 | case_val_idx += items_len; |
| 11187 | | 11598 | |
| 11188 | case_block.instructions.shrinkRetainingCapacity(0); | 11599 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11189 | case_block.wip_capture_scope = child_block.wip_capture_scope; | 11600 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 11190 | case_block.inline_case_capture = .none; | | |
| 11191 | | 11601 | |
| 11192 | // Generate all possible cases as scalar prongs. | 11602 | // Generate all possible cases as scalar prongs. |
| 11193 | if (is_inline) { | 11603 | if (info.is_inline) { |
| 11194 | const body_start = extra_index + 2 * ranges_len; | 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 | var emit_bb = false; | 11606 | var emit_bb = false; |
| 11197 | | 11607 | |
| 11198 | var range_i: u32 = 0; | 11608 | var range_i: u32 = 0; |
| 11199 | while (range_i < ranges_len) : (range_i += 1) { | 11609 | while (range_i < ranges_len) : (range_i += 1) { |
| 11200 | const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 11610 | const range_items = case_vals.items[case_val_idx..][0..2]; |
| 11201 | extra_index += 1; | 11611 | extra_index += 2; |
| 11202 | const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 11612 | case_val_idx += 2; |
| 11203 | extra_index += 1; | 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 | var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable; | 11617 | var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable; |
| 11207 | const item_last_ref = try sema.resolveInst(last_ref); | | |
| 11208 | const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable; | 11618 | const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable; |
| 11209 | | 11619 | |
| 11210 | while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({ | 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,7 +11627,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11217 | cases_len += 1; | 11627 | cases_len += 1; |
| 11218 | | 11628 | |
| 11219 | const item_ref = try sema.addConstant(operand_ty, item); | 11629 | const item_ref = try sema.addConstant(operand_ty, item); |
| 11220 | case_block.inline_case_capture = item_ref; | | |
| 11221 | | 11630 | |
| 11222 | case_block.instructions.shrinkRetainingCapacity(0); | 11631 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11223 | case_block.wip_capture_scope = child_block.wip_capture_scope; | 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,22 +11642,28 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11233 | }; | 11642 | }; |
| 11234 | emit_bb = true; | 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 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); | 11656 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11239 | cases_extra.appendAssumeCapacity(1); // items_len | 11657 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11240 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); | 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 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); | 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 | cases_len += 1; | 11665 | cases_len += 1; |
| 11248 | | 11666 | |
| 11249 | const item = try sema.resolveInst(item_ref); | | |
| 11250 | case_block.inline_case_capture = item; | | |
| 11251 | | | |
| 11252 | case_block.instructions.shrinkRetainingCapacity(0); | 11667 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11253 | case_block.wip_capture_scope = child_block.wip_capture_scope; | 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,7 +11685,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11270 | emit_bb = true; | 11685 | emit_bb = true; |
| 11271 | | 11686 | |
| 11272 | if (analyze_body) { | 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 | } else { | 11698 | } else { |
| 11275 | _ = try case_block.addNoOp(.unreach); | 11699 | _ = try case_block.addNoOp(.unreach); |
| 11276 | } | 11700 | } |
| ... | @@ -11278,11 +11702,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11278,11 +11702,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11278 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); | 11702 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11279 | cases_extra.appendAssumeCapacity(1); // items_len | 11703 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11280 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); | 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 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); | 11706 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11283 | } | 11707 | } |
| 11284 | | 11708 | |
| 11285 | extra_index += body_len; | 11709 | extra_index += info.body_len; |
| 11286 | continue; | 11710 | continue; |
| 11287 | } | 11711 | } |
| 11288 | | 11712 | |
| ... | @@ -11295,8 +11719,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11295,8 +11719,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11295 | cases_len += 1; | 11719 | cases_len += 1; |
| 11296 | | 11720 | |
| 11297 | const analyze_body = if (union_originally) | 11721 | const analyze_body = if (union_originally) |
| 11298 | for (items) |item_ref| { | 11722 | for (items) |item| { |
| 11299 | const item = try sema.resolveInst(item_ref); | | |
| 11300 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; | 11723 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; |
| 11301 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); | 11724 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); |
| 11302 | if (field_ty.zigTypeTag(mod) != .NoReturn) break true; | 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,12 +11727,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11304 | else | 11727 | else |
| 11305 | true; | 11728 | true; |
| 11306 | | 11729 | |
| 11307 | const body = sema.code.extra[extra_index..][0..body_len]; | 11730 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11308 | extra_index += body_len; | 11731 | extra_index += info.body_len; |
| 11309 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { | 11732 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { |
| 11310 | // nothing to do here | 11733 | // nothing to do here |
| 11311 | } else if (analyze_body) { | 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 | } else { | 11745 | } else { |
| 11314 | _ = try case_block.addNoOp(.unreach); | 11746 | _ = try case_block.addNoOp(.unreach); |
| 11315 | } | 11747 | } |
| ... | @@ -11320,15 +11752,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11320,15 +11752,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11320 | cases_extra.appendAssumeCapacity(@intCast(u32, items.len)); | 11752 | cases_extra.appendAssumeCapacity(@intCast(u32, items.len)); |
| 11321 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); | 11753 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); |
| 11322 | | 11754 | |
| 11323 | for (items) |item_ref| { | 11755 | for (items) |item| { |
| 11324 | const item = try sema.resolveInst(item_ref); | | |
| 11325 | cases_extra.appendAssumeCapacity(@enumToInt(item)); | 11756 | cases_extra.appendAssumeCapacity(@enumToInt(item)); |
| 11326 | } | 11757 | } |
| 11327 | | 11758 | |
| 11328 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); | 11759 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11329 | } else { | 11760 | } else { |
| 11330 | for (items) |item_ref| { | 11761 | for (items) |item| { |
| 11331 | const item = try sema.resolveInst(item_ref); | | |
| 11332 | const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item); | 11762 | const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item); |
| 11333 | if (any_ok != .none) { | 11763 | if (any_ok != .none) { |
| 11334 | any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok); | 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,13 +11769,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11339 | | 11769 | |
| 11340 | var range_i: usize = 0; | 11770 | var range_i: usize = 0; |
| 11341 | while (range_i < ranges_len) : (range_i += 1) { | 11771 | while (range_i < ranges_len) : (range_i += 1) { |
| 11342 | const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 11772 | const range_items = case_vals.items[case_val_idx..][0..2]; |
| 11343 | extra_index += 1; | 11773 | extra_index += 2; |
| 11344 | const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 11774 | case_val_idx += 2; |
| 11345 | extra_index += 1; | | |
| 11346 | | 11775 | |
| 11347 | const item_first = try sema.resolveInst(first_ref); | 11776 | const item_first = range_items[0]; |
| 11348 | const item_last = try sema.resolveInst(last_ref); | 11777 | const item_last = range_items[1]; |
| 11349 | | 11778 | |
| 11350 | // operand >= first and operand <= last | 11779 | // operand >= first and operand <= last |
| 11351 | const range_first_ok = try case_block.addBinOp( | 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,12 +11814,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11385 | case_block.instructions.shrinkRetainingCapacity(0); | 11814 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11386 | case_block.wip_capture_scope = wip_captures.scope; | 11815 | case_block.wip_capture_scope = wip_captures.scope; |
| 11387 | | 11816 | |
| 11388 | const body = sema.code.extra[extra_index..][0..body_len]; | 11817 | const body = sema.code.extra[extra_index..][0..info.body_len]; |
| 11389 | extra_index += body_len; | 11818 | extra_index += info.body_len; |
| 11390 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { | 11819 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { |
| 11391 | // nothing to do here | 11820 | // nothing to do here |
| 11392 | } else { | 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 | try wip_captures.finalize(); | 11834 | try wip_captures.finalize(); |
| ... | @@ -11435,7 +11873,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11435,7 +11873,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11435 | | 11873 | |
| 11436 | const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i)); | 11874 | const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i)); |
| 11437 | const item_ref = try sema.addConstant(operand_ty, item_val); | 11875 | const item_ref = try sema.addConstant(operand_ty, item_val); |
| 11438 | case_block.inline_case_capture = item_ref; | | |
| 11439 | | 11876 | |
| 11440 | case_block.instructions.shrinkRetainingCapacity(0); | 11877 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11441 | case_block.wip_capture_scope = child_block.wip_capture_scope; | 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,7 +11886,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11449 | emit_bb = true; | 11886 | emit_bb = true; |
| 11450 | | 11887 | |
| 11451 | if (analyze_body) { | 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 | } else { | 11899 | } else { |
| 11454 | _ = try case_block.addNoOp(.unreach); | 11900 | _ = try case_block.addNoOp(.unreach); |
| 11455 | } | 11901 | } |
| ... | @@ -11457,7 +11903,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11457,7 +11903,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11457 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); | 11903 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11458 | cases_extra.appendAssumeCapacity(1); // items_len | 11904 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11459 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); | 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 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); | 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,7 +11923,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11477 | .name = error_name, | 11923 | .name = error_name, |
| 11478 | } }); | 11924 | } }); |
| 11479 | const item_ref = try sema.addConstant(operand_ty, item_val.toValue()); | 11925 | const item_ref = try sema.addConstant(operand_ty, item_val.toValue()); |
| 11480 | case_block.inline_case_capture = item_ref; | | |
| 11481 | | 11926 | |
| 11482 | case_block.instructions.shrinkRetainingCapacity(0); | 11927 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11483 | case_block.wip_capture_scope = child_block.wip_capture_scope; | 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,12 +11930,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11485 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); | 11930 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11486 | emit_bb = true; | 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 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); | 11944 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11491 | cases_extra.appendAssumeCapacity(1); // items_len | 11945 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11492 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); | 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 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); | 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,7 +11954,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11500 | cases_len += 1; | 11954 | cases_len += 1; |
| 11501 | | 11955 | |
| 11502 | const item_ref = try sema.addConstant(operand_ty, cur.toValue()); | 11956 | const item_ref = try sema.addConstant(operand_ty, cur.toValue()); |
| 11503 | case_block.inline_case_capture = item_ref; | | |
| 11504 | | 11957 | |
| 11505 | case_block.instructions.shrinkRetainingCapacity(0); | 11958 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11506 | case_block.wip_capture_scope = child_block.wip_capture_scope; | 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,19 +11961,27 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11508 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); | 11961 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11509 | emit_bb = true; | 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 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); | 11975 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11514 | cases_extra.appendAssumeCapacity(1); // items_len | 11976 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11515 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); | 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 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); | 11979 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11518 | } | 11980 | } |
| 11519 | }, | 11981 | }, |
| 11520 | .Bool => { | 11982 | .Bool => { |
| 11521 | if (true_count == 0) { | 11983 | if (true_count == 0) { |
| 11522 | cases_len += 1; | 11984 | cases_len += 1; |
| 11523 | case_block.inline_case_capture = Air.Inst.Ref.bool_true; | | |
| 11524 | | 11985 | |
| 11525 | case_block.instructions.shrinkRetainingCapacity(0); | 11986 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11526 | case_block.wip_capture_scope = child_block.wip_capture_scope; | 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,17 +11989,25 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11528 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); | 11989 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11529 | emit_bb = true; | 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 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); | 12003 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11534 | cases_extra.appendAssumeCapacity(1); // items_len | 12004 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11535 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); | 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 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); | 12007 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); |
| 11538 | } | 12008 | } |
| 11539 | if (false_count == 0) { | 12009 | if (false_count == 0) { |
| 11540 | cases_len += 1; | 12010 | cases_len += 1; |
| 11541 | case_block.inline_case_capture = Air.Inst.Ref.bool_false; | | |
| 11542 | | 12011 | |
| 11543 | case_block.instructions.shrinkRetainingCapacity(0); | 12012 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11544 | case_block.wip_capture_scope = child_block.wip_capture_scope; | 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,12 +12015,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11546 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); | 12015 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| 11547 | emit_bb = true; | 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 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); | 12029 | try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len); |
| 11552 | cases_extra.appendAssumeCapacity(1); // items_len | 12030 | cases_extra.appendAssumeCapacity(1); // items_len |
| 11553 | cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len)); | 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 | cases_extra.appendSliceAssumeCapacity(case_block.instructions.items); | 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,7 +12043,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11565 | | 12043 | |
| 11566 | case_block.instructions.shrinkRetainingCapacity(0); | 12044 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11567 | case_block.wip_capture_scope = wip_captures.scope; | 12045 | case_block.wip_capture_scope = wip_captures.scope; |
| 11568 | case_block.inline_case_capture = .none; | | |
| 11569 | | 12046 | |
| 11570 | if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and | 12047 | if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and |
| 11571 | operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) | 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,7 +12066,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11589 | { | 12066 | { |
| 11590 | // nothing to do here | 12067 | // nothing to do here |
| 11591 | } else if (special.body.len != 0 and analyze_body and !special.is_inline) { | 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 | } else { | 12079 | } else { |
| 11594 | // We still need a terminator in this block, but we have proven | 12080 | // We still need a terminator in this block, but we have proven |
| 11595 | // that it is unreachable. | 12081 | // that it is unreachable. |
| ... | @@ -11704,29 +12190,51 @@ const RangeSetUnhandledIterator = struct { | ... | @@ -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 | fn resolveSwitchItemVal( | 12197 | fn resolveSwitchItemVal( |
| 11708 | sema: *Sema, | 12198 | sema: *Sema, |
| 11709 | block: *Block, | 12199 | block: *Block, |
| 11710 | item_ref: Zir.Inst.Ref, | 12200 | item_ref: Zir.Inst.Ref, |
| | 12201 | /// Coerce `item_ref` to this type. |
| | 12202 | coerce_ty: Type, |
| 11711 | switch_node_offset: i32, | 12203 | switch_node_offset: i32, |
| 11712 | switch_prong_src: Module.SwitchProngSrc, | 12204 | switch_prong_src: Module.SwitchProngSrc, |
| 11713 | range_expand: Module.SwitchProngSrc.RangeExpand, | 12205 | range_expand: Module.SwitchProngSrc.RangeExpand, |
| 11714 | ) CompileError!InternPool.Index { | 12206 | ) CompileError!ResolvedSwitchItem { |
| 11715 | const mod = sema.mod; | 12207 | const mod = sema.mod; |
| 11716 | const item = try sema.resolveInst(item_ref); | 12208 | const uncoerced_item = try sema.resolveInst(item_ref); |
| | 12209 | |
| 11717 | // Constructing a LazySrcLoc is costly because we only have the switch AST node. | 12210 | // Constructing a LazySrcLoc is costly because we only have the switch AST node. |
| 11718 | // Only if we know for sure we need to report a compile error do we resolve the | 12211 | // Only if we know for sure we need to report a compile error do we resolve the |
| 11719 | // full source locations. | 12212 | // full source locations. |
| 11720 | if (sema.resolveConstLazyValue(block, .unneeded, item, "")) |val| { | 12213 | |
| 11721 | return val.toIntern(); | 12214 | const item = sema.coerce(block, coerce_ty, uncoerced_item, .unneeded) catch |err| switch (err) { |
| 11722 | } else |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 | error.NeededSourceLocation => { | 12224 | error.NeededSourceLocation => { |
| 11724 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand); | 12225 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand); |
| 11725 | _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known"); | 12226 | _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known"); |
| 11726 | unreachable; | 12227 | unreachable; |
| 11727 | }, | 12228 | }, |
| 11728 | else => |e| return e, | 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 | fn validateSwitchRange( | 12240 | fn validateSwitchRange( |
| ... | @@ -11735,31 +12243,35 @@ fn validateSwitchRange( | ... | @@ -11735,31 +12243,35 @@ fn validateSwitchRange( |
| 11735 | range_set: *RangeSet, | 12243 | range_set: *RangeSet, |
| 11736 | first_ref: Zir.Inst.Ref, | 12244 | first_ref: Zir.Inst.Ref, |
| 11737 | last_ref: Zir.Inst.Ref, | 12245 | last_ref: Zir.Inst.Ref, |
| | 12246 | operand_ty: Type, |
| 11738 | src_node_offset: i32, | 12247 | src_node_offset: i32, |
| 11739 | switch_prong_src: Module.SwitchProngSrc, | 12248 | switch_prong_src: Module.SwitchProngSrc, |
| 11740 | ) CompileError!void { | 12249 | ) CompileError![2]Air.Inst.Ref { |
| 11741 | const mod = sema.mod; | 12250 | const mod = sema.mod; |
| 11742 | const first = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first); | 12251 | const first = try sema.resolveSwitchItemVal(block, first_ref, operand_ty, src_node_offset, switch_prong_src, .first); |
| 11743 | const last = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last); | 12252 | const last = try sema.resolveSwitchItemVal(block, last_ref, operand_ty, src_node_offset, switch_prong_src, .last); |
| 11744 | if (first.toValue().compareScalar(.gt, last.toValue(), mod.intern_pool.typeOf(first).toType(), mod)) { | 12253 | if (try first.val.toValue().compareAll(.gt, last.val.toValue(), operand_ty, mod)) { |
| 11745 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first); | 12254 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first); |
| 11746 | return sema.fail(block, src, "range start value is greater than the end value", .{}); | 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); | 12257 | const maybe_prev_src = try range_set.add(first.val, last.val, switch_prong_src); |
| 11749 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); | 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 | sema: *Sema, | 12263 | sema: *Sema, |
| 11754 | block: *Block, | 12264 | block: *Block, |
| 11755 | range_set: *RangeSet, | 12265 | range_set: *RangeSet, |
| 11756 | item_ref: Zir.Inst.Ref, | 12266 | item_ref: Zir.Inst.Ref, |
| | 12267 | operand_ty: Type, |
| 11757 | src_node_offset: i32, | 12268 | src_node_offset: i32, |
| 11758 | switch_prong_src: Module.SwitchProngSrc, | 12269 | switch_prong_src: Module.SwitchProngSrc, |
| 11759 | ) CompileError!void { | 12270 | ) CompileError!Air.Inst.Ref { |
| 11760 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 12271 | const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none); |
| 11761 | const maybe_prev_src = try range_set.add(item, item, switch_prong_src); | 12272 | const maybe_prev_src = try range_set.add(item.val, item.val, switch_prong_src); |
| 11762 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); | 12273 | try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| | 12274 | return item.ref; |
| 11763 | } | 12275 | } |
| 11764 | | 12276 | |
| 11765 | fn validateSwitchItemEnum( | 12277 | fn validateSwitchItemEnum( |
| ... | @@ -11768,19 +12280,22 @@ fn validateSwitchItemEnum( | ... | @@ -11768,19 +12280,22 @@ fn validateSwitchItemEnum( |
| 11768 | seen_fields: []?Module.SwitchProngSrc, | 12280 | seen_fields: []?Module.SwitchProngSrc, |
| 11769 | range_set: *RangeSet, | 12281 | range_set: *RangeSet, |
| 11770 | item_ref: Zir.Inst.Ref, | 12282 | item_ref: Zir.Inst.Ref, |
| | 12283 | operand_ty: Type, |
| 11771 | src_node_offset: i32, | 12284 | src_node_offset: i32, |
| 11772 | switch_prong_src: Module.SwitchProngSrc, | 12285 | switch_prong_src: Module.SwitchProngSrc, |
| 11773 | ) CompileError!void { | 12286 | ) CompileError!Air.Inst.Ref { |
| 11774 | const ip = &sema.mod.intern_pool; | 12287 | const ip = &sema.mod.intern_pool; |
| 11775 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 12288 | const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none); |
| 11776 | const int = ip.indexToKey(item).enum_tag.int; | 12289 | const int = ip.indexToKey(item.val).enum_tag.int; |
| 11777 | const field_index = ip.indexToKey(ip.typeOf(item)).enum_type.tagValueIndex(ip, int) orelse { | 12290 | const field_index = ip.indexToKey(ip.typeOf(item.val)).enum_type.tagValueIndex(ip, int) orelse { |
| 11778 | const maybe_prev_src = try range_set.add(int, int, switch_prong_src); | 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 | const maybe_prev_src = seen_fields[field_index]; | 12295 | const maybe_prev_src = seen_fields[field_index]; |
| 11782 | seen_fields[field_index] = switch_prong_src; | 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 | fn validateSwitchItemError( | 12301 | fn validateSwitchItemError( |
| ... | @@ -11788,18 +12303,19 @@ fn validateSwitchItemError( | ... | @@ -11788,18 +12303,19 @@ fn validateSwitchItemError( |
| 11788 | block: *Block, | 12303 | block: *Block, |
| 11789 | seen_errors: *SwitchErrorSet, | 12304 | seen_errors: *SwitchErrorSet, |
| 11790 | item_ref: Zir.Inst.Ref, | 12305 | item_ref: Zir.Inst.Ref, |
| | 12306 | operand_ty: Type, |
| 11791 | src_node_offset: i32, | 12307 | src_node_offset: i32, |
| 11792 | switch_prong_src: Module.SwitchProngSrc, | 12308 | switch_prong_src: Module.SwitchProngSrc, |
| 11793 | ) CompileError!void { | 12309 | ) CompileError!Air.Inst.Ref { |
| 11794 | const ip = &sema.mod.intern_pool; | 12310 | const ip = &sema.mod.intern_pool; |
| 11795 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 12311 | const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none); |
| 11796 | // TODO: Do i need to typecheck here? | 12312 | const error_name = ip.indexToKey(item.val).err.name; |
| 11797 | const error_name = ip.indexToKey(item).err.name; | | |
| 11798 | const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev| | 12313 | const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev| |
| 11799 | prev.value | 12314 | prev.value |
| 11800 | else | 12315 | else |
| 11801 | null; | 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 | fn validateSwitchDupe( | 12321 | fn validateSwitchDupe( |
| ... | @@ -11842,19 +12358,20 @@ fn validateSwitchItemBool( | ... | @@ -11842,19 +12358,20 @@ fn validateSwitchItemBool( |
| 11842 | item_ref: Zir.Inst.Ref, | 12358 | item_ref: Zir.Inst.Ref, |
| 11843 | src_node_offset: i32, | 12359 | src_node_offset: i32, |
| 11844 | switch_prong_src: Module.SwitchProngSrc, | 12360 | switch_prong_src: Module.SwitchProngSrc, |
| 11845 | ) CompileError!void { | 12361 | ) CompileError!Air.Inst.Ref { |
| 11846 | const mod = sema.mod; | 12362 | const mod = sema.mod; |
| 11847 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 12363 | const item = try sema.resolveSwitchItemVal(block, item_ref, Type.bool, src_node_offset, switch_prong_src, .none); |
| 11848 | if (item.toValue().toBool()) { | 12364 | if (item.val.toValue().toBool()) { |
| 11849 | true_count.* += 1; | 12365 | true_count.* += 1; |
| 11850 | } else { | 12366 | } else { |
| 11851 | false_count.* += 1; | 12367 | false_count.* += 1; |
| 11852 | } | 12368 | } |
| 11853 | if (true_count.* + false_count.* > 2) { | 12369 | if (true_count.* > 1 or false_count.* > 1) { |
| 11854 | const block_src_decl = mod.declPtr(block.src_decl); | 12370 | const block_src_decl = sema.mod.declPtr(block.src_decl); |
| 11855 | const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); | 12371 | const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); |
| 11856 | return sema.fail(block, src, "duplicate switch value", .{}); | 12372 | return sema.fail(block, src, "duplicate switch value", .{}); |
| 11857 | } | 12373 | } |
| | 12374 | return item.ref; |
| 11858 | } | 12375 | } |
| 11859 | | 12376 | |
| 11860 | const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc); | 12377 | const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc); |
| ... | @@ -11864,12 +12381,14 @@ fn validateSwitchItemSparse( | ... | @@ -11864,12 +12381,14 @@ fn validateSwitchItemSparse( |
| 11864 | block: *Block, | 12381 | block: *Block, |
| 11865 | seen_values: *ValueSrcMap, | 12382 | seen_values: *ValueSrcMap, |
| 11866 | item_ref: Zir.Inst.Ref, | 12383 | item_ref: Zir.Inst.Ref, |
| | 12384 | operand_ty: Type, |
| 11867 | src_node_offset: i32, | 12385 | src_node_offset: i32, |
| 11868 | switch_prong_src: Module.SwitchProngSrc, | 12386 | switch_prong_src: Module.SwitchProngSrc, |
| 11869 | ) CompileError!void { | 12387 | ) CompileError!Air.Inst.Ref { |
| 11870 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 12388 | const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none); |
| 11871 | const kv = (try seen_values.fetchPut(sema.gpa, item, switch_prong_src)) orelse return; | 12389 | const kv = (try seen_values.fetchPut(sema.gpa, item.val, switch_prong_src)) orelse return item.ref; |
| 11872 | return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset); | 12390 | try sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset); |
| | 12391 | unreachable; |
| 11873 | } | 12392 | } |
| 11874 | | 12393 | |
| 11875 | fn validateSwitchNoRange( | 12394 | fn validateSwitchNoRange( |