allow implicit cast of fn to async fn

it forces the fn to be async. closes #3079
This commit is contained in:
Andrew Kelley 2019-08-17 17:22:20 -04:00
parent 66a490c27c
commit 57b90d2d98
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
2 changed files with 51 additions and 5 deletions

View File

@ -9485,10 +9485,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
result.id = ConstCastResultIdFnAlign;
return result;
}
if (wanted_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
result.id = ConstCastResultIdFnCC;
return result;
}
if (wanted_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
result.id = ConstCastResultIdFnVarArgs;
return result;
@ -9546,6 +9542,11 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
return result;
}
}
if (wanted_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
// ConstCastResultIdFnCC is guaranteed to be the last one reported, meaning everything else is ok.
result.id = ConstCastResultIdFnCC;
return result;
}
return result;
}
@ -11780,8 +11781,11 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
add_error_note(ira->codegen, parent_msg, source_node,
buf_sprintf("only one of the functions is generic"));
break;
case ConstCastResultIdFnCC:
add_error_note(ira->codegen, parent_msg, source_node,
buf_sprintf("calling convention mismatch"));
break;
case ConstCastResultIdFnAlign: // TODO
case ConstCastResultIdFnCC: // TODO
case ConstCastResultIdFnVarArgs: // TODO
case ConstCastResultIdFnReturnType: // TODO
case ConstCastResultIdFnArgCount: // TODO
@ -11891,6 +11895,21 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop);
}
if (const_cast_result.id == ConstCastResultIdFnCC) {
ir_assert(value->value.type->id == ZigTypeIdFn, source_instr);
// ConstCastResultIdFnCC is guaranteed to be the last one reported, meaning everything else is ok.
if (wanted_type->data.fn.fn_type_id.cc == CallingConventionAsync &&
actual_type->data.fn.fn_type_id.cc == CallingConventionUnspecified)
{
ir_assert(value->value.data.x_ptr.special == ConstPtrSpecialFunction, source_instr);
ZigFn *fn = value->value.data.x_ptr.data.fn.fn_entry;
if (fn->inferred_async_node == nullptr) {
fn->inferred_async_node = source_instr->source_node;
}
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop);
}
}
// cast from T to ?T
// note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism
if (wanted_type->id == ZigTypeIdOptional) {

View File

@ -817,3 +817,30 @@ test "struct parameter to async function is copied to the frame" {
};
S.doTheTest();
}
test "cast fn to async fn when it is inferred to be async" {
const S = struct {
var frame: anyframe = undefined;
var ok = false;
fn doTheTest() void {
var ptr: async fn () i32 = undefined;
ptr = func;
var buf: [100]u8 align(16) = undefined;
var result: i32 = undefined;
_ = await @asyncCall(&buf, &result, ptr);
expect(result == 1234);
ok = true;
}
fn func() i32 {
suspend {
frame = @frame();
}
return 1234;
}
};
_ = async S.doTheTest();
resume S.frame;
expect(S.ok);
}