Skip to content

Draft: Extractors proposal implementation #924

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

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

Conversation

fs-c
Copy link

@fs-c fs-c commented Jul 23, 2025

Copy link

Thank you for your pull request and welcome to our community! To contribute, please sign the Oracle Contributor Agreement (OCA).
The following contributors of this PR have not signed the OCA:

To sign the OCA, please create an Oracle account and sign the OCA in Oracle's Contributor Agreement Application.

When signing the OCA, please provide your GitHub username. After signing the OCA and getting an OCA approval from Oracle, this PR will be automatically updated.

If you are an Oracle employee, please make sure that you are a member of the main Oracle GitHub organization, and your membership in this organization is public.

@oracle-contributor-agreement oracle-contributor-agreement bot added the OCA Required At least one contributor does not have an approved Oracle Contributor Agreement. label Jul 23, 2025
// todo-lw: conditionalExpression feels way too broad here, but binding also uses it so idk
final Expression binding = conditionalExpression(true, yield, await, CoverExpressionError.DENY);

final boolean isExtracting = binding instanceof CallNode;
Copy link
Member

Choose a reason for hiding this comment

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

isExtracting seems unnecessary, and extractors may be nested inside

Copy link
Author

Choose a reason for hiding this comment

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

do you have a proposed change here? not sure why it seems unnecessary, and don't know why extractors being nested is relevant

Copy link
Member

Choose a reason for hiding this comment

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

Maybe I'm missing something but it seems you could just use isDestructuring and handle extractors in the same code paths, couldn't you?

why extractors being nested is relevant

Unless isExtracting is really supposed to be shallow, it won't be true for extractors nested inside a destructuring pattern. I just don't understand why you'd want such a check?

@@ -2835,6 +2863,26 @@ public boolean enterIdentNode(IdentNode identNode) {
return false;
}

// todo-lw: this is duplicate code
Copy link
Member

Choose a reason for hiding this comment

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

seems like it could be moved to VerifyDestructuringPatternNodeVisitor then.

throw error(AbstractParser.message(MSG_INVALID_LVALUE), callNode.getToken());
}
for (final var arg : callNode.getArgs()) {
if (arg instanceof IdentNode) {
Copy link
Member

Choose a reason for hiding this comment

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

could probably just use arg.accept(this)

@@ -1067,6 +1067,11 @@ private boolean isDestructuringLhs(Expression lhs) {
return false;
}

private boolean isExtractorLhs(Expression lhs) {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe this should be merged into isDestructuringLhs, or are there any cases where you don't want to accept both?

In any case, we need to add a feature flag that enables extractors (disabled by default, enabled via an option).


const subject = new C(1, 2, 3);

const C(x, ...y) = subject;
Copy link
Member

Choose a reason for hiding this comment

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

We should have Assignment and Binding patterns for all relevant cases (the file name seems a bit misleading here btw).

Make sure you also test extractors in function/method and arrow function parameters.

receiver = transform(accessNode.getBase());
}

final var invokeCustomMatcherOrThrowNode = InvokeCustomMatcherOrThrowNode.create(context, function, assignedValue, receiver);
Copy link
Member

Choose a reason for hiding this comment

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

Please wrap this in a NodeFactory method.

final var invokeCustomMatcherOrThrowNode = InvokeCustomMatcherOrThrowNode.create(context, function, assignedValue, receiver);

final var args = fakeCallNode.getArgs();
VarRef valueTempVar = environment.createTempVar();
Copy link
Member

Choose a reason for hiding this comment

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

valueTempVar seems to be not assigned here? I presume this (Extractor() = x) should still return x, right? we should also add a test for this.

Copy link
Author

Choose a reason for hiding this comment

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

my understanding is that this is not the case, no. it's just a leftover from when i factored out the destructuring code, will remove it.

// todo-lw: this is duplicate code
@Override
public boolean enterCallNode(CallNode callNode) {
if (callNode.isParenthesized()) {
Copy link
Member

Choose a reason for hiding this comment

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

This check needs to be stricter; not every non-parenthesized CallNode is valid in this context.

final Expression binding = bindingIdentifierOrPattern(yield, await, CONTEXT_VARIABLE_NAME);
final boolean isDestructuring = !(binding instanceof IdentNode);
// Get left hand side.
// todo-lw: conditionalExpression feels way too broad here, but binding also uses it so idk
Copy link
Member

Choose a reason for hiding this comment

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

conditionalExpression is indeed too broad here. not sure what you mean with "binding also uses it"?

@woess
Copy link
Member

woess commented Aug 6, 2025

btw, ExtractorAssignmentPattern and ExtractorBindingPattern are defined as:
ExtractorMemberExpression [no LineTerminator here] ()

so IIUC no newline is allowed before the opening parenthesis of an extractor, e.g.:

let Extractor(x) = y;

is valid but

let Extractor
(x) = y;

is not.
I don't see this case being handled currently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OCA Required At least one contributor does not have an approved Oracle Contributor Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants