golang.org/x/tools@v0.21.0/internal/refactor/inline/inline.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 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/ast" 11 "go/constant" 12 "go/format" 13 "go/parser" 14 "go/token" 15 "go/types" 16 pathpkg "path" 17 "reflect" 18 "strconv" 19 "strings" 20 21 "golang.org/x/tools/go/ast/astutil" 22 "golang.org/x/tools/go/types/typeutil" 23 "golang.org/x/tools/imports" 24 internalastutil "golang.org/x/tools/internal/astutil" 25 "golang.org/x/tools/internal/typeparams" 26 ) 27 28 // A Caller describes the function call and its enclosing context. 29 // 30 // The client is responsible for populating this struct and passing it to Inline. 31 type Caller struct { 32 Fset *token.FileSet 33 Types *types.Package 34 Info *types.Info 35 File *ast.File 36 Call *ast.CallExpr 37 Content []byte // source of file containing 38 39 path []ast.Node // path from call to root of file syntax tree 40 enclosingFunc *ast.FuncDecl // top-level function/method enclosing the call, if any 41 } 42 43 // Options specifies parameters affecting the inliner algorithm. 44 // All fields are optional. 45 type Options struct { 46 Logf func(string, ...any) // log output function, records decision-making process 47 IgnoreEffects bool // ignore potential side effects of arguments (unsound) 48 } 49 50 // Result holds the result of code transformation. 51 type Result struct { 52 Content []byte // formatted, transformed content of caller file 53 Literalized bool // chosen strategy replaced callee() with func(){...}() 54 55 // TODO(adonovan): provide an API for clients that want structured 56 // output: a list of import additions and deletions plus one or more 57 // localized diffs (or even AST transformations, though ownership and 58 // mutation are tricky) near the call site. 59 } 60 61 // Inline inlines the called function (callee) into the function call (caller) 62 // and returns the updated, formatted content of the caller source file. 63 // 64 // Inline does not mutate any public fields of Caller or Callee. 65 func Inline(caller *Caller, callee *Callee, opts *Options) (*Result, error) { 66 copy := *opts // shallow copy 67 opts = © 68 // Set default options. 69 if opts.Logf == nil { 70 opts.Logf = func(string, ...any) {} 71 } 72 73 st := &state{ 74 caller: caller, 75 callee: callee, 76 opts: opts, 77 } 78 return st.inline() 79 } 80 81 // state holds the working state of the inliner. 82 type state struct { 83 caller *Caller 84 callee *Callee 85 opts *Options 86 } 87 88 func (st *state) inline() (*Result, error) { 89 logf, caller, callee := st.opts.Logf, st.caller, st.callee 90 91 logf("inline %s @ %v", 92 debugFormatNode(caller.Fset, caller.Call), 93 caller.Fset.PositionFor(caller.Call.Lparen, false)) 94 95 if !consistentOffsets(caller) { 96 return nil, fmt.Errorf("internal error: caller syntax positions are inconsistent with file content (did you forget to use FileSet.PositionFor when computing the file name?)") 97 } 98 99 // TODO(adonovan): use go1.21's ast.IsGenerated. 100 // Break the string literal so we can use inlining in this file. :) 101 if bytes.Contains(caller.Content, []byte("// Code generated by "+"cmd/cgo; DO NOT EDIT.")) { 102 return nil, fmt.Errorf("cannot inline calls from files that import \"C\"") 103 } 104 105 res, err := st.inlineCall() 106 if err != nil { 107 return nil, err 108 } 109 110 // Replace the call (or some node that encloses it) by new syntax. 111 assert(res.old != nil, "old is nil") 112 assert(res.new != nil, "new is nil") 113 114 // A single return operand inlined to a unary 115 // expression context may need parens. Otherwise: 116 // func two() int { return 1+1 } 117 // print(-two()) => print(-1+1) // oops! 118 // 119 // Usually it is not necessary to insert ParenExprs 120 // as the formatter is smart enough to insert them as 121 // needed by the context. But the res.{old,new} 122 // substitution is done by formatting res.new in isolation 123 // and then splicing its text over res.old, so the 124 // formatter doesn't see the parent node and cannot do 125 // the right thing. (One solution would be to always 126 // format the enclosing node of old, but that requires 127 // non-lossy comment handling, #20744.) 128 // 129 // So, we must analyze the call's context 130 // to see whether ambiguity is possible. 131 // For example, if the context is x[y:z], then 132 // the x subtree is subject to precedence ambiguity 133 // (replacing x by p+q would give p+q[y:z] which is wrong) 134 // but the y and z subtrees are safe. 135 if needsParens(caller.path, res.old, res.new) { 136 res.new = &ast.ParenExpr{X: res.new.(ast.Expr)} 137 } 138 139 // Some reduction strategies return a new block holding the 140 // callee's statements. The block's braces may be elided when 141 // there is no conflict between names declared in the block 142 // with those declared by the parent block, and no risk of 143 // a caller's goto jumping forward across a declaration. 144 // 145 // This elision is only safe when the ExprStmt is beneath a 146 // BlockStmt, CaseClause.Body, or CommClause.Body; 147 // (see "statement theory"). 148 // 149 // The inlining analysis may have already determined that eliding braces is 150 // safe. Otherwise, we analyze its safety here. 151 elideBraces := res.elideBraces 152 if !elideBraces { 153 if newBlock, ok := res.new.(*ast.BlockStmt); ok { 154 i := nodeIndex(caller.path, res.old) 155 parent := caller.path[i+1] 156 var body []ast.Stmt 157 switch parent := parent.(type) { 158 case *ast.BlockStmt: 159 body = parent.List 160 case *ast.CommClause: 161 body = parent.Body 162 case *ast.CaseClause: 163 body = parent.Body 164 } 165 if body != nil { 166 callerNames := declares(body) 167 168 // If BlockStmt is a function body, 169 // include its receiver, params, and results. 170 addFieldNames := func(fields *ast.FieldList) { 171 if fields != nil { 172 for _, field := range fields.List { 173 for _, id := range field.Names { 174 callerNames[id.Name] = true 175 } 176 } 177 } 178 } 179 switch f := caller.path[i+2].(type) { 180 case *ast.FuncDecl: 181 addFieldNames(f.Recv) 182 addFieldNames(f.Type.Params) 183 addFieldNames(f.Type.Results) 184 case *ast.FuncLit: 185 addFieldNames(f.Type.Params) 186 addFieldNames(f.Type.Results) 187 } 188 189 if len(callerLabels(caller.path)) > 0 { 190 // TODO(adonovan): be more precise and reject 191 // only forward gotos across the inlined block. 192 logf("keeping block braces: caller uses control labels") 193 } else if intersects(declares(newBlock.List), callerNames) { 194 logf("keeping block braces: avoids name conflict") 195 } else { 196 elideBraces = true 197 } 198 } 199 } 200 } 201 202 // Don't call replaceNode(caller.File, res.old, res.new) 203 // as it mutates the caller's syntax tree. 204 // Instead, splice the file, replacing the extent of the "old" 205 // node by a formatting of the "new" node, and re-parse. 206 // We'll fix up the imports on this new tree, and format again. 207 var f *ast.File 208 { 209 start := offsetOf(caller.Fset, res.old.Pos()) 210 end := offsetOf(caller.Fset, res.old.End()) 211 var out bytes.Buffer 212 out.Write(caller.Content[:start]) 213 // TODO(adonovan): might it make more sense to use 214 // callee.Fset when formatting res.new? 215 // The new tree is a mix of (cloned) caller nodes for 216 // the argument expressions and callee nodes for the 217 // function body. In essence the question is: which 218 // is more likely to have comments? 219 // Usually the callee body will be larger and more 220 // statement-heavy than the arguments, but a 221 // strategy may widen the scope of the replacement 222 // (res.old) from CallExpr to, say, its enclosing 223 // block, so the caller nodes dominate. 224 // Precise comment handling would make this a 225 // non-issue. Formatting wouldn't really need a 226 // FileSet at all. 227 if elideBraces { 228 for i, stmt := range res.new.(*ast.BlockStmt).List { 229 if i > 0 { 230 out.WriteByte('\n') 231 } 232 if err := format.Node(&out, caller.Fset, stmt); err != nil { 233 return nil, err 234 } 235 } 236 } else { 237 if err := format.Node(&out, caller.Fset, res.new); err != nil { 238 return nil, err 239 } 240 } 241 out.Write(caller.Content[end:]) 242 const mode = parser.ParseComments | parser.SkipObjectResolution | parser.AllErrors 243 f, err = parser.ParseFile(caller.Fset, "callee.go", &out, mode) 244 if err != nil { 245 // Something has gone very wrong. 246 logf("failed to parse <<%s>>", &out) // debugging 247 return nil, err 248 } 249 } 250 251 // Add new imports. 252 // 253 // Insert new imports after last existing import, 254 // to avoid migration of pre-import comments. 255 // The imports will be organized below. 256 if len(res.newImports) > 0 { 257 var importDecl *ast.GenDecl 258 if len(f.Imports) > 0 { 259 // Append specs to existing import decl 260 importDecl = f.Decls[0].(*ast.GenDecl) 261 } else { 262 // Insert new import decl. 263 importDecl = &ast.GenDecl{Tok: token.IMPORT} 264 f.Decls = prepend[ast.Decl](importDecl, f.Decls...) 265 } 266 for _, imp := range res.newImports { 267 // Check that the new imports are accessible. 268 path, _ := strconv.Unquote(imp.spec.Path.Value) 269 if !canImport(caller.Types.Path(), path) { 270 return nil, fmt.Errorf("can't inline function %v as its body refers to inaccessible package %q", callee, path) 271 } 272 importDecl.Specs = append(importDecl.Specs, imp.spec) 273 } 274 } 275 276 var out bytes.Buffer 277 if err := format.Node(&out, caller.Fset, f); err != nil { 278 return nil, err 279 } 280 newSrc := out.Bytes() 281 282 // Remove imports that are no longer referenced. 283 // 284 // It ought to be possible to compute the set of PkgNames used 285 // by the "old" code, compute the free identifiers of the 286 // "new" code using a syntax-only (no go/types) algorithm, and 287 // see if the reduction in the number of uses of any PkgName 288 // equals the number of times it appears in caller.Info.Uses, 289 // indicating that it is no longer referenced by res.new. 290 // 291 // However, the notorious ambiguity of resolving T{F: 0} makes this 292 // unreliable: without types, we can't tell whether F refers to 293 // a field of struct T, or a package-level const/var of a 294 // dot-imported (!) package. 295 // 296 // So, for now, we run imports.Process, which is 297 // unsatisfactory as it has to run the go command, and it 298 // looks at the user's module cache state--unnecessarily, 299 // since this step cannot add new imports. 300 // 301 // TODO(adonovan): replace with a simpler implementation since 302 // all the necessary imports are present but merely untidy. 303 // That will be faster, and also less prone to nondeterminism 304 // if there are bugs in our logic for import maintenance. 305 // 306 // However, golang.org/x/tools/internal/imports.ApplyFixes is 307 // too simple as it requires the caller to have figured out 308 // all the logical edits. In our case, we know all the new 309 // imports that are needed (see newImports), each of which can 310 // be specified as: 311 // 312 // &imports.ImportFix{ 313 // StmtInfo: imports.ImportInfo{path, name, 314 // IdentName: name, 315 // FixType: imports.AddImport, 316 // } 317 // 318 // but we don't know which imports are made redundant by the 319 // inlining itself. For example, inlining a call to 320 // fmt.Println may make the "fmt" import redundant. 321 // 322 // Also, both imports.Process and internal/imports.ApplyFixes 323 // reformat the entire file, which is not ideal for clients 324 // such as gopls. (That said, the point of a canonical format 325 // is arguably that any tool can reformat as needed without 326 // this being inconvenient.) 327 // 328 // We could invoke imports.Process and parse its result, 329 // compare against the original AST, compute a list of import 330 // fixes, and return that too. 331 332 // Recompute imports only if there were existing ones. 333 if len(f.Imports) > 0 { 334 formatted, err := imports.Process("output", newSrc, nil) 335 if err != nil { 336 logf("cannot reformat: %v <<%s>>", err, &out) 337 return nil, err // cannot reformat (a bug?) 338 } 339 newSrc = formatted 340 } 341 342 literalized := false 343 if call, ok := res.new.(*ast.CallExpr); ok && is[*ast.FuncLit](call.Fun) { 344 literalized = true 345 } 346 347 return &Result{ 348 Content: newSrc, 349 Literalized: literalized, 350 }, nil 351 352 } 353 354 type newImport struct { 355 pkgName string 356 spec *ast.ImportSpec 357 } 358 359 type inlineCallResult struct { 360 newImports []newImport 361 // If elideBraces is set, old is an ast.Stmt and new is an ast.BlockStmt to 362 // be spliced in. This allows the inlining analysis to assert that inlining 363 // the block is OK; if elideBraces is unset and old is an ast.Stmt and new is 364 // an ast.BlockStmt, braces may still be elided if the post-processing 365 // analysis determines that it is safe to do so. 366 // 367 // Ideally, it would not be necessary for the inlining analysis to "reach 368 // through" to the post-processing pass in this way. Instead, inlining could 369 // just set old to be an ast.BlockStmt and rewrite the entire BlockStmt, but 370 // unfortunately in order to preserve comments, it is important that inlining 371 // replace as little syntax as possible. 372 elideBraces bool 373 old, new ast.Node // e.g. replace call expr by callee function body expression 374 } 375 376 // inlineCall returns a pair of an old node (the call, or something 377 // enclosing it) and a new node (its replacement, which may be a 378 // combination of caller, callee, and new nodes), along with the set 379 // of new imports needed. 380 // 381 // TODO(adonovan): rethink the 'result' interface. The assumption of a 382 // one-to-one replacement seems fragile. One can easily imagine the 383 // transformation replacing the call and adding new variable 384 // declarations, for example, or replacing a call statement by zero or 385 // many statements.) 386 // 387 // TODO(adonovan): in earlier drafts, the transformation was expressed 388 // by splicing substrings of the two source files because syntax 389 // trees don't preserve comments faithfully (see #20744), but such 390 // transformations don't compose. The current implementation is 391 // tree-based but is very lossy wrt comments. It would make a good 392 // candidate for evaluating an alternative fully self-contained tree 393 // representation, such as any proposed solution to #20744, or even 394 // dst or some private fork of go/ast.) 395 func (st *state) inlineCall() (*inlineCallResult, error) { 396 logf, caller, callee := st.opts.Logf, st.caller, &st.callee.impl 397 398 checkInfoFields(caller.Info) 399 400 // Inlining of dynamic calls is not currently supported, 401 // even for local closure calls. (This would be a lot of work.) 402 calleeSymbol := typeutil.StaticCallee(caller.Info, caller.Call) 403 if calleeSymbol == nil { 404 // e.g. interface method 405 return nil, fmt.Errorf("cannot inline: not a static function call") 406 } 407 408 // Reject cross-package inlining if callee has 409 // free references to unexported symbols. 410 samePkg := caller.Types.Path() == callee.PkgPath 411 if !samePkg && len(callee.Unexported) > 0 { 412 return nil, fmt.Errorf("cannot inline call to %s because body refers to non-exported %s", 413 callee.Name, callee.Unexported[0]) 414 } 415 416 // -- analyze callee's free references in caller context -- 417 418 // Compute syntax path enclosing Call, innermost first (Path[0]=Call), 419 // and outermost enclosing function, if any. 420 caller.path, _ = astutil.PathEnclosingInterval(caller.File, caller.Call.Pos(), caller.Call.End()) 421 for _, n := range caller.path { 422 if decl, ok := n.(*ast.FuncDecl); ok { 423 caller.enclosingFunc = decl 424 break 425 } 426 } 427 428 // If call is within a function, analyze all its 429 // local vars for the "single assignment" property. 430 // (Taking the address &v counts as a potential assignment.) 431 var assign1 func(v *types.Var) bool // reports whether v a single-assignment local var 432 { 433 updatedLocals := make(map[*types.Var]bool) 434 if caller.enclosingFunc != nil { 435 escape(caller.Info, caller.enclosingFunc, func(v *types.Var, _ bool) { 436 updatedLocals[v] = true 437 }) 438 logf("multiple-assignment vars: %v", updatedLocals) 439 } 440 assign1 = func(v *types.Var) bool { return !updatedLocals[v] } 441 } 442 443 // import map, initially populated with caller imports. 444 // 445 // For simplicity we ignore existing dot imports, so that a 446 // qualified identifier (QI) in the callee is always 447 // represented by a QI in the caller, allowing us to treat a 448 // QI like a selection on a package name. 449 importMap := make(map[string][]string) // maps package path to local name(s) 450 for _, imp := range caller.File.Imports { 451 if pkgname, ok := importedPkgName(caller.Info, imp); ok && 452 pkgname.Name() != "." && 453 pkgname.Name() != "_" { 454 path := pkgname.Imported().Path() 455 importMap[path] = append(importMap[path], pkgname.Name()) 456 } 457 } 458 459 // localImportName returns the local name for a given imported package path. 460 var newImports []newImport 461 localImportName := func(obj *object) string { 462 // Does an import exist? 463 for _, name := range importMap[obj.PkgPath] { 464 // Check that either the import preexisted, 465 // or that it was newly added (no PkgName) but is not shadowed, 466 // either in the callee (shadows) or caller (caller.lookup). 467 if !obj.Shadow[name] { 468 found := caller.lookup(name) 469 if is[*types.PkgName](found) || found == nil { 470 return name 471 } 472 } 473 } 474 475 newlyAdded := func(name string) bool { 476 for _, new := range newImports { 477 if new.pkgName == name { 478 return true 479 } 480 } 481 return false 482 } 483 484 // import added by callee 485 // 486 // Choose local PkgName based on last segment of 487 // package path plus, if needed, a numeric suffix to 488 // ensure uniqueness. 489 // 490 // "init" is not a legal PkgName. 491 // 492 // TODO(rfindley): is it worth preserving local package names for callee 493 // imports? Are they likely to be better or worse than the name we choose 494 // here? 495 base := obj.PkgName 496 name := base 497 for n := 0; obj.Shadow[name] || caller.lookup(name) != nil || newlyAdded(name) || name == "init"; n++ { 498 name = fmt.Sprintf("%s%d", base, n) 499 } 500 501 logf("adding import %s %q", name, obj.PkgPath) 502 spec := &ast.ImportSpec{ 503 Path: &ast.BasicLit{ 504 Kind: token.STRING, 505 Value: strconv.Quote(obj.PkgPath), 506 }, 507 } 508 // Use explicit pkgname (out of necessity) when it differs from the declared name, 509 // or (for good style) when it differs from base(pkgpath). 510 if name != obj.PkgName || name != pathpkg.Base(obj.PkgPath) { 511 spec.Name = makeIdent(name) 512 } 513 newImports = append(newImports, newImport{ 514 pkgName: name, 515 spec: spec, 516 }) 517 importMap[obj.PkgPath] = append(importMap[obj.PkgPath], name) 518 return name 519 } 520 521 // Compute the renaming of the callee's free identifiers. 522 objRenames := make([]ast.Expr, len(callee.FreeObjs)) // nil => no change 523 for i, obj := range callee.FreeObjs { 524 // obj is a free object of the callee. 525 // 526 // Possible cases are: 527 // - builtin function, type, or value (e.g. nil, zero) 528 // => check not shadowed in caller. 529 // - package-level var/func/const/types 530 // => same package: check not shadowed in caller. 531 // => otherwise: import other package, form a qualified identifier. 532 // (Unexported cross-package references were rejected already.) 533 // - type parameter 534 // => not yet supported 535 // - pkgname 536 // => import other package and use its local name. 537 // 538 // There can be no free references to labels, fields, or methods. 539 540 // Note that we must consider potential shadowing both 541 // at the caller side (caller.lookup) and, when 542 // choosing new PkgNames, within the callee (obj.shadow). 543 544 var newName ast.Expr 545 if obj.Kind == "pkgname" { 546 // Use locally appropriate import, creating as needed. 547 newName = makeIdent(localImportName(&obj)) // imported package 548 } else if !obj.ValidPos { 549 // Built-in function, type, or value (e.g. nil, zero): 550 // check not shadowed at caller. 551 found := caller.lookup(obj.Name) // always finds something 552 if found.Pos().IsValid() { 553 return nil, fmt.Errorf("cannot inline, because the callee refers to built-in %q, which in the caller is shadowed by a %s (declared at line %d)", 554 obj.Name, objectKind(found), 555 caller.Fset.PositionFor(found.Pos(), false).Line) 556 } 557 558 } else { 559 // Must be reference to package-level var/func/const/type, 560 // since type parameters are not yet supported. 561 qualify := false 562 if obj.PkgPath == callee.PkgPath { 563 // reference within callee package 564 if samePkg { 565 // Caller and callee are in same package. 566 // Check caller has not shadowed the decl. 567 // 568 // This may fail if the callee is "fake", such as for signature 569 // refactoring where the callee is modified to be a trivial wrapper 570 // around the refactored signature. 571 found := caller.lookup(obj.Name) 572 if found != nil && !isPkgLevel(found) { 573 return nil, fmt.Errorf("cannot inline, because the callee refers to %s %q, which in the caller is shadowed by a %s (declared at line %d)", 574 obj.Kind, obj.Name, 575 objectKind(found), 576 caller.Fset.PositionFor(found.Pos(), false).Line) 577 } 578 } else { 579 // Cross-package reference. 580 qualify = true 581 } 582 } else { 583 // Reference to a package-level declaration 584 // in another package, without a qualified identifier: 585 // it must be a dot import. 586 qualify = true 587 } 588 589 // Form a qualified identifier, pkg.Name. 590 if qualify { 591 pkgName := localImportName(&obj) 592 newName = &ast.SelectorExpr{ 593 X: makeIdent(pkgName), 594 Sel: makeIdent(obj.Name), 595 } 596 } 597 } 598 objRenames[i] = newName 599 } 600 601 res := &inlineCallResult{ 602 newImports: newImports, 603 } 604 605 // Parse callee function declaration. 606 calleeFset, calleeDecl, err := parseCompact(callee.Content) 607 if err != nil { 608 return nil, err // "can't happen" 609 } 610 611 // replaceCalleeID replaces an identifier in the callee. 612 // The replacement tree must not belong to the caller; use cloneNode as needed. 613 replaceCalleeID := func(offset int, repl ast.Expr) { 614 id := findIdent(calleeDecl, calleeDecl.Pos()+token.Pos(offset)) 615 logf("- replace id %q @ #%d to %q", id.Name, offset, debugFormatNode(calleeFset, repl)) 616 replaceNode(calleeDecl, id, repl) 617 } 618 619 // Generate replacements for each free identifier. 620 // (The same tree may be spliced in multiple times, resulting in a DAG.) 621 for _, ref := range callee.FreeRefs { 622 if repl := objRenames[ref.Object]; repl != nil { 623 replaceCalleeID(ref.Offset, repl) 624 } 625 } 626 627 // Gather the effective call arguments, including the receiver. 628 // Later, elements will be eliminated (=> nil) by parameter substitution. 629 args, err := st.arguments(caller, calleeDecl, assign1) 630 if err != nil { 631 return nil, err // e.g. implicit field selection cannot be made explicit 632 } 633 634 // Gather effective parameter tuple, including the receiver if any. 635 // Simplify variadic parameters to slices (in all cases but one). 636 var params []*parameter // including receiver; nil => parameter substituted 637 { 638 sig := calleeSymbol.Type().(*types.Signature) 639 if sig.Recv() != nil { 640 params = append(params, ¶meter{ 641 obj: sig.Recv(), 642 fieldType: calleeDecl.Recv.List[0].Type, 643 info: callee.Params[0], 644 }) 645 } 646 647 // Flatten the list of syntactic types. 648 var types []ast.Expr 649 for _, field := range calleeDecl.Type.Params.List { 650 if field.Names == nil { 651 types = append(types, field.Type) 652 } else { 653 for range field.Names { 654 types = append(types, field.Type) 655 } 656 } 657 } 658 659 for i := 0; i < sig.Params().Len(); i++ { 660 params = append(params, ¶meter{ 661 obj: sig.Params().At(i), 662 fieldType: types[i], 663 info: callee.Params[len(params)], 664 }) 665 } 666 667 // Variadic function? 668 // 669 // There are three possible types of call: 670 // - ordinary f(a1, ..., aN) 671 // - ellipsis f(a1, ..., slice...) 672 // - spread f(recv?, g()) where g() is a tuple. 673 // The first two are desugared to non-variadic calls 674 // with an ordinary slice parameter; 675 // the third is tricky and cannot be reduced, and (if 676 // a receiver is present) cannot even be literalized. 677 // Fortunately it is vanishingly rare. 678 // 679 // TODO(adonovan): extract this to a function. 680 if sig.Variadic() { 681 lastParam := last(params) 682 if len(args) > 0 && last(args).spread { 683 // spread call to variadic: tricky 684 lastParam.variadic = true 685 } else { 686 // ordinary/ellipsis call to variadic 687 688 // simplify decl: func(T...) -> func([]T) 689 lastParamField := last(calleeDecl.Type.Params.List) 690 lastParamField.Type = &ast.ArrayType{ 691 Elt: lastParamField.Type.(*ast.Ellipsis).Elt, 692 } 693 694 if caller.Call.Ellipsis.IsValid() { 695 // ellipsis call: f(slice...) -> f(slice) 696 // nop 697 } else { 698 // ordinary call: f(a1, ... aN) -> f([]T{a1, ..., aN}) 699 n := len(params) - 1 700 ordinary, extra := args[:n], args[n:] 701 var elts []ast.Expr 702 pure, effects := true, false 703 for _, arg := range extra { 704 elts = append(elts, arg.expr) 705 pure = pure && arg.pure 706 effects = effects || arg.effects 707 } 708 args = append(ordinary, &argument{ 709 expr: &ast.CompositeLit{ 710 Type: lastParamField.Type, 711 Elts: elts, 712 }, 713 typ: lastParam.obj.Type(), 714 constant: nil, 715 pure: pure, 716 effects: effects, 717 duplicable: false, 718 freevars: nil, // not needed 719 }) 720 } 721 } 722 } 723 } 724 725 // Log effective arguments. 726 for i, arg := range args { 727 logf("arg #%d: %s pure=%t effects=%t duplicable=%t free=%v type=%v", 728 i, debugFormatNode(caller.Fset, arg.expr), 729 arg.pure, arg.effects, arg.duplicable, arg.freevars, arg.typ) 730 } 731 732 // Note: computation below should be expressed in terms of 733 // the args and params slices, not the raw material. 734 735 // Perform parameter substitution. 736 // May eliminate some elements of params/args. 737 substitute(logf, caller, params, args, callee.Effects, callee.Falcon, replaceCalleeID) 738 739 // Update the callee's signature syntax. 740 updateCalleeParams(calleeDecl, params) 741 742 // Create a var (param = arg; ...) decl for use by some strategies. 743 bindingDecl := createBindingDecl(logf, caller, args, calleeDecl, callee.Results) 744 745 var remainingArgs []ast.Expr 746 for _, arg := range args { 747 if arg != nil { 748 remainingArgs = append(remainingArgs, arg.expr) 749 } 750 } 751 752 // -- let the inlining strategies begin -- 753 // 754 // When we commit to a strategy, we log a message of the form: 755 // 756 // "strategy: reduce expr-context call to { return expr }" 757 // 758 // This is a terse way of saying: 759 // 760 // we plan to reduce a call 761 // that appears in expression context 762 // to a function whose body is of the form { return expr } 763 764 // TODO(adonovan): split this huge function into a sequence of 765 // function calls with an error sentinel that means "try the 766 // next strategy", and make sure each strategy writes to the 767 // log the reason it didn't match. 768 769 // Special case: eliminate a call to a function whose body is empty. 770 // (=> callee has no results and caller is a statement.) 771 // 772 // func f(params) {} 773 // f(args) 774 // => _, _ = args 775 // 776 if len(calleeDecl.Body.List) == 0 { 777 logf("strategy: reduce call to empty body") 778 779 // Evaluate the arguments for effects and delete the call entirely. 780 stmt := callStmt(caller.path, false) // cannot fail 781 res.old = stmt 782 if nargs := len(remainingArgs); nargs > 0 { 783 // Emit "_, _ = args" to discard results. 784 785 // TODO(adonovan): if args is the []T{a1, ..., an} 786 // literal synthesized during variadic simplification, 787 // consider unwrapping it to its (pure) elements. 788 // Perhaps there's no harm doing this for any slice literal. 789 790 // Make correction for spread calls 791 // f(g()) or recv.f(g()) where g() is a tuple. 792 if last := last(args); last != nil && last.spread { 793 nspread := last.typ.(*types.Tuple).Len() 794 if len(args) > 1 { // [recv, g()] 795 // A single AssignStmt cannot discard both, so use a 2-spec var decl. 796 res.new = &ast.GenDecl{ 797 Tok: token.VAR, 798 Specs: []ast.Spec{ 799 &ast.ValueSpec{ 800 Names: []*ast.Ident{makeIdent("_")}, 801 Values: []ast.Expr{args[0].expr}, 802 }, 803 &ast.ValueSpec{ 804 Names: blanks[*ast.Ident](nspread), 805 Values: []ast.Expr{args[1].expr}, 806 }, 807 }, 808 } 809 return res, nil 810 } 811 812 // Sole argument is spread call. 813 nargs = nspread 814 } 815 816 res.new = &ast.AssignStmt{ 817 Lhs: blanks[ast.Expr](nargs), 818 Tok: token.ASSIGN, 819 Rhs: remainingArgs, 820 } 821 822 } else { 823 // No remaining arguments: delete call statement entirely 824 res.new = &ast.EmptyStmt{} 825 } 826 return res, nil 827 } 828 829 // If all parameters have been substituted and no result 830 // variable is referenced, we don't need a binding decl. 831 // This may enable better reduction strategies. 832 allResultsUnreferenced := forall(callee.Results, func(i int, r *paramInfo) bool { return len(r.Refs) == 0 }) 833 needBindingDecl := !allResultsUnreferenced || 834 exists(params, func(i int, p *parameter) bool { return p != nil }) 835 836 // The two strategies below overlap for a tail call of {return exprs}: 837 // The expr-context reduction is nice because it keeps the 838 // caller's return stmt and merely switches its operand, 839 // without introducing a new block, but it doesn't work with 840 // implicit return conversions. 841 // 842 // TODO(adonovan): unify these cases more cleanly, allowing return- 843 // operand replacement and implicit conversions, by adding 844 // conversions around each return operand (if not a spread return). 845 846 // Special case: call to { return exprs }. 847 // 848 // Reduces to: 849 // { var (bindings); _, _ = exprs } 850 // or _, _ = exprs 851 // or expr 852 // 853 // If: 854 // - the body is just "return expr" with trivial implicit conversions, 855 // or the caller's return type matches the callee's, 856 // - all parameters and result vars can be eliminated 857 // or replaced by a binding decl, 858 // then the call expression can be replaced by the 859 // callee's body expression, suitably substituted. 860 if len(calleeDecl.Body.List) == 1 && 861 is[*ast.ReturnStmt](calleeDecl.Body.List[0]) && 862 len(calleeDecl.Body.List[0].(*ast.ReturnStmt).Results) > 0 { // not a bare return 863 results := calleeDecl.Body.List[0].(*ast.ReturnStmt).Results 864 865 parent, grandparent := callContext(caller.path) 866 867 // statement context 868 if stmt, ok := parent.(*ast.ExprStmt); ok && 869 (!needBindingDecl || bindingDecl != nil) { 870 logf("strategy: reduce stmt-context call to { return exprs }") 871 clearPositions(calleeDecl.Body) 872 873 if callee.ValidForCallStmt { 874 logf("callee body is valid as statement") 875 // Inv: len(results) == 1 876 if !needBindingDecl { 877 // Reduces to: expr 878 res.old = caller.Call 879 res.new = results[0] 880 } else { 881 // Reduces to: { var (bindings); expr } 882 res.old = stmt 883 res.new = &ast.BlockStmt{ 884 List: []ast.Stmt{ 885 bindingDecl.stmt, 886 &ast.ExprStmt{X: results[0]}, 887 }, 888 } 889 } 890 } else { 891 logf("callee body is not valid as statement") 892 // The call is a standalone statement, but the 893 // callee body is not suitable as a standalone statement 894 // (f() or <-ch), explicitly discard the results: 895 // Reduces to: _, _ = exprs 896 discard := &ast.AssignStmt{ 897 Lhs: blanks[ast.Expr](callee.NumResults), 898 Tok: token.ASSIGN, 899 Rhs: results, 900 } 901 res.old = stmt 902 if !needBindingDecl { 903 // Reduces to: _, _ = exprs 904 res.new = discard 905 } else { 906 // Reduces to: { var (bindings); _, _ = exprs } 907 res.new = &ast.BlockStmt{ 908 List: []ast.Stmt{ 909 bindingDecl.stmt, 910 discard, 911 }, 912 } 913 } 914 } 915 return res, nil 916 } 917 918 // Assignment context. 919 // 920 // If there is no binding decl, or if the binding decl declares no names, 921 // an assignment a, b := f() can be reduced to a, b := x, y. 922 if stmt, ok := parent.(*ast.AssignStmt); ok && 923 is[*ast.BlockStmt](grandparent) && 924 (!needBindingDecl || (bindingDecl != nil && len(bindingDecl.names) == 0)) { 925 926 // Reduces to: { var (bindings); lhs... := rhs... } 927 if newStmts, ok := st.assignStmts(stmt, results); ok { 928 logf("strategy: reduce assign-context call to { return exprs }") 929 clearPositions(calleeDecl.Body) 930 931 block := &ast.BlockStmt{ 932 List: newStmts, 933 } 934 if needBindingDecl { 935 block.List = prepend(bindingDecl.stmt, block.List...) 936 } 937 938 // assignStmts does not introduce new bindings, and replacing an 939 // assignment only works if the replacement occurs in the same scope. 940 // Therefore, we must ensure that braces are elided. 941 res.elideBraces = true 942 res.old = stmt 943 res.new = block 944 return res, nil 945 } 946 } 947 948 // expression context 949 if !needBindingDecl { 950 clearPositions(calleeDecl.Body) 951 952 anyNonTrivialReturns := hasNonTrivialReturn(callee.Returns) 953 954 if callee.NumResults == 1 { 955 logf("strategy: reduce expr-context call to { return expr }") 956 // (includes some simple tail-calls) 957 958 // Make implicit return conversion explicit. 959 if anyNonTrivialReturns { 960 results[0] = convert(calleeDecl.Type.Results.List[0].Type, results[0]) 961 } 962 963 res.old = caller.Call 964 res.new = results[0] 965 return res, nil 966 967 } else if !anyNonTrivialReturns { 968 logf("strategy: reduce spread-context call to { return expr }") 969 // There is no general way to reify conversions in a spread 970 // return, hence the requirement above. 971 // 972 // TODO(adonovan): allow this reduction when no 973 // conversion is required by the context. 974 975 // The call returns multiple results but is 976 // not a standalone call statement. It must 977 // be the RHS of a spread assignment: 978 // var x, y = f() 979 // x, y := f() 980 // x, y = f() 981 // or the sole argument to a spread call: 982 // printf(f()) 983 // or spread return statement: 984 // return f() 985 res.old = parent 986 switch context := parent.(type) { 987 case *ast.AssignStmt: 988 // Inv: the call must be in Rhs[0], not Lhs. 989 assign := shallowCopy(context) 990 assign.Rhs = results 991 res.new = assign 992 case *ast.ValueSpec: 993 // Inv: the call must be in Values[0], not Names. 994 spec := shallowCopy(context) 995 spec.Values = results 996 res.new = spec 997 case *ast.CallExpr: 998 // Inv: the call must be in Args[0], not Fun. 999 call := shallowCopy(context) 1000 call.Args = results 1001 res.new = call 1002 case *ast.ReturnStmt: 1003 // Inv: the call must be Results[0]. 1004 ret := shallowCopy(context) 1005 ret.Results = results 1006 res.new = ret 1007 default: 1008 return nil, fmt.Errorf("internal error: unexpected context %T for spread call", context) 1009 } 1010 return res, nil 1011 } 1012 } 1013 } 1014 1015 // Special case: tail-call. 1016 // 1017 // Inlining: 1018 // return f(args) 1019 // where: 1020 // func f(params) (results) { body } 1021 // reduces to: 1022 // { var (bindings); body } 1023 // { body } 1024 // so long as: 1025 // - all parameters can be eliminated or replaced by a binding decl, 1026 // - call is a tail-call; 1027 // - all returns in body have trivial result conversions, 1028 // or the caller's return type matches the callee's, 1029 // - there is no label conflict; 1030 // - no result variable is referenced by name, 1031 // or implicitly by a bare return. 1032 // 1033 // The body may use defer, arbitrary control flow, and 1034 // multiple returns. 1035 // 1036 // TODO(adonovan): add a strategy for a 'void tail 1037 // call', i.e. a call statement prior to an (explicit 1038 // or implicit) return. 1039 parent, _ := callContext(caller.path) 1040 if ret, ok := parent.(*ast.ReturnStmt); ok && 1041 len(ret.Results) == 1 && 1042 tailCallSafeReturn(caller, calleeSymbol, callee) && 1043 !callee.HasBareReturn && 1044 (!needBindingDecl || bindingDecl != nil) && 1045 !hasLabelConflict(caller.path, callee.Labels) && 1046 allResultsUnreferenced { 1047 logf("strategy: reduce tail-call") 1048 body := calleeDecl.Body 1049 clearPositions(body) 1050 if needBindingDecl { 1051 body.List = prepend(bindingDecl.stmt, body.List...) 1052 } 1053 res.old = ret 1054 res.new = body 1055 return res, nil 1056 } 1057 1058 // Special case: call to void function 1059 // 1060 // Inlining: 1061 // f(args) 1062 // where: 1063 // func f(params) { stmts } 1064 // reduces to: 1065 // { var (bindings); stmts } 1066 // { stmts } 1067 // so long as: 1068 // - callee is a void function (no returns) 1069 // - callee does not use defer 1070 // - there is no label conflict between caller and callee 1071 // - all parameters and result vars can be eliminated 1072 // or replaced by a binding decl, 1073 // - caller ExprStmt is in unrestricted statement context. 1074 if stmt := callStmt(caller.path, true); stmt != nil && 1075 (!needBindingDecl || bindingDecl != nil) && 1076 !callee.HasDefer && 1077 !hasLabelConflict(caller.path, callee.Labels) && 1078 len(callee.Returns) == 0 { 1079 logf("strategy: reduce stmt-context call to { stmts }") 1080 body := calleeDecl.Body 1081 var repl ast.Stmt = body 1082 clearPositions(repl) 1083 if needBindingDecl { 1084 body.List = prepend(bindingDecl.stmt, body.List...) 1085 } 1086 res.old = stmt 1087 res.new = repl 1088 return res, nil 1089 } 1090 1091 // TODO(adonovan): parameterless call to { stmts; return expr } 1092 // from one of these contexts: 1093 // x, y = f() 1094 // x, y := f() 1095 // var x, y = f() 1096 // => 1097 // var (x T1, y T2); { stmts; x, y = expr } 1098 // 1099 // Because the params are no longer declared simultaneously 1100 // we need to check that (for example) x ∉ freevars(T2), 1101 // in addition to the usual checks for arg/result conversions, 1102 // complex control, etc. 1103 // Also test cases where expr is an n-ary call (spread returns). 1104 1105 // Literalization isn't quite infallible. 1106 // Consider a spread call to a method in which 1107 // no parameters are eliminated, e.g. 1108 // new(T).f(g()) 1109 // where 1110 // func (recv *T) f(x, y int) { body } 1111 // func g() (int, int) 1112 // This would be literalized to: 1113 // func (recv *T, x, y int) { body }(new(T), g()), 1114 // which is not a valid argument list because g() must appear alone. 1115 // Reject this case for now. 1116 if len(args) == 2 && args[0] != nil && args[1] != nil && is[*types.Tuple](args[1].typ) { 1117 return nil, fmt.Errorf("can't yet inline spread call to method") 1118 } 1119 1120 // Infallible general case: literalization. 1121 // 1122 // func(params) { body }(args) 1123 // 1124 logf("strategy: literalization") 1125 funcLit := &ast.FuncLit{ 1126 Type: calleeDecl.Type, 1127 Body: calleeDecl.Body, 1128 } 1129 1130 // Literalization can still make use of a binding 1131 // decl as it gives a more natural reading order: 1132 // 1133 // func() { var params = args; body }() 1134 // 1135 // TODO(adonovan): relax the allResultsUnreferenced requirement 1136 // by adding a parameter-only (no named results) binding decl. 1137 if bindingDecl != nil && allResultsUnreferenced { 1138 funcLit.Type.Params.List = nil 1139 remainingArgs = nil 1140 funcLit.Body.List = prepend(bindingDecl.stmt, funcLit.Body.List...) 1141 } 1142 1143 // Emit a new call to a function literal in place of 1144 // the callee name, with appropriate replacements. 1145 newCall := &ast.CallExpr{ 1146 Fun: funcLit, 1147 Ellipsis: token.NoPos, // f(slice...) is always simplified 1148 Args: remainingArgs, 1149 } 1150 clearPositions(newCall.Fun) 1151 res.old = caller.Call 1152 res.new = newCall 1153 return res, nil 1154 } 1155 1156 type argument struct { 1157 expr ast.Expr 1158 typ types.Type // may be tuple for sole non-receiver arg in spread call 1159 constant constant.Value // value of argument if constant 1160 spread bool // final arg is call() assigned to multiple params 1161 pure bool // expr is pure (doesn't read variables) 1162 effects bool // expr has effects (updates variables) 1163 duplicable bool // expr may be duplicated 1164 freevars map[string]bool // free names of expr 1165 substitutable bool // is candidate for substitution 1166 } 1167 1168 // arguments returns the effective arguments of the call. 1169 // 1170 // If the receiver argument and parameter have 1171 // different pointerness, make the "&" or "*" explicit. 1172 // 1173 // Also, if x.f() is shorthand for promoted method x.y.f(), 1174 // make the .y explicit in T.f(x.y, ...). 1175 // 1176 // Beware that: 1177 // 1178 // - a method can only be called through a selection, but only 1179 // the first of these two forms needs special treatment: 1180 // 1181 // expr.f(args) -> ([&*]expr, args) MethodVal 1182 // T.f(recv, args) -> ( expr, args) MethodExpr 1183 // 1184 // - the presence of a value in receiver-position in the call 1185 // is a property of the caller, not the callee. A method 1186 // (calleeDecl.Recv != nil) may be called like an ordinary 1187 // function. 1188 // 1189 // - the types.Signatures seen by the caller (from 1190 // StaticCallee) and by the callee (from decl type) 1191 // differ in this case. 1192 // 1193 // In a spread call f(g()), the sole ordinary argument g(), 1194 // always last in args, has a tuple type. 1195 // 1196 // We compute type-based predicates like pure, duplicable, 1197 // freevars, etc, now, before we start modifying syntax. 1198 func (st *state) arguments(caller *Caller, calleeDecl *ast.FuncDecl, assign1 func(*types.Var) bool) ([]*argument, error) { 1199 var args []*argument 1200 1201 callArgs := caller.Call.Args 1202 if calleeDecl.Recv != nil { 1203 sel := astutil.Unparen(caller.Call.Fun).(*ast.SelectorExpr) 1204 seln := caller.Info.Selections[sel] 1205 var recvArg ast.Expr 1206 switch seln.Kind() { 1207 case types.MethodVal: // recv.f(callArgs) 1208 recvArg = sel.X 1209 case types.MethodExpr: // T.f(recv, callArgs) 1210 recvArg = callArgs[0] 1211 callArgs = callArgs[1:] 1212 } 1213 if recvArg != nil { 1214 // Compute all the type-based predicates now, 1215 // before we start meddling with the syntax; 1216 // the meddling will update them. 1217 arg := &argument{ 1218 expr: recvArg, 1219 typ: caller.Info.TypeOf(recvArg), 1220 constant: caller.Info.Types[recvArg].Value, 1221 pure: pure(caller.Info, assign1, recvArg), 1222 effects: st.effects(caller.Info, recvArg), 1223 duplicable: duplicable(caller.Info, recvArg), 1224 freevars: freeVars(caller.Info, recvArg), 1225 } 1226 recvArg = nil // prevent accidental use 1227 1228 // Move receiver argument recv.f(args) to argument list f(&recv, args). 1229 args = append(args, arg) 1230 1231 // Make field selections explicit (recv.f -> recv.y.f), 1232 // updating arg.{expr,typ}. 1233 indices := seln.Index() 1234 for _, index := range indices[:len(indices)-1] { 1235 fld := typeparams.CoreType(typeparams.Deref(arg.typ)).(*types.Struct).Field(index) 1236 if fld.Pkg() != caller.Types && !fld.Exported() { 1237 return nil, fmt.Errorf("in %s, implicit reference to unexported field .%s cannot be made explicit", 1238 debugFormatNode(caller.Fset, caller.Call.Fun), 1239 fld.Name()) 1240 } 1241 if isPointer(arg.typ) { 1242 arg.pure = false // implicit *ptr operation => impure 1243 } 1244 arg.expr = &ast.SelectorExpr{ 1245 X: arg.expr, 1246 Sel: makeIdent(fld.Name()), 1247 } 1248 arg.typ = fld.Type() 1249 arg.duplicable = false 1250 } 1251 1252 // Make * or & explicit. 1253 argIsPtr := isPointer(arg.typ) 1254 paramIsPtr := isPointer(seln.Obj().Type().Underlying().(*types.Signature).Recv().Type()) 1255 if !argIsPtr && paramIsPtr { 1256 // &recv 1257 arg.expr = &ast.UnaryExpr{Op: token.AND, X: arg.expr} 1258 arg.typ = types.NewPointer(arg.typ) 1259 } else if argIsPtr && !paramIsPtr { 1260 // *recv 1261 arg.expr = &ast.StarExpr{X: arg.expr} 1262 arg.typ = typeparams.Deref(arg.typ) 1263 arg.duplicable = false 1264 arg.pure = false 1265 } 1266 } 1267 } 1268 for _, expr := range callArgs { 1269 tv := caller.Info.Types[expr] 1270 args = append(args, &argument{ 1271 expr: expr, 1272 typ: tv.Type, 1273 constant: tv.Value, 1274 spread: is[*types.Tuple](tv.Type), // => last 1275 pure: pure(caller.Info, assign1, expr), 1276 effects: st.effects(caller.Info, expr), 1277 duplicable: duplicable(caller.Info, expr), 1278 freevars: freeVars(caller.Info, expr), 1279 }) 1280 } 1281 1282 // Re-typecheck each constant argument expression in a neutral context. 1283 // 1284 // In a call such as func(int16){}(1), the type checker infers 1285 // the type "int16", not "untyped int", for the argument 1, 1286 // because it has incorporated information from the left-hand 1287 // side of the assignment implicit in parameter passing, but 1288 // of course in a different context, the expression 1 may have 1289 // a different type. 1290 // 1291 // So, we must use CheckExpr to recompute the type of the 1292 // argument in a neutral context to find its inherent type. 1293 // (This is arguably a bug in go/types, but I'm pretty certain 1294 // I requested it be this way long ago... -adonovan) 1295 // 1296 // This is only needed for constants. Other implicit 1297 // assignment conversions, such as unnamed-to-named struct or 1298 // chan to <-chan, do not result in the type-checker imposing 1299 // the LHS type on the RHS value. 1300 for _, arg := range args { 1301 if arg.constant == nil { 1302 continue 1303 } 1304 info := &types.Info{Types: make(map[ast.Expr]types.TypeAndValue)} 1305 if err := types.CheckExpr(caller.Fset, caller.Types, caller.Call.Pos(), arg.expr, info); err != nil { 1306 return nil, err 1307 } 1308 arg.typ = info.TypeOf(arg.expr) 1309 } 1310 1311 return args, nil 1312 } 1313 1314 type parameter struct { 1315 obj *types.Var // parameter var from caller's signature 1316 fieldType ast.Expr // syntax of type, from calleeDecl.Type.{Recv,Params} 1317 info *paramInfo // information from AnalyzeCallee 1318 variadic bool // (final) parameter is unsimplified ...T 1319 } 1320 1321 // substitute implements parameter elimination by substitution. 1322 // 1323 // It considers each parameter and its corresponding argument in turn 1324 // and evaluate these conditions: 1325 // 1326 // - the parameter is neither address-taken nor assigned; 1327 // - the argument is pure; 1328 // - if the parameter refcount is zero, the argument must 1329 // not contain the last use of a local var; 1330 // - if the parameter refcount is > 1, the argument must be duplicable; 1331 // - the argument (or types.Default(argument) if it's untyped) has 1332 // the same type as the parameter. 1333 // 1334 // If all conditions are met then the parameter can be substituted and 1335 // each reference to it replaced by the argument. In that case, the 1336 // replaceCalleeID function is called for each reference to the 1337 // parameter, and is provided with its relative offset and replacement 1338 // expression (argument), and the corresponding elements of params and 1339 // args are replaced by nil. 1340 func substitute(logf func(string, ...any), caller *Caller, params []*parameter, args []*argument, effects []int, falcon falconResult, replaceCalleeID func(offset int, repl ast.Expr)) { 1341 // Inv: 1342 // in calls to variadic, len(args) >= len(params)-1 1343 // in spread calls to non-variadic, len(args) < len(params) 1344 // in spread calls to variadic, len(args) <= len(params) 1345 // (In spread calls len(args) = 1, or 2 if call has receiver.) 1346 // Non-spread variadics have been simplified away already, 1347 // so the args[i] lookup is safe if we stop after the spread arg. 1348 next: 1349 for i, param := range params { 1350 arg := args[i] 1351 // Check argument against parameter. 1352 // 1353 // Beware: don't use types.Info on arg since 1354 // the syntax may be synthetic (not created by parser) 1355 // and thus lacking positions and types; 1356 // do it earlier (see pure/duplicable/freevars). 1357 1358 if arg.spread { 1359 // spread => last argument, but not always last parameter 1360 logf("keeping param %q and following ones: argument %s is spread", 1361 param.info.Name, debugFormatNode(caller.Fset, arg.expr)) 1362 return // give up 1363 } 1364 assert(!param.variadic, "unsimplified variadic parameter") 1365 if param.info.Escapes { 1366 logf("keeping param %q: escapes from callee", param.info.Name) 1367 continue 1368 } 1369 if param.info.Assigned { 1370 logf("keeping param %q: assigned by callee", param.info.Name) 1371 continue // callee needs the parameter variable 1372 } 1373 if len(param.info.Refs) > 1 && !arg.duplicable { 1374 logf("keeping param %q: argument is not duplicable", param.info.Name) 1375 continue // incorrect or poor style to duplicate an expression 1376 } 1377 if len(param.info.Refs) == 0 { 1378 if arg.effects { 1379 logf("keeping param %q: though unreferenced, it has effects", param.info.Name) 1380 continue 1381 } 1382 1383 // If the caller is within a function body, 1384 // eliminating an unreferenced parameter might 1385 // remove the last reference to a caller local var. 1386 if caller.enclosingFunc != nil { 1387 for free := range arg.freevars { 1388 // TODO(rfindley): we can get this 100% right by looking for 1389 // references among other arguments which have non-zero references 1390 // within the callee. 1391 if v, ok := caller.lookup(free).(*types.Var); ok && within(v.Pos(), caller.enclosingFunc.Body) && !isUsedOutsideCall(caller, v) { 1392 logf("keeping param %q: arg contains perhaps the last reference to caller local %v @ %v", 1393 param.info.Name, v, caller.Fset.PositionFor(v.Pos(), false)) 1394 continue next 1395 } 1396 } 1397 } 1398 } 1399 1400 // Check for shadowing. 1401 // 1402 // Consider inlining a call f(z, 1) to 1403 // func f(x, y int) int { z := y; return x + y + z }: 1404 // we can't replace x in the body by z (or any 1405 // expression that has z as a free identifier) 1406 // because there's an intervening declaration of z 1407 // that would shadow the caller's one. 1408 for free := range arg.freevars { 1409 if param.info.Shadow[free] { 1410 logf("keeping param %q: cannot replace with argument as it has free ref to %s that is shadowed", param.info.Name, free) 1411 continue next // shadowing conflict 1412 } 1413 } 1414 1415 arg.substitutable = true // may be substituted, if effects permit 1416 } 1417 1418 // Reject constant arguments as substitution candidates 1419 // if they cause violation of falcon constraints. 1420 checkFalconConstraints(logf, params, args, falcon) 1421 1422 // As a final step, introduce bindings to resolve any 1423 // evaluation order hazards. This must be done last, as 1424 // additional subsequent bindings could introduce new hazards. 1425 resolveEffects(logf, args, effects) 1426 1427 // The remaining candidates are safe to substitute. 1428 for i, param := range params { 1429 if arg := args[i]; arg.substitutable { 1430 1431 // Wrap the argument in an explicit conversion if 1432 // substitution might materially change its type. 1433 // (We already did the necessary shadowing check 1434 // on the parameter type syntax.) 1435 // 1436 // This is only needed for substituted arguments. All 1437 // other arguments are given explicit types in either 1438 // a binding decl or when using the literalization 1439 // strategy. 1440 if len(param.info.Refs) > 0 && !trivialConversion(args[i].constant, args[i].typ, params[i].obj.Type()) { 1441 arg.expr = convert(params[i].fieldType, arg.expr) 1442 logf("param %q: adding explicit %s -> %s conversion around argument", 1443 param.info.Name, args[i].typ, params[i].obj.Type()) 1444 } 1445 1446 // It is safe to substitute param and replace it with arg. 1447 // The formatter introduces parens as needed for precedence. 1448 // 1449 // Because arg.expr belongs to the caller, 1450 // we clone it before splicing it into the callee tree. 1451 logf("replacing parameter %q by argument %q", 1452 param.info.Name, debugFormatNode(caller.Fset, arg.expr)) 1453 for _, ref := range param.info.Refs { 1454 replaceCalleeID(ref, internalastutil.CloneNode(arg.expr).(ast.Expr)) 1455 } 1456 params[i] = nil // substituted 1457 args[i] = nil // substituted 1458 } 1459 } 1460 } 1461 1462 // isUsedOutsideCall reports whether v is used outside of caller.Call, within 1463 // the body of caller.enclosingFunc. 1464 func isUsedOutsideCall(caller *Caller, v *types.Var) bool { 1465 used := false 1466 ast.Inspect(caller.enclosingFunc.Body, func(n ast.Node) bool { 1467 if n == caller.Call { 1468 return false 1469 } 1470 switch n := n.(type) { 1471 case *ast.Ident: 1472 if use := caller.Info.Uses[n]; use == v { 1473 used = true 1474 } 1475 case *ast.FuncType: 1476 // All params are used. 1477 for _, fld := range n.Params.List { 1478 for _, n := range fld.Names { 1479 if def := caller.Info.Defs[n]; def == v { 1480 used = true 1481 } 1482 } 1483 } 1484 } 1485 return !used // keep going until we find a use 1486 }) 1487 return used 1488 } 1489 1490 // checkFalconConstraints checks whether constant arguments 1491 // are safe to substitute (e.g. s[i] -> ""[0] is not safe.) 1492 // 1493 // Any failed constraint causes us to reject all constant arguments as 1494 // substitution candidates (by clearing args[i].substitution=false). 1495 // 1496 // TODO(adonovan): we could obtain a finer result rejecting only the 1497 // freevars of each failed constraint, and processing constraints in 1498 // order of increasing arity, but failures are quite rare. 1499 func checkFalconConstraints(logf func(string, ...any), params []*parameter, args []*argument, falcon falconResult) { 1500 // Create a dummy package, as this is the only 1501 // way to create an environment for CheckExpr. 1502 pkg := types.NewPackage("falcon", "falcon") 1503 1504 // Declare types used by constraints. 1505 for _, typ := range falcon.Types { 1506 logf("falcon env: type %s %s", typ.Name, types.Typ[typ.Kind]) 1507 pkg.Scope().Insert(types.NewTypeName(token.NoPos, pkg, typ.Name, types.Typ[typ.Kind])) 1508 } 1509 1510 // Declared constants and variables for for parameters. 1511 nconst := 0 1512 for i, param := range params { 1513 name := param.info.Name 1514 if name == "" { 1515 continue // unreferenced 1516 } 1517 arg := args[i] 1518 if arg.constant != nil && arg.substitutable && param.info.FalconType != "" { 1519 t := pkg.Scope().Lookup(param.info.FalconType).Type() 1520 pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, t, arg.constant)) 1521 logf("falcon env: const %s %s = %v", name, param.info.FalconType, arg.constant) 1522 nconst++ 1523 } else { 1524 pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, arg.typ)) 1525 logf("falcon env: var %s %s", name, arg.typ) 1526 } 1527 } 1528 if nconst == 0 { 1529 return // nothing to do 1530 } 1531 1532 // Parse and evaluate the constraints in the environment. 1533 fset := token.NewFileSet() 1534 for _, falcon := range falcon.Constraints { 1535 expr, err := parser.ParseExprFrom(fset, "falcon", falcon, 0) 1536 if err != nil { 1537 panic(fmt.Sprintf("failed to parse falcon constraint %s: %v", falcon, err)) 1538 } 1539 if err := types.CheckExpr(fset, pkg, token.NoPos, expr, nil); err != nil { 1540 logf("falcon: constraint %s violated: %v", falcon, err) 1541 for j, arg := range args { 1542 if arg.constant != nil && arg.substitutable { 1543 logf("keeping param %q due falcon violation", params[j].info.Name) 1544 arg.substitutable = false 1545 } 1546 } 1547 break 1548 } 1549 logf("falcon: constraint %s satisfied", falcon) 1550 } 1551 } 1552 1553 // resolveEffects marks arguments as non-substitutable to resolve 1554 // hazards resulting from the callee evaluation order described by the 1555 // effects list. 1556 // 1557 // To do this, each argument is categorized as a read (R), write (W), 1558 // or pure. A hazard occurs when the order of evaluation of a W 1559 // changes with respect to any R or W. Pure arguments can be 1560 // effectively ignored, as they can be safely evaluated in any order. 1561 // 1562 // The callee effects list contains the index of each parameter in the 1563 // order it is first evaluated during execution of the callee. In 1564 // addition, the two special values R∞ and W∞ indicate the relative 1565 // position of the callee's first non-parameter read and its first 1566 // effects (or other unknown behavior). 1567 // For example, the list [0 2 1 R∞ 3 W∞] for func(a, b, c, d) 1568 // indicates that the callee referenced parameters a, c, and b, 1569 // followed by an arbitrary read, then parameter d, and finally 1570 // unknown behavior. 1571 // 1572 // When an argument is marked as not substitutable, we say that it is 1573 // 'bound', in the sense that its evaluation occurs in a binding decl 1574 // or literalized call. Such bindings always occur in the original 1575 // callee parameter order. 1576 // 1577 // In this context, "resolving hazards" means binding arguments so 1578 // that they are evaluated in a valid, hazard-free order. A trivial 1579 // solution to this problem would be to bind all arguments, but of 1580 // course that's not useful. The goal is to bind as few arguments as 1581 // possible. 1582 // 1583 // The algorithm proceeds by inspecting arguments in reverse parameter 1584 // order (right to left), preserving the invariant that every 1585 // higher-ordered argument is either already substituted or does not 1586 // need to be substituted. At each iteration, if there is an 1587 // evaluation hazard in the callee effects relative to the current 1588 // argument, the argument must be bound. Subsequently, if the argument 1589 // is bound for any reason, each lower-ordered argument must also be 1590 // bound if either the argument or lower-order argument is a 1591 // W---otherwise the binding itself would introduce a hazard. 1592 // 1593 // Thus, after each iteration, there are no hazards relative to the 1594 // current argument. Subsequent iterations cannot introduce hazards 1595 // with that argument because they can result only in additional 1596 // binding of lower-ordered arguments. 1597 func resolveEffects(logf func(string, ...any), args []*argument, effects []int) { 1598 effectStr := func(effects bool, idx int) string { 1599 i := fmt.Sprint(idx) 1600 if idx == len(args) { 1601 i = "∞" 1602 } 1603 return string("RW"[btoi(effects)]) + i 1604 } 1605 for i := len(args) - 1; i >= 0; i-- { 1606 argi := args[i] 1607 if argi.substitutable && !argi.pure { 1608 // i is not bound: check whether it must be bound due to hazards. 1609 idx := index(effects, i) 1610 if idx >= 0 { 1611 for _, j := range effects[:idx] { 1612 var ( 1613 ji int // effective param index 1614 jw bool // j is a write 1615 ) 1616 if j == winf || j == rinf { 1617 jw = j == winf 1618 ji = len(args) 1619 } else { 1620 jw = args[j].effects 1621 ji = j 1622 } 1623 if ji > i && (jw || argi.effects) { // out of order evaluation 1624 logf("binding argument %s: preceded by %s", 1625 effectStr(argi.effects, i), effectStr(jw, ji)) 1626 argi.substitutable = false 1627 break 1628 } 1629 } 1630 } 1631 } 1632 if !argi.substitutable { 1633 for j := 0; j < i; j++ { 1634 argj := args[j] 1635 if argj.pure { 1636 continue 1637 } 1638 if (argi.effects || argj.effects) && argj.substitutable { 1639 logf("binding argument %s: %s is bound", 1640 effectStr(argj.effects, j), effectStr(argi.effects, i)) 1641 argj.substitutable = false 1642 } 1643 } 1644 } 1645 } 1646 } 1647 1648 // updateCalleeParams updates the calleeDecl syntax to remove 1649 // substituted parameters and move the receiver (if any) to the head 1650 // of the ordinary parameters. 1651 func updateCalleeParams(calleeDecl *ast.FuncDecl, params []*parameter) { 1652 // The logic is fiddly because of the three forms of ast.Field: 1653 // 1654 // func(int), func(x int), func(x, y int) 1655 // 1656 // Also, ensure that all remaining parameters are named 1657 // to avoid a mix of named/unnamed when joining (recv, params...). 1658 // func (T) f(int, bool) -> (_ T, _ int, _ bool) 1659 // (Strictly, we need do this only for methods and only when 1660 // the namednesses of Recv and Params differ; that might be tidier.) 1661 1662 paramIdx := 0 // index in original parameter list (incl. receiver) 1663 var newParams []*ast.Field 1664 filterParams := func(field *ast.Field) { 1665 var names []*ast.Ident 1666 if field.Names == nil { 1667 // Unnamed parameter field (e.g. func f(int) 1668 if params[paramIdx] != nil { 1669 // Give it an explicit name "_" since we will 1670 // make the receiver (if any) a regular parameter 1671 // and one cannot mix named and unnamed parameters. 1672 names = append(names, makeIdent("_")) 1673 } 1674 paramIdx++ 1675 } else { 1676 // Named parameter field e.g. func f(x, y int) 1677 // Remove substituted parameters in place. 1678 // If all were substituted, delete field. 1679 for _, id := range field.Names { 1680 if pinfo := params[paramIdx]; pinfo != nil { 1681 // Rename unreferenced parameters with "_". 1682 // This is crucial for binding decls, since 1683 // unlike parameters, they are subject to 1684 // "unreferenced var" checks. 1685 if len(pinfo.info.Refs) == 0 { 1686 id = makeIdent("_") 1687 } 1688 names = append(names, id) 1689 } 1690 paramIdx++ 1691 } 1692 } 1693 if names != nil { 1694 newParams = append(newParams, &ast.Field{ 1695 Names: names, 1696 Type: field.Type, 1697 }) 1698 } 1699 } 1700 if calleeDecl.Recv != nil { 1701 filterParams(calleeDecl.Recv.List[0]) 1702 calleeDecl.Recv = nil 1703 } 1704 for _, field := range calleeDecl.Type.Params.List { 1705 filterParams(field) 1706 } 1707 calleeDecl.Type.Params.List = newParams 1708 } 1709 1710 // bindingDeclInfo records information about the binding decl produced by 1711 // createBindingDecl. 1712 type bindingDeclInfo struct { 1713 names map[string]bool // names bound by the binding decl; possibly empty 1714 stmt ast.Stmt // the binding decl itself 1715 } 1716 1717 // createBindingDecl constructs a "binding decl" that implements 1718 // parameter assignment and declares any named result variables 1719 // referenced by the callee. It returns nil if there were no 1720 // unsubstituted parameters. 1721 // 1722 // It may not always be possible to create the decl (e.g. due to 1723 // shadowing), in which case it also returns nil; but if it succeeds, 1724 // the declaration may be used by reduction strategies to relax the 1725 // requirement that all parameters have been substituted. 1726 // 1727 // For example, a call: 1728 // 1729 // f(a0, a1, a2) 1730 // 1731 // where: 1732 // 1733 // func f(p0, p1 T0, p2 T1) { body } 1734 // 1735 // reduces to: 1736 // 1737 // { 1738 // var ( 1739 // p0, p1 T0 = a0, a1 1740 // p2 T1 = a2 1741 // ) 1742 // body 1743 // } 1744 // 1745 // so long as p0, p1 ∉ freevars(T1) or freevars(a2), and so on, 1746 // because each spec is statically resolved in sequence and 1747 // dynamically assigned in sequence. By contrast, all 1748 // parameters are resolved simultaneously and assigned 1749 // simultaneously. 1750 // 1751 // The pX names should already be blank ("_") if the parameter 1752 // is unreferenced; this avoids "unreferenced local var" checks. 1753 // 1754 // Strategies may impose additional checks on return 1755 // conversions, labels, defer, etc. 1756 func createBindingDecl(logf func(string, ...any), caller *Caller, args []*argument, calleeDecl *ast.FuncDecl, results []*paramInfo) *bindingDeclInfo { 1757 // Spread calls are tricky as they may not align with the 1758 // parameters' field groupings nor types. 1759 // For example, given 1760 // func g() (int, string) 1761 // the call 1762 // f(g()) 1763 // is legal with these decls of f: 1764 // func f(int, string) 1765 // func f(x, y any) 1766 // func f(x, y ...any) 1767 // TODO(adonovan): support binding decls for spread calls by 1768 // splitting parameter groupings as needed. 1769 if lastArg := last(args); lastArg != nil && lastArg.spread { 1770 logf("binding decls not yet supported for spread calls") 1771 return nil 1772 } 1773 1774 var ( 1775 specs []ast.Spec 1776 names = make(map[string]bool) // names defined by previous specs 1777 ) 1778 // shadow reports whether any name referenced by spec is 1779 // shadowed by a name declared by a previous spec (since, 1780 // unlike parameters, each spec of a var decl is within the 1781 // scope of the previous specs). 1782 shadow := func(spec *ast.ValueSpec) bool { 1783 // Compute union of free names of type and values 1784 // and detect shadowing. Values is the arguments 1785 // (caller syntax), so we can use type info. 1786 // But Type is the untyped callee syntax, 1787 // so we have to use a syntax-only algorithm. 1788 free := make(map[string]bool) 1789 for _, value := range spec.Values { 1790 for name := range freeVars(caller.Info, value) { 1791 free[name] = true 1792 } 1793 } 1794 freeishNames(free, spec.Type) 1795 for name := range free { 1796 if names[name] { 1797 logf("binding decl would shadow free name %q", name) 1798 return true 1799 } 1800 } 1801 for _, id := range spec.Names { 1802 if id.Name != "_" { 1803 names[id.Name] = true 1804 } 1805 } 1806 return false 1807 } 1808 1809 // parameters 1810 // 1811 // Bind parameters that were not eliminated through 1812 // substitution. (Non-nil arguments correspond to the 1813 // remaining parameters in calleeDecl.) 1814 var values []ast.Expr 1815 for _, arg := range args { 1816 if arg != nil { 1817 values = append(values, arg.expr) 1818 } 1819 } 1820 for _, field := range calleeDecl.Type.Params.List { 1821 // Each field (param group) becomes a ValueSpec. 1822 spec := &ast.ValueSpec{ 1823 Names: field.Names, 1824 Type: field.Type, 1825 Values: values[:len(field.Names)], 1826 } 1827 values = values[len(field.Names):] 1828 if shadow(spec) { 1829 return nil 1830 } 1831 specs = append(specs, spec) 1832 } 1833 assert(len(values) == 0, "args/params mismatch") 1834 1835 // results 1836 // 1837 // Add specs to declare any named result 1838 // variables that are referenced by the body. 1839 if calleeDecl.Type.Results != nil { 1840 resultIdx := 0 1841 for _, field := range calleeDecl.Type.Results.List { 1842 if field.Names == nil { 1843 resultIdx++ 1844 continue // unnamed field 1845 } 1846 var names []*ast.Ident 1847 for _, id := range field.Names { 1848 if len(results[resultIdx].Refs) > 0 { 1849 names = append(names, id) 1850 } 1851 resultIdx++ 1852 } 1853 if len(names) > 0 { 1854 spec := &ast.ValueSpec{ 1855 Names: names, 1856 Type: field.Type, 1857 } 1858 if shadow(spec) { 1859 return nil 1860 } 1861 specs = append(specs, spec) 1862 } 1863 } 1864 } 1865 1866 if len(specs) == 0 { 1867 logf("binding decl not needed: all parameters substituted") 1868 return nil 1869 } 1870 1871 stmt := &ast.DeclStmt{ 1872 Decl: &ast.GenDecl{ 1873 Tok: token.VAR, 1874 Specs: specs, 1875 }, 1876 } 1877 logf("binding decl: %s", debugFormatNode(caller.Fset, stmt)) 1878 return &bindingDeclInfo{names: names, stmt: stmt} 1879 } 1880 1881 // lookup does a symbol lookup in the lexical environment of the caller. 1882 func (caller *Caller) lookup(name string) types.Object { 1883 pos := caller.Call.Pos() 1884 for _, n := range caller.path { 1885 if scope := scopeFor(caller.Info, n); scope != nil { 1886 if _, obj := scope.LookupParent(name, pos); obj != nil { 1887 return obj 1888 } 1889 } 1890 } 1891 return nil 1892 } 1893 1894 func scopeFor(info *types.Info, n ast.Node) *types.Scope { 1895 // The function body scope (containing not just params) 1896 // is associated with the function's type, not body. 1897 switch fn := n.(type) { 1898 case *ast.FuncDecl: 1899 n = fn.Type 1900 case *ast.FuncLit: 1901 n = fn.Type 1902 } 1903 return info.Scopes[n] 1904 } 1905 1906 // -- predicates over expressions -- 1907 1908 // freeVars returns the names of all free identifiers of e: 1909 // those lexically referenced by it but not defined within it. 1910 // (Fields and methods are not included.) 1911 func freeVars(info *types.Info, e ast.Expr) map[string]bool { 1912 free := make(map[string]bool) 1913 ast.Inspect(e, func(n ast.Node) bool { 1914 if id, ok := n.(*ast.Ident); ok { 1915 // The isField check is so that we don't treat T{f: 0} as a ref to f. 1916 if obj, ok := info.Uses[id]; ok && !within(obj.Pos(), e) && !isField(obj) { 1917 free[obj.Name()] = true 1918 } 1919 } 1920 return true 1921 }) 1922 return free 1923 } 1924 1925 // freeishNames computes an over-approximation to the free names 1926 // of the type syntax t, inserting values into the map. 1927 // 1928 // Because we don't have go/types annotations, we can't give an exact 1929 // result in all cases. In particular, an array type [n]T might have a 1930 // size such as unsafe.Sizeof(func() int{stmts...}()) and now the 1931 // precise answer depends upon all the statement syntax too. But that 1932 // never happens in practice. 1933 func freeishNames(free map[string]bool, t ast.Expr) { 1934 var visit func(n ast.Node) bool 1935 visit = func(n ast.Node) bool { 1936 switch n := n.(type) { 1937 case *ast.Ident: 1938 free[n.Name] = true 1939 1940 case *ast.SelectorExpr: 1941 ast.Inspect(n.X, visit) 1942 return false // don't visit .Sel 1943 1944 case *ast.Field: 1945 ast.Inspect(n.Type, visit) 1946 // Don't visit .Names: 1947 // FuncType parameters, interface methods, struct fields 1948 return false 1949 } 1950 return true 1951 } 1952 ast.Inspect(t, visit) 1953 } 1954 1955 // effects reports whether an expression might change the state of the 1956 // program (through function calls and channel receives) and affect 1957 // the evaluation of subsequent expressions. 1958 func (st *state) effects(info *types.Info, expr ast.Expr) bool { 1959 effects := false 1960 ast.Inspect(expr, func(n ast.Node) bool { 1961 switch n := n.(type) { 1962 case *ast.FuncLit: 1963 return false // prune descent 1964 1965 case *ast.CallExpr: 1966 if info.Types[n.Fun].IsType() { 1967 // A conversion T(x) has only the effect of its operand. 1968 } else if !callsPureBuiltin(info, n) { 1969 // A handful of built-ins have no effect 1970 // beyond those of their arguments. 1971 // All other calls (including append, copy, recover) 1972 // have unknown effects. 1973 // 1974 // As with 'pure', there is room for 1975 // improvement by inspecting the callee. 1976 effects = true 1977 } 1978 1979 case *ast.UnaryExpr: 1980 if n.Op == token.ARROW { // <-ch 1981 effects = true 1982 } 1983 } 1984 return true 1985 }) 1986 1987 // Even if consideration of effects is not desired, 1988 // we continue to compute, log, and discard them. 1989 if st.opts.IgnoreEffects && effects { 1990 effects = false 1991 st.opts.Logf("ignoring potential effects of argument %s", 1992 debugFormatNode(st.caller.Fset, expr)) 1993 } 1994 1995 return effects 1996 } 1997 1998 // pure reports whether an expression has the same result no matter 1999 // when it is executed relative to other expressions, so it can be 2000 // commuted with any other expression or statement without changing 2001 // its meaning. 2002 // 2003 // An expression is considered impure if it reads the contents of any 2004 // variable, with the exception of "single assignment" local variables 2005 // (as classified by the provided callback), which are never updated 2006 // after their initialization. 2007 // 2008 // Pure does not imply duplicable: for example, new(T) and T{} are 2009 // pure expressions but both return a different value each time they 2010 // are evaluated, so they are not safe to duplicate. 2011 // 2012 // Purity does not imply freedom from run-time panics. We assume that 2013 // target programs do not encounter run-time panics nor depend on them 2014 // for correct operation. 2015 // 2016 // TODO(adonovan): add unit tests of this function. 2017 func pure(info *types.Info, assign1 func(*types.Var) bool, e ast.Expr) bool { 2018 var pure func(e ast.Expr) bool 2019 pure = func(e ast.Expr) bool { 2020 switch e := e.(type) { 2021 case *ast.ParenExpr: 2022 return pure(e.X) 2023 2024 case *ast.Ident: 2025 if v, ok := info.Uses[e].(*types.Var); ok { 2026 // In general variables are impure 2027 // as they may be updated, but 2028 // single-assignment local variables 2029 // never change value. 2030 // 2031 // We assume all package-level variables 2032 // may be updated, but for non-exported 2033 // ones we could do better by analyzing 2034 // the complete package. 2035 return !isPkgLevel(v) && assign1(v) 2036 } 2037 2038 // All other kinds of reference are pure. 2039 return true 2040 2041 case *ast.FuncLit: 2042 // A function literal may allocate a closure that 2043 // references mutable variables, but mutation 2044 // cannot be observed without calling the function, 2045 // and calls are considered impure. 2046 return true 2047 2048 case *ast.BasicLit: 2049 return true 2050 2051 case *ast.UnaryExpr: // + - ! ^ & but not <- 2052 return e.Op != token.ARROW && pure(e.X) 2053 2054 case *ast.BinaryExpr: // arithmetic, shifts, comparisons, &&/|| 2055 return pure(e.X) && pure(e.Y) 2056 2057 case *ast.CallExpr: 2058 // A conversion is as pure as its operand. 2059 if info.Types[e.Fun].IsType() { 2060 return pure(e.Args[0]) 2061 } 2062 2063 // Calls to some built-ins are as pure as their arguments. 2064 if callsPureBuiltin(info, e) { 2065 for _, arg := range e.Args { 2066 if !pure(arg) { 2067 return false 2068 } 2069 } 2070 return true 2071 } 2072 2073 // All other calls are impure, so we can 2074 // reject them without even looking at e.Fun. 2075 // 2076 // More sophisticated analysis could infer purity in 2077 // commonly used functions such as strings.Contains; 2078 // perhaps we could offer the client a hook so that 2079 // go/analysis-based implementation could exploit the 2080 // results of a purity analysis. But that would make 2081 // the inliner's choices harder to explain. 2082 return false 2083 2084 case *ast.CompositeLit: 2085 // T{...} is as pure as its elements. 2086 for _, elt := range e.Elts { 2087 if kv, ok := elt.(*ast.KeyValueExpr); ok { 2088 if !pure(kv.Value) { 2089 return false 2090 } 2091 if id, ok := kv.Key.(*ast.Ident); ok { 2092 if v, ok := info.Uses[id].(*types.Var); ok && v.IsField() { 2093 continue // struct {field: value} 2094 } 2095 } 2096 // map/slice/array {key: value} 2097 if !pure(kv.Key) { 2098 return false 2099 } 2100 2101 } else if !pure(elt) { 2102 return false 2103 } 2104 } 2105 return true 2106 2107 case *ast.SelectorExpr: 2108 if seln, ok := info.Selections[e]; ok { 2109 2110 // See types.SelectionKind for background. 2111 switch seln.Kind() { 2112 case types.MethodExpr: 2113 // A method expression T.f acts like a 2114 // reference to a func decl, so it is pure. 2115 return true 2116 2117 case types.MethodVal, types.FieldVal: 2118 // A field or method selection x.f is pure 2119 // if x is pure and the selection does 2120 // not indirect a pointer. 2121 return !indirectSelection(seln) && pure(e.X) 2122 2123 default: 2124 panic(seln) 2125 } 2126 } else { 2127 // A qualified identifier is 2128 // treated like an unqualified one. 2129 return pure(e.Sel) 2130 } 2131 2132 case *ast.StarExpr: 2133 return false // *ptr depends on the state of the heap 2134 2135 default: 2136 return false 2137 } 2138 } 2139 return pure(e) 2140 } 2141 2142 // callsPureBuiltin reports whether call is a call of a built-in 2143 // function that is a pure computation over its operands (analogous to 2144 // a + operator). Because it does not depend on program state, it may 2145 // be evaluated at any point--though not necessarily at multiple 2146 // points (consider new, make). 2147 func callsPureBuiltin(info *types.Info, call *ast.CallExpr) bool { 2148 if id, ok := astutil.Unparen(call.Fun).(*ast.Ident); ok { 2149 if b, ok := info.ObjectOf(id).(*types.Builtin); ok { 2150 switch b.Name() { 2151 case "len", "cap", "complex", "imag", "real", "make", "new", "max", "min": 2152 return true 2153 } 2154 // Not: append clear close copy delete panic print println recover 2155 } 2156 } 2157 return false 2158 } 2159 2160 // duplicable reports whether it is appropriate for the expression to 2161 // be freely duplicated. 2162 // 2163 // Given the declaration 2164 // 2165 // func f(x T) T { return x + g() + x } 2166 // 2167 // an argument y is considered duplicable if we would wish to see a 2168 // call f(y) simplified to y+g()+y. This is true for identifiers, 2169 // integer literals, unary negation, and selectors x.f where x is not 2170 // a pointer. But we would not wish to duplicate expressions that: 2171 // - have side effects (e.g. nearly all calls), 2172 // - are not referentially transparent (e.g. &T{}, ptr.field, *ptr), or 2173 // - are long (e.g. "huge string literal"). 2174 func duplicable(info *types.Info, e ast.Expr) bool { 2175 switch e := e.(type) { 2176 case *ast.ParenExpr: 2177 return duplicable(info, e.X) 2178 2179 case *ast.Ident: 2180 return true 2181 2182 case *ast.BasicLit: 2183 v := info.Types[e].Value 2184 switch e.Kind { 2185 case token.INT: 2186 return true // any int 2187 case token.STRING: 2188 return consteq(v, kZeroString) // only "" 2189 case token.FLOAT: 2190 return consteq(v, kZeroFloat) || consteq(v, kOneFloat) // only 0.0 or 1.0 2191 } 2192 2193 case *ast.UnaryExpr: // e.g. +1, -1 2194 return (e.Op == token.ADD || e.Op == token.SUB) && duplicable(info, e.X) 2195 2196 case *ast.CompositeLit: 2197 // Empty struct or array literals T{} are duplicable. 2198 // (Non-empty literals are too verbose, and slice/map 2199 // literals allocate indirect variables.) 2200 if len(e.Elts) == 0 { 2201 switch info.TypeOf(e).Underlying().(type) { 2202 case *types.Struct, *types.Array: 2203 return true 2204 } 2205 } 2206 return false 2207 2208 case *ast.CallExpr: 2209 // Don't treat a conversion T(x) as duplicable even 2210 // if x is duplicable because it could duplicate 2211 // allocations. 2212 // 2213 // TODO(adonovan): there are cases to tease apart here: 2214 // duplicating string([]byte) conversions increases 2215 // allocation but doesn't change behavior, but the 2216 // reverse, []byte(string), allocates a distinct array, 2217 // which is observable 2218 return false 2219 2220 case *ast.SelectorExpr: 2221 if seln, ok := info.Selections[e]; ok { 2222 // A field or method selection x.f is referentially 2223 // transparent if it does not indirect a pointer. 2224 return !indirectSelection(seln) 2225 } 2226 // A qualified identifier pkg.Name is referentially transparent. 2227 return true 2228 } 2229 return false 2230 } 2231 2232 func consteq(x, y constant.Value) bool { 2233 return constant.Compare(x, token.EQL, y) 2234 } 2235 2236 var ( 2237 kZeroInt = constant.MakeInt64(0) 2238 kZeroString = constant.MakeString("") 2239 kZeroFloat = constant.MakeFloat64(0.0) 2240 kOneFloat = constant.MakeFloat64(1.0) 2241 ) 2242 2243 // -- inline helpers -- 2244 2245 func assert(cond bool, msg string) { 2246 if !cond { 2247 panic(msg) 2248 } 2249 } 2250 2251 // blanks returns a slice of n > 0 blank identifiers. 2252 func blanks[E ast.Expr](n int) []E { 2253 if n == 0 { 2254 panic("blanks(0)") 2255 } 2256 res := make([]E, n) 2257 for i := range res { 2258 res[i] = ast.Expr(makeIdent("_")).(E) // ugh 2259 } 2260 return res 2261 } 2262 2263 func makeIdent(name string) *ast.Ident { 2264 return &ast.Ident{Name: name} 2265 } 2266 2267 // importedPkgName returns the PkgName object declared by an ImportSpec. 2268 // TODO(adonovan): make this a method of types.Info (#62037). 2269 func importedPkgName(info *types.Info, imp *ast.ImportSpec) (*types.PkgName, bool) { 2270 var obj types.Object 2271 if imp.Name != nil { 2272 obj = info.Defs[imp.Name] 2273 } else { 2274 obj = info.Implicits[imp] 2275 } 2276 pkgname, ok := obj.(*types.PkgName) 2277 return pkgname, ok 2278 } 2279 2280 func isPkgLevel(obj types.Object) bool { 2281 // TODO(adonovan): consider using the simpler obj.Parent() == 2282 // obj.Pkg().Scope() instead. But be sure to test carefully 2283 // with instantiations of generics. 2284 return obj.Pkg().Scope().Lookup(obj.Name()) == obj 2285 } 2286 2287 // callContext returns the two nodes immediately enclosing the call 2288 // (specified as a PathEnclosingInterval), ignoring parens. 2289 func callContext(callPath []ast.Node) (parent, grandparent ast.Node) { 2290 _ = callPath[0].(*ast.CallExpr) // sanity check 2291 for _, n := range callPath[1:] { 2292 if !is[*ast.ParenExpr](n) { 2293 if parent == nil { 2294 parent = n 2295 } else { 2296 return parent, n 2297 } 2298 } 2299 } 2300 return parent, nil 2301 } 2302 2303 // hasLabelConflict reports whether the set of labels of the function 2304 // enclosing the call (specified as a PathEnclosingInterval) 2305 // intersects with the set of callee labels. 2306 func hasLabelConflict(callPath []ast.Node, calleeLabels []string) bool { 2307 labels := callerLabels(callPath) 2308 for _, label := range calleeLabels { 2309 if labels[label] { 2310 return true // conflict 2311 } 2312 } 2313 return false 2314 } 2315 2316 // callerLabels returns the set of control labels in the function (if 2317 // any) enclosing the call (specified as a PathEnclosingInterval). 2318 func callerLabels(callPath []ast.Node) map[string]bool { 2319 var callerBody *ast.BlockStmt 2320 switch f := callerFunc(callPath).(type) { 2321 case *ast.FuncDecl: 2322 callerBody = f.Body 2323 case *ast.FuncLit: 2324 callerBody = f.Body 2325 } 2326 var labels map[string]bool 2327 if callerBody != nil { 2328 ast.Inspect(callerBody, func(n ast.Node) bool { 2329 switch n := n.(type) { 2330 case *ast.FuncLit: 2331 return false // prune traversal 2332 case *ast.LabeledStmt: 2333 if labels == nil { 2334 labels = make(map[string]bool) 2335 } 2336 labels[n.Label.Name] = true 2337 } 2338 return true 2339 }) 2340 } 2341 return labels 2342 } 2343 2344 // callerFunc returns the innermost Func{Decl,Lit} node enclosing the 2345 // call (specified as a PathEnclosingInterval). 2346 func callerFunc(callPath []ast.Node) ast.Node { 2347 _ = callPath[0].(*ast.CallExpr) // sanity check 2348 for _, n := range callPath[1:] { 2349 if is[*ast.FuncDecl](n) || is[*ast.FuncLit](n) { 2350 return n 2351 } 2352 } 2353 return nil 2354 } 2355 2356 // callStmt reports whether the function call (specified 2357 // as a PathEnclosingInterval) appears within an ExprStmt, 2358 // and returns it if so. 2359 // 2360 // If unrestricted, callStmt returns nil if the ExprStmt f() appears 2361 // in a restricted context (such as "if f(); cond {") where it cannot 2362 // be replaced by an arbitrary statement. (See "statement theory".) 2363 func callStmt(callPath []ast.Node, unrestricted bool) *ast.ExprStmt { 2364 parent, _ := callContext(callPath) 2365 stmt, ok := parent.(*ast.ExprStmt) 2366 if ok && unrestricted { 2367 switch callPath[nodeIndex(callPath, stmt)+1].(type) { 2368 case *ast.LabeledStmt, 2369 *ast.BlockStmt, 2370 *ast.CaseClause, 2371 *ast.CommClause: 2372 // unrestricted 2373 default: 2374 // TODO(adonovan): handle restricted 2375 // XYZStmt.Init contexts (but not ForStmt.Post) 2376 // by creating a block around the if/for/switch: 2377 // "if f(); cond {" -> "{ stmts; if cond {" 2378 2379 return nil // restricted 2380 } 2381 } 2382 return stmt 2383 } 2384 2385 // Statement theory 2386 // 2387 // These are all the places a statement may appear in the AST: 2388 // 2389 // LabeledStmt.Stmt Stmt -- any 2390 // BlockStmt.List []Stmt -- any (but see switch/select) 2391 // IfStmt.Init Stmt? -- simple 2392 // IfStmt.Body BlockStmt 2393 // IfStmt.Else Stmt? -- IfStmt or BlockStmt 2394 // CaseClause.Body []Stmt -- any 2395 // SwitchStmt.Init Stmt? -- simple 2396 // SwitchStmt.Body BlockStmt -- CaseClauses only 2397 // TypeSwitchStmt.Init Stmt? -- simple 2398 // TypeSwitchStmt.Assign Stmt -- AssignStmt(TypeAssertExpr) or ExprStmt(TypeAssertExpr) 2399 // TypeSwitchStmt.Body BlockStmt -- CaseClauses only 2400 // CommClause.Comm Stmt? -- SendStmt or ExprStmt(UnaryExpr) or AssignStmt(UnaryExpr) 2401 // CommClause.Body []Stmt -- any 2402 // SelectStmt.Body BlockStmt -- CommClauses only 2403 // ForStmt.Init Stmt? -- simple 2404 // ForStmt.Post Stmt? -- simple 2405 // ForStmt.Body BlockStmt 2406 // RangeStmt.Body BlockStmt 2407 // 2408 // simple = AssignStmt | SendStmt | IncDecStmt | ExprStmt. 2409 // 2410 // A BlockStmt cannot replace an ExprStmt in 2411 // {If,Switch,TypeSwitch}Stmt.Init or ForStmt.Post. 2412 // That is allowed only within: 2413 // LabeledStmt.Stmt Stmt 2414 // BlockStmt.List []Stmt 2415 // CaseClause.Body []Stmt 2416 // CommClause.Body []Stmt 2417 2418 // replaceNode performs a destructive update of the tree rooted at 2419 // root, replacing each occurrence of "from" with "to". If to is nil and 2420 // the element is within a slice, the slice element is removed. 2421 // 2422 // The root itself cannot be replaced; an attempt will panic. 2423 // 2424 // This function must not be called on the caller's syntax tree. 2425 // 2426 // TODO(adonovan): polish this up and move it to astutil package. 2427 // TODO(adonovan): needs a unit test. 2428 func replaceNode(root ast.Node, from, to ast.Node) { 2429 if from == nil { 2430 panic("from == nil") 2431 } 2432 if reflect.ValueOf(from).IsNil() { 2433 panic(fmt.Sprintf("from == (%T)(nil)", from)) 2434 } 2435 if from == root { 2436 panic("from == root") 2437 } 2438 found := false 2439 var parent reflect.Value // parent variable of interface type, containing a pointer 2440 var visit func(reflect.Value) 2441 visit = func(v reflect.Value) { 2442 switch v.Kind() { 2443 case reflect.Ptr: 2444 if v.Interface() == from { 2445 found = true 2446 2447 // If v is a struct field or array element 2448 // (e.g. Field.Comment or Field.Names[i]) 2449 // then it is addressable (a pointer variable). 2450 // 2451 // But if it was the value an interface 2452 // (e.g. *ast.Ident within ast.Node) 2453 // then it is non-addressable, and we need 2454 // to set the enclosing interface (parent). 2455 if !v.CanAddr() { 2456 v = parent 2457 } 2458 2459 // to=nil => use zero value 2460 var toV reflect.Value 2461 if to != nil { 2462 toV = reflect.ValueOf(to) 2463 } else { 2464 toV = reflect.Zero(v.Type()) // e.g. ast.Expr(nil) 2465 } 2466 v.Set(toV) 2467 2468 } else if !v.IsNil() { 2469 switch v.Interface().(type) { 2470 case *ast.Object, *ast.Scope: 2471 // Skip fields of types potentially involved in cycles. 2472 default: 2473 visit(v.Elem()) 2474 } 2475 } 2476 2477 case reflect.Struct: 2478 for i := 0; i < v.Type().NumField(); i++ { 2479 visit(v.Field(i)) 2480 } 2481 2482 case reflect.Slice: 2483 compact := false 2484 for i := 0; i < v.Len(); i++ { 2485 visit(v.Index(i)) 2486 if v.Index(i).IsNil() { 2487 compact = true 2488 } 2489 } 2490 if compact { 2491 // Elements were deleted. Eliminate nils. 2492 // (Do this is a second pass to avoid 2493 // unnecessary writes in the common case.) 2494 j := 0 2495 for i := 0; i < v.Len(); i++ { 2496 if !v.Index(i).IsNil() { 2497 v.Index(j).Set(v.Index(i)) 2498 j++ 2499 } 2500 } 2501 v.SetLen(j) 2502 } 2503 case reflect.Interface: 2504 parent = v 2505 visit(v.Elem()) 2506 2507 case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.UnsafePointer: 2508 panic(v) // unreachable in AST 2509 default: 2510 // bool, string, number: nop 2511 } 2512 parent = reflect.Value{} 2513 } 2514 visit(reflect.ValueOf(root)) 2515 if !found { 2516 panic(fmt.Sprintf("%T not found", from)) 2517 } 2518 } 2519 2520 // clearPositions destroys token.Pos information within the tree rooted at root, 2521 // as positions in callee trees may cause caller comments to be emitted prematurely. 2522 // 2523 // In general it isn't safe to clear a valid Pos because some of them 2524 // (e.g. CallExpr.Ellipsis, TypeSpec.Assign) are significant to 2525 // go/printer, so this function sets each non-zero Pos to 1, which 2526 // suffices to avoid advancing the printer's comment cursor. 2527 // 2528 // This function mutates its argument; do not invoke on caller syntax. 2529 // 2530 // TODO(adonovan): remove this horrendous workaround when #20744 is finally fixed. 2531 func clearPositions(root ast.Node) { 2532 posType := reflect.TypeOf(token.NoPos) 2533 ast.Inspect(root, func(n ast.Node) bool { 2534 if n != nil { 2535 v := reflect.ValueOf(n).Elem() // deref the pointer to struct 2536 fields := v.Type().NumField() 2537 for i := 0; i < fields; i++ { 2538 f := v.Field(i) 2539 // Clearing Pos arbitrarily is destructive, 2540 // as its presence may be semantically significant 2541 // (e.g. CallExpr.Ellipsis, TypeSpec.Assign) 2542 // or affect formatting preferences (e.g. GenDecl.Lparen). 2543 // 2544 // Note: for proper formatting, it may be necessary to be selective 2545 // about which positions we set to 1 vs which we set to token.NoPos. 2546 // (e.g. we can set most to token.NoPos, save the few that are 2547 // significant). 2548 if f.Type() == posType { 2549 if f.Interface() != token.NoPos { 2550 f.Set(reflect.ValueOf(token.Pos(1))) 2551 } 2552 } 2553 } 2554 } 2555 return true 2556 }) 2557 } 2558 2559 // findIdent returns the Ident beneath root that has the given pos. 2560 func findIdent(root ast.Node, pos token.Pos) *ast.Ident { 2561 // TODO(adonovan): opt: skip subtrees that don't contain pos. 2562 var found *ast.Ident 2563 ast.Inspect(root, func(n ast.Node) bool { 2564 if found != nil { 2565 return false 2566 } 2567 if id, ok := n.(*ast.Ident); ok { 2568 if id.Pos() == pos { 2569 found = id 2570 } 2571 } 2572 return true 2573 }) 2574 if found == nil { 2575 panic(fmt.Sprintf("findIdent %d not found in %s", 2576 pos, debugFormatNode(token.NewFileSet(), root))) 2577 } 2578 return found 2579 } 2580 2581 func prepend[T any](elem T, slice ...T) []T { 2582 return append([]T{elem}, slice...) 2583 } 2584 2585 // debugFormatNode formats a node or returns a formatting error. 2586 // Its sloppy treatment of errors is appropriate only for logging. 2587 func debugFormatNode(fset *token.FileSet, n ast.Node) string { 2588 var out strings.Builder 2589 if err := format.Node(&out, fset, n); err != nil { 2590 out.WriteString(err.Error()) 2591 } 2592 return out.String() 2593 } 2594 2595 func shallowCopy[T any](ptr *T) *T { 2596 copy := *ptr 2597 return © 2598 } 2599 2600 // ∀ 2601 func forall[T any](list []T, f func(i int, x T) bool) bool { 2602 for i, x := range list { 2603 if !f(i, x) { 2604 return false 2605 } 2606 } 2607 return true 2608 } 2609 2610 // ∃ 2611 func exists[T any](list []T, f func(i int, x T) bool) bool { 2612 for i, x := range list { 2613 if f(i, x) { 2614 return true 2615 } 2616 } 2617 return false 2618 } 2619 2620 // last returns the last element of a slice, or zero if empty. 2621 func last[T any](slice []T) T { 2622 n := len(slice) 2623 if n > 0 { 2624 return slice[n-1] 2625 } 2626 return *new(T) 2627 } 2628 2629 // canImport reports whether one package is allowed to import another. 2630 // 2631 // TODO(adonovan): allow customization of the accessibility relation 2632 // (e.g. for Bazel). 2633 func canImport(from, to string) bool { 2634 // TODO(adonovan): better segment hygiene. 2635 if strings.HasPrefix(to, "internal/") { 2636 // Special case: only std packages may import internal/... 2637 // We can't reliably know whether we're in std, so we 2638 // use a heuristic on the first segment. 2639 first, _, _ := strings.Cut(from, "/") 2640 if strings.Contains(first, ".") { 2641 return false // example.com/foo ∉ std 2642 } 2643 if first == "testdata" { 2644 return false // testdata/foo ∉ std 2645 } 2646 } 2647 if i := strings.LastIndex(to, "/internal/"); i >= 0 { 2648 return strings.HasPrefix(from, to[:i]) 2649 } 2650 return true 2651 } 2652 2653 // consistentOffsets reports whether the portion of caller.Content 2654 // that corresponds to caller.Call can be parsed as a call expression. 2655 // If not, the client has provided inconsistent information, possibly 2656 // because they forgot to ignore line directives when computing the 2657 // filename enclosing the call. 2658 // This is just a heuristic. 2659 func consistentOffsets(caller *Caller) bool { 2660 start := offsetOf(caller.Fset, caller.Call.Pos()) 2661 end := offsetOf(caller.Fset, caller.Call.End()) 2662 if !(0 < start && start < end && end <= len(caller.Content)) { 2663 return false 2664 } 2665 expr, err := parser.ParseExpr(string(caller.Content[start:end])) 2666 if err != nil { 2667 return false 2668 } 2669 return is[*ast.CallExpr](expr) 2670 } 2671 2672 // needsParens reports whether parens are required to avoid ambiguity 2673 // around the new node replacing the specified old node (which is some 2674 // ancestor of the CallExpr identified by its PathEnclosingInterval). 2675 func needsParens(callPath []ast.Node, old, new ast.Node) bool { 2676 // Find enclosing old node and its parent. 2677 i := nodeIndex(callPath, old) 2678 if i == -1 { 2679 panic("not found") 2680 } 2681 2682 // There is no precedence ambiguity when replacing 2683 // (e.g.) a statement enclosing the call. 2684 if !is[ast.Expr](old) { 2685 return false 2686 } 2687 2688 // An expression beneath a non-expression 2689 // has no precedence ambiguity. 2690 parent, ok := callPath[i+1].(ast.Expr) 2691 if !ok { 2692 return false 2693 } 2694 2695 precedence := func(n ast.Node) int { 2696 switch n := n.(type) { 2697 case *ast.UnaryExpr, *ast.StarExpr: 2698 return token.UnaryPrec 2699 case *ast.BinaryExpr: 2700 return n.Op.Precedence() 2701 } 2702 return -1 2703 } 2704 2705 // Parens are not required if the new node 2706 // is not unary or binary. 2707 newprec := precedence(new) 2708 if newprec < 0 { 2709 return false 2710 } 2711 2712 // Parens are required if parent and child are both 2713 // unary or binary and the parent has higher precedence. 2714 if precedence(parent) > newprec { 2715 return true 2716 } 2717 2718 // Was the old node the operand of a postfix operator? 2719 // f().sel 2720 // f()[i:j] 2721 // f()[i] 2722 // f().(T) 2723 // f()(x) 2724 switch parent := parent.(type) { 2725 case *ast.SelectorExpr: 2726 return parent.X == old 2727 case *ast.IndexExpr: 2728 return parent.X == old 2729 case *ast.SliceExpr: 2730 return parent.X == old 2731 case *ast.TypeAssertExpr: 2732 return parent.X == old 2733 case *ast.CallExpr: 2734 return parent.Fun == old 2735 } 2736 return false 2737 } 2738 2739 func nodeIndex(nodes []ast.Node, n ast.Node) int { 2740 // TODO(adonovan): Use index[ast.Node]() in go1.20. 2741 for i, node := range nodes { 2742 if node == n { 2743 return i 2744 } 2745 } 2746 return -1 2747 } 2748 2749 // declares returns the set of lexical names declared by a 2750 // sequence of statements from the same block, excluding sub-blocks. 2751 // (Lexical names do not include control labels.) 2752 func declares(stmts []ast.Stmt) map[string]bool { 2753 names := make(map[string]bool) 2754 for _, stmt := range stmts { 2755 switch stmt := stmt.(type) { 2756 case *ast.DeclStmt: 2757 for _, spec := range stmt.Decl.(*ast.GenDecl).Specs { 2758 switch spec := spec.(type) { 2759 case *ast.ValueSpec: 2760 for _, id := range spec.Names { 2761 names[id.Name] = true 2762 } 2763 case *ast.TypeSpec: 2764 names[spec.Name.Name] = true 2765 } 2766 } 2767 2768 case *ast.AssignStmt: 2769 if stmt.Tok == token.DEFINE { 2770 for _, lhs := range stmt.Lhs { 2771 names[lhs.(*ast.Ident).Name] = true 2772 } 2773 } 2774 } 2775 } 2776 delete(names, "_") 2777 return names 2778 } 2779 2780 // assignStmts rewrites a statement assigning the results of a call into zero 2781 // or more statements that assign its return operands, or (nil, false) if no 2782 // such rewrite is possible. The set of bindings created by the result of 2783 // assignStmts is the same as the set of bindings created by the callerStmt. 2784 // 2785 // The callee must contain exactly one return statement. 2786 // 2787 // This is (once again) a surprisingly complex task. For example, depending on 2788 // types and existing bindings, the assignment 2789 // 2790 // a, b := f() 2791 // 2792 // could be rewritten as: 2793 // 2794 // a, b := 1, 2 2795 // 2796 // but may need to be written as: 2797 // 2798 // a, b := int8(1), int32(2) 2799 // 2800 // In the case where the return statement within f is a spread call to another 2801 // function g(), we cannot explicitly convert the return values inline, and so 2802 // it may be necessary to split the declaration and assignment of variables 2803 // into separate statements: 2804 // 2805 // a, b := g() 2806 // 2807 // or 2808 // 2809 // var a int32 2810 // a, b = g() 2811 // 2812 // or 2813 // 2814 // var ( 2815 // a int8 2816 // b int32 2817 // ) 2818 // a, b = g() 2819 // 2820 // Note: assignStmts may return (nil, true) if it determines that the rewritten 2821 // assignment consists only of _ = nil assignments. 2822 func (st *state) assignStmts(callerStmt *ast.AssignStmt, returnOperands []ast.Expr) ([]ast.Stmt, bool) { 2823 logf, caller, callee := st.opts.Logf, st.caller, &st.callee.impl 2824 2825 assert(len(callee.Returns) == 1, "unexpected multiple returns") 2826 resultInfo := callee.Returns[0] 2827 2828 // When constructing assign statements, we need to make sure that we don't 2829 // modify types on the left-hand side, such as would happen if the type of a 2830 // RHS expression does not match the corresponding LHS type at the caller 2831 // (due to untyped conversion or interface widening). 2832 // 2833 // This turns out to be remarkably tricky to handle correctly. 2834 // 2835 // Substrategies below are labeled as `Substrategy <name>:`. 2836 2837 // Collect LHS information. 2838 var ( 2839 lhs []ast.Expr // shallow copy of the LHS slice, for mutation 2840 defs = make([]*ast.Ident, len(callerStmt.Lhs)) // indexes in lhs of defining identifiers 2841 blanks = make([]bool, len(callerStmt.Lhs)) // indexes in lhs of blank identifiers 2842 byType typeutil.Map // map of distinct types -> indexes, for writing specs later 2843 ) 2844 for i, expr := range callerStmt.Lhs { 2845 lhs = append(lhs, expr) 2846 if name, ok := expr.(*ast.Ident); ok { 2847 if name.Name == "_" { 2848 blanks[i] = true 2849 continue // no type 2850 } 2851 2852 if obj, isDef := caller.Info.Defs[name]; isDef { 2853 defs[i] = name 2854 typ := obj.Type() 2855 idxs, _ := byType.At(typ).([]int) 2856 idxs = append(idxs, i) 2857 byType.Set(typ, idxs) 2858 } 2859 } 2860 } 2861 2862 // Collect RHS information 2863 // 2864 // The RHS is either a parallel assignment or spread assignment, but by 2865 // looping over both callerStmt.Rhs and returnOperands we handle both. 2866 var ( 2867 rhs []ast.Expr // new RHS of assignment, owned by the inliner 2868 callIdx = -1 // index of the call among the original RHS 2869 nilBlankAssigns = make(map[int]unit) // indexes in rhs of _ = nil assignments, which can be deleted 2870 freeNames = make(map[string]bool) // free(ish) names among rhs expressions 2871 nonTrivial = make(map[int]bool) // indexes in rhs of nontrivial result conversions 2872 ) 2873 for i, expr := range callerStmt.Rhs { 2874 if expr == caller.Call { 2875 assert(callIdx == -1, "malformed (duplicative) AST") 2876 callIdx = i 2877 for j, returnOperand := range returnOperands { 2878 freeishNames(freeNames, returnOperand) 2879 rhs = append(rhs, returnOperand) 2880 if resultInfo[j]&nonTrivialResult != 0 { 2881 nonTrivial[i+j] = true 2882 } 2883 if blanks[i+j] && resultInfo[j]&untypedNilResult != 0 { 2884 nilBlankAssigns[i+j] = unit{} 2885 } 2886 } 2887 } else { 2888 // We must clone before clearing positions, since e came from the caller. 2889 expr = internalastutil.CloneNode(expr) 2890 clearPositions(expr) 2891 freeishNames(freeNames, expr) 2892 rhs = append(rhs, expr) 2893 } 2894 } 2895 assert(callIdx >= 0, "failed to find call in RHS") 2896 2897 // Substrategy "splice": Check to see if we can simply splice in the result 2898 // expressions from the callee, such as simplifying 2899 // 2900 // x, y := f() 2901 // 2902 // to 2903 // 2904 // x, y := e1, e2 2905 // 2906 // where the types of x and y match the types of e1 and e2. 2907 // 2908 // This works as long as we don't need to write any additional type 2909 // information. 2910 if callerStmt.Tok == token.ASSIGN && // LHS types already determined before call 2911 len(nonTrivial) == 0 { // no non-trivial conversions to worry about 2912 2913 logf("substrategy: slice assignment") 2914 return []ast.Stmt{&ast.AssignStmt{ 2915 Lhs: lhs, 2916 Tok: callerStmt.Tok, 2917 TokPos: callerStmt.TokPos, 2918 Rhs: rhs, 2919 }}, true 2920 } 2921 2922 // Inlining techniques below will need to write type information in order to 2923 // preserve the correct types of LHS identifiers. 2924 // 2925 // writeType is a simple helper to write out type expressions. 2926 // TODO(rfindley): 2927 // 1. handle qualified type names (potentially adding new imports) 2928 // 2. expand this to handle more type expressions. 2929 // 3. refactor to share logic with callee rewriting. 2930 universeAny := types.Universe.Lookup("any") 2931 typeExpr := func(typ types.Type, shadows ...map[string]bool) ast.Expr { 2932 var typeName string 2933 switch typ := typ.(type) { 2934 case *types.Basic: 2935 typeName = typ.Name() 2936 case interface{ Obj() *types.TypeName }: // Named, Alias, TypeParam 2937 typeName = typ.Obj().Name() 2938 } 2939 2940 // Special case: check for universe "any". 2941 // TODO(golang/go#66921): this may become unnecessary if any becomes a proper alias. 2942 if typ == universeAny.Type() { 2943 typeName = "any" 2944 } 2945 2946 if typeName == "" { 2947 return nil 2948 } 2949 2950 for _, shadow := range shadows { 2951 if shadow[typeName] { 2952 logf("cannot write shadowed type name %q", typeName) 2953 return nil 2954 } 2955 } 2956 obj, _ := caller.lookup(typeName).(*types.TypeName) 2957 if obj != nil && types.Identical(obj.Type(), typ) { 2958 return ast.NewIdent(typeName) 2959 } 2960 return nil 2961 } 2962 2963 // Substrategy "spread": in the case of a spread call (func f() (T1, T2) return 2964 // g()), since we didn't hit the 'splice' substrategy, there must be some 2965 // non-declaring expression on the LHS. Simplify this by pre-declaring 2966 // variables, rewriting 2967 // 2968 // x, y := f() 2969 // 2970 // to 2971 // 2972 // var x int 2973 // x, y = g() 2974 // 2975 // Which works as long as the predeclared variables do not overlap with free 2976 // names on the RHS. 2977 if len(rhs) != len(lhs) { 2978 assert(len(rhs) == 1 && len(returnOperands) == 1, "expected spread call") 2979 2980 for _, id := range defs { 2981 if id != nil && freeNames[id.Name] { 2982 // By predeclaring variables, we're changing them to be in scope of the 2983 // RHS. We can't do this if their names are free on the RHS. 2984 return nil, false 2985 } 2986 } 2987 2988 // Write out the specs, being careful to avoid shadowing free names in 2989 // their type expressions. 2990 var ( 2991 specs []ast.Spec 2992 specIdxs []int 2993 shadow = make(map[string]bool) 2994 ) 2995 failed := false 2996 byType.Iterate(func(typ types.Type, v any) { 2997 if failed { 2998 return 2999 } 3000 idxs := v.([]int) 3001 specIdxs = append(specIdxs, idxs[0]) 3002 texpr := typeExpr(typ, shadow) 3003 if texpr == nil { 3004 failed = true 3005 return 3006 } 3007 spec := &ast.ValueSpec{ 3008 Type: texpr, 3009 } 3010 for _, idx := range idxs { 3011 spec.Names = append(spec.Names, ast.NewIdent(defs[idx].Name)) 3012 } 3013 specs = append(specs, spec) 3014 }) 3015 if failed { 3016 return nil, false 3017 } 3018 logf("substrategy: spread assignment") 3019 return []ast.Stmt{ 3020 &ast.DeclStmt{ 3021 Decl: &ast.GenDecl{ 3022 Tok: token.VAR, 3023 Specs: specs, 3024 }, 3025 }, 3026 &ast.AssignStmt{ 3027 Lhs: callerStmt.Lhs, 3028 Tok: token.ASSIGN, 3029 Rhs: returnOperands, 3030 }, 3031 }, true 3032 } 3033 3034 assert(len(lhs) == len(rhs), "mismatching LHS and RHS") 3035 3036 // Substrategy "convert": write out RHS expressions with explicit type conversions 3037 // as necessary, rewriting 3038 // 3039 // x, y := f() 3040 // 3041 // to 3042 // 3043 // x, y := 1, int32(2) 3044 // 3045 // As required to preserve types. 3046 // 3047 // In the special case of _ = nil, which is disallowed by the type checker 3048 // (since nil has no default type), we delete the assignment. 3049 var origIdxs []int // maps back to original indexes after lhs and rhs are pruned 3050 i := 0 3051 for j := range lhs { 3052 if _, ok := nilBlankAssigns[j]; !ok { 3053 lhs[i] = lhs[j] 3054 rhs[i] = rhs[j] 3055 origIdxs = append(origIdxs, j) 3056 i++ 3057 } 3058 } 3059 lhs = lhs[:i] 3060 rhs = rhs[:i] 3061 3062 if len(lhs) == 0 { 3063 logf("trivial assignment after pruning nil blanks assigns") 3064 // After pruning, we have no remaining assignments. 3065 // Signal this by returning a non-nil slice of statements. 3066 return nil, true 3067 } 3068 3069 // Write out explicit conversions as necessary. 3070 // 3071 // A conversion is necessary if the LHS is being defined, and the RHS return 3072 // involved a nontrivial implicit conversion. 3073 for i, expr := range rhs { 3074 idx := origIdxs[i] 3075 if nonTrivial[idx] && defs[idx] != nil { 3076 typ := caller.Info.TypeOf(lhs[i]) 3077 texpr := typeExpr(typ) 3078 if texpr == nil { 3079 return nil, false 3080 } 3081 if _, ok := texpr.(*ast.StarExpr); ok { 3082 // TODO(rfindley): is this necessary? Doesn't the formatter add these parens? 3083 texpr = &ast.ParenExpr{X: texpr} // *T -> (*T) so that (*T)(x) is valid 3084 } 3085 rhs[i] = &ast.CallExpr{ 3086 Fun: texpr, 3087 Args: []ast.Expr{expr}, 3088 } 3089 } 3090 } 3091 logf("substrategy: convert assignment") 3092 return []ast.Stmt{&ast.AssignStmt{ 3093 Lhs: lhs, 3094 Tok: callerStmt.Tok, 3095 Rhs: rhs, 3096 }}, true 3097 } 3098 3099 // tailCallSafeReturn reports whether the callee's return statements may be safely 3100 // used to return from the function enclosing the caller (which must exist). 3101 func tailCallSafeReturn(caller *Caller, calleeSymbol *types.Func, callee *gobCallee) bool { 3102 // It is safe if all callee returns involve only trivial conversions. 3103 if !hasNonTrivialReturn(callee.Returns) { 3104 return true 3105 } 3106 3107 var callerType types.Type 3108 // Find type of innermost function enclosing call. 3109 // (Beware: Caller.enclosingFunc is the outermost.) 3110 loop: 3111 for _, n := range caller.path { 3112 switch f := n.(type) { 3113 case *ast.FuncDecl: 3114 callerType = caller.Info.ObjectOf(f.Name).Type() 3115 break loop 3116 case *ast.FuncLit: 3117 callerType = caller.Info.TypeOf(f) 3118 break loop 3119 } 3120 } 3121 3122 // Non-trivial return conversions in the callee are permitted 3123 // if the same non-trivial conversion would occur after inlining, 3124 // i.e. if the caller and callee results tuples are identical. 3125 callerResults := callerType.(*types.Signature).Results() 3126 calleeResults := calleeSymbol.Type().(*types.Signature).Results() 3127 return types.Identical(callerResults, calleeResults) 3128 } 3129 3130 // hasNonTrivialReturn reports whether any of the returns involve a nontrivial 3131 // implicit conversion of a result expression. 3132 func hasNonTrivialReturn(returnInfo [][]returnOperandFlags) bool { 3133 for _, resultInfo := range returnInfo { 3134 for _, r := range resultInfo { 3135 if r&nonTrivialResult != 0 { 3136 return true 3137 } 3138 } 3139 } 3140 return false 3141 } 3142 3143 type unit struct{} // for representing sets as maps