internal/pkgdoc: handle IndexListExpr

This fixes the panic occuring when the documentation generator
(pkgdoc) processes methods defined on generic types with multiple
type parameters (e.g., func (T[A, B]) M() {}).

The pkg.go.dev (pkgsite) is the default documentation serer and
go.dev/pkg/... are redirected to pkg.go.dev/....
However, the pkgdoc package is still used in certain cases:

- golang.google.cn serves package documentation directly using pkgdoc.
- when explicitly requested via `?m=old` (https://go.dev/pkg/fmt/?m=old)
- local development

Fixes golang/go#80430

Change-Id: I4d12c7d20ca74da4f95eb40dbb4f5e964373eeef
Reviewed-on: https://go-review.googlesource.com/c/website/+/801540
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/internal/pkgdoc/doc.go b/internal/pkgdoc/doc.go
index 75e556d..3ed6c3a 100644
--- a/internal/pkgdoc/doc.go
+++ b/internal/pkgdoc/doc.go
@@ -356,6 +356,8 @@
 			}
 			if index, ok := r.(*ast.IndexExpr); ok { // Name[T]
 				r = index.X
+			} else if indexList, ok := r.(*ast.IndexListExpr); ok { // Name[T1, T2]
+				r = indexList.X
 			}
 			name = r.(*ast.Ident).Name + "_" + name
 		}
diff --git a/internal/pkgdoc/doc_test.go b/internal/pkgdoc/doc_test.go
index c28aa79..8fc0116 100644
--- a/internal/pkgdoc/doc_test.go
+++ b/internal/pkgdoc/doc_test.go
@@ -75,3 +75,43 @@
 		t.Errorf("pInfo.PDoc.Funcs[0].Doc = %q; want %q", got, want)
 	}
 }
+
+func TestGenericMethodWithMultipleTypeParams(t *testing.T) {
+	const packagePath = "example.com/p"
+	fs := fstest.MapFS{
+		"lib/godoc/x.html": {},
+		"src/" + packagePath + "/p.go": {Data: []byte(`package p
+type T[A, B any] struct{}
+func (T[A, B]) M() {}
+`)},
+	}
+
+	site := web.NewSite(fs)
+	h, err := NewServer(fs, site, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	d := h.(*docs)
+
+	pInfo := d.open("src/"+packagePath, 0, "linux", "amd64") // must not panic
+	if pInfo.Err != nil {
+		t.Fatal(pInfo.Err)
+	}
+	if pInfo.PDoc == nil {
+		t.Fatal("pInfo.PDoc = nil; want non-nil")
+	}
+	if len(pInfo.PDoc.Types) != 1 {
+		t.Fatalf("len(pInfo.PDoc.Types) = %d; want 1", len(pInfo.PDoc.Types))
+	}
+	typ := pInfo.PDoc.Types[0]
+	if got, want := typ.Name, "T"; got != want {
+		t.Errorf("typ.Name = %q; want %q", got, want)
+	}
+	if len(typ.Methods) != 1 {
+		t.Fatalf("len(typ.Methods) = %d; want 1", len(typ.Methods))
+	}
+	meth := typ.Methods[0]
+	if got, want := meth.Name, "M"; got != want {
+		t.Errorf("meth.Name = %q; want %q", got, want)
+	}
+}