| author | |
| committer | |
| log | ed2364a1480f99a7380285cec15ff1962d9df519 |
| tree | da488724987e43e11a5938589a9df5b92c79d8c4 |
| parent | 6f303c01f3e06fe8203563065ea32537f6eff456 |
13 files changed, 392 insertions(+), 141 deletions(-)
src/Sema.zig+128-34| ... | @@ -7704,7 +7704,7 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -7704,7 +7704,7 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 7704 | const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs); | 7704 | const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs); |
| 7705 | 7705 | ||
| 7706 | // tuples are structs but they don't have a namespace | 7706 | // tuples are structs but they don't have a namespace |
| 7707 | if (container_type.isTuple()) return Air.Inst.Ref.bool_false; | 7707 | if (container_type.isTupleOrAnonStruct()) return Air.Inst.Ref.bool_false; |
| 7708 | const namespace = container_type.getNamespace() orelse return sema.fail( | 7708 | const namespace = container_type.getNamespace() orelse return sema.fail( |
| 7709 | block, | 7709 | block, |
| 7710 | lhs_src, | 7710 | lhs_src, |
| ... | @@ -10615,15 +10615,19 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -10615,15 +10615,19 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 10615 | const layout = struct_ty.containerLayout(); | 10615 | const layout = struct_ty.containerLayout(); |
| 10616 | 10616 | ||
| 10617 | const struct_field_vals = fv: { | 10617 | const struct_field_vals = fv: { |
| 10618 | if (struct_ty.castTag(.tuple)) |payload| { | 10618 | if (struct_ty.isTupleOrAnonStruct()) { |
| 10619 | const field_types = payload.data.types; | 10619 | const tuple = struct_ty.tupleFields(); |
| 10620 | const field_types = tuple.types; | ||
| 10620 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len); | 10621 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len); |
| 10621 | for (struct_field_vals) |*struct_field_val, i| { | 10622 | for (struct_field_vals) |*struct_field_val, i| { |
| 10622 | const field_ty = field_types[i]; | 10623 | const field_ty = field_types[i]; |
| 10623 | const name_val = v: { | 10624 | const name_val = v: { |
| 10624 | var anon_decl = try block.startAnonDecl(src); | 10625 | var anon_decl = try block.startAnonDecl(src); |
| 10625 | defer anon_decl.deinit(); | 10626 | defer anon_decl.deinit(); |
| 10626 | const bytes = try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i}); | 10627 | const bytes = if (struct_ty.castTag(.anon_struct)) |payload| |
| 10628 | try anon_decl.arena().dupeZ(u8, payload.data.names[i]) | ||
| 10629 | else | ||
| 10630 | try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i}); | ||
| 10627 | const new_decl = try anon_decl.finish( | 10631 | const new_decl = try anon_decl.finish( |
| 10628 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | 10632 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), |
| 10629 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | 10633 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), |
| ... | @@ -10632,7 +10636,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -10632,7 +10636,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 10632 | }; | 10636 | }; |
| 10633 | 10637 | ||
| 10634 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); | 10638 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); |
| 10635 | const field_val = payload.data.values[i]; | 10639 | const field_val = tuple.values[i]; |
| 10636 | const is_comptime = field_val.tag() != .unreachable_value; | 10640 | const is_comptime = field_val.tag() != .unreachable_value; |
| 10637 | const opt_default_val = if (is_comptime) field_val else null; | 10641 | const opt_default_val = if (is_comptime) field_val else null; |
| 10638 | const default_val_ptr = try sema.optRefValue(block, src, field_ty, opt_default_val); | 10642 | const default_val_ptr = try sema.optRefValue(block, src, field_ty, opt_default_val); |
| ... | @@ -11631,12 +11635,86 @@ fn finishStructInit( | ... | @@ -11631,12 +11635,86 @@ fn finishStructInit( |
| 11631 | return block.addAggregateInit(struct_ty, field_inits); | 11635 | return block.addAggregateInit(struct_ty, field_inits); |
| 11632 | } | 11636 | } |
| 11633 | 11637 | ||
| 11634 | fn zirStructInitAnon(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref { | 11638 | fn zirStructInitAnon( |
| 11639 | sema: *Sema, | ||
| 11640 | block: *Block, | ||
| 11641 | inst: Zir.Inst.Index, | ||
| 11642 | is_ref: bool, | ||
| 11643 | ) CompileError!Air.Inst.Ref { | ||
| 11635 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 11644 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 11636 | const src = inst_data.src(); | 11645 | const src = inst_data.src(); |
| 11646 | const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); | ||
| 11647 | const types = try sema.arena.alloc(Type, extra.data.fields_len); | ||
| 11648 | const values = try sema.arena.alloc(Value, types.len); | ||
| 11649 | const names = try sema.arena.alloc([]const u8, types.len); | ||
| 11650 | |||
| 11651 | const opt_runtime_src = rs: { | ||
| 11652 | var runtime_src: ?LazySrcLoc = null; | ||
| 11653 | var extra_index = extra.end; | ||
| 11654 | for (types) |*field_ty, i| { | ||
| 11655 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); | ||
| 11656 | extra_index = item.end; | ||
| 11637 | 11657 | ||
| 11638 | _ = is_ref; | 11658 | names[i] = sema.code.nullTerminatedString(item.data.field_name); |
| 11639 | return sema.fail(block, src, "TODO: Sema.zirStructInitAnon", .{}); | 11659 | const init = sema.resolveInst(item.data.init); |
| 11660 | field_ty.* = sema.typeOf(init); | ||
| 11661 | const init_src = src; // TODO better source location | ||
| 11662 | if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| { | ||
| 11663 | values[i] = init_val; | ||
| 11664 | } else { | ||
| 11665 | values[i] = Value.initTag(.unreachable_value); | ||
| 11666 | runtime_src = init_src; | ||
| 11667 | } | ||
| 11668 | } | ||
| 11669 | break :rs runtime_src; | ||
| 11670 | }; | ||
| 11671 | |||
| 11672 | const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{ | ||
| 11673 | .names = names, | ||
| 11674 | .types = types, | ||
| 11675 | .values = values, | ||
| 11676 | }); | ||
| 11677 | |||
| 11678 | const runtime_src = opt_runtime_src orelse { | ||
| 11679 | const tuple_val = try Value.Tag.@"struct".create(sema.arena, values); | ||
| 11680 | return sema.addConstantMaybeRef(block, src, tuple_ty, tuple_val, is_ref); | ||
| 11681 | }; | ||
| 11682 | |||
| 11683 | try sema.requireRuntimeBlock(block, runtime_src); | ||
| 11684 | |||
| 11685 | if (is_ref) { | ||
| 11686 | const target = sema.mod.getTarget(); | ||
| 11687 | const alloc = try block.addTy(.alloc, tuple_ty); | ||
| 11688 | var extra_index = extra.end; | ||
| 11689 | for (types) |field_ty, i_usize| { | ||
| 11690 | const i = @intCast(u32, i_usize); | ||
| 11691 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); | ||
| 11692 | extra_index = item.end; | ||
| 11693 | |||
| 11694 | const field_ptr_ty = try Type.ptr(sema.arena, target, .{ | ||
| 11695 | .mutable = true, | ||
| 11696 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | ||
| 11697 | .pointee_type = field_ty, | ||
| 11698 | }); | ||
| 11699 | if (values[i].tag() == .unreachable_value) { | ||
| 11700 | const init = sema.resolveInst(item.data.init); | ||
| 11701 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); | ||
| 11702 | _ = try block.addBinOp(.store, field_ptr, init); | ||
| 11703 | } | ||
| 11704 | } | ||
| 11705 | |||
| 11706 | return alloc; | ||
| 11707 | } | ||
| 11708 | |||
| 11709 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, types.len); | ||
| 11710 | var extra_index = extra.end; | ||
| 11711 | for (types) |_, i| { | ||
| 11712 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); | ||
| 11713 | extra_index = item.end; | ||
| 11714 | element_refs[i] = sema.resolveInst(item.data.init); | ||
| 11715 | } | ||
| 11716 | |||
| 11717 | return block.addAggregateInit(tuple_ty, element_refs); | ||
| 11640 | } | 11718 | } |
| 11641 | 11719 | ||
| 11642 | fn zirArrayInit( | 11720 | fn zirArrayInit( |
| ... | @@ -11764,8 +11842,10 @@ fn zirArrayInitAnon( | ... | @@ -11764,8 +11842,10 @@ fn zirArrayInitAnon( |
| 11764 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 11842 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 11765 | .pointee_type = types[i], | 11843 | .pointee_type = types[i], |
| 11766 | }); | 11844 | }); |
| 11767 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); | 11845 | if (values[i].tag() == .unreachable_value) { |
| 11768 | _ = try block.addBinOp(.store, field_ptr, sema.resolveInst(operand)); | 11846 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 11847 | _ = try block.addBinOp(.store, field_ptr, sema.resolveInst(operand)); | ||
| 11848 | } | ||
| 11769 | } | 11849 | } |
| 11770 | 11850 | ||
| 11771 | return alloc; | 11851 | return alloc; |
| ... | @@ -12126,7 +12206,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -12126,7 +12206,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 12126 | .size = ptr_size, | 12206 | .size = ptr_size, |
| 12127 | .mutable = !is_const_val.toBool(), | 12207 | .mutable = !is_const_val.toBool(), |
| 12128 | .@"volatile" = is_volatile_val.toBool(), | 12208 | .@"volatile" = is_volatile_val.toBool(), |
| 12129 | .@"align" = @intCast(u8, alignment_val.toUnsignedInt()), // TODO: Validate this value. | 12209 | .@"align" = @intCast(u16, alignment_val.toUnsignedInt()), // TODO: Validate this value. |
| 12130 | .@"addrspace" = address_space_val.toEnum(std.builtin.AddressSpace), | 12210 | .@"addrspace" = address_space_val.toEnum(std.builtin.AddressSpace), |
| 12131 | .pointee_type = try child_ty.copy(sema.arena), | 12211 | .pointee_type = try child_ty.copy(sema.arena), |
| 12132 | .@"allowzero" = is_allowzero_val.toBool(), | 12212 | .@"allowzero" = is_allowzero_val.toBool(), |
| ... | @@ -14842,29 +14922,43 @@ fn structFieldVal( | ... | @@ -14842,29 +14922,43 @@ fn structFieldVal( |
| 14842 | assert(unresolved_struct_ty.zigTypeTag() == .Struct); | 14922 | assert(unresolved_struct_ty.zigTypeTag() == .Struct); |
| 14843 | 14923 | ||
| 14844 | const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); | 14924 | const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); |
| 14845 | if (struct_ty.isTuple()) { | 14925 | switch (struct_ty.tag()) { |
| 14846 | return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); | 14926 | .tuple, .empty_struct_literal => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty), |
| 14847 | } | 14927 | .anon_struct => { |
| 14928 | const anon_struct = struct_ty.castTag(.anon_struct).?.data; | ||
| 14848 | 14929 | ||
| 14849 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 14930 | const field_index = for (anon_struct.names) |name, i| { |
| 14931 | if (mem.eql(u8, name, field_name)) break @intCast(u32, i); | ||
| 14932 | } else { | ||
| 14933 | return sema.fail(block, field_name_src, "anonymous struct {} has no such field '{s}'", .{ | ||
| 14934 | struct_ty, field_name, | ||
| 14935 | }); | ||
| 14936 | }; | ||
| 14937 | return tupleFieldValByIndex(sema, block, src, struct_byval, field_index, struct_ty); | ||
| 14938 | }, | ||
| 14939 | .@"struct" => { | ||
| 14940 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | ||
| 14850 | 14941 | ||
| 14851 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | 14942 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse |
| 14852 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | 14943 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); |
| 14853 | const field_index = @intCast(u32, field_index_usize); | 14944 | const field_index = @intCast(u32, field_index_usize); |
| 14854 | const field = struct_obj.fields.values()[field_index]; | 14945 | const field = struct_obj.fields.values()[field_index]; |
| 14855 | 14946 | ||
| 14856 | if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| { | 14947 | if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| { |
| 14857 | if (struct_val.isUndef()) return sema.addConstUndef(field.ty); | 14948 | if (struct_val.isUndef()) return sema.addConstUndef(field.ty); |
| 14858 | if ((try sema.typeHasOnePossibleValue(block, src, field.ty))) |opv| { | 14949 | if ((try sema.typeHasOnePossibleValue(block, src, field.ty))) |opv| { |
| 14859 | return sema.addConstant(field.ty, opv); | 14950 | return sema.addConstant(field.ty, opv); |
| 14860 | } | 14951 | } |
| 14861 | 14952 | ||
| 14862 | const field_values = struct_val.castTag(.@"struct").?.data; | 14953 | const field_values = struct_val.castTag(.@"struct").?.data; |
| 14863 | return sema.addConstant(field.ty, field_values[field_index]); | 14954 | return sema.addConstant(field.ty, field_values[field_index]); |
| 14864 | } | 14955 | } |
| 14865 | 14956 | ||
| 14866 | try sema.requireRuntimeBlock(block, src); | 14957 | try sema.requireRuntimeBlock(block, src); |
| 14867 | return block.addStructFieldVal(struct_byval, field_index, field.ty); | 14958 | return block.addStructFieldVal(struct_byval, field_index, field.ty); |
| 14959 | }, | ||
| 14960 | else => unreachable, | ||
| 14961 | } | ||
| 14868 | } | 14962 | } |
| 14869 | 14963 | ||
| 14870 | fn tupleFieldVal( | 14964 | fn tupleFieldVal( |
| ... | @@ -14901,7 +14995,7 @@ fn tupleFieldValByIndex( | ... | @@ -14901,7 +14995,7 @@ fn tupleFieldValByIndex( |
| 14901 | field_index: u32, | 14995 | field_index: u32, |
| 14902 | tuple_ty: Type, | 14996 | tuple_ty: Type, |
| 14903 | ) CompileError!Air.Inst.Ref { | 14997 | ) CompileError!Air.Inst.Ref { |
| 14904 | const tuple = tuple_ty.castTag(.tuple).?.data; | 14998 | const tuple = tuple_ty.tupleFields(); |
| 14905 | const field_ty = tuple.types[field_index]; | 14999 | const field_ty = tuple.types[field_index]; |
| 14906 | 15000 | ||
| 14907 | if (tuple.values[field_index].tag() != .unreachable_value) { | 15001 | if (tuple.values[field_index].tag() != .unreachable_value) { |
| ... | @@ -18954,8 +19048,8 @@ pub fn typeHasOnePossibleValue( | ... | @@ -18954,8 +19048,8 @@ pub fn typeHasOnePossibleValue( |
| 18954 | return Value.initTag(.empty_struct_value); | 19048 | return Value.initTag(.empty_struct_value); |
| 18955 | }, | 19049 | }, |
| 18956 | 19050 | ||
| 18957 | .tuple => { | 19051 | .tuple, .anon_struct => { |
| 18958 | const tuple = ty.castTag(.tuple).?.data; | 19052 | const tuple = ty.tupleFields(); |
| 18959 | for (tuple.values) |val| { | 19053 | for (tuple.values) |val| { |
| 18960 | if (val.tag() == .unreachable_value) { | 19054 | if (val.tag() == .unreachable_value) { |
| 18961 | return null; // non-comptime field | 19055 | return null; // non-comptime field |
| ... | @@ -19583,8 +19677,8 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C | ... | @@ -19583,8 +19677,8 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C |
| 19583 | return sema.typeRequiresComptime(block, src, ty.optionalChild(&buf)); | 19677 | return sema.typeRequiresComptime(block, src, ty.optionalChild(&buf)); |
| 19584 | }, | 19678 | }, |
| 19585 | 19679 | ||
| 19586 | .tuple => { | 19680 | .tuple, .anon_struct => { |
| 19587 | const tuple = ty.castTag(.tuple).?.data; | 19681 | const tuple = ty.tupleFields(); |
| 19588 | for (tuple.types) |field_ty, i| { | 19682 | for (tuple.types) |field_ty, i| { |
| 19589 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; | 19683 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; |
| 19590 | if (!have_comptime_val and try sema.typeRequiresComptime(block, src, field_ty)) { | 19684 | if (!have_comptime_val and try sema.typeRequiresComptime(block, src, field_ty)) { |
src/Zir.zig+3-1| ... | @@ -2850,7 +2850,9 @@ pub const Inst = struct { | ... | @@ -2850,7 +2850,9 @@ pub const Inst = struct { |
| 2850 | }; | 2850 | }; |
| 2851 | }; | 2851 | }; |
| 2852 | 2852 | ||
| 2853 | /// Trailing is an item per field. | 2853 | /// Trailing is an Item per field. |
| 2854 | /// TODO make this instead array of inits followed by array of names because | ||
| 2855 | /// it will be simpler Sema code and better for CPU cache. | ||
| 2854 | pub const StructInitAnon = struct { | 2856 | pub const StructInitAnon = struct { |
| 2855 | fields_len: u32, | 2857 | fields_len: u32, |
| 2856 | 2858 |
src/codegen/llvm.zig+3-3| ... | @@ -958,7 +958,7 @@ pub const DeclGen = struct { | ... | @@ -958,7 +958,7 @@ pub const DeclGen = struct { |
| 958 | // reference, we need to copy it here. | 958 | // reference, we need to copy it here. |
| 959 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); | 959 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); |
| 960 | 960 | ||
| 961 | if (t.isTuple()) { | 961 | if (t.isTupleOrAnonStruct()) { |
| 962 | const tuple = t.tupleFields(); | 962 | const tuple = t.tupleFields(); |
| 963 | const llvm_struct_ty = dg.context.structCreateNamed(""); | 963 | const llvm_struct_ty = dg.context.structCreateNamed(""); |
| 964 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | 964 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| ... | @@ -2104,7 +2104,7 @@ pub const DeclGen = struct { | ... | @@ -2104,7 +2104,7 @@ pub const DeclGen = struct { |
| 2104 | var zig_big_align: u32 = 0; | 2104 | var zig_big_align: u32 = 0; |
| 2105 | var llvm_big_align: u32 = 0; | 2105 | var llvm_big_align: u32 = 0; |
| 2106 | 2106 | ||
| 2107 | if (ty.isTuple()) { | 2107 | if (ty.isTupleOrAnonStruct()) { |
| 2108 | const tuple = ty.tupleFields(); | 2108 | const tuple = ty.tupleFields(); |
| 2109 | var llvm_field_index: c_uint = 0; | 2109 | var llvm_field_index: c_uint = 0; |
| 2110 | for (tuple.types) |field_ty, i| { | 2110 | for (tuple.types) |field_ty, i| { |
| ... | @@ -5704,7 +5704,7 @@ fn isByRef(ty: Type) bool { | ... | @@ -5704,7 +5704,7 @@ fn isByRef(ty: Type) bool { |
| 5704 | .Struct => { | 5704 | .Struct => { |
| 5705 | // Packed structs are represented to LLVM as integers. | 5705 | // Packed structs are represented to LLVM as integers. |
| 5706 | if (ty.containerLayout() == .Packed) return false; | 5706 | if (ty.containerLayout() == .Packed) return false; |
| 5707 | if (ty.isTuple()) { | 5707 | if (ty.isTupleOrAnonStruct()) { |
| 5708 | const tuple = ty.tupleFields(); | 5708 | const tuple = ty.tupleFields(); |
| 5709 | var count: usize = 0; | 5709 | var count: usize = 0; |
| 5710 | for (tuple.values) |field_val, i| { | 5710 | for (tuple.values) |field_val, i| { |
src/type.zig+151-24| ... | @@ -131,6 +131,7 @@ pub const Type = extern union { | ... | @@ -131,6 +131,7 @@ pub const Type = extern union { |
| 131 | .export_options, | 131 | .export_options, |
| 132 | .extern_options, | 132 | .extern_options, |
| 133 | .tuple, | 133 | .tuple, |
| 134 | .anon_struct, | ||
| 134 | => return .Struct, | 135 | => return .Struct, |
| 135 | 136 | ||
| 136 | .enum_full, | 137 | .enum_full, |
| ... | @@ -792,6 +793,42 @@ pub const Type = extern union { | ... | @@ -792,6 +793,42 @@ pub const Type = extern union { |
| 792 | 793 | ||
| 793 | return true; | 794 | return true; |
| 794 | }, | 795 | }, |
| 796 | .anon_struct => { | ||
| 797 | const a_struct_obj = a.castTag(.anon_struct).?.data; | ||
| 798 | const b_struct_obj = (b.castTag(.anon_struct) orelse return false).data; | ||
| 799 | |||
| 800 | if (a_struct_obj.types.len != b_struct_obj.types.len) return false; | ||
| 801 | |||
| 802 | for (a_struct_obj.names) |a_name, i| { | ||
| 803 | const b_name = b_struct_obj.names[i]; | ||
| 804 | if (!std.mem.eql(u8, a_name, b_name)) return false; | ||
| 805 | } | ||
| 806 | |||
| 807 | for (a_struct_obj.types) |a_ty, i| { | ||
| 808 | const b_ty = b_struct_obj.types[i]; | ||
| 809 | if (!eql(a_ty, b_ty)) return false; | ||
| 810 | } | ||
| 811 | |||
| 812 | for (a_struct_obj.values) |a_val, i| { | ||
| 813 | const ty = a_struct_obj.types[i]; | ||
| 814 | const b_val = b_struct_obj.values[i]; | ||
| 815 | if (a_val.tag() == .unreachable_value) { | ||
| 816 | if (b_val.tag() == .unreachable_value) { | ||
| 817 | continue; | ||
| 818 | } else { | ||
| 819 | return false; | ||
| 820 | } | ||
| 821 | } else { | ||
| 822 | if (b_val.tag() == .unreachable_value) { | ||
| 823 | return false; | ||
| 824 | } else { | ||
| 825 | if (!Value.eql(a_val, b_val, ty)) return false; | ||
| 826 | } | ||
| 827 | } | ||
| 828 | } | ||
| 829 | |||
| 830 | return true; | ||
| 831 | }, | ||
| 795 | 832 | ||
| 796 | // we can't compare these based on tags because it wouldn't detect if, | 833 | // we can't compare these based on tags because it wouldn't detect if, |
| 797 | // for example, a was resolved into .@"struct" but b was one of these tags. | 834 | // for example, a was resolved into .@"struct" but b was one of these tags. |
| ... | @@ -1062,6 +1099,20 @@ pub const Type = extern union { | ... | @@ -1062,6 +1099,20 @@ pub const Type = extern union { |
| 1062 | field_val.hash(field_ty, hasher); | 1099 | field_val.hash(field_ty, hasher); |
| 1063 | } | 1100 | } |
| 1064 | }, | 1101 | }, |
| 1102 | .anon_struct => { | ||
| 1103 | const struct_obj = ty.castTag(.anon_struct).?.data; | ||
| 1104 | std.hash.autoHash(hasher, std.builtin.TypeId.Struct); | ||
| 1105 | std.hash.autoHash(hasher, struct_obj.types.len); | ||
| 1106 | |||
| 1107 | for (struct_obj.types) |field_ty, i| { | ||
| 1108 | const field_name = struct_obj.names[i]; | ||
| 1109 | const field_val = struct_obj.values[i]; | ||
| 1110 | hasher.update(field_name); | ||
| 1111 | hashWithHasher(field_ty, hasher); | ||
| 1112 | if (field_val.tag() == .unreachable_value) continue; | ||
| 1113 | field_val.hash(field_ty, hasher); | ||
| 1114 | } | ||
| 1115 | }, | ||
| 1065 | 1116 | ||
| 1066 | // we can't hash these based on tags because they wouldn't match the expanded version. | 1117 | // we can't hash these based on tags because they wouldn't match the expanded version. |
| 1067 | .call_options, | 1118 | .call_options, |
| ... | @@ -1279,6 +1330,26 @@ pub const Type = extern union { | ... | @@ -1279,6 +1330,26 @@ pub const Type = extern union { |
| 1279 | .values = values, | 1330 | .values = values, |
| 1280 | }); | 1331 | }); |
| 1281 | }, | 1332 | }, |
| 1333 | .anon_struct => { | ||
| 1334 | const payload = self.castTag(.anon_struct).?.data; | ||
| 1335 | const names = try allocator.alloc([]const u8, payload.names.len); | ||
| 1336 | const types = try allocator.alloc(Type, payload.types.len); | ||
| 1337 | const values = try allocator.alloc(Value, payload.values.len); | ||
| 1338 | for (payload.names) |name, i| { | ||
| 1339 | names[i] = try allocator.dupe(u8, name); | ||
| 1340 | } | ||
| 1341 | for (payload.types) |ty, i| { | ||
| 1342 | types[i] = try ty.copy(allocator); | ||
| 1343 | } | ||
| 1344 | for (payload.values) |val, i| { | ||
| 1345 | values[i] = try val.copy(allocator); | ||
| 1346 | } | ||
| 1347 | return Tag.anon_struct.create(allocator, .{ | ||
| 1348 | .names = names, | ||
| 1349 | .types = types, | ||
| 1350 | .values = values, | ||
| 1351 | }); | ||
| 1352 | }, | ||
| 1282 | .function => { | 1353 | .function => { |
| 1283 | const payload = self.castTag(.function).?.data; | 1354 | const payload = self.castTag(.function).?.data; |
| 1284 | const param_types = try allocator.alloc(Type, payload.param_types.len); | 1355 | const param_types = try allocator.alloc(Type, payload.param_types.len); |
| ... | @@ -1533,6 +1604,26 @@ pub const Type = extern union { | ... | @@ -1533,6 +1604,26 @@ pub const Type = extern union { |
| 1533 | try writer.writeAll("}"); | 1604 | try writer.writeAll("}"); |
| 1534 | return; | 1605 | return; |
| 1535 | }, | 1606 | }, |
| 1607 | .anon_struct => { | ||
| 1608 | const anon_struct = ty.castTag(.anon_struct).?.data; | ||
| 1609 | try writer.writeAll("struct{"); | ||
| 1610 | for (anon_struct.types) |field_ty, i| { | ||
| 1611 | if (i != 0) try writer.writeAll(", "); | ||
| 1612 | const val = anon_struct.values[i]; | ||
| 1613 | if (val.tag() != .unreachable_value) { | ||
| 1614 | try writer.writeAll("comptime "); | ||
| 1615 | } | ||
| 1616 | try writer.writeAll(anon_struct.names[i]); | ||
| 1617 | try writer.writeAll(": "); | ||
| 1618 | try field_ty.format("", .{}, writer); | ||
| 1619 | if (val.tag() != .unreachable_value) { | ||
| 1620 | try writer.writeAll(" = "); | ||
| 1621 | try val.format("", .{}, writer); | ||
| 1622 | } | ||
| 1623 | } | ||
| 1624 | try writer.writeAll("}"); | ||
| 1625 | return; | ||
| 1626 | }, | ||
| 1536 | .single_const_pointer => { | 1627 | .single_const_pointer => { |
| 1537 | const pointee_type = ty.castTag(.single_const_pointer).?.data; | 1628 | const pointee_type = ty.castTag(.single_const_pointer).?.data; |
| 1538 | try writer.writeAll("*const "); | 1629 | try writer.writeAll("*const "); |
| ... | @@ -2020,8 +2111,8 @@ pub const Type = extern union { | ... | @@ -2020,8 +2111,8 @@ pub const Type = extern union { |
| 2020 | return payload.error_set.hasRuntimeBits() or payload.payload.hasRuntimeBits(); | 2111 | return payload.error_set.hasRuntimeBits() or payload.payload.hasRuntimeBits(); |
| 2021 | }, | 2112 | }, |
| 2022 | 2113 | ||
| 2023 | .tuple => { | 2114 | .tuple, .anon_struct => { |
| 2024 | const tuple = ty.castTag(.tuple).?.data; | 2115 | const tuple = ty.tupleFields(); |
| 2025 | for (tuple.types) |field_ty, i| { | 2116 | for (tuple.types) |field_ty, i| { |
| 2026 | const val = tuple.values[i]; | 2117 | const val = tuple.values[i]; |
| 2027 | if (val.tag() != .unreachable_value) continue; // comptime field | 2118 | if (val.tag() != .unreachable_value) continue; // comptime field |
| ... | @@ -2292,8 +2383,8 @@ pub const Type = extern union { | ... | @@ -2292,8 +2383,8 @@ pub const Type = extern union { |
| 2292 | return big_align; | 2383 | return big_align; |
| 2293 | }, | 2384 | }, |
| 2294 | 2385 | ||
| 2295 | .tuple => { | 2386 | .tuple, .anon_struct => { |
| 2296 | const tuple = self.castTag(.tuple).?.data; | 2387 | const tuple = self.tupleFields(); |
| 2297 | var big_align: u32 = 0; | 2388 | var big_align: u32 = 0; |
| 2298 | for (tuple.types) |field_ty, i| { | 2389 | for (tuple.types) |field_ty, i| { |
| 2299 | const val = tuple.values[i]; | 2390 | const val = tuple.values[i]; |
| ... | @@ -2375,7 +2466,7 @@ pub const Type = extern union { | ... | @@ -2375,7 +2466,7 @@ pub const Type = extern union { |
| 2375 | .void, | 2466 | .void, |
| 2376 | => 0, | 2467 | => 0, |
| 2377 | 2468 | ||
| 2378 | .@"struct", .tuple => switch (self.containerLayout()) { | 2469 | .@"struct", .tuple, .anon_struct => switch (self.containerLayout()) { |
| 2379 | .Packed => { | 2470 | .Packed => { |
| 2380 | const struct_obj = self.castTag(.@"struct").?.data; | 2471 | const struct_obj = self.castTag(.@"struct").?.data; |
| 2381 | var buf: Type.Payload.Bits = undefined; | 2472 | var buf: Type.Payload.Bits = undefined; |
| ... | @@ -2575,6 +2666,13 @@ pub const Type = extern union { | ... | @@ -2575,6 +2666,13 @@ pub const Type = extern union { |
| 2575 | .bound_fn => unreachable, | 2666 | .bound_fn => unreachable, |
| 2576 | 2667 | ||
| 2577 | .void => 0, | 2668 | .void => 0, |
| 2669 | .bool, .u1 => 1, | ||
| 2670 | .u8, .i8 => 8, | ||
| 2671 | .i16, .u16, .f16 => 16, | ||
| 2672 | .i32, .u32, .f32 => 32, | ||
| 2673 | .i64, .u64, .f64 => 64, | ||
| 2674 | .f80 => 80, | ||
| 2675 | .u128, .i128, .f128 => 128, | ||
| 2578 | 2676 | ||
| 2579 | .@"struct" => { | 2677 | .@"struct" => { |
| 2580 | const field_count = ty.structFieldCount(); | 2678 | const field_count = ty.structFieldCount(); |
| ... | @@ -2595,8 +2693,13 @@ pub const Type = extern union { | ... | @@ -2595,8 +2693,13 @@ pub const Type = extern union { |
| 2595 | } | 2693 | } |
| 2596 | }, | 2694 | }, |
| 2597 | 2695 | ||
| 2598 | .tuple => { | 2696 | .tuple, .anon_struct => { |
| 2599 | @panic("TODO bitSize tuples"); | 2697 | const tuple = ty.tupleFields(); |
| 2698 | var total: u64 = 0; | ||
| 2699 | for (tuple.types) |field_ty| { | ||
| 2700 | total += field_ty.bitSize(target); | ||
| 2701 | } | ||
| 2702 | return total; | ||
| 2600 | }, | 2703 | }, |
| 2601 | 2704 | ||
| 2602 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { | 2705 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { |
| ... | @@ -2608,10 +2711,6 @@ pub const Type = extern union { | ... | @@ -2608,10 +2711,6 @@ pub const Type = extern union { |
| 2608 | @panic("TODO bitSize unions"); | 2711 | @panic("TODO bitSize unions"); |
| 2609 | }, | 2712 | }, |
| 2610 | 2713 | ||
| 2611 | .u8, .i8 => 8, | ||
| 2612 | |||
| 2613 | .bool, .u1 => 1, | ||
| 2614 | |||
| 2615 | .vector => { | 2714 | .vector => { |
| 2616 | const payload = ty.castTag(.vector).?.data; | 2715 | const payload = ty.castTag(.vector).?.data; |
| 2617 | const elem_bit_size = payload.elem_type.bitSize(target); | 2716 | const elem_bit_size = payload.elem_type.bitSize(target); |
| ... | @@ -2634,11 +2733,6 @@ pub const Type = extern union { | ... | @@ -2634,11 +2733,6 @@ pub const Type = extern union { |
| 2634 | ); | 2733 | ); |
| 2635 | return payload.len * 8 * elem_size + payload.elem_type.bitSize(target); | 2734 | return payload.len * 8 * elem_size + payload.elem_type.bitSize(target); |
| 2636 | }, | 2735 | }, |
| 2637 | .i16, .u16, .f16 => 16, | ||
| 2638 | .i32, .u32, .f32 => 32, | ||
| 2639 | .i64, .u64, .f64 => 64, | ||
| 2640 | .f80 => 80, | ||
| 2641 | .u128, .i128, .f128 => 128, | ||
| 2642 | 2736 | ||
| 2643 | .isize, | 2737 | .isize, |
| 2644 | .usize, | 2738 | .usize, |
| ... | @@ -3295,7 +3389,7 @@ pub const Type = extern union { | ... | @@ -3295,7 +3389,7 @@ pub const Type = extern union { |
| 3295 | 3389 | ||
| 3296 | pub fn containerLayout(ty: Type) std.builtin.TypeInfo.ContainerLayout { | 3390 | pub fn containerLayout(ty: Type) std.builtin.TypeInfo.ContainerLayout { |
| 3297 | return switch (ty.tag()) { | 3391 | return switch (ty.tag()) { |
| 3298 | .tuple, .empty_struct_literal => .Auto, | 3392 | .tuple, .empty_struct_literal, .anon_struct => .Auto, |
| 3299 | .@"struct" => ty.castTag(.@"struct").?.data.layout, | 3393 | .@"struct" => ty.castTag(.@"struct").?.data.layout, |
| 3300 | .@"union" => ty.castTag(.@"union").?.data.layout, | 3394 | .@"union" => ty.castTag(.@"union").?.data.layout, |
| 3301 | .union_tagged => ty.castTag(.union_tagged).?.data.layout, | 3395 | .union_tagged => ty.castTag(.union_tagged).?.data.layout, |
| ... | @@ -3369,6 +3463,7 @@ pub const Type = extern union { | ... | @@ -3369,6 +3463,7 @@ pub const Type = extern union { |
| 3369 | .array_u8 => ty.castTag(.array_u8).?.data, | 3463 | .array_u8 => ty.castTag(.array_u8).?.data, |
| 3370 | .array_u8_sentinel_0 => ty.castTag(.array_u8_sentinel_0).?.data, | 3464 | .array_u8_sentinel_0 => ty.castTag(.array_u8_sentinel_0).?.data, |
| 3371 | .tuple => ty.castTag(.tuple).?.data.types.len, | 3465 | .tuple => ty.castTag(.tuple).?.data.types.len, |
| 3466 | .anon_struct => ty.castTag(.anon_struct).?.data.types.len, | ||
| 3372 | .@"struct" => ty.castTag(.@"struct").?.data.fields.count(), | 3467 | .@"struct" => ty.castTag(.@"struct").?.data.fields.count(), |
| 3373 | 3468 | ||
| 3374 | else => unreachable, | 3469 | else => unreachable, |
| ... | @@ -3383,6 +3478,7 @@ pub const Type = extern union { | ... | @@ -3383,6 +3478,7 @@ pub const Type = extern union { |
| 3383 | return switch (ty.tag()) { | 3478 | return switch (ty.tag()) { |
| 3384 | .vector => @intCast(u32, ty.castTag(.vector).?.data.len), | 3479 | .vector => @intCast(u32, ty.castTag(.vector).?.data.len), |
| 3385 | .tuple => @intCast(u32, ty.castTag(.tuple).?.data.types.len), | 3480 | .tuple => @intCast(u32, ty.castTag(.tuple).?.data.types.len), |
| 3481 | .anon_struct => @intCast(u32, ty.castTag(.anon_struct).?.data.types.len), | ||
| 3386 | else => unreachable, | 3482 | else => unreachable, |
| 3387 | }; | 3483 | }; |
| 3388 | } | 3484 | } |
| ... | @@ -3849,8 +3945,8 @@ pub const Type = extern union { | ... | @@ -3849,8 +3945,8 @@ pub const Type = extern union { |
| 3849 | return Value.initTag(.empty_struct_value); | 3945 | return Value.initTag(.empty_struct_value); |
| 3850 | }, | 3946 | }, |
| 3851 | 3947 | ||
| 3852 | .tuple => { | 3948 | .tuple, .anon_struct => { |
| 3853 | const tuple = ty.castTag(.tuple).?.data; | 3949 | const tuple = ty.tupleFields(); |
| 3854 | for (tuple.values) |val| { | 3950 | for (tuple.values) |val| { |
| 3855 | if (val.tag() == .unreachable_value) { | 3951 | if (val.tag() == .unreachable_value) { |
| 3856 | return null; // non-comptime field | 3952 | return null; // non-comptime field |
| ... | @@ -4048,8 +4144,8 @@ pub const Type = extern union { | ... | @@ -4048,8 +4144,8 @@ pub const Type = extern union { |
| 4048 | return ty.optionalChild(&buf).comptimeOnly(); | 4144 | return ty.optionalChild(&buf).comptimeOnly(); |
| 4049 | }, | 4145 | }, |
| 4050 | 4146 | ||
| 4051 | .tuple => { | 4147 | .tuple, .anon_struct => { |
| 4052 | const tuple = ty.castTag(.tuple).?.data; | 4148 | const tuple = ty.tupleFields(); |
| 4053 | for (tuple.types) |field_ty, i| { | 4149 | for (tuple.types) |field_ty, i| { |
| 4054 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; | 4150 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; |
| 4055 | if (!have_comptime_val and field_ty.comptimeOnly()) return true; | 4151 | if (!have_comptime_val and field_ty.comptimeOnly()) return true; |
| ... | @@ -4350,6 +4446,7 @@ pub const Type = extern union { | ... | @@ -4350,6 +4446,7 @@ pub const Type = extern union { |
| 4350 | }, | 4446 | }, |
| 4351 | .empty_struct, .empty_struct_literal => return 0, | 4447 | .empty_struct, .empty_struct_literal => return 0, |
| 4352 | .tuple => return ty.castTag(.tuple).?.data.types.len, | 4448 | .tuple => return ty.castTag(.tuple).?.data.types.len, |
| 4449 | .anon_struct => return ty.castTag(.anon_struct).?.data.types.len, | ||
| 4353 | else => unreachable, | 4450 | else => unreachable, |
| 4354 | } | 4451 | } |
| 4355 | } | 4452 | } |
| ... | @@ -4366,6 +4463,7 @@ pub const Type = extern union { | ... | @@ -4366,6 +4463,7 @@ pub const Type = extern union { |
| 4366 | return union_obj.fields.values()[index].ty; | 4463 | return union_obj.fields.values()[index].ty; |
| 4367 | }, | 4464 | }, |
| 4368 | .tuple => return ty.castTag(.tuple).?.data.types[index], | 4465 | .tuple => return ty.castTag(.tuple).?.data.types[index], |
| 4466 | .anon_struct => return ty.castTag(.anon_struct).?.data.types[index], | ||
| 4369 | else => unreachable, | 4467 | else => unreachable, |
| 4370 | } | 4468 | } |
| 4371 | } | 4469 | } |
| ... | @@ -4424,8 +4522,8 @@ pub const Type = extern union { | ... | @@ -4424,8 +4522,8 @@ pub const Type = extern union { |
| 4424 | return std.mem.alignForwardGeneric(u64, it.offset, it.big_align); | 4522 | return std.mem.alignForwardGeneric(u64, it.offset, it.big_align); |
| 4425 | }, | 4523 | }, |
| 4426 | 4524 | ||
| 4427 | .tuple => { | 4525 | .tuple, .anon_struct => { |
| 4428 | const tuple = ty.castTag(.tuple).?.data; | 4526 | const tuple = ty.tupleFields(); |
| 4429 | 4527 | ||
| 4430 | var offset: u64 = 0; | 4528 | var offset: u64 = 0; |
| 4431 | var big_align: u32 = 0; | 4529 | var big_align: u32 = 0; |
| ... | @@ -4700,6 +4798,8 @@ pub const Type = extern union { | ... | @@ -4700,6 +4798,8 @@ pub const Type = extern union { |
| 4700 | vector, | 4798 | vector, |
| 4701 | /// Possible Value tags for this: @"struct" | 4799 | /// Possible Value tags for this: @"struct" |
| 4702 | tuple, | 4800 | tuple, |
| 4801 | /// Possible Value tags for this: @"struct" | ||
| 4802 | anon_struct, | ||
| 4703 | pointer, | 4803 | pointer, |
| 4704 | single_const_pointer, | 4804 | single_const_pointer, |
| 4705 | single_mut_pointer, | 4805 | single_mut_pointer, |
| ... | @@ -4846,6 +4946,7 @@ pub const Type = extern union { | ... | @@ -4846,6 +4946,7 @@ pub const Type = extern union { |
| 4846 | .enum_numbered => Payload.EnumNumbered, | 4946 | .enum_numbered => Payload.EnumNumbered, |
| 4847 | .empty_struct => Payload.ContainerScope, | 4947 | .empty_struct => Payload.ContainerScope, |
| 4848 | .tuple => Payload.Tuple, | 4948 | .tuple => Payload.Tuple, |
| 4949 | .anon_struct => Payload.AnonStruct, | ||
| 4849 | }; | 4950 | }; |
| 4850 | } | 4951 | } |
| 4851 | 4952 | ||
| ... | @@ -4869,12 +4970,26 @@ pub const Type = extern union { | ... | @@ -4869,12 +4970,26 @@ pub const Type = extern union { |
| 4869 | }; | 4970 | }; |
| 4870 | 4971 | ||
| 4871 | pub fn isTuple(ty: Type) bool { | 4972 | pub fn isTuple(ty: Type) bool { |
| 4872 | return ty.tag() == .tuple or ty.tag() == .empty_struct_literal; | 4973 | return switch (ty.tag()) { |
| 4974 | .tuple, .empty_struct_literal => true, | ||
| 4975 | else => false, | ||
| 4976 | }; | ||
| 4977 | } | ||
| 4978 | |||
| 4979 | pub fn isTupleOrAnonStruct(ty: Type) bool { | ||
| 4980 | return switch (ty.tag()) { | ||
| 4981 | .tuple, .empty_struct_literal, .anon_struct => true, | ||
| 4982 | else => false, | ||
| 4983 | }; | ||
| 4873 | } | 4984 | } |
| 4874 | 4985 | ||
| 4875 | pub fn tupleFields(ty: Type) Payload.Tuple.Data { | 4986 | pub fn tupleFields(ty: Type) Payload.Tuple.Data { |
| 4876 | return switch (ty.tag()) { | 4987 | return switch (ty.tag()) { |
| 4877 | .tuple => ty.castTag(.tuple).?.data, | 4988 | .tuple => ty.castTag(.tuple).?.data, |
| 4989 | .anon_struct => .{ | ||
| 4990 | .types = ty.castTag(.anon_struct).?.data.types, | ||
| 4991 | .values = ty.castTag(.anon_struct).?.data.values, | ||
| 4992 | }, | ||
| 4878 | .empty_struct_literal => .{ .types = &.{}, .values = &.{} }, | 4993 | .empty_struct_literal => .{ .types = &.{}, .values = &.{} }, |
| 4879 | else => unreachable, | 4994 | else => unreachable, |
| 4880 | }; | 4995 | }; |
| ... | @@ -5042,6 +5157,18 @@ pub const Type = extern union { | ... | @@ -5042,6 +5157,18 @@ pub const Type = extern union { |
| 5042 | }; | 5157 | }; |
| 5043 | }; | 5158 | }; |
| 5044 | 5159 | ||
| 5160 | pub const AnonStruct = struct { | ||
| 5161 | base: Payload = .{ .tag = .anon_struct }, | ||
| 5162 | data: Data, | ||
| 5163 | |||
| 5164 | pub const Data = struct { | ||
| 5165 | names: []const []const u8, | ||
| 5166 | types: []Type, | ||
| 5167 | /// unreachable_value elements are used to indicate runtime-known. | ||
| 5168 | values: []Value, | ||
| 5169 | }; | ||
| 5170 | }; | ||
| 5171 | |||
| 5045 | pub const Union = struct { | 5172 | pub const Union = struct { |
| 5046 | base: Payload, | 5173 | base: Payload, |
| 5047 | data: *Module.Union, | 5174 | data: *Module.Union, |
src/value.zig+2-2| ... | @@ -1895,7 +1895,7 @@ pub const Value = extern union { | ... | @@ -1895,7 +1895,7 @@ pub const Value = extern union { |
| 1895 | const a_field_vals = a.castTag(.@"struct").?.data; | 1895 | const a_field_vals = a.castTag(.@"struct").?.data; |
| 1896 | const b_field_vals = b.castTag(.@"struct").?.data; | 1896 | const b_field_vals = b.castTag(.@"struct").?.data; |
| 1897 | assert(a_field_vals.len == b_field_vals.len); | 1897 | assert(a_field_vals.len == b_field_vals.len); |
| 1898 | if (ty.isTuple()) { | 1898 | if (ty.isTupleOrAnonStruct()) { |
| 1899 | const types = ty.tupleFields().types; | 1899 | const types = ty.tupleFields().types; |
| 1900 | assert(types.len == a_field_vals.len); | 1900 | assert(types.len == a_field_vals.len); |
| 1901 | for (types) |field_ty, i| { | 1901 | for (types) |field_ty, i| { |
| ... | @@ -2031,7 +2031,7 @@ pub const Value = extern union { | ... | @@ -2031,7 +2031,7 @@ pub const Value = extern union { |
| 2031 | } | 2031 | } |
| 2032 | }, | 2032 | }, |
| 2033 | .Struct => { | 2033 | .Struct => { |
| 2034 | if (ty.isTuple()) { | 2034 | if (ty.isTupleOrAnonStruct()) { |
| 2035 | const fields = ty.tupleFields(); | 2035 | const fields = ty.tupleFields(); |
| 2036 | for (fields.values) |field_val, i| { | 2036 | for (fields.values) |field_val, i| { |
| 2037 | field_val.hash(fields.types[i], hasher); | 2037 | field_val.hash(fields.types[i], hasher); |
test/behavior.zig+7-7| ... | @@ -65,19 +65,20 @@ test { | ... | @@ -65,19 +65,20 @@ test { |
| 65 | _ = @import("behavior/inttoptr.zig"); | 65 | _ = @import("behavior/inttoptr.zig"); |
| 66 | _ = @import("behavior/ir_block_deps.zig"); | 66 | _ = @import("behavior/ir_block_deps.zig"); |
| 67 | _ = @import("behavior/member_func.zig"); | 67 | _ = @import("behavior/member_func.zig"); |
| 68 | _ = @import("behavior/muladd.zig"); | ||
| 68 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); | 69 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); |
| 69 | _ = @import("behavior/null.zig"); | 70 | _ = @import("behavior/null.zig"); |
| 70 | _ = @import("behavior/optional.zig"); | 71 | _ = @import("behavior/optional.zig"); |
| 71 | _ = @import("behavior/prefetch.zig"); | ||
| 72 | _ = @import("behavior/pointers.zig"); | 72 | _ = @import("behavior/pointers.zig"); |
| 73 | _ = @import("behavior/pub_enum.zig"); | 73 | _ = @import("behavior/prefetch.zig"); |
| 74 | _ = @import("behavior/ptrcast.zig"); | 74 | _ = @import("behavior/ptrcast.zig"); |
| 75 | _ = @import("behavior/reflection.zig"); | 75 | _ = @import("behavior/pub_enum.zig"); |
| 76 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); | 76 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); |
| 77 | _ = @import("behavior/reflection.zig"); | ||
| 77 | _ = @import("behavior/slice.zig"); | 78 | _ = @import("behavior/slice.zig"); |
| 78 | _ = @import("behavior/slice_sentinel_comptime.zig"); | 79 | _ = @import("behavior/slice_sentinel_comptime.zig"); |
| 79 | _ = @import("behavior/struct.zig"); | ||
| 80 | _ = @import("behavior/src.zig"); | 80 | _ = @import("behavior/src.zig"); |
| 81 | _ = @import("behavior/struct.zig"); | ||
| 81 | _ = @import("behavior/this.zig"); | 82 | _ = @import("behavior/this.zig"); |
| 82 | _ = @import("behavior/truncate.zig"); | 83 | _ = @import("behavior/truncate.zig"); |
| 83 | _ = @import("behavior/try.zig"); | 84 | _ = @import("behavior/try.zig"); |
| ... | @@ -135,6 +136,7 @@ test { | ... | @@ -135,6 +136,7 @@ test { |
| 135 | _ = @import("behavior/bugs/5398.zig"); | 136 | _ = @import("behavior/bugs/5398.zig"); |
| 136 | _ = @import("behavior/bugs/5413.zig"); | 137 | _ = @import("behavior/bugs/5413.zig"); |
| 137 | _ = @import("behavior/bugs/5487.zig"); | 138 | _ = @import("behavior/bugs/5487.zig"); |
| 139 | _ = @import("behavior/bugs/7003.zig"); | ||
| 138 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); | 140 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); |
| 139 | _ = @import("behavior/switch_prong_err_enum.zig"); | 141 | _ = @import("behavior/switch_prong_err_enum.zig"); |
| 140 | _ = @import("behavior/switch_prong_implicit_cast.zig"); | 142 | _ = @import("behavior/switch_prong_implicit_cast.zig"); |
| ... | @@ -156,14 +158,12 @@ test { | ... | @@ -156,14 +158,12 @@ test { |
| 156 | _ = @import("behavior/bugs/3779.zig"); | 158 | _ = @import("behavior/bugs/3779.zig"); |
| 157 | _ = @import("behavior/bugs/6456.zig"); | 159 | _ = @import("behavior/bugs/6456.zig"); |
| 158 | _ = @import("behavior/bugs/6781.zig"); | 160 | _ = @import("behavior/bugs/6781.zig"); |
| 159 | _ = @import("behavior/bugs/7003.zig"); | ||
| 160 | _ = @import("behavior/bugs/7027.zig"); | 161 | _ = @import("behavior/bugs/7027.zig"); |
| 161 | _ = @import("behavior/bugs/7047.zig"); | 162 | _ = @import("behavior/bugs/7047.zig"); |
| 162 | _ = @import("behavior/bugs/10147.zig"); | 163 | _ = @import("behavior/bugs/10147.zig"); |
| 163 | _ = @import("behavior/const_slice_child.zig"); | 164 | _ = @import("behavior/const_slice_child.zig"); |
| 165 | _ = @import("behavior/export.zig"); | ||
| 164 | _ = @import("behavior/export_self_referential_type_info.zig"); | 166 | _ = @import("behavior/export_self_referential_type_info.zig"); |
| 165 | _ = @import("behavior/misc.zig"); | ||
| 166 | _ = @import("behavior/muladd.zig"); | ||
| 167 | _ = @import("behavior/select.zig"); | 167 | _ = @import("behavior/select.zig"); |
| 168 | _ = @import("behavior/shuffle.zig"); | 168 | _ = @import("behavior/shuffle.zig"); |
| 169 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); | 169 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); |
test/behavior/enum.zig-16| ... | @@ -972,22 +972,6 @@ test "enum literal casting to error union with payload enum" { | ... | @@ -972,22 +972,6 @@ test "enum literal casting to error union with payload enum" { |
| 972 | try expect((try bar) == Bar.B); | 972 | try expect((try bar) == Bar.B); |
| 973 | } | 973 | } |
| 974 | 974 | ||
| 975 | test "exporting enum type and value" { | ||
| 976 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | ||
| 977 | |||
| 978 | const S = struct { | ||
| 979 | const E = enum(c_int) { one, two }; | ||
| 980 | comptime { | ||
| 981 | @export(E, .{ .name = "E" }); | ||
| 982 | } | ||
| 983 | const e: E = .two; | ||
| 984 | comptime { | ||
| 985 | @export(e, .{ .name = "e" }); | ||
| 986 | } | ||
| 987 | }; | ||
| 988 | try expect(S.e == .two); | ||
| 989 | } | ||
| 990 | |||
| 991 | test "constant enum initialization with differing sizes" { | 975 | test "constant enum initialization with differing sizes" { |
| 992 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 976 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 993 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 977 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
test/behavior/export.zig created+50| ... | @@ -0,0 +1,50 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 4 | const expectEqualStrings = std.testing.expectEqualStrings; | ||
| 5 | const mem = std.mem; | ||
| 6 | const builtin = @import("builtin"); | ||
| 7 | |||
| 8 | // can't really run this test but we can make sure it has no compile error | ||
| 9 | // and generates code | ||
| 10 | const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000]; | ||
| 11 | export fn writeToVRam() void { | ||
| 12 | vram[0] = 'X'; | ||
| 13 | } | ||
| 14 | |||
| 15 | const PackedStruct = packed struct { | ||
| 16 | a: u8, | ||
| 17 | b: u8, | ||
| 18 | }; | ||
| 19 | const PackedUnion = packed union { | ||
| 20 | a: u8, | ||
| 21 | b: u32, | ||
| 22 | }; | ||
| 23 | |||
| 24 | test "packed struct, enum, union parameters in extern function" { | ||
| 25 | testPackedStuff(&(PackedStruct{ | ||
| 26 | .a = 1, | ||
| 27 | .b = 2, | ||
| 28 | }), &(PackedUnion{ .a = 1 })); | ||
| 29 | } | ||
| 30 | |||
| 31 | export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void { | ||
| 32 | if (false) { | ||
| 33 | a; | ||
| 34 | b; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | test "exporting enum type and value" { | ||
| 39 | const S = struct { | ||
| 40 | const E = enum(c_int) { one, two }; | ||
| 41 | comptime { | ||
| 42 | @export(E, .{ .name = "E" }); | ||
| 43 | } | ||
| 44 | const e: E = .two; | ||
| 45 | comptime { | ||
| 46 | @export(e, .{ .name = "e" }); | ||
| 47 | } | ||
| 48 | }; | ||
| 49 | try expect(S.e == .two); | ||
| 50 | } | ||
test/behavior/misc.zig deleted-36| ... | @@ -1,36 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 4 | const expectEqualStrings = std.testing.expectEqualStrings; | ||
| 5 | const mem = std.mem; | ||
| 6 | const builtin = @import("builtin"); | ||
| 7 | |||
| 8 | // can't really run this test but we can make sure it has no compile error | ||
| 9 | // and generates code | ||
| 10 | const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000]; | ||
| 11 | export fn writeToVRam() void { | ||
| 12 | vram[0] = 'X'; | ||
| 13 | } | ||
| 14 | |||
| 15 | const PackedStruct = packed struct { | ||
| 16 | a: u8, | ||
| 17 | b: u8, | ||
| 18 | }; | ||
| 19 | const PackedUnion = packed union { | ||
| 20 | a: u8, | ||
| 21 | b: u32, | ||
| 22 | }; | ||
| 23 | |||
| 24 | test "packed struct, enum, union parameters in extern function" { | ||
| 25 | testPackedStuff(&(PackedStruct{ | ||
| 26 | .a = 1, | ||
| 27 | .b = 2, | ||
| 28 | }), &(PackedUnion{ .a = 1 })); | ||
| 29 | } | ||
| 30 | |||
| 31 | export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void { | ||
| 32 | if (false) { | ||
| 33 | a; | ||
| 34 | b; | ||
| 35 | } | ||
| 36 | } | ||
test/behavior/muladd.zig+34-12| ... | @@ -2,6 +2,8 @@ const builtin = @import("builtin"); | ... | @@ -2,6 +2,8 @@ const builtin = @import("builtin"); |
| 2 | const expect = @import("std").testing.expect; | 2 | const expect = @import("std").testing.expect; |
| 3 | 3 | ||
| 4 | test "@mulAdd" { | 4 | test "@mulAdd" { |
| 5 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | ||
| 6 | |||
| 5 | comptime try testMulAdd(); | 7 | comptime try testMulAdd(); |
| 6 | try testMulAdd(); | 8 | try testMulAdd(); |
| 7 | } | 9 | } |
| ... | @@ -25,20 +27,40 @@ fn testMulAdd() !void { | ... | @@ -25,20 +27,40 @@ fn testMulAdd() !void { |
| 25 | var c: f64 = 6.25; | 27 | var c: f64 = 6.25; |
| 26 | try expect(@mulAdd(f64, a, b, c) == 20); | 28 | try expect(@mulAdd(f64, a, b, c) == 20); |
| 27 | } | 29 | } |
| 28 | // { | 30 | } |
| 29 | // var a: f16 = 5.5; | 31 | |
| 30 | // var b: f80 = 2.5; | 32 | test "@mulAdd f80" { |
| 31 | // var c: f80 = 6.25; | 33 | if (true) { |
| 32 | // try expect(@mulAdd(f80, a, b, c) == 20); | 34 | // https://github.com/ziglang/zig/issues/11030 |
| 33 | // } | 35 | return error.SkipZigTest; |
| 36 | } | ||
| 37 | |||
| 38 | comptime try testMulAdd80(); | ||
| 39 | try testMulAdd80(); | ||
| 40 | } | ||
| 41 | |||
| 42 | fn testMulAdd80() !void { | ||
| 43 | var a: f16 = 5.5; | ||
| 44 | var b: f80 = 2.5; | ||
| 45 | var c: f80 = 6.25; | ||
| 46 | try expect(@mulAdd(f80, a, b, c) == 20); | ||
| 47 | } | ||
| 48 | |||
| 49 | test "@mulAdd f128" { | ||
| 50 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | ||
| 51 | |||
| 34 | if (builtin.os.tag == .macos and builtin.cpu.arch == .aarch64) { | 52 | if (builtin.os.tag == .macos and builtin.cpu.arch == .aarch64) { |
| 35 | // https://github.com/ziglang/zig/issues/9900 | 53 | // https://github.com/ziglang/zig/issues/9900 |
| 36 | return error.SkipZigTest; | 54 | return error.SkipZigTest; |
| 37 | } | 55 | } |
| 38 | { | 56 | |
| 39 | var a: f16 = 5.5; | 57 | comptime try testMullAdd128(); |
| 40 | var b: f128 = 2.5; | 58 | try testMullAdd128(); |
| 41 | var c: f128 = 6.25; | 59 | } |
| 42 | try expect(@mulAdd(f128, a, b, c) == 20); | 60 | |
| 43 | } | 61 | fn testMullAdd128() !void { |
| 62 | var a: f16 = 5.5; | ||
| 63 | var b: f128 = 2.5; | ||
| 64 | var c: f128 = 6.25; | ||
| 65 | try expect(@mulAdd(f128, a, b, c) == 20); | ||
| 44 | } | 66 | } |
test/behavior/src.zig+3-1| ... | @@ -14,7 +14,9 @@ const builtin = @import("builtin"); | ... | @@ -14,7 +14,9 @@ const builtin = @import("builtin"); |
| 14 | const expect = std.testing.expect; | 14 | const expect = std.testing.expect; |
| 15 | 15 | ||
| 16 | test "@src" { | 16 | test "@src" { |
| 17 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; | 17 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 18 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 18 | 20 | ||
| 19 | try doTheTest(); | 21 | try doTheTest(); |
| 20 | } | 22 | } |
test/behavior/struct.zig+5-3| ... | @@ -930,7 +930,9 @@ test "anonymous struct literal syntax" { | ... | @@ -930,7 +930,9 @@ test "anonymous struct literal syntax" { |
| 930 | } | 930 | } |
| 931 | 931 | ||
| 932 | test "fully anonymous struct" { | 932 | test "fully anonymous struct" { |
| 933 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 933 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 934 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 935 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 934 | 936 | ||
| 935 | const S = struct { | 937 | const S = struct { |
| 936 | fn doTheTest() !void { | 938 | fn doTheTest() !void { |
| ... | @@ -974,7 +976,7 @@ test "fully anonymous list literal" { | ... | @@ -974,7 +976,7 @@ test "fully anonymous list literal" { |
| 974 | comptime try S.doTheTest(); | 976 | comptime try S.doTheTest(); |
| 975 | } | 977 | } |
| 976 | 978 | ||
| 977 | test "anonymous struct literal assigned to variable" { | 979 | test "tuple assigned to variable" { |
| 978 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 980 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
| 979 | 981 | ||
| 980 | var vec = .{ @as(i32, 22), @as(i32, 55), @as(i32, 99) }; | 982 | var vec = .{ @as(i32, 22), @as(i32, 55), @as(i32, 99) }; |
| ... | @@ -995,7 +997,7 @@ test "comptime struct field" { | ... | @@ -995,7 +997,7 @@ test "comptime struct field" { |
| 995 | comptime try expect(foo.b == 1234); | 997 | comptime try expect(foo.b == 1234); |
| 996 | } | 998 | } |
| 997 | 999 | ||
| 998 | test "anon struct literal field value initialized with fn call" { | 1000 | test "tuple element initialized with fn call" { |
| 999 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 1001 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
| 1000 | 1002 | ||
| 1001 | const S = struct { | 1003 | const S = struct { |
test/behavior/type_info.zig+6-2| ... | @@ -503,9 +503,13 @@ test "Struct.is_tuple for anon list literal" { | ... | @@ -503,9 +503,13 @@ test "Struct.is_tuple for anon list literal" { |
| 503 | } | 503 | } |
| 504 | 504 | ||
| 505 | test "Struct.is_tuple for anon struct literal" { | 505 | test "Struct.is_tuple for anon struct literal" { |
| 506 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 506 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 507 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 508 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 507 | 509 | ||
| 508 | try expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple); | 510 | const info = @typeInfo(@TypeOf(.{ .a = 0 })); |
| 511 | try expect(!info.Struct.is_tuple); | ||
| 512 | try expect(std.mem.eql(u8, info.Struct.fields[0].name, "a")); | ||
| 509 | } | 513 | } |
| 510 | 514 | ||
| 511 | test "StructField.is_comptime" { | 515 | test "StructField.is_comptime" { |