Compiler Closure: @enum, property folding and JSC_UNSAFE_NAMESPACE
initial situation
I have the following code:
var NS = {}; // namespace
NS.myEnum = {
foo: 1,
bar: 2
};
var extendedNS = Object.create(NS);
extendedNS.myAlert = function (x) { alert(x); };
extendedNS.myAlert(extendedNS.myEnum.foo);
It compiles successfully with this command (no warnings or errors):
java -jar compiler-20150609.jar --js test.js --compilation_level ADVANCED --warning_level VERBOSE
Question 1
According to the docs forJSC_UNSAFE_NAMESPACE
, I think Advanced optimization can replace NS.myEnum
with NS$myEnum
and then remove NS
.
So why doesn't the compiler raise a warning for this line?
var extendedNS = Object.create(NS);
Isn't that a dangerous namespace reference NS
? Shouldn't the compiler warn: "incomplete alias generated for namespace NS
"?
Calling like @enum compiled output
Now I mark NS.myEnum
as an enum:
/**
* @enum {number}
*/
NS.myEnum = {
foo: 1,
bar: 2
};
According to this old SO answer , the compiler expects to collapse the enum value into separate variables. So I think the compiler can now collapse NS.myEnum
to:
NS$myEnum$foo = 1;
NS$myEnum$bar = 2;
The compiler now issues a warning:
WARNING - incomplete alias created for namespace NS
var extendedNS = Object.create(NS);
^
I think I understand why: Optimization Advanced removed NS
after collapsing enum values.
The compiled output is indeed broken:
var a = Object.create({});
a.a = function() {
alert(a.c.b); // a.c.b doesn't exist, so a runtime error will occur
};
a.a();
Question 2
Now I add a tag @nocollapse
to the enum ("Indicates a property that should not be collapsed into a variable by the compiler. If you annotate a property that is an object with @nocollapse
, all its properties will also remain mismatched."):
/**
* @enum {number}
* @nocollapse
*/
NS.myEnum = {
foo: 1,
bar: 2
};
The compiled output is now valid code:
var a = Object.create({c:{a:1, f:2}});
a.b = function() {
alert(a.c.a); // a.c.a does exist
};
a.b();
But the compiler raises a warning anyway JSC_UNSAFE_NAMESPACE
:
WARNING - incomplete alias created for namespace NS
var extended = Object.create(NS);
^
Why? Is there another tag to add to NS.myEnum
to prevent this warning?
(Note: I would prefer no @suppress
warning. I would like to understand and correct the cause of the warning.)
source to share
The main problem comes down to the fact that traditionally properties @enum
have always been collapsed - so a warning when annotation is added @enum
, since the code might be broken (and is in your first example).
@nocollapse
blocks an enumeration overflow, and the warning is probably incorrectly issued when this annotation is present. You can report a bug if you like, but this is likely to be a low priority issue.
In general, enums are meant to be used more like constants, and thus use them since proto-object is not the intended / supported behavior.
The rules and cases involving property destruction are complex. The best way to understand them is to look at the tester to see the specific patterns that trigger the alert.
source to share