From 5de9aac7491958806164f46c356fce983b1c8624 Mon Sep 17 00:00:00 2001 From: Vexu Date: Mon, 24 Aug 2020 16:24:23 +0300 Subject: [PATCH] stage2: error set types --- src-self-hosted/type.zig | 82 ++++++++++++++++++++++++++++++++++-- src-self-hosted/value.zig | 25 +++++++++-- src-self-hosted/zir.zig | 2 +- src-self-hosted/zir_sema.zig | 26 ++++++++---- 4 files changed, 118 insertions(+), 17 deletions(-) diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 37f9f0c638f1a34a471fba6c91bd1c428f89c291..eb8fa2acd7c79014da540c6c2db01c77c7e23bf2 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -3,6 +3,7 @@ const Value = @import("value.zig").Value; const assert = std.debug.assert; const Allocator = std.mem.Allocator; const Target = std.Target; +const Module = @import("Module.zig"); /// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication. /// It's important for this type to be small. @@ -52,7 +53,7 @@ pub const Type = extern union { .bool => return .Bool, .void => return .Void, .type => return .Type, - .anyerror => return .ErrorSet, + .error_set, .error_set_single, .anyerror => return .ErrorSet, .comptime_int => return .ComptimeInt, .comptime_float => return .ComptimeFloat, .noreturn => return .NoReturn, @@ -436,6 +437,8 @@ pub const Type = extern union { }; return Type{ .ptr_otherwise = &new_payload.base }; }, + .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), + .error_set_single => return self.copyPayloadShallow(allocator, Payload.ErrorSetSingle), } } @@ -657,6 +660,14 @@ pub const Type = extern union { ty = payload.payload; continue; }, + .error_set => { + const payload = @fieldParentPtr(Payload.ErrorSet, "base", ty.ptr_otherwise); + return out_stream.writeAll(std.mem.spanZ(payload.decl.name)); + }, + .error_set_single => { + const payload = @fieldParentPtr(Payload.ErrorSetSingle, "base", ty.ptr_otherwise); + return out_stream.print("error{{{}}}", .{payload.name}); + }, } unreachable; } @@ -753,6 +764,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => true, // TODO lazy types .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, @@ -848,7 +861,11 @@ pub const Type = extern union { .f128 => return 16, .c_longdouble => return 16, - .anyerror_void_error_union, .anyerror => return 2, // TODO revisit this when we have the concept of the error tag type + .error_set, + .error_set_single, + .anyerror_void_error_union, + .anyerror, + => return 2, // TODO revisit this when we have the concept of the error tag type .array, .array_sentinel => return self.elemType().abiAlignment(target), @@ -981,7 +998,11 @@ pub const Type = extern union { .f128 => return 16, .c_longdouble => return 16, - .anyerror_void_error_union, .anyerror => return 2, // TODO revisit this when we have the concept of the error tag type + .error_set, + .error_set_single, + .anyerror_void_error_union, + .anyerror, + => return 2, // TODO revisit this when we have the concept of the error tag type .int_signed, .int_unsigned => { const bits: u16 = if (self.cast(Payload.IntSigned)) |pl| @@ -1084,6 +1105,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => false, .single_const_pointer, @@ -1156,6 +1179,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => false, .const_slice, @@ -1225,6 +1250,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => false, .single_const_pointer, @@ -1303,6 +1330,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => false, .pointer => { @@ -1418,6 +1447,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => unreachable, .array => self.cast(Payload.Array).?.elem_type, @@ -1543,6 +1574,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => unreachable, .array => self.cast(Payload.Array).?.len, @@ -1614,6 +1647,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => unreachable, .array, .array_u8 => return null, @@ -1683,6 +1718,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => false, .int_signed, @@ -1755,6 +1792,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => false, .int_unsigned, @@ -1817,6 +1856,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => unreachable, .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits }, @@ -1897,6 +1938,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => false, .usize, @@ -2006,6 +2049,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => unreachable, }; } @@ -2081,6 +2126,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => unreachable, } } @@ -2155,6 +2202,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => unreachable, } } @@ -2229,6 +2278,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => unreachable, }; } @@ -2300,6 +2351,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => unreachable, }; } @@ -2371,6 +2424,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => unreachable, }; } @@ -2442,6 +2497,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => false, }; } @@ -2497,6 +2554,8 @@ pub const Type = extern union { .anyframe_T, .@"anyframe", .error_union, + .error_set, + .error_set_single, => return null, .void => return Value.initTag(.void_value), @@ -2604,6 +2663,8 @@ pub const Type = extern union { .@"anyframe", .anyframe_T, .anyerror_void_error_union, + .error_set, + .error_set_single, => return false, .c_const_pointer, @@ -2687,6 +2748,8 @@ pub const Type = extern union { optional_single_const_pointer, error_union, anyframe_T, + error_set, + error_set_single, pub const last_no_payload_tag = Tag.const_slice_u8; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; @@ -2781,6 +2844,19 @@ pub const Type = extern union { return_type: Type, }; + + pub const ErrorSet = struct { + base: Payload = .{ .tag = .error_set }, + + decl: *Module.Decl, + }; + + pub const ErrorSetSingle = struct { + base: Payload = .{ .tag = .error_set_single }, + + /// memory is owned by `Module` + name: []const u8, + }; }; }; diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index eacbd4e9ab677fbc3fbfaa00cc300fca7b080933..f2e36b59a49632a78ab508b8fa1fffd921dec8a1 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -381,11 +381,9 @@ pub const Value = extern union { } /// Asserts that the value is representable as a type. - pub fn toType(self: Value) Type { + pub fn toType(self: Value, allocator: *Allocator) !Type { return switch (self.tag()) { .ty => self.cast(Payload.Ty).?.ty, - .int_type => @panic("TODO int type to type"), - .u8_type => Type.initTag(.u8), .i8_type => Type.initTag(.i8), .u16_type => Type.initTag(.u16), @@ -427,7 +425,25 @@ pub const Value = extern union { .const_slice_u8_type => Type.initTag(.const_slice_u8), .enum_literal_type => Type.initTag(.enum_literal), .anyframe_type => Type.initTag(.@"anyframe"), - .error_set => @panic("TODO error set to type"), + + .int_type => { + const payload = self.cast(Payload.IntType).?; + if (payload.signed) { + const new = try allocator.create(Type.Payload.IntSigned); + new.* = .{ .bits = payload.bits }; + return Type.initPayload(&new.base); + } else { + const new = try allocator.create(Type.Payload.IntUnsigned); + new.* = .{ .bits = payload.bits }; + return Type.initPayload(&new.base); + } + }, + .error_set => { + const payload = self.cast(Payload.ErrorSet).?; + const new = try allocator.create(Type.Payload.ErrorSet); + new.* = .{ .decl = payload.decl }; + return Type.initPayload(&new.base); + }, .undef, .zero, @@ -1579,6 +1595,7 @@ pub const Value = extern union { // TODO revisit this when we have the concept of the error tag type fields: std.StringHashMapUnmanaged(u16), + decl: *Module.Decl, }; pub const Error = struct { diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 079dc13c35800f60fc2c8295b0a0f5c0f44ba739..3557c88f4eb5a94d88a35b3f8af36533498ee382 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -2016,7 +2016,7 @@ const EmitZIR = struct { return self.emitUnnamedDecl(&as_inst.base); }, .Type => { - const ty = typed_value.val.toType(); + const ty = try typed_value.val.toType(&self.arena.allocator); return self.emitType(src, ty); }, .Fn => { diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 85e6a764fbf442a99d7de71d3e015a2c47e7c118..7106bda0905e22e5585f3cc15c83c1d7e0798451 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -150,7 +150,7 @@ pub fn analyzeBodyValueAsType(mod: *Module, block_scope: *Scope.Block, body: zir for (block_scope.instructions.items) |inst| { if (inst.castTag(.ret)) |ret| { const val = try mod.resolveConstValue(&block_scope.base, ret.operand); - return val.toType(); + return val.toType(block_scope.base.arena()); } else { return mod.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); } @@ -275,7 +275,7 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type { const wanted_type = Type.initTag(.@"type"); const coerced_inst = try mod.coerce(scope, wanted_type, new_inst); const val = try mod.resolveConstValue(scope, coerced_inst); - return val.toType(); + return val.toType(scope.arena()); } fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 { @@ -745,7 +745,10 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In errdefer new_decl_arena.deinit(); const payload = try scope.arena().create(Value.Payload.ErrorSet); - payload.* = .{ .fields = .{} }; + payload.* = .{ + .fields = .{}, + .decl = undefined, // populated below + }; try payload.fields.ensureCapacity(&new_decl_arena.allocator, inst.positionals.fields.len); for (inst.positionals.fields) |field_name| { @@ -759,6 +762,7 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In .ty = Type.initTag(.type), .val = Value.initPayload(&payload.base), }); + payload.decl = new_decl; return mod.analyzeDeclRef(scope, inst.base.src, new_decl); } @@ -939,18 +943,17 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr _ = try mod.resolveConstValue(scope, object_ptr); const result = try mod.analyzeDeref(scope, fieldptr.base.src, object_ptr, object_ptr.src); const val = result.value().?; - const child_type = val.toType(); + const child_type = try val.toType(scope.arena()); switch (child_type.zigTypeTag()) { .ErrorSet => { // TODO resolve inferred error sets const entry = if (val.cast(Value.Payload.ErrorSet)) |payload| (payload.fields.getEntry(field_name) orelse return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).* - else - try mod.getErrorValue(field_name); + else try mod.getErrorValue(field_name); const error_payload = try scope.arena().create(Value.Payload.Error); - error_payload.* = .{ + error_payload.* = .{ .name = entry.key, .value = entry.value, }; @@ -958,9 +961,14 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr const ref_payload = try scope.arena().create(Value.Payload.RefVal); ref_payload.* = .{ .val = Value.initPayload(&error_payload.base) }; - // TODO if this is accessing the global error set create a `error{field_name}` type + const result_type = if (child_type.tag() == .anyerror) blk: { + const result_payload = try scope.arena().create(Type.Payload.ErrorSetSingle); + result_payload.* = .{ .name = entry.key }; + break :blk Type.initPayload(&result_payload.base); + } else child_type; + return mod.constInst(scope, fieldptr.base.src, .{ - .ty = try mod.simplePtrType(scope, fieldptr.base.src, child_type, false, .One), + .ty = try mod.simplePtrType(scope, fieldptr.base.src, result_type, false, .One), .val = Value.initPayload(&ref_payload.base), }); }, -- 2.54.0