diff --git a/src/libponyc/codegen/gencontrol.c b/src/libponyc/codegen/gencontrol.c index 69c54763d9..d2cc44137d 100644 --- a/src/libponyc/codegen/gencontrol.c +++ b/src/libponyc/codegen/gencontrol.c @@ -459,6 +459,27 @@ LLVMValueRef gen_repeat(compile_t* c, ast_t* ast) return GEN_NOTNEEDED; } +LLVMValueRef gen_recover(compile_t* c, ast_t* ast) +{ + ast_t* body = ast_childidx(ast, 1); + LLVMValueRef ret = gen_expr(c, body); + + if(is_result_needed(ast)) + { + deferred_reification_t* reify = c->frame->reify; + + ast_t* type = deferred_reify(reify, ast_type(ast), c->opt); + compile_type_t* c_t = (compile_type_t*)reach_type(c->reach, type)->c_type; + ast_free_unattached(type); + + type = deferred_reify(reify, ast_type(body), c->opt); + ret = gen_assign_cast(c, c_t->use_type, ret, type); + ast_free_unattached(type); + } + + return ret; +} + LLVMValueRef gen_break(compile_t* c, ast_t* ast) { ast_t* body = ast_child(ast); diff --git a/src/libponyc/codegen/gencontrol.h b/src/libponyc/codegen/gencontrol.h index 6b4ec15c9e..d25ed2bc01 100644 --- a/src/libponyc/codegen/gencontrol.h +++ b/src/libponyc/codegen/gencontrol.h @@ -16,6 +16,8 @@ LLVMValueRef gen_while(compile_t* c, ast_t* ast); LLVMValueRef gen_repeat(compile_t* c, ast_t* ast); +LLVMValueRef gen_recover(compile_t* c, ast_t* ast); + LLVMValueRef gen_break(compile_t* c, ast_t* ast); LLVMValueRef gen_continue(compile_t* c, ast_t* ast); diff --git a/src/libponyc/codegen/genexpr.c b/src/libponyc/codegen/genexpr.c index 543295035e..565fd44b6b 100644 --- a/src/libponyc/codegen/genexpr.c +++ b/src/libponyc/codegen/genexpr.c @@ -116,7 +116,7 @@ LLVMValueRef gen_expr(compile_t* c, ast_t* ast) } case TK_RECOVER: - ret = gen_expr(c, ast_childidx(ast, 1)); + ret = gen_recover(c, ast); break; case TK_BREAK: diff --git a/src/libponyc/codegen/genfun.c b/src/libponyc/codegen/genfun.c index 0fca757578..c3096ef1e0 100644 --- a/src/libponyc/codegen/genfun.c +++ b/src/libponyc/codegen/genfun.c @@ -723,7 +723,7 @@ static bool genfun_allocator(compile_t* c, reach_type_t* t) } static bool genfun_forward(compile_t* c, reach_type_t* t, - reach_method_name_t* n, reach_method_t* m) + reach_method_name_t* n, reach_method_t* m) { compile_method_t* c_m = (compile_method_t*)m->c_method; pony_assert(c_m->func != NULL); @@ -761,6 +761,52 @@ static bool genfun_forward(compile_t* c, reach_type_t* t, return true; } +static bool genfun_method(compile_t* c, reach_type_t* t, + reach_method_name_t* n, reach_method_t* m) +{ + if(m->intrinsic) + { + if(m->internal && (n->name == c->str__final)) + { + if(!genfun_implicit_final(c, t, m)) + return false; + } + } else if(m->forwarding) { + if(!genfun_forward(c, t, n, m)) + return false; + } else { + switch(ast_id(m->fun->ast)) + { + case TK_NEW: + if(t->underlying == TK_ACTOR) + { + if(!genfun_newbe(c, t, m)) + return false; + } else { + if(!genfun_new(c, t, m)) + return false; + } + break; + + case TK_BE: + if(!genfun_be(c, t, m)) + return false; + break; + + case TK_FUN: + if(!genfun_fun(c, t, m)) + return false; + break; + + default: + pony_assert(0); + return false; + } + } + + return true; +} + void genfun_param_attrs(compile_t* c, reach_type_t* t, reach_method_t* m, LLVMValueRef fun) { @@ -900,44 +946,17 @@ bool genfun_method_bodies(compile_t* c, reach_type_t* t) while((m = reach_mangled_next(&n->r_mangled, &j)) != NULL) { - if(m->intrinsic) + if(!genfun_method(c, t, n, m)) { - if(m->internal && (n->name == c->str__final)) + if(errors_get_count(c->opt->check.errors) == 0) { - if(!genfun_implicit_final(c, t, m)) - return false; + pony_assert(m->fun != NULL); + ast_error(c->opt->check.errors, m->fun->ast, + "internal failure: code generation failed for method %s", + m->full_name); } - } else if(m->forwarding) { - if(!genfun_forward(c, t, n, m)) - return false; - } else { - switch(ast_id(m->fun->ast)) - { - case TK_NEW: - if(t->underlying == TK_ACTOR) - { - if(!genfun_newbe(c, t, m)) - return false; - } else { - if(!genfun_new(c, t, m)) - return false; - } - break; - - case TK_BE: - if(!genfun_be(c, t, m)) - return false; - break; - - case TK_FUN: - if(!genfun_fun(c, t, m)) - return false; - break; - default: - pony_assert(0); - return false; - } + return false; } } } diff --git a/src/libponyc/reach/reach.c b/src/libponyc/reach/reach.c index f05a4bb8ca..044520b4ed 100644 --- a/src/libponyc/reach/reach.c +++ b/src/libponyc/reach/reach.c @@ -1433,6 +1433,7 @@ static void reachable_expr(reach_t* r, deferred_reification_t* reify, case TK_WHILE: case TK_REPEAT: case TK_TRY: + case TK_RECOVER: { if(is_result_needed(ast) && !ast_checkflag(ast, AST_FLAG_JUMPS_AWAY)) { diff --git a/test/libponyc/codegen.cc b/test/libponyc/codegen.cc index 27c43f8d3b..d837e5b8e3 100644 --- a/test/libponyc/codegen.cc +++ b/test/libponyc/codegen.cc @@ -368,7 +368,7 @@ TEST_F(CodegenTest, ViewpointAdaptedFieldReach) TEST_F(CodegenTest, StringSerialization) { - // From issue 2245 + // From issue #2245 const char* src = "use \"serialise\"\n" @@ -623,3 +623,23 @@ TEST_F(CodegenTest, DescTable) ASSERT_EQ(type_id->getZExtValue(), i); } } + + +TEST_F(CodegenTest, RecoverCast) +{ + // From issue #2639 + const char* src = + "class A\n" + " new create() => None\n" + + "actor Main\n" + " new create(env: Env) =>\n" + " let x: ((None, None) | (A iso, None)) =\n" + " if false then\n" + " (None, None)\n" + " else\n" + " recover (A, None) end\n" + " end"; + + TEST_COMPILE(src); +}