-
-
Notifications
You must be signed in to change notification settings - Fork 339
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
feat(linter/eslint): add no_unreachable
rule.
#3238
base: 06-06-feat_semantic_cfg_add_condition_instruction
Are you sure you want to change the base?
feat(linter/eslint): add no_unreachable
rule.
#3238
Conversation
Your org has enabled the Graphite merge queue for merging into mainAdd the label “merge” to the PR and Graphite will automatically add it to the merge queue when it’s ready to merge. Or use the label “hotfix” to add to the merge queue as a hot fix. You must have a Graphite account and log in to Graphite in order to use the merge queue. Sign up using this link. |
57f6ca1
to
94c3001
Compare
CodSpeed Performance ReportMerging #3238 will degrade performances by 22.18%Comparing Summary
Benchmarks breakdown
|
94c3001
to
ece1ff3
Compare
4b0951e
to
a4f9ee3
Compare
658e5d5
to
ae657bc
Compare
a4f9ee3
to
ba99160
Compare
ae657bc
to
857840a
Compare
ba99160
to
842eccc
Compare
6bb0206
to
9bdf934
Compare
504c906
to
1644851
Compare
b54237e
to
3b12589
Compare
@Boshen Can you read the first comment on this PR? I was wondering how much should I improve the performance to make it acceptable. |
@rzvxa Instead of doing the check inside the rule, are you able to mark the statement as unreachable during the cfg building phase inside semantic builder? For example add any of the following: pub struct Semantic<'a> {
pub unreachable: Vec<Span>, // All the unreachable spans
} In the rule you just print out these spans in one go - a rule with only one line of code lol. Or: pub struct SemanticNode<'a> {
pub unreachable: bool
} Think outside of the box, we have the whole compiler pipeline, we can precompute a lot of stuff! |
Doesn't adding this to the semantic mean we have to pay for this cost in places where it isn't necessary? Not to mention the amount of code we have to add to our semantic builder to compute and determine the reachability. I'm sure with this much performance regression even I wouldn't like my current results (and if it was my project I wouldn't allow it to merge) But having it in semantic doesn't feel right to me either. Maybe we can achieve a better performance by rewriting the rule to use For example if we visit an infinite loop we know for sure everything after this loop is unreachable, But in my current implementation we can't remember that information between nodes so we get to do it all over again. |
Yes, a |
In TypeScript, it marks nodes as unreachable via |
We already have an unreachable instruction to mark the first unreachable block but it doesn't propagate and we use it to filter out the subgraph when walking through the flow, I assume they are doing all of our checks - if not more - to set these flags correctly. I'll give the typescript approach a read before making any major changes but I have a hunch that whatever approach we use to implement this rule it should get rid of our current redundant revisits either by running once or precomputing the information(which in of itself is another kind of run once happening in the core instead of linter crate). It all brings me to the question I was going to ask before seeing this comment. Considering that this information can be reused but comes at the cost of more memory and overhead for everything using the semantics, Do you think having it there is going to be better overall? |
The sad part is that all of our dfs paths are only 8% of the performance regression the other |
We'll eventually make cfg construction optional at some point. Regarding performance regression, I think we can accept around 10 - 15% given that we are doing a lot of work for cfg. |
Just to be clear do you mean it is acceptable if we keep it in the semantics or are you talking about this rule alone? |
Overall performance regression of 10 to 15%. We can keep the unreachable query in the linter rule if that's what you prefer, I was only suggesting that maybe it's better to precompute in the semantic builder. I'll let you make the decision 😁 |
no-unreachable
oxlint-echosystem-ci result
This rule is done but since it is running for every possible statement and does quite a bit of work on them to determine whether it is 100% reachable or not; The performance in my opinion is kind of abysmal.
I'll try to work it out, I know Biome does 2 types of checks to simplify the rule for some nodes, However, they have a lot more false negatives than our implementation.
Here is one example of those false negatives
Update 1:
I've benchmarked this rule using only the simplified reachability checks and it was around 5% faster, To be honest, it isn't much improvement especially considering that we can only use this check for a small portion of nodes and even that is accompanied by newly introduced checks which would lessen the amount of performance gain further.
Most of the performance regression is because of allocations during our depth first search since we have to store both the visited and finished nodes which results in a bunch of rapid-fire allocations back to back. Currently, At the moment I don't have a great idea of how to improve it, We may have to implement our own graph to use arenas underneath.
Given that this rule is the most extensive use case of control flow (It doesn't come with a limited scope similar to property and constructor rules already implemented) this performance drop might be reasonable to some extent.