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

Add private-property-in-object support #11372

Merged

Conversation

jridgewell
Copy link
Member

@jridgewell jridgewell commented Apr 3, 2020

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

https://github.com/tc39/proposal-private-fields-in-in

The parsing is a little loose, but it's going to take a lot of effort to restrict it to only in binary expressions.

@JLHwung JLHwung added the PR: New Feature 🚀 A type of pull request used for our changelog categories label Apr 3, 2020
@jridgewell
Copy link
Member Author

/cc @ljharb

Copy link
Member

@ljharb ljharb left a comment

Choose a reason for hiding this comment

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

LGTM overall

return;
}

path.replaceWith(template.expression.ast`${id}.has(${right})`);
Copy link
Member

Choose a reason for hiding this comment

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

just curious; do these field WeakMaps have WeakMap.prototype.has copied onto them? or can i intercept babel private fields, even in spec mode, by replacing WeakMap.prototype.has?

Copy link
Member Author

Choose a reason for hiding this comment

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

We do not secure the weak
maps, so this will do a prototype reference. Note that even get and set calls go through the prototype, too. We can't ensure the order of our evaluation, so the WeakMap could have already been patched by the time we reach the class definition.

Copy link
Member

Choose a reason for hiding this comment

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

Of course - you can't protect against first-run code, but to be spec compliant you'd have to at least protect against later code. Object.defineProperties(id, Object.getOwnPropertyDescriptors(WeakMap.prototype)) at id creation would address that.

Copy link
Member

Choose a reason for hiding this comment

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

Currently, all of our output assumes that builtins haven't been modified.

Copy link
Member

Choose a reason for hiding this comment

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

oof, ok - it's totally fine to assume they haven't been modified at module evaluation time (you don't really have a choice) but it's not fine to assume they haven't been modified later. that should be fixed asap (but not in this PR, obviously)

Copy link
Contributor

@JLHwung JLHwung left a comment

Choose a reason for hiding this comment

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

  1. We should also throw when private in is out of the class scope.
({
  test() {
    #x in {};
  }
})
  1. #constructor as private identifier is a syntax error when it is used in a class element. Should we also forbid #constructor in c? @ljharb

@ljharb
Copy link
Member

ljharb commented Apr 3, 2020

@JLHwung I would assume obj.#constructor is a syntax error, so that #constructor in x should be as well?

@nicolo-ribaudo
Copy link
Member

I think that for #constructor we will already throw when handling private names not in scope, because since it can't be declared it will ever be in scope.

@ljharb
Copy link
Member

ljharb commented Apr 3, 2020

I've just added an early error for #constructor to the proposed spec; thanks for the ping :-)

@nicolo-ribaudo nicolo-ribaudo added this to the v7.10.0 milestone Apr 4, 2020
@jridgewell jridgewell force-pushed the private-prop-in-obj branch 2 times, most recently from 75e7c6f to 47dbbfd Compare April 15, 2020 04:07
@@ -1158,7 +1171,11 @@ export default class ExpressionParser extends LValParser {
const isPrivate = this.match(tt.hash);

if (isPrivate) {
this.expectOnePlugin(["classPrivateProperties", "classPrivateMethods"]);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think throwing missing privateIn error for the common private property case will confuse users.

class C {
  #p = 42;
}

Instead we can expect privateIn when we see tt._in after a private name.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't understand the suggestion. I need to expect one of the 3 plugins here, or else I won't be able to parse the private name.

Copy link
Contributor

Choose a reason for hiding this comment

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

I just realize that this line is never failed due to https://github.com/babel/babel/pull/11478/files#diff-80da704a8d2fc8d339ab57f154fb225eL429, which I address in #11478.

Base on #11478 and current implementation, if users are enabling classPrivateProperties but without privateIn, the following case does not throw missing privateIn error. (REPL)

class C {
  #p = 42;
  m() { return #p in this }
}

because we never really check privateIn as long as classPrivateProperties is enabled.

Can you add a test case to packages/babel-parser/test/fixtures/experimental/_no-plugin?

Copy link
Member Author

Choose a reason for hiding this comment

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

We check at https://github.com/babel/babel/pull/11372/files#diff-56fea09eea2de51b8291db400d2f69beR1142. Added a test, we get SyntaxError: Unexpected token at the # in #foo in {}.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we throw the privateIn plugin is expected when we see #foo in {} but privateIn is missing? Just like we did for classPrivateProperties.

Copy link
Member Author

Choose a reason for hiding this comment

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

There are several conflicting desires here:

  1. Parsing smart pipelines, and giving good errors
  2. Parsing invalid #foo expressions (not followed by in)
  3. Parsing #foo in {} expressions, but not having plugin enabled

I don't have a good solution to all three of these. If you can push a commit, that'd be awesome.

Copy link
Contributor

Choose a reason for hiding this comment

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

Pushed a commit that should address 2) and 3).

For 1) we are printing good errors when |> is seen but no pipeline plugin. I think current situation is acceptable and since they are competing proposals we can give better errors after any of them advances.

@babel-bot
Copy link
Collaborator

babel-bot commented Apr 24, 2020

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

@codesandbox-ci
Copy link

codesandbox-ci bot commented Apr 28, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit f304cdb:

Sandbox Source
thirsty-feather-q481d Configuration
patient-sea-osfcw Configuration

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.

Thanks @JLHwung for helping!

Copy link
Contributor

@JLHwung JLHwung left a comment

Choose a reason for hiding this comment

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

Thanks.

@jridgewell
Copy link
Member Author

Excellent, thanks for the help!

@nicolo-ribaudo nicolo-ribaudo added the PR: Ready to be Merged A pull request with already two approvals, but waiting for the next minor release label Apr 28, 2020
@nicolo-ribaudo
Copy link
Member

nicolo-ribaudo commented Apr 28, 2020

@jridgewell Could you add a docs page for this new plugin to babel/website? You can copy one of the existing pages for other simple plugins.

@jridgewell
Copy link
Member Author

babel/website#2235

@nicolo-ribaudo nicolo-ribaudo changed the base branch from master to feat-7.10.0/private-stuff May 18, 2020 19:06
@nicolo-ribaudo nicolo-ribaudo merged commit 4379f5c into babel:feat-7.10.0/private-stuff May 18, 2020
@nicolo-ribaudo
Copy link
Member

Note: this is not merged to master yet.

nicolo-ribaudo added a commit that referenced this pull request May 21, 2020
https://github.com/tc39/proposal-private-fields-in-in

Co-Authored-By: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
Co-Authored-By: Huáng Jùnliàng <jlhwung@gmail.com>
nicolo-ribaudo added a commit that referenced this pull request May 26, 2020
https://github.com/tc39/proposal-private-fields-in-in

Co-Authored-By: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
Co-Authored-By: Huáng Jùnliàng <jlhwung@gmail.com>
@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 Oct 21, 2020
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 21, 2020
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: New Feature 🚀 A type of pull request used for our changelog categories Spec: Brand Check for Private Fields
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants