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/cmd/stringer: can't find packages #10249

Closed
randall77 opened this issue Mar 25, 2015 · 30 comments
Closed

x/tools/cmd/stringer: can't find packages #10249

randall77 opened this issue Mar 25, 2015 · 30 comments

Comments

@randall77
Copy link
Contributor

I'm having a problem using stringer with go generate. It reports errors because it can't find packages that I think it should be able to find. go build has no trouble finding them.

a.go, in directory $GOPATH/src/a:

package a

import "a/b"

type A int

const (
Aone A = 1
Atwo = 2
Athree = 3
)

//go:generate stringer -type=A

func a() {
b.B()
}

b.go, in directory $GOPATH/src/a/b:

package b

func B() {
}

In $GOPATH/src/a, this happens:

go generate
stringer: checking package: a.go:3:8: could not import a/b (can't find import: a/b)
a.go:13: running "stringer": exit status 1

Running go build instead of go generate works fine.

@minux
Copy link
Member

minux commented Mar 25, 2015 via email

@randall77
Copy link
Contributor Author

Ok, that works. Why?

@robpike
Copy link
Contributor

robpike commented Mar 26, 2015

Stringer packages to be installed so it can parse and type check the files it's reading.

@robpike robpike closed this as completed Mar 26, 2015
@josharian
Copy link
Contributor

Ok, that works. Why?

stringer uses go/types, which uses go/loader to find packages. There are multiple strategies for finding packages available. Stringer uses gcimporter, which parses gc's object files. If the package has not been installed, the object files are not available to parse.

@randall77
Copy link
Contributor Author

So this should be documented somewhere, perhaps at https://godoc.org/golang.org/x/tools/cmd/stringer
Confused the hell out of me.

@robpike
Copy link
Contributor

robpike commented Mar 27, 2015

It's not a property of stringer per se. You can't build or parse (actually type check) a package without building (or parsing) its dependencies first. Any tool that looks at types has the same property.

It's the nature of the work.

@mikioh mikioh changed the title stringer can't find packages cmd/stringer: can't find packages Mar 27, 2015
@randall77
Copy link
Contributor Author

So shouldn't stringer build its dependencies if they haven't been built yet? Or at least parse them if it can't find a built object file? Or give me a better error message than "could not import a/b (can't find import: a/b)", like "could not import a/b (it must be built first)"?

@josharian
Copy link
Contributor

@randall77 I agree entirely, but this is a broader problem than just stringer. Filed #10276 for this.

@alandonovan
Copy link
Contributor

For the record:

This CL https://go-review.googlesource.com/#/c/8561/ changes stringer to use go/loader, which loads the entire program from source code, so it gets the correct result no matter what compiler you use or how fresh your .a cache is. The change has been mothballed pending a clean-up of the go/loader API (some of which has already happened).

@szabba
Copy link

szabba commented Aug 3, 2015

What's the status on this? Will this not be implemented, or will this be addressed somewhere else (the Go gerrit seems to suggest this was abandoned altogether)?

@oryband
Copy link

oryband commented Dec 13, 2015

for the record, i'm still getting can't find import for installed pacakges, even after go installing it. Can we please revive the fix for this issue?

As a side note, I think forcing a go install of the package in order for it to get picked up by gotype is a bad choice. Most imported packages have no executable thus no reason to go install them.

@alandonovan
Copy link
Contributor

Don't hold your breath: it will likely be several months before go/loader is stable enough to have its API frozen, and this is why CL 8561 was rejected.

I agree that using compiler export data is rarely the right solution for analysis tools; source is the ground truth (and provides better diagnostic information such as locations for types and functions). The set of installed packages is usually very stale.

@pdf
Copy link

pdf commented Jan 27, 2016

@alandonovan where can I find the blocking go/loader issue(s)? I tried searching this tracker but couldn't find anything open that appears relevant.

@alandonovan
Copy link
Contributor

@pdf: #14120

mapuri added a commit to mapuri/cluster that referenced this issue Mar 23, 2016
other stringer fails due to:

golang/go#10249

Signed-off-by: Madhav Puri <madhav.puri@gmail.com>
@SamWhited
Copy link
Member

SamWhited commented Jul 11, 2016

I know this problem isn't specific to stringer, but I just spent ages trying to track it down before realizing that it's using go/types and things have to be installed; I came here to file an issue about documentation and found this issue. Even though the problem isn't specific to stringer, lots of people will be using stringer that might be confused by this issue, so I still think that it's worth documenting in the mean time, or at least mentioning it in the error message ("Can't find package <whatever>, did you go install it?")

