google / google/closure-compiler

Bug: static class members defined via an IIFE cause the class to not be removed

Open
#4,116 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
7.7k
Forks
1.2k
Avg merge
2d 12h
Merged PRs (30d)
6

Description

***Input***
```ts
function getFoo() {
class Foo {
}
(() => {
Foo.x = 1;
})();
return Foo;
}
const Foo1 = getFoo();

class Bar {
constructor(num) {
this.num = num;
}

n() {
console.log(this.num);
}

neverCalled() {
console.log(Foo1);
}
}

new Bar(5).n();
```

***Expected output***
```ts
function b() {
this.g = 5;
}
b.prototype.n = function() {
console.log(this.g);
};
(new b()).n();
```

***Actual output***
```ts
(function() {
function a() {
}
a.x = 1;
return a;
})();
function b() {
this.g = 5;
}
b.prototype.n = function() {
console.log(this.g);
};
(new b()).n();
```

[closure compiler playground](https://closure-compiler.appspot.com/home#code%3D%252F%252F%2520%253D%253DClosureCompiler%253D%253D%250A%252F%252F%2520%2540compilation_level%2520ADVANCED_OPTIMIZATIONS%250A%252F%252F%2520%2540output_file_name%2520default.js%250A%252F%252F%2520%2540formatting%2520pretty_print%250A%252F%252F%2520%253D%253D%252FClosureCompiler%253D%253D%250A%250A%252F%252F%2520ADD%2520YOUR%2520CODE%2520HERE%250Afunction%2520getFoo()%2520%257B%250A%2520%2520class%2520Foo%2520%257B%250A%2520%2520%257D%250A%2520%2520(()%2520%253D%253E%2520%257B%250A%2520%2520%2520%2520Foo.x%2520%253D%25201%253B%250A%2520%2520%257D)()%253B%250A%2520%2520return%2520Foo%253B%250A%257D%250Aconst%2520Foo1%2520%253D%2520getFoo()%253B%250A%250Aclass%2520Bar%2520%257B%250A%2520%2520constructor(num)%2520%257B%250A%2520%2520%2520%2520this.num%2520%253D%2520num%253B%250A%2520%2520%257D%250A%250A%2520%2520n()%2520%257B%250A%2520%2520%2520%2520console.log(this.num)%253B%250A%2520%2520%257D%250A%250A%2520%2520neverCalled()%2520%257B%250A%2520%2520%2520%2520console.log(Foo1)%253B%250A%2520%2520%257D%250A%257D%250A%250Anew%2520Bar(5).n()%253B)

From the looks of it, CC's side-effect detection doesn't correctly understand the IIFE and CC decides the enclosing scope is impure. This in turn means that CC won't remove the unused code paths.

We ran into this because this is the code that [swc generates for static class members](https://play.swc.rs/?version=1.3.83&code=H4sIAAAAAAAAA0vOSSwuVnDLz1eo5lJQKC5JLMlMVqhQsFUwtOaqBQDy0lHhHQAAAA%3D%3D&config=H4sIAAAAAAAAA02MwQrCQAxE7%2F2KJWcP6s1elf5HqFlZWbdLJoKl9N%2BbWioeBjIvMzM1IdATPbVh8tNNZYXozzvBWIw%2FTsjGKug1VaPvcz5sHWN9iK0Jwfl4utDOlQvioK%2F%2FuTfkJjEV6Qa9Zga6JPkOj0TOkG24WTUvhyN2954AAAA%3D). I'm trying to migrate our codebase from `tsc` to `swc` for transpilation and we noticed a bundle size increase. A lot of investigation later we eventually narrowed it down to this problem.

cc @WearyMonkey

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.