#995 If statement returned in a closure - Internal compiler error

katox Thu 25 Feb 2010

I found out that

internal XElem? findFront(XElem e)
{
    frontmatter := e.elems.eachWhile |x|
    { 
      log.debug ("name=${x.name}") // without this line it compiles OK
      if (x.name == "frontmatter")
         return x
      else
        return findFront(x)
    }

    return frontmatter
}

causes an internal compiler error (mercurial tip):

ERR: Internal compiler error
sys::CastErr: java.lang.ClassCastException: fan.compiler.IfStmt cannot be cast to 
fan.compiler.ReturnStmt
compiler::ClosureExpr.collapseExprAndReturn (Expr.fan:1500)
compiler::ClosureExpr.setInferredSignature (Expr.fan:1483)
compiler::CallResolver.inferClosureTypeFromCall (CallResolver.fan:377)
compiler::CallResolver.inferClosureType (CallResolver.fan:349)
compiler::CallResolver.resolve (CallResolver.fan:65)
compiler::ResolveExpr.resolveCall (ResolveExpr.fan:447)
compiler::ResolveExpr.resolveExpr (ResolveExpr.fan:163)
compiler::ResolveExpr.visitExpr (ResolveExpr.fan:123)
compiler::Expr.walk (Expr.fan:247)
compiler::Stmt.walkExpr (Stmt.fan:61)
compiler::LocalDefStmt.walkChildren (Stmt.fan:159)
compiler::Stmt.walk (Stmt.fan:48)
compiler::Block.walk (Block.fan:89)
fan.sys.List.each (List.java:527)
compiler::Block.walk (Block.fan:87)
compiler::MethodDef.walk (MethodDef.fan:158)
compiler::TypeDef.walk (TypeDef.fan:306)
fan.sys.List.each (List.java:527)
compiler::TypeDef.walk (TypeDef.fan:306)
compiler::Visitor.walk (Visitor.fan:31)
34 More...

If rewritten as

internal XElem? findFront(XElem e)
{
    frontmatter := e.elems.eachWhile |x|
    { 
      log.debug ("name=${x.name}")
      return x.name == "frontmatter" ? x : findFront(x)
    }

    return frontmatter
}

it works fine.

Sidenote: What was the reason disallowing return in it-blocks? No big issue but it behaves a bit strangely. Going from

frontmatter := e.elems.eachWhile 
    { 
      it.name == "frontmatter" ? it : findFront(it) // ok
    }

which compiles fine to a debugging version of

frontmatter := e.elems.eachWhile 
    { 
      log.debug ("name=${it.name}")
      it.name == "frontmatter" ? it : findFront(it) // nonexpr, missing return
    }

the compiler complains of Must return a value from non-Void method but return is not allowed here so one have to rewrite everything as

frontmatter := e.elems.eachWhile |x|
    { 
      log.debug ("name=${x.name}")
      return x.name == "frontmatter" ? x : findFront(x) // return ok
    }

brian Thu 25 Feb 2010

Promoted to ticket #995 and assigned to brian

There is some bug in the compiler there.

You can't use return in it-block to be make it crystal clear what you are returning from (we've had some previous discussions on that topic). So if you want to use return then you need to use normal closure syntax.

katox Thu 25 Feb 2010

You can't use return in it-block to be make it crystal clear what you are returning from

I wasn't sure if it wasn't due to some nasty case. Thanks for reminding me. Also, I'm glad that we don't have non-local returns - the more I'm getting used to closures the less I like that idea.

brian Tue 23 Mar 2010

Ticket resolved in 1.0.52

Fixed ClosureExpr.collapseExprAndReturn to ignore non-return statements

Login or Signup to reply.