tbg added a commit to tbg/cockroach that referenced this issue Oct 14, 2016
All packages need to be installed before we can run (some) of the checks and
code generators reliably. More precisely, anything that using x/tools/go/loader
is fragile (this includes stringer, vet and others).

The blocking issue is golang/go#14120; see
golang/go#10249 for some more concrete discussion on
`stringer` and golang/go#16086 for `vet`.
@robpike
Copy link
Contributor

robpike commented Jul 2, 2018

Reopening because the fixing CL was reverted.

@gopherbot
Copy link

Change https://golang.org/cl/121884 mentions this issue: cmd/stringer: revert CL 40403

@golang golang unlocked this conversation Jul 3, 2018
@benesch
Copy link
Contributor

benesch commented Jul 5, 2018

Reverting that CL just broke any code that assumed stringer was safe to run without running go install -i first. And that was a valid assumption to make for the last twelve months. I realize it was slow (in fact I raised that very issue on the mailing list in May: https://groups.google.com/forum/#!topic/golang-dev/NL1zE4Sesg0), but better slow and correct than fast and subtly broken.

I know that x/tools is not subject to the standard compatibility promise, but we'd lived with slow stringer for a year. Couldn't we have waited a few more months for go/packages to land? Or put the fast-but-broken importer behind a flag, like -importer=gc? It's one thing for code to be broken, but it's another thing entirely to fix it, then intentionally break it again.

And when I say "broken," I understand that it's working as designed. I mean that it has a very hostile design. Running go build -i PKG beforehand isn't even a workable solution, since that often tries to install to an unwriteable GOROOT.

@robpike
Copy link
Contributor

robpike commented Jul 5, 2018

"Reverting that CL just broke any code that assumed stringer was safe to run without running go install -i first. " No it didn't, only some code, while not reverting it broke mine. The situation is unfortunately very messy. I for one have never run go install -i, not once.

It's not just that stringer was slow, it's that it didn't work as it was supposed to. It's meant to create code; requiring the package it writes into to be fully correct beforehand is putting the cart before the horse. The idea behind stringer (other than being a plaything to test out "go generate") was that it would pick up some half-written code with a constant type defined and add a file that helps the package along. But various steps along the way, along with a lack of initial insight, have broken that intention by requiring the package it's in to be valid beforehand.

There is a fundamental conflict going on here. I doubt that go/packages will fix it, since I presume it too will require a complete type-checkable package before stringer will run.

I thought the resolution would be to go back to the beginning and roll out as much as possible of the dependence on types. Evaluation of constants would then require avoiding type checking and adding its own evaluator. I haven't done that yet; one reason is that in general one might have to look at another package to do that, for cases like const A = pkg.C, and doing that requires importing again. Back to square one.

It's possible there is literally no clean way to resolve this.

We could roll back my recent changes, and maybe should do so, but the original problem would then remain unaddressed.

@myitcv
Copy link
Member

myitcv commented Jul 6, 2018

I doubt that go/packages will fix it, since I presume it too will require a complete type-checkable package before stringer will run.

Can we not simply loosen the requirement that the target fully type checks? e.g.:

https://go-review.googlesource.com/c/tools/+/122377

That way we can leverage the constant evaluation code etc in go/types.

Same approach could be followed with go/packages (which would also solve the "speed" problem as well as imports being current), although the configuration/usage would likely be a bit different.

The above CL allows the following to generate successfully:

package main

//go:generate stringer -type Banana

type Banana uint

const (
        B1 Banana = iota
)

var x Apple

func main() {
}

whereas with the current stringer it fails:

stringer: checking package: main.go:11:7: undeclared name: Apple
main.go:3: running "stringer": exit status 1

@alandonovan
Copy link
Contributor

alandonovan commented Jul 6, 2018 via email

@benesch
Copy link
Contributor

benesch commented Jul 6, 2018

"Reverting that CL just broke any code that assumed stringer was safe to run without running go install -i first. " No it didn't, only some code, while not reverting it broke mine.

No, it subtly broke all code and workflows that do not involve running some equivalent of go install -i.

If I have a file in package github.com/benesch/stringertest/b like this

package b

type Garbage int

const (
  FooGarbage Garbage = iota
  BarGarbage
)

I can run stringer -type=Garbage ./b successfully. But as soon as I introduce a dependency on a new package, I run the risk of using outdated type information. Suppose I apply this diff:

diff --git a/b/b.go b/b/b.go
index ebfda0e..3c9bcb7 100644
--- a/b/b.go
+++ b/b/b.go
@@ -1,8 +1,11 @@
 package b
 
+import "github.com/benesch/stringertest/a"
+
 type Garbage int
 
 const (
   FooGarbage Garbage = iota
   BarGarbage
+  BazGarbage = a.Sym
 )

Now stringer fails because github.com/benesch/stringertest/a is not installed:

$ stringer -type=Garbage 
stringer: checking package: b.go:3:8: could not import github.com/benesch/stringertest/a (can't find import: "github.com/benesch/stringertest/a")

There are two ways to resolve this. I can run go install on every dependency of b (in this case, just go install ./a), or I can run go install -i ./b and let the Go toolchain sort out the dependency graph. The latter option is the only reasonable option when a package has hundreds of transitive dependencies and any one of them may have changed.

This was not a problem when stringer used the source importer. Here, github.com/benesch/stringertest/a is not installed, and source-importer stringer succeeds:

$ (cd $GOPATH/src/golang.org/x/tools && git checkout ffe8890^ && go install ./cmd/stringer)
$ stringer -type=Garbage 
# success

The situation is unfortunately very messy. I for one have never run go install -i, not once.

Yes, which is why you ran into the "could not import" error when trying to use stringer: #25650 (comment)

I thought the resolution would be to go back to the beginning and roll out as much as possible of the dependence on types. Evaluation of constants would then require avoiding type checking and adding its own evaluator. I haven't done that yet; one reason is that in general one might have to look at another package to do that, for cases like const A = pkg.C, and doing that requires importing again. Back to square one.

There are two orthogonal issues that are being conflated in this discussion. The first issue is how stringer loads a package's dependencies. The second is what sort of type checking stringer performs, if any.

I don't see why the first issue has any bearing on the second. Your change to pass IgnoreFuncBodies to the type checker is equally effective with the source importer as it is with the gc importer. Ditto for the CL @myitcv has proposed to ignore errors from the type-checker.

@robpike
Copy link
Contributor

robpike commented Jul 6, 2018

With great reluctance, I will roll back my changes and pray that Alan Donovan's work will fix this, if only to shut down this conversation.

I do believe there is a deep problem here that only I am worried about, but then if it's only me that worries about it, I guess it doesn't matter much.

@gopherbot
Copy link

Change https://golang.org/cl/122535 mentions this issue: cmd/stringer: revert back to source importer

gopherbot pushed a commit to golang/tools that referenced this issue Jul 7, 2018
Roll back my two recent changes. Stringer is now very slow again,
but works in most use cases.

My git foo is insufficient to do this as a revert, but it is a by-hand
reversion of CLs

	https://go-review.googlesource.com/121884
	https://go-review.googlesource.com/121995

See the issue for a long conversation about the general problem.

Update golang/go#10249
Update golang/go#25650

Change-Id: I7b6ce352a4c7ebf0977883509e9d7189aaac1251
Reviewed-on: https://go-review.googlesource.com/122535
Run-TryBot: Rob Pike <r@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
@benesch
Copy link
Contributor

benesch commented Jul 8, 2018

With great reluctance, I will roll back my changes and pray that Alan Donovan's work will fix this, if only to shut down this conversation.

Thanks. It's appreciated.

I do believe there is a deep problem here that only I am worried about, but then if it's only me that worries about it, I guess it doesn't matter much.

I'm also worried about this problem now that you've raised it, so that makes at least two of us. As I've mentioned elsewhere, I think https://go-review.googlesource.com/c/121995/ is a step in the right direction and I hope you'll resubmit it.

golangci pushed a commit to golangci/tools that referenced this issue Jul 28, 2018
Revert "cmd/stringer: use source importer when available"

This reverts CL 40403.

The idea is to avoid type-checking and use just parsing, which should be
enough for stringer.

Separately reopening golang/go#10249 because the original change closed that issue,
but the change is itself causing other problems as described in the discussion
at golang/go#25650.

This reversion restores the old behavior of stringer and will be followed
with other fixes if they can be worked out.

Change-Id: I8404d78da08043ede1a36b0e135a3fc7fdf6728d
Reviewed-on: https://go-review.googlesource.com/121884
Reviewed-by: Ian Lance Taylor <iant@golang.org>
SOF3 pushed a commit to SOF3/go-stringer-inverse that referenced this issue Aug 23, 2018
This means that running stringer should always
have the intended effect, without having to
go install the package first, which was a common
source of confusion.

The source importer is marginally slower,
but stringer is run infrequently,
and we're only typechecking one package (and fmt),
not an entire tree, as vet does.

Fixes golang/go#10249

Change-Id: Ib8cde29bd6cc596964dbe7348065932dd59075fc
Reviewed-on: https://go-review.googlesource.com/40403
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Robert Griesemer <gri@golang.org>
SOF3 pushed a commit to SOF3/go-stringer-inverse that referenced this issue Aug 23, 2018
Revert "cmd/stringer: use source importer when available"

This reverts CL 40403.

The idea is to avoid type-checking and use just parsing, which should be
enough for stringer.

Separately reopening golang/go#10249 because the original change closed that issue,
but the change is itself causing other problems as described in the discussion
at golang/go#25650.

This reversion restores the old behavior of stringer and will be followed
with other fixes if they can be worked out.

Change-Id: I8404d78da08043ede1a36b0e135a3fc7fdf6728d
Reviewed-on: https://go-review.googlesource.com/121884
Reviewed-by: Ian Lance Taylor <iant@golang.org>
SOF3 pushed a commit to SOF3/go-stringer-inverse that referenced this issue Aug 23, 2018
Roll back my two recent changes. Stringer is now very slow again,
but works in most use cases.

My git foo is insufficient to do this as a revert, but it is a by-hand
reversion of CLs

	https://go-review.googlesource.com/121884
	https://go-review.googlesource.com/121995

See the issue for a long conversation about the general problem.

Update golang/go#10249
Update golang/go#25650

Change-Id: I7b6ce352a4c7ebf0977883509e9d7189aaac1251
Reviewed-on: https://go-review.googlesource.com/122535
Run-TryBot: Rob Pike <r@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
SOF3 pushed a commit to SOF3/go-stringer-inverse that referenced this issue Aug 23, 2018
This means that running stringer should always
have the intended effect, without having to
go install the package first, which was a common
source of confusion.

The source importer is marginally slower,
but stringer is run infrequently,
and we're only typechecking one package (and fmt),
not an entire tree, as vet does.

Fixes golang/go#10249

Change-Id: Ib8cde29bd6cc596964dbe7348065932dd59075fc
Reviewed-on: https://go-review.googlesource.com/40403
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Robert Griesemer <gri@golang.org>
SOF3 pushed a commit to SOF3/go-stringer-inverse that referenced this issue Aug 23, 2018
Revert "cmd/stringer: use source importer when available"

This reverts CL 40403.

The idea is to avoid type-checking and use just parsing, which should be
enough for stringer.

Separately reopening golang/go#10249 because the original change closed that issue,
but the change is itself causing other problems as described in the discussion
at golang/go#25650.

This reversion restores the old behavior of stringer and will be followed
with other fixes if they can be worked out.

Change-Id: I8404d78da08043ede1a36b0e135a3fc7fdf6728d
Reviewed-on: https://go-review.googlesource.com/121884
Reviewed-by: Ian Lance Taylor <iant@golang.org>
SOF3 pushed a commit to SOF3/go-stringer-inverse that referenced this issue Aug 23, 2018
Roll back my two recent changes. Stringer is now very slow again,
but works in most use cases.

My git foo is insufficient to do this as a revert, but it is a by-hand
reversion of CLs

	https://go-review.googlesource.com/121884
	https://go-review.googlesource.com/121995

See the issue for a long conversation about the general problem.

Update golang/go#10249
Update golang/go#25650

Change-Id: I7b6ce352a4c7ebf0977883509e9d7189aaac1251
Reviewed-on: https://go-review.googlesource.com/122535
Run-TryBot: Rob Pike <r@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
@andig
Copy link
Contributor

andig commented Jan 27, 2019

There are two orthogonal issues that are being conflated in this discussion. The first issue is how stringer loads a package's dependencies. The second is what sort of type checking stringer performs, if any.

I've come here from #24661 via https://go-review.googlesource.com/c/tools/+/126535 and #25650 (comment).

Although this issue is closed, the problem still exists in go1.11.5. As the issues above basically go round in circles I'd appreciate your attention.

@golang golang locked and limited conversation to collaborators Jan 27, 2020
@rsc rsc unassigned robpike Jun 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests