Skip to content

Commit 4a2dd0d

Browse files
committed
go/callgraph/vta: allow pointer to type parameter in sliceArrayElem
Fixes a bug in sliceArrayElem that panicked when when a pointer to type parameter type where the type parameters is indexable, but does not have a core type. Example: func set[T [1]I | [2]I](arr *T, i int, x I) { (*arr)[i] = x } Fixes golang/go#59754 Change-Id: I196e2b882ffa84a13b7c6153796b38c1b8707722 Reviewed-on: https://go-review.googlesource.com/c/tools/+/492739 Commit-Queue: Tim King <[email protected]> gopls-CI: kokoro <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Zvonimir Pavlinovic <[email protected]> Run-TryBot: Tim King <[email protected]>
1 parent 7c6c2b7 commit 4a2dd0d

File tree

4 files changed

+66
-12
lines changed

4 files changed

+66
-12
lines changed

go/callgraph/vta/helpers_test.go

+11
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
package vta
66

77
import (
8+
"bytes"
89
"fmt"
910
"go/ast"
1011
"go/parser"
1112
"io/ioutil"
1213
"sort"
1314
"strings"
15+
"testing"
1416

1517
"golang.org/x/tools/go/callgraph"
1618
"golang.org/x/tools/go/ssa/ssautil"
@@ -114,3 +116,12 @@ func callGraphStr(g *callgraph.Graph) []string {
114116
}
115117
return gs
116118
}
119+
120+
// Logs the functions of prog to t.
121+
func logFns(t testing.TB, prog *ssa.Program) {
122+
for fn := range ssautil.AllFunctions(prog) {
123+
var buf bytes.Buffer
124+
fn.WriteTo(&buf)
125+
t.Log(buf.String())
126+
}
127+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// go:build ignore
6+
7+
package testdata
8+
9+
type F func()
10+
11+
func set[T [1]F | [2]F](arr *T, i int) {
12+
// Indexes into a pointer to an indexable type T and T does not have a coretype.
13+
// SSA instruction: t0 = &arr[i]
14+
(*arr)[i] = bar
15+
}
16+
17+
func bar() {
18+
print("here")
19+
}
20+
21+
func Foo() {
22+
var arr [1]F
23+
set(&arr, 0)
24+
arr[0]()
25+
}
26+
27+
// WANT:
28+
// Foo: set[[1]testdata.F](t0, 0:int) -> set[[1]testdata.F]; t3() -> bar

go/callgraph/vta/utils.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,14 @@ func functionUnderPtr(t types.Type) types.Type {
123123
func sliceArrayElem(t types.Type) types.Type {
124124
switch u := t.Underlying().(type) {
125125
case *types.Pointer:
126-
return u.Elem().Underlying().(*types.Array).Elem()
126+
switch e := u.Elem().Underlying().(type) {
127+
case *types.Array:
128+
return e.Elem()
129+
case *types.Interface:
130+
return sliceArrayElem(e) // e is a type param with matching element types.
131+
default:
132+
panic(t)
133+
}
127134
case *types.Array:
128135
return u.Elem()
129136
case *types.Slice:

go/callgraph/vta/vta_test.go

+19-11
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,26 @@ func TestVTACallGraphGenerics(t *testing.T) {
124124
}
125125

126126
// TODO(zpavlinovic): add more tests
127-
file := "testdata/src/callgraph_generics.go"
128-
prog, want, err := testProg(file, ssa.InstantiateGenerics)
129-
if err != nil {
130-
t.Fatalf("couldn't load test file '%s': %s", file, err)
131-
}
132-
if len(want) == 0 {
133-
t.Fatalf("couldn't find want in `%s`", file)
127+
files := []string{
128+
"testdata/src/arrays_generics.go",
129+
"testdata/src/callgraph_generics.go",
134130
}
131+
for _, file := range files {
132+
t.Run(file, func(t *testing.T) {
133+
prog, want, err := testProg(file, ssa.InstantiateGenerics)
134+
if err != nil {
135+
t.Fatalf("couldn't load test file '%s': %s", file, err)
136+
}
137+
if len(want) == 0 {
138+
t.Fatalf("couldn't find want in `%s`", file)
139+
}
135140

136-
g := CallGraph(ssautil.AllFunctions(prog), cha.CallGraph(prog))
137-
got := callGraphStr(g)
138-
if diff := setdiff(want, got); len(diff) != 0 {
139-
t.Errorf("computed callgraph %v should contain %v (diff: %v)", got, want, diff)
141+
g := CallGraph(ssautil.AllFunctions(prog), cha.CallGraph(prog))
142+
got := callGraphStr(g)
143+
if diff := setdiff(want, got); len(diff) != 0 {
144+
t.Errorf("computed callgraph %v should contain %v (diff: %v)", got, want, diff)
145+
logFns(t, prog)
146+
}
147+
})
140148
}
141149
}

0 commit comments

Comments
 (0)