diff options
| -rw-r--r-- | lib/std/Build.zig | 21 | ||||
| -rw-r--r-- | src/Sema.zig | 22 | ||||
| -rw-r--r-- | test/behavior/maximum_minimum.zig | 14 | ||||
| -rw-r--r-- | test/behavior/try.zig | 37 |
4 files changed, 79 insertions, 15 deletions
diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 236ac16c47..dbd96441b1 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -89,6 +89,7 @@ dep_prefix: []const u8 = "", modules: std.StringArrayHashMap(*Module), named_writefiles: std.StringArrayHashMap(*Step.WriteFile), +named_lazy_paths: std.StringArrayHashMap(LazyPath), /// A map from build root dirs to the corresponding `*Dependency`. This is shared with all child /// `Build`s. initialized_deps: *InitializedDepMap, @@ -300,8 +301,9 @@ pub fn create( .install_path = undefined, .args = null, .host = graph.host, - .modules = std.StringArrayHashMap(*Module).init(arena), - .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(arena), + .modules = .init(arena), + .named_writefiles = .init(arena), + .named_lazy_paths = .init(arena), .initialized_deps = initialized_deps, .pkg_hash = "", .available_deps = available_deps, @@ -393,8 +395,9 @@ fn createChildOnly( .glibc_runtimes_dir = parent.glibc_runtimes_dir, .host = parent.host, .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }), - .modules = std.StringArrayHashMap(*Module).init(allocator), - .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator), + .modules = .init(allocator), + .named_writefiles = .init(allocator), + .named_lazy_paths = .init(allocator), .initialized_deps = parent.initialized_deps, .pkg_hash = pkg_hash, .available_deps = pkg_deps, @@ -1060,6 +1063,10 @@ pub fn addNamedWriteFiles(b: *Build, name: []const u8) *Step.WriteFile { return wf; } +pub fn addNamedLazyPath(b: *Build, name: []const u8, lp: LazyPath) void { + b.named_lazy_paths.put(b.dupe(name), lp.dupe(b)) catch @panic("OOM"); +} + pub fn addWriteFiles(b: *Build) *Step.WriteFile { return Step.WriteFile.create(b); } @@ -1902,6 +1909,12 @@ pub const Dependency = struct { }; } + pub fn namedLazyPath(d: *Dependency, name: []const u8) LazyPath { + return d.builder.named_lazy_paths.get(name) orelse { + panic("unable to find named lazypath '{s}'", .{name}); + }; + } + pub fn path(d: *Dependency, sub_path: []const u8) LazyPath { return .{ .dependency = .{ diff --git a/src/Sema.zig b/src/Sema.zig index 278ca154d7..559fbe3e53 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4487,7 +4487,7 @@ fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: boo break :ty operand_ty.childType(zcu); } else operand_ty; - const err_set_ty = err_set: { + const err_set_ty: Type = err_set: { // There are awkward cases, like `?E`. Our strategy is to repeatedly unwrap optionals // until we hit an error union or set. var cur_ty = sema.fn_ret_ty; @@ -4496,16 +4496,12 @@ fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: boo .error_set => break :err_set cur_ty, .error_union => break :err_set cur_ty.errorUnionSet(zcu), .optional => cur_ty = cur_ty.optionalChild(zcu), - else => return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "expected '{}', found error set", .{sema.fn_ret_ty.fmt(pt)}); - errdefer msg.destroy(sema.gpa); - const ret_ty_src: LazySrcLoc = .{ - .base_node_inst = sema.getOwnerFuncDeclInst(), - .offset = .{ .node_offset_fn_type_ret_ty = 0 }, - }; - try sema.errNote(ret_ty_src, msg, "function cannot return an error", .{}); - break :msg msg; - }), + else => { + // This function cannot return an error. + // `try` is still valid if the error case is impossible, i.e. no error is returned. + // So, the result type has an error set of `error{}`. + break :err_set .fromInterned(try zcu.intern_pool.getErrorSetType(zcu.gpa, pt.tid, &.{})); + }, } } }; @@ -26205,6 +26201,10 @@ fn analyzeMinMax( .child = refined_scalar_ty.toIntern(), }) else refined_scalar_ty; + if (try sema.typeHasOnePossibleValue(refined_ty)) |opv| { + return Air.internedToRef(opv.toIntern()); + } + if (!refined_ty.eql(unrefined_ty, zcu)) { // We've reduced the type - cast the result down return block.addTyOp(.intcast, refined_ty, cur_minmax.?); diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index ab1803c5b1..8994d9d182 100644 --- a/test/behavior/maximum_minimum.zig +++ b/test/behavior/maximum_minimum.zig @@ -336,3 +336,17 @@ test "@min/@max of signed and unsigned runtime integers" { try expectEqual(x, @min(x, y)); try expectEqual(y, @max(x, y)); } + +test "@min resulting in u0" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + + const S = struct { + fn min(a: u0, b: u8) u8 { + return @min(a, b); + } + }; + const x = S.min(0, 1); + try expect(x == 0); +} diff --git a/test/behavior/try.zig b/test/behavior/try.zig index f17133fabe..3e66582aaa 100644 --- a/test/behavior/try.zig +++ b/test/behavior/try.zig @@ -86,3 +86,40 @@ test "try forwards result location" { try expect((S.foo(false) catch return error.TestUnexpectedResult) == 123); try std.testing.expectError(error.Foo, S.foo(true)); } + +test "'return try' of empty error set in function returning non-error" { + if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + + const S = struct { + fn succeed0() error{}!u32 { + return 123; + } + fn succeed1() !u32 { + return 456; + } + fn tryNoError0() u32 { + return try succeed0(); + } + fn tryNoError1() u32 { + return try succeed1(); + } + fn tryNoError2() u32 { + const e: error{}!u32 = 789; + return try e; + } + fn doTheTest() !void { + const res0 = tryNoError0(); + const res1 = tryNoError1(); + const res2 = tryNoError2(); + try expect(res0 == 123); + try expect(res1 == 456); + try expect(res2 == 789); + } + }; + try S.doTheTest(); + try comptime S.doTheTest(); +} |
