Codenil

7 Key Aspects of Go 1.26's Source-Level Inliner You Should Know

Published: 2026-05-11 09:47:50 | Category: Programming

The release of Go 1.26 brings a completely revamped go fix subcommand, designed to help developers keep their codebases modern and up-to-date. Among its most exciting features is the source-level inliner—a tool that goes beyond typical compiler optimizations to actually rewrite your source code. Whether you're a package author looking to simplify API migrations or a developer curious about the latest Go tooling, understanding this new inliner is essential. Below, we break down the seven most important things you need to know about the source-level inliner, from its basic operation to its role in automated refactoring and self-service upgrades.

1. What Is the Source-Level Inliner?

The source-level inliner is a transformation algorithm that replaces a function call with a copy of the called function's body, substituting actual arguments for formal parameters. Unlike traditional compiler inlining—which operates on an internal intermediate representation to generate faster machine code—this inliner modifies your Go source files permanently. Introduced in 2023 as a building block for refactoring tools, it now powers several features in Go 1.26. Think of it as a surgical tool that can expand a call site into its full implementation, making the code explicit and often easier to optimize later. This capability is especially valuable when migrating deprecated APIs or simplifying complex call chains.

7 Key Aspects of Go 1.26's Source-Level Inliner You Should Know
Source: blog.golang.org

2. How Source-Level Inlining Works

When you inline a function call, the inliner takes the body of the called function and pastes it directly at the call site, replacing each parameter with the corresponding argument. For example, if you have sum(a, b) defined as return a + b, inlining sum(10, 20) would produce 10 + 20. The algorithm handles subtle details like variable renaming to avoid name clashes and preserving evaluation order. It also respects Go's scoping rules and correctly manages side effects. This transformation is safe because it preserves the original semantics of the program. In practice, the source-level inliner is invoked either through an interactive refactoring command in your editor (via gopls) or automatically as part of go fix when a //go:fix inline directive is present.

3. Difference from Compiler Inlining

Many developers are familiar with compiler inlining, where the Go compiler replaces a function call with its body during optimization to reduce overhead. However, compiler inlining is an ephemeral transformation—it happens behind the scenes and does not change your source code. The source-level inliner, by contrast, rewrites your source files. This makes it a refactoring tool rather than an optimization technique. Because it modifies the code you see and maintain, it can be used for permanent migrations: for instance, replacing a call to a deprecated library function with its inline expansion. Another key difference is that the source-level inliner is invoked deliberately (manually or via a directive), while compiler inlining happens automatically based on heuristics.

4. Integration with gopls (The Go LSP)

If you've ever used gopls with VS Code or another LSP client, you may have seen the "Inline call" code action on the Source Action menu. This feature is powered by the same source-level inliner. When you select a function call and trigger the inline action, gopls uses the inliner to expand the call in place. The resulting diff is presented to you as a preview, and you can accept or reject it. This makes the inliner accessible as an interactive refactoring, giving developers fine-grained control. Beyond inline call, gopls also uses the inliner internally for other operations such as "Change Signature" and "Remove Unused Parameter", because these refactorings often need to adjust call sites—and the inliner handles those transformations safely.

5. Use in Other Refactoring Tools

The source-level inliner is not just a standalone feature; it's a foundational component for several refactoring operations in the Go ecosystem. When you perform a "Change Signature" refactoring, gopls needs to update all call sites to match the new signature. In some cases, it may be simpler to first inline the old call and then rewrite the resulting code. Similarly, "Remove Unused Parameter" can be implemented by inlining any call to the function and dropping the unused argument. The inliner's ability to handle complex transformations (like renaming variables and preserving order) makes it a reliable building block. This modular design means that as the inliner improves, all dependent refactorings benefit automatically. For developers, this translates to more robust and predictable code transformations across the board.

7 Key Aspects of Go 1.26's Source-Level Inliner You Should Know
Source: blog.golang.org

6. Role in the New go fix Command

Go 1.26's overhauled go fix command includes the source-level inliner as one of its analyzers and fixers. While go fix has long provided bespoke modernizers for language and library updates, the inliner introduces a "self-service" model: any package author can define API migrations using special directives. When you run go fix, it scans your source code for functions annotated with //go:fix inline and automatically inlines calls to those functions. This allows library maintainers to deprecate old APIs and provide a seamless upgrade path—users just run go fix and their code is updated. The inliner's correctness guarantees ensure that the migration is safe, handling edge cases like multiple returns or variadic arguments without introducing bugs.

7. How Package Authors Can Use It for API Migrations

If you maintain a Go package, you can leverage the source-level inliner to simplify API migrations. By placing a //go:fix inline directive on a deprecated function, you tell go fix that calls to this function should be replaced by its body at call sites. For example, if you rename a function or change its signature, you can keep the old function as a compatibility wrapper and mark it for inline. Running go fix on user code will then expand all calls to the old function, allowing users to update their code efficiently. This approach reduces manual effort and human error. Additionally, you can combine the inliner with other analyzers to perform complex migrations, like moving from a monolithic utility function to more specific ones. The self-service nature means you don't need to wait for the Go team to build a custom modernizer—you can do it yourself.

Conclusion

The source-level inliner is a powerful addition to Go's tooling ecosystem, bridging the gap between compiler optimizations and practical source-level refactoring. From interactive use in gopls to automated migrations in go fix, it empowers both developers and package authors to keep their code clean and up-to-date. As the first "self-service" modernizer, it sets the stage for more community-driven improvements in future Go releases. To get started, update to Go 1.26 and experiment with the go fix command or try the inline call action in your editor. For more details, revisit Item 1 for a refresher on the basics.