Whatschat

Go 1.26's Source-Level Inliner: A Guide for API Modernization

Published: 2026-05-03 17:04:17 | Category: Programming

The Go 1.26 release introduces a revamped go fix command, and one of its standout features is the source-level inliner. This tool enables package authors to perform simple yet safe API migrations and code modernizations automatically. Whether you're a library maintainer wanting to deprecate old functions or a developer cleaning up repetitive patterns, the source-level inliner can help. Below, we answer key questions about what it is, how it works, and how you can use it.

What is the source-level inliner in Go?

The source-level inliner is a tool that replaces a function call with a copy of the called function's body, substituting actual arguments for parameters. Unlike a traditional compiler that performs inlining on its internal representation to generate faster code, this inliner modifies your source code permanently. It was originally built in 2023 and is used by gopls for interactive refactoring—for example, the "Inline call" action in VS Code. In Go 1.26, it also powers a new analyzer in go fix, allowing automated, project-wide transformations.

Go 1.26's Source-Level Inliner: A Guide for API Modernization
Source: blog.golang.org

How does the source-level inliner differ from compiler inlining?

Compiler inlining is an optimization technique that works on the compiler's internal intermediate representation (IR) to produce more efficient machine code. It's ephemeral and invisible to the developer. In contrast, the source-level inliner works directly on your Go source files, producing a durable change that you can see in your editor or commit to version control. This makes it ideal for refactoring and API migration, because the transformed code remains human-readable and can be further modified. The source-level inliner also handles many subtle correctness issues, such as variable name collisions and side effects, which a compiler inliner doesn't need to worry about since it operates at a lower level.

How can developers use the source-level inliner?

There are two primary ways to use it:

  • Interactive refactoring in gopls: In VS Code or other LSP clients, you can invoke the "Inline call" code action from the source action menu. This instantly replaces a selected function call with its inlined version.
  • Automated with go fix: The go fix command in Go 1.26 includes an analyzer that applies source-level inlining as part of its suite of modernizers. Running go fix on your project can automatically apply transformations defined by package authors (e.g., migrating from an old API to a new one).

Both methods rely on the same underlying algorithm, ensuring consistent behavior and correctness.

What makes the source-level inliner a "self-service" modernizer?

The term "self-service" means that any package author can define simple API migrations and updates without waiting for the Go team to write a specialized tool. Instead of requiring a bespoke modernizer for each new language or library change, the source-level inliner allows authors to express migrations directly—for instance, by marking a function with a special comment that tells go fix to inline calls to that function. This empowers the Go ecosystem to evolve more quickly, as library maintainers can provide automated upgrade paths for their users. The inliner's safety guarantees (handling side effects, variable shadowing, etc.) make it reliable for widespread use.

What are the benefits of using the source-level inliner for API migrations?

Using the source-level inliner for API migrations offers several advantages:

  • Correctness: It automatically resolves complex issues like argument evaluation order, temporary variable introduction, and name clashes.
  • Productivity: Developers no longer need to manually inline hundreds of function calls across a codebase.
  • Consistency: All transformations are applied uniformly, reducing the chance of human error.
  • Reversibility: Since the change is to source code, you can review it in pull requests and revert if needed.

For example, if a library deprecates a function oldFunc and provides a simpler alternative, the package author can define a rule that inlines oldFunc calls directly, allowing users to update their code with a single go fix command.

Go 1.26's Source-Level Inliner: A Guide for API Modernization
Source: blog.golang.org

Can you give an example of how source-level inlining works?

Certainly. Suppose you have a function sum(a, b int) int that returns a + b, and another function six() int that calls sum(1, 5). When you invoke the source-level inliner on the call sum(1, 5) inside six, it replaces the call with 1 + 5—the body of sum with arguments substituted. The result is func six() int { return 1 + 5 }. In gopls, this is shown with a before-and-after diff: the old code is highlighted in red (deleted) and the new code in green (inserted). The inliner ensures that any side effects in the arguments are preserved and that temporary variables are created if needed to avoid duplicate evaluations.

What role does go fix play in this ecosystem?

In Go 1.26, go fix is completely reimplemented and now includes analyzers that perform source-level transformations, including the source-level inliner. When you run go fix on your module, it can automatically apply a set of rules—some built-in (for new language features) and some defined by third-party packages. This makes go fix a powerful tool for keeping your codebase modern without manual effort. For example, if a library releases a new version that deprecates certain functions, you can update the function's definition to include an inline directive, and then running go fix will rewrite all call sites across your project.

How does the inliner support other refactorings in gopls?

The source-level inliner is a foundational building block for several gopls refactorings, such as "Change Signature" and "Remove Unused Parameter." When you change a function's signature, gopls must update all call sites to match. It does so by first inlining the original calls, then adjusting the arguments accordingly. The inliner's ability to correctly handle multiple arguments, side effects, and return values makes these complex refactorings possible. Without a robust source-level inliner, such transformations would be error-prone or require ad-hoc logic. Thus, the inliner not only serves as a standalone tool but also powers a broader set of modernizations in the Go ecosystem.