@@ -52,6 +52,7 @@ type codeGen struct {
5252 currentFunc * ast.FuncDef // current function being generated (for type lookups)
5353 varTypeScope string // override scope key for varType lookups (test/bench blocks)
5454 inSpawn int // nesting depth of spawn blocks (>0 means inside spawn)
55+ inTryHandler int // nesting depth of try/or handler defers (>0 means inside handler)
5556 lambdaDepth int // nesting depth of lambda bodies (>0 means inside fn)
5657 lambdaScopeBase []int // scope index at each lambda entry (stack)
5758 lambdaOuterFunc []* ast.FuncDef // enclosing function at each lambda entry (stack)
@@ -978,16 +979,14 @@ func (g *codeGen) writeFunc(f *ast.FuncDef) error {
978979 g .inFunc = true
979980 hasImplicitReturn := false
980981 for i , s := range f .Body {
981- // Implicit return: last expression in function body becomes the return value.
982+ // Implicit return: last expression or if/else in function body becomes the return value.
982983 if i == len (f .Body )- 1 {
983- if es , ok := s .(* ast.ExprStmt ); ok {
984- g .emitLineDirective (es .SourceLine )
985- expr , err := g .exprString (es .Expression )
986- if err != nil {
987- return err
988- }
989- g .writef ("return %s\n " , expr )
990- hasImplicitReturn = true
984+ handled , allCovered , err := g .writeLastStmtAs (s , "return %s\n " )
985+ if err != nil {
986+ return err
987+ }
988+ if handled {
989+ hasImplicitReturn = allCovered
991990 continue
992991 }
993992 }
@@ -1220,6 +1219,51 @@ func (g *codeGen) writeExprStmt(e *ast.ExprStmt) error {
12201219func (g * codeGen ) writeIf (i * ast.IfStmt ) error {
12211220 // Pre-declare variables assigned in any branch so they're visible
12221221 // after the if block (Ruby-like scoping: if/else doesn't create a new scope).
1222+ g .predeclareIfVars (i )
1223+
1224+ cond , err := g .exprString (i .Condition )
1225+ if err != nil {
1226+ return err
1227+ }
1228+ g .writef ("if %s {\n " , g .condExpr (cond , i .Condition ))
1229+ g .indent ++
1230+ for _ , s := range i .Body {
1231+ if err := g .writeStmt (s ); err != nil {
1232+ return err
1233+ }
1234+ }
1235+ g .indent --
1236+ for _ , ec := range i .ElsifClauses {
1237+ cond , err := g .exprString (ec .Condition )
1238+ if err != nil {
1239+ return err
1240+ }
1241+ g .writef ("} else if %s {\n " , g .condExpr (cond , ec .Condition ))
1242+ g .indent ++
1243+ for _ , s := range ec .Body {
1244+ if err := g .writeStmt (s ); err != nil {
1245+ return err
1246+ }
1247+ }
1248+ g .indent --
1249+ }
1250+ if len (i .ElseBody ) > 0 {
1251+ g .writeln ("} else {" )
1252+ g .indent ++
1253+ for _ , s := range i .ElseBody {
1254+ if err := g .writeStmt (s ); err != nil {
1255+ return err
1256+ }
1257+ }
1258+ g .indent --
1259+ }
1260+ g .writeln ("}" )
1261+ return nil
1262+ }
1263+
1264+ // predeclareIfVars pre-declares variables assigned in any branch of an if/else
1265+ // so they're visible after the if block (Ruby-like scoping).
1266+ func (g * codeGen ) predeclareIfVars (i * ast.IfStmt ) {
12231267 var allBranches []ast.Statement
12241268 allBranches = append (allBranches , i .Body ... )
12251269 for _ , ec := range i .ElsifClauses {
@@ -1237,44 +1281,91 @@ func (g *codeGen) writeIf(i *ast.IfStmt) error {
12371281 g .declareVar (name )
12381282 }
12391283 }
1284+ }
1285+
1286+ // writeLastStmtAs tries to write a statement as an implicit return or assignment.
1287+ // format is the format string for the last expression (e.g. "return %s\n" or "r = %s\n").
1288+ // Returns handled=true if the statement was written, allCovered=true if all code paths
1289+ // produce a value (e.g. if/elsif/else with all branches handled).
1290+ func (g * codeGen ) writeLastStmtAs (s ast.Statement , format string ) (handled bool , allCovered bool , err error ) {
1291+ switch st := s .(type ) {
1292+ case * ast.ExprStmt :
1293+ g .emitLineDirective (st .StmtLine ())
1294+ expr , err := g .exprString (st .Expression )
1295+ if err != nil {
1296+ return false , false , err
1297+ }
1298+ g .writef (format , expr )
1299+ return true , true , nil
1300+ case * ast.IfStmt :
1301+ allCovered , err := g .writeIfWithLastAction (st , format )
1302+ if err != nil {
1303+ return false , false , err
1304+ }
1305+ return true , allCovered , nil
1306+ default :
1307+ return false , false , nil
1308+ }
1309+ }
1310+
1311+ // writeIfWithLastAction writes an if/elsif/else block where the last expression
1312+ // in each branch is formatted with the given format string (for implicit returns).
1313+ func (g * codeGen ) writeIfWithLastAction (i * ast.IfStmt , format string ) (bool , error ) {
1314+ g .predeclareIfVars (i )
12401315
12411316 cond , err := g .exprString (i .Condition )
12421317 if err != nil {
1243- return err
1318+ return false , err
12441319 }
12451320 g .writef ("if %s {\n " , g .condExpr (cond , i .Condition ))
12461321 g .indent ++
1247- for _ , s := range i .Body {
1248- if err := g .writeStmt (s ); err != nil {
1249- return err
1250- }
1322+ if err := g .writeBodyWithLastAction (i .Body , format ); err != nil {
1323+ return false , err
12511324 }
12521325 g .indent --
12531326 for _ , ec := range i .ElsifClauses {
12541327 cond , err := g .exprString (ec .Condition )
12551328 if err != nil {
1256- return err
1329+ return false , err
12571330 }
12581331 g .writef ("} else if %s {\n " , g .condExpr (cond , ec .Condition ))
12591332 g .indent ++
1260- for _ , s := range ec .Body {
1261- if err := g .writeStmt (s ); err != nil {
1262- return err
1263- }
1333+ if err := g .writeBodyWithLastAction (ec .Body , format ); err != nil {
1334+ return false , err
12641335 }
12651336 g .indent --
12661337 }
1338+ allCovered := false
12671339 if len (i .ElseBody ) > 0 {
12681340 g .writeln ("} else {" )
12691341 g .indent ++
1270- for _ , s := range i .ElseBody {
1271- if err := g .writeStmt (s ); err != nil {
1272- return err
1273- }
1342+ if err := g .writeBodyWithLastAction (i .ElseBody , format ); err != nil {
1343+ return false , err
12741344 }
12751345 g .indent --
1346+ allCovered = true
12761347 }
12771348 g .writeln ("}" )
1349+ return allCovered , nil
1350+ }
1351+
1352+ // writeBodyWithLastAction writes a list of statements, converting the last
1353+ // expression into the given format (e.g. "return %s\n").
1354+ func (g * codeGen ) writeBodyWithLastAction (body []ast.Statement , format string ) error {
1355+ for i , s := range body {
1356+ if i == len (body )- 1 {
1357+ handled , _ , err := g .writeLastStmtAs (s , format )
1358+ if err != nil {
1359+ return err
1360+ }
1361+ if handled {
1362+ continue
1363+ }
1364+ }
1365+ if err := g .writeStmt (s ); err != nil {
1366+ return err
1367+ }
1368+ }
12781369 return nil
12791370}
12801371
@@ -1476,6 +1567,18 @@ func (g *codeGen) rangeIntExpr(e ast.Expr) string {
14761567}
14771568
14781569func (g * codeGen ) writeReturn (r * ast.ReturnStmt ) error {
1570+ // Inside a try/or handler defer, return sets the handler result (r).
1571+ if g .inTryHandler > 0 {
1572+ if r .Value != nil {
1573+ expr , err := g .exprString (r .Value )
1574+ if err != nil {
1575+ return err
1576+ }
1577+ g .writef ("r = %s\n " , expr )
1578+ }
1579+ g .writeln ("return" )
1580+ return nil
1581+ }
14791582 // Inside a spawn block, return EXPR must assign to t.result and
14801583 // use a bare return (the goroutine closure has no return value).
14811584 if g .inSpawn > 0 {
@@ -2145,27 +2248,30 @@ func (g *codeGen) tryExpr(e *ast.TryExpr) (string, error) {
21452248 handlerCode , cerr := g .captureOutput (func () error {
21462249 g .pushScope ()
21472250 g .declareVar (e .ErrVar )
2251+ g .inTryHandler ++
21482252
21492253 for i , s := range e .Handler {
21502254 isLast := i == len (e .Handler )- 1
21512255 if isLast {
2152- // Last statement: if it's a bare expression, assign to r (return value)
2153- if es , ok := s .( * ast. ExprStmt ); ok {
2154- val , verr := g . exprString ( es . Expression )
2155- if verr != nil {
2156- g .popScope ()
2157- return verr
2158- }
2159- g . writef ( "r = %s \n " , val )
2256+ // Last statement: if it's a bare expression or if/else , assign to r (return value)
2257+ handled , _ , herr := g . writeLastStmtAs ( s , "r = %s \n " )
2258+ if herr != nil {
2259+ g . inTryHandler --
2260+ g .popScope ()
2261+ return herr
2262+ }
2263+ if handled {
21602264 continue
21612265 }
21622266 }
21632267 if werr := g .writeStmt (s ); werr != nil {
2268+ g .inTryHandler --
21642269 g .popScope ()
21652270 return werr
21662271 }
21672272 }
21682273
2274+ g .inTryHandler --
21692275 g .popScope ()
21702276 return nil
21712277 })
@@ -2274,15 +2380,13 @@ func (g *codeGen) fnExpr(e *ast.FnExpr) (string, error) {
22742380 for i , s := range e .Body {
22752381 isLast := i == len (e .Body )- 1
22762382 if isLast {
2277- // Last statement: if it's a bare expression, make it the return value
2278- if es , ok := s .(* ast.ExprStmt ); ok {
2279- g .emitLineDirective (es .StmtLine ())
2280- val , verr := g .exprString (es .Expression )
2281- if verr != nil {
2282- restoreLambda ()
2283- return verr
2284- }
2285- g .writef ("return %s\n " , val )
2383+ // Last statement: if it's a bare expression or if/else, make it the return value
2384+ handled , _ , herr := g .writeLastStmtAs (s , "return %s\n " )
2385+ if herr != nil {
2386+ restoreLambda ()
2387+ return herr
2388+ }
2389+ if handled {
22862390 continue
22872391 }
22882392 }
0 commit comments