Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/tools/internal/refactor/inline: analyzer is non-deterministic #67335

Open
lfolger opened this issue May 13, 2024 · 2 comments
Open

x/tools/internal/refactor/inline: analyzer is non-deterministic #67335

lfolger opened this issue May 13, 2024 · 2 comments
Assignees
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Refactoring Issues related to refactoring tools Tools This label describes issues relating to any tools in the x/tools repository.
Milestone

Comments

@lfolger
Copy link
Contributor

lfolger commented May 13, 2024

Go version

not relevant

Output of go env in your module/workspace:

not relevant

What did you do?

While preparing the reproducer for (https://go.dev/issue/67336), I encounter non-determinism in the analyzer or test-framework. I don't know if there is a smaller reproducer either.

func TestImport(t *testing.T) {
	files := map[string]string{
		"define/my/typ/foo.go": `
		package typ
		type T int
		`,

		"some/other/pkg/foo.go": `
		package pkg
		import "context"
		import "define/my/typ"
		func Foo(typ.T) context.Context{ return nil }
		`,

		"one/more/pkg/foo.go": `
		package pkg
		func Bar() {}
		`,

		"to/be/inlined/foo.go": `
			package inlined

			import "context"
			import "some/other/pkg"
			import "define/my/typ"

			// inlineme
			func Baz(ctx context.Context) context.Context {
				return pkg.Foo(typ.T(5))
			}
		`,

		"b/c/foo.go": `
package c
import (
	"context"
	"to/be/inlined"
	"one/more/pkg"
)

const (
	// This is a variable
	someConst = 5
)

func foo() {
	inlined.Baz(context.TODO()) // want "inline call of inlined.Baz"
	pkg.Bar()
}
		`,
		"b/c/foo.go.golden": `package c
import (
	"context"
	"one/more/pkg"
	pkg0 "some/other/pkg"
	
	// This is a variable
	"define/my/typ"
)

const (
	someConst = 5
)

func foo() {
	var _ context.Context = context.TODO()
	pkg0.Foo(typ.T(5)) // want "inline call of inlined.Baz"
	pkg.Bar()
}`,
	}
	dir, cleanup, err := analysistest.WriteFiles(files)
	if err != nil {
		t.Fatal(err)
	}
	analysistest.RunWithSuggestedFixes(t, dir, analyzer.Analyzer, "b/c")
	cleanup()
}

What did you see happen?

Sometimes the test fails (non-deterministically) with:

=== RUN   TestImport
    third_party/golang/go_tools/go/analysis/analysistest/analysistest.go:263: suggested fixes failed for /tmp/analysistest1470885990/src/b/c/foo.go:
        --- /tmp/analysistest1470885990/src/b/c/foo.go.golden
        +++ actual
        @@ -14,7 +14,8 @@
         )
         
         func foo() {
        -       var _ context.Context = context.TODO()
        +       var _ context.
        +               Context = context.TODO()
                pkg0.Foo(typ.T(5)) // want "inline call of inlined.Baz"
                pkg.Bar()
         }
--- FAIL: TestImport (1.43s)

I don't know if this is an issue with the test framework or with the analyzer.

What did you expect to see?

I would expect the test to always pass (minus the bug tracked in https://go.dev/issue/67336).

@gopherbot gopherbot added the Tools This label describes issues relating to any tools in the x/tools repository. label May 13, 2024
@gopherbot gopherbot added this to the Unreleased milestone May 13, 2024
@lfolger
Copy link
Contributor Author

lfolger commented May 13, 2024

cc: @adonovan

@adonovan adonovan self-assigned this May 13, 2024
@adonovan adonovan added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Refactoring Issues related to refactoring tools labels May 13, 2024
@adonovan adonovan modified the milestones: Unreleased, gopls/v0.16.0 May 13, 2024
@adonovan
Copy link
Member

adonovan commented May 13, 2024

Thanks for the very helpful test case, which reproduces the bug for me. My immediate guess as to the cause is that the order in which the files (e.g. caller and callee) are added to the token.FileSet is nondeterministic, and that the relative token.Pos values affect the formatter logic that decides when to insert a line break.

[Update: doesn't seem to be exactly that. The Pos values of caller and callee are completely deterministic in the test. When I enable logging (Options.Logf) I notice that the logged binding decl has the same nondeterminism problem in isolation when printed with debugFormatNode(caller.Fset...). Passing new(token.FileSet) makes the logging deterministic though.]

@findleyr findleyr modified the milestones: gopls/v0.16.0, gopls/v0.17.0 May 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Refactoring Issues related to refactoring tools Tools This label describes issues relating to any tools in the x/tools repository.
Projects
None yet
Development

No branches or pull requests

4 participants