fix: InfoTree was missing information for (pseudo) match patterns such as x + 1.

This kind of pattern has to be reduced to a constructor, and the
`PatternWithRef` information was being lost in the process.
This commit is contained in:
Leonardo de Moura 2022-04-23 12:08:59 -07:00
parent 305d8e641c
commit ed12b62e28
3 changed files with 65 additions and 1 deletions

View file

@ -422,6 +422,54 @@ private def withMVar (mvarId : MVarId) (x : M α) : M α := do
else
x
/--
Creating a mapping containing `b ↦ e'` where `patternWithRef e' = some (stx, b)`,
and `e'` is a subterm of `e`.
This is a helper function for `whnfPreservingPatternRef`. -/
private def mkPatternRefMap (e : Expr) : ExprMap Expr :=
runST go
where
go (σ) : ST σ (ExprMap Expr) := do
let map : ST.Ref σ (ExprMap Expr) ← ST.mkRef {}
e.forEach fun e => do
match patternWithRef? e with
| some (ref, b) => map.modify (·.insert b e)
| none => return ()
map.get
/--
Try to restore `Syntax` ref information stored in `map` after
applying `whnf` at `whnfPreservingPatternRef`.
It assumes `map` has been constructed using `mkPatternRefMap`.
-/
private def applyRefMap (e : Expr) (map : ExprMap Expr) : Expr :=
e.replace fun e =>
match patternWithRef? e with
| some _ => some e -- stop `e` already has annotation
| none => match map.find? e with
| some eWithRef => some eWithRef -- stop `e` found annotation
| none => none -- continue
/--
Applies `whnf` but tries to preserve `PatternWithRef` information.
This is a bit hackish, but it is necessary for providing proper
jump-to-definition information in examples such as
```
def f (x : Nat) : Nat :=
match x with
| 0 => 1
| y + 1 => y
```
Without this trick, the `PatternWithRef` is lost for the `y` at the pattern `y+1`.
-/
private def whnfPreservingPatternRef (e : Expr) : MetaM Expr := do
let eNew ← whnf e
if eNew.isConstructorApp (← getEnv) then
return eNew
else
return applyRefMap eNew (mkPatternRefMap e)
/--
Normalize the pattern and collect all patterns variables (explicit and implicit).
This method is the one that decides where the inaccessible annotations must be inserted.
@ -464,7 +512,7 @@ partial def normalize (e : Expr) : M Expr := do
else
throwInvalidPattern e
else
let eNew ← whnf e
let eNew ← whnfPreservingPatternRef e
if eNew != e then
normalize eNew
else

View file

@ -4,3 +4,9 @@ example : Foo :=
let c := Foo.foo
c
--^ textDocument/typeDefinition
def f (x : Nat) : Nat :=
match x with
| 0 => 1
| y + 1 => y
--^ textDocument/declaration

View file

@ -7,3 +7,13 @@
{"start": {"line": 0, "character": 0}, "end": {"line": 1, "character": 7}},
"originSelectionRange":
{"start": {"line": 4, "character": 2}, "end": {"line": 4, "character": 3}}}]
{"textDocument": {"uri": "file://definition.lean"},
"position": {"line": 10, "character": 13}}
[{"targetUri": "file://definition.lean",
"targetSelectionRange":
{"start": {"line": 10, "character": 4}, "end": {"line": 10, "character": 5}},
"targetRange":
{"start": {"line": 10, "character": 4}, "end": {"line": 10, "character": 5}},
"originSelectionRange":
{"start": {"line": 10, "character": 13},
"end": {"line": 10, "character": 14}}}]