Repository navigation
Return false for #x in on static private fields before initialization - #18265
Conversation
Thanks for opening this pull request! 🎉We really appreciate you taking the time to contribute, @hoobnn. A maintainer will take a look as soon as they can. In the meantime, please make sure that:
If anything needs adjusting we'll leave comments here. Thanks again! |
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/62220 |
|
commit: |
Done, thanks! |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0b4ddd0 to
219bf51
Compare
|
@JLHwung I was also confused, but that assumption already exists :) https://babeljs.io/docs/assumptions#nouninitializedprivatefieldaccess (if you merge this PR, please squash-merge replacing |
Oh my bad. I didn't realize we already have this assumption. In that case this PR is indeed a bug fix. |
## pnpm-workspace.yaml (default) ## Dependency Updates | Package | From | To | Type | | --- | --- | --- | --- | | `@babel/core` | 8.0.6 | 8.0.7 | patch | | `@react-email/ui` | 6.11.0 | 6.11.1 | patch | | `ai` | 7.0.128 | 7.0.130 | patch | | `react-email` | 6.11.0 | 6.11.1 | patch | | `shadcn` | 4.21.3 | 4.21.4 | patch | ## Release Notes <details> <summary><b>@<!---->babel/core</b> (8.0.6 → 8.0.7)</summary> ## v8.0.7 (2026-10-07) Thanks @<!---->brunoborta, @<!---->CINC0S, @<!---->hoobnn, and @<!---->jpradelle for your first PRs! #### 🐛 Bug Fix * `babel-helper-create-regexp-features-plugin`, `babel-plugin-transform-dotall-regex`, `babel-plugin-transform-unicode-sets-regex`, `babel-preset-env` * [#18295](babel/babel#18295) Bump regexpu-core to 6.5.3 ([@<!---->JLHwung](https://github.com/JLHwung)) * `babel-plugin-transform-for-of` * [#18292](babel/babel#18292) Skip `for await` in `transform-for-of` ([@<!---->brunoborta](https://github.com/brunoborta)) * `babel-helpers`, `babel-plugin-transform-async-generator-functions`, `babel-runtime-corejs3` * [#18283](babel/babel#18283) Fix `asyncIterator` helper forwarding `.throw()` to `.return()` ([@<!---->brunoborta](https://github.com/brunoborta)) * `babel-parser` * [#18288](babel/babel#18288) fix(parser): allow await as a function expression name inside async arrow ([@<!---->JLHwung](https://github.com/JLHwung)) * `babel-helpers`, `babel-plugin-transform-class-properties`, `babel-plugin-transform-modules-systemjs`, `babel-runtime-corejs3` * [#18284](babel/babel#18284) Guard `@@toPrimitive` usage in toPrimitive helper ([@<!---->nicolo-ribaudo](https://github.com/nicolo-ribaudo)) * `babel-plugin-transform-block-scoping` * [#18195](babel/babel#18195) fix: closures in for-loop init capture wrong binding ([@<!---->joelle-a-dev](https://github.com/joelle-a-dev)) * `babel-helper-create-class-features-plugin`, `babel-plugin-transform-private-property-in-object` * [#18265](babel/babel#18265) Return false for `#x in` on static private fields before initialization ([@<!---->hoobnn](https://github.com/hoobnn)) * `babel-traverse` * [#18151](babel/babel#18151) Evaluate TypeScript expression wrappers in `NodePath#evaluate` ([@<!---->CINC0S](https://github.com/CINC0S)) * [#18250](https://github …[full notes](https://github.com/babel/babel/releases/tag/v8.0.7) </details> <details> <summary><b>react-email</b> (6.11.0 → 6.11.1)</summary> ### Patch Changes * 54769fc: Prevent `email export` from deleting the project, the home directory, the email templates or the static assets when `--outDir` points at them. * 6926bac: `<Markdown>` now applies `markdownCustomStyles.th` to table header cells. Header cells were previously styled with `td`, so any `th` styles were ignored. </details> <details> <summary><b>shadcn</b> (4.21.3 → 4.21.4)</summary> ### Patch Changes - [#12189](shadcn-ui/ui#12189) [`76fd499595ba7cc01f49d159bd7ac82d7aca8e63`](shadcn-ui/ui@76fd499) Thanks [@<!---->shadcn](https://github.com/shadcn)! - Drop the ts-morph dependency from @<!---->shadcn/registry. - [#12184](shadcn-ui/ui#12184) [`995c2cfff44c373bd210d451089726ec097ab917`](shadcn-ui/ui@995c2cf) Thanks [@<!---->shadcn](https://github.com/shadcn)! - Run the icons and asChild transformers without ts-morph. - [#12160](shadcn-ui/ui#12160) [`6efecd8fe9aa167886fe2cc0c05c5623a5bb5670`](shadcn-ui/ui@6efecd8) Thanks [@<!---->shadcn](https://github.com/shadcn)! - Edit the Next.js layout for font items without ts-morph, and skip it with a warning instead of writing a broken layout. - [#12188](shadcn-ui/ui#12188) [`efa11781f756c86debb0392fbea4fe468250b41b`](shadcn-ui/ui@efa1178) Thanks [@<!---->shadcn](https://github.com/shadcn)! - Rewrite imports and crawl file imports without ts-morph. - [#12177](shadcn-ui/ui#12177) [`e8c3143b1cd191280befcd6c9538284bb43399a8`](shadcn-ui/ui@e8c3143) Thanks [@<!---->shadcn](https://github.com/shadcn)! - Edit tailwind.config without ts-morph, and skip it with a warning instead of writing a broken config. - [#12183](shadcn-ui/ui#12183) [`f56bbd7282f0116a925a601cb6d7e0c3fede448b`](shadcn-ui/ui@f56bbd7) Thanks [@<!---->shadcn](https://github.com/shadcn)! - Run the rsc, import, CSS variable, cleanup, font and menu transformers without ts-morph. - [#12185](shadcn-ui/ui#12185) [`4a90344c42dc9ae47494179065219377ff5f2a8f`](https://github.com/shadcn-ui/u …[full notes](https://github.com/shadcn-ui/ui/releases/tag/shadcn%404.21.4) </details> --- *This PR was auto-generated by [catalog-update-action](https://github.com/brandhaug/catalog-update-action).* Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
For a static private field,
#x in objcompiles tocheckInRHS(obj) === Class. But the field's value lives invar _x = { _: value }, which isn't assigned until the class body has finished evaluating. So any code that runs before that point (a static block, an earlier static field initializer, or anything after the field's initializer has thrown) getstrue, even though natively the class doesn't have the field yet.This PR adds
&& _x !== void 0to the check for static private fields.checkInRHSstill runs first, so a non-object right-hand side throws as before, and it's only evaluated once. Static private methods and accessors are left as they are, because the class already has them before any field initializer runs. UndernoUninitializedPrivateFieldAccessthe storage holds the raw value, soundefineddoesn't mean "not initialized yet"; in that case the check is skipped and the output doesn't change.privateFieldsAsProperties/privateFieldsAsSymbolsgo through thehasOwnPropertypath and aren't affected.Tests:
private/static-field-initialization(exec): brand checks on a static field, a field with no initializer, a static method and a static getter, before and after each initializer. It also checks that the RHS is evaluated once and that the getter is never called.private/half-constructed-static(exec): returnsfalseafter the field's initializer throws.assumption-noUninitializedPrivateFieldAccess/static-field(output): no extra check under the assumption.&& _x !== void 0.private-loose/static-shadowandto-native-fields/static-shadowoverride their plugins totransform-class-properties, so their change is the spec-mode one; actual loose-mode output is unchanged.With only the new fixtures, the private-in suite has 8 failures. With the change it passes (67 tests), and so does
babel-helper-create-class-features-plugin(17). I checked this on Linux and macOS.One known gap: when the same class declaration is evaluated more than once, for example in a loop,
var _xis shared between evaluations, so only the first one is fixed. Natively you get[false, true, false, true]; with this PR it's[false, true, true, true], and before it was[true, true, true, true]. This comes from how static private field storage is hoisted, which affects reads and writes as well, so I've kept it out of this PR.This also extends
noUninitializedPrivateFieldAccessto coverinchecks. If you'd like, I can open a PR on the website to update the docs for that assumption.