Go version
go version go1.26.1 darwin/arm64
Output of go env in your module/workspace:
What did you do?
I wasn't sure whether to report as a bug or enhancement, as this may be within the line of expectations, but I noticed that go fix fails to inline if an inline is an argument to a function/method that itself has to be inlined. If this happens within a package, the whole package is ignored; "inlines" that work in other packages are not applied.
Some things I tried to see what could make this work;
- Putting the types to inline in separate files does not make a difference (so it seems the "skip" is at the package level).
- Formatting the types to inline over multiple lines did not make a difference (this was testing if the "skip" was due to conflicts / adjacent lines).
I also tried if running go fix multiple times would help (as it sometimes would if applying multiple would result in a merge conflict), but unfortunately, that didn't work.
I'm not (yet) familiar with the implementation / logic under the hood for this feature, and maybe this is just a limitation to document, but also looked at the problem cases, and wondered if it could apply these changes in multiple passes (either automatically, or repeated go fix), for example;
Before:
client.NewWithOpts(client.FromEnv, client.WithLegacyOpt("x"))
client.NewWithOpts(client.FromEnv, client.WithLegacyOpt("x"), client.WithLegacyOpt2())
Pass 1:
client.NewWithOpts(client.FromEnv, client.WithOpt("x"))
client.NewWithOpts(client.FromEnv, client.WithOpt("x"), client.WithOpt2())
Pass 2:
client.New(client.FromEnv, client.WithOpt("x"))
client.New(client.FromEnv, client.WithOpt("x"), client.WithOpt2())
I created an example module that I used to test some of these scenarios (attached); some examples from that described below;
example.zip
(edit: attached the wrong example, and updated with extra example 😂 )
What did you see happen?
Examples
Given these //go:fix inline directives;
package client
type Client struct{}
type Opt func(*Client)
type CreateOpt struct{ Cmd []string }
//go:fix inline
type StrSlice = []string
func FromEnv(*Client) {}
//go:fix inline
func WithLegacyOpt(v string) Opt { return WithOpt(v) }
func WithOpt(string) Opt { return nil }
//go:fix inline
func WithLegacyOpt2() Opt { return WithOpt2() }
func WithOpt2() Opt { return nil }
//go:fix inline
func NewWithOpts(opts ...Opt) *Client { return New(opts...) }
func New(...Opt) *Client { return nil }
//go:fix inline
func (c *Client) CreateLegacy(o CreateOpt) { c.Create(o) }
func (c *Client) Create(CreateOpt) {}
✅ These work
opts := []client.Opt{
client.FromEnv,
client.WithLegacyOpt("x"),
client.WithLegacyOpt2(),
}
c := client.NewWithOpts(opts...)
c.Create(client.CreateOpt{Cmd: client.StrSlice{"top"}})
cmd := client.StrSlice{"top"}
c.CreateLegacy(client.CreateOpt{Cmd: cmd})
client.New(client.FromEnv, client.WithLegacyOpt("x"))
client.New(client.FromEnv, client.WithLegacyOpt("x"), client.WithLegacyOpt2())
client.NewWithOpts(client.FromEnv)
c := client.New(client.FromEnv)
c.Create(client.CreateOpt{Cmd: client.StrSlice{"top"}})
❌ These fail
client.NewWithOpts(client.FromEnv, client.WithLegacyOpt("x"))
client.NewWithOpts(client.FromEnv, client.WithLegacyOpt("x"), client.WithLegacyOpt2())
Combining a "failing" with a "non failing" inline will result in the whole package not being updated;
// OK works when in a separate package (see package "b"), but fails when in same package as [KO]
func OK() {
client.New(client.FromEnv, client.WithLegacyOpt("x"))
}
// KO fails (due to nested inlines?), and causes whole package to be skipped.
func KO() {
client.NewWithOpts(client.FromEnv, client.WithLegacyOpt("x"))
}
What did you expect to see?
I expected that repeated go fix runs could resolve this.
Go version
go version go1.26.1 darwin/arm64
Output of
go envin your module/workspace:What did you do?
I wasn't sure whether to report as a bug or enhancement, as this may be within the line of expectations, but I noticed that
go fixfails to inline if an inline is an argument to a function/method that itself has to be inlined. If this happens within a package, the whole package is ignored; "inlines" that work in other packages are not applied.Some things I tried to see what could make this work;
I also tried if running
go fixmultiple times would help (as it sometimes would if applying multiple would result in a merge conflict), but unfortunately, that didn't work.I'm not (yet) familiar with the implementation / logic under the hood for this feature, and maybe this is just a limitation to document, but also looked at the problem cases, and wondered if it could apply these changes in multiple passes (either automatically, or repeated
go fix), for example;Before:
Pass 1:
Pass 2:
I created an example module that I used to test some of these scenarios (attached); some examples from that described below;
example.zip
(edit: attached the wrong example, and updated with extra example 😂 )
What did you see happen?
Examples
Given these
//go:fix inlinedirectives;✅ These work
❌ These fail
Combining a "failing" with a "non failing" inline will result in the whole package not being updated;
What did you expect to see?
I expected that repeated
go fixruns could resolve this.