From a7221ef4e902e63e72524559a067afcf6c1dfd17 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 6 May 2021 22:30:44 -0700 Subject: Sema: implement `@typeInfo` for functions The goal is to get start code to be able to inspect the calling convention of `main` in order to determine whether to export a main for libc to call, or to allow the root source file to do it. --- src/Sema.zig | 39 ++++++++++++++++++++++++++++++++++++++- src/type.zig | 2 +- src/value.zig | 20 ++++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Sema.zig b/src/Sema.zig index 5b2dc339f6..eb9400e7b1 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4708,7 +4708,44 @@ fn zirBuiltinSrc( fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const inst_data = sema.code.instructions.items(.data)[inst].un_node; const src = inst_data.src(); - return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeInfo", .{}); + const ty = try sema.resolveType(block, src, inst_data.operand); + const type_info_ty = try sema.getBuiltinType(block, src, "TypeInfo"); + const target = sema.mod.getTarget(); + + switch (ty.zigTypeTag()) { + .Fn => { + const field_values = try sema.arena.alloc(Value, 6); + // calling_convention: CallingConvention, + field_values[0] = try Value.Tag.enum_field_index.create( + sema.arena, + @enumToInt(ty.fnCallingConvention()), + ); + // alignment: comptime_int, + field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.ptrAlignment(target)); + // is_generic: bool, + field_values[2] = Value.initTag(.bool_false); // TODO + // is_var_args: bool, + field_values[3] = Value.initTag(.bool_false); // TODO + // return_type: ?type, + field_values[4] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType()); + // args: []const FnArg, + field_values[5] = Value.initTag(.null_value); // TODO + + return sema.mod.constInst(sema.arena, src, .{ + .ty = type_info_ty, + .val = try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create( + sema.arena, + @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Fn), + ), + .val = try Value.Tag.@"struct".create(sema.arena, field_values.ptr), + }), + }); + }, + else => |t| return sema.mod.fail(&block.base, src, "TODO: implement zirTypeInfo for {s}", .{ + @tagName(t), + }), + } } fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { diff --git a/src/type.zig b/src/type.zig index bf4b3f7b64..f492eeb3ec 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1214,7 +1214,7 @@ pub const Type = extern union { if (ptr_info.@"align" != 0) { return ptr_info.@"align"; } else { - return ptr_info.pointee_type.abiAlignment(); + return ptr_info.pointee_type.abiAlignment(target); } }, diff --git a/src/value.zig b/src/value.zig index e6ce65a9f4..2c7002402b 100644 --- a/src/value.zig +++ b/src/value.zig @@ -120,6 +120,8 @@ pub const Value = extern union { error_union, /// An instance of a struct. @"struct", + /// An instance of a union. + @"union", /// This is a special value that tracks a set of types that have been stored /// to an inferred allocation. It does not support any of the normal value queries. inferred_alloc, @@ -228,6 +230,7 @@ pub const Value = extern union { .@"error" => Payload.Error, .inferred_alloc => Payload.InferredAlloc, .@"struct" => Payload.Struct, + .@"union" => Payload.Union, }; } @@ -446,6 +449,7 @@ pub const Value = extern union { return Value{ .ptr_otherwise = &new_payload.base }; }, .@"struct" => @panic("TODO can't copy struct value without knowing the type"), + .@"union" => @panic("TODO can't copy union value without knowing the type"), .inferred_alloc => unreachable, } @@ -528,6 +532,9 @@ pub const Value = extern union { .@"struct" => { return out_stream.writeAll("(struct value)"); }, + .@"union" => { + return out_stream.writeAll("(union value)"); + }, .null_value => return out_stream.writeAll("null"), .undef => return out_stream.writeAll("undefined"), .zero => return out_stream.writeAll("0"), @@ -709,6 +716,7 @@ pub const Value = extern union { .error_union, .empty_struct_value, .@"struct", + .@"union", .inferred_alloc, .abi_align_default, => unreachable, @@ -1225,6 +1233,7 @@ pub const Value = extern union { .export_options_type, .extern_options_type, .@"struct", + .@"union", => @panic("TODO this hash function looks pretty broken. audit it"), } return hasher.final(); @@ -1413,6 +1422,7 @@ pub const Value = extern union { .error_union, .empty_struct_value, .@"struct", + .@"union", .null_value, .abi_align_default, => false, @@ -1564,6 +1574,16 @@ pub const Value = extern union { /// Field values. The number and type are according to the struct type. data: [*]Value, }; + + pub const Union = struct { + pub const base_tag = Tag.@"union"; + + base: Payload = .{ .tag = base_tag }, + data: struct { + tag: Value, + val: Value, + }, + }; }; /// Big enough to fit any non-BigInt value -- cgit v1.2.3