Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler doesn't see required assignment in try..else structure. #3283

Closed
niclash opened this issue Aug 19, 2019 · 8 comments · Fixed by #4011
Closed

Compiler doesn't see required assignment in try..else structure. #3283

niclash opened this issue Aug 19, 2019 · 8 comments · Fixed by #4011
Assignees

Comments

@niclash
Copy link
Contributor

niclash commented Aug 19, 2019

The sample https://playground.ponylang.io/?gist=8b8975e6007b92a892779ac8f6a838ac doesn't compile, even though _tcp is being assigned in both branches.

Perhaps there are additional/hidden branches that I am unaware of.

@mfelsche
Copy link
Contributor

Here is a more minimal example, exhibiting the same bug.

actor Main
  var _s: (String | None)
  
  new create(env: Env) =>
    try
      _s = "".usize()?.string()
    else
      _s = None
    end

@mfelsche
Copy link
Contributor

mfelsche commented Aug 20, 2019

As I am exploring the reason for this, there is more cases exhibiting the same behaviour.

while loops:

actor Main
  var _s: (String | None)
  
  new create(env: Env) =>
    var i: USize = 0
    while i < 5 do
       _s = i.string()
       i = i + 1
    else
      _s = ""
    end

The same is true for for loops as they desugar to while loops.

@ponylang ponylang deleted a comment from mfelsche Aug 27, 2019
@ponylang ponylang deleted a comment from mfelsche Aug 27, 2019
@SeanTAllen SeanTAllen added needs investigation This needs to be looked into before its "ready for work" bug and removed bug: 1 - needs investigation labels May 12, 2020
@SeanTAllen
Copy link
Member

SeanTAllen commented Feb 14, 2022

refer_while, refer_try, refer_repeat might be doing something different with ast_consolidate_branches than refer_if as if works.

This error is because SYM_DEFINED isn't set for the _s symbol and that happens via ast_consolidate_branches.

@ponylang-main ponylang-main added the discuss during sync Should be discussed during an upcoming sync label Feb 14, 2022
@SeanTAllen
Copy link
Member

SeanTAllen commented Feb 14, 2022

This change to refer_while fixes the issue despite some code that looks like it was intentionally trying to create the issue. Note that with this change, all the tests pass so, I think this would be fine for a PR. I'll open it later as it builds on another PR I did and I don't think they are connected at all, but I'm not positive of that and it is easier to redo this 1 method here once the other is merged and verify.

static bool refer_while(pass_opt_t* opt, ast_t* ast)
{
  pony_assert(ast_id(ast) == TK_WHILE);
  AST_GET_CHILDREN(ast, cond, body, else_clause);

  // All consumes have to be in scope when the loop body finishes.
  errorframe_t errorf = NULL;
  if(!ast_all_consumes_in_scope(body, body, &errorf))
  {
    errorframe_report(&errorf, opt->check.errors);
    return false;
  }

  size_t branch_count = 0;
  if(!ast_checkflag(else_clause, AST_FLAG_JUMPS_AWAY))
  {
    branch_count++;
    ast_inheritbranch(ast, body);

    ast_consolidate_branches(ast, branch_count);
  }

  // If all branches jump away with no value, then we do too.
  if(branch_count == 0 && ast_checkflag(body, AST_FLAG_JUMPS_AWAY))
    ast_setflag(ast, AST_FLAG_JUMPS_AWAY);

  // Push our symbol status to our parent scope.
  ast_inheritstatus(ast_parent(ast), ast);

  return true;
}

that leave refer_try and refer_repeat to look at.

@SeanTAllen SeanTAllen self-assigned this Feb 14, 2022
@SeanTAllen SeanTAllen removed the needs investigation This needs to be looked into before its "ready for work" label Feb 14, 2022
@SeanTAllen
Copy link
Member

The refer_while code above is incorrect. I have a fix on a branch and it looks like tests are passing.

SeanTAllen added a commit that referenced this issue Feb 15, 2022
Previously, due to a bug in the compile'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) =>
    var i: USize = 0
    while i < 5 do
       _s = i.string()
       i = i + 1
    else
      _s = ""
    end
```

This commit fixes while/else handling in `refer_while` so that it matches the
correct logic as seen in `refer_if`.

Partially addresses a series of related bugs in #3283.
SeanTAllen added a commit that referenced this issue Feb 15, 2022
Previously, due to a bug in the compile'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) =>
    var i: USize = 0
    while i < 5 do
       _s = i.string()
       i = i + 1
    else
      _s = ""
    end
```

This commit fixes while/else handling in `refer_while` so that it matches the
correct logic as seen in `refer_if`.

Partially addresses a series of related bugs in #3283.
@SeanTAllen
Copy link
Member

repeat is ok.

try has something weird going on where I am getting assertions for a symbol table being missing, so that requires more investigation.

@SeanTAllen
Copy link
Member

SeanTAllen commented Feb 15, 2022

So the issue with try appears to be that unlike if and while etc, if doesn't introduce a scope and without it, there's no symbol table. Not sure why that is. I don't believe this is possible to fix without try being a scope.

I'm also not sure why try isn't a scope.

@jemc @mfelsche any ideas on why try isn't a scope?

@SeanTAllen
Copy link
Member

Ok I figured out how to fix this and I think in the process I understand why try isn't a scope. I need to put more tests together and then I can open a PR.

SeanTAllen added a commit that referenced this issue Feb 15, 2022
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
SeanTAllen added a commit that referenced this issue Feb 15, 2022
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
SeanTAllen added a commit that referenced this issue Feb 15, 2022
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) =>
    var i: USize = 0
    while i < 5 do
       _s = i.string()
       i = i + 1
    else
      _s = ""
    end
```

This commit fixes while/else handling in `refer_while` so that it matches the
correct logic as seen in `refer_if`.

Partially addresses a series of related bugs in #3283.
@SeanTAllen SeanTAllen removed the discuss during sync Should be discussed during an upcoming sync label Feb 15, 2022
ergl pushed a commit that referenced this issue Feb 16, 2022
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) =>
    var i: USize = 0
    while i < 5 do
       _s = i.string()
       i = i + 1
    else
      _s = ""
    end
```

This commit fixes while/else handling in `refer_while` so that it matches the
correct logic as seen in `refer_if`.

Partially addresses a series of related bugs in #3283.
SeanTAllen added a commit that referenced this issue Feb 16, 2022
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
SeanTAllen added a commit that referenced this issue Feb 16, 2022
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
SeanTAllen added a commit that referenced this issue Feb 16, 2022
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
@SeanTAllen SeanTAllen removed the bug label Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants