From 1f2f9f05c254374044d8c30cce6f299d7a18da72 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 25 Sep 2021 22:18:43 -0700 Subject: [PATCH] stage2: implement zirCoerceResultPtr and remove Module.simplePtrType and Module.ptrType in favor of `Type.ptr`. --- src/Module.zig | 76 -------- src/Sema.zig | 306 ++++++++++++++++---------------- src/type.zig | 61 +++++-- test/behavior/struct.zig | 38 ++++ test/behavior/struct_stage1.zig | 29 +-- 5 files changed, 239 insertions(+), 271 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 278f8621d8..dbece09255 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4460,82 +4460,6 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) Co return error.AnalysisFail; } -pub fn simplePtrType( - arena: *Allocator, - elem_ty: Type, - mutable: bool, - size: std.builtin.TypeInfo.Pointer.Size, - @"addrspace": std.builtin.AddressSpace, -) Allocator.Error!Type { - return ptrType( - arena, - elem_ty, - null, - 0, - @"addrspace", - 0, - 0, - mutable, - false, - false, - size, - ); -} - -pub fn ptrType( - arena: *Allocator, - elem_ty: Type, - sentinel: ?Value, - @"align": u32, - @"addrspace": std.builtin.AddressSpace, - bit_offset: u16, - host_size: u16, - mutable: bool, - @"allowzero": bool, - @"volatile": bool, - size: std.builtin.TypeInfo.Pointer.Size, -) Allocator.Error!Type { - assert(host_size == 0 or bit_offset < host_size * 8); - - if (sentinel != null or @"align" != 0 or @"addrspace" != .generic or - bit_offset != 0 or host_size != 0 or @"allowzero" or @"volatile") - { - return Type.Tag.pointer.create(arena, .{ - .pointee_type = elem_ty, - .sentinel = sentinel, - .@"align" = @"align", - .@"addrspace" = @"addrspace", - .bit_offset = bit_offset, - .host_size = host_size, - .@"allowzero" = @"allowzero", - .mutable = mutable, - .@"volatile" = @"volatile", - .size = size, - }); - } - - if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) { - return Type.initTag(.const_slice_u8); - } - - // TODO stage1 type inference bug - const T = Type.Tag; - - const type_payload = try arena.create(Type.Payload.ElemType); - type_payload.* = .{ - .base = .{ - .tag = switch (size) { - .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, - .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, - .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, - .Slice => if (mutable) T.mut_slice else T.const_slice, - }, - }, - .data = elem_ty, - }; - return Type.initPayload(&type_payload.base); -} - pub fn optionalType(arena: *Allocator, child_type: Type) Allocator.Error!Type { switch (child_type.tag()) { .single_const_pointer => return Type.Tag.optional_single_const_pointer.create( diff --git a/src/Sema.zig b/src/Sema.zig index 1001b388a9..533252d682 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -979,10 +979,38 @@ fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) C } fn zirCoerceResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - _ = inst; const tracy = trace(@src()); defer tracy.end(); - return sema.mod.fail(&block.base, sema.src, "TODO implement zirCoerceResultPtr", .{}); + + const src: LazySrcLoc = sema.src; + const bin_inst = sema.code.instructions.items(.data)[inst].bin; + const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs); + const ptr = sema.resolveInst(bin_inst.rhs); + + // Create a runtime bitcast instruction with exactly the type the pointer wants. + const ptr_ty = try Type.ptr(sema.arena, .{ + .pointee_type = pointee_ty, + .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + }); + try sema.requireRuntimeBlock(block, src); + const bitcasted_ptr = try block.addTyOp(.bitcast, ptr_ty, ptr); + + if (Air.refToIndex(ptr)) |ptr_inst| { + if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) { + const air_datas = sema.air_instructions.items(.data); + const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; + if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| { + // Add the stored instruction to the set we will use to resolve peer types + // for the inferred allocation. + // This instruction will not make it to codegen; it is only to participate + // in the `stored_inst_list` of the `inferred_alloc`. + const operand = try block.addTyOp(.bitcast, pointee_ty, .void_value); + try inferred_alloc.data.stored_inst_list.append(sema.arena, operand); + } + } + } + + return bitcasted_ptr; } pub fn analyzeStructDecl( @@ -1427,13 +1455,10 @@ fn zirRetPtr( return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty); } - const ptr_type = try Module.simplePtrType( - sema.arena, - sema.fn_ret_ty, - true, - .One, - target_util.defaultAddressSpace(sema.mod.getTarget(), .local), - ); + const ptr_type = try Type.ptr(sema.arena, .{ + .pointee_type = sema.fn_ret_ty, + .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + }); return block.addTy(.alloc, ptr_type); } @@ -1581,13 +1606,10 @@ fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; const var_decl_src = inst_data.src(); const var_type = try sema.resolveType(block, ty_src, inst_data.operand); - const ptr_type = try Module.simplePtrType( - sema.arena, - var_type, - true, - .One, - target_util.defaultAddressSpace(sema.mod.getTarget(), .local), - ); + const ptr_type = try Type.ptr(sema.arena, .{ + .pointee_type = var_type, + .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + }); try sema.requireRuntimeBlock(block, var_decl_src); return block.addTy(.alloc, ptr_type); } @@ -1604,13 +1626,10 @@ fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr return sema.analyzeComptimeAlloc(block, var_type); } try sema.validateVarType(block, ty_src, var_type); - const ptr_type = try Module.simplePtrType( - sema.arena, - var_type, - true, - .One, - target_util.defaultAddressSpace(sema.mod.getTarget(), .local), - ); + const ptr_type = try Type.ptr(sema.arena, .{ + .pointee_type = var_type, + .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + }); try sema.requireRuntimeBlock(block, var_decl_src); return block.addTy(.alloc, ptr_type); } @@ -1670,13 +1689,10 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde try sema.mod.declareDeclDependency(sema.owner_decl, decl); const final_elem_ty = try decl.ty.copy(sema.arena); - const final_ptr_ty = try Module.simplePtrType( - sema.arena, - final_elem_ty, - true, - .One, - target_util.defaultAddressSpace(sema.mod.getTarget(), .local), - ); + const final_ptr_ty = try Type.ptr(sema.arena, .{ + .pointee_type = final_elem_ty, + .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + }); const final_ptr_ty_inst = try sema.addType(final_ptr_ty); sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst; @@ -1698,13 +1714,10 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde try sema.validateVarType(block, ty_src, final_elem_ty); } // Change it to a normal alloc. - const final_ptr_ty = try Module.simplePtrType( - sema.arena, - final_elem_ty, - true, - .One, - target_util.defaultAddressSpace(sema.mod.getTarget(), .local), - ); + const final_ptr_ty = try Type.ptr(sema.arena, .{ + .pointee_type = final_elem_ty, + .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + }); sema.air_instructions.set(ptr_inst, .{ .tag = .alloc, .data = .{ .ty = final_ptr_ty }, @@ -1858,14 +1871,11 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co } const ptr = sema.resolveInst(bin_inst.lhs); const value = sema.resolveInst(bin_inst.rhs); - const ptr_ty = try Module.simplePtrType( - sema.arena, - sema.typeOf(value), - true, - .One, + const ptr_ty = try Type.ptr(sema.arena, .{ + .pointee_type = sema.typeOf(value), // TODO figure out which address space is appropriate here - target_util.defaultAddressSpace(sema.mod.getTarget(), .local), - ); + .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + }); // TODO detect when this store should be done at compile-time. For example, // if expressions should force it when the condition is compile-time known. const src: LazySrcLoc = .unneeded; @@ -1912,14 +1922,10 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) // for the inferred allocation. try inferred_alloc.data.stored_inst_list.append(sema.arena, operand); // Create a runtime bitcast instruction with exactly the type the pointer wants. - const ptr_ty = try Module.simplePtrType( - sema.arena, - operand_ty, - true, - .One, - // TODO figure out which address space is appropriate here - target_util.defaultAddressSpace(sema.mod.getTarget(), .local), - ); + const ptr_ty = try Type.ptr(sema.arena, .{ + .pointee_type = operand_ty, + .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + }); const bitcasted_ptr = try block.addTyOp(.bitcast, ptr_ty, ptr); return sema.storePtr(block, src, bitcasted_ptr, operand); } @@ -3845,13 +3851,11 @@ fn zirOptionalPayloadPtr( } const child_type = try opt_type.optionalChildAlloc(sema.arena); - const child_pointer = try Module.simplePtrType( - sema.arena, - child_type, - !optional_ptr_ty.isConstPtr(), - .One, - optional_ptr_ty.ptrAddressSpace(), - ); + const child_pointer = try Type.ptr(sema.arena, .{ + .pointee_type = child_type, + .mutable = !optional_ptr_ty.isConstPtr(), + .@"addrspace" = optional_ptr_ty.ptrAddressSpace(), + }); if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| { if (try pointer_val.pointerDeref(sema.arena)) |val| { @@ -3966,13 +3970,11 @@ fn zirErrUnionPayloadPtr( return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand_ty.elemType()}); const payload_ty = operand_ty.elemType().errorUnionPayload(); - const operand_pointer_ty = try Module.simplePtrType( - sema.arena, - payload_ty, - !operand_ty.isConstPtr(), - .One, - operand_ty.ptrAddressSpace(), - ); + const operand_pointer_ty = try Type.ptr(sema.arena, .{ + .pointee_type = payload_ty, + .mutable = !operand_ty.isConstPtr(), + .@"addrspace" = operand_ty.ptrAddressSpace(), + }); if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { if (try pointer_val.pointerDeref(sema.arena)) |val| { @@ -7306,19 +7308,14 @@ fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp const inst_data = sema.code.instructions.items(.data)[inst].ptr_type_simple; const elem_type = try sema.resolveType(block, .unneeded, inst_data.elem_type); - const ty = try Module.ptrType( - sema.arena, - elem_type, - null, - 0, - .generic, - 0, - 0, - inst_data.is_mutable, - inst_data.is_allowzero, - inst_data.is_volatile, - inst_data.size, - ); + const ty = try Type.ptr(sema.arena, .{ + .pointee_type = elem_type, + .@"addrspace" = .generic, + .mutable = inst_data.is_mutable, + .@"allowzero" = inst_data.is_allowzero, + .@"volatile" = inst_data.is_volatile, + .size = inst_data.size, + }); return sema.addType(ty); } @@ -7367,19 +7364,18 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr const elem_type = try sema.resolveType(block, .unneeded, extra.data.elem_type); - const ty = try Module.ptrType( - sema.arena, - elem_type, - sentinel, - abi_align, - address_space, - bit_start, - bit_end, - inst_data.flags.is_mutable, - inst_data.flags.is_allowzero, - inst_data.flags.is_volatile, - inst_data.size, - ); + const ty = try Type.ptr(sema.arena, .{ + .pointee_type = elem_type, + .sentinel = sentinel, + .@"align" = abi_align, + .@"addrspace" = address_space, + .bit_offset = bit_start, + .host_size = bit_end, + .mutable = inst_data.flags.is_mutable, + .@"allowzero" = inst_data.flags.is_allowzero, + .@"volatile" = inst_data.flags.is_volatile, + .size = inst_data.size, + }); return sema.addType(ty); } @@ -8456,19 +8452,15 @@ fn zirMemcpy(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro }); } const src_ptr_info = uncasted_src_ptr_ty.ptrInfo().data; - const wanted_src_ptr_ty = try Module.ptrType( - sema.arena, - dest_ptr_ty.elemType2(), - null, - src_ptr_info.@"align", - src_ptr_info.@"addrspace", - 0, - 0, - false, - src_ptr_info.@"allowzero", - src_ptr_info.@"volatile", - .Many, - ); + const wanted_src_ptr_ty = try Type.ptr(sema.arena, .{ + .pointee_type = dest_ptr_ty.elemType2(), + .@"align" = src_ptr_info.@"align", + .@"addrspace" = src_ptr_info.@"addrspace", + .mutable = false, + .@"allowzero" = src_ptr_info.@"allowzero", + .@"volatile" = src_ptr_info.@"volatile", + .size = .Many, + }); const src_ptr = try sema.coerce(block, wanted_src_ptr_ty, uncasted_src_ptr, src_src); const len = try sema.coerce(block, Type.initTag(.usize), sema.resolveInst(extra.byte_count), len_src); @@ -8922,13 +8914,10 @@ fn panicWithMsg( const panic_fn = try sema.getBuiltin(block, src, "panic"); const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); - const ptr_stack_trace_ty = try Module.simplePtrType( - arena, - stack_trace_ty, - true, - .One, - target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant), // TODO might need a place that is more dynamic - ); + const ptr_stack_trace_ty = try Type.ptr(arena, .{ + .pointee_type = stack_trace_ty, + .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant), // TODO might need a place that is more dynamic + }); const null_stack_trace = try sema.addConstant( try Module.optionalType(arena, ptr_stack_trace_ty), Value.initTag(.null_value), @@ -9407,13 +9396,11 @@ fn structFieldPtr( const field_index = struct_obj.fields.getIndex(field_name) orelse return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name); const field = struct_obj.fields.values()[field_index]; - const ptr_field_ty = try Module.simplePtrType( - arena, - field.ty, - struct_ptr_ty.ptrIsMutable(), - .One, - struct_ptr_ty.ptrAddressSpace(), - ); + const ptr_field_ty = try Type.ptr(arena, .{ + .pointee_type = field.ty, + .mutable = struct_ptr_ty.ptrIsMutable(), + .@"addrspace" = struct_ptr_ty.ptrAddressSpace(), + }); if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { return sema.addConstant( @@ -9512,13 +9499,11 @@ fn unionFieldPtr( return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name); const field = union_obj.fields.values()[field_index]; - const ptr_field_ty = try Module.simplePtrType( - arena, - field.ty, - union_ptr_ty.ptrIsMutable(), - .One, - union_ptr_ty.ptrAddressSpace(), - ); + const ptr_field_ty = try Type.ptr(arena, .{ + .pointee_type = field.ty, + .mutable = union_ptr_ty.ptrIsMutable(), + .@"addrspace" = union_ptr_ty.ptrAddressSpace(), + }); if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| { // TODO detect inactive union field and emit compile error @@ -9694,13 +9679,11 @@ fn elemPtrArray( ) CompileError!Air.Inst.Ref { const array_ptr_ty = sema.typeOf(array_ptr); const pointee_type = array_ptr_ty.elemType().elemType(); - const result_ty = try Module.simplePtrType( - sema.arena, - pointee_type, - array_ptr_ty.ptrIsMutable(), - .One, - array_ptr_ty.ptrAddressSpace(), - ); + const result_ty = try Type.ptr(sema.arena, .{ + .pointee_type = pointee_type, + .mutable = array_ptr_ty.ptrIsMutable(), + .@"addrspace" = array_ptr_ty.ptrAddressSpace(), + }); if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| { if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| { @@ -10243,11 +10226,19 @@ fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref { const decl_tv = try decl.typedValue(); if (decl_tv.val.castTag(.variable)) |payload| { const variable = payload.data; - const ty = try Module.simplePtrType(sema.arena, decl_tv.ty, variable.is_mutable, .One, decl.@"addrspace"); + const ty = try Type.ptr(sema.arena, .{ + .pointee_type = decl_tv.ty, + .mutable = variable.is_mutable, + .@"addrspace" = decl.@"addrspace", + }); return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl)); } return sema.addConstant( - try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One, decl.@"addrspace"), + try Type.ptr(sema.arena, .{ + .pointee_type = decl_tv.ty, + .mutable = false, + .@"addrspace" = decl.@"addrspace", + }), try Value.Tag.decl_ref.create(sema.arena, decl), ); } @@ -10271,8 +10262,15 @@ fn analyzeRef( try sema.requireRuntimeBlock(block, src); const address_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local); - const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One, address_space); - const mut_ptr_type = try Module.simplePtrType(sema.arena, operand_ty, true, .One, address_space); + const ptr_type = try Type.ptr(sema.arena, .{ + .pointee_type = operand_ty, + .mutable = false, + .@"addrspace" = address_space, + }); + const mut_ptr_type = try Type.ptr(sema.arena, .{ + .pointee_type = operand_ty, + .@"addrspace" = address_space, + }); const alloc = try block.addTy(.alloc, mut_ptr_type); try sema.storePtr(block, src, alloc, operand); @@ -10428,19 +10426,16 @@ fn analyzeSlice( } } } - const return_type = try Module.ptrType( - sema.arena, - return_elem_type, - if (end_opt == .none) slice_sentinel else null, - 0, // TODO alignment - if (ptr_child.zigTypeTag() == .Pointer) ptr_child.ptrAddressSpace() else .generic, - 0, - 0, - !ptr_child.isConstPtr(), - ptr_child.isAllowzeroPtr(), - ptr_child.isVolatilePtr(), - return_ptr_size, - ); + const return_type = try Type.ptr(sema.arena, .{ + .pointee_type = return_elem_type, + .sentinel = if (end_opt == .none) slice_sentinel else null, + .@"align" = 0, // TODO alignment + .@"addrspace" = if (ptr_child.zigTypeTag() == .Pointer) ptr_child.ptrAddressSpace() else .generic, + .mutable = !ptr_child.isConstPtr(), + .@"allowzero" = ptr_child.isAllowzeroPtr(), + .@"volatile" = ptr_child.isVolatilePtr(), + .size = return_ptr_size, + }); _ = return_type; return sema.mod.fail(&block.base, src, "TODO implement analysis of slice", .{}); @@ -11626,13 +11621,10 @@ fn analyzeComptimeAlloc( block: *Scope.Block, var_type: Type, ) CompileError!Air.Inst.Ref { - const ptr_type = try Module.simplePtrType( - sema.arena, - var_type, - true, - .One, - target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant), - ); + const ptr_type = try Type.ptr(sema.arena, .{ + .pointee_type = var_type, + .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant), + }); var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); diff --git a/src/type.zig b/src/type.zig index bd008e809a..48c65c1008 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3652,12 +3652,12 @@ pub const Type = extern union { } pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!file_struct.Type { - const ptr = try ally.create(t.Type()); - ptr.* = .{ + const p = try ally.create(t.Type()); + p.* = .{ .base = .{ .tag = t }, .data = data, }; - return file_struct.Type{ .ptr_otherwise = &ptr.base }; + return file_struct.Type{ .ptr_otherwise = &p.base }; } pub fn Data(comptime t: Tag) type { @@ -3747,19 +3747,23 @@ pub const Type = extern union { pub const base_tag = Tag.pointer; base: Payload = Payload{ .tag = base_tag }, - data: struct { + data: Data, + + pub const Data = struct { pointee_type: Type, - sentinel: ?Value, + sentinel: ?Value = null, /// If zero use pointee_type.AbiAlign() - @"align": u32, + @"align": u32 = 0, + /// See src/target.zig defaultAddressSpace function for how to obtain + /// an appropriate value for this field. @"addrspace": std.builtin.AddressSpace, - bit_offset: u16, - host_size: u16, - @"allowzero": bool, - mutable: bool, - @"volatile": bool, - size: std.builtin.TypeInfo.Pointer.Size, - }, + bit_offset: u16 = 0, + host_size: u16 = 0, + @"allowzero": bool = false, + mutable: bool = true, // TODO change this to const, not mutable + @"volatile": bool = false, + size: std.builtin.TypeInfo.Pointer.Size = .One, + }; }; pub const ErrorUnion = struct { @@ -3815,6 +3819,37 @@ pub const Type = extern union { data: *Module.EnumSimple, }; }; + + pub fn ptr(arena: *Allocator, d: Payload.Pointer.Data) !Type { + assert(d.host_size == 0 or d.bit_offset < d.host_size * 8); + + if (d.sentinel != null or d.@"align" != 0 or d.@"addrspace" != .generic or + d.bit_offset != 0 or d.host_size != 0 or d.@"allowzero" or d.@"volatile") + { + return Type.Tag.pointer.create(arena, d); + } + + if (!d.mutable and d.size == .Slice and d.pointee_type.eql(Type.initTag(.u8))) { + return Type.initTag(.const_slice_u8); + } + + // TODO stage1 type inference bug + const T = Type.Tag; + + const type_payload = try arena.create(Type.Payload.ElemType); + type_payload.* = .{ + .base = .{ + .tag = switch (d.size) { + .One => if (d.mutable) T.single_mut_pointer else T.single_const_pointer, + .Many => if (d.mutable) T.many_mut_pointer else T.many_const_pointer, + .C => if (d.mutable) T.c_mut_pointer else T.c_const_pointer, + .Slice => if (d.mutable) T.mut_slice else T.const_slice, + }, + }, + .data = d.pointee_type, + }; + return Type.initPayload(&type_payload.base); + } }; pub const CType = enum { diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index e048848799..2dde3c930d 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -52,3 +52,41 @@ fn testFoo(foo: StructFoo) !void { fn testMutation(foo: *StructFoo) void { foo.c = 100; } + +test "struct byval assign" { + var foo1: StructFoo = undefined; + var foo2: StructFoo = undefined; + + foo1.a = 1234; + foo2.a = 0; + try expect(foo2.a == 0); + foo2 = foo1; + try expect(foo2.a == 1234); +} + +const Node = struct { + val: Val, + next: *Node, +}; + +const Val = struct { + x: i32, +}; + +test "struct initializer" { + const val = Val{ .x = 42 }; + try expect(val.x == 42); +} + +const MemberFnTestFoo = struct { + x: i32, + fn member(foo: MemberFnTestFoo) i32 { + return foo.x; + } +}; + +test "call member function directly" { + const instance = MemberFnTestFoo{ .x = 1234 }; + const result = MemberFnTestFoo.member(instance); + try expect(result == 1234); +} diff --git a/test/behavior/struct_stage1.zig b/test/behavior/struct_stage1.zig index fd19b37661..b5394afd50 100644 --- a/test/behavior/struct_stage1.zig +++ b/test/behavior/struct_stage1.zig @@ -5,6 +5,7 @@ const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; const expectEqualSlices = std.testing.expectEqualSlices; const maxInt = std.math.maxInt; + top_level_field: i32, test "top level fields" { @@ -58,22 +59,6 @@ test "struct point to self" { try expect(node.next.next.next.val.x == 1); } -test "struct byval assign" { - var foo1: StructFoo = undefined; - var foo2: StructFoo = undefined; - - foo1.a = 1234; - foo2.a = 0; - try expect(foo2.a == 0); - foo2 = foo1; - try expect(foo2.a == 1234); -} - -test "struct initializer" { - const val = Val{ .x = 42 }; - try expect(val.x == 42); -} - test "fn call of struct field" { const Foo = struct { ptr: fn () i32, @@ -91,22 +76,16 @@ test "fn call of struct field" { try expect(S.callStructField(Foo{ .ptr = S.aFunc }) == 13); } -test "store member function in variable" { - const instance = MemberFnTestFoo{ .x = 1234 }; - const memberFn = MemberFnTestFoo.member; - const result = memberFn(instance); - try expect(result == 1234); -} const MemberFnTestFoo = struct { x: i32, fn member(foo: MemberFnTestFoo) i32 { return foo.x; } }; - -test "call member function directly" { +test "store member function in variable" { const instance = MemberFnTestFoo{ .x = 1234 }; - const result = MemberFnTestFoo.member(instance); + const memberFn = MemberFnTestFoo.member; + const result = memberFn(instance); try expect(result == 1234); }