aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/std/Build.zig21
-rw-r--r--src/Sema.zig22
-rw-r--r--test/behavior/maximum_minimum.zig14
-rw-r--r--test/behavior/try.zig37
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();
+}