| 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 | 7704 | const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs); |
| 7705 | 7705 | |
| 7706 | 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 | 7708 | const namespace = container_type.getNamespace() orelse return sema.fail( |
| 7709 | 7709 | block, |
| 7710 | 7710 | lhs_src, |
| ... | ... | @@ -10615,15 +10615,19 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 10615 | 10615 | const layout = struct_ty.containerLayout(); |
| 10616 | 10616 | |
| 10617 | 10617 | const struct_field_vals = fv: { |
| 10618 | if (struct_ty.castTag(.tuple)) |payload| { | |
| 10619 | const field_types = payload.data.types; | |
| 10618 | if (struct_ty.isTupleOrAnonStruct()) { | |
| 10619 | const tuple = struct_ty.tupleFields(); | |
| 10620 | const field_types = tuple.types; | |
| 10620 | 10621 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len); |
| 10621 | 10622 | for (struct_field_vals) |*struct_field_val, i| { |
| 10622 | 10623 | const field_ty = field_types[i]; |
| 10623 | 10624 | const name_val = v: { |
| 10624 | 10625 | var anon_decl = try block.startAnonDecl(src); |
| 10625 | 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 | 10631 | const new_decl = try anon_decl.finish( |
| 10628 | 10632 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), |
| 10629 | 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 | 10636 | }; |
| 10633 | 10637 | |
| 10634 | 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 | 10640 | const is_comptime = field_val.tag() != .unreachable_value; |
| 10637 | 10641 | const opt_default_val = if (is_comptime) field_val else null; |
| 10638 | 10642 | const default_val_ptr = try sema.optRefValue(block, src, field_ty, opt_default_val); |
| ... | ... | @@ -11631,12 +11635,86 @@ fn finishStructInit( |
| 11631 | 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 | 11644 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 11636 | 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; | |
| 11639 | return sema.fail(block, src, "TODO: Sema.zirStructInitAnon", .{}); | |
| 11658 | names[i] = sema.code.nullTerminatedString(item.data.field_name); | |
| 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 | 11720 | fn zirArrayInit( |
| ... | ... | @@ -11764,8 +11842,10 @@ fn zirArrayInitAnon( |
| 11764 | 11842 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 11765 | 11843 | .pointee_type = types[i], |
| 11766 | 11844 | }); |
| 11767 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); | |
| 11768 | _ = try block.addBinOp(.store, field_ptr, sema.resolveInst(operand)); | |
| 11845 | if (values[i].tag() == .unreachable_value) { | |
| 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 | 11851 | return alloc; |
| ... | ... | @@ -12126,7 +12206,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 12126 | 12206 | .size = ptr_size, |
| 12127 | 12207 | .mutable = !is_const_val.toBool(), |
| 12128 | 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 | 12210 | .@"addrspace" = address_space_val.toEnum(std.builtin.AddressSpace), |
| 12131 | 12211 | .pointee_type = try child_ty.copy(sema.arena), |
| 12132 | 12212 | .@"allowzero" = is_allowzero_val.toBool(), |
| ... | ... | @@ -14842,29 +14922,43 @@ fn structFieldVal( |
| 14842 | 14922 | assert(unresolved_struct_ty.zigTypeTag() == .Struct); |
| 14843 | 14923 | |
| 14844 | 14924 | const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); |
| 14845 | if (struct_ty.isTuple()) { | |
| 14846 | return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); | |
| 14847 | } | |
| 14925 | switch (struct_ty.tag()) { | |
| 14926 | .tuple, .empty_struct_literal => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty), | |
| 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 | |
| 14852 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | |
| 14853 | const field_index = @intCast(u32, field_index_usize); | |
| 14854 | const field = struct_obj.fields.values()[field_index]; | |
| 14942 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | |
| 14943 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | |
| 14944 | const field_index = @intCast(u32, field_index_usize); | |
| 14945 | const field = struct_obj.fields.values()[field_index]; | |
| 14855 | 14946 | |
| 14856 | if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| { | |
| 14857 | if (struct_val.isUndef()) return sema.addConstUndef(field.ty); | |
| 14858 | if ((try sema.typeHasOnePossibleValue(block, src, field.ty))) |opv| { | |
| 14859 | return sema.addConstant(field.ty, opv); | |
| 14860 | } | |
| 14947 | if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| { | |
| 14948 | if (struct_val.isUndef()) return sema.addConstUndef(field.ty); | |
| 14949 | if ((try sema.typeHasOnePossibleValue(block, src, field.ty))) |opv| { | |
| 14950 | return sema.addConstant(field.ty, opv); | |
| 14951 | } | |
| 14861 | 14952 | |
| 14862 | const field_values = struct_val.castTag(.@"struct").?.data; | |
| 14863 | return sema.addConstant(field.ty, field_values[field_index]); | |
| 14864 | } | |
| 14953 | const field_values = struct_val.castTag(.@"struct").?.data; | |
| 14954 | return sema.addConstant(field.ty, field_values[field_index]); | |
| 14955 | } | |
| 14865 | 14956 | |
| 14866 | try sema.requireRuntimeBlock(block, src); | |
| 14867 | return block.addStructFieldVal(struct_byval, field_index, field.ty); | |
| 14957 | try sema.requireRuntimeBlock(block, src); | |
| 14958 | return block.addStructFieldVal(struct_byval, field_index, field.ty); | |
| 14959 | }, | |
| 14960 | else => unreachable, | |
| 14961 | } | |
| 14868 | 14962 | } |
| 14869 | 14963 | |
| 14870 | 14964 | fn tupleFieldVal( |
| ... | ... | @@ -14901,7 +14995,7 @@ fn tupleFieldValByIndex( |
| 14901 | 14995 | field_index: u32, |
| 14902 | 14996 | tuple_ty: Type, |
| 14903 | 14997 | ) CompileError!Air.Inst.Ref { |
| 14904 | const tuple = tuple_ty.castTag(.tuple).?.data; | |
| 14998 | const tuple = tuple_ty.tupleFields(); | |
| 14905 | 14999 | const field_ty = tuple.types[field_index]; |
| 14906 | 15000 | |
| 14907 | 15001 | if (tuple.values[field_index].tag() != .unreachable_value) { |
| ... | ... | @@ -18954,8 +19048,8 @@ pub fn typeHasOnePossibleValue( |
| 18954 | 19048 | return Value.initTag(.empty_struct_value); |
| 18955 | 19049 | }, |
| 18956 | 19050 | |
| 18957 | .tuple => { | |
| 18958 | const tuple = ty.castTag(.tuple).?.data; | |
| 19051 | .tuple, .anon_struct => { | |
| 19052 | const tuple = ty.tupleFields(); | |
| 18959 | 19053 | for (tuple.values) |val| { |
| 18960 | 19054 | if (val.tag() == .unreachable_value) { |
| 18961 | 19055 | return null; // non-comptime field |
| ... | ... | @@ -19583,8 +19677,8 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C |
| 19583 | 19677 | return sema.typeRequiresComptime(block, src, ty.optionalChild(&buf)); |
| 19584 | 19678 | }, |
| 19585 | 19679 | |
| 19586 | .tuple => { | |
| 19587 | const tuple = ty.castTag(.tuple).?.data; | |
| 19680 | .tuple, .anon_struct => { | |
| 19681 | const tuple = ty.tupleFields(); | |
| 19588 | 19682 | for (tuple.types) |field_ty, i| { |
| 19589 | 19683 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; |
| 19590 | 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 | 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 | 2856 | pub const StructInitAnon = struct { |
| 2855 | 2857 | fields_len: u32, |
| 2856 | 2858 |
src/codegen/llvm.zig+3-3| ... | ... | @@ -958,7 +958,7 @@ pub const DeclGen = struct { |
| 958 | 958 | // reference, we need to copy it here. |
| 959 | 959 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); |
| 960 | 960 | |
| 961 | if (t.isTuple()) { | |
| 961 | if (t.isTupleOrAnonStruct()) { | |
| 962 | 962 | const tuple = t.tupleFields(); |
| 963 | 963 | const llvm_struct_ty = dg.context.structCreateNamed(""); |
| 964 | 964 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| ... | ... | @@ -2104,7 +2104,7 @@ pub const DeclGen = struct { |
| 2104 | 2104 | var zig_big_align: u32 = 0; |
| 2105 | 2105 | var llvm_big_align: u32 = 0; |
| 2106 | 2106 | |
| 2107 | if (ty.isTuple()) { | |
| 2107 | if (ty.isTupleOrAnonStruct()) { | |
| 2108 | 2108 | const tuple = ty.tupleFields(); |
| 2109 | 2109 | var llvm_field_index: c_uint = 0; |
| 2110 | 2110 | for (tuple.types) |field_ty, i| { |
| ... | ... | @@ -5704,7 +5704,7 @@ fn isByRef(ty: Type) bool { |
| 5704 | 5704 | .Struct => { |
| 5705 | 5705 | // Packed structs are represented to LLVM as integers. |
| 5706 | 5706 | if (ty.containerLayout() == .Packed) return false; |
| 5707 | if (ty.isTuple()) { | |
| 5707 | if (ty.isTupleOrAnonStruct()) { | |
| 5708 | 5708 | const tuple = ty.tupleFields(); |
| 5709 | 5709 | var count: usize = 0; |
| 5710 | 5710 | for (tuple.values) |field_val, i| { |
src/type.zig+151-24| ... | ... | @@ -131,6 +131,7 @@ pub const Type = extern union { |
| 131 | 131 | .export_options, |
| 132 | 132 | .extern_options, |
| 133 | 133 | .tuple, |
| 134 | .anon_struct, | |
| 134 | 135 | => return .Struct, |
| 135 | 136 | |
| 136 | 137 | .enum_full, |
| ... | ... | @@ -792,6 +793,42 @@ pub const Type = extern union { |
| 792 | 793 | |
| 793 | 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 | 833 | // we can't compare these based on tags because it wouldn't detect if, |
| 797 | 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 | 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 | 1117 | // we can't hash these based on tags because they wouldn't match the expanded version. |
| 1067 | 1118 | .call_options, |
| ... | ... | @@ -1279,6 +1330,26 @@ pub const Type = extern union { |
| 1279 | 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 | 1353 | .function => { |
| 1283 | 1354 | const payload = self.castTag(.function).?.data; |
| 1284 | 1355 | const param_types = try allocator.alloc(Type, payload.param_types.len); |
| ... | ... | @@ -1533,6 +1604,26 @@ pub const Type = extern union { |
| 1533 | 1604 | try writer.writeAll("}"); |
| 1534 | 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 | 1627 | .single_const_pointer => { |
| 1537 | 1628 | const pointee_type = ty.castTag(.single_const_pointer).?.data; |
| 1538 | 1629 | try writer.writeAll("*const "); |
| ... | ... | @@ -2020,8 +2111,8 @@ pub const Type = extern union { |
| 2020 | 2111 | return payload.error_set.hasRuntimeBits() or payload.payload.hasRuntimeBits(); |
| 2021 | 2112 | }, |
| 2022 | 2113 | |
| 2023 | .tuple => { | |
| 2024 | const tuple = ty.castTag(.tuple).?.data; | |
| 2114 | .tuple, .anon_struct => { | |
| 2115 | const tuple = ty.tupleFields(); | |
| 2025 | 2116 | for (tuple.types) |field_ty, i| { |
| 2026 | 2117 | const val = tuple.values[i]; |
| 2027 | 2118 | if (val.tag() != .unreachable_value) continue; // comptime field |
| ... | ... | @@ -2292,8 +2383,8 @@ pub const Type = extern union { |
| 2292 | 2383 | return big_align; |
| 2293 | 2384 | }, |
| 2294 | 2385 | |
| 2295 | .tuple => { | |
| 2296 | const tuple = self.castTag(.tuple).?.data; | |
| 2386 | .tuple, .anon_struct => { | |
| 2387 | const tuple = self.tupleFields(); | |
| 2297 | 2388 | var big_align: u32 = 0; |
| 2298 | 2389 | for (tuple.types) |field_ty, i| { |
| 2299 | 2390 | const val = tuple.values[i]; |
| ... | ... | @@ -2375,7 +2466,7 @@ pub const Type = extern union { |
| 2375 | 2466 | .void, |
| 2376 | 2467 | => 0, |
| 2377 | 2468 | |
| 2378 | .@"struct", .tuple => switch (self.containerLayout()) { | |
| 2469 | .@"struct", .tuple, .anon_struct => switch (self.containerLayout()) { | |
| 2379 | 2470 | .Packed => { |
| 2380 | 2471 | const struct_obj = self.castTag(.@"struct").?.data; |
| 2381 | 2472 | var buf: Type.Payload.Bits = undefined; |
| ... | ... | @@ -2575,6 +2666,13 @@ pub const Type = extern union { |
| 2575 | 2666 | .bound_fn => unreachable, |
| 2576 | 2667 | |
| 2577 | 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 | 2677 | .@"struct" => { |
| 2580 | 2678 | const field_count = ty.structFieldCount(); |
| ... | ... | @@ -2595,8 +2693,13 @@ pub const Type = extern union { |
| 2595 | 2693 | } |
| 2596 | 2694 | }, |
| 2597 | 2695 | |
| 2598 | .tuple => { | |
| 2599 | @panic("TODO bitSize tuples"); | |
| 2696 | .tuple, .anon_struct => { | |
| 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 | 2705 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { |
| ... | ... | @@ -2608,10 +2711,6 @@ pub const Type = extern union { |
| 2608 | 2711 | @panic("TODO bitSize unions"); |
| 2609 | 2712 | }, |
| 2610 | 2713 | |
| 2611 | .u8, .i8 => 8, | |
| 2612 | ||
| 2613 | .bool, .u1 => 1, | |
| 2614 | ||
| 2615 | 2714 | .vector => { |
| 2616 | 2715 | const payload = ty.castTag(.vector).?.data; |
| 2617 | 2716 | const elem_bit_size = payload.elem_type.bitSize(target); |
| ... | ... | @@ -2634,11 +2733,6 @@ pub const Type = extern union { |
| 2634 | 2733 | ); |
| 2635 | 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 | 2737 | .isize, |
| 2644 | 2738 | .usize, |
| ... | ... | @@ -3295,7 +3389,7 @@ pub const Type = extern union { |
| 3295 | 3389 | |
| 3296 | 3390 | pub fn containerLayout(ty: Type) std.builtin.TypeInfo.ContainerLayout { |
| 3297 | 3391 | return switch (ty.tag()) { |
| 3298 | .tuple, .empty_struct_literal => .Auto, | |
| 3392 | .tuple, .empty_struct_literal, .anon_struct => .Auto, | |
| 3299 | 3393 | .@"struct" => ty.castTag(.@"struct").?.data.layout, |
| 3300 | 3394 | .@"union" => ty.castTag(.@"union").?.data.layout, |
| 3301 | 3395 | .union_tagged => ty.castTag(.union_tagged).?.data.layout, |
| ... | ... | @@ -3369,6 +3463,7 @@ pub const Type = extern union { |
| 3369 | 3463 | .array_u8 => ty.castTag(.array_u8).?.data, |
| 3370 | 3464 | .array_u8_sentinel_0 => ty.castTag(.array_u8_sentinel_0).?.data, |
| 3371 | 3465 | .tuple => ty.castTag(.tuple).?.data.types.len, |
| 3466 | .anon_struct => ty.castTag(.anon_struct).?.data.types.len, | |
| 3372 | 3467 | .@"struct" => ty.castTag(.@"struct").?.data.fields.count(), |
| 3373 | 3468 | |
| 3374 | 3469 | else => unreachable, |
| ... | ... | @@ -3383,6 +3478,7 @@ pub const Type = extern union { |
| 3383 | 3478 | return switch (ty.tag()) { |
| 3384 | 3479 | .vector => @intCast(u32, ty.castTag(.vector).?.data.len), |
| 3385 | 3480 | .tuple => @intCast(u32, ty.castTag(.tuple).?.data.types.len), |
| 3481 | .anon_struct => @intCast(u32, ty.castTag(.anon_struct).?.data.types.len), | |
| 3386 | 3482 | else => unreachable, |
| 3387 | 3483 | }; |
| 3388 | 3484 | } |
| ... | ... | @@ -3849,8 +3945,8 @@ pub const Type = extern union { |
| 3849 | 3945 | return Value.initTag(.empty_struct_value); |
| 3850 | 3946 | }, |
| 3851 | 3947 | |
| 3852 | .tuple => { | |
| 3853 | const tuple = ty.castTag(.tuple).?.data; | |
| 3948 | .tuple, .anon_struct => { | |
| 3949 | const tuple = ty.tupleFields(); | |
| 3854 | 3950 | for (tuple.values) |val| { |
| 3855 | 3951 | if (val.tag() == .unreachable_value) { |
| 3856 | 3952 | return null; // non-comptime field |
| ... | ... | @@ -4048,8 +4144,8 @@ pub const Type = extern union { |
| 4048 | 4144 | return ty.optionalChild(&buf).comptimeOnly(); |
| 4049 | 4145 | }, |
| 4050 | 4146 | |
| 4051 | .tuple => { | |
| 4052 | const tuple = ty.castTag(.tuple).?.data; | |
| 4147 | .tuple, .anon_struct => { | |
| 4148 | const tuple = ty.tupleFields(); | |
| 4053 | 4149 | for (tuple.types) |field_ty, i| { |
| 4054 | 4150 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; |
| 4055 | 4151 | if (!have_comptime_val and field_ty.comptimeOnly()) return true; |
| ... | ... | @@ -4350,6 +4446,7 @@ pub const Type = extern union { |
| 4350 | 4446 | }, |
| 4351 | 4447 | .empty_struct, .empty_struct_literal => return 0, |
| 4352 | 4448 | .tuple => return ty.castTag(.tuple).?.data.types.len, |
| 4449 | .anon_struct => return ty.castTag(.anon_struct).?.data.types.len, | |
| 4353 | 4450 | else => unreachable, |
| 4354 | 4451 | } |
| 4355 | 4452 | } |
| ... | ... | @@ -4366,6 +4463,7 @@ pub const Type = extern union { |
| 4366 | 4463 | return union_obj.fields.values()[index].ty; |
| 4367 | 4464 | }, |
| 4368 | 4465 | .tuple => return ty.castTag(.tuple).?.data.types[index], |
| 4466 | .anon_struct => return ty.castTag(.anon_struct).?.data.types[index], | |
| 4369 | 4467 | else => unreachable, |
| 4370 | 4468 | } |
| 4371 | 4469 | } |
| ... | ... | @@ -4424,8 +4522,8 @@ pub const Type = extern union { |
| 4424 | 4522 | return std.mem.alignForwardGeneric(u64, it.offset, it.big_align); |
| 4425 | 4523 | }, |
| 4426 | 4524 | |
| 4427 | .tuple => { | |
| 4428 | const tuple = ty.castTag(.tuple).?.data; | |
| 4525 | .tuple, .anon_struct => { | |
| 4526 | const tuple = ty.tupleFields(); | |
| 4429 | 4527 | |
| 4430 | 4528 | var offset: u64 = 0; |
| 4431 | 4529 | var big_align: u32 = 0; |
| ... | ... | @@ -4700,6 +4798,8 @@ pub const Type = extern union { |
| 4700 | 4798 | vector, |
| 4701 | 4799 | /// Possible Value tags for this: @"struct" |
| 4702 | 4800 | tuple, |
| 4801 | /// Possible Value tags for this: @"struct" | |
| 4802 | anon_struct, | |
| 4703 | 4803 | pointer, |
| 4704 | 4804 | single_const_pointer, |
| 4705 | 4805 | single_mut_pointer, |
| ... | ... | @@ -4846,6 +4946,7 @@ pub const Type = extern union { |
| 4846 | 4946 | .enum_numbered => Payload.EnumNumbered, |
| 4847 | 4947 | .empty_struct => Payload.ContainerScope, |
| 4848 | 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 | 4970 | }; |
| 4870 | 4971 | |
| 4871 | 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 | 4986 | pub fn tupleFields(ty: Type) Payload.Tuple.Data { |
| 4876 | 4987 | return switch (ty.tag()) { |
| 4877 | 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 | 4993 | .empty_struct_literal => .{ .types = &.{}, .values = &.{} }, |
| 4879 | 4994 | else => unreachable, |
| 4880 | 4995 | }; |
| ... | ... | @@ -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 | 5172 | pub const Union = struct { |
| 5046 | 5173 | base: Payload, |
| 5047 | 5174 | data: *Module.Union, |
src/value.zig+2-2| ... | ... | @@ -1895,7 +1895,7 @@ pub const Value = extern union { |
| 1895 | 1895 | const a_field_vals = a.castTag(.@"struct").?.data; |
| 1896 | 1896 | const b_field_vals = b.castTag(.@"struct").?.data; |
| 1897 | 1897 | assert(a_field_vals.len == b_field_vals.len); |
| 1898 | if (ty.isTuple()) { | |
| 1898 | if (ty.isTupleOrAnonStruct()) { | |
| 1899 | 1899 | const types = ty.tupleFields().types; |
| 1900 | 1900 | assert(types.len == a_field_vals.len); |
| 1901 | 1901 | for (types) |field_ty, i| { |
| ... | ... | @@ -2031,7 +2031,7 @@ pub const Value = extern union { |
| 2031 | 2031 | } |
| 2032 | 2032 | }, |
| 2033 | 2033 | .Struct => { |
| 2034 | if (ty.isTuple()) { | |
| 2034 | if (ty.isTupleOrAnonStruct()) { | |
| 2035 | 2035 | const fields = ty.tupleFields(); |
| 2036 | 2036 | for (fields.values) |field_val, i| { |
| 2037 | 2037 | field_val.hash(fields.types[i], hasher); |
test/behavior.zig+7-7| ... | ... | @@ -65,19 +65,20 @@ test { |
| 65 | 65 | _ = @import("behavior/inttoptr.zig"); |
| 66 | 66 | _ = @import("behavior/ir_block_deps.zig"); |
| 67 | 67 | _ = @import("behavior/member_func.zig"); |
| 68 | _ = @import("behavior/muladd.zig"); | |
| 68 | 69 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); |
| 69 | 70 | _ = @import("behavior/null.zig"); |
| 70 | 71 | _ = @import("behavior/optional.zig"); |
| 71 | _ = @import("behavior/prefetch.zig"); | |
| 72 | 72 | _ = @import("behavior/pointers.zig"); |
| 73 | _ = @import("behavior/pub_enum.zig"); | |
| 73 | _ = @import("behavior/prefetch.zig"); | |
| 74 | 74 | _ = @import("behavior/ptrcast.zig"); |
| 75 | _ = @import("behavior/reflection.zig"); | |
| 75 | _ = @import("behavior/pub_enum.zig"); | |
| 76 | 76 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); |
| 77 | _ = @import("behavior/reflection.zig"); | |
| 77 | 78 | _ = @import("behavior/slice.zig"); |
| 78 | 79 | _ = @import("behavior/slice_sentinel_comptime.zig"); |
| 79 | _ = @import("behavior/struct.zig"); | |
| 80 | 80 | _ = @import("behavior/src.zig"); |
| 81 | _ = @import("behavior/struct.zig"); | |
| 81 | 82 | _ = @import("behavior/this.zig"); |
| 82 | 83 | _ = @import("behavior/truncate.zig"); |
| 83 | 84 | _ = @import("behavior/try.zig"); |
| ... | ... | @@ -135,6 +136,7 @@ test { |
| 135 | 136 | _ = @import("behavior/bugs/5398.zig"); |
| 136 | 137 | _ = @import("behavior/bugs/5413.zig"); |
| 137 | 138 | _ = @import("behavior/bugs/5487.zig"); |
| 139 | _ = @import("behavior/bugs/7003.zig"); | |
| 138 | 140 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); |
| 139 | 141 | _ = @import("behavior/switch_prong_err_enum.zig"); |
| 140 | 142 | _ = @import("behavior/switch_prong_implicit_cast.zig"); |
| ... | ... | @@ -156,14 +158,12 @@ test { |
| 156 | 158 | _ = @import("behavior/bugs/3779.zig"); |
| 157 | 159 | _ = @import("behavior/bugs/6456.zig"); |
| 158 | 160 | _ = @import("behavior/bugs/6781.zig"); |
| 159 | _ = @import("behavior/bugs/7003.zig"); | |
| 160 | 161 | _ = @import("behavior/bugs/7027.zig"); |
| 161 | 162 | _ = @import("behavior/bugs/7047.zig"); |
| 162 | 163 | _ = @import("behavior/bugs/10147.zig"); |
| 163 | 164 | _ = @import("behavior/const_slice_child.zig"); |
| 165 | _ = @import("behavior/export.zig"); | |
| 164 | 166 | _ = @import("behavior/export_self_referential_type_info.zig"); |
| 165 | _ = @import("behavior/misc.zig"); | |
| 166 | _ = @import("behavior/muladd.zig"); | |
| 167 | 167 | _ = @import("behavior/select.zig"); |
| 168 | 168 | _ = @import("behavior/shuffle.zig"); |
| 169 | 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 | 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 | 975 | test "constant enum initialization with differing sizes" { |
| 992 | 976 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 993 | 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 | 2 | const expect = @import("std").testing.expect; |
| 3 | 3 | |
| 4 | 4 | test "@mulAdd" { |
| 5 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 6 | ||
| 5 | 7 | comptime try testMulAdd(); |
| 6 | 8 | try testMulAdd(); |
| 7 | 9 | } |
| ... | ... | @@ -25,20 +27,40 @@ fn testMulAdd() !void { |
| 25 | 27 | var c: f64 = 6.25; |
| 26 | 28 | try expect(@mulAdd(f64, a, b, c) == 20); |
| 27 | 29 | } |
| 28 | // { | |
| 29 | // var a: f16 = 5.5; | |
| 30 | // var b: f80 = 2.5; | |
| 31 | // var c: f80 = 6.25; | |
| 32 | // try expect(@mulAdd(f80, a, b, c) == 20); | |
| 33 | // } | |
| 30 | } | |
| 31 | ||
| 32 | test "@mulAdd f80" { | |
| 33 | if (true) { | |
| 34 | // https://github.com/ziglang/zig/issues/11030 | |
| 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 | 52 | if (builtin.os.tag == .macos and builtin.cpu.arch == .aarch64) { |
| 35 | 53 | // https://github.com/ziglang/zig/issues/9900 |
| 36 | 54 | return error.SkipZigTest; |
| 37 | 55 | } |
| 38 | { | |
| 39 | var a: f16 = 5.5; | |
| 40 | var b: f128 = 2.5; | |
| 41 | var c: f128 = 6.25; | |
| 42 | try expect(@mulAdd(f128, a, b, c) == 20); | |
| 43 | } | |
| 56 | ||
| 57 | comptime try testMullAdd128(); | |
| 58 | try testMullAdd128(); | |
| 59 | } | |
| 60 | ||
| 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 | 14 | const expect = std.testing.expect; |
| 15 | 15 | |
| 16 | 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 | 21 | try doTheTest(); |
| 20 | 22 | } |
test/behavior/struct.zig+5-3| ... | ... | @@ -930,7 +930,9 @@ test "anonymous struct literal syntax" { |
| 930 | 930 | } |
| 931 | 931 | |
| 932 | 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 | 937 | const S = struct { |
| 936 | 938 | fn doTheTest() !void { |
| ... | ... | @@ -974,7 +976,7 @@ test "fully anonymous list literal" { |
| 974 | 976 | comptime try S.doTheTest(); |
| 975 | 977 | } |
| 976 | 978 | |
| 977 | test "anonymous struct literal assigned to variable" { | |
| 979 | test "tuple assigned to variable" { | |
| 978 | 980 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
| 979 | 981 | |
| 980 | 982 | var vec = .{ @as(i32, 22), @as(i32, 55), @as(i32, 99) }; |
| ... | ... | @@ -995,7 +997,7 @@ test "comptime struct field" { |
| 995 | 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 | 1001 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
| 1000 | 1002 | |
| 1001 | 1003 | const S = struct { |
test/behavior/type_info.zig+6-2| ... | ... | @@ -503,9 +503,13 @@ test "Struct.is_tuple for anon list literal" { |
| 503 | 503 | } |
| 504 | 504 | |
| 505 | 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 | 515 | test "StructField.is_comptime" { |