feat(data_structures): add is_exhausted method to NonEmptyStack and SparseStack#13672
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
There was a problem hiding this comment.
Pull Request Overview
This PR adds an is_exhausted method to both NonEmptyStack and SparseStack data structures to provide a clear way to check if all pushed items have been popped, returning the stack to its initial state. This is useful for debugging AST traversals where you want to ensure proper stack balance.
Key changes:
- Added
is_exhausted()method toNonEmptyStackthat checks ifcursor == start - Added
is_exhausted()method toSparseStackthat delegates to the underlyingNonEmptyStack - Added comprehensive tests for both implementations
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| crates/oxc_data_structures/src/stack/non_empty.rs | Adds is_exhausted() method and test for NonEmptyStack |
| crates/oxc_data_structures/src/stack/sparse.rs | Adds is_exhausted() method and test for SparseStack |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
CodSpeed Instrumentation Performance ReportMerging #13672 will not alter performanceComparing Summary
Footnotes |
d39f9d7 to
a6e1ace
Compare
Merge activity
|
…nd `SparseStack` (#13672) When using stacks, typically you create a stack at start of AST traversal, and then `debug_assert!` that the stack has been emptied again at the end of traversal, to make sure that the stack has not got out of sync - that every `push` is followed by a corresponding `pop`. With `NonEmptyStack` and `SparseStack` it's a little confusing how to do this, because these stacks can never be empty. `stack.is_empty()` is not correct. `stack.len() == 1` is correct, but it's unclear when reading that code what exactly this is testing. Add `is_exhausted` methods to `NonEmptyStack` and `SparseStack` to fulfil this role. Naming: `is_exhausted` is perhaps not the best name, but I couldn't come up with a better one. I considered `is_emptied`, which is more descriptive, but I think it's too close to `is_empty`. (prompted by #13632)
a6e1ace to
1a58e99
Compare
…time error (#13673) Continuation from #13672. Calling `NonEmptyStack::is_empty` is always a logic error. `NonEmptyStack` can never be empty, and `NonEmptyStack::is_exhausted` is very likely what was intended. Make calling `NonEmptyStack::is_empty` a compile-time error, to prevent this erroneous usage. Ideally, we'd remove the method entirely, but `&NonEmptyStack<T>` derefs to `&[T]`, so without defining `is_empty` method on `NonEmptyStack`, `stack.is_empty()` falls through to `[T]::is_empty`, which is not what we want.

When using stacks, typically you create a stack at start of AST traversal, and then
debug_assert!that the stack has been emptied again at the end of traversal, to make sure that the stack has not got out of sync - that everypushis followed by a correspondingpop.With
NonEmptyStackandSparseStackit's a little confusing how to do this, because these stacks can never be empty.stack.is_empty()is not correct.stack.len() == 1is correct, but it's unclear when reading that code what exactly this is testing.Add
is_exhaustedmethods toNonEmptyStackandSparseStackto fulfil this role.Naming:
is_exhaustedis perhaps not the best name, but I couldn't come up with a better one. I consideredis_emptied, which is more descriptive, but I think it's too close tois_empty.(prompted by #13632)