Description
While testing the compiler for Luau, I came across an issue with mutable globals.
The compiler will assume every global obtained (if optimisation is 1+) is importable. This is perfect for performance. However, if there's a metamethod set on the global scope that would return different values for one index at runtime, this becomes an issue that is a pain to debug, as when you are indexing, you are expecting potentially different values (say, in a loop), and you just get something that is invalid due to the importing behaviour returning the cached global (which was MARKED as mutable).
After combing through the compiler source, I met with the faulty line at canImport
bool canImport(AstExprGlobal* expr)
{
return options.optimizationLevel >= 1 && getGlobalState(globals, expr->name) != Global::Written;
}
This function assumes that every global can be imported, as long as it has not been written to. This is fine; however, it completely disregards globals that may change in the environment itself due to the presence of metamethods in the global scope. The fix would simply be checking if the global is Global::Default
, which would make it so if a variable is mutable, it cannot be imported; this, however, could come with some repercussions on performance. I believe the sacrifice for a global inclusion is far outweighed by the potential bugs and weird conditions this creates.
If this isn't really a bug, then it should be simply documented better about how mutableGlobals
works and its purpose. Currently, they are a feature that SHOULD fix this bug, but they only do it on import chains.