gopls/internal/golang/completion: avoid SEGV from double deslicing

Completing at the cursor in
func f[T ~[]int](x T) {var s string;  _ = append(x, append(<cursor>x, x...)...)
causes an extra deslicing in expectedCallParamType which makes the
expected param type as both variadic and nil which produces []nil
as the inner append's type, which gets matched against s's type
for completion, which seems to cause the panic.

The fix is to avoid slicing if there's a ..., in which case a slice is
being passed directly, so the code doesn't need to deslice.

Fixes: golang/go#74564
Change-Id: I4771417438969ba494ac51283c7932bbf26cb117
Reviewed-on: https://go-review.googlesource.com/c/tools/+/809600
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Hongxiang Jiang <hxjiang@golang.org>
diff --git a/gopls/internal/golang/completion/builtin.go b/gopls/internal/golang/completion/builtin.go
index 68f773e..d465b84 100644
--- a/gopls/internal/golang/completion/builtin.go
+++ b/gopls/internal/golang/completion/builtin.go
@@ -91,10 +91,11 @@
 			break
 		}
 
-		inf.objType = deslice(inf.objType)
-
-		// Check if we are completing the variadic append() param.
-		inf.variadic = exprIdx == 1 && len(call.Args) <= 2
+		if !call.Ellipsis.IsValid() {
+			inf.objType = deslice(inf.objType)
+			// Check if we are completing the variadic append() param. (TestIssue74564)
+			inf.variadic = exprIdx == 1 && len(call.Args) <= 2
+		}
 
 		// Penalize the first append() argument as a candidate. You
 		// don't normally append a slice to itself.
diff --git a/gopls/internal/golang/completion/completion.go b/gopls/internal/golang/completion/completion.go
index f9f53b7..ed146c0 100644
--- a/gopls/internal/golang/completion/completion.go
+++ b/gopls/internal/golang/completion/completion.go
@@ -2723,7 +2723,7 @@
 		inf.objType = sig.Params().At(exprIdx).Type()
 	}
 
-	if sig.Variadic() && exprIdx >= (numParams-1) {
+	if sig.Variadic() && exprIdx >= (numParams-1) && !node.Ellipsis.IsValid() {
 		// If we are completing a variadic param, deslice the variadic type.
 		inf.objType = deslice(inf.objType)
 		// Record whether we are completing the initial variadic param.
diff --git a/gopls/internal/test/integration/completion/completion_test.go b/gopls/internal/test/integration/completion/completion_test.go
index 0fcd8a6..045b859 100644
--- a/gopls/internal/test/integration/completion/completion_test.go
+++ b/gopls/internal/test/integration/completion/completion_test.go
@@ -1697,3 +1697,25 @@
 		env.Completion(loc)
 	})
 }
+
+func TestIssue74564(t *testing.T) {
+	const src = `
+-- go.mod --
+module mod.com
+go 1.22
+-- main.go --
+package main
+
+func f[T ~[]int](x T) {
+	var s string
+	_ = append(x, append(x, x...)...)
+}
+`
+	Run(t, src, func(t *testing.T, env *Env) {
+		env.OpenFile("main.go")
+		env.Await(env.DoneWithOpen())
+		// Place cursor inside the first 'x' of the inner append call.
+		loc := env.RegexpSearch("main.go", `append\(x, append\(()x,`)
+		env.Completion(loc)
+	})
+}