| author | |
| committer | |
| log | df7d6d263e4ad6adb302856235641ae9ceb142b6 |
| tree | 186182733c89cec8fa990a681ab8e6f915d15908 |
| parent | da7fcfd1586fa93c3d00815f60030e00ea583701 |
* Module: implement opaque type namespace lookup
* Add `Type.type` for convenience
* Sema: fix `validateVarType` for pointer-to-opaque
* x86_64 ABI: implement support for pointers
* LLVM backend: fix lowering of opaque types
* Type: implement equality checking for opaques8 files changed, 158 insertions(+), 46 deletions(-)
src/Module.zig+24-1| ... | @@ -708,7 +708,9 @@ pub const Decl = struct { | ... | @@ -708,7 +708,9 @@ pub const Decl = struct { |
| 708 | return ty.castTag(.empty_struct).?.data; | 708 | return ty.castTag(.empty_struct).?.data; |
| 709 | }, | 709 | }, |
| 710 | .@"opaque" => { | 710 | .@"opaque" => { |
| 711 | @panic("TODO opaque types"); | 711 | const opaque_obj = ty.cast(Type.Payload.Opaque).?.data; |
| 712 | assert(opaque_obj.owner_decl == decl); | ||
| 713 | return &opaque_obj.namespace; | ||
| 712 | }, | 714 | }, |
| 713 | .@"union", .union_tagged => { | 715 | .@"union", .union_tagged => { |
| 714 | const union_obj = ty.cast(Type.Payload.Union).?.data; | 716 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| ... | @@ -1080,6 +1082,27 @@ pub const Union = struct { | ... | @@ -1080,6 +1082,27 @@ pub const Union = struct { |
| 1080 | } | 1082 | } |
| 1081 | }; | 1083 | }; |
| 1082 | 1084 | ||
| 1085 | pub const Opaque = struct { | ||
| 1086 | /// The Decl that corresponds to the opaque itself. | ||
| 1087 | owner_decl: *Decl, | ||
| 1088 | /// Represents the declarations inside this opaque. | ||
| 1089 | namespace: Namespace, | ||
| 1090 | /// Offset from `owner_decl`, points to the opaque decl AST node. | ||
| 1091 | node_offset: i32, | ||
| 1092 | |||
| 1093 | pub fn srcLoc(self: Opaque) SrcLoc { | ||
| 1094 | return .{ | ||
| 1095 | .file_scope = self.owner_decl.getFileScope(), | ||
| 1096 | .parent_decl_node = self.owner_decl.src_node, | ||
| 1097 | .lazy = .{ .node_offset = self.node_offset }, | ||
| 1098 | }; | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | pub fn getFullyQualifiedName(s: *Opaque, gpa: *Allocator) ![:0]u8 { | ||
| 1102 | return s.owner_decl.getFullyQualifiedName(gpa); | ||
| 1103 | } | ||
| 1104 | }; | ||
| 1105 | |||
| 1083 | /// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator. | 1106 | /// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator. |
| 1084 | /// Extern functions do not have this data structure; they are represented by | 1107 | /// Extern functions do not have this data structure; they are represented by |
| 1085 | /// the `Decl` only, with a `Value` tag of `extern_fn`. | 1108 | /// the `Decl` only, with a `Value` tag of `extern_fn`. |
src/Sema.zig+68-13| ... | @@ -957,7 +957,7 @@ fn zirExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -957,7 +957,7 @@ fn zirExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 957 | .struct_decl => return sema.zirStructDecl( block, extended, inst), | 957 | .struct_decl => return sema.zirStructDecl( block, extended, inst), |
| 958 | .enum_decl => return sema.zirEnumDecl( block, extended), | 958 | .enum_decl => return sema.zirEnumDecl( block, extended), |
| 959 | .union_decl => return sema.zirUnionDecl( block, extended, inst), | 959 | .union_decl => return sema.zirUnionDecl( block, extended, inst), |
| 960 | .opaque_decl => return sema.zirOpaqueDecl( block, extended, inst), | 960 | .opaque_decl => return sema.zirOpaqueDecl( block, extended), |
| 961 | .ret_ptr => return sema.zirRetPtr( block, extended), | 961 | .ret_ptr => return sema.zirRetPtr( block, extended), |
| 962 | .ret_type => return sema.zirRetType( block, extended), | 962 | .ret_type => return sema.zirRetType( block, extended), |
| 963 | .this => return sema.zirThis( block, extended), | 963 | .this => return sema.zirThis( block, extended), |
| ... | @@ -1432,7 +1432,7 @@ fn zirStructDecl( | ... | @@ -1432,7 +1432,7 @@ fn zirStructDecl( |
| 1432 | const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty); | 1432 | const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty); |
| 1433 | const type_name = try sema.createTypeName(block, small.name_strategy); | 1433 | const type_name = try sema.createTypeName(block, small.name_strategy); |
| 1434 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ | 1434 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ |
| 1435 | .ty = Type.initTag(.type), | 1435 | .ty = Type.type, |
| 1436 | .val = struct_val, | 1436 | .val = struct_val, |
| 1437 | }, type_name); | 1437 | }, type_name); |
| 1438 | new_decl.owns_tv = true; | 1438 | new_decl.owns_tv = true; |
| ... | @@ -1541,7 +1541,7 @@ fn zirEnumDecl( | ... | @@ -1541,7 +1541,7 @@ fn zirEnumDecl( |
| 1541 | const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty); | 1541 | const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty); |
| 1542 | const type_name = try sema.createTypeName(block, small.name_strategy); | 1542 | const type_name = try sema.createTypeName(block, small.name_strategy); |
| 1543 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ | 1543 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ |
| 1544 | .ty = Type.initTag(.type), | 1544 | .ty = Type.type, |
| 1545 | .val = enum_val, | 1545 | .val = enum_val, |
| 1546 | }, type_name); | 1546 | }, type_name); |
| 1547 | new_decl.owns_tv = true; | 1547 | new_decl.owns_tv = true; |
| ... | @@ -1731,7 +1731,7 @@ fn zirUnionDecl( | ... | @@ -1731,7 +1731,7 @@ fn zirUnionDecl( |
| 1731 | const union_val = try Value.Tag.ty.create(&new_decl_arena.allocator, union_ty); | 1731 | const union_val = try Value.Tag.ty.create(&new_decl_arena.allocator, union_ty); |
| 1732 | const type_name = try sema.createTypeName(block, small.name_strategy); | 1732 | const type_name = try sema.createTypeName(block, small.name_strategy); |
| 1733 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ | 1733 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ |
| 1734 | .ty = Type.initTag(.type), | 1734 | .ty = Type.type, |
| 1735 | .val = union_val, | 1735 | .val = union_val, |
| 1736 | }, type_name); | 1736 | }, type_name); |
| 1737 | new_decl.owns_tv = true; | 1737 | new_decl.owns_tv = true; |
| ... | @@ -1764,14 +1764,63 @@ fn zirOpaqueDecl( | ... | @@ -1764,14 +1764,63 @@ fn zirOpaqueDecl( |
| 1764 | sema: *Sema, | 1764 | sema: *Sema, |
| 1765 | block: *Block, | 1765 | block: *Block, |
| 1766 | extended: Zir.Inst.Extended.InstData, | 1766 | extended: Zir.Inst.Extended.InstData, |
| 1767 | inst: Zir.Inst.Index, | ||
| 1768 | ) CompileError!Air.Inst.Ref { | 1767 | ) CompileError!Air.Inst.Ref { |
| 1769 | const tracy = trace(@src()); | 1768 | const tracy = trace(@src()); |
| 1770 | defer tracy.end(); | 1769 | defer tracy.end(); |
| 1771 | 1770 | ||
| 1772 | _ = extended; | 1771 | const mod = sema.mod; |
| 1773 | _ = inst; | 1772 | const gpa = sema.gpa; |
| 1774 | return sema.fail(block, sema.src, "TODO implement zirOpaqueDecl", .{}); | 1773 | const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small); |
| 1774 | var extra_index: usize = extended.operand; | ||
| 1775 | |||
| 1776 | const src: LazySrcLoc = if (small.has_src_node) blk: { | ||
| 1777 | const node_offset = @bitCast(i32, sema.code.extra[extra_index]); | ||
| 1778 | extra_index += 1; | ||
| 1779 | break :blk .{ .node_offset = node_offset }; | ||
| 1780 | } else sema.src; | ||
| 1781 | |||
| 1782 | const decls_len = if (small.has_decls_len) blk: { | ||
| 1783 | const decls_len = sema.code.extra[extra_index]; | ||
| 1784 | extra_index += 1; | ||
| 1785 | break :blk decls_len; | ||
| 1786 | } else 0; | ||
| 1787 | |||
| 1788 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 1789 | errdefer new_decl_arena.deinit(); | ||
| 1790 | |||
| 1791 | const opaque_obj = try new_decl_arena.allocator.create(Module.Opaque); | ||
| 1792 | const opaque_ty_payload = try new_decl_arena.allocator.create(Type.Payload.Opaque); | ||
| 1793 | opaque_ty_payload.* = .{ | ||
| 1794 | .base = .{ .tag = .@"opaque" }, | ||
| 1795 | .data = opaque_obj, | ||
| 1796 | }; | ||
| 1797 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); | ||
| 1798 | const opaque_val = try Value.Tag.ty.create(&new_decl_arena.allocator, opaque_ty); | ||
| 1799 | const type_name = try sema.createTypeName(block, small.name_strategy); | ||
| 1800 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ | ||
| 1801 | .ty = Type.type, | ||
| 1802 | .val = opaque_val, | ||
| 1803 | }, type_name); | ||
| 1804 | new_decl.owns_tv = true; | ||
| 1805 | errdefer mod.abortAnonDecl(new_decl); | ||
| 1806 | |||
| 1807 | opaque_obj.* = .{ | ||
| 1808 | .owner_decl = new_decl, | ||
| 1809 | .node_offset = src.node_offset, | ||
| 1810 | .namespace = .{ | ||
| 1811 | .parent = block.namespace, | ||
| 1812 | .ty = opaque_ty, | ||
| 1813 | .file_scope = block.getFileScope(), | ||
| 1814 | }, | ||
| 1815 | }; | ||
| 1816 | std.log.scoped(.module).debug("create opaque {*} owned by {*} ({s})", .{ | ||
| 1817 | &opaque_obj.namespace, new_decl, new_decl.name, | ||
| 1818 | }); | ||
| 1819 | |||
| 1820 | extra_index = try mod.scanNamespace(&opaque_obj.namespace, extra_index, decls_len, new_decl); | ||
| 1821 | |||
| 1822 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 1823 | return sema.analyzeDeclVal(block, src, new_decl); | ||
| 1775 | } | 1824 | } |
| 1776 | 1825 | ||
| 1777 | fn zirErrorSetDecl( | 1826 | fn zirErrorSetDecl( |
| ... | @@ -1797,7 +1846,7 @@ fn zirErrorSetDecl( | ... | @@ -1797,7 +1846,7 @@ fn zirErrorSetDecl( |
| 1797 | const error_set_val = try Value.Tag.ty.create(&new_decl_arena.allocator, error_set_ty); | 1846 | const error_set_val = try Value.Tag.ty.create(&new_decl_arena.allocator, error_set_ty); |
| 1798 | const type_name = try sema.createTypeName(block, name_strategy); | 1847 | const type_name = try sema.createTypeName(block, name_strategy); |
| 1799 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ | 1848 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ |
| 1800 | .ty = Type.initTag(.type), | 1849 | .ty = Type.type, |
| 1801 | .val = error_set_val, | 1850 | .val = error_set_val, |
| 1802 | }, type_name); | 1851 | }, type_name); |
| 1803 | new_decl.owns_tv = true; | 1852 | new_decl.owns_tv = true; |
| ... | @@ -4278,7 +4327,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -4278,7 +4327,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 4278 | .names_len = @intCast(u32, new_names.len), | 4327 | .names_len = @intCast(u32, new_names.len), |
| 4279 | }; | 4328 | }; |
| 4280 | const error_set_ty = try Type.Tag.error_set.create(sema.arena, new_error_set); | 4329 | const error_set_ty = try Type.Tag.error_set.create(sema.arena, new_error_set); |
| 4281 | return sema.addConstant(Type.initTag(.type), try Value.Tag.ty.create(sema.arena, error_set_ty)); | 4330 | return sema.addConstant(Type.type, try Value.Tag.ty.create(sema.arena, error_set_ty)); |
| 4282 | } | 4331 | } |
| 4283 | 4332 | ||
| 4284 | fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 4333 | fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -10158,6 +10207,11 @@ fn validateVarType( | ... | @@ -10158,6 +10207,11 @@ fn validateVarType( |
| 10158 | .Null, | 10207 | .Null, |
| 10159 | => break false, | 10208 | => break false, |
| 10160 | 10209 | ||
| 10210 | .Pointer => { | ||
| 10211 | const elem_ty = ty.childType(); | ||
| 10212 | if (elem_ty.zigTypeTag() == .Opaque) return; | ||
| 10213 | ty = elem_ty; | ||
| 10214 | }, | ||
| 10161 | .Opaque => break is_extern, | 10215 | .Opaque => break is_extern, |
| 10162 | 10216 | ||
| 10163 | .Optional => { | 10217 | .Optional => { |
| ... | @@ -10165,7 +10219,8 @@ fn validateVarType( | ... | @@ -10165,7 +10219,8 @@ fn validateVarType( |
| 10165 | const child_ty = ty.optionalChild(&buf); | 10219 | const child_ty = ty.optionalChild(&buf); |
| 10166 | return validateVarType(sema, block, src, child_ty, is_extern); | 10220 | return validateVarType(sema, block, src, child_ty, is_extern); |
| 10167 | }, | 10221 | }, |
| 10168 | .Pointer, .Array, .Vector => ty = ty.elemType(), | 10222 | .Array, .Vector => ty = ty.elemType(), |
| 10223 | |||
| 10169 | .ErrorUnion => ty = ty.errorUnionPayload(), | 10224 | .ErrorUnion => ty = ty.errorUnionPayload(), |
| 10170 | 10225 | ||
| 10171 | .Fn => @panic("TODO fn validateVarType"), | 10226 | .Fn => @panic("TODO fn validateVarType"), |
| ... | @@ -12978,7 +13033,7 @@ fn generateUnionTagTypeNumbered( | ... | @@ -12978,7 +13033,7 @@ fn generateUnionTagTypeNumbered( |
| 12978 | const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty); | 13033 | const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty); |
| 12979 | // TODO better type name | 13034 | // TODO better type name |
| 12980 | const new_decl = try mod.createAnonymousDecl(block, .{ | 13035 | const new_decl = try mod.createAnonymousDecl(block, .{ |
| 12981 | .ty = Type.initTag(.type), | 13036 | .ty = Type.type, |
| 12982 | .val = enum_val, | 13037 | .val = enum_val, |
| 12983 | }); | 13038 | }); |
| 12984 | new_decl.owns_tv = true; | 13039 | new_decl.owns_tv = true; |
| ... | @@ -13014,7 +13069,7 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: u32) !Type | ... | @@ -13014,7 +13069,7 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: u32) !Type |
| 13014 | const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty); | 13069 | const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty); |
| 13015 | // TODO better type name | 13070 | // TODO better type name |
| 13016 | const new_decl = try mod.createAnonymousDecl(block, .{ | 13071 | const new_decl = try mod.createAnonymousDecl(block, .{ |
| 13017 | .ty = Type.initTag(.type), | 13072 | .ty = Type.type, |
| 13018 | .val = enum_val, | 13073 | .val = enum_val, |
| 13019 | }); | 13074 | }); |
| 13020 | new_decl.owns_tv = true; | 13075 | new_decl.owns_tv = true; |
src/arch/x86_64/abi.zig+11| ... | @@ -34,6 +34,17 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { | ... | @@ -34,6 +34,17 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 34 | }; | 34 | }; |
| 35 | var result = [1]Class{.none} ** 8; | 35 | var result = [1]Class{.none} ** 8; |
| 36 | switch (ty.zigTypeTag()) { | 36 | switch (ty.zigTypeTag()) { |
| 37 | .Pointer => switch (ty.ptrSize()) { | ||
| 38 | .Slice => { | ||
| 39 | result[0] = .integer; | ||
| 40 | result[1] = .integer; | ||
| 41 | return result; | ||
| 42 | }, | ||
| 43 | else => { | ||
| 44 | result[0] = .integer; | ||
| 45 | return result; | ||
| 46 | }, | ||
| 47 | }, | ||
| 37 | .Int, .Enum, .ErrorSet => { | 48 | .Int, .Enum, .ErrorSet => { |
| 38 | const bits = ty.intInfo(target).bits; | 49 | const bits = ty.intInfo(target).bits; |
| 39 | if (bits <= 64) { | 50 | if (bits <= 64) { |
src/codegen/llvm.zig+18-3| ... | @@ -758,11 +758,27 @@ pub const DeclGen = struct { | ... | @@ -758,11 +758,27 @@ pub const DeclGen = struct { |
| 758 | }; | 758 | }; |
| 759 | return dg.context.structType(&fields, fields.len, .False); | 759 | return dg.context.structType(&fields, fields.len, .False); |
| 760 | } else { | 760 | } else { |
| 761 | const elem_type = try dg.llvmType(t.elemType()); | ||
| 762 | const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace()); | 761 | const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace()); |
| 763 | return elem_type.pointerType(llvm_addrspace); | 762 | const llvm_elem_ty = try dg.llvmType(t.childType()); |
| 763 | return llvm_elem_ty.pointerType(llvm_addrspace); | ||
| 764 | } | 764 | } |
| 765 | }, | 765 | }, |
| 766 | .Opaque => { | ||
| 767 | const gop = try dg.object.type_map.getOrPut(gpa, t); | ||
| 768 | if (gop.found_existing) return gop.value_ptr.*; | ||
| 769 | |||
| 770 | // The Type memory is ephemeral; since we want to store a longer-lived | ||
| 771 | // reference, we need to copy it here. | ||
| 772 | gop.key_ptr.* = try t.copy(&dg.object.type_map_arena.allocator); | ||
| 773 | |||
| 774 | const opaque_obj = t.castTag(.@"opaque").?.data; | ||
| 775 | const name = try opaque_obj.getFullyQualifiedName(gpa); | ||
| 776 | defer gpa.free(name); | ||
| 777 | |||
| 778 | const llvm_struct_ty = dg.context.structCreateNamed(name); | ||
| 779 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | ||
| 780 | return llvm_struct_ty; | ||
| 781 | }, | ||
| 766 | .Array => { | 782 | .Array => { |
| 767 | const elem_type = try dg.llvmType(t.elemType()); | 783 | const elem_type = try dg.llvmType(t.elemType()); |
| 768 | const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null); | 784 | const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null); |
| ... | @@ -896,7 +912,6 @@ pub const DeclGen = struct { | ... | @@ -896,7 +912,6 @@ pub const DeclGen = struct { |
| 896 | 912 | ||
| 897 | .BoundFn => @panic("TODO remove BoundFn from the language"), | 913 | .BoundFn => @panic("TODO remove BoundFn from the language"), |
| 898 | 914 | ||
| 899 | .Opaque, | ||
| 900 | .Frame, | 915 | .Frame, |
| 901 | .AnyFrame, | 916 | .AnyFrame, |
| 902 | .Vector, | 917 | .Vector, |
src/type.zig+9-4| ... | @@ -571,6 +571,11 @@ pub const Type = extern union { | ... | @@ -571,6 +571,11 @@ pub const Type = extern union { |
| 571 | } | 571 | } |
| 572 | return a.tag() == b.tag(); | 572 | return a.tag() == b.tag(); |
| 573 | }, | 573 | }, |
| 574 | .Opaque => { | ||
| 575 | const opaque_obj_a = a.castTag(.@"opaque").?.data; | ||
| 576 | const opaque_obj_b = b.castTag(.@"opaque").?.data; | ||
| 577 | return opaque_obj_a == opaque_obj_b; | ||
| 578 | }, | ||
| 574 | .Union => { | 579 | .Union => { |
| 575 | if (a.cast(Payload.Union)) |a_payload| { | 580 | if (a.cast(Payload.Union)) |a_payload| { |
| 576 | if (b.cast(Payload.Union)) |b_payload| { | 581 | if (b.cast(Payload.Union)) |b_payload| { |
| ... | @@ -611,7 +616,6 @@ pub const Type = extern union { | ... | @@ -611,7 +616,6 @@ pub const Type = extern union { |
| 611 | return false; | 616 | return false; |
| 612 | }, | 617 | }, |
| 613 | .Float => return a.tag() == b.tag(), | 618 | .Float => return a.tag() == b.tag(), |
| 614 | .Opaque, | ||
| 615 | .BoundFn, | 619 | .BoundFn, |
| 616 | .Frame, | 620 | .Frame, |
| 617 | => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }), | 621 | => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }), |
| ... | @@ -1408,6 +1412,7 @@ pub const Type = extern union { | ... | @@ -1408,6 +1412,7 @@ pub const Type = extern union { |
| 1408 | .extern_options, | 1412 | .extern_options, |
| 1409 | .@"anyframe", | 1413 | .@"anyframe", |
| 1410 | .anyframe_T, | 1414 | .anyframe_T, |
| 1415 | .@"opaque", | ||
| 1411 | => true, | 1416 | => true, |
| 1412 | 1417 | ||
| 1413 | .function => !self.castTag(.function).?.data.is_generic, | 1418 | .function => !self.castTag(.function).?.data.is_generic, |
| ... | @@ -1499,7 +1504,6 @@ pub const Type = extern union { | ... | @@ -1499,7 +1504,6 @@ pub const Type = extern union { |
| 1499 | .enum_literal, | 1504 | .enum_literal, |
| 1500 | .empty_struct, | 1505 | .empty_struct, |
| 1501 | .empty_struct_literal, | 1506 | .empty_struct_literal, |
| 1502 | .@"opaque", | ||
| 1503 | .type_info, | 1507 | .type_info, |
| 1504 | .bound_fn, | 1508 | .bound_fn, |
| 1505 | => false, | 1509 | => false, |
| ... | @@ -3097,7 +3101,7 @@ pub const Type = extern union { | ... | @@ -3097,7 +3101,7 @@ pub const Type = extern union { |
| 3097 | .enum_full => &self.castTag(.enum_full).?.data.namespace, | 3101 | .enum_full => &self.castTag(.enum_full).?.data.namespace, |
| 3098 | .enum_nonexhaustive => &self.castTag(.enum_nonexhaustive).?.data.namespace, | 3102 | .enum_nonexhaustive => &self.castTag(.enum_nonexhaustive).?.data.namespace, |
| 3099 | .empty_struct => self.castTag(.empty_struct).?.data, | 3103 | .empty_struct => self.castTag(.empty_struct).?.data, |
| 3100 | .@"opaque" => &self.castTag(.@"opaque").?.data, | 3104 | .@"opaque" => &self.castTag(.@"opaque").?.data.namespace, |
| 3101 | .@"union" => &self.castTag(.@"union").?.data.namespace, | 3105 | .@"union" => &self.castTag(.@"union").?.data.namespace, |
| 3102 | .union_tagged => &self.castTag(.union_tagged).?.data.namespace, | 3106 | .union_tagged => &self.castTag(.union_tagged).?.data.namespace, |
| 3103 | 3107 | ||
| ... | @@ -3870,7 +3874,7 @@ pub const Type = extern union { | ... | @@ -3870,7 +3874,7 @@ pub const Type = extern union { |
| 3870 | 3874 | ||
| 3871 | pub const Opaque = struct { | 3875 | pub const Opaque = struct { |
| 3872 | base: Payload = .{ .tag = .@"opaque" }, | 3876 | base: Payload = .{ .tag = .@"opaque" }, |
| 3873 | data: Module.Namespace, | 3877 | data: *Module.Opaque, |
| 3874 | }; | 3878 | }; |
| 3875 | 3879 | ||
| 3876 | pub const Struct = struct { | 3880 | pub const Struct = struct { |
| ... | @@ -3904,6 +3908,7 @@ pub const Type = extern union { | ... | @@ -3904,6 +3908,7 @@ pub const Type = extern union { |
| 3904 | pub const @"usize" = initTag(.usize); | 3908 | pub const @"usize" = initTag(.usize); |
| 3905 | pub const @"comptime_int" = initTag(.comptime_int); | 3909 | pub const @"comptime_int" = initTag(.comptime_int); |
| 3906 | pub const @"void" = initTag(.void); | 3910 | pub const @"void" = initTag(.void); |
| 3911 | pub const @"type" = initTag(.type); | ||
| 3907 | 3912 | ||
| 3908 | pub fn ptr(arena: *Allocator, d: Payload.Pointer.Data) !Type { | 3913 | pub fn ptr(arena: *Allocator, d: Payload.Pointer.Data) !Type { |
| 3909 | assert(d.host_size == 0 or d.bit_offset < d.host_size * 8); | 3914 | assert(d.host_size == 0 or d.bit_offset < d.host_size * 8); |
test/behavior/basic.zig+12| ... | @@ -188,3 +188,15 @@ fn testMemcpyMemset() !void { | ... | @@ -188,3 +188,15 @@ fn testMemcpyMemset() !void { |
| 188 | try expect(bar[11] == 'A'); | 188 | try expect(bar[11] == 'A'); |
| 189 | try expect(bar[19] == 'A'); | 189 | try expect(bar[19] == 'A'); |
| 190 | } | 190 | } |
| 191 | |||
| 192 | const OpaqueA = opaque {}; | ||
| 193 | const OpaqueB = opaque {}; | ||
| 194 | |||
| 195 | test "variable is allowed to be a pointer to an opaque type" { | ||
| 196 | var x: i32 = 1234; | ||
| 197 | _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); | ||
| 198 | } | ||
| 199 | fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { | ||
| 200 | var a = ptr; | ||
| 201 | return a; | ||
| 202 | } |
test/behavior/misc.zig-25| ... | @@ -5,22 +5,6 @@ const expectEqualStrings = std.testing.expectEqualStrings; | ... | @@ -5,22 +5,6 @@ const expectEqualStrings = std.testing.expectEqualStrings; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | 7 | ||
| 8 | test "slicing" { | ||
| 9 | var array: [20]i32 = undefined; | ||
| 10 | |||
| 11 | array[5] = 1234; | ||
| 12 | |||
| 13 | var slice = array[5..10]; | ||
| 14 | |||
| 15 | if (slice.len != 5) unreachable; | ||
| 16 | |||
| 17 | const ptr = &slice[0]; | ||
| 18 | if (ptr.* != 1234) unreachable; | ||
| 19 | |||
| 20 | var slice_rest = array[10..]; | ||
| 21 | if (slice_rest.len != 10) unreachable; | ||
| 22 | } | ||
| 23 | |||
| 24 | test "constant equal function pointers" { | 8 | test "constant equal function pointers" { |
| 25 | const alias = emptyFn; | 9 | const alias = emptyFn; |
| 26 | try expect(comptime x: { | 10 | try expect(comptime x: { |
| ... | @@ -230,15 +214,6 @@ test "opaque types" { | ... | @@ -230,15 +214,6 @@ test "opaque types" { |
| 230 | try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); | 214 | try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); |
| 231 | } | 215 | } |
| 232 | 216 | ||
| 233 | test "variable is allowed to be a pointer to an opaque type" { | ||
| 234 | var x: i32 = 1234; | ||
| 235 | _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); | ||
| 236 | } | ||
| 237 | fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { | ||
| 238 | var a = ptr; | ||
| 239 | return a; | ||
| 240 | } | ||
| 241 | |||
| 242 | test "comptime if inside runtime while which unconditionally breaks" { | 217 | test "comptime if inside runtime while which unconditionally breaks" { |
| 243 | testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); | 218 | testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); |
| 244 | comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); | 219 | comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); |
test/behavior/slice_stage1.zig+16| ... | @@ -4,6 +4,22 @@ const expectEqualSlices = std.testing.expectEqualSlices; | ... | @@ -4,6 +4,22 @@ const expectEqualSlices = std.testing.expectEqualSlices; |
| 4 | const expectEqual = std.testing.expectEqual; | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | 6 | ||
| 7 | test "slicing" { | ||
| 8 | var array: [20]i32 = undefined; | ||
| 9 | |||
| 10 | array[5] = 1234; | ||
| 11 | |||
| 12 | var slice = array[5..10]; | ||
| 13 | |||
| 14 | if (slice.len != 5) unreachable; | ||
| 15 | |||
| 16 | const ptr = &slice[0]; | ||
| 17 | if (ptr.* != 1234) unreachable; | ||
| 18 | |||
| 19 | var slice_rest = array[10..]; | ||
| 20 | if (slice_rest.len != 10) unreachable; | ||
| 21 | } | ||
| 22 | |||
| 7 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | 23 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; |
| 8 | const y = x[0x100..]; | 24 | const y = x[0x100..]; |
| 9 | test "compile time slice of pointer to hard coded address" { | 25 | test "compile time slice of pointer to hard coded address" { |