golang.org/x/tools@v0.21.0/internal/refactor/inline/inline_test.go (about)

     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  package inline_test
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/sha256"
    10  	"encoding/binary"
    11  	"encoding/gob"
    12  	"fmt"
    13  	"go/ast"
    14  	"go/parser"
    15  	"go/token"
    16  	"go/types"
    17  	"os"
    18  	"path/filepath"
    19  	"reflect"
    20  	"regexp"
    21  	"strings"
    22  	"testing"
    23  	"unsafe"
    24  
    25  	"golang.org/x/tools/go/ast/astutil"
    26  	"golang.org/x/tools/go/expect"
    27  	"golang.org/x/tools/go/packages"
    28  	"golang.org/x/tools/go/types/typeutil"
    29  	"golang.org/x/tools/internal/diff"
    30  	"golang.org/x/tools/internal/refactor/inline"
    31  	"golang.org/x/tools/internal/testenv"
    32  	"golang.org/x/tools/txtar"
    33  )
    34  
    35  // TestData executes test scenarios specified by files in testdata/*.txtar.
    36  func TestData(t *testing.T) {
    37  	testenv.NeedsGoPackages(t)
    38  
    39  	files, err := filepath.Glob("testdata/*.txtar")
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  	for _, file := range files {
    44  		file := file
    45  		t.Run(filepath.Base(file), func(t *testing.T) {
    46  			t.Parallel()
    47  
    48  			// The few tests that use cgo should be in
    49  			// files whose name includes "cgo".
    50  			if strings.Contains(t.Name(), "cgo") {
    51  				testenv.NeedsTool(t, "cgo")
    52  			}
    53  
    54  			// Extract archive to temporary tree.
    55  			ar, err := txtar.ParseFile(file)
    56  			if err != nil {
    57  				t.Fatal(err)
    58  			}
    59  			dir := t.TempDir()
    60  			if err := extractTxtar(ar, dir); err != nil {
    61  				t.Fatal(err)
    62  			}
    63  
    64  			// Load packages.
    65  			cfg := &packages.Config{
    66  				Dir:  dir,
    67  				Mode: packages.LoadAllSyntax,
    68  				Env: append(os.Environ(),
    69  					"GO111MODULES=on",
    70  					"GOPATH=",
    71  					"GOWORK=off",
    72  					"GOPROXY=off"),
    73  			}
    74  			pkgs, err := packages.Load(cfg, "./...")
    75  			if err != nil {
    76  				t.Errorf("Load: %v", err)
    77  			}
    78  			// Report parse/type errors; they may be benign.
    79  			packages.Visit(pkgs, nil, func(pkg *packages.Package) {
    80  				for _, err := range pkg.Errors {
    81  					t.Log(err)
    82  				}
    83  			})
    84  
    85  			// Process @inline notes in comments in initial packages.
    86  			for _, pkg := range pkgs {
    87  				for _, file := range pkg.Syntax {
    88  					// Read file content (for @inline regexp, and inliner).
    89  					content, err := os.ReadFile(pkg.Fset.File(file.Pos()).Name())
    90  					if err != nil {
    91  						t.Error(err)
    92  						continue
    93  					}
    94  
    95  					// Read and process @inline notes.
    96  					notes, err := expect.ExtractGo(pkg.Fset, file)
    97  					if err != nil {
    98  						t.Errorf("parsing notes in %q: %v", pkg.Fset.File(file.Pos()).Name(), err)
    99  						continue
   100  					}
   101  					for _, note := range notes {
   102  						posn := pkg.Fset.PositionFor(note.Pos, false)
   103  						if note.Name != "inline" {
   104  							t.Errorf("%s: invalid marker @%s", posn, note.Name)
   105  							continue
   106  						}
   107  						if nargs := len(note.Args); nargs != 2 {
   108  							t.Errorf("@inline: want 2 args, got %d", nargs)
   109  							continue
   110  						}
   111  						pattern, ok := note.Args[0].(*regexp.Regexp)
   112  						if !ok {
   113  							t.Errorf("%s: @inline(rx, want): want regular expression rx", posn)
   114  							continue
   115  						}
   116  
   117  						// want is a []byte (success) or *Regexp (failure)
   118  						var want any
   119  						switch x := note.Args[1].(type) {
   120  						case string, expect.Identifier:
   121  							for _, file := range ar.Files {
   122  								if file.Name == fmt.Sprint(x) {
   123  									want = file.Data
   124  									break
   125  								}
   126  							}
   127  							if want == nil {
   128  								t.Errorf("%s: @inline(rx, want): archive entry %q not found", posn, x)
   129  								continue
   130  							}
   131  						case *regexp.Regexp:
   132  							want = x
   133  						default:
   134  							t.Errorf("%s: @inline(rx, want): want file name (to assert success) or error message regexp (to assert failure)", posn)
   135  							continue
   136  						}
   137  						if err := doInlineNote(t.Logf, pkg, file, content, pattern, posn, want); err != nil {
   138  							t.Errorf("%s: @inline(%v, %v): %v", posn, note.Args[0], note.Args[1], err)
   139  							continue
   140  						}
   141  					}
   142  				}
   143  			}
   144  		})
   145  	}
   146  }
   147  
   148  // doInlineNote executes an assertion specified by a single
   149  // @inline(re"pattern", want) note in a comment. It finds the first
   150  // match of regular expression 'pattern' on the same line, finds the
   151  // innermost enclosing CallExpr, and inlines it.
   152  //
   153  // Finally it checks that, on success, the transformed file is equal
   154  // to want (a []byte), or on failure that the error message matches
   155  // want (a *Regexp).
   156  func doInlineNote(logf func(string, ...any), pkg *packages.Package, file *ast.File, content []byte, pattern *regexp.Regexp, posn token.Position, want any) error {
   157  	// Find extent of pattern match within commented line.
   158  	var startPos, endPos token.Pos
   159  	{
   160  		tokFile := pkg.Fset.File(file.Pos())
   161  		lineStartOffset := int(tokFile.LineStart(posn.Line)) - tokFile.Base()
   162  		line := content[lineStartOffset:]
   163  		if i := bytes.IndexByte(line, '\n'); i >= 0 {
   164  			line = line[:i]
   165  		}
   166  		matches := pattern.FindSubmatchIndex(line)
   167  		var start, end int // offsets
   168  		switch len(matches) {
   169  		case 2:
   170  			// no subgroups: return the range of the regexp expression
   171  			start, end = matches[0], matches[1]
   172  		case 4:
   173  			// one subgroup: return its range
   174  			start, end = matches[2], matches[3]
   175  		default:
   176  			return fmt.Errorf("invalid location regexp %q: expect either 0 or 1 subgroups, got %d",
   177  				pattern, len(matches)/2-1)
   178  		}
   179  		startPos = tokFile.Pos(lineStartOffset + start)
   180  		endPos = tokFile.Pos(lineStartOffset + end)
   181  	}
   182  
   183  	// Find innermost call enclosing the pattern match.
   184  	var caller *inline.Caller
   185  	{
   186  		path, _ := astutil.PathEnclosingInterval(file, startPos, endPos)
   187  		for _, n := range path {
   188  			if call, ok := n.(*ast.CallExpr); ok {
   189  				caller = &inline.Caller{
   190  					Fset:    pkg.Fset,
   191  					Types:   pkg.Types,
   192  					Info:    pkg.TypesInfo,
   193  					File:    file,
   194  					Call:    call,
   195  					Content: content,
   196  				}
   197  				break
   198  			}
   199  		}
   200  		if caller == nil {
   201  			return fmt.Errorf("no enclosing call")
   202  		}
   203  	}
   204  
   205  	// Is it a static function call?
   206  	fn := typeutil.StaticCallee(caller.Info, caller.Call)
   207  	if fn == nil {
   208  		return fmt.Errorf("cannot inline: not a static call")
   209  	}
   210  
   211  	// Find callee function.
   212  	var calleePkg *packages.Package
   213  	{
   214  		// Is the call within the package?
   215  		if fn.Pkg() == caller.Types {
   216  			calleePkg = pkg // same as caller
   217  		} else {
   218  			// Different package. Load it now.
   219  			// (The primary load loaded all dependencies,
   220  			// but we choose to load it again, with
   221  			// a distinct token.FileSet and types.Importer,
   222  			// to keep the implementation honest.)
   223  			cfg := &packages.Config{
   224  				// TODO(adonovan): get the original module root more cleanly
   225  				Dir:  filepath.Dir(filepath.Dir(pkg.GoFiles[0])),
   226  				Fset: token.NewFileSet(),
   227  				Mode: packages.LoadSyntax,
   228  			}
   229  			roots, err := packages.Load(cfg, fn.Pkg().Path())
   230  			if err != nil {
   231  				return fmt.Errorf("loading callee package: %v", err)
   232  			}
   233  			if packages.PrintErrors(roots) > 0 {
   234  				return fmt.Errorf("callee package had errors") // (see log)
   235  			}
   236  			calleePkg = roots[0]
   237  		}
   238  	}
   239  
   240  	calleeDecl, err := findFuncByPosition(calleePkg, caller.Fset.PositionFor(fn.Pos(), false))
   241  	if err != nil {
   242  		return err
   243  	}
   244  
   245  	// Do the inlining. For the purposes of the test,
   246  	// AnalyzeCallee and Inline are a single operation.
   247  	res, err := func() (*inline.Result, error) {
   248  		filename := calleePkg.Fset.File(calleeDecl.Pos()).Name()
   249  		content, err := os.ReadFile(filename)
   250  		if err != nil {
   251  			return nil, err
   252  		}
   253  		callee, err := inline.AnalyzeCallee(
   254  			logf,
   255  			calleePkg.Fset,
   256  			calleePkg.Types,
   257  			calleePkg.TypesInfo,
   258  			calleeDecl,
   259  			content)
   260  		if err != nil {
   261  			return nil, err
   262  		}
   263  
   264  		if err := checkTranscode(callee); err != nil {
   265  			return nil, err
   266  		}
   267  
   268  		check := checkNoMutation(caller.File)
   269  		defer check()
   270  		return inline.Inline(caller, callee, &inline.Options{Logf: logf})
   271  	}()
   272  	if err != nil {
   273  		if wantRE, ok := want.(*regexp.Regexp); ok {
   274  			if !wantRE.MatchString(err.Error()) {
   275  				return fmt.Errorf("Inline failed with wrong error: %v (want error matching %q)", err, want)
   276  			}
   277  			return nil // expected error
   278  		}
   279  		return fmt.Errorf("Inline failed: %v", err) // success was expected
   280  	}
   281  
   282  	// Inline succeeded.
   283  	got := res.Content
   284  	if want, ok := want.([]byte); ok {
   285  		got = append(bytes.TrimSpace(got), '\n')
   286  		want = append(bytes.TrimSpace(want), '\n')
   287  		if diff := diff.Unified("want", "got", string(want), string(got)); diff != "" {
   288  			return fmt.Errorf("Inline returned wrong output:\n%s\nWant:\n%s\nDiff:\n%s",
   289  				got, want, diff)
   290  		}
   291  		return nil
   292  	}
   293  	return fmt.Errorf("Inline succeeded unexpectedly: want error matching %q, got <<%s>>", want, got)
   294  
   295  }
   296  
   297  // findFuncByPosition returns the FuncDecl at the specified (package-agnostic) position.
   298  func findFuncByPosition(pkg *packages.Package, posn token.Position) (*ast.FuncDecl, error) {
   299  	same := func(decl *ast.FuncDecl) bool {
   300  		// We can't rely on columns in export data:
   301  		// some variants replace it with 1.
   302  		// We can't expect file names to have the same prefix.
   303  		// export data for go1.20 std packages have  $GOROOT written in
   304  		// them, so how are we supposed to find the source? Yuck!
   305  		// Ugh. need to samefile? Nope $GOROOT just won't work
   306  		// This is highly client specific anyway.
   307  		posn2 := pkg.Fset.PositionFor(decl.Name.Pos(), false)
   308  		return posn.Filename == posn2.Filename &&
   309  			posn.Line == posn2.Line
   310  	}
   311  	for _, file := range pkg.Syntax {
   312  		for _, decl := range file.Decls {
   313  			if decl, ok := decl.(*ast.FuncDecl); ok && same(decl) {
   314  				return decl, nil
   315  			}
   316  		}
   317  	}
   318  	return nil, fmt.Errorf("can't find FuncDecl at %v in package %q", posn, pkg.PkgPath)
   319  }
   320  
   321  // Each callee must declare a function or method named f,
   322  // and each caller must call it.
   323  const funcName = "f"
   324  
   325  // A testcase is an item in a table-driven test.
   326  //
   327  // The table-driven tests are less flexible, but enable more compact
   328  // expression of single-package test cases than is possible with the
   329  // txtar notation.
   330  //
   331  // TODO(adonovan): improve coverage of the cross product of each
   332  // strategy with the checklist of concerns enumerated in the package
   333  // doc comment.
   334  type testcase struct {
   335  	descr          string // description; substrings enable options (e.g. "IgnoreEffects")
   336  	callee, caller string // Go source files (sans package decl) of caller, callee
   337  	want           string // expected new portion of caller file, or "error: regexp"
   338  }
   339  
   340  func TestErrors(t *testing.T) {
   341  	runTests(t, []testcase{
   342  		{
   343  			"Generic functions are not yet supported.",
   344  			`func f[T any](x T) T { return x }`,
   345  			`var _ = f(0)`,
   346  			`error: type parameters are not yet supported`,
   347  		},
   348  		{
   349  			"Methods on generic types are not yet supported.",
   350  			`type G[T any] struct{}; func (G[T]) f(x T) T { return x }`,
   351  			`var _ = G[int]{}.f(0)`,
   352  			`error: type parameters are not yet supported`,
   353  		},
   354  	})
   355  }
   356  
   357  func TestBasics(t *testing.T) {
   358  	runTests(t, []testcase{
   359  		{
   360  			"Basic",
   361  			`func f(x int) int { return x }`,
   362  			`var _ = f(0)`,
   363  			`var _ = 0`,
   364  		},
   365  		{
   366  			"Empty body, no arg effects.",
   367  			`func f(x, y int) {}`,
   368  			`func _() { f(1, 2) }`,
   369  			`func _() {}`,
   370  		},
   371  		{
   372  			"Empty body, some arg effects.",
   373  			`func f(x, y, z int) {}`,
   374  			`func _() { f(1, recover().(int), 3) }`,
   375  			`func _() { _ = recover().(int) }`,
   376  		},
   377  		{
   378  			"Non-duplicable arguments are not substituted even if pure.",
   379  			`func f(s string, i int) { print(s, s, i, i) }`,
   380  			`func _() { f("hi", 0)  }`,
   381  			`func _() {
   382  	var s string = "hi"
   383  	print(s, s, 0, 0)
   384  }`,
   385  		},
   386  		{
   387  			"Workaround for T(x) misformatting (#63362).",
   388  			`func f(ch <-chan int) { <-ch }`,
   389  			`func _(ch chan int) { f(ch) }`,
   390  			`func _(ch chan int) { <-(<-chan int)(ch) }`,
   391  		},
   392  		{
   393  			// (a regression test for unnecessary braces)
   394  			"In block elision, blank decls don't count when computing name conflicts.",
   395  			`func f(x int) { var _ = x; var _ = 3 }`,
   396  			`func _() { var _ = 1; f(2) }`,
   397  			`func _() {
   398  	var _ = 1
   399  	var _ = 2
   400  	var _ = 3
   401  }`,
   402  		},
   403  		{
   404  			// (a regression test for a missing conversion)
   405  			"Implicit return conversions are inserted in expr-context reduction.",
   406  			`func f(x int) error { return nil }`,
   407  			`func _() { if err := f(0); err != nil {} }`,
   408  			`func _() {
   409  	if err := error(nil); err != nil {
   410  	}
   411  }`,
   412  		},
   413  	})
   414  }
   415  
   416  func TestDuplicable(t *testing.T) {
   417  	runTests(t, []testcase{
   418  		{
   419  			"Empty strings are duplicable.",
   420  			`func f(s string) { print(s, s) }`,
   421  			`func _() { f("")  }`,
   422  			`func _() { print("", "") }`,
   423  		},
   424  		{
   425  			"Non-empty string literals are not duplicable.",
   426  			`func f(s string) { print(s, s) }`,
   427  			`func _() { f("hi")  }`,
   428  			`func _() {
   429  	var s string = "hi"
   430  	print(s, s)
   431  }`,
   432  		},
   433  		{
   434  			"Empty array literals are duplicable.",
   435  			`func f(a [2]int) { print(a, a) }`,
   436  			`func _() { f([2]int{})  }`,
   437  			`func _() { print([2]int{}, [2]int{}) }`,
   438  		},
   439  		{
   440  			"Non-empty array literals are not duplicable.",
   441  			`func f(a [2]int) { print(a, a) }`,
   442  			`func _() { f([2]int{1, 2})  }`,
   443  			`func _() {
   444  	var a [2]int = [2]int{1, 2}
   445  	print(a, a)
   446  }`,
   447  		},
   448  		{
   449  			"Empty struct literals are duplicable.",
   450  			`func f(s S) { print(s, s) }; type S struct { x int }`,
   451  			`func _() { f(S{})  }`,
   452  			`func _() { print(S{}, S{}) }`,
   453  		},
   454  		{
   455  			"Non-empty struct literals are not duplicable.",
   456  			`func f(s S) { print(s, s) }; type S struct { x int }`,
   457  			`func _() { f(S{x: 1})  }`,
   458  			`func _() {
   459  	var s S = S{x: 1}
   460  	print(s, s)
   461  }`,
   462  		},
   463  	})
   464  }
   465  
   466  func TestExprStmtReduction(t *testing.T) {
   467  	runTests(t, []testcase{
   468  		{
   469  			"A call in an unrestricted ExprStmt may be replaced by the body stmts.",
   470  			`func f() { var _ = len("") }`,
   471  			`func _() { f() }`,
   472  			`func _() { var _ = len("") }`,
   473  		},
   474  		{
   475  			"ExprStmts in the body of a switch case are unrestricted.",
   476  			`func f() { x := 1; print(x) }`,
   477  			`func _() { switch { case true: f() } }`,
   478  			`func _() {
   479  	switch {
   480  	case true:
   481  		x := 1
   482  		print(x)
   483  	}
   484  }`,
   485  		},
   486  		{
   487  			"ExprStmts in the body of a select case are unrestricted.",
   488  			`func f() { x := 1; print(x) }`,
   489  			`func _() { select { default: f() } }`,
   490  			`func _() {
   491  	select {
   492  	default:
   493  		x := 1
   494  		print(x)
   495  	}
   496  }`,
   497  		},
   498  		{
   499  			"Some ExprStmt contexts are restricted to simple statements.",
   500  			`func f() { var _ = len("") }`,
   501  			`func _(cond bool) { if f(); cond {} }`,
   502  			`func _(cond bool) {
   503  	if func() { var _ = len("") }(); cond {
   504  	}
   505  }`,
   506  		},
   507  		{
   508  			"Braces must be preserved to avoid a name conflict (decl before).",
   509  			`func f() { x := 1; print(x) }`,
   510  			`func _() { x := 2; print(x); f() }`,
   511  			`func _() {
   512  	x := 2
   513  	print(x)
   514  	{
   515  		x := 1
   516  		print(x)
   517  	}
   518  }`,
   519  		},
   520  		{
   521  			"Braces must be preserved to avoid a name conflict (decl after).",
   522  			`func f() { x := 1; print(x) }`,
   523  			`func _() { f(); x := 2; print(x) }`,
   524  			`func _() {
   525  	{
   526  		x := 1
   527  		print(x)
   528  	}
   529  	x := 2
   530  	print(x)
   531  }`,
   532  		},
   533  		{
   534  			"Braces must be preserved to avoid a forward jump across a decl.",
   535  			`func f() { x := 1; print(x) }`,
   536  			`func _() { goto label; f(); label: }`,
   537  			`func _() {
   538  	goto label
   539  	{
   540  		x := 1
   541  		print(x)
   542  	}
   543  label:
   544  }`,
   545  		},
   546  	})
   547  }
   548  
   549  func TestPrecedenceParens(t *testing.T) {
   550  	// Ensure that parens are inserted when (and only when) necessary
   551  	// around the replacement for the call expression. (This is a special
   552  	// case in the way the inliner uses a combination of AST formatting
   553  	// for the call and text splicing for the rest of the file.)
   554  	runTests(t, []testcase{
   555  		{
   556  			"Multiplication in addition context (no parens).",
   557  			`func f(x, y int) int { return x * y }`,
   558  			`func _() { _ = 1 + f(2, 3) }`,
   559  			`func _() { _ = 1 + 2*3 }`,
   560  		},
   561  		{
   562  			"Addition in multiplication context (parens).",
   563  			`func f(x, y int) int { return x + y }`,
   564  			`func _() { _ = 1 * f(2, 3) }`,
   565  			`func _() { _ = 1 * (2 + 3) }`,
   566  		},
   567  		{
   568  			"Addition in negation context (parens).",
   569  			`func f(x, y int) int { return x + y }`,
   570  			`func _() { _ = -f(1, 2) }`,
   571  			`func _() { _ = -(1 + 2) }`,
   572  		},
   573  		{
   574  			"Addition in call context (no parens).",
   575  			`func f(x, y int) int { return x + y }`,
   576  			`func _() { println(f(1, 2)) }`,
   577  			`func _() { println(1 + 2) }`,
   578  		},
   579  		{
   580  			"Addition in slice operand context (parens).",
   581  			`func f(x, y string) string { return x + y }`,
   582  			`func _() { _ = f("x",  "y")[1:2] }`,
   583  			`func _() { _ = ("x" + "y")[1:2] }`,
   584  		},
   585  		{
   586  			"String literal in slice operand context (no parens).",
   587  			`func f(x string) string { return x }`,
   588  			`func _() { _ = f("xy")[1:2] }`,
   589  			`func _() { _ = "xy"[1:2] }`,
   590  		},
   591  	})
   592  }
   593  
   594  func TestSubstitution(t *testing.T) {
   595  	runTests(t, []testcase{
   596  		{
   597  			"Arg to unref'd param can be eliminated if has no effects.",
   598  			`func f(x, y int) {}; var global int`,
   599  			`func _() { f(0, global) }`,
   600  			`func _() {}`,
   601  		},
   602  		{
   603  			"But not if it may contain last reference to a caller local var.",
   604  			`func f(int) {}`,
   605  			`func _() { var local int; f(local) }`,
   606  			`func _() { var local int; _ = local }`,
   607  		},
   608  		{
   609  			"Arguments that are used are detected",
   610  			`func f(int) {}`,
   611  			`func _() { var local int; _ = local; f(local) }`,
   612  			`func _() { var local int; _ = local }`,
   613  		},
   614  		{
   615  			"Arguments that are used are detected",
   616  			`func f(x, y int) { print(x) }`,
   617  			`func _() { var z int; f(z, z) }`,
   618  			`func _() {
   619  	var z int
   620  	var _ int = z
   621  	print(z)
   622  }`,
   623  		},
   624  		{
   625  			"Function parameters are always used",
   626  			`func f(int) {}`,
   627  			`func _() {
   628  	func(local int) {
   629  		f(local)
   630  	}(1)
   631  }`,
   632  			`func _() {
   633  	func(local int) {
   634  
   635  	}(1)
   636  }`,
   637  		},
   638  		{
   639  			"Regression test for detection of shadowing in nested functions.",
   640  			`func f(x int) { _ = func() { y := 1; print(y); print(x) } }`,
   641  			`func _(y int) { f(y) } `,
   642  			`func _(y int) {
   643  	var x int = y
   644  	_ = func() { y := 1; print(y); print(x) }
   645  }`,
   646  		},
   647  	})
   648  }
   649  
   650  func TestTailCallStrategy(t *testing.T) {
   651  	runTests(t, []testcase{
   652  		{
   653  			"simple",
   654  			`func f() int { return 1 }`,
   655  			`func _() int { return f() }`,
   656  			`func _() int { return 1 }`,
   657  		},
   658  		{
   659  			"void",
   660  			`func f() { println() }`,
   661  			`func _() { f() }`,
   662  			`func _() { println() }`,
   663  		},
   664  		{
   665  			"void with defer", // => literalized
   666  			`func f() { defer f(); println() }`,
   667  			`func _() { f() }`,
   668  			`func _() { func() { defer f(); println() }() }`,
   669  		},
   670  		// Tests for issue #63336:
   671  		{
   672  			"non-trivial return conversion (caller.sig = callee.sig)",
   673  			`func f() error { if true { return nil } else { return e } }; var e struct{error}`,
   674  			`func _() error { return f() }`,
   675  			`func _() error {
   676  	if true {
   677  		return nil
   678  	} else {
   679  		return e
   680  	}
   681  }`,
   682  		},
   683  		{
   684  			"non-trivial return conversion (caller.sig != callee.sig)",
   685  			`func f() error { return E{} }; type E struct{error}`,
   686  			`func _() any { return f() }`,
   687  			`func _() any { return error(E{}) }`,
   688  		},
   689  	})
   690  }
   691  
   692  func TestSpreadCalls(t *testing.T) {
   693  	runTests(t, []testcase{
   694  		{
   695  			"Edge case: cannot literalize spread method call.",
   696  			`type I int
   697   			func g() (I, I)
   698  			func (r I) f(x, y I) I {
   699  				defer g() // force literalization
   700  				return x + y + r
   701  			}`,
   702  			`func _() I { return recover().(I).f(g()) }`,
   703  			`error: can't yet inline spread call to method`,
   704  		},
   705  		{
   706  			"Spread argument evaluated for effect.",
   707  			`func f(int, int) {}; func g() (int, int)`,
   708  			`func _() { f(g())  }`,
   709  			`func _() { _, _ = g() }`,
   710  		},
   711  		{
   712  			"Edge case: receiver and spread argument, both evaluated for effect.",
   713  			`type T int; func (T) f(int, int) {}; func g() (int, int)`,
   714  			`func _() { T(0).f(g())  }`,
   715  			`func _() {
   716  	var (
   717  		_    = T(0)
   718  		_, _ = g()
   719  	)
   720  }`,
   721  		},
   722  		{
   723  			"Spread call in return (#63398).",
   724  			`func f() (int, error) { return 0, nil }`,
   725  			`func _() (int, error) { return f() }`,
   726  			`func _() (int, error) { return 0, nil }`,
   727  		},
   728  	})
   729  }
   730  
   731  func TestAssignmentCallStrategy(t *testing.T) {
   732  	runTests(t, []testcase{
   733  		{
   734  			"splice: basic",
   735  			`func f(x int) (int, int) { return x, 2 }`,
   736  			`func _() { x, y := f(1); _, _ = x, y }`,
   737  			`func _() { x, y := 1, 2; _, _ = x, y }`,
   738  		},
   739  		{
   740  			"spread: basic",
   741  			`func f(x int) (any, any) { return g() }; func g() (error, error) { return nil, nil }`,
   742  			`func _() {
   743  	var x any
   744  	x, y := f(0)
   745  	_, _ = x, y
   746  }`,
   747  			`func _() {
   748  	var x any
   749  	var y any
   750  	x, y = g()
   751  	_, _ = x, y
   752  }`,
   753  		},
   754  		{
   755  			"spread: free var conflict",
   756  			`func f(x int) (any, any) { return g(x) }; func g(x int) (int, int) { return x, x }`,
   757  			`func _() {
   758  	y := 2
   759  	{
   760  		var x any
   761  		x, y := f(y)
   762  		_, _ = x, y
   763  	}
   764  }`,
   765  			`func _() {
   766  	y := 2
   767  	{
   768  		var x any
   769  		x, y := func() (any, any) { return g(y) }()
   770  		_, _ = x, y
   771  	}
   772  }`,
   773  		},
   774  		{
   775  			"convert: basic",
   776  			`func f(x int) (int32, int8) { return 1, 2 }`,
   777  			`func _() {
   778  	var x int32
   779    x, y := f(0)
   780  	_, _ = x, y
   781  }`,
   782  			`func _() {
   783  	var x int32
   784  	x, y := 1, int8(2)
   785  	_, _ = x, y
   786  }`,
   787  		},
   788  		{
   789  			"convert: rune and byte",
   790  			`func f(x int) (rune, byte) { return 0, 0 }`,
   791  			`func _() {
   792  	x, y := f(0)
   793  	_, _ = x, y
   794  }`,
   795  			`func _() {
   796  	x, y := rune(0), byte(0)
   797  	_, _ = x, y
   798  }`,
   799  		},
   800  		{
   801  			"convert: interface conversions",
   802  			`func f(x int) (_, _ error) { return nil, nil }`,
   803  			`func _() {
   804    x, y := f(0)
   805  	_, _ = x, y
   806  }`,
   807  			`func _() {
   808  	x, y := error(nil), error(nil)
   809  	_, _ = x, y
   810  }`,
   811  		},
   812  		{
   813  			"convert: implicit nil conversions",
   814  			`func f(x int) (_, _ error) { return nil, nil }`,
   815  			`func _() { x, y := f(0); _, _ = x, y }`,
   816  			`func _() { x, y := error(nil), error(nil); _, _ = x, y }`,
   817  		},
   818  		{
   819  			"convert: pruning nil assignments left",
   820  			`func f(x int) (_, _ error) { return nil, nil }`,
   821  			`func _() { _, y := f(0); _ = y }`,
   822  			`func _() { y := error(nil); _ = y }`,
   823  		},
   824  		{
   825  			"convert: pruning nil assignments right",
   826  			`func f(x int) (_, _ error) { return nil, nil }`,
   827  			`func _() { x, _ := f(0); _ = x }`,
   828  			`func _() { x := error(nil); _ = x }`,
   829  		},
   830  		{
   831  			"convert: partial assign",
   832  			`func f(x int) (_, _ error) { return nil, nil }`,
   833  			`func _() {
   834  	var x error
   835    x, y := f(0)
   836  	_, _ = x, y
   837  }`,
   838  			`func _() {
   839  	var x error
   840  	x, y := nil, error(nil)
   841  	_, _ = x, y
   842  }`,
   843  		},
   844  		{
   845  			"convert: single assignment left",
   846  			`func f() int { return 0 }`,
   847  			`func _() {
   848  	x, y := f(), "hello"
   849  	_, _ = x, y
   850  }`,
   851  			`func _() {
   852  	x, y := 0, "hello"
   853  	_, _ = x, y
   854  }`,
   855  		},
   856  		{
   857  			"convert: single assignment left with conversion",
   858  			`func f() int32 { return 0 }`,
   859  			`func _() {
   860  	x, y := f(), "hello"
   861  	_, _ = x, y
   862  }`,
   863  			`func _() {
   864  	x, y := int32(0), "hello"
   865  	_, _ = x, y
   866  }`,
   867  		},
   868  		{
   869  			"convert: single assignment right",
   870  			`func f() int32 { return 0 }`,
   871  			`func _() {
   872  	x, y := "hello", f()
   873  	_, _ = x, y
   874  }`,
   875  			`func _() {
   876  	x, y := "hello", int32(0)
   877  	_, _ = x, y
   878  }`,
   879  		},
   880  		{
   881  			"convert: single assignment middle",
   882  			`func f() int32 { return 0 }`,
   883  			`func _() {
   884  	x, y, z := "hello", f(), 1.56
   885  	_, _, _ = x, y, z
   886  }`,
   887  			`func _() {
   888  	x, y, z := "hello", int32(0), 1.56
   889  	_, _, _ = x, y, z
   890  }`,
   891  		},
   892  	})
   893  }
   894  
   895  func TestVariadic(t *testing.T) {
   896  	runTests(t, []testcase{
   897  		{
   898  			"Variadic cancellation (basic).",
   899  			`func f(args ...any) { defer f(&args); println(args) }`,
   900  			`func _(slice []any) { f(slice...) }`,
   901  			`func _(slice []any) { func() { var args []any = slice; defer f(&args); println(args) }() }`,
   902  		},
   903  		{
   904  			"Variadic cancellation (literalization with parameter elimination).",
   905  			`func f(args ...any) { defer f(); println(args) }`,
   906  			`func _(slice []any) { f(slice...) }`,
   907  			`func _(slice []any) { func() { defer f(); println(slice) }() }`,
   908  		},
   909  		{
   910  			"Variadic cancellation (reduction).",
   911  			`func f(args ...any) { println(args) }`,
   912  			`func _(slice []any) { f(slice...) }`,
   913  			`func _(slice []any) { println(slice) }`,
   914  		},
   915  		{
   916  			"Variadic elimination (literalization).",
   917  			`func f(x any, rest ...any) { defer println(x, rest) }`, // defer => literalization
   918  			`func _() { f(1, 2, 3) }`,
   919  			`func _() { func() { defer println(any(1), []any{2, 3}) }() }`,
   920  		},
   921  		{
   922  			"Variadic elimination (reduction).",
   923  			`func f(x int, rest ...int) { println(x, rest) }`,
   924  			`func _() { f(1, 2, 3) }`,
   925  			`func _() { println(1, []int{2, 3}) }`,
   926  		},
   927  		{
   928  			"Spread call to variadic (1 arg, 1 param).",
   929  			`func f(rest ...int) { println(rest) }; func g() (a, b int)`,
   930  			`func _() { f(g()) }`,
   931  			`func _() { func(rest ...int) { println(rest) }(g()) }`,
   932  		},
   933  		{
   934  			"Spread call to variadic (1 arg, 2 params).",
   935  			`func f(x int, rest ...int) { println(x, rest) }; func g() (a, b int)`,
   936  			`func _() { f(g()) }`,
   937  			`func _() { func(x int, rest ...int) { println(x, rest) }(g()) }`,
   938  		},
   939  		{
   940  			"Spread call to variadic (1 arg, 3 params).",
   941  			`func f(x, y int, rest ...int) { println(x, y, rest) }; func g() (a, b, c int)`,
   942  			`func _() { f(g()) }`,
   943  			`func _() { func(x, y int, rest ...int) { println(x, y, rest) }(g()) }`,
   944  		},
   945  	})
   946  }
   947  
   948  func TestParameterBindingDecl(t *testing.T) {
   949  	runTests(t, []testcase{
   950  		{
   951  			"IncDec counts as assignment.",
   952  			`func f(x int) { x++ }`,
   953  			`func _() { f(1) }`,
   954  			`func _() {
   955  	var x int = 1
   956  	x++
   957  }`,
   958  		},
   959  		{
   960  			"Binding declaration (x, y, z eliminated).",
   961  			`func f(w, x, y any, z int) { println(w, y, z) }; func g(int) int`,
   962  			`func _() { f(g(0), g(1), g(2), g(3)) }`,
   963  			`func _() {
   964  	var w, _ any = g(0), g(1)
   965  	println(w, any(g(2)), g(3))
   966  }`,
   967  		},
   968  		{
   969  			"Reduction of stmt-context call to { return exprs }, with substitution",
   970  			`func f(ch chan int) int { return <-ch }; func g() chan int`,
   971  			`func _() { f(g()) }`,
   972  			`func _() { <-g() }`,
   973  		},
   974  		{
   975  			// Same again, with callee effects:
   976  			"Binding decl in reduction of stmt-context call to { return exprs }",
   977  			`func f(x int) int { return <-h(g(2), x) }; func g(int) int; func h(int, int) chan int`,
   978  			`func _() { f(g(1)) }`,
   979  			`func _() {
   980  	var x int = g(1)
   981  	<-h(g(2), x)
   982  }`,
   983  		},
   984  		{
   985  			"No binding decl due to shadowing of int",
   986  			`func f(int, y any, z int) { defer g(0); println(int, y, z) }; func g(int) int`,
   987  			`func _() { f(g(1), g(2), g(3)) }`,
   988  			`func _() { func(int, y any, z int) { defer g(0); println(int, y, z) }(g(1), g(2), g(3)) }`,
   989  		},
   990  		{
   991  			"An indirect method selection (*x).g acts as a read.",
   992  			`func f(x *T, y any) any { return x.g(y) }; type T struct{}; func (T) g(x any) any { return x }`,
   993  			`func _(x *T) { f(x, recover()) }`,
   994  			`func _(x *T) {
   995  	var y any = recover()
   996  	x.g(y)
   997  }`,
   998  		},
   999  		{
  1000  			"A direct method selection x.g is pure.",
  1001  			`func f(x *T, y any) any { return x.g(y) }; type T struct{}; func (*T) g(x any) any { return x }`,
  1002  			`func _(x *T) { f(x, recover()) }`,
  1003  			`func _(x *T) { x.g(recover()) }`,
  1004  		},
  1005  		{
  1006  			"Literalization can make use of a binding decl (all params).",
  1007  			`func f(x, y int) int { defer println(); return y + x }; func g(int) int`,
  1008  			`func _() { println(f(g(1), g(2))) }`,
  1009  			`func _() { println(func() int { var x, y int = g(1), g(2); defer println(); return y + x }()) }`,
  1010  		},
  1011  		{
  1012  			"Literalization can make use of a binding decl (some params).",
  1013  			`func f(x, y int) int { z := y + x; defer println(); return z }; func g(int) int`,
  1014  			`func _() { println(f(g(1), g(2))) }`,
  1015  			`func _() { println(func() int { var x int = g(1); z := g(2) + x; defer println(); return z }()) }`,
  1016  		},
  1017  		{
  1018  			"Literalization can't yet use of a binding decl if named results.",
  1019  			`func f(x, y int) (z int) { z = y + x; defer println(); return }; func g(int) int`,
  1020  			`func _() { println(f(g(1), g(2))) }`,
  1021  			`func _() { println(func(x int) (z int) { z = g(2) + x; defer println(); return }(g(1))) }`,
  1022  		},
  1023  	})
  1024  }
  1025  
  1026  func TestEmbeddedFields(t *testing.T) {
  1027  	runTests(t, []testcase{
  1028  		{
  1029  			"Embedded fields in x.f method selection (direct).",
  1030  			`type T int; func (t T) f() { print(t) }; type U struct{ T }`,
  1031  			`func _(u U) { u.f() }`,
  1032  			`func _(u U) { print(u.T) }`,
  1033  		},
  1034  		{
  1035  			"Embedded fields in x.f method selection (implicit *).",
  1036  			`type ( T int; U struct{*T}; V struct {U} ); func (t T) f() { print(t) }`,
  1037  			`func _(v V) { v.f() }`,
  1038  			`func _(v V) { print(*v.U.T) }`,
  1039  		},
  1040  		{
  1041  			"Embedded fields in x.f method selection (implicit &).",
  1042  			`type ( T int; U struct{T}; V struct {U} ); func (t *T) f() { print(t) }`,
  1043  			`func _(v V) { v.f() }`,
  1044  			`func _(v V) { print(&v.U.T) }`,
  1045  		},
  1046  		// Now the same tests again with T.f(recv).
  1047  		{
  1048  			"Embedded fields in T.f method selection.",
  1049  			`type T int; func (t T) f() { print(t) }; type U struct{ T }`,
  1050  			`func _(u U) { U.f(u) }`,
  1051  			`func _(u U) { print(u.T) }`,
  1052  		},
  1053  		{
  1054  			"Embedded fields in T.f method selection (implicit *).",
  1055  			`type ( T int; U struct{*T}; V struct {U} ); func (t T) f() { print(t) }`,
  1056  			`func _(v V) { V.f(v) }`,
  1057  			`func _(v V) { print(*v.U.T) }`,
  1058  		},
  1059  		{
  1060  			"Embedded fields in (*T).f method selection.",
  1061  			`type ( T int; U struct{T}; V struct {U} ); func (t *T) f() { print(t) }`,
  1062  			`func _(v V) { (*V).f(&v) }`,
  1063  			`func _(v V) { print(&(&v).U.T) }`,
  1064  		},
  1065  		{
  1066  			// x is a single-assign var, and x.f does not load through a pointer
  1067  			// (despite types.Selection.Indirect=true), so x is pure.
  1068  			"No binding decl is required for recv in method-to-method calls.",
  1069  			`type T struct{}; func (x *T) f() { g(); print(*x) }; func g()`,
  1070  			`func (x *T) _() { x.f() }`,
  1071  			`func (x *T) _() {
  1072  	g()
  1073  	print(*x)
  1074  }`,
  1075  		},
  1076  		{
  1077  			"Same, with implicit &recv.",
  1078  			`type T struct{}; func (x *T) f() { g(); print(*x) }; func g()`,
  1079  			`func (x T) _() { x.f() }`,
  1080  			`func (x T) _() {
  1081  	{
  1082  		var x *T = &x
  1083  		g()
  1084  		print(*x)
  1085  	}
  1086  }`,
  1087  		},
  1088  	})
  1089  }
  1090  
  1091  func TestSubstitutionPreservesArgumentEffectOrder(t *testing.T) {
  1092  	runTests(t, []testcase{
  1093  		{
  1094  			"Arguments have effects, but parameters are evaluated in order.",
  1095  			`func f(a, b, c int) { print(a, b, c) }; func g(int) int`,
  1096  			`func _() { f(g(1), g(2), g(3)) }`,
  1097  			`func _() { print(g(1), g(2), g(3)) }`,
  1098  		},
  1099  		{
  1100  			"Arguments have effects, and parameters are evaluated out of order.",
  1101  			`func f(a, b, c int) { print(a, c, b) }; func g(int) int`,
  1102  			`func _() { f(g(1), g(2), g(3)) }`,
  1103  			`func _() {
  1104  	var a, b int = g(1), g(2)
  1105  	print(a, g(3), b)
  1106  }`,
  1107  		},
  1108  		{
  1109  			"Pure arguments may commute with argument that have effects.",
  1110  			`func f(a, b, c int) { print(a, c, b) }; func g(int) int`,
  1111  			`func _() { f(g(1), 2, g(3)) }`,
  1112  			`func _() { print(g(1), g(3), 2) }`,
  1113  		},
  1114  		{
  1115  			"Impure arguments may commute with each other.",
  1116  			`func f(a, b, c, d int) { print(a, c, b, d) }; func g(int) int; var x, y int`,
  1117  			`func _() { f(g(1), x, y, g(2)) }`,
  1118  			`func _() { print(g(1), y, x, g(2)) }`,
  1119  		},
  1120  		{
  1121  			"Impure arguments do not commute with arguments that have effects (1)",
  1122  			`func f(a, b, c, d int) { print(a, c, b, d) }; func g(int) int; var x, y int`,
  1123  			`func _() { f(g(1), g(2), y, g(3)) }`,
  1124  			`func _() {
  1125  	var a, b int = g(1), g(2)
  1126  	print(a, y, b, g(3))
  1127  }`,
  1128  		},
  1129  		{
  1130  			"Impure arguments do not commute with those that have effects (2).",
  1131  			`func f(a, b, c, d int) { print(a, c, b, d) }; func g(int) int; var x, y int`,
  1132  			`func _() { f(g(1), y, g(2), g(3)) }`,
  1133  			`func _() {
  1134  	var a, b int = g(1), y
  1135  	print(a, g(2), b, g(3))
  1136  }`,
  1137  		},
  1138  		{
  1139  			"Callee effects commute with pure arguments.",
  1140  			`func f(a, b, c int) { print(a, c, recover().(int), b) }; func g(int) int`,
  1141  			`func _() { f(g(1), 2, g(3)) }`,
  1142  			`func _() { print(g(1), g(3), recover().(int), 2) }`,
  1143  		},
  1144  		{
  1145  			"Callee reads may commute with impure arguments.",
  1146  			`func f(a, b int) { print(a, x, b) }; func g(int) int; var x, y int`,
  1147  			`func _() { f(g(1), y) }`,
  1148  			`func _() { print(g(1), x, y) }`,
  1149  		},
  1150  		{
  1151  			"All impure parameters preceding a read hazard must be kept.",
  1152  			`func f(a, b, c int) { print(a, b, recover().(int), c) }; var x, y, z int`,
  1153  			`func _() { f(x, y, z) }`,
  1154  			`func _() {
  1155  	var c int = z
  1156  	print(x, y, recover().(int), c)
  1157  }`,
  1158  		},
  1159  		{
  1160  			"All parameters preceding a write hazard must be kept.",
  1161  			`func f(a, b, c int) { print(a, b, recover().(int), c) }; func g(int) int; var x, y, z int`,
  1162  			`func _() { f(x, y, g(0))  }`,
  1163  			`func _() {
  1164  	var a, b, c int = x, y, g(0)
  1165  	print(a, b, recover().(int), c)
  1166  }`,
  1167  		},
  1168  		{
  1169  			"[W1 R0 W2 W4 R3] -- test case for second iteration of effect loop",
  1170  			`func f(a, b, c, d, e int) { print(b, a, c, e, d) }; func g(int) int; var x, y int`,
  1171  			`func _() { f(x, g(1), g(2), y, g(3))  }`,
  1172  			`func _() {
  1173  	var a, b, c, d int = x, g(1), g(2), y
  1174  	print(b, a, c, g(3), d)
  1175  }`,
  1176  		},
  1177  		{
  1178  			// In this example, the set() call is rejected as a substitution
  1179  			// candidate due to a shadowing conflict (x). This must entail that the
  1180  			// selection x.y (R) is also rejected, because it is lower numbered.
  1181  			//
  1182  			// Incidentally this program (which panics when executed) illustrates
  1183  			// that although effects occur left-to-right, read operations such
  1184  			// as x.y are not ordered wrt writes, depending on the compiler.
  1185  			// Changing x.y to identity(x).y forces the ordering and avoids the panic.
  1186  			"Hazards with args already rejected (e.g. due to shadowing) are detected too.",
  1187  			`func f(x, y int) int { return x + y }; func set[T any](ptr *T, old, new T) int { println(old); *ptr = new; return 0; }`,
  1188  			`func _() { x := new(struct{ y int }); f(x.y, set(&x, x, nil)) }`,
  1189  			`func _() {
  1190  	x := new(struct{ y int })
  1191  	{
  1192  		var x, y int = x.y, set(&x, x, nil)
  1193  		_ = x + y
  1194  	}
  1195  }`,
  1196  		},
  1197  		{
  1198  			// Rejection of a later parameter for reasons other than callee
  1199  			// effects (e.g. escape) may create hazards with lower-numbered
  1200  			// parameters that require them to be rejected too.
  1201  			"Hazards with already eliminated parameters (variant)",
  1202  			`func f(x, y int) { _ = &y }; func g(int) int`,
  1203  			`func _() { f(g(1), g(2)) }`,
  1204  			`func _() {
  1205  	var _, y int = g(1), g(2)
  1206  	_ = &y
  1207  }`,
  1208  		},
  1209  		{
  1210  			// In this case g(2) is rejected for substitution because it is
  1211  			// unreferenced but has effects, so parameter x must also be rejected
  1212  			// so that its argument v can be evaluated earlier in the binding decl.
  1213  			"Hazards with already eliminated parameters (unreferenced fx variant)",
  1214  			`func f(x, y int) { _ = x }; func g(int) int; var v int`,
  1215  			`func _() { f(v, g(2)) }`,
  1216  			`func _() {
  1217  	var x, _ int = v, g(2)
  1218  	_ = x
  1219  }`,
  1220  		},
  1221  		{
  1222  			"Defer f() evaluates f() before unknown effects",
  1223  			`func f(int, y any, z int) { defer println(int, y, z) }; func g(int) int`,
  1224  			`func _() { f(g(1), g(2), g(3)) }`,
  1225  			`func _() { func() { defer println(any(g(1)), any(g(2)), g(3)) }() }`,
  1226  		},
  1227  		{
  1228  			"Effects are ignored when IgnoreEffects",
  1229  			`func f(x, y int) { println(y, x) }; func g(int) int`,
  1230  			`func _() { f(g(1), g(2)) }`,
  1231  			`func _() { println(g(2), g(1)) }`,
  1232  		},
  1233  	})
  1234  }
  1235  
  1236  func TestNamedResultVars(t *testing.T) {
  1237  	runTests(t, []testcase{
  1238  		{
  1239  			"Stmt-context call to {return g()} that mentions named result.",
  1240  			`func f() (x int) { return g(x) }; func g(int) int`,
  1241  			`func _() { f() }`,
  1242  			`func _() {
  1243  	var x int
  1244  	g(x)
  1245  }`,
  1246  		},
  1247  		{
  1248  			"Ditto, with binding decl again.",
  1249  			`func f(y string) (x int) { return x+x+len(y+y) }`,
  1250  			`func _() { f(".") }`,
  1251  			`func _() {
  1252  	var (
  1253  		y string = "."
  1254  		x int
  1255  	)
  1256  	_ = x + x + len(y+y)
  1257  }`,
  1258  		},
  1259  
  1260  		{
  1261  			"Ditto, with binding decl (due to repeated y refs).",
  1262  			`func f(y string) (x string) { return x+y+y }`,
  1263  			`func _() { f(".") }`,
  1264  			`func _() {
  1265  	var (
  1266  		y string = "."
  1267  		x string
  1268  	)
  1269  	_ = x + y + y
  1270  }`,
  1271  		},
  1272  		{
  1273  			"Stmt-context call to {return binary} that mentions named result.",
  1274  			`func f() (x int) { return x+x }`,
  1275  			`func _() { f() }`,
  1276  			`func _() {
  1277  	var x int
  1278  	_ = x + x
  1279  }`,
  1280  		},
  1281  		{
  1282  			"Tail call to {return expr} that mentions named result.",
  1283  			`func f() (x int) { return x }`,
  1284  			`func _() int { return f() }`,
  1285  			`func _() int { return func() (x int) { return x }() }`,
  1286  		},
  1287  		{
  1288  			"Tail call to {return} that implicitly reads named result.",
  1289  			`func f() (x int) { return }`,
  1290  			`func _() int { return f() }`,
  1291  			`func _() int { return func() (x int) { return }() }`,
  1292  		},
  1293  		{
  1294  			"Spread-context call to {return expr} that mentions named result.",
  1295  			`func f() (x, y int) { return x, y }`,
  1296  			`func _() { var _, _ = f() }`,
  1297  			`func _() { var _, _ = func() (x, y int) { return x, y }() }`,
  1298  		},
  1299  		{
  1300  			"Shadowing in binding decl for named results => literalization.",
  1301  			`func f(y string) (x y) { return x+x+len(y+y) }; type y = int`,
  1302  			`func _() { f(".") }`,
  1303  			`func _() { func(y string) (x y) { return x + x + len(y+y) }(".") }`,
  1304  		},
  1305  	})
  1306  }
  1307  
  1308  func TestSubstitutionPreservesParameterType(t *testing.T) {
  1309  	runTests(t, []testcase{
  1310  		{
  1311  			"Substitution preserves argument type (#63193).",
  1312  			`func f(x int16) { y := x; _ = (*int16)(&y) }`,
  1313  			`func _() { f(1) }`,
  1314  			`func _() {
  1315  	y := int16(1)
  1316  	_ = (*int16)(&y)
  1317  }`,
  1318  		},
  1319  		{
  1320  			"Same, with non-constant (unnamed to named struct) conversion.",
  1321  			`func f(x T) { y := x; _ = (*T)(&y) }; type T struct{}`,
  1322  			`func _() { f(struct{}{}) }`,
  1323  			`func _() {
  1324  	y := T(struct{}{})
  1325  	_ = (*T)(&y)
  1326  }`,
  1327  		},
  1328  		{
  1329  			"Same, with non-constant (chan to <-chan) conversion.",
  1330  			`func f(x T) { y := x; _ = (*T)(&y) }; type T = <-chan int; var ch chan int`,
  1331  			`func _() { f(ch) }`,
  1332  			`func _() {
  1333  	y := T(ch)
  1334  	_ = (*T)(&y)
  1335  }`,
  1336  		},
  1337  		{
  1338  			"Same, with untyped nil to typed nil conversion.",
  1339  			`func f(x *int) { y := x; _ = (**int)(&y) }`,
  1340  			`func _() { f(nil) }`,
  1341  			`func _() {
  1342  	y := (*int)(nil)
  1343  	_ = (**int)(&y)
  1344  }`,
  1345  		},
  1346  		{
  1347  			"Conversion of untyped int to named type is made explicit.",
  1348  			`type T int; func (x T) f() { x.g() }; func (T) g() {}`,
  1349  			`func _() { T.f(1) }`,
  1350  			`func _() { T(1).g() }`,
  1351  		},
  1352  		{
  1353  			"Check for shadowing error on type used in the conversion.",
  1354  			`func f(x T) { _ = &x == (*T)(nil) }; type T int16`,
  1355  			`func _() { type T bool; f(1) }`,
  1356  			`error: T.*shadowed.*by.*type`,
  1357  		},
  1358  	})
  1359  }
  1360  
  1361  func runTests(t *testing.T, tests []testcase) {
  1362  	for _, test := range tests {
  1363  		test := test
  1364  		t.Run(test.descr, func(t *testing.T) {
  1365  			fset := token.NewFileSet()
  1366  			mustParse := func(filename string, content any) *ast.File {
  1367  				f, err := parser.ParseFile(fset, filename, content, parser.ParseComments|parser.SkipObjectResolution)
  1368  				if err != nil {
  1369  					t.Fatalf("ParseFile: %v", err)
  1370  				}
  1371  				return f
  1372  			}
  1373  
  1374  			// Parse callee file and find first func decl named f.
  1375  			calleeContent := "package p\n" + test.callee
  1376  			calleeFile := mustParse("callee.go", calleeContent)
  1377  			var decl *ast.FuncDecl
  1378  			for _, d := range calleeFile.Decls {
  1379  				if d, ok := d.(*ast.FuncDecl); ok && d.Name.Name == funcName {
  1380  					decl = d
  1381  					break
  1382  				}
  1383  			}
  1384  			if decl == nil {
  1385  				t.Fatalf("declaration of func %s not found: %s", funcName, test.callee)
  1386  			}
  1387  
  1388  			// Parse caller file and find first call to f().
  1389  			callerContent := "package p\n" + test.caller
  1390  			callerFile := mustParse("caller.go", callerContent)
  1391  			var call *ast.CallExpr
  1392  			ast.Inspect(callerFile, func(n ast.Node) bool {
  1393  				if n, ok := n.(*ast.CallExpr); ok {
  1394  					switch fun := n.Fun.(type) {
  1395  					case *ast.SelectorExpr:
  1396  						if fun.Sel.Name == funcName {
  1397  							call = n
  1398  						}
  1399  					case *ast.Ident:
  1400  						if fun.Name == funcName {
  1401  							call = n
  1402  						}
  1403  					}
  1404  				}
  1405  				return call == nil
  1406  			})
  1407  			if call == nil {
  1408  				t.Fatalf("call to %s not found: %s", funcName, test.caller)
  1409  			}
  1410  
  1411  			// Type check both files as one package.
  1412  			info := &types.Info{
  1413  				Defs:       make(map[*ast.Ident]types.Object),
  1414  				Uses:       make(map[*ast.Ident]types.Object),
  1415  				Types:      make(map[ast.Expr]types.TypeAndValue),
  1416  				Implicits:  make(map[ast.Node]types.Object),
  1417  				Selections: make(map[*ast.SelectorExpr]*types.Selection),
  1418  				Scopes:     make(map[ast.Node]*types.Scope),
  1419  			}
  1420  			conf := &types.Config{Error: func(err error) { t.Error(err) }}
  1421  			pkg, err := conf.Check("p", fset, []*ast.File{callerFile, calleeFile}, info)
  1422  			if err != nil {
  1423  				t.Fatal("transformation introduced type errors")
  1424  			}
  1425  
  1426  			// Analyze callee and inline call.
  1427  			doIt := func() (*inline.Result, error) {
  1428  				callee, err := inline.AnalyzeCallee(t.Logf, fset, pkg, info, decl, []byte(calleeContent))
  1429  				if err != nil {
  1430  					return nil, err
  1431  				}
  1432  				if err := checkTranscode(callee); err != nil {
  1433  					t.Fatal(err)
  1434  				}
  1435  
  1436  				caller := &inline.Caller{
  1437  					Fset:    fset,
  1438  					Types:   pkg,
  1439  					Info:    info,
  1440  					File:    callerFile,
  1441  					Call:    call,
  1442  					Content: []byte(callerContent),
  1443  				}
  1444  				check := checkNoMutation(caller.File)
  1445  				defer check()
  1446  				return inline.Inline(caller, callee, &inline.Options{
  1447  					Logf:          t.Logf,
  1448  					IgnoreEffects: strings.Contains(test.descr, "IgnoreEffects"),
  1449  				})
  1450  			}
  1451  			res, err := doIt()
  1452  
  1453  			// Want error?
  1454  			if rest := strings.TrimPrefix(test.want, "error: "); rest != test.want {
  1455  				if err == nil {
  1456  					t.Fatalf("unexpected success: want error matching %q", rest)
  1457  				}
  1458  				msg := err.Error()
  1459  				if ok, err := regexp.MatchString(rest, msg); err != nil {
  1460  					t.Fatalf("invalid regexp: %v", err)
  1461  				} else if !ok {
  1462  					t.Fatalf("wrong error: %s (want match for %q)", msg, rest)
  1463  				}
  1464  				return
  1465  			}
  1466  
  1467  			// Want success.
  1468  			if err != nil {
  1469  				t.Fatal(err)
  1470  			}
  1471  
  1472  			gotContent := res.Content
  1473  
  1474  			// Compute a single-hunk line-based diff.
  1475  			srcLines := strings.Split(callerContent, "\n")
  1476  			gotLines := strings.Split(string(gotContent), "\n")
  1477  			for len(srcLines) > 0 && len(gotLines) > 0 &&
  1478  				srcLines[0] == gotLines[0] {
  1479  				srcLines = srcLines[1:]
  1480  				gotLines = gotLines[1:]
  1481  			}
  1482  			for len(srcLines) > 0 && len(gotLines) > 0 &&
  1483  				srcLines[len(srcLines)-1] == gotLines[len(gotLines)-1] {
  1484  				srcLines = srcLines[:len(srcLines)-1]
  1485  				gotLines = gotLines[:len(gotLines)-1]
  1486  			}
  1487  			got := strings.Join(gotLines, "\n")
  1488  
  1489  			if strings.TrimSpace(got) != strings.TrimSpace(test.want) {
  1490  				t.Fatalf("\nInlining this call:\t%s\nof this callee:    \t%s\nproduced:\n%s\nWant:\n\n%s",
  1491  					test.caller,
  1492  					test.callee,
  1493  					got,
  1494  					test.want)
  1495  			}
  1496  
  1497  			// Check that resulting code type-checks.
  1498  			newCallerFile := mustParse("newcaller.go", gotContent)
  1499  			if _, err := conf.Check("p", fset, []*ast.File{newCallerFile, calleeFile}, nil); err != nil {
  1500  				t.Fatalf("modified source failed to typecheck: <<%s>>", gotContent)
  1501  			}
  1502  		})
  1503  	}
  1504  }
  1505  
  1506  // -- helpers --
  1507  
  1508  // checkNoMutation returns a function that, when called,
  1509  // asserts that file was not modified since the checkNoMutation call.
  1510  func checkNoMutation(file *ast.File) func() {
  1511  	pre := deepHash(file)
  1512  	return func() {
  1513  		post := deepHash(file)
  1514  		if pre != post {
  1515  			panic("Inline mutated caller.File")
  1516  		}
  1517  	}
  1518  }
  1519  
  1520  // checkTranscode replaces *callee by the results of gob-encoding and
  1521  // then decoding it, to test that these operations are lossless.
  1522  func checkTranscode(callee *inline.Callee) error {
  1523  	// Perform Gob transcoding so that it is exercised by the test.
  1524  	var enc bytes.Buffer
  1525  	if err := gob.NewEncoder(&enc).Encode(callee); err != nil {
  1526  		return fmt.Errorf("internal error: gob encoding failed: %v", err)
  1527  	}
  1528  	*callee = inline.Callee{}
  1529  	if err := gob.NewDecoder(&enc).Decode(callee); err != nil {
  1530  		return fmt.Errorf("internal error: gob decoding failed: %v", err)
  1531  	}
  1532  	return nil
  1533  }
  1534  
  1535  // TODO(adonovan): publish this a helper (#61386).
  1536  func extractTxtar(ar *txtar.Archive, dir string) error {
  1537  	for _, file := range ar.Files {
  1538  		name := filepath.Join(dir, file.Name)
  1539  		if err := os.MkdirAll(filepath.Dir(name), 0777); err != nil {
  1540  			return err
  1541  		}
  1542  		if err := os.WriteFile(name, file.Data, 0666); err != nil {
  1543  			return err
  1544  		}
  1545  	}
  1546  	return nil
  1547  }
  1548  
  1549  // deepHash computes a cryptographic hash of an ast.Node so that
  1550  // if the data structure is mutated, the hash changes.
  1551  // It assumes Go variables do not change address.
  1552  //
  1553  // TODO(adonovan): consider publishing this in the astutil package.
  1554  //
  1555  // TODO(adonovan): consider a variant that reports where in the tree
  1556  // the mutation occurred (obviously at a cost in space).
  1557  func deepHash(n ast.Node) any {
  1558  	seen := make(map[unsafe.Pointer]bool) // to break cycles
  1559  
  1560  	hasher := sha256.New()
  1561  	le := binary.LittleEndian
  1562  	writeUint64 := func(v uint64) {
  1563  		var bs [8]byte
  1564  		le.PutUint64(bs[:], v)
  1565  		hasher.Write(bs[:])
  1566  	}
  1567  
  1568  	var visit func(reflect.Value)
  1569  	visit = func(v reflect.Value) {
  1570  		switch v.Kind() {
  1571  		case reflect.Ptr:
  1572  			ptr := v.UnsafePointer()
  1573  			writeUint64(uint64(uintptr(ptr)))
  1574  			if !v.IsNil() {
  1575  				if !seen[ptr] {
  1576  					seen[ptr] = true
  1577  					// Skip types we don't handle yet, but don't care about.
  1578  					switch v.Interface().(type) {
  1579  					case *ast.Scope:
  1580  						return // involves a map
  1581  					}
  1582  
  1583  					visit(v.Elem())
  1584  				}
  1585  			}
  1586  
  1587  		case reflect.Struct:
  1588  			for i := 0; i < v.Type().NumField(); i++ {
  1589  				visit(v.Field(i))
  1590  			}
  1591  
  1592  		case reflect.Slice:
  1593  			ptr := v.UnsafePointer()
  1594  			// We may encounter different slices at the same address,
  1595  			// so don't mark ptr as "seen".
  1596  			writeUint64(uint64(uintptr(ptr)))
  1597  			writeUint64(uint64(v.Len()))
  1598  			writeUint64(uint64(v.Cap()))
  1599  			for i := 0; i < v.Len(); i++ {
  1600  				visit(v.Index(i))
  1601  			}
  1602  
  1603  		case reflect.Interface:
  1604  			if v.IsNil() {
  1605  				writeUint64(0)
  1606  			} else {
  1607  				rtype := reflect.ValueOf(v.Type()).UnsafePointer()
  1608  				writeUint64(uint64(uintptr(rtype)))
  1609  				visit(v.Elem())
  1610  			}
  1611  
  1612  		case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.UnsafePointer:
  1613  			panic(v) // unreachable in AST
  1614  
  1615  		default: // bool, string, number
  1616  			if v.Kind() == reflect.String { // proper framing
  1617  				writeUint64(uint64(v.Len()))
  1618  			}
  1619  			binary.Write(hasher, le, v.Interface())
  1620  		}
  1621  	}
  1622  	visit(reflect.ValueOf(n))
  1623  
  1624  	var hash [sha256.Size]byte
  1625  	hasher.Sum(hash[:0])
  1626  	return hash
  1627  }