Commit 080dd27157

Andrew Kelley <andrew@ziglang.org>
2019-03-14 16:55:29
breaking: fix @typeInfo handling of global error set type
`builtin.TypeInfo.ErrorSet` is now `?[]Error` instead of `struct{errors:[]Error}`. closes #1936
1 parent e861da0
Changed files (7)
doc/docgen.zig
@@ -707,7 +707,7 @@ const builtin_types = [][]const u8{
     "f16", "f32", "f64", "f128", "c_longdouble", "c_short",
     "c_ushort", "c_int", "c_uint", "c_long", "c_ulong", "c_longlong",
     "c_ulonglong", "c_char", "c_void", "void", "bool", "isize",
-    "usize", "noreturn", "type", "error", "comptime_int", "comptime_float",
+    "usize", "noreturn", "type", "anyerror", "comptime_int", "comptime_float",
 };
 
 fn isType(name: []const u8) bool {
src/codegen.cpp
@@ -7581,9 +7581,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
             "        value: comptime_int,\n"
             "    };\n"
             "\n"
-            "    pub const ErrorSet = struct {\n"
-            "        errors: []Error,\n"
-            "    };\n"
+            "    pub const ErrorSet = ?[]Error;\n"
             "\n"
             "    pub const EnumField = struct {\n"
             "        name: []const u8,\n"
src/ir.cpp
@@ -18265,21 +18265,16 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
                 result->special = ConstValSpecialStatic;
                 result->type = ir_type_info_get_type(ira, "ErrorSet", nullptr);
 
-                ConstExprValue *fields = create_const_vals(1);
-                result->data.x_struct.fields = fields;
-
-                // errors: []TypeInfo.Error
-                ensure_field_index(result->type, "errors", 0);
-
                 ZigType *type_info_error_type = ir_type_info_get_type(ira, "Error", nullptr);
                 if (!resolve_inferred_error_set(ira->codegen, type_entry, source_instr->source_node)) {
                     return ErrorSemanticAnalyzeFail;
                 }
                 if (type_is_global_error_set(type_entry)) {
-                    ir_add_error(ira, source_instr,
-                        buf_sprintf("TODO: compiler bug: implement @typeInfo support for anyerror. https://github.com/ziglang/zig/issues/1936"));
-                    return ErrorSemanticAnalyzeFail;
+                    result->data.x_optional = nullptr;
+                    break;
                 }
+                ConstExprValue *slice_val = create_const_vals(1);
+                result->data.x_optional = slice_val;
 
                 uint32_t error_count = type_entry->data.error_set.err_count;
                 ConstExprValue *error_array = create_const_vals(1);
@@ -18288,7 +18283,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
                 error_array->data.x_array.special = ConstArraySpecialNone;
                 error_array->data.x_array.data.s_none.elements = create_const_vals(error_count);
 
-                init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false);
+                init_const_slice(ira->codegen, slice_val, error_array, 0, error_count, false);
                 for (uint32_t error_index = 0; error_index < error_count; error_index++) {
                     ErrorTableEntry *error = type_entry->data.error_set.errors[error_index];
                     ConstExprValue *error_val = &error_array->data.x_array.data.s_none.elements[error_index];
std/fmt.zig
@@ -112,10 +112,6 @@ pub fn formatType(
     output: fn (@typeOf(context), []const u8) Errors!void,
 ) Errors!void {
     const T = @typeOf(value);
-    if (T == anyerror) {
-        try output(context, "error.");
-        return output(context, @errorName(value));
-    }
     switch (@typeInfo(T)) {
         builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {
             return formatValue(value, fmt, context, Errors, output);
std/meta.zig
@@ -13,32 +13,8 @@ const TypeInfo = builtin.TypeInfo;
 pub fn tagName(v: var) []const u8 {
     const T = @typeOf(v);
     switch (@typeInfo(T)) {
-        TypeId.Enum => |info| {
-            const Tag = info.tag_type;
-            inline for (info.fields) |field| {
-                if (field.value == @enumToInt(v)) return field.name;
-            }
-
-            unreachable;
-        },
-        TypeId.Union => |info| {
-            const UnionTag = if (info.tag_type) |UT| UT else @compileError("union is untagged");
-            const Tag = @typeInfo(UnionTag).Enum.tag_type;
-            inline for (info.fields) |field| {
-                if (field.enum_field.?.value == @enumToInt(UnionTag(v)))
-                    return field.name;
-            }
-
-            unreachable;
-        },
-        TypeId.ErrorSet => |info| {
-            inline for (info.errors) |err| {
-                if (err.value == @errorToInt(v)) return err.name;
-            }
-
-            unreachable;
-        },
-        else => @compileError("expected enum, error set or union type, found '" ++ @typeName(T) ++ "'"),
+        TypeId.ErrorSet => return @errorName(v),
+        else => return @tagName(v),
     }
 }
 
@@ -267,7 +243,7 @@ pub fn fields(comptime T: type) switch (@typeInfo(T)) {
         TypeId.Struct => |info| info.fields,
         TypeId.Union => |info| info.fields,
         TypeId.Enum => |info| info.fields,
-        TypeId.ErrorSet => |info| info.errors,
+        TypeId.ErrorSet => |errors| errors.?, // must be non global error set
         else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
     };
 }
std/testing.zig
@@ -5,7 +5,6 @@ const std = @import("std.zig");
 /// This function is intended to be used only in tests. It prints diagnostics to stderr
 /// and then aborts when actual_error_union is not expected_error.
 pub fn expectError(expected_error: anyerror, actual_error_union: var) void {
-    // TODO remove the workaround here for https://github.com/ziglang/zig/issues/1936
     if (actual_error_union) |actual_payload| {
         // TODO remove workaround here for https://github.com/ziglang/zig/issues/557
         if (@sizeOf(@typeOf(actual_payload)) == 0) {
test/stage1/behavior/type_info.zig
@@ -143,14 +143,18 @@ fn testErrorSet() void {
 
     const error_set_info = @typeInfo(TestErrorSet);
     expect(TypeId(error_set_info) == TypeId.ErrorSet);
-    expect(error_set_info.ErrorSet.errors.len == 3);
-    expect(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
-    expect(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third));
+    expect(error_set_info.ErrorSet.?.len == 3);
+    expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "First"));
+    expect(error_set_info.ErrorSet.?[2].value == @errorToInt(TestErrorSet.Third));
 
     const error_union_info = @typeInfo(TestErrorSet!usize);
     expect(TypeId(error_union_info) == TypeId.ErrorUnion);
     expect(error_union_info.ErrorUnion.error_set == TestErrorSet);
     expect(error_union_info.ErrorUnion.payload == usize);
+
+    const global_info = @typeInfo(anyerror);
+    expect(TypeId(global_info) == TypeId.ErrorSet);
+    expect(global_info.ErrorSet == null);
 }
 
 test "type info: enum info" {