Understanding Go's Source-Level Inliner and Self-Service Modernization
Go 1.26 introduces a completely revamped go fix command, designed to help developers keep their code modern and up-to-date. Among its new features is the source-level inliner, a powerful tool that enables package authors to create simple, safe API migrations and upgrades. This Q&A explores what the source-level inliner is, how it works, and why it matters for Go developers.
What is the source-level inliner?
The source-level inliner is a Go tool that replaces a function call with a copy of the function body, substituting arguments for parameters. Unlike compiler inlining, which works on an ephemeral intermediate representation to optimize performance, the source-level inliner durably modifies the actual source code. This means the change persists in your project files, making it ideal for refactoring and API migration.

For example, if you have a call to a sum function in a function called six, the inliner can expand that call inline, directly substituting the arguments into the logic of sum. The result is a clearer, more self-contained piece of code that no longer depends on the original function.
The source-level inliner is also used by the gopls language server for its "Inline call" refactoring, which you can access via the Source Action menu in VS Code. This makes it a practical tool for everyday Go development, not just a one-time migration utility.
How does source-level inlining differ from compiler inlining?
The key difference lies in the persistence of the transformation. Compiler inlining is an optimization that happens during compilation: the compiler temporarily expands a function call in its internal representation to generate faster code, but the source code remains unchanged. In contrast, source-level inlining actually rewrites your source files, replacing the call with the function body directly.
This distinction is crucial for refactoring tools. Since source-level inlining modifies the code you work with every day, it helps you eliminate unnecessary abstractions, simplify complex call chains, and modernize interfaces without worrying about whether the compiled binary will be faster or slower. It also enables other automated transformations, such as changing a function’s signature or removing unused parameters, because the inliner can correctly propagate the changes through all call sites.
Moreover, the source-level inliner handles subtle edge cases like side effects, multiple returns, and type conversions, ensuring the rewritten code is semantically equivalent to the original. This makes it safe for automated use in go fix and gopls.
How can developers use the source-level inliner for API migrations?
The source-level inliner enables a self-service approach to API migration. Package authors can write simple transformation rules that tell go fix how to replace a deprecated function call with its modern equivalent. The inliner then applies these rules across a codebase, substituting calls with inline code that matches the new API—all without breaking correctness.
For instance, suppose a library deprecates a utility function in favor of a newer pattern. The author can provide a mapping that, when a deprecated function is detected, the inliner will expand the call and then apply additional cleanup rules. Because the inliner works at the source level, the resulting code is fully human-readable and can be further edited by hand if needed.
This is particularly valuable for large codebases where manually updating every call would be error-prone and time-consuming. The go fix command, which now includes the source-level inliner, makes it easy to run these migrations across an entire module or project with a single command.
What role does the inliner play in gopls refactorings?
gopls uses the source-level inliner as a building block for several interactive refactorings. The most direct example is the “Inline call” code action, which allows you to select a function call and replace it with the function’s body. This is useful for simplifying code or for preparing the ground for further refactoring.
Beyond direct inlining, gopls leverages the inliner for “Change signature” and “Remove unused parameter” refactorings. When you want to change a function’s signature, gopls must update every call site. The inliner helps by temporarily inlining the call, then re-extracting a new function with the desired signature. This handles tricky cases like multiple calls with different argument expressions, side effects, and return values correctly.

By relying on the same robust algorithm that powers go fix, gopls ensures that these refactorings produce correct, idiomatic Go code. The integration is seamless: you invoke a command in your editor, and the inliner’s careful substitution logic works behind the scenes to make the change safe.
What subtle correctness issues does the source-level inliner handle?
When inlining a function call, several tricky situations can arise if not handled carefully. The source-level inliner automatically manages these and more:
- Argument side effects: If an argument expression has side effects (e.g., a function call or increment), the inliner must evaluate it exactly once and in the correct order, even if the parameter is used multiple times in the body. It may introduce temporary variables to preserve the original behavior.
- Multiple return values: Inlining a function that returns multiple values requires correctly assigning them to the variables used at the call site. The inliner ensures that all return values are properly captured.
- Variable shadowing: The inliner renames variables in the inlined body to avoid conflicting with names in the caller’s scope, preventing subtle bugs.
- Closure interactions: When inlining a function that contains closures, the inliner must correctly capture variables by reference, preserving the intended semantics.
These safeguards make the source-level inliner a reliable tool for automated transformation, whether used interactively in gopls or in bulk via go fix.
How does go fix incorporate the source-level inliner?
The new go fix command in Go 1.26 includes the source-level inliner as one of its analyzers. While go fix already had several bespoke modernizers for new language features and library changes, the inliner represents the first general-purpose building block for self-service upgrades.
Package authors can now write simple rules that tell go fix to replace a call to a deprecated function with an inline expansion of that function’s modern equivalent. Because the inliner handles all the subtle correctness details automatically, these rules are safe to apply across an entire codebase.
For example, a library might provide a //go:fix inline directive (as hinted by the original post’s title) that, when run through go fix, expands all calls to the deprecated function into their modern form. This dramatically lowers the barrier to keep your code’s dependencies up-to-date, since you don’t have to wait for the Go team to write a bespoke modernizer for every change.
In essence, the source-level inliner turns go fix from a passive set of curated migrations into an extensible platform for the entire Go ecosystem.
Related Articles
- Exploring Python 3.15.0 Alpha 2: Key Features and Developer Insights
- A Complete Guide to the New Python Packaging Council: Governance, Elections, and Practical Steps
- AI Labs' Single-Minded Focus on Transformers Risk Missing True AGI, Expert Warns
- Understanding WebAssembly JSPI: Origin Trial and What It Means for Developers
- Why JavaScript Date and Time Is So Broken and How Temporal Will Fix It
- Go 1.26 Released: New Language Features, Performance Gains, and Experimental SIMD Support
- Getting Started with Python 3.15 Alpha 5: A Developer's Guide to New Features and Testing
- 5 Key Enhancements in Visual Studio Code’s Python September 2025 Release