diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-05-07 14:18:14 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-05-07 14:18:14 -0700 |
| commit | 47531b7d9389c45af3e46b623235792f14a40ff2 (patch) | |
| tree | 9412cb8c20a690381e58d607e6348028e19ab3d2 /src/type.zig | |
| parent | a7221ef4e902e63e72524559a067afcf6c1dfd17 (diff) | |
| download | zig-47531b7d9389c45af3e46b623235792f14a40ff2.tar.gz zig-47531b7d9389c45af3e46b623235792f14a40ff2.zip | |
Sema: support enough to check main calling convention via `@typeInfo`
After this commit, `pub export fn main() c_int { ... }` will be
correctly detected as the intended entry point, and therefore start code
will not try to export its own conflicting `main` function.
* Implement basic union support
- lots of stuff is still TODO, including runtime field access
- also TODO: resolving the union tag type
- comptime field access is implemented
* DRY up some code by using the `Zir.DeclIterator` for skipping over
decls in structs and unions.
* Start to clean up Sema with regards to calling `.value()` to find out
a const value. Instead, Sema code should call one of these two:
- `resolvePossiblyUndefinedValue` (followed by logic dealing with
undefined values)
- `resolveDefinedValue` (a compile error will be emitted if the value
is undefined)
* An exported function with an unspecified calling convention gets the
C calling convention.
* Implement comptime field access for structs.
* Add another implementation of "type has one possible value" in Sema.
This is a bit unfortunate since the logic is duplicated, but the one
in Type asserts that the types are resolved already, and is
appropriate to call from codegen, while the one in Sema performs
type resolution if necessary, reporting any compile errors that occur
in the process.
Diffstat (limited to 'src/type.zig')
| -rw-r--r-- | src/type.zig | 122 |
1 files changed, 107 insertions, 15 deletions
diff --git a/src/type.zig b/src/type.zig index f492eeb3ec..6c4b4273c3 100644 --- a/src/type.zig +++ b/src/type.zig @@ -122,6 +122,10 @@ pub const Type = extern union { .reduce_op, => return .Enum, + .@"union", + .union_tagged, + => return .Union, + .var_args_param => unreachable, // can be any type } } @@ -506,11 +510,18 @@ pub const Type = extern union { } return a.tag() == b.tag(); }, + .Union => { + if (a.cast(Payload.Union)) |a_payload| { + if (b.cast(Payload.Union)) |b_payload| { + return a_payload.data == b_payload.data; + } + } + return a.tag() == b.tag(); + }, .Opaque, .Float, .ErrorUnion, .ErrorSet, - .Union, .BoundFn, .Frame, => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }), @@ -735,6 +746,7 @@ pub const Type = extern union { .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name), .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope), .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct), + .@"union", .union_tagged => return self.copyPayloadShallow(allocator, Payload.Union), .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple), .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull), .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque), @@ -806,6 +818,10 @@ pub const Type = extern union { const struct_obj = ty.castTag(.@"struct").?.data; return struct_obj.owner_decl.renderFullyQualifiedName(writer); }, + .@"union", .union_tagged => { + const union_obj = ty.cast(Payload.Union).?.data; + return union_obj.owner_decl.renderFullyQualifiedName(writer); + }, .enum_full, .enum_nonexhaustive => { const enum_full = ty.cast(Payload.EnumFull).?.data; return enum_full.owner_decl.renderFullyQualifiedName(writer); @@ -1151,6 +1167,27 @@ pub const Type = extern union { const int_tag_ty = self.intTagType(&buffer); return int_tag_ty.hasCodeGenBits(); }, + .@"union" => { + const union_obj = self.castTag(.@"union").?.data; + for (union_obj.fields.entries.items) |entry| { + if (entry.value.ty.hasCodeGenBits()) + return true; + } else { + return false; + } + }, + .union_tagged => { + const union_obj = self.castTag(.@"union").?.data; + if (union_obj.tag_ty.hasCodeGenBits()) { + return true; + } + for (union_obj.fields.entries.items) |entry| { + if (entry.value.ty.hasCodeGenBits()) + return true; + } else { + return false; + } + }, // TODO lazy types .array, .vector => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, @@ -1359,6 +1396,34 @@ pub const Type = extern union { const int_tag_ty = self.intTagType(&buffer); return int_tag_ty.abiAlignment(target); }, + .union_tagged => { + const union_obj = self.castTag(.union_tagged).?.data; + var biggest: u32 = union_obj.tag_ty.abiAlignment(target); + for (union_obj.fields.entries.items) |entry| { + const field_ty = entry.value.ty; + if (!field_ty.hasCodeGenBits()) continue; + const field_align = field_ty.abiAlignment(target); + if (field_align > biggest) { + return field_align; + } + } + assert(biggest != 0); + return biggest; + }, + .@"union" => { + const union_obj = self.castTag(.@"union").?.data; + var biggest: u32 = 0; + for (union_obj.fields.entries.items) |entry| { + const field_ty = entry.value.ty; + if (!field_ty.hasCodeGenBits()) continue; + const field_align = field_ty.abiAlignment(target); + if (field_align > biggest) { + return field_align; + } + } + assert(biggest != 0); + return biggest; + }, .c_void, .void, .type, @@ -1411,6 +1476,9 @@ pub const Type = extern union { const int_tag_ty = self.intTagType(&buffer); return int_tag_ty.abiSize(target); }, + .@"union", .union_tagged => { + @panic("TODO abiSize unions"); + }, .u8, .i8, @@ -1570,6 +1638,9 @@ pub const Type = extern union { const int_tag_ty = self.intTagType(&buffer); return int_tag_ty.bitSize(target); }, + .@"union", .union_tagged => { + @panic("TODO bitSize unions"); + }, .u8, .i8 => 8, @@ -2263,6 +2334,8 @@ pub const Type = extern union { }; } + /// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which + /// resolves field types rather than asserting they are already resolved. pub fn onePossibleValue(starting_type: Type) ?Value { var ty = starting_type; while (true) switch (ty.tag()) { @@ -2330,10 +2403,18 @@ pub const Type = extern union { .extern_options, .@"anyframe", .anyframe_T, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .single_const_pointer, + .single_mut_pointer, + .pointer, => return null, .@"struct" => { const s = ty.castTag(.@"struct").?.data; + assert(s.haveFieldTypes()); for (s.fields.entries.items) |entry| { const field_ty = entry.value.ty; if (field_ty.onePossibleValue() == null) { @@ -2359,6 +2440,12 @@ pub const Type = extern union { } }, .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty, + .@"union" => { + return null; // TODO + }, + .union_tagged => { + return null; // TODO + }, .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), .void => return Value.initTag(.void_value), @@ -2379,20 +2466,7 @@ pub const Type = extern union { ty = ty.elemType(); continue; }, - .many_const_pointer, - .many_mut_pointer, - .c_const_pointer, - .c_mut_pointer, - .single_const_pointer, - .single_mut_pointer, - => { - ty = ty.castPointer().?.data; - continue; - }, - .pointer => { - ty = ty.castTag(.pointer).?.data.pointee_type; - continue; - }, + .inferred_alloc_const => unreachable, .inferred_alloc_mut => unreachable, }; @@ -2412,6 +2486,8 @@ pub const Type = extern union { .enum_full => &self.castTag(.enum_full).?.data.namespace, .empty_struct => self.castTag(.empty_struct).?.data, .@"opaque" => &self.castTag(.@"opaque").?.data, + .@"union" => &self.castTag(.@"union").?.data.namespace, + .union_tagged => &self.castTag(.union_tagged).?.data.namespace, else => null, }; @@ -2612,6 +2688,10 @@ pub const Type = extern union { const error_set = ty.castTag(.error_set).?.data; return error_set.srcLoc(); }, + .@"union", .union_tagged => { + const union_obj = ty.cast(Payload.Union).?.data; + return union_obj.srcLoc(); + }, .atomic_ordering, .atomic_rmw_op, .calling_convention, @@ -2643,6 +2723,10 @@ pub const Type = extern union { const error_set = ty.castTag(.error_set).?.data; return error_set.owner_decl; }, + .@"union", .union_tagged => { + const union_obj = ty.cast(Payload.Union).?.data; + return union_obj.owner_decl; + }, .@"opaque" => @panic("TODO"), .atomic_ordering, .atomic_rmw_op, @@ -2801,6 +2885,8 @@ pub const Type = extern union { empty_struct, @"opaque", @"struct", + @"union", + union_tagged, enum_simple, enum_full, enum_nonexhaustive, @@ -2902,6 +2988,7 @@ pub const Type = extern union { .error_set_single => Payload.Name, .@"opaque" => Payload.Opaque, .@"struct" => Payload.Struct, + .@"union", .union_tagged => Payload.Union, .enum_full, .enum_nonexhaustive => Payload.EnumFull, .enum_simple => Payload.EnumSimple, .empty_struct => Payload.ContainerScope, @@ -3040,6 +3127,11 @@ pub const Type = extern union { data: *Module.Struct, }; + pub const Union = struct { + base: Payload, + data: *Module.Union, + }; + pub const EnumFull = struct { base: Payload, data: *Module.EnumFull, |
