all: merge master (43c41b5) into gopls-release-branch.0.14

For golang/go#63220

Merge List:

+ 2023-10-16 43c41b5e5 internal/refactor/inline: reify implicit return conversions

Change-Id: Ie2beb052f316efb38d52f7a35557f7c580c19da7
diff --git a/internal/refactor/inline/inline.go b/internal/refactor/inline/inline.go
index 8a6d777..be16161 100644
--- a/internal/refactor/inline/inline.go
+++ b/internal/refactor/inline/inline.go
@@ -760,6 +760,16 @@
 	needBindingDecl := !allResultsUnreferenced ||
 		exists(params, func(i int, p *parameter) bool { return p != nil })
 
+	// The two strategies below overlap for a tail call of {return exprs}:
+	// The expr-context reduction is nice because it keeps the
+	// caller's return stmt and merely switches its operand,
+	// without introducing a new block, but it doesn't work with
+	// implicit return conversions.
+	//
+	// TODO(adonovan): unify these cases more cleanly, allowing return-
+	// operand replacement and implicit conversions, by adding
+	// conversions around each return operand (if not a spread return).
+
 	// Special case: call to { return exprs }.
 	//
 	// Reduces to:
@@ -776,8 +786,7 @@
 	// callee's body expression, suitably substituted.
 	if len(calleeDecl.Body.List) == 1 &&
 		is[*ast.ReturnStmt](calleeDecl.Body.List[0]) &&
-		len(calleeDecl.Body.List[0].(*ast.ReturnStmt).Results) > 0 && // not a bare return
-		safeReturn(caller, calleeSymbol, callee) {
+		len(calleeDecl.Body.List[0].(*ast.ReturnStmt).Results) > 0 { // not a bare return
 		results := calleeDecl.Body.List[0].(*ast.ReturnStmt).Results
 
 		context := callContext(caller.path)
@@ -839,11 +848,24 @@
 
 			if callee.NumResults == 1 {
 				logf("strategy: reduce expr-context call to { return expr }")
+				// (includes some simple tail-calls)
+
+				// Make implicit return conversion explicit.
+				if callee.TrivialReturns < callee.TotalReturns {
+					results[0] = convert(calleeDecl.Type.Results.List[0].Type, results[0])
+				}
 
 				res.old = caller.Call
 				res.new = results[0]
-			} else {
+				return res, nil
+
+			} else if callee.TrivialReturns == callee.TotalReturns {
 				logf("strategy: reduce spread-context call to { return expr }")
+				// There is no general way to reify conversions in a spread
+				// return, hence the requirement above.
+				//
+				// TODO(adonovan): allow this reduction when no
+				// conversion is required by the context.
 
 				// The call returns multiple results but is
 				// not a standalone call statement. It must
@@ -880,8 +902,8 @@
 				default:
 					return nil, fmt.Errorf("internal error: unexpected context %T for spread call", context)
 				}
+				return res, nil
 			}
-			return res, nil
 		}
 	}
 
@@ -911,7 +933,7 @@
 	// or implicit) return.
 	if ret, ok := callContext(caller.path).(*ast.ReturnStmt); ok &&
 		len(ret.Results) == 1 &&
-		safeReturn(caller, calleeSymbol, callee) &&
+		tailCallSafeReturn(caller, calleeSymbol, callee) &&
 		!callee.HasBareReturn &&
 		(!needBindingDecl || bindingDeclStmt != nil) &&
 		!hasLabelConflict(caller.path, callee.Labels) &&
@@ -2624,9 +2646,9 @@
 	return names
 }
 
-// safeReturn reports whether the callee's return statements may be safely
+// tailCallSafeReturn reports whether the callee's return statements may be safely
 // used to return from the function enclosing the caller (which must exist).
-func safeReturn(caller *Caller, calleeSymbol *types.Func, callee *gobCallee) bool {
+func tailCallSafeReturn(caller *Caller, calleeSymbol *types.Func, callee *gobCallee) bool {
 	// It is safe if all callee returns involve only trivial conversions.
 	if callee.TrivialReturns == callee.TotalReturns {
 		return true
diff --git a/internal/refactor/inline/inline_test.go b/internal/refactor/inline/inline_test.go
index 99cc0de..525be74 100644
--- a/internal/refactor/inline/inline_test.go
+++ b/internal/refactor/inline/inline_test.go
@@ -399,6 +399,16 @@
 	var _ = 3
 }`,
 		},
+		{
+			// (a regression test for a missing conversion)
+			"Implicit return conversions are inserted in expr-context reduction.",
+			`func f(x int) error { return nil }`,
+			`func _() { if err := f(0); err != nil {} }`,
+			`func _() {
+	if err := error(nil); err != nil {
+	}
+}`,
+		},
 	})
 }
 
@@ -673,7 +683,7 @@
 			"Tail call with non-trivial return conversion (caller.sig != callee.sig).",
 			`func f() error { return E{} }; type E struct{error}`,
 			`func _() any { return f() }`,
-			`func _() any { return func() error { return E{} }() }`,
+			`func _() any { return error(E{}) }`,
 		},
 	})
 }
@@ -714,6 +724,12 @@
 			`func _() (int, error) { return f() }`,
 			`func _() (int, error) { return 0, nil }`,
 		},
+		{
+			"Implicit return conversions defeat reduction of spread returns, for now.",
+			`func f(x int) (_, _ error) { return nil, nil }`,
+			`func _() { _, _ = f(0) }`,
+			`func _() { _, _ = func() (_, _ error) { return nil, nil }() }`,
+		},
 	})
 }