diff --git a/src/Sema.zig b/src/Sema.zig index d6664f8d84..cd4c526822 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -10146,6 +10146,87 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }), ); }, + .ErrorSet => { + var fields_anon_decl = try block.startAnonDecl(src); + defer fields_anon_decl.deinit(); + + // Get the Error type + const error_field_ty = t: { + const set_field_ty_decl = (try sema.namespaceLookup( + block, + src, + type_info_ty.getNamespace().?, + "Error", + )).?; + try sema.mod.declareDeclDependency(sema.owner_decl, set_field_ty_decl); + try sema.ensureDeclAnalyzed(set_field_ty_decl); + var buffer: Value.ToTypeBuffer = undefined; + break :t try set_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); + }; + + // If the error set is inferred it has to be resolved at this point + if (ty.castTag(.error_set_inferred)) |payload| { + try sema.resolveInferredErrorSet(payload.data); + } + + // Build our list of Error values + // Optional value is only null if anyerror + // Value can be zero-length slice otherwise + const error_field_vals: ?[]Value = if (ty.isAnyError()) null else blk: { + const names = ty.errorSetNames(); + const vals = try fields_anon_decl.arena().alloc(Value, names.len); + for (vals) |*field_val, i| { + const name = names[i]; + const name_val = v: { + var anon_decl = try block.startAnonDecl(src); + defer anon_decl.deinit(); + const bytes = try anon_decl.arena().dupeZ(u8, name); + const new_decl = try anon_decl.finish( + try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), + try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), + ); + break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl); + }; + + const error_field_fields = try fields_anon_decl.arena().create([1]Value); + error_field_fields.* = .{ + // name: []const u8, + name_val, + }; + + field_val.* = try Value.Tag.@"struct".create( + fields_anon_decl.arena(), + error_field_fields, + ); + } + + break :blk vals; + }; + + // Build our ?[]const Error value + const errors_val = if (error_field_vals) |vals| v: { + const new_decl = try fields_anon_decl.finish( + try Type.Tag.array.create(fields_anon_decl.arena(), .{ + .len = vals.len, + .elem_type = error_field_ty, + }), + try Value.Tag.array.create( + fields_anon_decl.arena(), + vals, + ), + ); + break :v try Value.Tag.decl_ref.create(sema.arena, new_decl); + } else Value.@"null"; + + // Construct TypeInfo{ .ErrorSet = errors_val } + return sema.addConstant( + type_info_ty, + try Value.Tag.@"union".create(sema.arena, .{ + .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorSet)), + .val = errors_val, + }), + ); + }, .ErrorUnion => { const field_values = try sema.arena.alloc(Value, 2); // error_set: type, @@ -10520,7 +10601,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }), ); }, - .ErrorSet => return sema.fail(block, src, "TODO: implement zirTypeInfo for ErrorSet", .{}), .BoundFn => @panic("TODO remove this type from the language and compiler"), .Frame => return sema.fail(block, src, "TODO: implement zirTypeInfo for Frame", .{}), .AnyFrame => return sema.fail(block, src, "TODO: implement zirTypeInfo for AnyFrame", .{}), diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 82814dc587..e346e6a82a 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -176,7 +176,11 @@ fn foo2(f: fn () anyerror!void) void { fn bar2() (error{}!void) {} test "error union type " { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO try testErrorUnionType(); comptime try testErrorUnionType(); @@ -191,7 +195,11 @@ fn testErrorUnionType() !void { } test "error set type" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO try testErrorSetType(); comptime try testErrorSetType(); @@ -307,7 +315,11 @@ fn foo3(b: usize) Error!usize { } test "error: Infer error set from literals" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO _ = nullLiteral("n") catch |err| handleErrors(err); _ = floatLiteral("n") catch |err| handleErrors(err); diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index d436de36a1..c4517ac277 100644 --- a/test/behavior/type_info.zig +++ b/test/behavior/type_info.zig @@ -156,8 +156,12 @@ fn testArray() !void { } } -test "type info: error set, error union info" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO +test "type info: error set, error union info, anyerror" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO try testErrorSet(); comptime try testErrorSet(); @@ -185,6 +189,38 @@ fn testErrorSet() !void { try expect(global_info.ErrorSet == null); } +test "type info: error set single value" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + const TestSet = error.One; + + const error_set_info = @typeInfo(@TypeOf(TestSet)); + try expect(error_set_info == .ErrorSet); + try expect(error_set_info.ErrorSet.?.len == 1); + try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); +} + +test "type info: error set merged" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + const TestSet = error{ One, Two } || error{Three}; + + const error_set_info = @typeInfo(TestSet); + try expect(error_set_info == .ErrorSet); + try expect(error_set_info.ErrorSet.?.len == 3); + try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); + try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two")); + try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three")); +} + test "type info: enum info" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;