Open benasher44 opened 5 months ago
One interesting note: still debugging this one, but there is a similar flavor of bug where static functions on the class don't get transformed this way. For example:
@MarkClass("example")
class Example {
static create() {
new Example()
}
}
tsc creates an intermediary var so the emit looks like
let Example_1 = class Example {
static create() {
new Example_1()
}
}
// apply decorate code here
Somehow this doesn't exhibit the same bug in tsc, but the viable workaround for swc is similar. We've updated our code to instead use new this()
, in the static function. I guess somehow creating that Example_1 var allows makings this work by tsc — maybe something specific to tslib's decorate function? not sure though
I suppose swc could apply a similar transformation and also transform new Example()
to new this()
. Apologies; I haven't fully debugged this part yet, but I saw this issue was assigned and wanted to call out this part too, in case the assignee has a better handle on tslib's decorating than myself :)
Ah okay so what tsc does is apply the decoration to Example and update Example_1 to point to the decorated class, to then calling Example.create()
works as expected.
All the swc
would need to do in case of a decorated class, is to copycat the tsc
behavior, which itself slaps a workaround on to mitigate the issue.
so instead of:
class Example {
copy() {
return new Example();
}
}
Example = _ts_decorate([
Do:
let Example_1; // or _Example, or whatever you prefer
class Example {
static { Example_1 = this; } // yes, that's what tsc does when a class is decorated
copy() {
return new Example_1(); // and replace all static references inside the class with the alias
}
}
Example_1 = Example = _ts_decorate([
This would also fix other related issues i.a. https://github.com/swc-project/swc/issues/6515, https://github.com/swc-project/swc/issues/8039 @kdy1
Describe the bug
Literal references to the constructor inside the class's implementation reference the un-decorated class's constructor. This results in functions, like a copy function, unexpectedly returning instances of the class without decoration.
Input code
Config
Playground link (or link to the minimal reproduction)
https://play.swc.rs/?version=1.5.2&code=H4sIAAAAAAAAA3VRzWqDQBC%2BC77DkENZQXwAm0gh9Nj2klsIYbOZGFtdZXelhuC7d7Kurq30tsx%2B8%2F3NpZXCFLWEiqsvPG9LrvV6B9gZlGcN21pqo1pharXm8pZlLAwAhJ%2BmsIsfI7uu3nmFKdBfIfMwiOgTnhYccJ84QKFuSwObYQawn1EnktgOKYiHp8nRDDAu%2FTLEkiThKtcpkNb%2BEHkQgG4bnADRs%2F%2F4OH2iMAnpFLlk5lroGO5wPM5T%2BTf0frcfHr0tobdjhaZV0kVbBiIMLYXBZWz%2BjYht72xZorPvKP85TG3d020M5UJDrdvmN9mY3a3PTuyg8SzVkKkf7b14WyvseNWUuIrCALumVsbd5HWYDzJNeyoLQadobiz6oyzxewQzp2NlfgCGAagKfgIAAA%3D%3D&config=H4sIAAAAAAAAA21QQY6DMAy87yuQzz1sV%2Bql16Le%2BggrGBSUxMg2UlHVvzdQgtjt3uKZzHjGj6%2Bqgl4dnKtHfuZhQFGSbc6ITsnwnhGwaSB14geDQ2FNZ6rFoLRhDTkWNBbNlMlIC%2FF882CCSVuWuF8SqEM31UW46j4db2TYoOHfD6NSTa1PdGW5BFS9egqNlmi%2FA6B0ZHMh0p%2Fv42ktA9En3077VBFTF%2Bijn%2BM4COn%2F7oFZaccsOHi9cTMuXiU3xIKsp5%2FPO6fK9pFTr7Cpt2Rv0%2BcLSEYzDLcBAAA%3D
SWC Info output
Expected behavior
With the example setup, calling
(new Example()).copy()
should return a new instance of Example that is also decorated.Actual behavior
Instead you can an un-decorated Example instance.
Version
1.5.0
Additional context
The workaround is to ensure that you do
new this.constructor()
, when attempting to create a new version of a class from inside that same class. Upon inspecting tsc emit, this is exactly how typescript handles it: transforming suchnew Example()
(where Example is the constructor of the class owning the function where the constructor is being called) code to benew this.constructor()
instead.