Repository navigation
fix(compiler): defer variables that read variables needing other files - #551
Merged
Merged
Conversation
A package variable whose initializer uses a declaration of another file, such as a struct type, is initialized lazily, as that file may not be evaluated yet. A variable that read it was still initialized eagerly, so reading it ran the lazy initializer early, and threw a ReferenceError when the other file's class was not declared yet. github.com/pkg/sftp has this: sftpExtensions = supportedSFTPExtensions, a slice of a type of another file. Such readers are now lazy too, unless their initializers have runtime effects, transitively. Signed-off-by: Randall C. O'Reilly <oreilly@ucdavis.edu>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A package variable whose initializer uses a declaration of another file of its package, such as a struct type, is initialized lazily through a getter, since that file may not be evaluated yet. But a variable that only reads such a variable stayed eager, so its initializer called the getter at module evaluation, which ran the lazy initializer early anyway. When the file declaring the class is evaluated after the reader's file, as happens in an import cycle between the files, this throws a ReferenceError (Cannot access 'X' before initialization).
github.com/pkg/sftp has this pattern: sftp.go declares supportedSFTPExtensions as a slice of sshExtensionPair, a type of packet.go, and then sftpExtensions = supportedSFTPExtensions. A program that imports it failed at load time.
lazyPackageVars now makes such readers lazy too, transitively, through markLazyReaders. It only propagates from variables made lazy because their initializers or zero values need other files, so the whole-program handling of deferred tables is unchanged, and it leaves eager the initializers with runtime effects and blank variables, which must still run at package initialization.
The cross_file_struct_typeinfo_zero fixture gains a third file, whose table of a type of b.go is read by another variable, and b.go uses that variable, so b.go is evaluated after it; it failed with the ReferenceError before. The full compiler test suite passes, with no other generated fixture changes.