| ... | ... | @@ -1670,6 +1670,9 @@ pub const Index = enum(u32) { |
| 1670 | 1670 | @"trailing.comptime_args.len": *@"data.generic_owner.data.ty.data.params_len", |
| 1671 | 1671 | trailing: struct { resolved_error_set: []Index, comptime_args: []Index }, |
| 1672 | 1672 | }, |
| 1673 | func_coerced: struct { |
| 1674 | data: *Tag.FuncCoerced, |
| 1675 | }, |
| 1673 | 1676 | only_possible_value: DataIsIndex, |
| 1674 | 1677 | union_value: struct { data: *Key.Union }, |
| 1675 | 1678 | bytes: struct { data: *Bytes }, |
| ... | ... | @@ -2192,6 +2195,9 @@ pub const Tag = enum(u8) { |
| 2192 | 2195 | /// A generic function instantiation. |
| 2193 | 2196 | /// data is extra index to `FuncInstance`. |
| 2194 | 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 | 2201 | /// This represents the only possible value for *some* types which have |
| 2196 | 2202 | /// only one possible value. Not all only-possible-values are encoded this way; |
| 2197 | 2203 | /// for example structs which have all comptime fields are not encoded this way. |
| ... | ... | @@ -2298,6 +2304,7 @@ pub const Tag = enum(u8) { |
| 2298 | 2304 | .extern_func => ExternFunc, |
| 2299 | 2305 | .func_decl => FuncDecl, |
| 2300 | 2306 | .func_instance => FuncInstance, |
| 2307 | .func_coerced => FuncCoerced, |
| 2301 | 2308 | .only_possible_value => unreachable, |
| 2302 | 2309 | .union_value => Union, |
| 2303 | 2310 | .bytes => Bytes, |
| ... | ... | @@ -2364,6 +2371,11 @@ pub const Tag = enum(u8) { |
| 2364 | 2371 | generic_owner: Index, |
| 2365 | 2372 | }; |
| 2366 | 2373 | |
| 2374 | pub const FuncCoerced = struct { |
| 2375 | ty: Index, |
| 2376 | func: Index, |
| 2377 | }; |
| 2378 | |
| 2367 | 2379 | /// Trailing: |
| 2368 | 2380 | /// 0. name: NullTerminatedString for each names_len |
| 2369 | 2381 | pub const ErrorSet = struct { |
| ... | ... | @@ -3205,6 +3217,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3205 | 3217 | .extern_func => .{ .extern_func = ip.extraData(Tag.ExternFunc, data) }, |
| 3206 | 3218 | .func_instance => .{ .func = ip.extraFuncInstance(data) }, |
| 3207 | 3219 | .func_decl => .{ .func = ip.extraFuncDecl(data) }, |
| 3220 | .func_coerced => .{ .func = ip.extraFuncCoerced(data) }, |
| 3208 | 3221 | .only_possible_value => { |
| 3209 | 3222 | const ty = @as(Index, @enumFromInt(data)); |
| 3210 | 3223 | const ty_item = ip.items.get(@intFromEnum(ty)); |
| ... | ... | @@ -3397,6 +3410,18 @@ fn extraFuncInstance(ip: *const InternPool, extra_index: u32) Key.Func { |
| 3397 | 3410 | }; |
| 3398 | 3411 | } |
| 3399 | 3412 | |
| 3413 | fn 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 | |
| 3400 | 3425 | fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMode) Key { |
| 3401 | 3426 | const enum_explicit = ip.extraDataTrail(EnumExplicit, data); |
| 3402 | 3427 | const names = @as( |
| ... | ... | @@ -5480,210 +5505,226 @@ pub fn sliceLen(ip: *const InternPool, i: Index) Index { |
| 5480 | 5505 | pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index { |
| 5481 | 5506 | const old_ty = ip.typeOf(val); |
| 5482 | 5507 | if (old_ty == new_ty) return val; |
| 5508 | |
| 5509 | const tags = ip.items.items(.tag); |
| 5510 | |
| 5483 | 5511 | switch (val) { |
| 5484 | 5512 | .undef => return ip.get(gpa, .{ .undef = new_ty }), |
| 5485 | | .null_value => if (ip.isOptionalType(new_ty)) |
| 5486 | | return ip.get(gpa, .{ .opt = .{ |
| 5513 | .null_value => { |
| 5514 | if (ip.isOptionalType(new_ty)) return ip.get(gpa, .{ .opt = .{ |
| 5487 | 5515 | .ty = new_ty, |
| 5488 | 5516 | .val = .none, |
| 5489 | | } }) |
| 5490 | | else if (ip.isPointerType(new_ty)) |
| 5491 | | return ip.get(gpa, .{ .ptr = .{ |
| 5517 | } }); |
| 5518 | |
| 5519 | if (ip.isPointerType(new_ty)) return ip.get(gpa, .{ .ptr = .{ |
| 5492 | 5520 | .ty = new_ty, |
| 5493 | 5521 | .addr = .{ .int = .zero_usize }, |
| 5494 | 5522 | .len = switch (ip.indexToKey(new_ty).ptr_type.flags.size) { |
| 5495 | 5523 | .One, .Many, .C => .none, |
| 5496 | 5524 | .Slice => try ip.get(gpa, .{ .undef = .usize_type }), |
| 5497 | 5525 | }, |
| 5498 | | } }), |
| 5499 | | else => switch (ip.indexToKey(val)) { |
| 5500 | | .undef => return ip.get(gpa, .{ .undef = new_ty }), |
| 5501 | | .extern_func => |extern_func| if (ip.isFunctionType(new_ty)) |
| 5502 | | return ip.get(gpa, .{ .extern_func = .{ |
| 5503 | | .ty = new_ty, |
| 5504 | | .decl = extern_func.decl, |
| 5505 | | .lib_name = extern_func.lib_name, |
| 5506 | | } }), |
| 5507 | | |
| 5508 | | .func => |func| { |
| 5509 | | if (func.generic_owner == .none) { |
| 5510 | | @panic("TODO"); |
| 5511 | | } else { |
| 5512 | | @panic("TODO"); |
| 5526 | } }); |
| 5527 | }, |
| 5528 | else => switch (tags[@intFromEnum(val)]) { |
| 5529 | .func_decl => return getCoercedFuncDecl(ip, gpa, val, new_ty), |
| 5530 | .func_instance => return getCoercedFuncInstance(ip, gpa, val, new_ty), |
| 5531 | .func_coerced => { |
| 5532 | const extra_index = ip.items.items(.data)[@intFromEnum(val)]; |
| 5533 | const func: Index = @enumFromInt( |
| 5534 | ip.extra.items[extra_index + std.meta.fieldIndex(Tag.FuncCoerced, "func").?], |
| 5535 | ); |
| 5536 | switch (tags[@intFromEnum(func)]) { |
| 5537 | .func_decl => return getCoercedFuncDecl(ip, gpa, val, new_ty), |
| 5538 | .func_instance => return getCoercedFuncInstance(ip, gpa, val, new_ty), |
| 5539 | else => unreachable, |
| 5513 | 5540 | } |
| 5514 | 5541 | }, |
| 5542 | else => {}, |
| 5543 | }, |
| 5544 | } |
| 5515 | 5545 | |
| 5516 | | .int => |int| switch (ip.indexToKey(new_ty)) { |
| 5517 | | .enum_type => |enum_type| return ip.get(gpa, .{ .enum_tag = .{ |
| 5518 | | .ty = new_ty, |
| 5519 | | .int = try ip.getCoerced(gpa, val, enum_type.tag_ty), |
| 5520 | | } }), |
| 5521 | | .ptr_type => return ip.get(gpa, .{ .ptr = .{ |
| 5546 | switch (ip.indexToKey(val)) { |
| 5547 | .undef => return ip.get(gpa, .{ .undef = new_ty }), |
| 5548 | .extern_func => |extern_func| if (ip.isFunctionType(new_ty)) |
| 5549 | return ip.get(gpa, .{ .extern_func = .{ |
| 5550 | .ty = new_ty, |
| 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 | 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 | 5582 | else => {}, |
| 5544 | 5583 | }, |
| 5545 | | .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty)) |
| 5546 | | return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty), |
| 5547 | | .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) { |
| 5548 | | .enum_type => |enum_type| { |
| 5549 | | const index = enum_type.nameIndex(ip, enum_literal).?; |
| 5550 | | return ip.get(gpa, .{ .enum_tag = .{ |
| 5551 | | .ty = new_ty, |
| 5552 | | .int = if (enum_type.values.len != 0) |
| 5553 | | enum_type.values[index] |
| 5554 | | else |
| 5555 | | try ip.get(gpa, .{ .int = .{ |
| 5556 | | .ty = enum_type.tag_ty, |
| 5557 | | .storage = .{ .u64 = index }, |
| 5558 | | } }), |
| 5559 | | } }); |
| 5560 | | }, |
| 5584 | else => {}, |
| 5585 | }, |
| 5586 | .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty)) |
| 5587 | return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty), |
| 5588 | .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) { |
| 5589 | .enum_type => |enum_type| { |
| 5590 | const index = enum_type.nameIndex(ip, enum_literal).?; |
| 5591 | return ip.get(gpa, .{ .enum_tag = .{ |
| 5592 | .ty = new_ty, |
| 5593 | .int = if (enum_type.values.len != 0) |
| 5594 | enum_type.values[index] |
| 5595 | else |
| 5596 | try ip.get(gpa, .{ .int = .{ |
| 5597 | .ty = enum_type.tag_ty, |
| 5598 | .storage = .{ .u64 = index }, |
| 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 | 5613 | else => {}, |
| 5562 | 5614 | }, |
| 5563 | | .ptr => |ptr| if (ip.isPointerType(new_ty)) |
| 5564 | | return ip.get(gpa, .{ .ptr = .{ |
| 5615 | .opt => |opt| switch (ip.indexToKey(new_ty)) { |
| 5616 | .ptr_type => |ptr_type| return switch (opt.val) { |
| 5617 | .none => try ip.get(gpa, .{ .ptr = .{ |
| 5565 | 5618 | .ty = new_ty, |
| 5566 | | .addr = ptr.addr, |
| 5567 | | .len = ptr.len, |
| 5568 | | } }) |
| 5569 | | else if (ip.isIntegerType(new_ty)) |
| 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), |
| 5619 | .addr = .{ .int = .zero_usize }, |
| 5620 | .len = switch (ptr_type.flags.size) { |
| 5621 | .One, .Many, .C => .none, |
| 5622 | .Slice => try ip.get(gpa, .{ .undef = .usize_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)) |
| 5596 | | return ip.get(gpa, .{ .err = .{ |
| 5597 | | .ty = new_ty, |
| 5598 | | .name = err.name, |
| 5599 | | } }) |
| 5600 | | else if (ip.isErrorUnionType(new_ty)) |
| 5601 | | return ip.get(gpa, .{ .error_union = .{ |
| 5602 | | .ty = new_ty, |
| 5603 | | .val = .{ .err_name = err.name }, |
| 5604 | | } }), |
| 5605 | | .error_union => |error_union| if (ip.isErrorUnionType(new_ty)) |
| 5606 | | return ip.get(gpa, .{ .error_union = .{ |
| 5607 | | .ty = new_ty, |
| 5608 | | .val = error_union.val, |
| 5609 | | } }), |
| 5610 | | .aggregate => |aggregate| { |
| 5611 | | const new_len = @as(usize, @intCast(ip.aggregateTypeLen(new_ty))); |
| 5612 | | direct: { |
| 5613 | | const old_ty_child = switch (ip.indexToKey(old_ty)) { |
| 5614 | | inline .array_type, .vector_type => |seq_type| seq_type.child, |
| 5615 | | .anon_struct_type, .struct_type => break :direct, |
| 5616 | | else => unreachable, |
| 5617 | | }; |
| 5618 | | const new_ty_child = switch (ip.indexToKey(new_ty)) { |
| 5619 | | inline .array_type, .vector_type => |seq_type| seq_type.child, |
| 5620 | | .anon_struct_type, .struct_type => break :direct, |
| 5621 | | else => unreachable, |
| 5622 | | }; |
| 5623 | | if (old_ty_child != new_ty_child) break :direct; |
| 5624 | | // TODO: write something like getCoercedInts to avoid needing to dupe here |
| 5625 | | switch (aggregate.storage) { |
| 5626 | | .bytes => |bytes| { |
| 5627 | | const bytes_copy = try gpa.dupe(u8, bytes[0..new_len]); |
| 5628 | | defer gpa.free(bytes_copy); |
| 5629 | | return ip.get(gpa, .{ .aggregate = .{ |
| 5630 | | .ty = new_ty, |
| 5631 | | .storage = .{ .bytes = bytes_copy }, |
| 5632 | | } }); |
| 5633 | | }, |
| 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. |
| 5627 | .opt_type => |child_type| return try ip.get(gpa, .{ .opt = .{ |
| 5628 | .ty = new_ty, |
| 5629 | .val = switch (opt.val) { |
| 5630 | .none => .none, |
| 5631 | else => try ip.getCoerced(gpa, opt.val, child_type), |
| 5632 | }, |
| 5633 | } }), |
| 5634 | else => {}, |
| 5635 | }, |
| 5636 | .err => |err| if (ip.isErrorSetType(new_ty)) |
| 5637 | return ip.get(gpa, .{ .err = .{ |
| 5638 | .ty = new_ty, |
| 5639 | .name = err.name, |
| 5640 | } }) |
| 5641 | else if (ip.isErrorUnionType(new_ty)) |
| 5642 | return ip.get(gpa, .{ .error_union = .{ |
| 5643 | .ty = new_ty, |
| 5644 | .val = .{ .err_name = err.name }, |
| 5645 | } }), |
| 5646 | .error_union => |error_union| if (ip.isErrorUnionType(new_ty)) |
| 5647 | return ip.get(gpa, .{ .error_union = .{ |
| 5648 | .ty = new_ty, |
| 5649 | .val = error_union.val, |
| 5650 | } }), |
| 5651 | .aggregate => |aggregate| { |
| 5652 | const new_len = @as(usize, @intCast(ip.aggregateTypeLen(new_ty))); |
| 5653 | direct: { |
| 5654 | const old_ty_child = switch (ip.indexToKey(old_ty)) { |
| 5655 | inline .array_type, .vector_type => |seq_type| seq_type.child, |
| 5656 | .anon_struct_type, .struct_type => break :direct, |
| 5657 | else => unreachable, |
| 5658 | }; |
| 5659 | const new_ty_child = switch (ip.indexToKey(new_ty)) { |
| 5660 | inline .array_type, .vector_type => |seq_type| seq_type.child, |
| 5661 | .anon_struct_type, .struct_type => break :direct, |
| 5662 | else => unreachable, |
| 5663 | }; |
| 5664 | if (old_ty_child != new_ty_child) break :direct; |
| 5665 | // TODO: write something like getCoercedInts to avoid needing to dupe here |
| 5656 | 5666 | switch (aggregate.storage) { |
| 5657 | | .bytes => { |
| 5658 | | // We have to intern each value here, so unfortunately we can't easily avoid |
| 5659 | | // the repeated indexToKey calls. |
| 5660 | | for (agg_elems, 0..) |*elem, i| { |
| 5661 | | const x = ip.indexToKey(val).aggregate.storage.bytes[i]; |
| 5662 | | elem.* = try ip.get(gpa, .{ .int = .{ |
| 5663 | | .ty = .u8_type, |
| 5664 | | .storage = .{ .u64 = x }, |
| 5665 | | } }); |
| 5666 | | } |
| 5667 | .bytes => |bytes| { |
| 5668 | const bytes_copy = try gpa.dupe(u8, bytes[0..new_len]); |
| 5669 | defer gpa.free(bytes_copy); |
| 5670 | return ip.get(gpa, .{ .aggregate = .{ |
| 5671 | .ty = new_ty, |
| 5672 | .storage = .{ .bytes = bytes_copy }, |
| 5673 | } }); |
| 5674 | }, |
| 5675 | .elems => |elems| { |
| 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 } } }); |
| 5683 | | }, |
| 5684 | | else => {}, |
| 5690 | } |
| 5691 | // Direct approach failed - we must recursively coerce elems |
| 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 | 5728 | switch (ip.indexToKey(new_ty)) { |
| 5688 | 5729 | .opt_type => |child_type| switch (val) { |
| 5689 | 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 | 5752 | unreachable; |
| 5712 | 5753 | } |
| 5713 | 5754 | |
| 5755 | fn 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 | |
| 5765 | fn 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 | |
| 5775 | fn 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 | 5803 | /// Asserts `val` has an integer type. |
| 5715 | 5804 | /// Assumes `new_ty` is an integer type. |
| 5716 | 5805 | pub 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 | 6114 | break :b @sizeOf(Tag.FuncInstance) + @sizeOf(Index) * params_len + |
| 6026 | 6115 | @sizeOf(Module.Decl); |
| 6027 | 6116 | }, |
| 6117 | .func_coerced => @sizeOf(Tag.FuncCoerced), |
| 6028 | 6118 | .only_possible_value => 0, |
| 6029 | 6119 | .union_value => @sizeOf(Key.Union), |
| 6030 | 6120 | |
| ... | ... | @@ -6131,6 +6221,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void { |
| 6131 | 6221 | .extern_func, |
| 6132 | 6222 | .func_decl, |
| 6133 | 6223 | .func_instance, |
| 6224 | .func_coerced, |
| 6134 | 6225 | .union_value, |
| 6135 | 6226 | .memoized_call, |
| 6136 | 6227 | => try w.print("{d}", .{data}), |
| ... | ... | @@ -6471,7 +6562,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 6471 | 6562 | .undef, |
| 6472 | 6563 | .opt_null, |
| 6473 | 6564 | .only_possible_value, |
| 6474 | | => @as(Index, @enumFromInt(ip.items.items(.data)[@intFromEnum(index)])), |
| 6565 | => @enumFromInt(ip.items.items(.data)[@intFromEnum(index)]), |
| 6475 | 6566 | |
| 6476 | 6567 | .simple_value => unreachable, // handled via Index above |
| 6477 | 6568 | |
| ... | ... | @@ -6497,6 +6588,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 6497 | 6588 | .extern_func, |
| 6498 | 6589 | .func_decl, |
| 6499 | 6590 | .func_instance, |
| 6591 | .func_coerced, |
| 6500 | 6592 | .union_value, |
| 6501 | 6593 | .bytes, |
| 6502 | 6594 | .aggregate, |
| ... | ... | @@ -6504,7 +6596,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 6504 | 6596 | => |t| { |
| 6505 | 6597 | const extra_index = ip.items.items(.data)[@intFromEnum(index)]; |
| 6506 | 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 | }, |
| 6509 | 6601 | |
| 6510 | 6602 | .int_u8 => .u8_type, |
| ... | ... | @@ -6850,6 +6942,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois |
| 6850 | 6942 | .extern_func, |
| 6851 | 6943 | .func_decl, |
| 6852 | 6944 | .func_instance, |
| 6945 | .func_coerced, |
| 6853 | 6946 | .only_possible_value, |
| 6854 | 6947 | .union_value, |
| 6855 | 6948 | .bytes, |
| ... | ... | @@ -6866,7 +6959,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois |
| 6866 | 6959 | pub fn isFuncBody(ip: *const InternPool, i: Index) bool { |
| 6867 | 6960 | assert(i != .none); |
| 6868 | 6961 | return switch (ip.items.items(.tag)[@intFromEnum(i)]) { |
| 6869 | | .func_decl, .func_instance => true, |
| 6962 | .func_decl, .func_instance, .func_coerced => true, |
| 6870 | 6963 | else => false, |
| 6871 | 6964 | }; |
| 6872 | 6965 | } |