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

test(transformer/async-to-generator): failing test for async arrow function in class static block #8387

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

overlookmotel
Copy link
Contributor

@overlookmotel overlookmotel commented Jan 9, 2025

It's arguable whether we should support this, because async functions is ES2018 and class static blocks is ES2022. So there should not be any browser which needs async-to-generator transform, and not the static block transform too. And when class-static-block transform is enabled, this works fine.

But personally, I think we should support it, because:

  1. We allow user to enable/disable arbitrary transforms via TransformOptions.
  2. We support this in async arrow functions in class static blocks, so it makes sense to complete that support.
  3. I don't think it should be too hard, as the framework for it is already there in the async-to-generator transform.

Babel REPL

@github-actions github-actions bot added A-transformer Area - Transformer / Transpiler C-test Category - Testing. Code is missing test cases, or a PR is adding them labels Jan 9, 2025
Copy link
Contributor Author


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@overlookmotel overlookmotel marked this pull request as ready for review January 9, 2025 12:41
@Dunqing
Copy link
Member

Dunqing commented Jan 9, 2025

Just found that Babel's output is incorrect, super can't be outside a class. It wasted a few hours for me.

@Dunqing
Copy link
Member

Dunqing commented Jan 9, 2025

Even if the async arrow function is not in the class static block, it also needs to transform super, because async-to-generator will transform the async arrow function to a function generator, thus super will be in the wrong place.

But there is a troublesome example

Input:

class C { static f = async () => super.prop;  }

Babel's Output:

var _superprop_getProp = () => super.prop;
class C {
  static f = babelHelpers.asyncToGenerator(function* () {
    return _superprop_getProp();
  });
}

Babel's implementation is wrong because it inserts _superprop_getProp outside the class. But how to fix it? Where is the correct place to insert _superprop_getProp?

@overlookmotel overlookmotel force-pushed the 01-09-test_transformer_async-to-generator_failing_test_for_async_arrow_function_in_class_static_block branch from 46d2acc to 5a81005 Compare January 9, 2025 18:30
@overlookmotel
Copy link
Contributor Author

Just found that Babel's output is incorrect, super can't be outside a class. It wasted a few hours for me.

Oh bollocks sorry my fault. I posted the Babel REPL link meaning to say "look Babel is wrong again!" but I forgot to actually write that. The test in this PR shows what I think the correct output is for static blocks.

For static blocks, I don't expect it's too hard because there's already a block for the var statement to go in, and the transform already correctly handles this correctly in static blocks: class C { static { async () => this; } }

@overlookmotel
Copy link
Contributor Author

For properties (instance prop or static prop), it's much more annoying. Babel's solution for instance props looks correct, but for some reason it gets it wrong for static props: Babel REPL

But I'm not sure we should attempt to cover async arrow functions in class properties. It's maybe not worth the work. I only suggested that we might want to deal with static blocks because I thought it'd be quite easy.

We also have this problem with other transforms. e.g. class C { prop = x ?? y; } should probably create the temp var inside the property initializer, not outside the class. Or maybe in this cases it's fine (Babel thinks so), but in other transforms it's probably not fine.

We have other weird cases where we need to create temp vars as part of a transform inside:

  • function f(x = somethingThatNeedsALocalTempVarWhenTransformed) {}
  • for (let [x = somethingThatNeedsALocalTempVarWhenTransformed] of arr) {}
  • Probably more

I put class property initializers in the same category.

Rather than tackling this in individual transforms, I think we should probably try to figure out a way to handle these problems universally with helpers that create temp vars, and handle these edge cases for us.

@overlookmotel
Copy link
Contributor Author

overlookmotel commented Jan 9, 2025

It may also be easier to deal with when we have our own helper library. e.g. something like:

class C {
  static f = async (x, y) => super.prop;
}

->

class C {
  static f = oxcHelpers.asyncToGenerator(
    function*(x, y, _superprop_getProp) {
      return _superprop_getProp();
    },
    () => super.prop
  );
}

@Dunqing
Copy link
Member

Dunqing commented Jan 10, 2025

It may also be easier to deal with when we have our own helper library. e.g. something like:

class C {
  static f = async (x, y) => super.prop;
}

->

class C {
  static f = oxcHelpers.asyncToGenerator(
    function*(x, y, _superprop_getProp) {
      return _superprop_getProp();
    },
    () => super.prop
  );
}

I just came up with a way by SequenceExpression

var _superprop_getProp;
class C {
  static f =
    ((_superprop_getProp = () => super.prop),
    /*#__PURE__*/ (function () {
      var _ref = babelHelpers.asyncToGenerator(function* (x, y) {
        return _superprop_getProp();
      });
      return function (_x, _x2) {
        return _ref.apply(this, arguments);
      };
    })());
}

It doesn't rely on our own helper, so we can support it soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-transformer Area - Transformer / Transpiler C-test Category - Testing. Code is missing test cases, or a PR is adding them
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants