| ... | ... | @@ -10992,51 +10992,67 @@ const SwitchProngAnalysis = struct { |
| 10992 | 10992 | |
| 10993 | 10993 | // By-reference captures have some further restrictions which make them easier to emit |
| 10994 | 10994 | if (capture_byref) { |
| 10995 | const first_field_alignment = union_obj.fieldAlign(ip, first_field_index); |
| 10996 | const same_alignment = for (field_indices[1..]) |field_idx| { |
| 10997 | const field_alignment = union_obj.fieldAlign(ip, field_idx); |
| 10998 | if (field_alignment != first_field_alignment) break false; |
| 10999 | } else true; |
| 10995 | 11000 | const operand_ptr_info = operand_ptr_ty.ptrInfo(mod); |
| 10996 | | const capture_ptr_ty = try sema.ptrType(.{ |
| 10997 | | .child = capture_ty.toIntern(), |
| 10998 | | .flags = .{ |
| 10999 | | // TODO: alignment! |
| 11000 | | .is_const = operand_ptr_info.flags.is_const, |
| 11001 | | .is_volatile = operand_ptr_info.flags.is_volatile, |
| 11002 | | .address_space = operand_ptr_info.flags.address_space, |
| 11003 | | }, |
| 11004 | | }); |
| 11005 | | |
| 11006 | | // By-ref captures of hetereogeneous types are only allowed if each field |
| 11007 | | // pointer type is in-memory coercible to the capture pointer type. |
| 11008 | | if (!same_types) { |
| 11009 | | for (field_indices, 0..) |field_idx, i| { |
| 11001 | const capture_ptr_ty = if (same_types and same_alignment) same: { |
| 11002 | break :same try sema.ptrType(.{ |
| 11003 | .child = capture_ty.toIntern(), |
| 11004 | .flags = .{ |
| 11005 | .is_const = operand_ptr_info.flags.is_const, |
| 11006 | .is_volatile = operand_ptr_info.flags.is_volatile, |
| 11007 | .address_space = operand_ptr_info.flags.address_space, |
| 11008 | .alignment = first_field_alignment, |
| 11009 | }, |
| 11010 | }); |
| 11011 | } else resolve: { |
| 11012 | // By-ref captures of hetereogeneous types are only allowed if all field |
| 11013 | // pointer types are peer resolvable to each other. |
| 11014 | // We need values to run PTR on, so make a bunch of undef constants. |
| 11015 | const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len); |
| 11016 | for (field_indices, dummy_captures) |field_idx, *dummy| { |
| 11010 | 11017 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]); |
| 11011 | 11018 | const field_ptr_ty = try sema.ptrType(.{ |
| 11012 | 11019 | .child = field_ty.toIntern(), |
| 11013 | 11020 | .flags = .{ |
| 11014 | | // TODO: alignment! |
| 11015 | 11021 | .is_const = operand_ptr_info.flags.is_const, |
| 11016 | 11022 | .is_volatile = operand_ptr_info.flags.is_volatile, |
| 11017 | 11023 | .address_space = operand_ptr_info.flags.address_space, |
| 11024 | .alignment = union_obj.fieldAlign(ip, field_idx), |
| 11018 | 11025 | }, |
| 11019 | 11026 | }); |
| 11020 | | if (.ok != try sema.coerceInMemoryAllowed(block, capture_ptr_ty, field_ptr_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) { |
| 11027 | dummy.* = try mod.undefRef(field_ptr_ty); |
| 11028 | } |
| 11029 | const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len); |
| 11030 | @memset(case_srcs, .unneeded); |
| 11031 | |
| 11032 | break :resolve sema.resolvePeerTypes(block, .unneeded, dummy_captures, .{ .override = case_srcs }) catch |err| switch (err) { |
| 11033 | error.NeededSourceLocation => { |
| 11034 | // This must be a multi-prong so this must be a `multi_capture` src |
| 11021 | 11035 | const multi_idx = raw_capture_src.multi_capture; |
| 11022 | 11036 | const src_decl_ptr = sema.mod.declPtr(block.src_decl); |
| 11037 | for (case_srcs, 0..) |*case_src, i| { |
| 11038 | const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(i) } }; |
| 11039 | case_src.* = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none); |
| 11040 | } |
| 11023 | 11041 | const capture_src = raw_capture_src.resolve(mod, src_decl_ptr, switch_node_offset, .none); |
| 11024 | | const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(i) } }; |
| 11025 | | const case_src = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none); |
| 11026 | | const msg = msg: { |
| 11027 | | const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{}); |
| 11028 | | errdefer msg.destroy(sema.gpa); |
| 11029 | | try sema.errNote(block, case_src, msg, "pointer type child '{}' cannot cast into resolved pointer type child '{}'", .{ |
| 11030 | | field_ty.fmt(sema.mod), |
| 11031 | | capture_ty.fmt(sema.mod), |
| 11032 | | }); |
| 11033 | | try sema.errNote(block, capture_src, msg, "this coercion is only possible when capturing by value", .{}); |
| 11034 | | break :msg msg; |
| 11042 | _ = sema.resolvePeerTypes(block, capture_src, dummy_captures, .{ .override = case_srcs }) catch |err1| switch (err1) { |
| 11043 | error.AnalysisFail => { |
| 11044 | const msg = sema.err orelse return error.AnalysisFail; |
| 11045 | try sema.errNote(block, capture_src, msg, "this coercion is only possible when capturing by value", .{}); |
| 11046 | try sema.reparentOwnedErrorMsg(block, capture_src, msg, "capture group with incompatible types", .{}); |
| 11047 | return error.AnalysisFail; |
| 11048 | }, |
| 11049 | else => |e| return e, |
| 11035 | 11050 | }; |
| 11036 | | return sema.failWithOwnedErrorMsg(block, msg); |
| 11037 | | } |
| 11038 | | } |
| 11039 | | } |
| 11051 | unreachable; |
| 11052 | }, |
| 11053 | else => |e| return e, |
| 11054 | }; |
| 11055 | }; |
| 11040 | 11056 | |
| 11041 | 11057 | if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |op_ptr_val| { |
| 11042 | 11058 | if (op_ptr_val.isUndef(mod)) return mod.undefRef(capture_ptr_ty); |