aristanetworks / purescript-backend-optimizer

Optimizing backend toolkit and modern ECMAScript backend for PureScript
MIT License
201 stars 18 forks source link

Issue in codegen for effect loops results in unintended fallthrough #96

Closed natefaubion closed 1 year ago

natefaubion commented 1 year ago

Given the input:

test :: Effect (Maybe (Array String)) -> Effect Unit
test eff = do
  res <- eff
  case res of
    Nothing ->
      pure unit
    Just as ->
      foreachE as \a ->
        Console.log a

This generates:

const test = eff => () => {
  const res = eff();
  if (res.tag === "Nothing") { return; }
  if (res.tag === "Just") {
    for (const a of res._1) {
      Effect$dConsole.log(a)();
    }
  }
  $runtime.fail();
};

Which has an unintended fallthrough to the call to fail. Without some of the syntactic optimizations, this generates:

const test = eff => () => {
  const res = eff();
  if (res.tag === "Nothing") { return; }
  if (res.tag === "Just") {
    return (() => {
      for (const a of res._1) {
        Effect$dConsole.log(a)();
      }
    })();
  }
  $runtime.fail();
};

Which correctly returns, but is unnecessary. There is a rewrite which inlines this block with in the if "true" branch, which is incorrect. Instead we should inline the loop block, but then tack on a return after.