Skip to content

Commit cd349f3

Browse files
committed
go/ssa: Move instantiation tests off of unexported API
Change-Id: Ibf0af6eac594081f9274d08a5e932d9dc52355b6 Reviewed-on: https://go-review.googlesource.com/c/tools/+/614295 Reviewed-by: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 45851d3 commit cd349f3

File tree

2 files changed

+59
-78
lines changed

2 files changed

+59
-78
lines changed

go/analysis/passes/unusedwrite/unusedwrite.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ var Analyzer = &analysis.Analyzer{
3232
func run(pass *analysis.Pass) (interface{}, error) {
3333
ssainput := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA)
3434
for _, fn := range ssainput.SrcFuncs {
35-
// TODO(taking): Iterate over fn._Instantiations() once exported. If so, have 1 report per Pos().
3635
reports := checkStores(fn)
3736
for _, store := range reports {
3837
switch addr := store.Addr.(type) {

go/ssa/instantiate_test.go

Lines changed: 59 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
package ssa
6-
7-
// Note: Tests use unexported method _Instances.
5+
package ssa_test
86

97
import (
10-
"bytes"
118
"fmt"
129
"go/types"
1310
"reflect"
@@ -16,6 +13,8 @@ import (
1613
"testing"
1714

1815
"golang.org/x/tools/go/loader"
16+
"golang.org/x/tools/go/ssa"
17+
"golang.org/x/tools/go/ssa/ssautil"
1918
)
2019

2120
// loadProgram creates loader.Program out of p.
@@ -37,8 +36,8 @@ func loadProgram(p string) (*loader.Program, error) {
3736
}
3837

3938
// buildPackage builds and returns ssa representation of package pkg of lprog.
40-
func buildPackage(lprog *loader.Program, pkg string, mode BuilderMode) *Package {
41-
prog := NewProgram(lprog.Fset, mode)
39+
func buildPackage(lprog *loader.Program, pkg string, mode ssa.BuilderMode) *ssa.Package {
40+
prog := ssa.NewProgram(lprog.Fset, mode)
4241

4342
for _, info := range lprog.AllPackages {
4443
prog.CreatePackage(info.Pkg, info.Files, &info.Info, info.Importable)
@@ -49,8 +48,7 @@ func buildPackage(lprog *loader.Program, pkg string, mode BuilderMode) *Package
4948
return p
5049
}
5150

52-
// TestNeedsInstance ensures that new method instances can be created via needsInstance,
53-
// that TypeArgs are as expected, and can be accessed via _Instances.
51+
// TestNeedsInstance ensures that new method instances can be created via MethodValue.
5452
func TestNeedsInstance(t *testing.T) {
5553
const input = `
5654
package p
@@ -79,7 +77,10 @@ func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
7977
t.Fatal(err)
8078
}
8179

82-
for _, mode := range []BuilderMode{BuilderMode(0), InstantiateGenerics} {
80+
for _, mode := range []ssa.BuilderMode{
81+
ssa.SanityCheckFunctions,
82+
ssa.SanityCheckFunctions | ssa.InstantiateGenerics,
83+
} {
8384
// Create and build SSA
8485
p := buildPackage(lprog, "p", mode)
8586
prog := p.Prog
@@ -96,48 +97,39 @@ func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
9697

9798
meth := prog.FuncValue(obj)
9899

99-
b := &builder{}
100-
intSliceTyp := types.NewSlice(types.Typ[types.Int])
101-
instance := meth.instance([]types.Type{intSliceTyp}, b)
102-
if len(b.fns) != 1 {
103-
t.Errorf("Expected first instance to create a function. got %d created functions", len(b.fns))
100+
// instantiateLoadMethod returns the first method (Load) of the instantiation *Pointer[T].
101+
instantiateLoadMethod := func(T types.Type) *ssa.Function {
102+
ptrT, err := types.Instantiate(nil, ptr, []types.Type{T}, false)
103+
if err != nil {
104+
t.Fatalf("Failed to Instantiate %q by %q", ptr, T)
105+
}
106+
methods := types.NewMethodSet(types.NewPointer(ptrT))
107+
if methods.Len() != 1 {
108+
t.Fatalf("Expected 1 method for %q. got %d", ptrT, methods.Len())
109+
}
110+
return prog.MethodValue(methods.At(0))
104111
}
112+
113+
intSliceTyp := types.NewSlice(types.Typ[types.Int])
114+
instance := instantiateLoadMethod(intSliceTyp) // (*Pointer[[]int]).Load
105115
if instance.Origin() != meth {
106116
t.Errorf("Expected Origin of %s to be %s. got %s", instance, meth, instance.Origin())
107117
}
108118
if len(instance.TypeArgs()) != 1 || !types.Identical(instance.TypeArgs()[0], intSliceTyp) {
109-
t.Errorf("Expected TypeArgs of %s to be %v. got %v", instance, []types.Type{intSliceTyp}, instance.typeargs)
110-
}
111-
instances := allInstances(meth)
112-
if want := []*Function{instance}; !reflect.DeepEqual(instances, want) {
113-
t.Errorf("Expected instances of %s to be %v. got %v", meth, want, instances)
119+
t.Errorf("Expected TypeArgs of %s to be %v. got %v", instance, []types.Type{intSliceTyp}, instance.TypeArgs())
114120
}
115121

116122
// A second request with an identical type returns the same Function.
117-
second := meth.instance([]types.Type{types.NewSlice(types.Typ[types.Int])}, b)
118-
if second != instance || len(b.fns) != 1 {
119-
t.Error("Expected second identical instantiation to not create a function")
120-
}
121-
122-
// Add a second instance.
123-
inst2 := meth.instance([]types.Type{types.NewSlice(types.Typ[types.Uint])}, b)
124-
instances = allInstances(meth)
125-
126-
// Note: instance.Name() < inst2.Name()
127-
sort.Slice(instances, func(i, j int) bool {
128-
return instances[i].Name() < instances[j].Name()
129-
})
130-
if want := []*Function{instance, inst2}; !reflect.DeepEqual(instances, want) {
131-
t.Errorf("Expected instances of %s to be %v. got %v", meth, want, instances)
123+
second := instantiateLoadMethod(types.NewSlice(types.Typ[types.Int]))
124+
if second != instance {
125+
t.Error("Expected second identical instantiation to be the same function")
132126
}
133127

134-
// TODO(adonovan): tests should not rely on unexported functions.
128+
// (*Pointer[[]uint]).Load
129+
inst2 := instantiateLoadMethod(types.NewSlice(types.Typ[types.Uint]))
135130

136-
// build and sanity check manually created instance.
137-
b.buildFunction(instance)
138-
var buf bytes.Buffer
139-
if !sanityCheck(instance, &buf) {
140-
t.Errorf("sanityCheck of %s failed with: %s", instance, buf.String())
131+
if instance.Name() >= inst2.Name() {
132+
t.Errorf("Expected name of instance %s to be before instance %v", instance, inst2)
141133
}
142134
}
143135
}
@@ -198,8 +190,8 @@ func entry(i int, a A) int {
198190
t.Fatal(err)
199191
}
200192

201-
p := buildPackage(lprog, "p", SanityCheckFunctions)
202-
prog := p.Prog
193+
p := buildPackage(lprog, "p", ssa.SanityCheckFunctions)
194+
all := ssautil.AllFunctions(p.Prog)
203195

204196
for _, ti := range []struct {
205197
orig string
@@ -215,12 +207,18 @@ func entry(i int, a A) int {
215207
} {
216208
test := ti
217209
t.Run(test.instance, func(t *testing.T) {
218-
f := p.Members[test.orig].(*Function)
210+
f := p.Members[test.orig].(*ssa.Function)
219211
if f == nil {
220212
t.Fatalf("origin function not found")
221213
}
222214

223-
i := instanceOf(f, test.instance, prog)
215+
var i *ssa.Function
216+
for _, fn := range instancesOf(all, f) {
217+
if fn.Name() == test.instance {
218+
i = fn
219+
break
220+
}
221+
}
224222
if i == nil {
225223
t.Fatalf("instance not found")
226224
}
@@ -249,16 +247,7 @@ func entry(i int, a A) int {
249247
}
250248
}
251249

252-
func instanceOf(f *Function, name string, prog *Program) *Function {
253-
for _, i := range allInstances(f) {
254-
if i.Name() == name {
255-
return i
256-
}
257-
}
258-
return nil
259-
}
260-
261-
func tparams(f *Function) string {
250+
func tparams(f *ssa.Function) string {
262251
tplist := f.TypeParams()
263252
var tps []string
264253
for i := 0; i < tplist.Len(); i++ {
@@ -267,18 +256,18 @@ func tparams(f *Function) string {
267256
return fmt.Sprint(tps)
268257
}
269258

270-
func targs(f *Function) string {
259+
func targs(f *ssa.Function) string {
271260
var tas []string
272261
for _, ta := range f.TypeArgs() {
273262
tas = append(tas, ta.String())
274263
}
275264
return fmt.Sprint(tas)
276265
}
277266

278-
func changeTypeInstrs(b *BasicBlock) int {
267+
func changeTypeInstrs(b *ssa.BasicBlock) int {
279268
cnt := 0
280269
for _, i := range b.Instrs {
281-
if _, ok := i.(*ChangeType); ok {
270+
if _, ok := i.(*ssa.ChangeType); ok {
282271
cnt++
283272
}
284273
}
@@ -314,8 +303,9 @@ func Foo[T any, S any](t T, s S) {
314303
t.Fatal(err)
315304
}
316305

317-
p := buildPackage(lprog, "p", SanityCheckFunctions)
306+
p := buildPackage(lprog, "p", ssa.SanityCheckFunctions)
318307

308+
all := ssautil.AllFunctions(p.Prog)
319309
for _, test := range []struct {
320310
orig string
321311
instances string
@@ -324,12 +314,12 @@ func Foo[T any, S any](t T, s S) {
324314
{"Foo", "[p.Foo[S T] p.Foo[T S]]"},
325315
} {
326316
t.Run(test.orig, func(t *testing.T) {
327-
f := p.Members[test.orig].(*Function)
317+
f := p.Members[test.orig].(*ssa.Function)
328318
if f == nil {
329319
t.Fatalf("origin function not found")
330320
}
331321

332-
instances := allInstances(f)
322+
instances := instancesOf(all, f)
333323
sort.Slice(instances, func(i, j int) bool { return instances[i].Name() < instances[j].Name() })
334324

335325
if got := fmt.Sprintf("%v", instances); !reflect.DeepEqual(got, test.instances) {
@@ -339,22 +329,14 @@ func Foo[T any, S any](t T, s S) {
339329
}
340330
}
341331

342-
// allInstances returns a new unordered array of all instances of the
343-
// specified function, if generic, or nil otherwise.
344-
//
345-
// Thread-safe.
346-
//
347-
// TODO(adonovan): delete this. The tests should be intensional (e.g.
348-
// "what instances of f are reachable?") not representational (e.g.
349-
// "what is the history of calls to Function.instance?").
350-
//
351-
// Acquires fn.generic.instancesMu.
352-
func allInstances(fn *Function) []*Function {
353-
if fn.generic == nil {
354-
return nil
332+
// instancesOf returns a new unordered slice of all instances of the
333+
// specified function g in fns.
334+
func instancesOf(fns map[*ssa.Function]bool, g *ssa.Function) []*ssa.Function {
335+
var instances []*ssa.Function
336+
for fn := range fns {
337+
if fn != g && fn.Origin() == g {
338+
instances = append(instances, fn)
339+
}
355340
}
356-
357-
fn.generic.instancesMu.Lock()
358-
defer fn.generic.instancesMu.Unlock()
359-
return mapValues(fn.generic.instances)
341+
return instances
360342
}

0 commit comments

Comments
 (0)