diff --git a/codebuild.go b/codebuild.go index ede89f8..7819e7a 100644 --- a/codebuild.go +++ b/codebuild.go @@ -454,6 +454,9 @@ func (p *CodeBuilder) Return(n int, src ...ast.Node) *CodeBuilder { log.Println("Return", n) } fn := p.current.fn + if fn.cate != AutoLambdaNormal { + p.panicCodeErrorf(getPos(src), getEnd(src), cantUseFlowsInAutoLambda) + } // For non-inline functions, if stack has fewer elements than expected, it // means compilation of return arguments failed. We still mark return to @@ -2287,7 +2290,7 @@ func (p *CodeBuilder) Fallthrough() *CodeBuilder { panic("please use fallthrough in case statement") } -// For func +// For loop statement: For (..|None) Then [.. Post] .. End func (p *CodeBuilder) For(src ...ast.Node) *CodeBuilder { if debugInstr { log.Println("For") diff --git a/error_msg_test.go b/error_msg_test.go index fc3c26c..5bccafc 100644 --- a/error_msg_test.go +++ b/error_msg_test.go @@ -134,12 +134,20 @@ func TestErrSwitch(t *testing.T) { } func TestErrAutoLambda(t *testing.T) { - codeErrorTest(t, `./foo.gop:5:1: can't use return/continue/break/goto in auto lambda`, func(pkg *gogen.Package) { + codeErrorTest(t, `./foo.gop:5:2: can't use return/continue/break/goto in auto lambda`, func(pkg *gogen.Package) { cb := pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg) sig := types.NewSignatureType(nil, nil, nil, nil, nil, false) cb.NewClosureWith(sig, gogen.AutoLambdaLoop).BodyStart(pkg). - Return(0). - End(source("foo", 5, 1)) + Return(0, source("foo", 5, 2)). + End() + cb.End() + }) + codeErrorTest(t, `./foo.gop:6:1: can't use return/continue/break/goto in auto lambda`, func(pkg *gogen.Package) { + cb := pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg) + sig := types.NewSignatureType(nil, nil, nil, nil, nil, false) + cb.NewClosureWith(sig, gogen.AutoLambdaLoop).BodyStart(pkg). + Break(nil). + End(source("foo", 6, 1)) cb.End() }) } diff --git a/func.go b/func.go index 0e6548a..77f374f 100644 --- a/func.go +++ b/func.go @@ -100,18 +100,24 @@ func (p *Func) End(cb *CodeBuilder, src ast.Node) { p.inlineClosureEnd(cb) return } + pkg := cb.pkg checker := termChecker{cb.current.panicCalls} fnBody, flows := cb.endFuncBody(p.old) - if flows != 0 && p.cate != AutoLambdaNormal { - cb.handleCodeError(getSrcPos(src), getSrcEnd(src), cantUseFlowsInAutoLambda) + cate := p.cate + if cate != AutoLambdaNormal { + if flows != 0 { + cb.handleCodeError(getSrcPos(src), getSrcEnd(src), cantUseFlowsInAutoLambda) + } else { + fnBody = return0IfNeeded(fnBody) + } } body := &target.BlockStmt{List: fnBody} t := p.Type().(*types.Signature) // Check for missing return at the closing brace position. // For FuncDecl/FuncLit/BlockStmt, End() returns Rbrace+1, so End()-1 is the Rbrace position. - if t.Results().Len() > 0 && !checker.isTerminating(body, "") { + if cate == AutoLambdaNormal && t.Results().Len() > 0 && !checker.isTerminating(body, "") { pos, end := token.NoPos, token.NoPos if src != nil { end = src.End() diff --git a/package_test.go b/package_test.go index fd99fe6..d707da6 100644 --- a/package_test.go +++ b/package_test.go @@ -3787,6 +3787,45 @@ func main() { `) } +func TestAutoLambda1(t *testing.T) { + pkg := newMainPackage() + results := types.NewTuple(types.NewVar(0, pkg.Types, "", types.Typ[types.Int])) + sig := types.NewSignatureType(nil, nil, nil, nil, results, false) + pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). + NewClosureWith(sig, gogen.AutoLambdaLoop).BodyStart(pkg). + End().Call(0).EndStmt(). + End() + domTest(t, pkg, `package main + +func main() { + func() int { + return 0 + }() +} +`) +} + +func TestAutoLambda2(t *testing.T) { + pkg := newMainPackage() + results := types.NewTuple(types.NewVar(0, pkg.Types, "", types.Typ[types.Int])) + sig := types.NewSignatureType(nil, nil, nil, nil, results, false) + pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). + NewClosureWith(sig, gogen.AutoLambdaLoop).BodyStart(pkg). + For().None().Then().End(). + End().Call(0).EndStmt(). + End() + domTest(t, pkg, `package main + +func main() { + func() int { + for { + } + return 0 + }() +} +`) +} + func TestClosure(t *testing.T) { pkg := newMainPackage() fmt := pkg.Import("fmt") diff --git a/util_gengo.go b/util_gengo.go index 00fb48f..fb2cca0 100644 --- a/util_gengo.go +++ b/util_gengo.go @@ -1022,6 +1022,21 @@ func buildTypeForCallExpr(pkg *Package, T types.Type) ast.Expr { } } +func return0IfNeeded(stmts []ast.Stmt) []ast.Stmt { + var hasReturn bool + if len(stmts) > 0 { + _, hasReturn = stmts[len(stmts)-1].(*ast.ReturnStmt) + } + if !hasReturn { + stmts = append(stmts, &ast.ReturnStmt{ + Results: []ast.Expr{ + &ast.BasicLit{Kind: token.INT, Value: "0"}, + }, + }) + } + return stmts +} + // ---------------------------------------------------------------------------- func newIncDecStmt(x ast.Expr, tok token.Token) *ast.IncDecStmt { diff --git a/util_genjs.go b/util_genjs.go index d6ff269..c0bd2ef 100644 --- a/util_genjs.go +++ b/util_genjs.go @@ -216,6 +216,10 @@ func buildTypeForCallExpr(pkg *Package, T types.Type) js.Expr { panic("todo buildTypeForCallExpr") } +func return0IfNeeded(stmts []js.Stmt) []js.Stmt { + panic("todo return0IfNeeded") +} + // ---------------------------------------------------------------------------- func newIncDecStmt(x js.Expr, tok token.Token) js.Stmt {