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
refactor(ast): get rid of unsafe transmutation in VisitMut trait. #2764
Conversation
@Boshen somehow I can't get tasks to run on my system, Is there any possibility for me to have tasks run on GitHub? If there is no lack of resources for running my tasks remotely, it would help me to continue my work on it easier. Please consider approving this PR for running workflows. It stopped me dead on track after the initial commit of mine, I need to get it to work before I can continue working on the issue on hand since I'm sure I've already broken some stuff with this change. I suspect that it is because of external resources, I've found out that older releases(which went around 5 to 8 months back) use submodules to add some external repositories, and I can see there are no more submodules on the |
Sure, Since this is your first time contributing to this repo we need to manually approve the run ci. |
CodSpeed Performance ReportMerging #2764 will not alter performanceComparing Summary
|
Thanks! |
This PR should be ready to merge, I've managed to get rid of the transmutation in the Let me know if there is any issue, ambiguity, lack of documentation, or clarity in this PR. |
@Dunqing Hi, Sorry to ping you here. Can you approve workflow actions for this PR once more? I've found a workaround for tests by running them on my fork but I can't get the benchmark result. |
I wonder whether we should copy a For two reasons:
I'm on vacation right now, please excuse me for the late response and the trouble. |
Hello @Boshen, First off I wanna thank you for responding while on vacation. It means a lot!
I believe if this change goes through despite it being a breaking change it will be a net positive for the third-party tools since we don't enforce unsafe code without letting them know about our assumptions of the code. Plus we are in the minor versions so breaking changes should be expected as it is not a stable release. It is also fairly easy to achieve the same thing without the old design, And if you need the transmutation in a specific transformer or third-party tool? well, then it is on the implementor to handle it, not the core trait itself.
I didn't quite understand this statement, Can you let me know why is there going to be additional iteration as a result of this approach? If we add the walk functions most of the time when changing the logic we are going to do it in walk_functions and those can be used for most use cases unless something really needs deep changes like how SemanticBuilder works. So most people won't need to worry about upcoming breaking changes if they only rely on visit functions and defer walking to the walk function instead of doing it themselves. I honestly believe we can even remove TL;DR I think since implementing a custom VisitMut with walk functions introduced in #2776 isn't going to be such a chore, People can implement their own custom implementations if there is a need for a specific visitor in a specific case. |
I just want to add this, We can have a local trait called ScopeVisit which adds the scope events and is a super trait of the Visit. |
In future, we can also experiment with the use of reference counting for AstNode's reference to the node itself. This way we shouldn't need the transmutation to begin with at the cost of some runtime performance. |
Sorry for speaking in such short comments, I'm just thinking about this PR out loud so you know my thought process and can give me some insight if there is something that I'm not aware of. Take this for example impl<'a> VisitMut<'a> for NewTarget<'a> {
fn enter_node(&mut self, kind: AstKind<'a>) {
if let Some(kind) = self.get_kind(kind) {
self.kinds.push(kind);
}
}
fn leave_node(&mut self, kind: AstKind<'a>) {
if self.get_kind(kind).is_some() {
self.kinds.pop();
}
}
} While it does implement VisitMut it doesn't need it to work. If it was going to actually walk the nodes itself it would've been a lot slower. impl<'a> NewTarget<'a> {
pub(crate) fn enter_method_definition(&mut self, def: &MethodDefinition<'a>) {
let kind = match def.kind {
MethodDefinitionKind::Get
| MethodDefinitionKind::Set
| MethodDefinitionKind::Method => NewTargetKind::Method,
MethodDefinitionKind::Constructor => NewTargetKind::Constructor,
};
self.push(kind);
}
pub(crate) fn leave_method_definition(&mut self, _: &MethodDefinition) {
self.pop();
}
pub(crate) fn enter_object_property(&mut self, prop: &ObjectProperty<'a>) {
if prop.method {
self.push(NewTargetKind::Method);
}
}
pub(crate) fn leave_object_property(&mut self, prop: &ObjectProperty<'a>) {
if prop.method {
self.pop();
}
}
pub(crate) fn enter_function(&mut self, func: &Function<'a>) {
if let Some(kind) = self.function_new_target_kind(func) {
self.push(kind);
}
}
pub(crate) fn leave_function(&mut self, func: &Function<'a>) {
if self.function_new_target_kind(func).is_some() {
self.pop();
}
}
fn function_new_target_kind(&self, func: &Function<'a>) -> Option<NewTargetKind<'a>> {
// oxc visitor `MethodDefinitionKind` will enter `Function` node, here need to exclude it
if let Some(kind) = self.kinds.last() {
if !matches!(kind, NewTargetKind::Function(_)) {
return None;
}
}
func.id.as_ref().map(|id| NewTargetKind::Function(Some(id.name.clone())))
}
} Now with walk functions, we can have the main transformer( // from Transformer implementation of VisitMut
fn visit_function(&mut self, func: &mut Function<'a>, flags: Option<ScopeFlags>) {
self.es2015_new_target.as_mut().map(|t| t.enter_function(func));
walk_function_mut(self, func, flags);
self.es2015_new_target.as_mut().map(|t| t.leave_function(func));
} It is a bit more verbose as you can see, But it is more readable, does less work, compiles easier(including compiler optimizations), and is more future-proof. For example, it won't break if we add an additional AstKind and don't have a default case, or even worse we handle the default case which makes a place that needs change go unnoticed. |
I would like to elaborate on this statement.
In the example I've mentioned above it wouldn't be noticeable, But when walking huge arrays if we don't call enter and leave functions on every node it is going to let the compiler and CPU better use cache lines which in theory should minimize the cache misses while iterating the child nodes. I believe if this early benchmark improvement isn't a false positive, It is probably because of the reason I've talked about here. |
part of `AstKind`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's get the boat sailing.
…c-project#2764) This will close oxc-project#2745, In this PR I attempt to fix this issue using a combination of ideas discussed in the issue mentioned above, I've created this early draft so people can pitch in if there is something I should consider doing. The first goal of this PR is to resolve the issue with the possible illegal references, As a result of my approach it would also end up with a bunch of walk_* and walk_*_mut functions to help with the abstraction. I want to eliminate enter_node and leave_node functions, but I still haven't started working on it since I first want to familiarize myself with all of its usage throughout the project. I'm hesitating to do it at the moment, When we want to do this it would require quite a bit of refactoring so we should make sure it is probably going to work and end up being a better implementation.
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [oxlint](https://oxc-project.github.io) ([source](https://togithub.com/oxc-project/oxc/tree/HEAD/npm/oxlint)) | [`0.2.14` -> `0.2.17`](https://renovatebot.com/diffs/npm/oxlint/0.2.14/0.2.17) | [![age](https://developer.mend.io/api/mc/badges/age/npm/oxlint/0.2.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/oxlint/0.2.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/oxlint/0.2.14/0.2.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/oxlint/0.2.14/0.2.17?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>oxc-project/oxc (oxlint)</summary> ### [`v0.2.17`](https://togithub.com/oxc-project/oxc/releases/tag/oxlint_v0.2.17): oxlint v0.2.17 [Compare Source](https://togithub.com/oxc-project/oxc/compare/7066d55153ad70f95ae975adc3958c1010f9c5ff...df11d10a2220e9aa7a33d9ab39ed662c2ba6fdb5) ##### What's Changed - feat(linter): eslint-plugin-jest/prefer-lowercase-title by [@​eryue0220](https://togithub.com/eryue0220) in [oxc-project/oxc#2911 - feat(linter): typescript-eslint/consistent-type-definitions by [@​todor-a](https://togithub.com/todor-a) in [oxc-project/oxc#2885 - fix(cli): fix `oxlint --format json` yields 0 files to lint by [@​Boshen](https://togithub.com/Boshen) in [oxc-project/oxc#2940 - fix(cli): if format is json do not print summary information ([#​2899](https://togithub.com/oxc-project/oxc/issues/2899)) by [@​kalvenschraut](https://togithub.com/kalvenschraut) in [oxc-project/oxc#2925 - fix(linter): import/no-cycle ignore type-only imports by [@​JohnDaly](https://togithub.com/JohnDaly) in [oxc-project/oxc#2924 - refactor(semantic/jsdoc): Rework JSDoc struct for better Span handling by [@​leaysgur](https://togithub.com/leaysgur) in [oxc-project/oxc#2917 ##### New Contributors - [@​bradzacher](https://togithub.com/bradzacher) made their first contribution in [oxc-project/oxc#2938 **Full Changelog**: oxc-project/oxc@oxlint_v0.2.16...oxlint_v0.2.17 ### [`v0.2.16`](https://togithub.com/oxc-project/oxc/releases/tag/oxlint_v0.2.16): oxlint v0.2.16 [Compare Source](https://togithub.com/oxc-project/oxc/compare/e7307ed23ca9b0707586b6bf4220cafb221ae86e...7066d55153ad70f95ae975adc3958c1010f9c5ff) #### What's Changed - feat(linter): [@​typescript-eslint/prefer-for-of](https://togithub.com/typescript-eslint/prefer-for-of) by [@​charnog](https://togithub.com/charnog) in [oxc-project/oxc#2789 - feat(linter): Implement jsdoc/check-access by [@​leaysgur](https://togithub.com/leaysgur) in [oxc-project/oxc#2642 - feat(linter): Implement jsdoc/empty-tags by [@​leaysgur](https://togithub.com/leaysgur) in [oxc-project/oxc#2893 - feat(linter): eslint-plugin-jest/prefer-mock-promise-sorthand by [@​eryue0220](https://togithub.com/eryue0220) in [oxc-project/oxc#2864 - feat(linter/import): Add `ignoreTypes` option for the `import/no-cycle` rule by [@​JohnDaly](https://togithub.com/JohnDaly) in [oxc-project/oxc#2905 - fix(ast): `FinallyClause` won't get visited as `BlockStatement` anymore. by [@​rzvxa](https://togithub.com/rzvxa) in [oxc-project/oxc#2881 - fix(linter): handle self closing script tags in astro partial loader ([#​2017](https://togithub.com/oxc-project/oxc/issues/2017)) by [@​kalvenschraut](https://togithub.com/kalvenschraut) in [oxc-project/oxc#2907 - fix(linter): svelte partial loader handle generics ([#​2875](https://togithub.com/oxc-project/oxc/issues/2875)) by [@​kalvenschraut](https://togithub.com/kalvenschraut) in [oxc-project/oxc#2906 #### New Contributors - [@​charnog](https://togithub.com/charnog) made their first contribution in [oxc-project/oxc#2789 - [@​kalvenschraut](https://togithub.com/kalvenschraut) made their first contribution in [oxc-project/oxc#2906 - [@​JohnDaly](https://togithub.com/JohnDaly) made their first contribution in [oxc-project/oxc#2905 **Full Changelog**: oxc-project/oxc@oxlint_v0.2.15...oxlint_v0.2.16 ### [`v0.2.15`](https://togithub.com/oxc-project/oxc/releases/tag/oxlint_v0.2.15): oxlint v0.2.15 [Compare Source](https://togithub.com/oxc-project/oxc/compare/b1343d7bcbd490105583b561946f057ac91e40cf...e7307ed23ca9b0707586b6bf4220cafb221ae86e) #### What's Changed - feat(linter): default_param_last by [@​JoSeBu1](https://togithub.com/JoSeBu1) in [oxc-project/oxc#2756 - feat(linter): eslint-plugin-jest/no-untyped-mock-factory by [@​eryue0220](https://togithub.com/eryue0220) in [oxc-project/oxc#2807 - feat(linter): eslint-plugin-jest/prefer-comparison-matcher by [@​eryue0220](https://togithub.com/eryue0220) in [oxc-project/oxc#2806 - feat(linter): eslint-plugin-react checked-requires-onchange-or-readonly by [@​keita-hino](https://togithub.com/keita-hino) in [oxc-project/oxc#2754 - feat(linter): eslint/no-iterator by [@​JoSeBu1](https://togithub.com/JoSeBu1) in [oxc-project/oxc#2758 - feat(linter): fallback to the default tsconfig path by [@​Dunqing](https://togithub.com/Dunqing) in [oxc-project/oxc#2842 - feat(linter): no_script_url by [@​JoSeBu1](https://togithub.com/JoSeBu1) in [oxc-project/oxc#2761 - feat(linter/import) check deep namespace in namespace rule by [@​Dunqing](https://togithub.com/Dunqing) in [oxc-project/oxc#2805 - feat(linter/import) check module import in no_duplicates by [@​Dunqing](https://togithub.com/Dunqing) in [oxc-project/oxc#2771 - feat(linter/import) check type import in no_duplicates by [@​Dunqing](https://togithub.com/Dunqing) in [oxc-project/oxc#2777 - feat(linter/import) support allow_computed option in namespace by [@​Dunqing](https://togithub.com/Dunqing) in [oxc-project/oxc#2840 - feat(linter/import) support check re-export in named by [@​Dunqing](https://togithub.com/Dunqing) in [oxc-project/oxc#2769 - feat(linter/import): ignore type-only imports and exports in no_unresolved by [@​Dunqing](https://togithub.com/Dunqing) in [oxc-project/oxc#2849 - fix(linter/import): false positive for indirect export in namespace by [@​Dunqing](https://togithub.com/Dunqing) in [oxc-project/oxc#2862 - fix(linter/import): ignore export declaration in no-duplicates by [@​Dunqing](https://togithub.com/Dunqing) in [oxc-project/oxc#2863 - fix(linter/max-lines): only report codes that exceed the line limit by [@​mysteryven](https://togithub.com/mysteryven) in [oxc-project/oxc#2778 - fix(parser): add support for empty module declaration by [@​rzvxa](https://togithub.com/rzvxa) in [oxc-project/oxc#2834 #### New Contributors - [@​rzvxa](https://togithub.com/rzvxa) made their first contribution in [oxc-project/oxc#2764 **Full Changelog**: oxc-project/oxc@oxlint_v0.2.14...oxlint_v0.2.15 </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/toeverything/AFFiNE). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4xNTMuMiIsInVwZGF0ZWRJblZlciI6IjM3LjI2OS4yIiwidGFyZ2V0QnJhbmNoIjoiY2FuYXJ5In0=-->
This will close #2745,
In this PR I attempt to fix this issue using a combination of ideas discussed in the issue mentioned above, I've created this early draft so people can pitch in if there is something I should consider doing.
The first goal of this PR is to resolve the issue with the possible illegal references, As a result of my approach it would also end up with a bunch of walk_* and walk_*_mut functions to help with the abstraction. I want to eliminate enter_node and leave_node functions, but I still haven't started working on it since I first want to familiarize myself with all of its usage throughout the project. I'm hesitating to do it at the moment, When we want to do this it would require quite a bit of refactoring so we should make sure it is probably going to work and end up being a better implementation.