Packages P1 and P2 can define identical struct types T1 and T2, and one
can convert from type T1 to T2 or vice versa.
The spec defines two identical struct types as:
Two struct types are identical if they have the same sequence of
fields, and if corresponding fields have the same names, and
identical types, and identical tags. Non-exported field names
from different packages are always different.
Unfortunately, garble broke this: since we obfuscated field names
differently depending on the package, cross-package conversions like the
case above would result in typechecking errors.
To fix this, implement Joe Tsai's idea: hash struct field names with the
string representation of the entire struct. This way, identical struct
types will have their field names obfuscated in the same way in all
packages across a build.
Note that we had to refactor "reverse" a bit to start using transformer,
since now it needs to keep track of struct types as well.
This failure was affecting the build of google.golang.org/protobuf,
since it makes regular use of cross-package struct conversions.
Note that the protobuf module still fails to build, but for other
reasons. The package that used to fail now succeeds, so the build gets a
bit further than before. #240 tracks adding relevant third-party Go
modules to CI, so we'll track the other remaining failures there.
Fixes#310.
This mainly cleans up the few bits of code where we explicitly kept
support for Go 1.15.x. With v0.1.0 released, we can drop support now,
since the next v0.2.0 release will only support Go 1.16.x.
Also updates all modules, including test ones, to 'go 1.16'.
Note that the TOOLEXEC_IMPORTPATH refactor is not done here, despite all
the TODOs about doing so when we drop 1.15 support. This is because that
refactor needs to be done carefully and might have side effects, so it's
best to keep it to a separate commit.
Finally, update the deps.
In Go 1.15, if a dependency is required but not listed in go.mod/go.sum,
it's resolved and added automatically.
This is changing in 1.16. From that release, one will have to explicitly
update the mod files via 'go mod tidy' or 'go get'.
To get ahead of the curve, start using -mod=readonly to get the same
behavior in 1.15, and fix all existing tests.
The only tests that failed were imports.txt and syntax.txt, the only
ones to require other modules. But since we're here, let's add the 'go'
line to all go.mod files as well.
basic.txt just builds main.go without a module. Similarly, we leave
imports.txt without a GOPRIVATE, to test the 'go list -m' fallback.
For all other tests, explicitly set GOPRIVATE, to avoid two exec calls -
both 'go env GOPRIVATE' as well as 'go list -m'. Each of those calls
takes in the order of 10ms, so saving ~26 exec calls should easily add
to 200-300ms saved from 'go test -short'.
Like other tests, importing fmt results in quite a lot of extra work,
due to the lack of build caching.
In this particular test, we wanted fmt.Println so that T.String would be
called in an indirect way, without defining or referencing Stringer
interface in the main package.
We can do that by rolling our own "tinyfmt" package in a dozen or so
lines of code.
Below is how 'go test -short -vet=off -run Script/implement' is
affected, measured via benchcmd and benchstat:
name old time/op new time/op delta
GoTestScriptImplement 3.67s ± 9% 2.65s ±11% -27.68% (p=0.008 n=5+5)
name old user-time/op new user-time/op delta
GoTestScriptImplement 8.18s ± 4% 4.55s ± 9% -44.35% (p=0.008 n=5+5)
name old sys-time/op new sys-time/op delta
GoTestScriptImplement 1.27s ±12% 0.71s ±13% -44.07% (p=0.008 n=5+5)
name old peak-RSS-bytes new peak-RSS-bytes delta
GoTestScriptImplement 145MB ± 1% 145MB ± 2% ~ (p=1.000 n=5+5)
All in all, we shave about one full second. It doesn't seem to affect
the total 'go test -short' noticeably, but every little bit counts.
Spotted while trying to link a program using unix.Syscall, since its
implementation is assembly.
Telling if a function couldn't be garbled isn't trivial. If that
function belongs to an imported package, we only load its export data
instead of type-checking from source, so we don't have all the
information needed.
Instead, use the gc export data importer to import two versions of each
dependency: its original version, for the initial type-checking, and its
garbled version, to check if any of its exported names weren't garbled.
Updates #9.
The problem with the "grep" built-in command is that it prints the
entire data if there is an error. We don't want megabytes of binary
output for a test.