Skip to content

Commit

Permalink
Fix incorrect "field not initialized" error with try/else
Browse files Browse the repository at this point in the history
Previously, due to a bug in the compiler's while/else handling code, the
following code would be rejected as not initializing all object fields:

```pony
actor Main
  var _s: (String | None)

  new create(env: Env) =>
    try
      _s = "".usize()?.string()
    else
      _s = None
    end
```

This commit fixes try/else handling in `refer_try` so that it matches the
general shape of `refer_if`, `refer_while`, and `refer_repeat`. It differs from
them because `try` isn't a scope and we want to push everything into the `then`
clause as it can fulfill initialization all on its own or if it doesn't handle
initialization, we can still get it from the try body and the else clause.

Closes #3283
  • Loading branch information
SeanTAllen committed Feb 15, 2022
1 parent d330436 commit ab85ab2
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 0 deletions.
15 changes: 15 additions & 0 deletions .release-notes/try-else-initialization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Fix incorrect "field not initialized" error with try/else

Previously, due to a bug in the compiler's try/else handling code, the following code would be rejected as not initializing all object fields:

```pony
actor Main
var _s: (String | None)
new create(env: Env) =>
try
_s = "".usize()?.string()
else
_s = None
end
```
8 changes: 8 additions & 0 deletions src/libponyc/pass/refer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1679,10 +1679,16 @@ static bool refer_try(pass_opt_t* opt, ast_t* ast)
size_t branch_count = 0;

if(!ast_checkflag(body, AST_FLAG_JUMPS_AWAY))
{
branch_count++;
ast_inheritbranch(then_clause, body);
}

if(!ast_checkflag(else_clause, AST_FLAG_JUMPS_AWAY))
{
branch_count++;
ast_inheritbranch(then_clause, else_clause);
}

if(ast_checkflag(then_clause, AST_FLAG_JUMPS_AWAY))
{
Expand All @@ -1691,6 +1697,8 @@ static bool refer_try(pass_opt_t* opt, ast_t* ast)
return false;
}

ast_consolidate_branches(then_clause, branch_count);

// If all branches jump away with no value, then we do too.
if(branch_count == 0)
ast_setflag(ast, AST_FLAG_JUMPS_AWAY);
Expand Down
9 changes: 9 additions & 0 deletions test/libponyc-run/try-else-can-initialize-fields/main.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
actor Main
var _s: (String | None)

new create(env: Env) =>
try
_s = "".usize()?.string()
else
_s = None
end
9 changes: 9 additions & 0 deletions test/libponyc-run/try-then-can-initialize-fields/main.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
actor Main
var _s: (String | None)

new create(env: Env) =>
try
"".usize()?.string()
then
_s = "initialized"
end
36 changes: 36 additions & 0 deletions test/libponyc/refer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#define TEST_COMPILE(src) DO(test_compile(src, "refer"))

#define TEST_ERROR(src) DO(test_error(src, "refer"))

#define TEST_ERRORS_1(src, err1) \
{ const char* errs[] = {err1, NULL}; \
DO(test_expected_errors(src, "refer", errs)); }
Expand Down Expand Up @@ -900,3 +902,37 @@ TEST_F(ReferTest, MemberAccessWithConsumeLhs)

TEST_COMPILE(src);
}

TEST_F(ReferTest, TryElseNoFieldInitializationInBody)
{
const char* src =
"actor Main\n"
" var _s: (String | None)\n"
" new create(env: Env) =>\n"
" try\n"
" \"\".usize()?.string()\n"
" else\n"
" _s = None\n"
" end";

TEST_ERRORS_2(src,
"field left undefined in constructor",
"constructor with undefined fields is here");
}

TEST_F(ReferTest, TryElseNoFieldInitializationInElse)
{
const char* src =
"actor Main\n"
" var _s: (String | None)\n"
" new create(env: Env) =>\n"
" try\n"
" _s = \"\".usize()?.string()\n"
" else\n"
" let s: String = \"hello\"\n"
" end";

TEST_ERRORS_2(src,
"field left undefined in constructor",
"constructor with undefined fields is here");
}

0 comments on commit ab85ab2

Please sign in to comment.