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.)

+3


source to share


1 answer


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.

+1


source







All Articles