Skip to content

fix(rust): EqCapture accepted cases where number of captured nodes differed by one#4532

Merged
clason merged 3 commits intotree-sitter:masterfrom
quentinLeDilavrec:master
Aug 27, 2025
Merged

fix(rust): EqCapture accepted cases where number of captured nodes differed by one#4532
clason merged 3 commits intotree-sitter:masterfrom
quentinLeDilavrec:master

Conversation

@quentinLeDilavrec
Copy link
Contributor

I noticed a bug with the implementation of the eq predicate in Rust, when using alternations.
The bug becomes apparent when comparing values of captures in different alternations not always using the same capture name.
The fix is very straight forward, I just had to iterate the left and right captured nodes more independently.

Hope it helps :)

Thank you a lot for improving and maintaining Tree-Sitter !

the provided example should not match
If either side yielded None we could not know the value of the other.
Thus, returning true even if the other yielded a node.
quentinLeDilavrec added a commit to quentinLeDilavrec/HyperAST that referenced this pull request Jun 25, 2025
quentinLeDilavrec added a commit to HyperAST/HyperAST that referenced this pull request Jul 17, 2025
Many improvements and bug fixes

* Introduce lattice graphs and pattern refinement tools to query synthesis
* fix a bug in tsquery related to EqCapture where it incorrectly matched instances differing number of captured nodes,
also see fix(rust): EqCapture accepted cases where number of captured nodes differed by one tree-sitter/tree-sitter#4532
* In gen/tree_sitter/cpp, The generation was made more resilient to ts errors that were not properly wrapping non-space characters
* fix error in vcs/git where multiple configs would crash the server, for now let's consider that handling pom.xml only require a single config
Copy link
Member

@WillLillis WillLillis left a comment

Choose a reason for hiding this comment

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

Very nice catch! I think we can stay a little closer to the original iteration logic for the sake of readability.

diff --git a/lib/binding_rust/lib.rs b/lib/binding_rust/lib.rs
index a866acb8..99ba5557 100644
--- a/lib/binding_rust/lib.rs
+++ b/lib/binding_rust/lib.rs
@@ -3356,12 +3356,11 @@ impl<'tree> QueryMatch<'_, 'tree> {
             .iter()
             .all(|predicate| match predicate {
                 TextPredicateCapture::EqCapture(i, j, is_positive, match_all_nodes) => {
-                    let nodes_1 = self.nodes_for_capture_index(*i);
-                    let mut nodes_2 = self.nodes_for_capture_index(*j);
-                    for node1 in nodes_1 {
-                        let Some(node2) = nodes_2.next() else {
-                            return false;
-                        };
+                    let mut nodes_1 = self.nodes_for_capture_index(*i).peekable();
+                    let mut nodes_2 = self.nodes_for_capture_index(*j).peekable();
+                    while nodes_1.peek().is_some() && nodes_2.peek().is_some() {
+                        let node1 = nodes_1.next().unwrap();
+                        let node2 = nodes_2.next().unwrap();
                         let mut text1 = text_provider.text(node1);
                         let mut text2 = text_provider.text(node2);
                         let text1 = node_text1.get_text(&mut text1);
@@ -3374,7 +3373,7 @@ impl<'tree> QueryMatch<'_, 'tree> {
                             return true;
                         }
                     }
-                    nodes_2.next().is_none()
+                    nodes_1.next().is_none() && nodes_2.next().is_none()
                 }
                 TextPredicateCapture::EqString(i, s, is_positive, match_all_nodes) => {
                     let nodes = self.nodes_for_capture_index(*i);

@clason clason requested a review from WillLillis August 26, 2025 12:25
@WillLillis
Copy link
Member

@quentinLeDilavrec Changes look good to me, thanks again for the fix! You've opened up the PR from your fork's master branch, so I'm not able to push to it. Could you squash those three commits into ccd5dc3? Happy to merge after that!

@clason clason merged commit 79177a1 into tree-sitter:master Aug 27, 2025
18 checks passed
@github-actions github-actions bot removed the request for review from amaanq August 27, 2025 08:25
@tree-sitter-ci-bot
Copy link

Successfully created backport PR for release-0.25:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants