Fix locate in let punnings#2066
Open
panglesd wants to merge 3 commits into
Open
Conversation
panglesd
added a commit
to panglesd/merlin
that referenced
this pull request
May 11, 2026
Include let punnings, named argument punnings and fields punning
Change the order in which we fold the let operators, to give priority to the expression in the "locate" query
22e7942 to
31b48aa
Compare
voodoos
reviewed
May 22, 2026
Collaborator
There was a problem hiding this comment.
I have mixed feeling because this makes the behavior of occurrences (and maybe other queries? we should think about it!) less intuitive. I do think locate is the most important of them so this is an improvement, just one that is not entirely satisfying.
| > x | ||
| > EOF | ||
|
|
||
| FIXME: Should locate to the `x` in `f x`, not say that we are at the definition |
Collaborator
There was a problem hiding this comment.
This is not a fixme anymore, tight ?
Suggested change
| FIXME: Should locate to the `x` in `f x`, not say that we are at the definition | |
| Should locate to the `x` in `f x`, not say that we are at the definition |
| "col": 6 | ||
| } | ||
| } | ||
|
|
Collaborator
There was a problem hiding this comment.
Of course this change impacts other queries too, and some might expect the new value to be considered, not the punned one. I can think of occurrences, but maybe others too ?
Fixing Locate at that costs feels like a fair payment, but ideally we could fix one without breaking the other.
Suggested change
| FIXME Since #2066 this shows the occurrences of the punned value (lines 3 and | |
| 4), not of the pattern (lines 4 and 5). Unlike for the locate query this does | |
| not feel like the more natural choice. We should think of a more flexible fix at | |
| some point. | |
| $ $MERLIN single occurrences -identifier-at 4:7 -filename let_punning.ml < let_punning.ml | jq .value | |
| [ | |
| { | |
| "start": { | |
| "line": 3, | |
| "col": 6 | |
| }, | |
| "end": { | |
| "line": 3, | |
| "col": 7 | |
| }, | |
| "stale": false | |
| }, | |
| { | |
| "start": { | |
| "line": 4, | |
| "col": 7 | |
| }, | |
| "end": { | |
| "line": 4, | |
| "col": 8 | |
| }, | |
| "stale": false | |
| } | |
| ] | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This fixes an issue with the locate query reported in #1796.
(Sorry this is quite verbose for such a small PR but it is also here to help me be corrected if I have assumed something wrong)
In a punned let binding, both the pattern and the expression have the same location. None of them is ghost. I think that somehow breaks the assumption that "sibling nodes have disjoint locations".
During a locate query, the first thing is to load the environment at the point of the cursor. The lookup of "nodes at cursor position" will suppose the invariant mentioned above to return a list all nodes the cursor is in (of which we take the first one, the "deepest").
Since two siblings (the pattern and expression) have the same location, the order in which they are considered matter: when the first one is found, we never look at the other siblings, and "enter" it to continue the search.
In the current implementation, patterns are looked first, and we end up with the environment at the pattern to do our "locate". And so, the unhelpful "Already at definition point".
This PR fixes this by folding let operators in a different order, making the expressions side be entered first.
Having the behaviour depend on the order of the fold is slightly brittle, but I think this PR is still fine to solve #1796 without refactoring a huge part to solve a bigger underlying issue ("siblings might have the same location"). But I'm new to the codebase so I might miss something!
(I'm happy to implement a better fix, but then I'd like to discuss with more experienced Merlin disciple first)