@@ -760,6 +760,16 @@ func inline(logf func(string, ...any), caller *Caller, callee *gobCallee) (*resu
760
760
needBindingDecl := ! allResultsUnreferenced ||
761
761
exists (params , func (i int , p * parameter ) bool { return p != nil })
762
762
763
+ // The two strategies below overlap for a tail call of {return exprs}:
764
+ // The expr-context reduction is nice because it keeps the
765
+ // caller's return stmt and merely switches its operand,
766
+ // without introducing a new block, but it doesn't work with
767
+ // implicit return conversions.
768
+ //
769
+ // TODO(adonovan): unify these cases more cleanly, allowing return-
770
+ // operand replacement and implicit conversions, by adding
771
+ // conversions around each return operand (if not a spread return).
772
+
763
773
// Special case: call to { return exprs }.
764
774
//
765
775
// Reduces to:
@@ -776,8 +786,7 @@ func inline(logf func(string, ...any), caller *Caller, callee *gobCallee) (*resu
776
786
// callee's body expression, suitably substituted.
777
787
if len (calleeDecl .Body .List ) == 1 &&
778
788
is [* ast.ReturnStmt ](calleeDecl .Body .List [0 ]) &&
779
- len (calleeDecl .Body .List [0 ].(* ast.ReturnStmt ).Results ) > 0 && // not a bare return
780
- safeReturn (caller , calleeSymbol , callee ) {
789
+ len (calleeDecl .Body .List [0 ].(* ast.ReturnStmt ).Results ) > 0 { // not a bare return
781
790
results := calleeDecl .Body .List [0 ].(* ast.ReturnStmt ).Results
782
791
783
792
context := callContext (caller .path )
@@ -839,11 +848,24 @@ func inline(logf func(string, ...any), caller *Caller, callee *gobCallee) (*resu
839
848
840
849
if callee .NumResults == 1 {
841
850
logf ("strategy: reduce expr-context call to { return expr }" )
851
+ // (includes some simple tail-calls)
852
+
853
+ // Make implicit return conversion explicit.
854
+ if callee .TrivialReturns < callee .TotalReturns {
855
+ results [0 ] = convert (calleeDecl .Type .Results .List [0 ].Type , results [0 ])
856
+ }
842
857
843
858
res .old = caller .Call
844
859
res .new = results [0 ]
845
- } else {
860
+ return res , nil
861
+
862
+ } else if callee .TrivialReturns == callee .TotalReturns {
846
863
logf ("strategy: reduce spread-context call to { return expr }" )
864
+ // There is no general way to reify conversions in a spread
865
+ // return, hence the requirement above.
866
+ //
867
+ // TODO(adonovan): allow this reduction when no
868
+ // conversion is required by the context.
847
869
848
870
// The call returns multiple results but is
849
871
// not a standalone call statement. It must
@@ -880,8 +902,8 @@ func inline(logf func(string, ...any), caller *Caller, callee *gobCallee) (*resu
880
902
default :
881
903
return nil , fmt .Errorf ("internal error: unexpected context %T for spread call" , context )
882
904
}
905
+ return res , nil
883
906
}
884
- return res , nil
885
907
}
886
908
}
887
909
@@ -911,7 +933,7 @@ func inline(logf func(string, ...any), caller *Caller, callee *gobCallee) (*resu
911
933
// or implicit) return.
912
934
if ret , ok := callContext (caller .path ).(* ast.ReturnStmt ); ok &&
913
935
len (ret .Results ) == 1 &&
914
- safeReturn (caller , calleeSymbol , callee ) &&
936
+ tailCallSafeReturn (caller , calleeSymbol , callee ) &&
915
937
! callee .HasBareReturn &&
916
938
(! needBindingDecl || bindingDeclStmt != nil ) &&
917
939
! hasLabelConflict (caller .path , callee .Labels ) &&
@@ -2624,9 +2646,9 @@ func declares(stmts []ast.Stmt) map[string]bool {
2624
2646
return names
2625
2647
}
2626
2648
2627
- // safeReturn reports whether the callee's return statements may be safely
2649
+ // tailCallSafeReturn reports whether the callee's return statements may be safely
2628
2650
// used to return from the function enclosing the caller (which must exist).
2629
- func safeReturn (caller * Caller , calleeSymbol * types.Func , callee * gobCallee ) bool {
2651
+ func tailCallSafeReturn (caller * Caller , calleeSymbol * types.Func , callee * gobCallee ) bool {
2630
2652
// It is safe if all callee returns involve only trivial conversions.
2631
2653
if callee .TrivialReturns == callee .TotalReturns {
2632
2654
return true
0 commit comments