internal/vuln: remove the dependency on golang.org/x/exp

It's used for slices.Compact. This change makes a copy of that
function, which should be removed once we can depend on it being
present in the standard library.

For golang/go#61399

Change-Id: I3fcd49a3d4cf1a40c402ca137efa9a16929c2cc1
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/514519
kokoro-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Michael Matloob <matloob@golang.org>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/go.mod b/go.mod
index b44ecad..cec5eb7 100644
--- a/go.mod
+++ b/go.mod
@@ -34,7 +34,6 @@
 	github.com/yuin/goldmark v1.4.13
 	github.com/yuin/goldmark-emoji v1.0.1
 	go.opencensus.io v0.23.0
-	golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
 	golang.org/x/mod v0.8.0
 	golang.org/x/net v0.13.0
 	golang.org/x/sync v0.1.0
diff --git a/go.sum b/go.sum
index 7f122e8..2c4b14a 100644
--- a/go.sum
+++ b/go.sum
@@ -1108,8 +1108,6 @@
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
-golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
diff --git a/internal/vuln/client.go b/internal/vuln/client.go
index ef1bfd9..bc53bc6 100644
--- a/internal/vuln/client.go
+++ b/internal/vuln/client.go
@@ -12,7 +12,6 @@
 	"sort"
 	"strings"
 
-	"golang.org/x/exp/slices"
 	"golang.org/x/pkgsite/internal/derrors"
 	"golang.org/x/pkgsite/internal/osv"
 	"golang.org/x/pkgsite/internal/stdlib"
@@ -299,11 +298,31 @@
 	}
 	sortIDs(ids)
 	// Remove any duplicates.
-	ids = slices.Compact(ids)
+	ids = slicesCompact(ids)
 
 	return c.byIDsFilter(ctx, ids, entryMatch)
 }
 
+// slicesCompact is a copy of slices.Compact.
+// TODO: remove this function and replace its usage with
+// slices.Compact once we can depend on it being present
+// in the standard library of the previous two Go versions.
+func slicesCompact[S ~[]E, E comparable](s S) S {
+	if len(s) < 2 {
+		return s
+	}
+	i := 1
+	for k := 1; k < len(s); k++ {
+		if s[k] != s[k-1] {
+			if i != k {
+				s[i] = s[k]
+			}
+			i++
+		}
+	}
+	return s[:i]
+}
+
 func (c *Client) byIDsFilter(ctx context.Context, ids []string, filter func(*osv.Entry) bool) (_ []*osv.Entry, err error) {
 	entries, err := c.byIDs(ctx, ids)
 	if err != nil {