Skip to content

SWC doesn't behave the same when it comes to symbol properties with experimental decorators #1844

@CMCDragonkai

Description

@CMCDragonkai

Search Terms

Decorators and swc

Expected Behavior

I've got an upstream project that sets symbol properties inside a class decorator.

The generated code looks like this:

Details
function CreateDestroy() {
    return (constructor) => {
        var _a, _b, _c;
        const constructor_ = class extends constructor {
            constructor() {
                super(...arguments);
                this[_a] = false;
                this[_b] = null;
                this[_c] = new async_locks_1.RWLockWriter();
            }
            get [(_a = utils_1._destroyed, _b = utils_1._status, _c = utils_1.initLock, utils_1.destroyed)]() {
                return this[utils_1._destroyed];
            }
            get [utils_1.status]() {
                return this[utils_1._status];
            }
            async destroy(...args) {
                return this[utils_1.initLock].withWriteF(async () => {
                    this[utils_1._status] = 'destroying';
                    try {
                        if (this[utils_1._destroyed]) {
                            return;
                        }
                        let result;
                        if (typeof super['destroy'] === 'function') {
                            result = await super.destroy(...args);
                        }
                        this[utils_1._destroyed] = true;
                        return result;
                    }
                    finally {
                        this[utils_1._status] = null;
                    }
                });
            }
        };
        // Preserve the name
        Object.defineProperty(constructor_, 'name', Object.getOwnPropertyDescriptor(constructor, 'name'));
        return constructor_;
    };
}

Then I have code being executed under ts-node, which uses this decorator. The project has experimentalDecorators: "true" switched on.

With swc, it turns out that the decorator constructor itself is never executed.

If I put a console.log('hello world'); underneath

                this[_c] = new async_locks_1.RWLockWriter();

The message never shows.

But if I switch off swc, it does work, and I see the message being printed on the console.

This seems to mean that ts-node with swc isn't understanding decorated code, or perhaps swc itself doesn't know how to transpile with decorator code upstream.

Actual Behavior

Because the decorator constructor doesn't work, the actual behaviour is that I get undefined properties when attempting to access properties that the decorated constructor is supposed to set.

Steps to reproduce the problem

Go to this PR: MatrixAI/js-workers#4. Check out this commit: MatrixAI/js-workers@7c591cd.

Then try npm run bench.

You should see:

[nix-shell:~/Projects/js-workers]$ npm run bench

> @matrixai/workers@1.3.4 bench
> rimraf ./benches/results && ts-node ./benches

WARN:WorkerManager Bench:Cores: 16
TypeError: Cannot read properties of undefined (reading 'isLocked')
    at WorkerManager.queue (/home/cmcdragonkai/Projects/js-workers/node_modules/@matrixai/async-init/src/CreateDestroy.ts:159:38)
    at /home/cmcdragonkai/Projects/js-workers/benches/worker_manager.ts:54:23
    at /home/cmcdragonkai/Projects/js-workers/node_modules/benny/lib/add.js:16:47
    at Generator.next (<anonymous>)
    at /home/cmcdragonkai/Projects/js-workers/node_modules/benny/lib/add.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/home/cmcdragonkai/Projects/js-workers/node_modules/benny/lib/add.js:4:12)
    at prepareCaseFn (/home/cmcdragonkai/Projects/js-workers/node_modules/benny/lib/add.js:15:33)
    at /home/cmcdragonkai/Projects/js-workers/node_modules/benny/lib/add.js:59:38
    at Generator.next (<anonymous>)

And the property is undefined because the constructor doesn't get executed.

Specifications

  • ts-node version: v10.9.1
  • node version: v16.15.0
  • TypeScript version: v4.7.4
  • tsconfig.json, if you're using one:
{
  "compilerOptions": {
    "outDir": "./dist",
    "tsBuildInfoFile": "./dist/tsbuildinfo",
    "incremental": true,
    "sourceMap": true,
    "declaration": true,
    "allowJs": true,
    "strictNullChecks": true,
    "noImplicitAny": false,
    "experimentalDecorators": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "resolveJsonModule": true,
    "moduleResolution": "node",
    "module": "CommonJS",
    "target": "ES2021",
    "baseUrl": "./src",
    "paths": {
      "@": ["index"],
      "@/*": ["*"]
    },
    "noEmit": true
  },
  "include": [
    "./src/**/*",
    "./src/**/*.json",
    "./tests/**/*",
    "./scripts/**/*",
    "./benches/**/*"
  ],
  "ts-node": {
    "require": ["tsconfig-paths/register"],
    "transpileOnly": true,
    "swc": true
  }
}
  • package.json:
{
  "name": "@matrixai/workers",
  "version": "1.3.4",
  "author": "Roger Qiu",
  "description": "Multithreaded Workers",
  "license": "Apache-2.0",
  "repository": {
    "type": "git",
    "url": "https://github.com/MatrixAI/js-workers.git"
  },
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "prepare": "tsc -p ./tsconfig.build.json",
    "build": "rimraf ./dist && tsc -p ./tsconfig.build.json",
    "postversion": "npm install --package-lock-only --ignore-scripts --silent",
    "ts-node": "ts-node",
    "test": "jest",
    "lint": "eslint '{src,tests,scripts,benches}/**/*.{js,ts}'",
    "lintfix": "eslint '{src,tests,scripts,benches}/**/*.{js,ts}' --fix",
    "lint-shell": "find ./src ./tests ./scripts -type f -regextype posix-extended -regex '.*\\.(sh)' -exec shellcheck {} +",
    "docs": "rimraf ./docs && typedoc --gitRevision master --tsconfig ./tsconfig.build.json --out ./docs src",
    "bench": "rimraf ./benches/results && ts-node ./benches"
  },
  "dependencies": {
    "@matrixai/async-init": "^1.8.1",
    "@matrixai/logger": "^3.0.0",
    "@matrixai/errors": "^1.1.2",
    "threads": "^1.6.5"
  },
  "devDependencies": {
    "@swc/core": "^1.2.215",
    "@types/jest": "^28.1.3",
    "@types/node": "^16.11.7",
    "@typescript-eslint/eslint-plugin": "^5.23.0",
    "@typescript-eslint/parser": "^5.23.0",
    "benny": "^3.7.1",
    "common-tags": "^1.8.2",
    "eslint": "^8.15.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-prettier": "^4.0.0",
    "jest": "^28.1.1",
    "jest-junit": "^14.0.0",
    "prettier": "^2.6.2",
    "rimraf": "^3.0.2",
    "systeminformation": "^5.12.1",
    "ts-jest": "^28.0.5",
    "ts-node": "^10.9.1",
    "tsconfig-paths": "^3.9.0",
    "typedoc": "^0.22.15",
    "typescript": "^4.5.2"
  }
}
  • Operating system and version: Linux matrix-ml-1 5.10.118 #1-NixOS SMP Wed May 25 07:18:02 UTC 2022 x86_64 GNU/Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions