authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-13 13:24:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-18 19:02:06-07:00
log684aee32209932166713462cc341fa469aad0728
treec7d90cbd2143bf022f8dc324fadf12a04364f73e
parent927f6ec8ca2234e8c4f27174359d5053da63a77d

frontend: fixes for function regressions in this branch

* Introduce InternPool.Tag.func_coerced to handle the case of a function body coerced to a new type. `InternPool.getCoerced` is now implemented for function bodies in this branch. * implement resolution of ad-hoc inferred error sets in `Sema.analyzeCall`. * fix generic_owner being set wrong for child Sema bodies of param expressions. * fix `Sema.resolveInferredErrorSetTy` when passed `anyerror`.

2 files changed, 306 insertions(+), 187 deletions(-)

src/InternPool.zig+272-179
...@@ -1670,6 +1670,9 @@ pub const Index = enum(u32) {...@@ -1670,6 +1670,9 @@ pub const Index = enum(u32) {
1670 @"trailing.comptime_args.len": *@"data.generic_owner.data.ty.data.params_len",1670 @"trailing.comptime_args.len": *@"data.generic_owner.data.ty.data.params_len",
1671 trailing: struct { resolved_error_set: []Index, comptime_args: []Index },1671 trailing: struct { resolved_error_set: []Index, comptime_args: []Index },
1672 },1672 },
1673 func_coerced: struct {
1674 data: *Tag.FuncCoerced,
1675 },
1673 only_possible_value: DataIsIndex,1676 only_possible_value: DataIsIndex,
1674 union_value: struct { data: *Key.Union },1677 union_value: struct { data: *Key.Union },
1675 bytes: struct { data: *Bytes },1678 bytes: struct { data: *Bytes },
...@@ -2192,6 +2195,9 @@ pub const Tag = enum(u8) {...@@ -2192,6 +2195,9 @@ pub const Tag = enum(u8) {
2192 /// A generic function instantiation.2195 /// A generic function instantiation.
2193 /// data is extra index to `FuncInstance`.2196 /// data is extra index to `FuncInstance`.
2194 func_instance,2197 func_instance,
2198 /// A `func_decl` or a `func_instance` that has been coerced to a different type.
2199 /// data is extra index to `FuncCoerced`.
2200 func_coerced,
2195 /// This represents the only possible value for *some* types which have2201 /// This represents the only possible value for *some* types which have
2196 /// only one possible value. Not all only-possible-values are encoded this way;2202 /// only one possible value. Not all only-possible-values are encoded this way;
2197 /// for example structs which have all comptime fields are not encoded this way.2203 /// for example structs which have all comptime fields are not encoded this way.
...@@ -2298,6 +2304,7 @@ pub const Tag = enum(u8) {...@@ -2298,6 +2304,7 @@ pub const Tag = enum(u8) {
2298 .extern_func => ExternFunc,2304 .extern_func => ExternFunc,
2299 .func_decl => FuncDecl,2305 .func_decl => FuncDecl,
2300 .func_instance => FuncInstance,2306 .func_instance => FuncInstance,
2307 .func_coerced => FuncCoerced,
2301 .only_possible_value => unreachable,2308 .only_possible_value => unreachable,
2302 .union_value => Union,2309 .union_value => Union,
2303 .bytes => Bytes,2310 .bytes => Bytes,
...@@ -2364,6 +2371,11 @@ pub const Tag = enum(u8) {...@@ -2364,6 +2371,11 @@ pub const Tag = enum(u8) {
2364 generic_owner: Index,2371 generic_owner: Index,
2365 };2372 };
23662373
2374 pub const FuncCoerced = struct {
2375 ty: Index,
2376 func: Index,
2377 };
2378
2367 /// Trailing:2379 /// Trailing:
2368 /// 0. name: NullTerminatedString for each names_len2380 /// 0. name: NullTerminatedString for each names_len
2369 pub const ErrorSet = struct {2381 pub const ErrorSet = struct {
...@@ -3205,6 +3217,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3205,6 +3217,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3205 .extern_func => .{ .extern_func = ip.extraData(Tag.ExternFunc, data) },3217 .extern_func => .{ .extern_func = ip.extraData(Tag.ExternFunc, data) },
3206 .func_instance => .{ .func = ip.extraFuncInstance(data) },3218 .func_instance => .{ .func = ip.extraFuncInstance(data) },
3207 .func_decl => .{ .func = ip.extraFuncDecl(data) },3219 .func_decl => .{ .func = ip.extraFuncDecl(data) },
3220 .func_coerced => .{ .func = ip.extraFuncCoerced(data) },
3208 .only_possible_value => {3221 .only_possible_value => {
3209 const ty = @as(Index, @enumFromInt(data));3222 const ty = @as(Index, @enumFromInt(data));
3210 const ty_item = ip.items.get(@intFromEnum(ty));3223 const ty_item = ip.items.get(@intFromEnum(ty));
...@@ -3397,6 +3410,18 @@ fn extraFuncInstance(ip: *const InternPool, extra_index: u32) Key.Func {...@@ -3397,6 +3410,18 @@ fn extraFuncInstance(ip: *const InternPool, extra_index: u32) Key.Func {
3397 };3410 };
3398}3411}
33993412
3413fn extraFuncCoerced(ip: *const InternPool, extra_index: u32) Key.Func {
3414 const func_coerced = ip.extraData(Tag.FuncCoerced, extra_index);
3415 const sub_item = ip.items.get(@intFromEnum(func_coerced.func));
3416 var func: Key.Func = switch (sub_item.tag) {
3417 .func_instance => ip.extraFuncInstance(sub_item.data),
3418 .func_decl => ip.extraFuncDecl(sub_item.data),
3419 else => unreachable,
3420 };
3421 func.ty = func_coerced.ty;
3422 return func;
3423}
3424
3400fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMode) Key {3425fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMode) Key {
3401 const enum_explicit = ip.extraDataTrail(EnumExplicit, data);3426 const enum_explicit = ip.extraDataTrail(EnumExplicit, data);
3402 const names = @as(3427 const names = @as(
...@@ -5480,210 +5505,226 @@ pub fn sliceLen(ip: *const InternPool, i: Index) Index {...@@ -5480,210 +5505,226 @@ pub fn sliceLen(ip: *const InternPool, i: Index) Index {
5480pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {5505pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
5481 const old_ty = ip.typeOf(val);5506 const old_ty = ip.typeOf(val);
5482 if (old_ty == new_ty) return val;5507 if (old_ty == new_ty) return val;
5508
5509 const tags = ip.items.items(.tag);
5510
5483 switch (val) {5511 switch (val) {
5484 .undef => return ip.get(gpa, .{ .undef = new_ty }),5512 .undef => return ip.get(gpa, .{ .undef = new_ty }),
5485 .null_value => if (ip.isOptionalType(new_ty))5513 .null_value => {
5486 return ip.get(gpa, .{ .opt = .{5514 if (ip.isOptionalType(new_ty)) return ip.get(gpa, .{ .opt = .{
5487 .ty = new_ty,5515 .ty = new_ty,
5488 .val = .none,5516 .val = .none,
5489 } })5517 } });
5490 else if (ip.isPointerType(new_ty))5518
5491 return ip.get(gpa, .{ .ptr = .{5519 if (ip.isPointerType(new_ty)) return ip.get(gpa, .{ .ptr = .{
5492 .ty = new_ty,5520 .ty = new_ty,
5493 .addr = .{ .int = .zero_usize },5521 .addr = .{ .int = .zero_usize },
5494 .len = switch (ip.indexToKey(new_ty).ptr_type.flags.size) {5522 .len = switch (ip.indexToKey(new_ty).ptr_type.flags.size) {
5495 .One, .Many, .C => .none,5523 .One, .Many, .C => .none,
5496 .Slice => try ip.get(gpa, .{ .undef = .usize_type }),5524 .Slice => try ip.get(gpa, .{ .undef = .usize_type }),
5497 },5525 },
5498 } }),5526 } });
5499 else => switch (ip.indexToKey(val)) {5527 },
5500 .undef => return ip.get(gpa, .{ .undef = new_ty }),5528 else => switch (tags[@intFromEnum(val)]) {
5501 .extern_func => |extern_func| if (ip.isFunctionType(new_ty))5529 .func_decl => return getCoercedFuncDecl(ip, gpa, val, new_ty),
5502 return ip.get(gpa, .{ .extern_func = .{5530 .func_instance => return getCoercedFuncInstance(ip, gpa, val, new_ty),
5503 .ty = new_ty,5531 .func_coerced => {
5504 .decl = extern_func.decl,5532 const extra_index = ip.items.items(.data)[@intFromEnum(val)];
5505 .lib_name = extern_func.lib_name,5533 const func: Index = @enumFromInt(
5506 } }),5534 ip.extra.items[extra_index + std.meta.fieldIndex(Tag.FuncCoerced, "func").?],
55075535 );
5508 .func => |func| {5536 switch (tags[@intFromEnum(func)]) {
5509 if (func.generic_owner == .none) {5537 .func_decl => return getCoercedFuncDecl(ip, gpa, val, new_ty),
5510 @panic("TODO");5538 .func_instance => return getCoercedFuncInstance(ip, gpa, val, new_ty),
5511 } else {5539 else => unreachable,
5512 @panic("TODO");
5513 }5540 }
5514 },5541 },
5542 else => {},
5543 },
5544 }
55155545
5516 .int => |int| switch (ip.indexToKey(new_ty)) {5546 switch (ip.indexToKey(val)) {
5517 .enum_type => |enum_type| return ip.get(gpa, .{ .enum_tag = .{5547 .undef => return ip.get(gpa, .{ .undef = new_ty }),
5518 .ty = new_ty,5548 .extern_func => |extern_func| if (ip.isFunctionType(new_ty))
5519 .int = try ip.getCoerced(gpa, val, enum_type.tag_ty),5549 return ip.get(gpa, .{ .extern_func = .{
5520 } }),5550 .ty = new_ty,
5521 .ptr_type => return ip.get(gpa, .{ .ptr = .{5551 .decl = extern_func.decl,
5552 .lib_name = extern_func.lib_name,
5553 } }),
5554
5555 .func => unreachable,
5556
5557 .int => |int| switch (ip.indexToKey(new_ty)) {
5558 .enum_type => |enum_type| return ip.get(gpa, .{ .enum_tag = .{
5559 .ty = new_ty,
5560 .int = try ip.getCoerced(gpa, val, enum_type.tag_ty),
5561 } }),
5562 .ptr_type => return ip.get(gpa, .{ .ptr = .{
5563 .ty = new_ty,
5564 .addr = .{ .int = try ip.getCoerced(gpa, val, .usize_type) },
5565 } }),
5566 else => if (ip.isIntegerType(new_ty))
5567 return getCoercedInts(ip, gpa, int, new_ty),
5568 },
5569 .float => |float| switch (ip.indexToKey(new_ty)) {
5570 .simple_type => |simple| switch (simple) {
5571 .f16,
5572 .f32,
5573 .f64,
5574 .f80,
5575 .f128,
5576 .c_longdouble,
5577 .comptime_float,
5578 => return ip.get(gpa, .{ .float = .{
5522 .ty = new_ty,5579 .ty = new_ty,
5523 .addr = .{ .int = try ip.getCoerced(gpa, val, .usize_type) },5580 .storage = float.storage,
5524 } }),5581 } }),
5525 else => if (ip.isIntegerType(new_ty))
5526 return getCoercedInts(ip, gpa, int, new_ty),
5527 },
5528 .float => |float| switch (ip.indexToKey(new_ty)) {
5529 .simple_type => |simple| switch (simple) {
5530 .f16,
5531 .f32,
5532 .f64,
5533 .f80,
5534 .f128,
5535 .c_longdouble,
5536 .comptime_float,
5537 => return ip.get(gpa, .{ .float = .{
5538 .ty = new_ty,
5539 .storage = float.storage,
5540 } }),
5541 else => {},
5542 },
5543 else => {},5582 else => {},
5544 },5583 },
5545 .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))5584 else => {},
5546 return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),5585 },
5547 .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {5586 .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))
5548 .enum_type => |enum_type| {5587 return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),
5549 const index = enum_type.nameIndex(ip, enum_literal).?;5588 .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {
5550 return ip.get(gpa, .{ .enum_tag = .{5589 .enum_type => |enum_type| {
5551 .ty = new_ty,5590 const index = enum_type.nameIndex(ip, enum_literal).?;
5552 .int = if (enum_type.values.len != 0)5591 return ip.get(gpa, .{ .enum_tag = .{
5553 enum_type.values[index]5592 .ty = new_ty,
5554 else5593 .int = if (enum_type.values.len != 0)
5555 try ip.get(gpa, .{ .int = .{5594 enum_type.values[index]
5556 .ty = enum_type.tag_ty,5595 else
5557 .storage = .{ .u64 = index },5596 try ip.get(gpa, .{ .int = .{
5558 } }),5597 .ty = enum_type.tag_ty,
5559 } });5598 .storage = .{ .u64 = index },
5560 },5599 } }),
5600 } });
5601 },
5602 else => {},
5603 },
5604 .ptr => |ptr| if (ip.isPointerType(new_ty))
5605 return ip.get(gpa, .{ .ptr = .{
5606 .ty = new_ty,
5607 .addr = ptr.addr,
5608 .len = ptr.len,
5609 } })
5610 else if (ip.isIntegerType(new_ty))
5611 switch (ptr.addr) {
5612 .int => |int| return ip.getCoerced(gpa, int, new_ty),
5561 else => {},5613 else => {},
5562 },5614 },
5563 .ptr => |ptr| if (ip.isPointerType(new_ty))5615 .opt => |opt| switch (ip.indexToKey(new_ty)) {
5564 return ip.get(gpa, .{ .ptr = .{5616 .ptr_type => |ptr_type| return switch (opt.val) {
5617 .none => try ip.get(gpa, .{ .ptr = .{
5565 .ty = new_ty,5618 .ty = new_ty,
5566 .addr = ptr.addr,5619 .addr = .{ .int = .zero_usize },
5567 .len = ptr.len,5620 .len = switch (ptr_type.flags.size) {
5568 } })5621 .One, .Many, .C => .none,
5569 else if (ip.isIntegerType(new_ty))5622 .Slice => try ip.get(gpa, .{ .undef = .usize_type }),
5570 switch (ptr.addr) {
5571 .int => |int| return ip.getCoerced(gpa, int, new_ty),
5572 else => {},
5573 },
5574 .opt => |opt| switch (ip.indexToKey(new_ty)) {
5575 .ptr_type => |ptr_type| return switch (opt.val) {
5576 .none => try ip.get(gpa, .{ .ptr = .{
5577 .ty = new_ty,
5578 .addr = .{ .int = .zero_usize },
5579 .len = switch (ptr_type.flags.size) {
5580 .One, .Many, .C => .none,
5581 .Slice => try ip.get(gpa, .{ .undef = .usize_type }),
5582 },
5583 } }),
5584 else => |payload| try ip.getCoerced(gpa, payload, new_ty),
5585 },
5586 .opt_type => |child_type| return try ip.get(gpa, .{ .opt = .{
5587 .ty = new_ty,
5588 .val = switch (opt.val) {
5589 .none => .none,
5590 else => try ip.getCoerced(gpa, opt.val, child_type),
5591 },5623 },
5592 } }),5624 } }),
5593 else => {},5625 else => |payload| try ip.getCoerced(gpa, payload, new_ty),
5594 },5626 },
5595 .err => |err| if (ip.isErrorSetType(new_ty))5627 .opt_type => |child_type| return try ip.get(gpa, .{ .opt = .{
5596 return ip.get(gpa, .{ .err = .{5628 .ty = new_ty,
5597 .ty = new_ty,5629 .val = switch (opt.val) {
5598 .name = err.name,5630 .none => .none,
5599 } })5631 else => try ip.getCoerced(gpa, opt.val, child_type),
5600 else if (ip.isErrorUnionType(new_ty))5632 },
5601 return ip.get(gpa, .{ .error_union = .{5633 } }),
5602 .ty = new_ty,5634 else => {},
5603 .val = .{ .err_name = err.name },5635 },
5604 } }),5636 .err => |err| if (ip.isErrorSetType(new_ty))
5605 .error_union => |error_union| if (ip.isErrorUnionType(new_ty))5637 return ip.get(gpa, .{ .err = .{
5606 return ip.get(gpa, .{ .error_union = .{5638 .ty = new_ty,
5607 .ty = new_ty,5639 .name = err.name,
5608 .val = error_union.val,5640 } })
5609 } }),5641 else if (ip.isErrorUnionType(new_ty))
5610 .aggregate => |aggregate| {5642 return ip.get(gpa, .{ .error_union = .{
5611 const new_len = @as(usize, @intCast(ip.aggregateTypeLen(new_ty)));5643 .ty = new_ty,
5612 direct: {5644 .val = .{ .err_name = err.name },
5613 const old_ty_child = switch (ip.indexToKey(old_ty)) {5645 } }),
5614 inline .array_type, .vector_type => |seq_type| seq_type.child,5646 .error_union => |error_union| if (ip.isErrorUnionType(new_ty))
5615 .anon_struct_type, .struct_type => break :direct,5647 return ip.get(gpa, .{ .error_union = .{
5616 else => unreachable,5648 .ty = new_ty,
5617 };5649 .val = error_union.val,
5618 const new_ty_child = switch (ip.indexToKey(new_ty)) {5650 } }),
5619 inline .array_type, .vector_type => |seq_type| seq_type.child,5651 .aggregate => |aggregate| {
5620 .anon_struct_type, .struct_type => break :direct,5652 const new_len = @as(usize, @intCast(ip.aggregateTypeLen(new_ty)));
5621 else => unreachable,5653 direct: {
5622 };5654 const old_ty_child = switch (ip.indexToKey(old_ty)) {
5623 if (old_ty_child != new_ty_child) break :direct;5655 inline .array_type, .vector_type => |seq_type| seq_type.child,
5624 // TODO: write something like getCoercedInts to avoid needing to dupe here5656 .anon_struct_type, .struct_type => break :direct,
5625 switch (aggregate.storage) {5657 else => unreachable,
5626 .bytes => |bytes| {5658 };
5627 const bytes_copy = try gpa.dupe(u8, bytes[0..new_len]);5659 const new_ty_child = switch (ip.indexToKey(new_ty)) {
5628 defer gpa.free(bytes_copy);5660 inline .array_type, .vector_type => |seq_type| seq_type.child,
5629 return ip.get(gpa, .{ .aggregate = .{5661 .anon_struct_type, .struct_type => break :direct,
5630 .ty = new_ty,5662 else => unreachable,
5631 .storage = .{ .bytes = bytes_copy },5663 };
5632 } });5664 if (old_ty_child != new_ty_child) break :direct;
5633 },5665 // TODO: write something like getCoercedInts to avoid needing to dupe here
5634 .elems => |elems| {
5635 const elems_copy = try gpa.dupe(InternPool.Index, elems[0..new_len]);
5636 defer gpa.free(elems_copy);
5637 return ip.get(gpa, .{ .aggregate = .{
5638 .ty = new_ty,
5639 .storage = .{ .elems = elems_copy },
5640 } });
5641 },
5642 .repeated_elem => |elem| {
5643 return ip.get(gpa, .{ .aggregate = .{
5644 .ty = new_ty,
5645 .storage = .{ .repeated_elem = elem },
5646 } });
5647 },
5648 }
5649 }
5650 // Direct approach failed - we must recursively coerce elems
5651 const agg_elems = try gpa.alloc(InternPool.Index, new_len);
5652 defer gpa.free(agg_elems);
5653 // First, fill the vector with the uncoerced elements. We do this to avoid key
5654 // lifetime issues, since it'll allow us to avoid referencing `aggregate` after we
5655 // begin interning elems.
5656 switch (aggregate.storage) {5666 switch (aggregate.storage) {
5657 .bytes => {5667 .bytes => |bytes| {
5658 // We have to intern each value here, so unfortunately we can't easily avoid5668 const bytes_copy = try gpa.dupe(u8, bytes[0..new_len]);
5659 // the repeated indexToKey calls.5669 defer gpa.free(bytes_copy);
5660 for (agg_elems, 0..) |*elem, i| {5670 return ip.get(gpa, .{ .aggregate = .{
5661 const x = ip.indexToKey(val).aggregate.storage.bytes[i];5671 .ty = new_ty,
5662 elem.* = try ip.get(gpa, .{ .int = .{5672 .storage = .{ .bytes = bytes_copy },
5663 .ty = .u8_type,5673 } });
5664 .storage = .{ .u64 = x },5674 },
5665 } });5675 .elems => |elems| {
5666 }5676 const elems_copy = try gpa.dupe(InternPool.Index, elems[0..new_len]);
5677 defer gpa.free(elems_copy);
5678 return ip.get(gpa, .{ .aggregate = .{
5679 .ty = new_ty,
5680 .storage = .{ .elems = elems_copy },
5681 } });
5682 },
5683 .repeated_elem => |elem| {
5684 return ip.get(gpa, .{ .aggregate = .{
5685 .ty = new_ty,
5686 .storage = .{ .repeated_elem = elem },
5687 } });
5667 },5688 },
5668 .elems => |elems| @memcpy(agg_elems, elems[0..new_len]),
5669 .repeated_elem => |elem| @memset(agg_elems, elem),
5670 }
5671 // Now, coerce each element to its new type.
5672 for (agg_elems, 0..) |*elem, i| {
5673 const new_elem_ty = switch (ip.indexToKey(new_ty)) {
5674 inline .array_type, .vector_type => |seq_type| seq_type.child,
5675 .anon_struct_type => |anon_struct_type| anon_struct_type.types[i],
5676 .struct_type => |struct_type| ip.structPtr(struct_type.index.unwrap().?)
5677 .fields.values()[i].ty.toIntern(),
5678 else => unreachable,
5679 };
5680 elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty);
5681 }5689 }
5682 return ip.get(gpa, .{ .aggregate = .{ .ty = new_ty, .storage = .{ .elems = agg_elems } } });5690 }
5683 },5691 // Direct approach failed - we must recursively coerce elems
5684 else => {},5692 const agg_elems = try gpa.alloc(InternPool.Index, new_len);
5693 defer gpa.free(agg_elems);
5694 // First, fill the vector with the uncoerced elements. We do this to avoid key
5695 // lifetime issues, since it'll allow us to avoid referencing `aggregate` after we
5696 // begin interning elems.
5697 switch (aggregate.storage) {
5698 .bytes => {
5699 // We have to intern each value here, so unfortunately we can't easily avoid
5700 // the repeated indexToKey calls.
5701 for (agg_elems, 0..) |*elem, i| {
5702 const x = ip.indexToKey(val).aggregate.storage.bytes[i];
5703 elem.* = try ip.get(gpa, .{ .int = .{
5704 .ty = .u8_type,
5705 .storage = .{ .u64 = x },
5706 } });
5707 }
5708 },
5709 .elems => |elems| @memcpy(agg_elems, elems[0..new_len]),
5710 .repeated_elem => |elem| @memset(agg_elems, elem),
5711 }
5712 // Now, coerce each element to its new type.
5713 for (agg_elems, 0..) |*elem, i| {
5714 const new_elem_ty = switch (ip.indexToKey(new_ty)) {
5715 inline .array_type, .vector_type => |seq_type| seq_type.child,
5716 .anon_struct_type => |anon_struct_type| anon_struct_type.types[i],
5717 .struct_type => |struct_type| ip.structPtr(struct_type.index.unwrap().?)
5718 .fields.values()[i].ty.toIntern(),
5719 else => unreachable,
5720 };
5721 elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty);
5722 }
5723 return ip.get(gpa, .{ .aggregate = .{ .ty = new_ty, .storage = .{ .elems = agg_elems } } });
5685 },5724 },
5725 else => {},
5686 }5726 }
5727
5687 switch (ip.indexToKey(new_ty)) {5728 switch (ip.indexToKey(new_ty)) {
5688 .opt_type => |child_type| switch (val) {5729 .opt_type => |child_type| switch (val) {
5689 .null_value => return ip.get(gpa, .{ .opt = .{5730 .null_value => return ip.get(gpa, .{ .opt = .{
...@@ -5711,6 +5752,54 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al...@@ -5711,6 +5752,54 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
5711 unreachable;5752 unreachable;
5712}5753}
57135754
5755fn getCoercedFuncDecl(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
5756 const datas = ip.items.items(.data);
5757 const extra_index = datas[@intFromEnum(val)];
5758 const prev_ty: Index = @enumFromInt(
5759 ip.extra.items[extra_index + std.meta.fieldIndex(Tag.FuncDecl, "ty").?],
5760 );
5761 if (new_ty == prev_ty) return val;
5762 return getCoercedFunc(ip, gpa, val, new_ty);
5763}
5764
5765fn getCoercedFuncInstance(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
5766 const datas = ip.items.items(.data);
5767 const extra_index = datas[@intFromEnum(val)];
5768 const prev_ty: Index = @enumFromInt(
5769 ip.extra.items[extra_index + std.meta.fieldIndex(Tag.FuncInstance, "ty").?],
5770 );
5771 if (new_ty == prev_ty) return val;
5772 return getCoercedFunc(ip, gpa, val, new_ty);
5773}
5774
5775fn getCoercedFunc(ip: *InternPool, gpa: Allocator, func: Index, ty: Index) Allocator.Error!Index {
5776 const prev_extra_len = ip.extra.items.len;
5777 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncCoerced).Struct.fields.len);
5778 try ip.items.ensureUnusedCapacity(gpa, 1);
5779 try ip.map.ensureUnusedCapacity(gpa, 1);
5780
5781 const extra_index = ip.addExtraAssumeCapacity(Tag.FuncCoerced{
5782 .ty = ty,
5783 .func = func,
5784 });
5785
5786 const adapter: KeyAdapter = .{ .intern_pool = ip };
5787 const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{
5788 .func = extraFuncCoerced(ip, extra_index),
5789 }, adapter);
5790
5791 if (gop.found_existing) {
5792 ip.extra.items.len = prev_extra_len;
5793 return @enumFromInt(gop.index);
5794 }
5795
5796 ip.items.appendAssumeCapacity(.{
5797 .tag = .func_coerced,
5798 .data = extra_index,
5799 });
5800 return @enumFromInt(ip.items.len - 1);
5801}
5802
5714/// Asserts `val` has an integer type.5803/// Asserts `val` has an integer type.
5715/// Assumes `new_ty` is an integer type.5804/// Assumes `new_ty` is an integer type.
5716pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, int: Key.Int, new_ty: Index) Allocator.Error!Index {5805pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, int: Key.Int, new_ty: Index) Allocator.Error!Index {
...@@ -6025,6 +6114,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -6025,6 +6114,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
6025 break :b @sizeOf(Tag.FuncInstance) + @sizeOf(Index) * params_len +6114 break :b @sizeOf(Tag.FuncInstance) + @sizeOf(Index) * params_len +
6026 @sizeOf(Module.Decl);6115 @sizeOf(Module.Decl);
6027 },6116 },
6117 .func_coerced => @sizeOf(Tag.FuncCoerced),
6028 .only_possible_value => 0,6118 .only_possible_value => 0,
6029 .union_value => @sizeOf(Key.Union),6119 .union_value => @sizeOf(Key.Union),
60306120
...@@ -6131,6 +6221,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {...@@ -6131,6 +6221,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
6131 .extern_func,6221 .extern_func,
6132 .func_decl,6222 .func_decl,
6133 .func_instance,6223 .func_instance,
6224 .func_coerced,
6134 .union_value,6225 .union_value,
6135 .memoized_call,6226 .memoized_call,
6136 => try w.print("{d}", .{data}),6227 => try w.print("{d}", .{data}),
...@@ -6471,7 +6562,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -6471,7 +6562,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
6471 .undef,6562 .undef,
6472 .opt_null,6563 .opt_null,
6473 .only_possible_value,6564 .only_possible_value,
6474 => @as(Index, @enumFromInt(ip.items.items(.data)[@intFromEnum(index)])),6565 => @enumFromInt(ip.items.items(.data)[@intFromEnum(index)]),
64756566
6476 .simple_value => unreachable, // handled via Index above6567 .simple_value => unreachable, // handled via Index above
64776568
...@@ -6497,6 +6588,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -6497,6 +6588,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
6497 .extern_func,6588 .extern_func,
6498 .func_decl,6589 .func_decl,
6499 .func_instance,6590 .func_instance,
6591 .func_coerced,
6500 .union_value,6592 .union_value,
6501 .bytes,6593 .bytes,
6502 .aggregate,6594 .aggregate,
...@@ -6504,7 +6596,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -6504,7 +6596,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
6504 => |t| {6596 => |t| {
6505 const extra_index = ip.items.items(.data)[@intFromEnum(index)];6597 const extra_index = ip.items.items(.data)[@intFromEnum(index)];
6506 const field_index = std.meta.fieldIndex(t.Payload(), "ty").?;6598 const field_index = std.meta.fieldIndex(t.Payload(), "ty").?;
6507 return @as(Index, @enumFromInt(ip.extra.items[extra_index + field_index]));6599 return @enumFromInt(ip.extra.items[extra_index + field_index]);
6508 },6600 },
65096601
6510 .int_u8 => .u8_type,6602 .int_u8 => .u8_type,
...@@ -6850,6 +6942,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois...@@ -6850,6 +6942,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
6850 .extern_func,6942 .extern_func,
6851 .func_decl,6943 .func_decl,
6852 .func_instance,6944 .func_instance,
6945 .func_coerced,
6853 .only_possible_value,6946 .only_possible_value,
6854 .union_value,6947 .union_value,
6855 .bytes,6948 .bytes,
...@@ -6866,7 +6959,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois...@@ -6866,7 +6959,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
6866pub fn isFuncBody(ip: *const InternPool, i: Index) bool {6959pub fn isFuncBody(ip: *const InternPool, i: Index) bool {
6867 assert(i != .none);6960 assert(i != .none);
6868 return switch (ip.items.items(.tag)[@intFromEnum(i)]) {6961 return switch (ip.items.items(.tag)[@intFromEnum(i)]) {
6869 .func_decl, .func_instance => true,6962 .func_decl, .func_instance, .func_coerced => true,
6870 else => false,6963 else => false,
6871 };6964 };
6872}6965}
src/Sema.zig+34-8
...@@ -7155,9 +7155,17 @@ fn analyzeCall(...@@ -7155,9 +7155,17 @@ fn analyzeCall(
7155 break :res2 Air.internedToRef(result_transformed);7155 break :res2 Air.internedToRef(result_transformed);
7156 }7156 }
71577157
7158 if (sema.fn_ret_ty_ies) |ies| {7158 if (try sema.resolveMaybeUndefVal(result)) |result_val| {
7159 _ = ies;7159 const result_interned = try result_val.intern(sema.fn_ret_ty, mod);
7160 @panic("TODO: resolve ad-hoc inferred error set");7160 const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned);
7161 break :res2 Air.internedToRef(result_transformed);
7162 }
7163
7164 const new_ty = try sema.resolveAdHocInferredErrorSetTy(block, call_src, sema.typeOf(result).toIntern());
7165 if (new_ty != .none) {
7166 // TODO: mutate in place the previous instruction if possible
7167 // rather than adding a bitcast instruction.
7168 break :res2 try block.addBitCast(new_ty.toType(), result);
7161 }7169 }
71627170
7163 break :res2 result;7171 break :res2 result;
...@@ -9141,11 +9149,14 @@ fn zirParam(...@@ -9141,11 +9149,14 @@ fn zirParam(
9141 // Make sure any nested param instructions don't clobber our work.9149 // Make sure any nested param instructions don't clobber our work.
9142 const prev_params = block.params;9150 const prev_params = block.params;
9143 const prev_no_partial_func_type = sema.no_partial_func_ty;9151 const prev_no_partial_func_type = sema.no_partial_func_ty;
9152 const prev_generic_owner = sema.generic_owner;
9144 block.params = .{};9153 block.params = .{};
9145 sema.no_partial_func_ty = true;9154 sema.no_partial_func_ty = true;
9155 sema.generic_owner = .none;
9146 defer {9156 defer {
9147 block.params = prev_params;9157 block.params = prev_params;
9148 sema.no_partial_func_ty = prev_no_partial_func_type;9158 sema.no_partial_func_ty = prev_no_partial_func_type;
9159 sema.generic_owner = prev_generic_owner;
9149 }9160 }
91509161
9151 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {9162 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
...@@ -34114,24 +34125,37 @@ fn resolveAdHocInferredErrorSet(...@@ -34114,24 +34125,37 @@ fn resolveAdHocInferredErrorSet(
34114 src: LazySrcLoc,34125 src: LazySrcLoc,
34115 value: InternPool.Index,34126 value: InternPool.Index,
34116) CompileError!InternPool.Index {34127) CompileError!InternPool.Index {
34117 const ies = sema.fn_ret_ty_ies orelse return value;
34118 const mod = sema.mod;34128 const mod = sema.mod;
34119 const gpa = sema.gpa;34129 const gpa = sema.gpa;
34120 const ip = &mod.intern_pool;34130 const ip = &mod.intern_pool;
34121 const ty = ip.typeOf(value);34131 const new_ty = try resolveAdHocInferredErrorSetTy(sema, block, src, ip.typeOf(value));
34132 if (new_ty == .none) return value;
34133 return ip.getCoerced(gpa, value, new_ty);
34134}
34135
34136fn resolveAdHocInferredErrorSetTy(
34137 sema: *Sema,
34138 block: *Block,
34139 src: LazySrcLoc,
34140 ty: InternPool.Index,
34141) CompileError!InternPool.Index {
34142 const ies = sema.fn_ret_ty_ies orelse return .none;
34143 const mod = sema.mod;
34144 const gpa = sema.gpa;
34145 const ip = &mod.intern_pool;
34122 const error_union_info = switch (ip.indexToKey(ty)) {34146 const error_union_info = switch (ip.indexToKey(ty)) {
34123 .error_union_type => |x| x,34147 .error_union_type => |x| x,
34124 else => return value,34148 else => return .none,
34125 };34149 };
34126 if (error_union_info.error_set_type != .adhoc_inferred_error_set_type)34150 if (error_union_info.error_set_type != .adhoc_inferred_error_set_type)
34127 return value;34151 return .none;
3412834152
34129 try sema.resolveInferredErrorSetPtr(block, src, ies);34153 try sema.resolveInferredErrorSetPtr(block, src, ies);
34130 const new_ty = try ip.get(gpa, .{ .error_union_type = .{34154 const new_ty = try ip.get(gpa, .{ .error_union_type = .{
34131 .error_set_type = ies.resolved,34155 .error_set_type = ies.resolved,
34132 .payload_type = error_union_info.payload_type,34156 .payload_type = error_union_info.payload_type,
34133 } });34157 } });
34134 return ip.getCoerced(gpa, value, new_ty);34158 return new_ty;
34135}34159}
3413634160
34137fn resolveInferredErrorSetTy(34161fn resolveInferredErrorSetTy(
...@@ -34142,6 +34166,7 @@ fn resolveInferredErrorSetTy(...@@ -34142,6 +34166,7 @@ fn resolveInferredErrorSetTy(
34142) CompileError!InternPool.Index {34166) CompileError!InternPool.Index {
34143 const mod = sema.mod;34167 const mod = sema.mod;
34144 const ip = &mod.intern_pool;34168 const ip = &mod.intern_pool;
34169 if (ty == .anyerror_type) return ty;
34145 switch (ip.indexToKey(ty)) {34170 switch (ip.indexToKey(ty)) {
34146 .error_set_type => return ty,34171 .error_set_type => return ty,
34147 .inferred_error_set_type => return sema.resolveInferredErrorSet(block, src, ty),34172 .inferred_error_set_type => return sema.resolveInferredErrorSet(block, src, ty),
...@@ -35229,6 +35254,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -35229,6 +35254,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
35229 .extern_func,35254 .extern_func,
35230 .func_decl,35255 .func_decl,
35231 .func_instance,35256 .func_instance,
35257 .func_coerced,
35232 .only_possible_value,35258 .only_possible_value,
35233 .union_value,35259 .union_value,
35234 .bytes,35260 .bytes,