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
According to the docs for JSC_UNSAFE_NAMESPACE, I think the Advanced optimisations may replace NS.myEnum with NS$myEnum, and then remove NS.
So why does the compiler not raise a warning for this line?
var extendedNS = Object.create(NS);
Isn't this an unsafe reference to the namespace NS? Shouldn't the compiler warn: "incomplete alias created for namespace NS"?
I now 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 single variables". So I think the compiler may now collapse NS.myEnum to:
NS$myEnum$foo = 1;
NS$myEnum$bar = 2;
The compiler now raises a warning:
WARNING - incomplete alias created for namespace NS
var extendedNS = Object.create(NS);
^
I think I understand why: the Advanced optimisations may have removed NS after collapsing the enum's 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();
I now add a @nocollapse tag to the enum ("Denotes a property that should not be collapsed by the compiler into a variable. If you annotate a property that is an object with @nocollapse, all its properties will also remain uncollapsed."):
/**
* @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 still raises a JSC_UNSAFE_NAMESPACE warning:
WARNING - incomplete alias created for namespace NS
var extended = Object.create(NS);
^
Why? Is there another tag I need to add to NS.myEnum to prevent this warning?
(Note: I'd prefer not to @suppress the warning. I'd like to understand and fix the cause of the warning.)
The core issue comes down to the fact that traditionally, @enum properties have always been collapsed - thus the warning when the @enum annotation is added as code could be broken (and is in your first example).
@nocollapse does block enum collapsing and the warning is probably incorrectly emitted when that annotation is present. You can file a bug about this if you wish, but it will probably be a low priority issue.
In the general case, enums are designed to be used more like constants and thus using them as the proto object is not an intended/supported behavior.
The rules and cases surrounding property collapsing are complex. The best way to understand them is look through the unit tests to see the specific patterns which trigger the warning.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With