diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Module.zig | 42 | ||||
| -rw-r--r-- | src/Sema.zig | 87 | ||||
| -rw-r--r-- | src/type.zig | 6 |
3 files changed, 116 insertions, 19 deletions
diff --git a/src/Module.zig b/src/Module.zig index 0cbf75c735..8c14f080d2 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -831,6 +831,10 @@ pub const Struct = struct { have_field_types, layout_wip, have_layout, + fully_resolved_wip, + // The types and all its fields have had their layout resolved. Even through pointer, + // which `have_layout` does not ensure. + fully_resolved, }, /// If true, definitely nonzero size at runtime. If false, resolving the fields /// is necessary to determine whether it has bits at runtime. @@ -889,6 +893,22 @@ pub const Struct = struct { .have_field_types, .layout_wip, .have_layout, + .fully_resolved_wip, + .fully_resolved, + => true, + }; + } + + pub fn haveLayout(s: Struct) bool { + return switch (s.status) { + .none, + .field_types_wip, + .have_field_types, + .layout_wip, + => false, + .have_layout, + .fully_resolved_wip, + .fully_resolved, => true, }; } @@ -1003,6 +1023,10 @@ pub const Union = struct { have_field_types, layout_wip, have_layout, + fully_resolved_wip, + // The types and all its fields have had their layout resolved. Even through pointer, + // which `have_layout` does not ensure. + fully_resolved, }, pub const Field = struct { @@ -1033,6 +1057,8 @@ pub const Union = struct { .have_field_types, .layout_wip, .have_layout, + .fully_resolved_wip, + .fully_resolved, => true, }; } @@ -1102,8 +1128,22 @@ pub const Union = struct { tag_size: u64, }; + pub fn haveLayout(u: Union) bool { + return switch (u.status) { + .none, + .field_types_wip, + .have_field_types, + .layout_wip, + => false, + .have_layout, + .fully_resolved_wip, + .fully_resolved, + => true, + }; + } + pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout { - assert(u.status == .have_layout); + assert(u.haveLayout()); var most_aligned_field: u32 = undefined; var most_aligned_field_size: u64 = undefined; var biggest_field: u32 = undefined; diff --git a/src/Sema.zig b/src/Sema.zig index 8389eed6d5..9ecac34c77 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4503,14 +4503,14 @@ fn analyzeCall( const arg_src = call_src; // TODO: better source location if (i < fn_params_len) { const param_ty = func_ty.fnParamType(i); - try sema.resolveTypeForCodegen(block, arg_src, param_ty); + try sema.resolveTypeFully(block, arg_src, param_ty); args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src); } else { args[i] = uncasted_arg; } } - try sema.resolveTypeForCodegen(block, call_src, func_ty_info.return_type); + try sema.resolveTypeFully(block, call_src, func_ty_info.return_type); try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + args.len); @@ -4580,7 +4580,7 @@ fn finishGenericCall( const param_ty = new_fn_ty.fnParamType(runtime_i); const arg_src = call_src; // TODO: better source location const uncasted_arg = uncasted_args[total_i]; - try sema.resolveTypeForCodegen(block, arg_src, param_ty); + try sema.resolveTypeFully(block, arg_src, param_ty); const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); runtime_args[runtime_i] = casted_arg; runtime_i += 1; @@ -4588,7 +4588,7 @@ fn finishGenericCall( total_i += 1; } - try sema.resolveTypeForCodegen(block, call_src, new_fn_ty.fnReturnType()); + try sema.resolveTypeFully(block, call_src, new_fn_ty.fnReturnType()); } try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + runtime_args_len); @@ -15228,7 +15228,7 @@ fn resolveStructLayout( .field_types_wip, .layout_wip => { return sema.fail(block, src, "struct {} depends on itself", .{ty}); }, - .have_layout => return, + .have_layout, .fully_resolved_wip, .fully_resolved => return, } struct_obj.status = .layout_wip; for (struct_obj.fields.values()) |field| { @@ -15250,7 +15250,7 @@ fn resolveUnionLayout( .field_types_wip, .layout_wip => { return sema.fail(block, src, "union {} depends on itself", .{ty}); }, - .have_layout => return, + .have_layout, .fully_resolved_wip, .fully_resolved => return, } union_obj.status = .layout_wip; for (union_obj.fields.values()) |field| { @@ -15259,7 +15259,7 @@ fn resolveUnionLayout( union_obj.status = .have_layout; } -fn resolveTypeForCodegen( +fn resolveTypeFully( sema: *Sema, block: *Block, src: LazySrcLoc, @@ -15268,20 +15268,67 @@ fn resolveTypeForCodegen( switch (ty.zigTypeTag()) { .Pointer => { const child_ty = try sema.resolveTypeFields(block, src, ty.childType()); - return resolveTypeForCodegen(sema, block, src, child_ty); + return resolveTypeFully(sema, block, src, child_ty); }, - .Struct => return resolveStructLayout(sema, block, src, ty), - .Union => return resolveUnionLayout(sema, block, src, ty), - .Array => return resolveTypeForCodegen(sema, block, src, ty.childType()), + .Struct => return resolveStructFully(sema, block, src, ty), + .Union => return resolveUnionFully(sema, block, src, ty), + .Array => return resolveTypeFully(sema, block, src, ty.childType()), .Optional => { var buf: Type.Payload.ElemType = undefined; - return resolveTypeForCodegen(sema, block, src, ty.optionalChild(&buf)); + return resolveTypeFully(sema, block, src, ty.optionalChild(&buf)); }, - .ErrorUnion => return resolveTypeForCodegen(sema, block, src, ty.errorUnionPayload()), + .ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()), else => {}, } } +fn resolveStructFully( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + ty: Type, +) CompileError!void { + try resolveStructLayout(sema, block, src, ty); + + const resolved_ty = try sema.resolveTypeFields(block, src, ty); + const struct_obj = resolved_ty.castTag(.@"struct").?.data; + switch (struct_obj.status) { + .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, + .fully_resolved_wip, .fully_resolved => return, + } + + // After we have resolve struct layout we have to go over the fields again to + // make sure pointer fields get their child types resolved as well + struct_obj.status = .fully_resolved_wip; + for (struct_obj.fields.values()) |field| { + try sema.resolveTypeFully(block, src, field.ty); + } + struct_obj.status = .fully_resolved; +} + +fn resolveUnionFully( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + ty: Type, +) CompileError!void { + try resolveUnionLayout(sema, block, src, ty); + + const resolved_ty = try sema.resolveTypeFields(block, src, ty); + const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; + switch (union_obj.status) { + .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, + .fully_resolved_wip, .fully_resolved => return, + } + + // Same goes for unions (see comment about structs) + union_obj.status = .fully_resolved_wip; + for (union_obj.fields.values()) |field| { + try sema.resolveTypeFully(block, src, field.ty); + } + union_obj.status = .fully_resolved; +} + fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type { switch (ty.tag()) { .@"struct" => { @@ -15291,7 +15338,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp .field_types_wip => { return sema.fail(block, src, "struct {} depends on itself", .{ty}); }, - .have_field_types, .have_layout, .layout_wip => return ty, + .have_field_types, + .have_layout, + .layout_wip, + .fully_resolved_wip, + .fully_resolved, + => return ty, } struct_obj.status = .field_types_wip; @@ -15324,7 +15376,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp .field_types_wip => { return sema.fail(block, src, "union {} depends on itself", .{ty}); }, - .have_field_types, .have_layout, .layout_wip => return ty, + .have_field_types, + .have_layout, + .layout_wip, + .fully_resolved_wip, + .fully_resolved, + => return ty, } union_obj.status = .field_types_wip; diff --git a/src/type.zig b/src/type.zig index 4ad15f2399..f4561769e2 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1916,7 +1916,7 @@ pub const Type = extern union { const fields = self.structFields(); const is_packed = if (self.castTag(.@"struct")) |payload| p: { const struct_obj = payload.data; - assert(struct_obj.status == .have_layout); + assert(struct_obj.haveLayout()); break :p struct_obj.layout == .Packed; } else false; @@ -2220,7 +2220,7 @@ pub const Type = extern union { if (field_count == 0) return 0; const struct_obj = ty.castTag(.@"struct").?.data; - assert(struct_obj.status == .have_layout); + assert(struct_obj.haveLayout()); var total: u64 = 0; for (struct_obj.fields.values()) |field| { @@ -3771,7 +3771,7 @@ pub const Type = extern union { switch (ty.tag()) { .@"struct" => { const struct_obj = ty.castTag(.@"struct").?.data; - assert(struct_obj.status == .have_layout); + assert(struct_obj.haveLayout()); const is_packed = struct_obj.layout == .Packed; if (!is_packed) { var offset: u64 = 0; |
