-
Notifications
You must be signed in to change notification settings - Fork 335
Fix cyclic dependencies bug #1180
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
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this is the correct fix for this bug.
Pkl allows circular imports (except in cases where a module's type is defined in terms of itself, like two modules extending each other).
Also, amending/extending modules expose types defined on their parent.
I created a reproducer for this bug in this issue here: #1183
I think either:
- We throw a meaningful error about some circular dependency
- We fix some deeper underlying issue so that this code works
BTW: can we add the reproducer as a test case here? You can add them to the input-helpers
dir.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good start, but this needs to be refined some. See comments
|
||
var importedModule = (VmTyped) result; | ||
if (importedModule.isNotInitialized() | ||
&& importedModule.isModuleObject() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should always be a module object, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. Removed the check.
} | ||
} | ||
|
||
module.setCachedValue(importName, result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be cacheing this under the same name as the import value. Otherwise, this snippet breaks:
import "amendingFoo.pkl"
// here, `amendingFoo` should resolve to the prototype
res: amendingFoo.Foo
// here, `amendingFoo` should resolve to the import itself
bar = amendingFoo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. cycles2.pkl
tests that (fails if you cache).
var amendedModuleKey = moduleInfo.getAmendedModuleKey(); | ||
|
||
if (amendedModuleKey != null) { | ||
return VmLanguage.get(null).loadModule(amendedModuleKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The amended module key itself may be amending another module; we need to keep going until we find the first non-amending module. Can we add a test for this?
Also, pass the node in when looking up the reference
return VmLanguage.get(null).loadModule(amendedModuleKey); | |
return VmLanguage.get(this).loadModule(amendedModuleKey, this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! I changed the test to have another layer of indirection.
if (prototypeModule != null) { | ||
result = prototypeModule; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The result of getImport
should always be the prototype in all cases, even when the module has not yet been initialized.
In some very specific scenarios cyclic dependencies may lead to a null pointer due to the module not being properly initialized.
Fixes #1183.