github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/ssa/builder_test.go (about)

     1  // Copyright 2013 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  package ssa_test
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"go/ast"
    11  	"go/build"
    12  	"go/importer"
    13  	"go/parser"
    14  	"go/token"
    15  	"go/types"
    16  	"os"
    17  	"path/filepath"
    18  	"reflect"
    19  	"sort"
    20  	"strings"
    21  	"testing"
    22  
    23  	"golang.org/x/tools/go/buildutil"
    24  	"golang.org/x/tools/go/loader"
    25  	"golang.org/x/tools/go/ssa"
    26  	"golang.org/x/tools/go/ssa/ssautil"
    27  	"golang.org/x/tools/internal/testenv"
    28  	"golang.org/x/tools/internal/typeparams"
    29  )
    30  
    31  func isEmpty(f *ssa.Function) bool { return f.Blocks == nil }
    32  
    33  // Tests that programs partially loaded from gc object files contain
    34  // functions with no code for the external portions, but are otherwise ok.
    35  func TestBuildPackage(t *testing.T) {
    36  	testenv.NeedsGoBuild(t) // for importer.Default()
    37  
    38  	input := `
    39  package main
    40  
    41  import (
    42  	"bytes"
    43  	"io"
    44  	"testing"
    45  )
    46  
    47  func main() {
    48          var t testing.T
    49  	    t.Parallel()    // static call to external declared method
    50          t.Fail()        // static call to promoted external declared method
    51          testing.Short() // static call to external package-level function
    52  
    53          var w io.Writer = new(bytes.Buffer)
    54          w.Write(nil)    // interface invoke of external declared method
    55  }
    56  `
    57  
    58  	// Parse the file.
    59  	fset := token.NewFileSet()
    60  	f, err := parser.ParseFile(fset, "input.go", input, 0)
    61  	if err != nil {
    62  		t.Error(err)
    63  		return
    64  	}
    65  
    66  	// Build an SSA program from the parsed file.
    67  	// Load its dependencies from gc binary export data.
    68  	mode := ssa.SanityCheckFunctions
    69  	mainPkg, _, err := ssautil.BuildPackage(&types.Config{Importer: importer.Default()}, fset,
    70  		types.NewPackage("main", ""), []*ast.File{f}, mode)
    71  	if err != nil {
    72  		t.Error(err)
    73  		return
    74  	}
    75  
    76  	// The main package, its direct and indirect dependencies are loaded.
    77  	deps := []string{
    78  		// directly imported dependencies:
    79  		"bytes", "io", "testing",
    80  		// indirect dependencies mentioned by
    81  		// the direct imports' export data
    82  		"sync", "unicode", "time",
    83  	}
    84  
    85  	prog := mainPkg.Prog
    86  	all := prog.AllPackages()
    87  	if len(all) <= len(deps) {
    88  		t.Errorf("unexpected set of loaded packages: %q", all)
    89  	}
    90  	for _, path := range deps {
    91  		pkg := prog.ImportedPackage(path)
    92  		if pkg == nil {
    93  			t.Errorf("package not loaded: %q", path)
    94  			continue
    95  		}
    96  
    97  		// External packages should have no function bodies (except for wrappers).
    98  		isExt := pkg != mainPkg
    99  
   100  		// init()
   101  		if isExt && !isEmpty(pkg.Func("init")) {
   102  			t.Errorf("external package %s has non-empty init", pkg)
   103  		} else if !isExt && isEmpty(pkg.Func("init")) {
   104  			t.Errorf("main package %s has empty init", pkg)
   105  		}
   106  
   107  		for _, mem := range pkg.Members {
   108  			switch mem := mem.(type) {
   109  			case *ssa.Function:
   110  				// Functions at package level.
   111  				if isExt && !isEmpty(mem) {
   112  					t.Errorf("external function %s is non-empty", mem)
   113  				} else if !isExt && isEmpty(mem) {
   114  					t.Errorf("function %s is empty", mem)
   115  				}
   116  
   117  			case *ssa.Type:
   118  				// Methods of named types T.
   119  				// (In this test, all exported methods belong to *T not T.)
   120  				if !isExt {
   121  					t.Fatalf("unexpected name type in main package: %s", mem)
   122  				}
   123  				mset := prog.MethodSets.MethodSet(types.NewPointer(mem.Type()))
   124  				for i, n := 0, mset.Len(); i < n; i++ {
   125  					m := prog.MethodValue(mset.At(i))
   126  					// For external types, only synthetic wrappers have code.
   127  					expExt := !strings.Contains(m.Synthetic, "wrapper")
   128  					if expExt && !isEmpty(m) {
   129  						t.Errorf("external method %s is non-empty: %s",
   130  							m, m.Synthetic)
   131  					} else if !expExt && isEmpty(m) {
   132  						t.Errorf("method function %s is empty: %s",
   133  							m, m.Synthetic)
   134  					}
   135  				}
   136  			}
   137  		}
   138  	}
   139  
   140  	expectedCallee := []string{
   141  		"(*testing.T).Parallel",
   142  		"(*testing.common).Fail",
   143  		"testing.Short",
   144  		"N/A",
   145  	}
   146  	callNum := 0
   147  	for _, b := range mainPkg.Func("main").Blocks {
   148  		for _, instr := range b.Instrs {
   149  			switch instr := instr.(type) {
   150  			case ssa.CallInstruction:
   151  				call := instr.Common()
   152  				if want := expectedCallee[callNum]; want != "N/A" {
   153  					got := call.StaticCallee().String()
   154  					if want != got {
   155  						t.Errorf("call #%d from main.main: got callee %s, want %s",
   156  							callNum, got, want)
   157  					}
   158  				}
   159  				callNum++
   160  			}
   161  		}
   162  	}
   163  	if callNum != 4 {
   164  		t.Errorf("in main.main: got %d calls, want %d", callNum, 4)
   165  	}
   166  }
   167  
   168  // TestRuntimeTypes tests that (*Program).RuntimeTypes() includes all necessary types.
   169  func TestRuntimeTypes(t *testing.T) {
   170  	testenv.NeedsGoBuild(t) // for importer.Default()
   171  
   172  	tests := []struct {
   173  		input string
   174  		want  []string
   175  	}{
   176  		// An exported package-level type is needed.
   177  		{`package A; type T struct{}; func (T) f() {}`,
   178  			[]string{"*p.T", "p.T"},
   179  		},
   180  		// An unexported package-level type is not needed.
   181  		{`package B; type t struct{}; func (t) f() {}`,
   182  			nil,
   183  		},
   184  		// Subcomponents of type of exported package-level var are needed.
   185  		{`package C; import "bytes"; var V struct {*bytes.Buffer}`,
   186  			[]string{"*bytes.Buffer", "*struct{*bytes.Buffer}", "struct{*bytes.Buffer}"},
   187  		},
   188  		// Subcomponents of type of unexported package-level var are not needed.
   189  		{`package D; import "bytes"; var v struct {*bytes.Buffer}`,
   190  			nil,
   191  		},
   192  		// Subcomponents of type of exported package-level function are needed.
   193  		{`package E; import "bytes"; func F(struct {*bytes.Buffer}) {}`,
   194  			[]string{"*bytes.Buffer", "struct{*bytes.Buffer}"},
   195  		},
   196  		// Subcomponents of type of unexported package-level function are not needed.
   197  		{`package F; import "bytes"; func f(struct {*bytes.Buffer}) {}`,
   198  			nil,
   199  		},
   200  		// Subcomponents of type of exported method of uninstantiated unexported type are not needed.
   201  		{`package G; import "bytes"; type x struct{}; func (x) G(struct {*bytes.Buffer}) {}; var v x`,
   202  			nil,
   203  		},
   204  		// ...unless used by MakeInterface.
   205  		{`package G2; import "bytes"; type x struct{}; func (x) G(struct {*bytes.Buffer}) {}; var v interface{} = x{}`,
   206  			[]string{"*bytes.Buffer", "*p.x", "p.x", "struct{*bytes.Buffer}"},
   207  		},
   208  		// Subcomponents of type of unexported method are not needed.
   209  		{`package I; import "bytes"; type X struct{}; func (X) G(struct {*bytes.Buffer}) {}`,
   210  			[]string{"*bytes.Buffer", "*p.X", "p.X", "struct{*bytes.Buffer}"},
   211  		},
   212  		// Local types aren't needed.
   213  		{`package J; import "bytes"; func f() { type T struct {*bytes.Buffer}; var t T; _ = t }`,
   214  			nil,
   215  		},
   216  		// ...unless used by MakeInterface.
   217  		{`package K; import "bytes"; func f() { type T struct {*bytes.Buffer}; _ = interface{}(T{}) }`,
   218  			[]string{"*bytes.Buffer", "*p.T", "p.T"},
   219  		},
   220  		// Types used as operand of MakeInterface are needed.
   221  		{`package L; import "bytes"; func f() { _ = interface{}(struct{*bytes.Buffer}{}) }`,
   222  			[]string{"*bytes.Buffer", "struct{*bytes.Buffer}"},
   223  		},
   224  		// MakeInterface is optimized away when storing to a blank.
   225  		{`package M; import "bytes"; var _ interface{} = struct{*bytes.Buffer}{}`,
   226  			nil,
   227  		},
   228  	}
   229  
   230  	if typeparams.Enabled {
   231  		tests = append(tests, []struct {
   232  			input string
   233  			want  []string
   234  		}{
   235  			// MakeInterface does not create runtime type for parameterized types.
   236  			{`package N; var g interface{}; func f[S any]() { var v []S; g = v }; `,
   237  				nil,
   238  			},
   239  		}...)
   240  	}
   241  	for _, test := range tests {
   242  		// Parse the file.
   243  		fset := token.NewFileSet()
   244  		f, err := parser.ParseFile(fset, "input.go", test.input, 0)
   245  		if err != nil {
   246  			t.Errorf("test %q: %s", test.input[:15], err)
   247  			continue
   248  		}
   249  
   250  		// Create a single-file main package.
   251  		// Load dependencies from gc binary export data.
   252  		mode := ssa.SanityCheckFunctions
   253  		ssapkg, _, err := ssautil.BuildPackage(&types.Config{Importer: importer.Default()}, fset,
   254  			types.NewPackage("p", ""), []*ast.File{f}, mode)
   255  		if err != nil {
   256  			t.Errorf("test %q: %s", test.input[:15], err)
   257  			continue
   258  		}
   259  
   260  		var typstrs []string
   261  		for _, T := range ssapkg.Prog.RuntimeTypes() {
   262  			typstrs = append(typstrs, T.String())
   263  		}
   264  		sort.Strings(typstrs)
   265  
   266  		if !reflect.DeepEqual(typstrs, test.want) {
   267  			t.Errorf("test 'package %s': got %q, want %q",
   268  				f.Name.Name, typstrs, test.want)
   269  		}
   270  	}
   271  }
   272  
   273  // TestInit tests that synthesized init functions are correctly formed.
   274  // Bare init functions omit calls to dependent init functions and the use of
   275  // an init guard. They are useful in cases where the client uses a different
   276  // calling convention for init functions, or cases where it is easier for a
   277  // client to analyze bare init functions. Both of these aspects are used by
   278  // the llgo compiler for simpler integration with gccgo's runtime library,
   279  // and to simplify the analysis whereby it deduces which stores to globals
   280  // can be lowered to global initializers.
   281  func TestInit(t *testing.T) {
   282  	tests := []struct {
   283  		mode        ssa.BuilderMode
   284  		input, want string
   285  	}{
   286  		{0, `package A; import _ "errors"; var i int = 42`,
   287  			`# Name: A.init
   288  # Package: A
   289  # Synthetic: package initializer
   290  func init():
   291  0:                                                                entry P:0 S:2
   292  	t0 = *init$guard                                                   bool
   293  	if t0 goto 2 else 1
   294  1:                                                           init.start P:1 S:1
   295  	*init$guard = true:bool
   296  	t1 = errors.init()                                                   ()
   297  	*i = 42:int
   298  	jump 2
   299  2:                                                            init.done P:2 S:0
   300  	return
   301  
   302  `},
   303  		{ssa.BareInits, `package B; import _ "errors"; var i int = 42`,
   304  			`# Name: B.init
   305  # Package: B
   306  # Synthetic: package initializer
   307  func init():
   308  0:                                                                entry P:0 S:0
   309  	*i = 42:int
   310  	return
   311  
   312  `},
   313  	}
   314  	for _, test := range tests {
   315  		// Create a single-file main package.
   316  		var conf loader.Config
   317  		f, err := conf.ParseFile("<input>", test.input)
   318  		if err != nil {
   319  			t.Errorf("test %q: %s", test.input[:15], err)
   320  			continue
   321  		}
   322  		conf.CreateFromFiles(f.Name.Name, f)
   323  
   324  		lprog, err := conf.Load()
   325  		if err != nil {
   326  			t.Errorf("test 'package %s': Load: %s", f.Name.Name, err)
   327  			continue
   328  		}
   329  		prog := ssautil.CreateProgram(lprog, test.mode)
   330  		mainPkg := prog.Package(lprog.Created[0].Pkg)
   331  		prog.Build()
   332  		initFunc := mainPkg.Func("init")
   333  		if initFunc == nil {
   334  			t.Errorf("test 'package %s': no init function", f.Name.Name)
   335  			continue
   336  		}
   337  
   338  		var initbuf bytes.Buffer
   339  		_, err = initFunc.WriteTo(&initbuf)
   340  		if err != nil {
   341  			t.Errorf("test 'package %s': WriteTo: %s", f.Name.Name, err)
   342  			continue
   343  		}
   344  
   345  		if initbuf.String() != test.want {
   346  			t.Errorf("test 'package %s': got %s, want %s", f.Name.Name, initbuf.String(), test.want)
   347  		}
   348  	}
   349  }
   350  
   351  // TestSyntheticFuncs checks that the expected synthetic functions are
   352  // created, reachable, and not duplicated.
   353  func TestSyntheticFuncs(t *testing.T) {
   354  	const input = `package P
   355  type T int
   356  func (T) f() int
   357  func (*T) g() int
   358  var (
   359  	// thunks
   360  	a = T.f
   361  	b = T.f
   362  	c = (struct{T}).f
   363  	d = (struct{T}).f
   364  	e = (*T).g
   365  	f = (*T).g
   366  	g = (struct{*T}).g
   367  	h = (struct{*T}).g
   368  
   369  	// bounds
   370  	i = T(0).f
   371  	j = T(0).f
   372  	k = new(T).g
   373  	l = new(T).g
   374  
   375  	// wrappers
   376  	m interface{} = struct{T}{}
   377  	n interface{} = struct{T}{}
   378  	o interface{} = struct{*T}{}
   379  	p interface{} = struct{*T}{}
   380  	q interface{} = new(struct{T})
   381  	r interface{} = new(struct{T})
   382  	s interface{} = new(struct{*T})
   383  	t interface{} = new(struct{*T})
   384  )
   385  `
   386  	// Parse
   387  	var conf loader.Config
   388  	f, err := conf.ParseFile("<input>", input)
   389  	if err != nil {
   390  		t.Fatalf("parse: %v", err)
   391  	}
   392  	conf.CreateFromFiles(f.Name.Name, f)
   393  
   394  	// Load
   395  	lprog, err := conf.Load()
   396  	if err != nil {
   397  		t.Fatalf("Load: %v", err)
   398  	}
   399  
   400  	// Create and build SSA
   401  	prog := ssautil.CreateProgram(lprog, ssa.BuilderMode(0))
   402  	prog.Build()
   403  
   404  	// Enumerate reachable synthetic functions
   405  	want := map[string]string{
   406  		"(*P.T).g$bound": "bound method wrapper for func (*P.T).g() int",
   407  		"(P.T).f$bound":  "bound method wrapper for func (P.T).f() int",
   408  
   409  		"(*P.T).g$thunk":         "thunk for func (*P.T).g() int",
   410  		"(P.T).f$thunk":          "thunk for func (P.T).f() int",
   411  		"(struct{*P.T}).g$thunk": "thunk for func (*P.T).g() int",
   412  		"(struct{P.T}).f$thunk":  "thunk for func (P.T).f() int",
   413  
   414  		"(*P.T).f":          "wrapper for func (P.T).f() int",
   415  		"(*struct{*P.T}).f": "wrapper for func (P.T).f() int",
   416  		"(*struct{*P.T}).g": "wrapper for func (*P.T).g() int",
   417  		"(*struct{P.T}).f":  "wrapper for func (P.T).f() int",
   418  		"(*struct{P.T}).g":  "wrapper for func (*P.T).g() int",
   419  		"(struct{*P.T}).f":  "wrapper for func (P.T).f() int",
   420  		"(struct{*P.T}).g":  "wrapper for func (*P.T).g() int",
   421  		"(struct{P.T}).f":   "wrapper for func (P.T).f() int",
   422  
   423  		"P.init": "package initializer",
   424  	}
   425  	for fn := range ssautil.AllFunctions(prog) {
   426  		if fn.Synthetic == "" {
   427  			continue
   428  		}
   429  		name := fn.String()
   430  		wantDescr, ok := want[name]
   431  		if !ok {
   432  			t.Errorf("got unexpected/duplicate func: %q: %q", name, fn.Synthetic)
   433  			continue
   434  		}
   435  		delete(want, name)
   436  
   437  		if wantDescr != fn.Synthetic {
   438  			t.Errorf("(%s).Synthetic = %q, want %q", name, fn.Synthetic, wantDescr)
   439  		}
   440  	}
   441  	for fn, descr := range want {
   442  		t.Errorf("want func: %q: %q", fn, descr)
   443  	}
   444  }
   445  
   446  // TestPhiElimination ensures that dead phis, including those that
   447  // participate in a cycle, are properly eliminated.
   448  func TestPhiElimination(t *testing.T) {
   449  	const input = `
   450  package p
   451  
   452  func f() error
   453  
   454  func g(slice []int) {
   455  	for {
   456  		for range slice {
   457  			// e should not be lifted to a dead φ-node.
   458  			e := f()
   459  			h(e)
   460  		}
   461  	}
   462  }
   463  
   464  func h(error)
   465  `
   466  	// The SSA code for this function should look something like this:
   467  	// 0:
   468  	//         jump 1
   469  	// 1:
   470  	//         t0 = len(slice)
   471  	//         jump 2
   472  	// 2:
   473  	//         t1 = phi [1: -1:int, 3: t2]
   474  	//         t2 = t1 + 1:int
   475  	//         t3 = t2 < t0
   476  	//         if t3 goto 3 else 1
   477  	// 3:
   478  	//         t4 = f()
   479  	//         t5 = h(t4)
   480  	//         jump 2
   481  	//
   482  	// But earlier versions of the SSA construction algorithm would
   483  	// additionally generate this cycle of dead phis:
   484  	//
   485  	// 1:
   486  	//         t7 = phi [0: nil:error, 2: t8] #e
   487  	//         ...
   488  	// 2:
   489  	//         t8 = phi [1: t7, 3: t4] #e
   490  	//         ...
   491  
   492  	// Parse
   493  	var conf loader.Config
   494  	f, err := conf.ParseFile("<input>", input)
   495  	if err != nil {
   496  		t.Fatalf("parse: %v", err)
   497  	}
   498  	conf.CreateFromFiles("p", f)
   499  
   500  	// Load
   501  	lprog, err := conf.Load()
   502  	if err != nil {
   503  		t.Fatalf("Load: %v", err)
   504  	}
   505  
   506  	// Create and build SSA
   507  	prog := ssautil.CreateProgram(lprog, ssa.BuilderMode(0))
   508  	p := prog.Package(lprog.Package("p").Pkg)
   509  	p.Build()
   510  	g := p.Func("g")
   511  
   512  	phis := 0
   513  	for _, b := range g.Blocks {
   514  		for _, instr := range b.Instrs {
   515  			if _, ok := instr.(*ssa.Phi); ok {
   516  				phis++
   517  			}
   518  		}
   519  	}
   520  	if phis != 1 {
   521  		g.WriteTo(os.Stderr)
   522  		t.Errorf("expected a single Phi (for the range index), got %d", phis)
   523  	}
   524  }
   525  
   526  // TestGenericDecls ensures that *unused* generic types, methods and functions
   527  // signatures can be built.
   528  //
   529  // TODO(taking): Add calls from non-generic functions to instantiations of generic functions.
   530  // TODO(taking): Add globals with types that are instantiations of generic functions.
   531  func TestGenericDecls(t *testing.T) {
   532  	if !typeparams.Enabled {
   533  		t.Skip("TestGenericDecls only works with type parameters enabled.")
   534  	}
   535  	const input = `
   536  package p
   537  
   538  import "unsafe"
   539  
   540  type Pointer[T any] struct {
   541  	v unsafe.Pointer
   542  }
   543  
   544  func (x *Pointer[T]) Load() *T {
   545  	return (*T)(LoadPointer(&x.v))
   546  }
   547  
   548  func Load[T any](x *Pointer[T]) *T {
   549  	return x.Load()
   550  }
   551  
   552  func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
   553  `
   554  	// The SSA members for this package should look something like this:
   555  	//          func  LoadPointer func(addr *unsafe.Pointer) (val unsafe.Pointer)
   556  	//      type  Pointer     struct{v unsafe.Pointer}
   557  	//        method (*Pointer[T any]) Load() *T
   558  	//      func  init        func()
   559  	//      var   init$guard  bool
   560  
   561  	// Parse
   562  	var conf loader.Config
   563  	f, err := conf.ParseFile("<input>", input)
   564  	if err != nil {
   565  		t.Fatalf("parse: %v", err)
   566  	}
   567  	conf.CreateFromFiles("p", f)
   568  
   569  	// Load
   570  	lprog, err := conf.Load()
   571  	if err != nil {
   572  		t.Fatalf("Load: %v", err)
   573  	}
   574  
   575  	// Create and build SSA
   576  	prog := ssautil.CreateProgram(lprog, ssa.BuilderMode(0))
   577  	p := prog.Package(lprog.Package("p").Pkg)
   578  	p.Build()
   579  
   580  	if load := p.Func("Load"); typeparams.ForSignature(load.Signature).Len() != 1 {
   581  		t.Errorf("expected a single type param T for Load got %q", load.Signature)
   582  	}
   583  	if ptr := p.Type("Pointer"); typeparams.ForNamed(ptr.Type().(*types.Named)).Len() != 1 {
   584  		t.Errorf("expected a single type param T for Pointer got %q", ptr.Type())
   585  	}
   586  }
   587  
   588  func TestGenericWrappers(t *testing.T) {
   589  	if !typeparams.Enabled {
   590  		t.Skip("TestGenericWrappers only works with type parameters enabled.")
   591  	}
   592  	const input = `
   593  package p
   594  
   595  type S[T any] struct {
   596  	t *T
   597  }
   598  
   599  func (x S[T]) M() T {
   600  	return *(x.t)
   601  }
   602  
   603  var thunk = S[int].M
   604  
   605  var g S[int]
   606  var bound = g.M
   607  
   608  type R[T any] struct{ S[T] }
   609  
   610  var indirect = R[int].M
   611  `
   612  	// The relevant SSA members for this package should look something like this:
   613  	// var   bound      func() int
   614  	// var   thunk      func(S[int]) int
   615  	// var   wrapper    func(R[int]) int
   616  
   617  	// Parse
   618  	var conf loader.Config
   619  	f, err := conf.ParseFile("<input>", input)
   620  	if err != nil {
   621  		t.Fatalf("parse: %v", err)
   622  	}
   623  	conf.CreateFromFiles("p", f)
   624  
   625  	// Load
   626  	lprog, err := conf.Load()
   627  	if err != nil {
   628  		t.Fatalf("Load: %v", err)
   629  	}
   630  
   631  	for _, mode := range []ssa.BuilderMode{ssa.BuilderMode(0), ssa.InstantiateGenerics} {
   632  		// Create and build SSA
   633  		prog := ssautil.CreateProgram(lprog, mode)
   634  		p := prog.Package(lprog.Package("p").Pkg)
   635  		p.Build()
   636  
   637  		for _, entry := range []struct {
   638  			name    string // name of the package variable
   639  			typ     string // type of the package variable
   640  			wrapper string // wrapper function to which the package variable is set
   641  			callee  string // callee within the wrapper function
   642  		}{
   643  			{
   644  				"bound",
   645  				"*func() int",
   646  				"(p.S[int]).M$bound",
   647  				"(p.S[int]).M[int]",
   648  			},
   649  			{
   650  				"thunk",
   651  				"*func(p.S[int]) int",
   652  				"(p.S[int]).M$thunk",
   653  				"(p.S[int]).M[int]",
   654  			},
   655  			{
   656  				"indirect",
   657  				"*func(p.R[int]) int",
   658  				"(p.R[int]).M$thunk",
   659  				"(p.S[int]).M[int]",
   660  			},
   661  		} {
   662  			entry := entry
   663  			t.Run(entry.name, func(t *testing.T) {
   664  				v := p.Var(entry.name)
   665  				if v == nil {
   666  					t.Fatalf("Did not find variable for %q in %s", entry.name, p.String())
   667  				}
   668  				if v.Type().String() != entry.typ {
   669  					t.Errorf("Expected type for variable %s: %q. got %q", v, entry.typ, v.Type())
   670  				}
   671  
   672  				// Find the wrapper for v. This is stored exactly once in init.
   673  				var wrapper *ssa.Function
   674  				for _, bb := range p.Func("init").Blocks {
   675  					for _, i := range bb.Instrs {
   676  						if store, ok := i.(*ssa.Store); ok && v == store.Addr {
   677  							switch val := store.Val.(type) {
   678  							case *ssa.Function:
   679  								wrapper = val
   680  							case *ssa.MakeClosure:
   681  								wrapper = val.Fn.(*ssa.Function)
   682  							}
   683  						}
   684  					}
   685  				}
   686  				if wrapper == nil {
   687  					t.Fatalf("failed to find wrapper function for %s", entry.name)
   688  				}
   689  				if wrapper.String() != entry.wrapper {
   690  					t.Errorf("Expected wrapper function %q. got %q", wrapper, entry.wrapper)
   691  				}
   692  
   693  				// Find the callee within the wrapper. There should be exactly one call.
   694  				var callee *ssa.Function
   695  				for _, bb := range wrapper.Blocks {
   696  					for _, i := range bb.Instrs {
   697  						if call, ok := i.(*ssa.Call); ok {
   698  							callee = call.Call.StaticCallee()
   699  						}
   700  					}
   701  				}
   702  				if callee == nil {
   703  					t.Fatalf("failed to find callee within wrapper %s", wrapper)
   704  				}
   705  				if callee.String() != entry.callee {
   706  					t.Errorf("Expected callee in wrapper %q is %q. got %q", v, entry.callee, callee)
   707  				}
   708  			})
   709  		}
   710  	}
   711  }
   712  
   713  // TestTypeparamTest builds SSA over compilable examples in $GOROOT/test/typeparam/*.go.
   714  
   715  func TestTypeparamTest(t *testing.T) {
   716  	if !typeparams.Enabled {
   717  		return
   718  	}
   719  
   720  	// Tests use a fake goroot to stub out standard libraries with delcarations in
   721  	// testdata/src. Decreases runtime from ~80s to ~1s.
   722  
   723  	dir := filepath.Join(build.Default.GOROOT, "test", "typeparam")
   724  
   725  	// Collect all of the .go files in
   726  	list, err := os.ReadDir(dir)
   727  	if err != nil {
   728  		t.Fatal(err)
   729  	}
   730  
   731  	for _, entry := range list {
   732  		if entry.Name() == "issue58513.go" {
   733  			continue // uses runtime.Caller; unimplemented by go/ssa/interp
   734  		}
   735  		if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
   736  			continue // Consider standalone go files.
   737  		}
   738  		input := filepath.Join(dir, entry.Name())
   739  		t.Run(entry.Name(), func(t *testing.T) {
   740  			src, err := os.ReadFile(input)
   741  			if err != nil {
   742  				t.Fatal(err)
   743  			}
   744  			// Only build test files that can be compiled, or compiled and run.
   745  			if !bytes.HasPrefix(src, []byte("// run")) && !bytes.HasPrefix(src, []byte("// compile")) {
   746  				t.Skipf("not detected as a run test")
   747  			}
   748  
   749  			t.Logf("Input: %s\n", input)
   750  
   751  			ctx := build.Default    // copy
   752  			ctx.GOROOT = "testdata" // fake goroot. Makes tests ~1s. tests take ~80s.
   753  
   754  			reportErr := func(err error) {
   755  				t.Error(err)
   756  			}
   757  			conf := loader.Config{Build: &ctx, TypeChecker: types.Config{Error: reportErr}}
   758  			if _, err := conf.FromArgs([]string{input}, true); err != nil {
   759  				t.Fatalf("FromArgs(%s) failed: %s", input, err)
   760  			}
   761  
   762  			iprog, err := conf.Load()
   763  			if iprog != nil {
   764  				for _, pkg := range iprog.Created {
   765  					for i, e := range pkg.Errors {
   766  						t.Errorf("Loading pkg %s error[%d]=%s", pkg, i, e)
   767  					}
   768  				}
   769  			}
   770  			if err != nil {
   771  				t.Fatalf("conf.Load(%s) failed: %s", input, err)
   772  			}
   773  
   774  			mode := ssa.SanityCheckFunctions | ssa.InstantiateGenerics
   775  			prog := ssautil.CreateProgram(iprog, mode)
   776  			prog.Build()
   777  		})
   778  	}
   779  }
   780  
   781  // TestOrderOfOperations ensures order of operations are as intended.
   782  func TestOrderOfOperations(t *testing.T) {
   783  	// Testing for the order of operations within an expression is done
   784  	// by collecting the sequence of direct function calls within a *Function.
   785  	// Callees are all external functions so they cannot be safely re-ordered by ssa.
   786  	const input = `
   787  package p
   788  
   789  func a() int
   790  func b() int
   791  func c() int
   792  
   793  func slice(s []int) []int { return s[a():b()] }
   794  func sliceMax(s []int) []int { return s[a():b():c()] }
   795  
   796  `
   797  
   798  	// Parse
   799  	var conf loader.Config
   800  	f, err := conf.ParseFile("<input>", input)
   801  	if err != nil {
   802  		t.Fatalf("parse: %v", err)
   803  	}
   804  	conf.CreateFromFiles("p", f)
   805  
   806  	// Load
   807  	lprog, err := conf.Load()
   808  	if err != nil {
   809  		t.Fatalf("Load: %v", err)
   810  	}
   811  
   812  	// Create and build SSA
   813  	prog := ssautil.CreateProgram(lprog, ssa.BuilderMode(0))
   814  	p := prog.Package(lprog.Package("p").Pkg)
   815  	p.Build()
   816  
   817  	for _, item := range []struct {
   818  		fn   string
   819  		want string // sequence of calls within the function.
   820  	}{
   821  		{"sliceMax", "[a() b() c()]"},
   822  		{"slice", "[a() b()]"},
   823  	} {
   824  		fn := p.Func(item.fn)
   825  		want := item.want
   826  		t.Run(item.fn, func(t *testing.T) {
   827  			t.Parallel()
   828  
   829  			var calls []string
   830  			for _, b := range fn.Blocks {
   831  				for _, instr := range b.Instrs {
   832  					if call, ok := instr.(ssa.CallInstruction); ok {
   833  						calls = append(calls, call.String())
   834  					}
   835  				}
   836  			}
   837  			if got := fmt.Sprint(calls); got != want {
   838  				fn.WriteTo(os.Stderr)
   839  				t.Errorf("Expected sequence of function calls in %s was %s. got %s", fn, want, got)
   840  			}
   841  		})
   842  	}
   843  }
   844  
   845  // TestGenericFunctionSelector ensures generic functions from other packages can be selected.
   846  func TestGenericFunctionSelector(t *testing.T) {
   847  	if !typeparams.Enabled {
   848  		t.Skip("TestGenericFunctionSelector uses type parameters.")
   849  	}
   850  
   851  	pkgs := map[string]map[string]string{
   852  		"main": {"m.go": `package main; import "a"; func main() { a.F[int](); a.G[int,string](); a.H(0) }`},
   853  		"a":    {"a.go": `package a; func F[T any](){}; func G[S, T any](){}; func H[T any](a T){} `},
   854  	}
   855  
   856  	for _, mode := range []ssa.BuilderMode{
   857  		ssa.SanityCheckFunctions,
   858  		ssa.SanityCheckFunctions | ssa.InstantiateGenerics,
   859  	} {
   860  		conf := loader.Config{
   861  			Build: buildutil.FakeContext(pkgs),
   862  		}
   863  		conf.Import("main")
   864  
   865  		lprog, err := conf.Load()
   866  		if err != nil {
   867  			t.Errorf("Load failed: %s", err)
   868  		}
   869  		if lprog == nil {
   870  			t.Fatalf("Load returned nil *Program")
   871  		}
   872  		// Create and build SSA
   873  		prog := ssautil.CreateProgram(lprog, mode)
   874  		p := prog.Package(lprog.Package("main").Pkg)
   875  		p.Build()
   876  
   877  		var callees []string // callees of the CallInstruction.String() in main().
   878  		for _, b := range p.Func("main").Blocks {
   879  			for _, i := range b.Instrs {
   880  				if call, ok := i.(ssa.CallInstruction); ok {
   881  					if callee := call.Common().StaticCallee(); call != nil {
   882  						callees = append(callees, callee.String())
   883  					} else {
   884  						t.Errorf("CallInstruction without StaticCallee() %q", call)
   885  					}
   886  				}
   887  			}
   888  		}
   889  		sort.Strings(callees) // ignore the order in the code.
   890  
   891  		want := "[a.F[int] a.G[int string] a.H[int]]"
   892  		if got := fmt.Sprint(callees); got != want {
   893  			t.Errorf("Expected main() to contain calls %v. got %v", want, got)
   894  		}
   895  	}
   896  }
   897  
   898  func TestIssue58491(t *testing.T) {
   899  	// Test that a local type reaches type param in instantiation.
   900  	testenv.NeedsGo1Point(t, 18)
   901  	src := `
   902  		package p
   903  
   904  		func foo[T any](blocking func() (T, error)) error {
   905  			type result struct {
   906  				res T
   907  				error // ensure the method set of result is non-empty
   908  			}
   909  
   910  			res := make(chan result, 1)
   911  			go func() {
   912  				var r result
   913  				r.res, r.error = blocking()
   914  				res <- r
   915  			}()
   916  			r := <-res
   917  			err := r // require the rtype for result when instantiated
   918  			return err
   919  		}
   920  		var Inst = foo[int]
   921  	`
   922  	fset := token.NewFileSet()
   923  	f, err := parser.ParseFile(fset, "p.go", src, 0)
   924  	if err != nil {
   925  		t.Error(err)
   926  	}
   927  	files := []*ast.File{f}
   928  
   929  	pkg := types.NewPackage("p", "")
   930  	conf := &types.Config{}
   931  	p, _, err := ssautil.BuildPackage(conf, fset, pkg, files, ssa.SanityCheckFunctions|ssa.InstantiateGenerics)
   932  	if err != nil {
   933  		t.Fatalf("unexpected error: %v", err)
   934  	}
   935  
   936  	// Find the local type result instantiated with int.
   937  	var found bool
   938  	for _, rt := range p.Prog.RuntimeTypes() {
   939  		if n, ok := rt.(*types.Named); ok {
   940  			if u, ok := n.Underlying().(*types.Struct); ok {
   941  				found = true
   942  				if got, want := n.String(), "p.result"; got != want {
   943  					t.Errorf("Expected the name %s got: %s", want, got)
   944  				}
   945  				if got, want := u.String(), "struct{res int; error}"; got != want {
   946  					t.Errorf("Expected the underlying type of %s to be %s. got %s", n, want, got)
   947  				}
   948  			}
   949  		}
   950  	}
   951  	if !found {
   952  		t.Error("Failed to find any Named to struct types")
   953  	}
   954  }
   955  
   956  func TestIssue58491Rec(t *testing.T) {
   957  	// Roughly the same as TestIssue58491 but with a recursive type.
   958  	testenv.NeedsGo1Point(t, 18)
   959  	src := `
   960  		package p
   961  
   962  		func foo[T any]() error {
   963  			type result struct {
   964  				res T
   965  				next *result
   966  				error // ensure the method set of result is non-empty
   967  			}
   968  
   969  			r := &result{}
   970  			err := r // require the rtype for result when instantiated
   971  			return err
   972  		}
   973  		var Inst = foo[int]
   974  	`
   975  	fset := token.NewFileSet()
   976  	f, err := parser.ParseFile(fset, "p.go", src, 0)
   977  	if err != nil {
   978  		t.Error(err)
   979  	}
   980  	files := []*ast.File{f}
   981  
   982  	pkg := types.NewPackage("p", "")
   983  	conf := &types.Config{}
   984  	p, _, err := ssautil.BuildPackage(conf, fset, pkg, files, ssa.SanityCheckFunctions|ssa.InstantiateGenerics)
   985  	if err != nil {
   986  		t.Fatalf("unexpected error: %v", err)
   987  	}
   988  
   989  	// Find the local type result instantiated with int.
   990  	var found bool
   991  	for _, rt := range p.Prog.RuntimeTypes() {
   992  		if n, ok := rt.(*types.Named); ok {
   993  			if u, ok := n.Underlying().(*types.Struct); ok {
   994  				found = true
   995  				if got, want := n.String(), "p.result"; got != want {
   996  					t.Errorf("Expected the name %s got: %s", want, got)
   997  				}
   998  				if got, want := u.String(), "struct{res int; next *p.result; error}"; got != want {
   999  					t.Errorf("Expected the underlying type of %s to be %s. got %s", n, want, got)
  1000  				}
  1001  			}
  1002  		}
  1003  	}
  1004  	if !found {
  1005  		t.Error("Failed to find any Named to struct types")
  1006  	}
  1007  }