go/ssa/interp: handle nil slice convert to array pointer

Converting from nil slice to a zero length array pointer must be nil.

Updates golang/go#46987

Change-Id: I8894b92bd85fae8ea77bf01b92ee56f1a215a75b
Reviewed-on: https://go-review.googlesource.com/c/tools/+/336489
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Trust: Tim King <taking@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Tim King <taking@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Tim King <taking@google.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/go/ssa/interp/ops.go b/go/ssa/interp/ops.go
index 9c12d4a..6af7847 100644
--- a/go/ssa/interp/ops.go
+++ b/go/ssa/interp/ops.go
@@ -1367,11 +1367,13 @@
 		if utSrc, ok := utDst.(*types.Pointer); ok {
 			if arr, ok := utSrc.Elem().(*types.Array); ok {
 				x := x.([]value)
-				a := make(array, arr.Len())
-				for i := range a {
-					a[i] = x[i]
+				if arr.Len() > int64(len(x)) {
+					panic("array length is greater than slice length")
 				}
-				v := value(a)
+				if x == nil {
+					return zero(utSrc)
+				}
+				v := value(array(x[:arr.Len()]))
 				return &v
 			}
 		}
diff --git a/go/ssa/interp/testdata/slice2arrayptr.go b/go/ssa/interp/testdata/slice2arrayptr.go
index 21f9906..ad37a18 100644
--- a/go/ssa/interp/testdata/slice2arrayptr.go
+++ b/go/ssa/interp/testdata/slice2arrayptr.go
@@ -2,22 +2,47 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// Test for slice to array pointer conversion introduced in go1.17
+// See: https://tip.golang.org/ref/spec#Conversions_from_slice_to_array_pointer
+
 package main
 
-// Test for slice to array pointer conversion introduced in go1.17
-
-import "fmt"
-
-var s = []byte{1, 2, 3, 4}
-var a = (*[4]byte)(s)
-
 func main() {
-	for i := range s {
-		if a[i] != s[i] {
-			panic(fmt.Sprintf("value mismatched: %v - %v\n", a[i], s[i]))
-		}
-		if (*a)[i] != s[i] {
-			panic(fmt.Sprintf("value mismatched: %v - %v\n", (*a)[i], s[i]))
-		}
+	s := make([]byte, 2, 4)
+	if s0 := (*[0]byte)(s); s0 == nil {
+		panic("converted from non-nil slice result in nil array pointer")
 	}
+	if s2 := (*[2]byte)(s); &s2[0] != &s[0] {
+		panic("the converted array is not slice underlying array")
+	}
+	wantPanic(
+		func() {
+			_ = (*[4]byte)(s) // panics: len([4]byte) > len(s)
+		},
+		"runtime error: array length is greater than slice length",
+	)
+
+	var t []string
+	if t0 := (*[0]string)(t); t0 != nil {
+		panic("nil slice converted to *[0]byte should be nil")
+	}
+	wantPanic(
+		func() {
+			_ = (*[1]string)(t) // panics: len([1]string) > len(t)
+		},
+		"runtime error: array length is greater than slice length",
+	)
+}
+
+func wantPanic(fn func(), s string) {
+	defer func() {
+		err := recover()
+		if err == nil {
+			panic("expected panic")
+		}
+		if got := err.(error).Error(); got != s {
+			panic("expected panic " + s + " got " + got)
+		}
+	}()
+	fn()
 }