Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: push newClass only when class is decorated #14334

Merged
merged 1 commit into from Mar 6, 2022

Conversation

JLHwung
Copy link
Contributor

@JLHwung JLHwung commented Mar 4, 2022

Q                       A
Fixed Issues? Fixes #14242 (comment)
Patch: Bug Fix? Y
Major: Breaking Change?
Minor: New Feature?
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes?
License MIT

Before this PR we always push newClass to the return of applyDecs but did not provide such bindings at the transformer when the class is not decorated. This PR resolves this issue.

@JLHwung JLHwung added PR: Bug Fix 🐛 A type of pull request used for our changelog categories Spec: Decorators labels Mar 4, 2022
@@ -1,8 +1,4 @@
function dec(fn, context) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original test case is renamed to *-with-initializers/exec.js. They are replaced by a simpler test without initializers, which exactly catches this bug.

@babel-bot
Copy link
Collaborator

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/51410/

@@ -699,23 +696,19 @@ export default function applyDecs(targetClass, memberDecs, classDecs) {
var ret = [];
var staticMetadataMap = {};

if (memberDecs) {
Copy link
Contributor Author

@JLHwung JLHwung Mar 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The guard is removed because the transformer always provides an array literal for memberDecs.

pushInitializers(ret, staticInitializers);
}
pushInitializers(ret, protoInitializers);
pushInitializers(ret, staticInitializers);
Copy link
Contributor Author

@JLHwung JLHwung Mar 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A dub initializer should be pushed when the member decorators do not introduce initializers, which can only be known at runtime.


if (classDecs) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for classDecs.

Copy link
Member

@nicolo-ribaudo nicolo-ribaudo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @pzuraq if you have time to review!

@nicolo-ribaudo nicolo-ribaudo changed the title fix: push newClass only when class is decorated fix: push newClass only when class is decorated Mar 6, 2022
@nicolo-ribaudo nicolo-ribaudo merged commit 0b29359 into babel:main Mar 6, 2022
@nicolo-ribaudo nicolo-ribaudo deleted the fix-14242 branch March 6, 2022 12:20
@wvq
Copy link

wvq commented Mar 6, 2022

I'm sorry, after some test, It's still have problem, Maybe this plugin need more testcase.

This merge fixed my comment on #14242 , But class decorator and method decorator Cannot exist at the same time.

function logged(value, { kind, name }) {
  if (kind === 'method') {
    return function () {}
  }
  return value
}

```javascript

@logged
class C {
  @logged m(arg) {}
}
TypeError: _initClass is not a function

@JLHwung
Copy link
Contributor Author

JLHwung commented Mar 7, 2022

@wvq Turns out the helpers-generated is out-of-dated, I am surprised that the test is still passing. I will open a new PR soon.

@nicolo-ribaudo
Copy link
Member

nicolo-ribaudo commented Mar 7, 2022

We should also make CI fail when that happens. The tests aren't failing because make bootstrap regenerates the helpers.

@wvq
Copy link

wvq commented Mar 7, 2022

:( still have problem with the generated source.
And I found a new bug with this merge.

Function applyMemberDecs always push two function to ret at least,
https://github.com/babel/babel/blame/4f80f5c4171bcdcf1c6a41d0234bb167bd27e0e7/packages/babel-helpers/src/helpers/applyDecs.js#L494-L515

but staticInitLocal is optional push https://github.com/babel/babel/blame/4f80f5c4171bcdcf1c6a41d0234bb167bd27e0e7/packages/babel-plugin-proposal-decorators/src/transformer-2021-12.ts#L824-L827

so, with a method decorator, It may compile to:

[_initProto, _Todo, _initClass] = _applyDecs(this, [[log, 2, 'hello']], [log])

But there always have two function, It need to be:

[_initProto, _initStatic, _Todo, _initClass] = _applyDecs(this, [[log, 2, "hello"]], [log]);

Why not use an object with clear keys (or a fixed size array) instead of dynamic arrays,
it's much more reliable.

@JLHwung
Copy link
Contributor Author

JLHwung commented Mar 7, 2022

@wvq I believe it has been fixed in #14335, could you try that merge instead?

Why not use an object with clear keys (or a fixed size array) instead of dynamic arrays

Array destructuring is indeed harder to maintain than object keys, however, it yields to smaller code after minification, since object keys is harder to mangle properly and thus not enabled by default in uglifyJS/terser.

@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Jun 7, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 7, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue PR: Bug Fix 🐛 A type of pull request used for our changelog categories Spec: Decorators
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: Uncaught TypeError: Class constructor cannot be invoked without 'new'
6 participants