From 41b37712ea0af660365b1638b9b7f742990c175a Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 22 Nov 2021 02:22:16 +0100 Subject: sema: function (pointer) in-memory coercion --- src/Sema.zig | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Sema.zig b/src/Sema.zig index 4efc8846da..4dfccfd03e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -12435,16 +12435,70 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target: return coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target); } + // Functions + if (dest_ty.zigTypeTag() == .Fn and src_ty.zigTypeTag() == .Fn) { + return coerceInMemoryAllowedFns(dest_ty, src_ty, target); + } + // TODO: arrays // TODO: non-pointer-like optionals // TODO: error unions // TODO: error sets - // TODO: functions // TODO: vectors return .no_match; } +fn coerceInMemoryAllowedFns( + dest_ty: Type, + src_ty: Type, + target: std.Target, +) InMemoryCoercionResult { + const dest_info = dest_ty.fnInfo(); + const src_info = src_ty.fnInfo(); + + if (dest_info.is_var_args != src_info.is_var_args) { + return .no_match; + } + + if (dest_info.is_generic != src_info.is_generic) { + return .no_match; + } + + if (!src_info.return_type.isNoReturn()) { + const rt = coerceInMemoryAllowed(dest_info.return_type, src_info.return_type, false, target); + if (rt == .no_match) { + return rt; + } + } + + if (dest_info.param_types.len != src_info.param_types.len) { + return .no_match; + } + + for (dest_info.param_types) |dest_param_ty, i| { + const src_param_ty = src_info.param_types[i]; + + if (dest_info.comptime_params[i] != src_info.comptime_params[i]) { + return .no_match; + } + + // TODO: nolias + + // Note: Cast direction is reversed here. + const param = coerceInMemoryAllowed(src_param_ty, dest_param_ty, false, target); + if (param == .no_match) { + return param; + } + } + + if (dest_info.cc != src_info.cc) { + return .no_match; + } + + return .ok; +} + fn coerceInMemoryAllowedPtrs( dest_ty: Type, src_ty: Type, -- cgit v1.2.3 From 83a0329c92dc8302b7098f718ceed2ed00e9fda2 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 22 Nov 2021 02:38:28 +0100 Subject: sema: move error set coercion to coerceInMemoryAlloed --- src/Sema.zig | 79 +++++++++++++++++++++++++----------------------------------- 1 file changed, 33 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/Sema.zig b/src/Sema.zig index 4dfccfd03e..06bd74c67d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -12358,31 +12358,6 @@ fn coerce( // T to E!T or E to E!T return sema.wrapErrorUnion(block, dest_ty, inst, inst_src); }, - .ErrorSet => switch (inst_ty.zigTypeTag()) { - .ErrorSet => { - // Coercion to `anyerror`. Note that this check can return false positives - // in case the error sets did not get resolved. - if (dest_ty.isAnyError()) { - return sema.coerceCompatibleErrorSets(block, inst, inst_src); - } - // If both are inferred error sets of functions, and - // the dest includes the source function, the coercion is OK. - // This check is important because it works without forcing a full resolution - // of inferred error sets. - if (inst_ty.castTag(.error_set_inferred)) |src_payload| { - if (dest_ty.castTag(.error_set_inferred)) |dst_payload| { - const src_func = src_payload.data.func; - const dst_func = dst_payload.data.func; - - if (src_func == dst_func or dst_payload.data.functions.contains(src_func)) { - return sema.coerceCompatibleErrorSets(block, inst, inst_src); - } - } - } - // TODO full error set resolution and compare sets by names. - }, - else => {}, - }, .Union => switch (inst_ty.zigTypeTag()) { .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src), else => {}, @@ -12440,15 +12415,47 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target: return coerceInMemoryAllowedFns(dest_ty, src_ty, target); } + // Error Sets + if (dest_ty.zigTypeTag() == .ErrorSet and src_ty.zigTypeTag() == .ErrorSet) { + return coerceInMemoryAllowedErrorSets(dest_ty, src_ty); + } + // TODO: arrays // TODO: non-pointer-like optionals // TODO: error unions - // TODO: error sets // TODO: vectors return .no_match; } +fn coerceInMemoryAllowedErrorSets( + dest_ty: Type, + src_ty: Type, +) InMemoryCoercionResult { + // Coercion to `anyerror`. Note that this check can return false positives + // in case the error sets did not get resolved. + if (dest_ty.isAnyError()) { + return .ok; + } + // If both are inferred error sets of functions, and + // the dest includes the source function, the coercion is OK. + // This check is important because it works without forcing a full resolution + // of inferred error sets. + if (src_ty.castTag(.error_set_inferred)) |src_payload| { + if (dest_ty.castTag(.error_set_inferred)) |dst_payload| { + const src_func = src_payload.data.func; + const dst_func = dst_payload.data.func; + + if (src_func == dst_func or dst_payload.data.functions.contains(src_func)) { + return .ok; + } + } + } + + // TODO full error set resolution and compare sets by names. + return .no_match; +} + fn coerceInMemoryAllowedFns( dest_ty: Type, src_ty: Type, @@ -13224,26 +13231,6 @@ fn coerceVectorInMemory( return block.addBitCast(dest_ty, inst); } -fn coerceCompatibleErrorSets( - sema: *Sema, - block: *Block, - err_set: Air.Inst.Ref, - err_set_src: LazySrcLoc, -) !Air.Inst.Ref { - if (try sema.resolveDefinedValue(block, err_set_src, err_set)) |err_set_val| { - // Same representation works. - return sema.addConstant(Type.anyerror, err_set_val); - } - try sema.requireRuntimeBlock(block, err_set_src); - return block.addInst(.{ - .tag = .bitcast, - .data = .{ .ty_op = .{ - .ty = Air.Inst.Ref.anyerror_type, - .operand = err_set, - } }, - }); -} - fn analyzeDeclVal( sema: *Sema, block: *Block, -- cgit v1.2.3 From cb248898ab41378c2e9bcf94d05c7c42577a7bab Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 22 Nov 2021 02:52:26 +0100 Subject: sema: error union in-memory coercion --- src/Sema.zig | 10 +++++++++- test/behavior/error.zig | 16 ++++++++++++++++ test/behavior/error_stage1.zig | 16 ---------------- 3 files changed, 25 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/Sema.zig b/src/Sema.zig index 06bd74c67d..376dc25278 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -12415,6 +12415,15 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target: return coerceInMemoryAllowedFns(dest_ty, src_ty, target); } + // Error Unions + if (dest_ty.zigTypeTag() == .ErrorUnion and src_ty.zigTypeTag() == .ErrorUnion) { + const child = coerceInMemoryAllowed(dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target); + if (child == .no_match) { + return child; + } + return coerceInMemoryAllowed(dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target); + } + // Error Sets if (dest_ty.zigTypeTag() == .ErrorSet and src_ty.zigTypeTag() == .ErrorSet) { return coerceInMemoryAllowedErrorSets(dest_ty, src_ty); @@ -12422,7 +12431,6 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target: // TODO: arrays // TODO: non-pointer-like optionals - // TODO: error unions // TODO: vectors return .no_match; diff --git a/test/behavior/error.zig b/test/behavior/error.zig index edbe866b95..b7d4511fe9 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -115,3 +115,19 @@ test "implicit cast to optional to error union to return result loc" { try S.entry(); //comptime S.entry(); TODO } + +test "error: fn returning empty error set can be passed as fn returning any error" { + entry(); + comptime entry(); +} + +fn entry() void { + foo2(bar2); +} + +fn foo2(f: fn () anyerror!void) void { + const x = f(); + x catch {}; +} + +fn bar2() (error{}!void) {} diff --git a/test/behavior/error_stage1.zig b/test/behavior/error_stage1.zig index c379257b99..b279927eb8 100644 --- a/test/behavior/error_stage1.zig +++ b/test/behavior/error_stage1.zig @@ -120,22 +120,6 @@ fn quux_1() !i32 { return error.C; } -test "error: fn returning empty error set can be passed as fn returning any error" { - entry(); - comptime entry(); -} - -fn entry() void { - foo2(bar2); -} - -fn foo2(f: fn () anyerror!void) void { - const x = f(); - x catch {}; -} - -fn bar2() (error{}!void) {} - test "error: Zero sized error set returned with value payload crash" { _ = foo3(0) catch {}; _ = comptime foo3(0) catch {}; -- cgit v1.2.3