authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-06-13 18:50:53+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-06-13 21:48:21+01:00
log8a92beb088c5eb890f0b662ca6e0c8d68b72fd6a
tree3acb3639945161008da3092313ed8a7eb107315e
parent588f45a0a1492711b2cd9991ba8e9137e583e513
signaturelock-open Commit is signed but in an unrecognized format.

Sema: move all in-memory coercion logic to InternPool

Previously, this logic was split between Sema.coerceValueInMemory and InternPool.getCoerced. This led to issues when trying to coerce e.g. an optional containing an aggregate, because we'd call through to InternPool's version which only recurses on itself so could not coerce aggregates. Unifying them is fairly simple, and also simplified a bit of logic in Sema. Also fixes a key lifetime bug in aggregate coercion.

2 files changed, 166 insertions(+), 238 deletions(-)

src/InternPool.zig+93
...@@ -4568,6 +4568,7 @@ pub fn sliceLen(ip: *const InternPool, i: Index) Index {...@@ -4568,6 +4568,7 @@ pub fn sliceLen(ip: *const InternPool, i: Index) Index {
4568/// * int <=> int4568/// * int <=> int
4569/// * int <=> enum4569/// * int <=> enum
4570/// * enum_literal => enum4570/// * enum_literal => enum
4571/// * float <=> float
4571/// * ptr <=> ptr4572/// * ptr <=> ptr
4572/// * opt ptr <=> ptr4573/// * opt ptr <=> ptr
4573/// * opt ptr <=> opt ptr4574/// * opt ptr <=> opt ptr
...@@ -4579,6 +4580,7 @@ pub fn sliceLen(ip: *const InternPool, i: Index) Index {...@@ -4579,6 +4580,7 @@ pub fn sliceLen(ip: *const InternPool, i: Index) Index {
4579/// * error set => error union4580/// * error set => error union
4580/// * payload => error union4581/// * payload => error union
4581/// * fn <=> fn4582/// * fn <=> fn
4583/// * aggregate <=> aggregate (where children can also be coerced)
4582pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {4584pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
4583 const old_ty = ip.typeOf(val);4585 const old_ty = ip.typeOf(val);
4584 if (old_ty == new_ty) return val;4586 if (old_ty == new_ty) return val;
...@@ -4623,6 +4625,23 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al...@@ -4623,6 +4625,23 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
4623 else => if (ip.isIntegerType(new_ty))4625 else => if (ip.isIntegerType(new_ty))
4624 return getCoercedInts(ip, gpa, int, new_ty),4626 return getCoercedInts(ip, gpa, int, new_ty),
4625 },4627 },
4628 .float => |float| switch (ip.indexToKey(new_ty)) {
4629 .simple_type => |simple| switch (simple) {
4630 .f16,
4631 .f32,
4632 .f64,
4633 .f80,
4634 .f128,
4635 .c_longdouble,
4636 .comptime_float,
4637 => return ip.get(gpa, .{ .float = .{
4638 .ty = new_ty,
4639 .storage = float.storage,
4640 } }),
4641 else => {},
4642 },
4643 else => {},
4644 },
4626 .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))4645 .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))
4627 return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),4646 return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),
4628 .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {4647 .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {
...@@ -4688,6 +4707,80 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al...@@ -4688,6 +4707,80 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
4688 .ty = new_ty,4707 .ty = new_ty,
4689 .val = error_union.val,4708 .val = error_union.val,
4690 } }),4709 } }),
4710 .aggregate => |aggregate| {
4711 const new_len = @intCast(usize, ip.aggregateTypeLen(new_ty));
4712 direct: {
4713 const old_ty_child = switch (ip.indexToKey(old_ty)) {
4714 inline .array_type, .vector_type => |seq_type| seq_type.child,
4715 .anon_struct_type, .struct_type => break :direct,
4716 else => unreachable,
4717 };
4718 const new_ty_child = switch (ip.indexToKey(new_ty)) {
4719 inline .array_type, .vector_type => |seq_type| seq_type.child,
4720 .anon_struct_type, .struct_type => break :direct,
4721 else => unreachable,
4722 };
4723 if (old_ty_child != new_ty_child) break :direct;
4724 // TODO: write something like getCoercedInts to avoid needing to dupe here
4725 switch (aggregate.storage) {
4726 .bytes => |bytes| {
4727 const bytes_copy = try gpa.dupe(u8, bytes[0..new_len]);
4728 defer gpa.free(bytes_copy);
4729 return ip.get(gpa, .{ .aggregate = .{
4730 .ty = new_ty,
4731 .storage = .{ .bytes = bytes_copy },
4732 } });
4733 },
4734 .elems => |elems| {
4735 const elems_copy = try gpa.dupe(InternPool.Index, elems[0..new_len]);
4736 defer gpa.free(elems_copy);
4737 return ip.get(gpa, .{ .aggregate = .{
4738 .ty = new_ty,
4739 .storage = .{ .elems = elems_copy },
4740 } });
4741 },
4742 .repeated_elem => |elem| {
4743 return ip.get(gpa, .{ .aggregate = .{
4744 .ty = new_ty,
4745 .storage = .{ .repeated_elem = elem },
4746 } });
4747 },
4748 }
4749 }
4750 // Direct approach failed - we must recursively coerce elems
4751 const agg_elems = try gpa.alloc(InternPool.Index, new_len);
4752 defer gpa.free(agg_elems);
4753 // First, fill the vector with the uncoerced elements. We do this to avoid key
4754 // lifetime issues, since it'll allow us to avoid referencing `aggregate` after we
4755 // begin interning elems.
4756 switch (aggregate.storage) {
4757 .bytes => {
4758 // We have to intern each value here, so unfortunately we can't easily avoid
4759 // the repeated indexToKey calls.
4760 for (agg_elems, 0..) |*elem, i| {
4761 const x = ip.indexToKey(val).aggregate.storage.bytes[i];
4762 elem.* = try ip.get(gpa, .{ .int = .{
4763 .ty = .u8_type,
4764 .storage = .{ .u64 = x },
4765 } });
4766 }
4767 },
4768 .elems => |elems| @memcpy(agg_elems, elems[0..new_len]),
4769 .repeated_elem => |elem| @memset(agg_elems, elem),
4770 }
4771 // Now, coerce each element to its new type.
4772 for (agg_elems, 0..) |*elem, i| {
4773 const new_elem_ty = switch (ip.indexToKey(new_ty)) {
4774 inline .array_type, .vector_type => |seq_type| seq_type.child,
4775 .anon_struct_type => |anon_struct_type| anon_struct_type.types[i],
4776 .struct_type => |struct_type| ip.structPtr(struct_type.index.unwrap().?)
4777 .fields.values()[i].ty.toIntern(),
4778 else => unreachable,
4779 };
4780 elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty);
4781 }
4782 return ip.get(gpa, .{ .aggregate = .{ .ty = new_ty, .storage = .{ .elems = agg_elems } } });
4783 },
4691 else => {},4784 else => {},
4692 },4785 },
4693 }4786 }
src/Sema.zig+73-238
...@@ -23069,7 +23069,7 @@ fn analyzeMinMax(...@@ -23069,7 +23069,7 @@ fn analyzeMinMax(
23069 if (std.debug.runtime_safety) {23069 if (std.debug.runtime_safety) {
23070 assert(try sema.intFitsInType(val, refined_ty, null));23070 assert(try sema.intFitsInType(val, refined_ty, null));
23071 }23071 }
23072 cur_minmax = try sema.coerceInMemory(block, val, orig_ty, refined_ty, src);23072 cur_minmax = try sema.coerceInMemory(val, refined_ty);
23073 }23073 }
2307423074
23075 break :refined refined_ty;23075 break :refined refined_ty;
...@@ -26610,7 +26610,7 @@ fn coerceExtra(...@@ -26610,7 +26610,7 @@ fn coerceExtra(
26610 var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);26610 var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
26611 if (in_memory_result == .ok) {26611 if (in_memory_result == .ok) {
26612 if (maybe_inst_val) |val| {26612 if (maybe_inst_val) |val| {
26613 return sema.coerceInMemory(block, val, inst_ty, dest_ty, dest_ty_src);26613 return sema.coerceInMemory(val, dest_ty);
26614 }26614 }
26615 try sema.requireRuntimeBlock(block, inst_src, null);26615 try sema.requireRuntimeBlock(block, inst_src, null);
26616 return block.addBitCast(dest_ty, inst);26616 return block.addBitCast(dest_ty, inst);
...@@ -27278,89 +27278,12 @@ fn coerceExtra(...@@ -27278,89 +27278,12 @@ fn coerceExtra(
27278 return sema.failWithOwnedErrorMsg(msg);27278 return sema.failWithOwnedErrorMsg(msg);
27279}27279}
2728027280
27281fn coerceValueInMemory(
27282 sema: *Sema,
27283 block: *Block,
27284 val: Value,
27285 src_ty: Type,
27286 dst_ty: Type,
27287 dst_ty_src: LazySrcLoc,
27288) CompileError!Value {
27289 const mod = sema.mod;
27290 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
27291 .aggregate => |aggregate| {
27292 const dst_ty_key = mod.intern_pool.indexToKey(dst_ty.toIntern());
27293 const dest_len = try sema.usizeCast(
27294 block,
27295 dst_ty_src,
27296 mod.intern_pool.aggregateTypeLen(dst_ty.toIntern()),
27297 );
27298 direct: {
27299 const src_ty_child = switch (mod.intern_pool.indexToKey(src_ty.toIntern())) {
27300 inline .array_type, .vector_type => |seq_type| seq_type.child,
27301 .anon_struct_type, .struct_type => break :direct,
27302 else => unreachable,
27303 };
27304 const dst_ty_child = switch (dst_ty_key) {
27305 inline .array_type, .vector_type => |seq_type| seq_type.child,
27306 .anon_struct_type, .struct_type => break :direct,
27307 else => unreachable,
27308 };
27309 if (src_ty_child != dst_ty_child) break :direct;
27310 // TODO: write something like getCoercedInts to avoid needing to dupe
27311 return (try mod.intern(.{ .aggregate = .{
27312 .ty = dst_ty.toIntern(),
27313 .storage = switch (aggregate.storage) {
27314 .bytes => |bytes| .{ .bytes = try sema.arena.dupe(u8, bytes[0..dest_len]) },
27315 .elems => |elems| .{ .elems = try sema.arena.dupe(InternPool.Index, elems[0..dest_len]) },
27316 .repeated_elem => |elem| .{ .repeated_elem = elem },
27317 },
27318 } })).toValue();
27319 }
27320 const dest_elems = try sema.arena.alloc(InternPool.Index, dest_len);
27321 for (dest_elems, 0..) |*dest_elem, i| {
27322 const elem_ty = switch (dst_ty_key) {
27323 inline .array_type, .vector_type => |seq_type| seq_type.child,
27324 .anon_struct_type => |anon_struct_type| anon_struct_type.types[i],
27325 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?
27326 .fields.values()[i].ty.toIntern(),
27327 else => unreachable,
27328 };
27329 const cur_val = switch (aggregate.storage) {
27330 .bytes => |bytes| (try mod.intValue(Type.u8, bytes[i])).toIntern(),
27331 .elems => |elems| elems[i],
27332 .repeated_elem => |elem| elem,
27333 };
27334 dest_elem.* = (try sema.coerceValueInMemory(
27335 block,
27336 cur_val.toValue(),
27337 mod.intern_pool.typeOf(cur_val).toType(),
27338 elem_ty.toType(),
27339 dst_ty_src,
27340 )).toIntern();
27341 }
27342 return (try mod.intern(.{ .aggregate = .{
27343 .ty = dst_ty.toIntern(),
27344 .storage = .{ .elems = dest_elems },
27345 } })).toValue();
27346 },
27347 .float => |float| (try mod.intern(.{ .float = .{
27348 .ty = dst_ty.toIntern(),
27349 .storage = float.storage,
27350 } })).toValue(),
27351 else => try mod.getCoerced(val, dst_ty),
27352 };
27353}
27354
27355fn coerceInMemory(27281fn coerceInMemory(
27356 sema: *Sema,27282 sema: *Sema,
27357 block: *Block,
27358 val: Value,27283 val: Value,
27359 src_ty: Type,
27360 dst_ty: Type,27284 dst_ty: Type,
27361 dst_ty_src: LazySrcLoc,
27362) CompileError!Air.Inst.Ref {27285) CompileError!Air.Inst.Ref {
27363 return sema.addConstant(dst_ty, try sema.coerceValueInMemory(block, val, src_ty, dst_ty, dst_ty_src));27286 return sema.addConstant(dst_ty, try sema.mod.getCoerced(val, dst_ty));
27364}27287}
2736527288
27366const InMemoryCoercionResult = union(enum) {27289const InMemoryCoercionResult = union(enum) {
...@@ -29820,7 +29743,7 @@ fn coerceArrayLike(...@@ -29820,7 +29743,7 @@ fn coerceArrayLike(
29820 if (in_memory_result == .ok) {29743 if (in_memory_result == .ok) {
29821 if (try sema.resolveMaybeUndefVal(inst)) |inst_val| {29744 if (try sema.resolveMaybeUndefVal(inst)) |inst_val| {
29822 // These types share the same comptime value representation.29745 // These types share the same comptime value representation.
29823 return sema.coerceInMemory(block, inst_val, inst_ty, dest_ty, dest_ty_src);29746 return sema.coerceInMemory(inst_val, dest_ty);
29824 }29747 }
29825 try sema.requireRuntimeBlock(block, inst_src, null);29748 try sema.requireRuntimeBlock(block, inst_src, null);
29826 return block.addBitCast(dest_ty, inst);29749 return block.addBitCast(dest_ty, inst);
...@@ -31653,40 +31576,12 @@ const PeerResolveStrategy = enum {...@@ -31653,40 +31576,12 @@ const PeerResolveStrategy = enum {
31653 /// The peers must all be of the same type.31576 /// The peers must all be of the same type.
31654 exact,31577 exact,
3165531578
31656 const Reason = struct {
31657 peers: std.DynamicBitSet,
31658 fn reset(r: *Reason) void {
31659 r.peers.setRangeValue(.{ .start = 0, .end = r.peers.capacity() }, false);
31660 }
31661 };
31662
31663 fn name(s: PeerResolveStrategy) []const u8 {
31664 return switch (s) {
31665 .unknown, .exact => "exact",
31666 .error_set => "error set",
31667 .error_union => "error union",
31668 .nullable => "null",
31669 .optional => "optional",
31670 .array => "array",
31671 .vector => "vector",
31672 .c_ptr => "C pointer",
31673 .ptr => "pointer",
31674 .func => "function",
31675 .enum_or_union => "enum or union",
31676 .comptime_int => "comptime_int",
31677 .comptime_float => "comptime_float",
31678 .fixed_int => "fixed-width int",
31679 .fixed_float => "fixed-width float",
31680 .coercible_struct => "anonymous struct or tuple",
31681 };
31682 }
31683
31684 /// Given two strategies, find a strategy that satisfies both, if one exists. If no such31579 /// Given two strategies, find a strategy that satisfies both, if one exists. If no such
31685 /// strategy exists, any strategy may be returned; an error will be emitted when the caller31580 /// strategy exists, any strategy may be returned; an error will be emitted when the caller
31686 /// attempts to use the strategy to resolve the type.31581 /// attempts to use the strategy to resolve the type.
31687 /// Strategy `a` comes from the peers set in `reason`, while strategy `b` comes from the peer at31582 /// Strategy `a` comes from the peer in `reason_peer`, while strategy `b` comes from the peer at
31688 /// index `b_peer_idx`. `reason` will be updated to reflect the reason for the new strategy.31583 /// index `b_peer_idx`. `reason_peer` is updated to reflect the reason for the new strategy.
31689 fn merge(a: PeerResolveStrategy, b: PeerResolveStrategy, reason: *Reason, b_peer_idx: usize) PeerResolveStrategy {31584 fn merge(a: PeerResolveStrategy, b: PeerResolveStrategy, reason_peer: *usize, b_peer_idx: usize) PeerResolveStrategy {
31690 // Our merging should be order-independent. Thus, even though the union order is arbitrary,31585 // Our merging should be order-independent. Thus, even though the union order is arbitrary,
31691 // by sorting the tags and switching first on the smaller, we have half as many cases to31586 // by sorting the tags and switching first on the smaller, we have half as many cases to
31692 // worry about (since we avoid the duplicates).31587 // worry about (since we avoid the duplicates).
...@@ -31698,14 +31593,13 @@ const PeerResolveStrategy = enum {...@@ -31698,14 +31593,13 @@ const PeerResolveStrategy = enum {
31698 all_s0,31593 all_s0,
31699 all_s1,31594 all_s1,
31700 either,31595 either,
31701 both,
31702 };31596 };
3170331597
31704 const res: struct { ReasonMethod, PeerResolveStrategy } = switch (s0) {31598 const res: struct { ReasonMethod, PeerResolveStrategy } = switch (s0) {
31705 .unknown => .{ .all_s1, s1 },31599 .unknown => .{ .all_s1, s1 },
31706 .error_set => switch (s1) {31600 .error_set => switch (s1) {
31707 .error_set => .{ .either, .error_set },31601 .error_set => .{ .either, .error_set },
31708 else => .{ .both, .error_union },31602 else => .{ .all_s0, .error_union },
31709 },31603 },
31710 .error_union => switch (s1) {31604 .error_union => switch (s1) {
31711 .error_union => .{ .either, .error_union },31605 .error_union => .{ .either, .error_union },
...@@ -31714,7 +31608,7 @@ const PeerResolveStrategy = enum {...@@ -31714,7 +31608,7 @@ const PeerResolveStrategy = enum {
31714 .nullable => switch (s1) {31608 .nullable => switch (s1) {
31715 .nullable => .{ .either, .nullable },31609 .nullable => .{ .either, .nullable },
31716 .c_ptr => .{ .all_s1, .c_ptr },31610 .c_ptr => .{ .all_s1, .c_ptr },
31717 else => .{ .both, .optional },31611 else => .{ .all_s0, .optional },
31718 },31612 },
31719 .optional => switch (s1) {31613 .optional => switch (s1) {
31720 .optional => .{ .either, .optional },31614 .optional => .{ .either, .optional },
...@@ -31772,23 +31666,17 @@ const PeerResolveStrategy = enum {...@@ -31772,23 +31666,17 @@ const PeerResolveStrategy = enum {
31772 switch (res[0]) {31666 switch (res[0]) {
31773 .all_s0 => {31667 .all_s0 => {
31774 if (!s0_is_a) {31668 if (!s0_is_a) {
31775 reason.reset();31669 reason_peer.* = b_peer_idx;
31776 reason.peers.set(b_peer_idx);
31777 }31670 }
31778 },31671 },
31779 .all_s1 => {31672 .all_s1 => {
31780 if (s0_is_a) {31673 if (s0_is_a) {
31781 reason.reset();31674 reason_peer.* = b_peer_idx;
31782 reason.peers.set(b_peer_idx);
31783 }31675 }
31784 },31676 },
31785 .either => {31677 .either => {
31786 // Prefer b, since it's a single peer31678 // Prefer the earliest peer
31787 reason.reset();31679 reason_peer.* = @min(reason_peer.*, b_peer_idx);
31788 reason.peers.set(b_peer_idx);
31789 },
31790 .both => {
31791 reason.peers.set(b_peer_idx);
31792 },31680 },
31793 }31681 }
3179431682
...@@ -31820,12 +31708,7 @@ const PeerResolveStrategy = enum {...@@ -31820,12 +31708,7 @@ const PeerResolveStrategy = enum {
31820const PeerResolveResult = union(enum) {31708const PeerResolveResult = union(enum) {
31821 /// The peer type resolution was successful, and resulted in the given type.31709 /// The peer type resolution was successful, and resulted in the given type.
31822 success: Type,31710 success: Type,
31823 /// The chosen strategy was incompatible with the given peer.31711 /// There was some generic conflict between two peers.
31824 bad_strat: struct {
31825 strat: PeerResolveStrategy,
31826 peer_idx: usize,
31827 },
31828 /// There was some conflict between two specific peers.
31829 conflict: struct {31712 conflict: struct {
31830 peer_idx_a: usize,31713 peer_idx_a: usize,
31831 peer_idx_b: usize,31714 peer_idx_b: usize,
...@@ -31847,7 +31730,6 @@ const PeerResolveResult = union(enum) {...@@ -31847,7 +31730,6 @@ const PeerResolveResult = union(enum) {
31847 src: LazySrcLoc,31730 src: LazySrcLoc,
31848 instructions: []const Air.Inst.Ref,31731 instructions: []const Air.Inst.Ref,
31849 candidate_srcs: Module.PeerTypeCandidateSrc,31732 candidate_srcs: Module.PeerTypeCandidateSrc,
31850 strat_reason: PeerResolveStrategy.Reason,
31851 ) !*Module.ErrorMsg {31733 ) !*Module.ErrorMsg {
31852 const mod = sema.mod;31734 const mod = sema.mod;
31853 const decl_ptr = mod.declPtr(block.src_decl);31735 const decl_ptr = mod.declPtr(block.src_decl);
...@@ -31867,41 +31749,6 @@ const PeerResolveResult = union(enum) {...@@ -31867,41 +31749,6 @@ const PeerResolveResult = union(enum) {
3186731749
31868 switch (cur) {31750 switch (cur) {
31869 .success => unreachable,31751 .success => unreachable,
31870 .bad_strat => |bad_strat| bad_strat: {
31871 if (strat_reason.peers.count() == 1) {
31872 // We can write this error more simply as a conflict between two peers
31873 conflict_idx = .{
31874 strat_reason.peers.findFirstSet().?,
31875 bad_strat.peer_idx,
31876 };
31877 break :bad_strat;
31878 }
31879
31880 const fmt = "type resolution strategy failed";
31881 const msg = if (opt_msg) |msg| msg: {
31882 try sema.errNote(block, src, msg, fmt, .{});
31883 break :msg msg;
31884 } else msg: {
31885 const msg = try sema.errMsg(block, src, fmt, .{});
31886 opt_msg = msg;
31887 break :msg msg;
31888 };
31889
31890 const peer_ty = peer_tys[bad_strat.peer_idx];
31891 const peer_src = candidate_srcs.resolve(mod, decl_ptr, bad_strat.peer_idx) orelse src;
31892 try sema.errNote(block, peer_src, msg, "strategy '{s}' failed for type '{}' here", .{ bad_strat.strat.name(), peer_ty.fmt(mod) });
31893
31894 try sema.errNote(block, src, msg, "strategy chosen using {} peers", .{strat_reason.peers.count()});
31895 var it = strat_reason.peers.iterator(.{});
31896 while (it.next()) |strat_peer_idx| {
31897 const strat_peer_ty = peer_tys[strat_peer_idx];
31898 const strat_peer_src = candidate_srcs.resolve(mod, decl_ptr, strat_peer_idx) orelse src;
31899 try sema.errNote(block, strat_peer_src, msg, "peer of type '{}' here", .{strat_peer_ty.fmt(mod)});
31900 }
31901
31902 // No child error
31903 break;
31904 },
31905 .conflict => |conflict| {31752 .conflict => |conflict| {
31906 // Fall through to two-peer conflict handling below31753 // Fall through to two-peer conflict handling below
31907 conflict_idx = .{31754 conflict_idx = .{
...@@ -31925,7 +31772,7 @@ const PeerResolveResult = union(enum) {...@@ -31925,7 +31772,7 @@ const PeerResolveResult = union(enum) {
31925 },31772 },
31926 }31773 }
3192731774
31928 // This is the path for reporting a conflict between two peers.31775 // This is the path for reporting a generic conflict between two peers.
3192931776
31930 if (conflict_idx[1] < conflict_idx[0]) {31777 if (conflict_idx[1] < conflict_idx[0]) {
31931 // b comes first in source, so it's better if it comes first in the error31778 // b comes first in source, so it's better if it comes first in the error
...@@ -31987,14 +31834,10 @@ fn resolvePeerTypes(...@@ -31987,14 +31834,10 @@ fn resolvePeerTypes(
31987 val.* = try sema.resolveMaybeUndefVal(inst);31834 val.* = try sema.resolveMaybeUndefVal(inst);
31988 }31835 }
3198931836
31990 var strat_reason: PeerResolveStrategy.Reason = .{31837 switch (try sema.resolvePeerTypesInner(block, src, peer_tys, peer_vals)) {
31991 .peers = try std.DynamicBitSet.initEmpty(sema.arena, instructions.len),
31992 };
31993
31994 switch (try sema.resolvePeerTypesInner(block, src, peer_tys, peer_vals, &strat_reason)) {
31995 .success => |ty| return ty,31838 .success => |ty| return ty,
31996 else => |result| {31839 else => |result| {
31997 const msg = try result.report(sema, block, src, instructions, candidate_srcs, strat_reason);31840 const msg = try result.report(sema, block, src, instructions, candidate_srcs);
31998 return sema.failWithOwnedErrorMsg(msg);31841 return sema.failWithOwnedErrorMsg(msg);
31999 },31842 },
32000 }31843 }
...@@ -32006,16 +31849,14 @@ fn resolvePeerTypesInner(...@@ -32006,16 +31849,14 @@ fn resolvePeerTypesInner(
32006 src: LazySrcLoc,31849 src: LazySrcLoc,
32007 peer_tys: []?Type,31850 peer_tys: []?Type,
32008 peer_vals: []?Value,31851 peer_vals: []?Value,
32009 strat_reason: *PeerResolveStrategy.Reason,
32010) !PeerResolveResult {31852) !PeerResolveResult {
32011 const mod = sema.mod;31853 const mod = sema.mod;
3201231854
32013 strat_reason.reset();31855 var strat_reason: usize = 0;
32014
32015 var s: PeerResolveStrategy = .unknown;31856 var s: PeerResolveStrategy = .unknown;
32016 for (peer_tys, 0..) |opt_ty, i| {31857 for (peer_tys, 0..) |opt_ty, i| {
32017 const ty = opt_ty orelse continue;31858 const ty = opt_ty orelse continue;
32018 s = s.merge(PeerResolveStrategy.select(ty, mod), strat_reason, i);31859 s = s.merge(PeerResolveStrategy.select(ty, mod), &strat_reason, i);
32019 }31860 }
3202031861
32021 if (s == .unknown) {31862 if (s == .unknown) {
...@@ -32041,9 +31882,9 @@ fn resolvePeerTypesInner(...@@ -32041,9 +31882,9 @@ fn resolvePeerTypesInner(
32041 var final_set: ?Type = null;31882 var final_set: ?Type = null;
32042 for (peer_tys, 0..) |opt_ty, i| {31883 for (peer_tys, 0..) |opt_ty, i| {
32043 const ty = opt_ty orelse continue;31884 const ty = opt_ty orelse continue;
32044 if (ty.zigTypeTag(mod) != .ErrorSet) return .{ .bad_strat = .{31885 if (ty.zigTypeTag(mod) != .ErrorSet) return .{ .conflict = .{
32045 .strat = s,31886 .peer_idx_a = strat_reason,
32046 .peer_idx = i,31887 .peer_idx_b = i,
32047 } };31888 } };
32048 if (final_set) |cur_set| {31889 if (final_set) |cur_set| {
32049 final_set = try sema.maybeMergeErrorSets(block, src, cur_set, ty);31890 final_set = try sema.maybeMergeErrorSets(block, src, cur_set, ty);
...@@ -32091,7 +31932,6 @@ fn resolvePeerTypesInner(...@@ -32091,7 +31932,6 @@ fn resolvePeerTypesInner(
32091 src,31932 src,
32092 peer_tys,31933 peer_tys,
32093 peer_vals,31934 peer_vals,
32094 strat_reason,
32095 )) {31935 )) {
32096 .success => |ty| ty,31936 .success => |ty| ty,
32097 else => |result| return result,31937 else => |result| return result,
...@@ -32102,9 +31942,9 @@ fn resolvePeerTypesInner(...@@ -32102,9 +31942,9 @@ fn resolvePeerTypesInner(
32102 .nullable => {31942 .nullable => {
32103 for (peer_tys, 0..) |opt_ty, i| {31943 for (peer_tys, 0..) |opt_ty, i| {
32104 const ty = opt_ty orelse continue;31944 const ty = opt_ty orelse continue;
32105 if (!ty.eql(Type.null, mod)) return .{ .bad_strat = .{31945 if (!ty.eql(Type.null, mod)) return .{ .conflict = .{
32106 .strat = s,31946 .peer_idx_a = strat_reason,
32107 .peer_idx = i,31947 .peer_idx_b = i,
32108 } };31948 } };
32109 }31949 }
32110 return .{ .success = Type.null };31950 return .{ .success = Type.null };
...@@ -32130,7 +31970,6 @@ fn resolvePeerTypesInner(...@@ -32130,7 +31970,6 @@ fn resolvePeerTypesInner(
32130 src,31970 src,
32131 peer_tys,31971 peer_tys,
32132 peer_vals,31972 peer_vals,
32133 strat_reason,
32134 )) {31973 )) {
32135 .success => |ty| ty,31974 .success => |ty| ty,
32136 else => |result| return result,31975 else => |result| return result,
...@@ -32154,9 +31993,9 @@ fn resolvePeerTypesInner(...@@ -32154,9 +31993,9 @@ fn resolvePeerTypesInner(
3215431993
32155 if (!ty.isArrayOrVector(mod)) {31994 if (!ty.isArrayOrVector(mod)) {
32156 // We allow tuples of the correct length. We won't validate their elem type, since the elements can be coerced.31995 // We allow tuples of the correct length. We won't validate their elem type, since the elements can be coerced.
32157 const arr_like = sema.typeIsArrayLike(ty) orelse return .{ .bad_strat = .{31996 const arr_like = sema.typeIsArrayLike(ty) orelse return .{ .conflict = .{
32158 .strat = s,31997 .peer_idx_a = strat_reason,
32159 .peer_idx = i,31998 .peer_idx_b = i,
32160 } };31999 } };
3216132000
32162 if (opt_first_idx) |first_idx| {32001 if (opt_first_idx) |first_idx| {
...@@ -32224,9 +32063,9 @@ fn resolvePeerTypesInner(...@@ -32224,9 +32063,9 @@ fn resolvePeerTypesInner(
3222432063
32225 if (!ty.isArrayOrVector(mod)) {32064 if (!ty.isArrayOrVector(mod)) {
32226 // Allow tuples of the correct length32065 // Allow tuples of the correct length
32227 const arr_like = sema.typeIsArrayLike(ty) orelse return .{ .bad_strat = .{32066 const arr_like = sema.typeIsArrayLike(ty) orelse return .{ .conflict = .{
32228 .strat = s,32067 .peer_idx_a = strat_reason,
32229 .peer_idx = i,32068 .peer_idx_b = i,
32230 } };32069 } };
3223132070
32232 if (len) |expect_len| {32071 if (len) |expect_len| {
...@@ -32266,7 +32105,6 @@ fn resolvePeerTypesInner(...@@ -32266,7 +32105,6 @@ fn resolvePeerTypesInner(
32266 src,32105 src,
32267 peer_tys,32106 peer_tys,
32268 peer_vals,32107 peer_vals,
32269 strat_reason,
32270 )) {32108 )) {
32271 .success => |ty| ty,32109 .success => |ty| ty,
32272 else => |result| return result,32110 else => |result| return result,
...@@ -32300,9 +32138,9 @@ fn resolvePeerTypesInner(...@@ -32300,9 +32138,9 @@ fn resolvePeerTypesInner(
32300 else => {},32138 else => {},
32301 }32139 }
3230232140
32303 if (!ty.isPtrAtRuntime(mod)) return .{ .bad_strat = .{32141 if (!ty.isPtrAtRuntime(mod)) return .{ .conflict = .{
32304 .strat = s,32142 .peer_idx_a = strat_reason,
32305 .peer_idx = i,32143 .peer_idx_b = i,
32306 } };32144 } };
3230732145
32308 // Goes through optionals32146 // Goes through optionals
...@@ -32316,7 +32154,6 @@ fn resolvePeerTypesInner(...@@ -32316,7 +32154,6 @@ fn resolvePeerTypesInner(
32316 };32154 };
3231732155
32318 // Try peer -> cur, then cur -> peer32156 // Try peer -> cur, then cur -> peer
32319 const old_pointee_type = ptr_info.pointee_type;
32320 ptr_info.pointee_type = (try sema.resolvePairInMemoryCoercible(block, src, ptr_info.pointee_type, peer_info.pointee_type)) orelse {32157 ptr_info.pointee_type = (try sema.resolvePairInMemoryCoercible(block, src, ptr_info.pointee_type, peer_info.pointee_type)) orelse {
32321 return .{ .conflict = .{32158 return .{ .conflict = .{
32322 .peer_idx_a = first_idx,32159 .peer_idx_a = first_idx,
...@@ -32325,8 +32162,8 @@ fn resolvePeerTypesInner(...@@ -32325,8 +32162,8 @@ fn resolvePeerTypesInner(
32325 };32162 };
3232632163
32327 if (ptr_info.sentinel != null and peer_info.sentinel != null) {32164 if (ptr_info.sentinel != null and peer_info.sentinel != null) {
32328 const peer_sent = try sema.coerceValueInMemory(block, ptr_info.sentinel.?, old_pointee_type, ptr_info.pointee_type, .unneeded);32165 const peer_sent = try mod.getCoerced(ptr_info.sentinel.?, ptr_info.pointee_type);
32329 const ptr_sent = try sema.coerceValueInMemory(block, peer_info.sentinel.?, peer_info.pointee_type, ptr_info.pointee_type, .unneeded);32166 const ptr_sent = try mod.getCoerced(peer_info.sentinel.?, ptr_info.pointee_type);
32330 if (ptr_sent.eql(peer_sent, ptr_info.pointee_type, mod)) {32167 if (ptr_sent.eql(peer_sent, ptr_info.pointee_type, mod)) {
32331 ptr_info.sentinel = ptr_sent;32168 ptr_info.sentinel = ptr_sent;
32332 } else {32169 } else {
...@@ -32379,18 +32216,18 @@ fn resolvePeerTypesInner(...@@ -32379,18 +32216,18 @@ fn resolvePeerTypesInner(
32379 .pointee_type = ty,32216 .pointee_type = ty,
32380 .@"addrspace" = target_util.defaultAddressSpace(target, .global_constant),32217 .@"addrspace" = target_util.defaultAddressSpace(target, .global_constant),
32381 },32218 },
32382 else => return .{ .bad_strat = .{32219 else => return .{ .conflict = .{
32383 .strat = s,32220 .peer_idx_a = strat_reason,
32384 .peer_idx = i,32221 .peer_idx_b = i,
32385 } },32222 } },
32386 };32223 };
3238732224
32388 switch (peer_info.size) {32225 switch (peer_info.size) {
32389 .One, .Many => {},32226 .One, .Many => {},
32390 .Slice => opt_slice_idx = i,32227 .Slice => opt_slice_idx = i,
32391 .C => return .{ .bad_strat = .{32228 .C => return .{ .conflict = .{
32392 .strat = s,32229 .peer_idx_a = strat_reason,
32393 .peer_idx = i,32230 .peer_idx_b = i,
32394 } },32231 } },
32395 }32232 }
3239632233
...@@ -32605,10 +32442,8 @@ fn resolvePeerTypesInner(...@@ -32605,10 +32442,8 @@ fn resolvePeerTypesInner(
32605 no_sentinel: {32442 no_sentinel: {
32606 if (peer_sentinel == null) break :no_sentinel;32443 if (peer_sentinel == null) break :no_sentinel;
32607 if (cur_sentinel == null) break :no_sentinel;32444 if (cur_sentinel == null) break :no_sentinel;
32608 const peer_sent_ty = mod.intern_pool.typeOf(peer_sentinel.?.toIntern()).toType();32445 const peer_sent_coerced = try mod.getCoerced(peer_sentinel.?, sentinel_ty);
32609 const cur_sent_ty = mod.intern_pool.typeOf(cur_sentinel.?.toIntern()).toType();32446 const cur_sent_coerced = try mod.getCoerced(cur_sentinel.?, sentinel_ty);
32610 const peer_sent_coerced = try sema.coerceValueInMemory(block, peer_sentinel.?, peer_sent_ty, sentinel_ty, .unneeded);
32611 const cur_sent_coerced = try sema.coerceValueInMemory(block, cur_sentinel.?, cur_sent_ty, sentinel_ty, .unneeded);
32612 if (!peer_sent_coerced.eql(cur_sent_coerced, sentinel_ty, mod)) break :no_sentinel;32447 if (!peer_sent_coerced.eql(cur_sent_coerced, sentinel_ty, mod)) break :no_sentinel;
32613 // Sentinels match32448 // Sentinels match
32614 if (ptr_info.size == .One) {32449 if (ptr_info.size == .One) {
...@@ -32664,9 +32499,9 @@ fn resolvePeerTypesInner(...@@ -32664,9 +32499,9 @@ fn resolvePeerTypesInner(
32664 first_idx = i;32499 first_idx = i;
32665 continue;32500 continue;
32666 };32501 };
32667 if (ty.zigTypeTag(mod) != .Fn) return .{ .bad_strat = .{32502 if (ty.zigTypeTag(mod) != .Fn) return .{ .conflict = .{
32668 .strat = s,32503 .peer_idx_a = strat_reason,
32669 .peer_idx = i,32504 .peer_idx_b = i,
32670 } };32505 } };
32671 // ty -> cur_ty32506 // ty -> cur_ty
32672 if (.ok == try sema.coerceInMemoryAllowedFns(block, cur_ty, ty, target, src, src)) {32507 if (.ok == try sema.coerceInMemoryAllowedFns(block, cur_ty, ty, target, src, src)) {
...@@ -32694,9 +32529,9 @@ fn resolvePeerTypesInner(...@@ -32694,9 +32529,9 @@ fn resolvePeerTypesInner(
32694 const ty = opt_ty orelse continue;32529 const ty = opt_ty orelse continue;
32695 switch (ty.zigTypeTag(mod)) {32530 switch (ty.zigTypeTag(mod)) {
32696 .EnumLiteral, .Enum, .Union => {},32531 .EnumLiteral, .Enum, .Union => {},
32697 else => return .{ .bad_strat = .{32532 else => return .{ .conflict = .{
32698 .strat = s,32533 .peer_idx_a = strat_reason,
32699 .peer_idx = i,32534 .peer_idx_b = i,
32700 } },32535 } },
32701 }32536 }
32702 const cur_ty = opt_cur_ty orelse {32537 const cur_ty = opt_cur_ty orelse {
...@@ -32751,9 +32586,9 @@ fn resolvePeerTypesInner(...@@ -32751,9 +32586,9 @@ fn resolvePeerTypesInner(
32751 const ty = opt_ty orelse continue;32586 const ty = opt_ty orelse continue;
32752 switch (ty.zigTypeTag(mod)) {32587 switch (ty.zigTypeTag(mod)) {
32753 .ComptimeInt => {},32588 .ComptimeInt => {},
32754 else => return .{ .bad_strat = .{32589 else => return .{ .conflict = .{
32755 .strat = s,32590 .peer_idx_a = strat_reason,
32756 .peer_idx = i,32591 .peer_idx_b = i,
32757 } },32592 } },
32758 }32593 }
32759 }32594 }
...@@ -32765,9 +32600,9 @@ fn resolvePeerTypesInner(...@@ -32765,9 +32600,9 @@ fn resolvePeerTypesInner(
32765 const ty = opt_ty orelse continue;32600 const ty = opt_ty orelse continue;
32766 switch (ty.zigTypeTag(mod)) {32601 switch (ty.zigTypeTag(mod)) {
32767 .ComptimeInt, .ComptimeFloat => {},32602 .ComptimeInt, .ComptimeFloat => {},
32768 else => return .{ .bad_strat = .{32603 else => return .{ .conflict = .{
32769 .strat = s,32604 .peer_idx_a = strat_reason,
32770 .peer_idx = i,32605 .peer_idx_b = i,
32771 } },32606 } },
32772 }32607 }
32773 }32608 }
...@@ -32789,18 +32624,18 @@ fn resolvePeerTypesInner(...@@ -32789,18 +32624,18 @@ fn resolvePeerTypesInner(
32789 switch (peer_tag) {32624 switch (peer_tag) {
32790 .ComptimeInt => {32625 .ComptimeInt => {
32791 // If the value is undefined, we can't refine to a fixed-width int32626 // If the value is undefined, we can't refine to a fixed-width int
32792 if (opt_val == null or opt_val.?.isUndef(mod)) return .{ .bad_strat = .{32627 if (opt_val == null or opt_val.?.isUndef(mod)) return .{ .conflict = .{
32793 .strat = s,32628 .peer_idx_a = strat_reason,
32794 .peer_idx = i,32629 .peer_idx_b = i,
32795 } };32630 } };
32796 any_comptime_known = true;32631 any_comptime_known = true;
32797 ptr_opt_val.* = try sema.resolveLazyValue(opt_val.?);32632 ptr_opt_val.* = try sema.resolveLazyValue(opt_val.?);
32798 continue;32633 continue;
32799 },32634 },
32800 .Int => {},32635 .Int => {},
32801 else => return .{ .bad_strat = .{32636 else => return .{ .conflict = .{
32802 .strat = s,32637 .peer_idx_a = strat_reason,
32803 .peer_idx = i,32638 .peer_idx_b = i,
32804 } },32639 } },
32805 }32640 }
3280632641
...@@ -32868,9 +32703,9 @@ fn resolvePeerTypesInner(...@@ -32868,9 +32703,9 @@ fn resolvePeerTypesInner(
32868 switch (ty.zigTypeTag(mod)) {32703 switch (ty.zigTypeTag(mod)) {
32869 .ComptimeFloat, .ComptimeInt => {},32704 .ComptimeFloat, .ComptimeInt => {},
32870 .Int => {32705 .Int => {
32871 if (opt_val == null) return .{ .bad_strat = .{32706 if (opt_val == null) return .{ .conflict = .{
32872 .strat = s,32707 .peer_idx_a = strat_reason,
32873 .peer_idx = i,32708 .peer_idx_b = i,
32874 } };32709 } };
32875 },32710 },
32876 .Float => {32711 .Float => {
...@@ -32890,9 +32725,9 @@ fn resolvePeerTypesInner(...@@ -32890,9 +32725,9 @@ fn resolvePeerTypesInner(
32890 opt_cur_ty = ty;32725 opt_cur_ty = ty;
32891 }32726 }
32892 },32727 },
32893 else => return .{ .bad_strat = .{32728 else => return .{ .conflict = .{
32894 .strat = s,32729 .peer_idx_a = strat_reason,
32895 .peer_idx = i,32730 .peer_idx_b = i,
32896 } },32731 } },
32897 }32732 }
32898 }32733 }
...@@ -32915,9 +32750,9 @@ fn resolvePeerTypesInner(...@@ -32915,9 +32750,9 @@ fn resolvePeerTypesInner(
32915 const ty = opt_ty orelse continue;32750 const ty = opt_ty orelse continue;
3291632751
32917 if (!ty.isTupleOrAnonStruct(mod)) {32752 if (!ty.isTupleOrAnonStruct(mod)) {
32918 return .{ .bad_strat = .{32753 return .{ .conflict = .{
32919 .strat = s,32754 .peer_idx_a = strat_reason,
32920 .peer_idx = i,32755 .peer_idx_b = i,
32921 } };32756 } };
32922 }32757 }
3292332758
...@@ -32973,7 +32808,7 @@ fn resolvePeerTypesInner(...@@ -32973,7 +32808,7 @@ fn resolvePeerTypesInner(
32973 }32808 }
3297432809
32975 // Resolve field type recursively32810 // Resolve field type recursively
32976 field_ty.* = switch (try sema.resolvePeerTypesInner(block, src, sub_peer_tys, sub_peer_vals, strat_reason)) {32811 field_ty.* = switch (try sema.resolvePeerTypesInner(block, src, sub_peer_tys, sub_peer_vals)) {
32977 .success => |ty| ty.toIntern(),32812 .success => |ty| ty.toIntern(),
32978 else => |result| {32813 else => |result| {
32979 const result_buf = try sema.arena.create(PeerResolveResult);32814 const result_buf = try sema.arena.create(PeerResolveResult);
...@@ -35538,7 +35373,7 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value...@@ -35538,7 +35373,7 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value
35538 // Move mutable decl values to the InternPool and assert other decls are already in35373 // Move mutable decl values to the InternPool and assert other decls are already in
35539 // the InternPool.35374 // the InternPool.
35540 const uncoerced_val = if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern();35375 const uncoerced_val = if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern();
35541 const coerced_val = try sema.coerceValueInMemory(block, uncoerced_val.toValue(), tv.ty, load_ty, src);35376 const coerced_val = try mod.getCoerced(uncoerced_val.toValue(), load_ty);
35542 return .{ .val = coerced_val };35377 return .{ .val = coerced_val };
35543 }35378 }
35544 }35379 }