Zulip Chat Archive

Stream: lean4

Topic: Possible bug in diff highlighting


Damiano Testa (Aug 07 2023 at 06:52):

Dear All,

in the code below, I was expecting 4 and 5 to be highlighted as being "ready to change", but they are not. I imagine that the issue is that the "diff'er" sees literals and decides that they have not changed, instead of inspecting what the actual literal is.

example {a b : Nat} (h : b + a = 0): a + b = 0 := by
  rw [Nat.add_comm] -- place the cursor at the beginning of this line: `a` and `b` are diff'ed
  assumption

example (h : 5 + 4 = 0) : 4 + 5 = 0 := by
  rw [Nat.add_comm] -- place the cursor at the beginning of this line: `4` and `5` are *not* diff'ed
  assumption

Of course, this has little consequence. However, if I wanted to find the place in the code where the diff'ing happens, how would I go about it?

Thanks!

Mario Carneiro (Aug 07 2023 at 06:59):

cc: @Edward Ayers

Damiano Testa (Aug 07 2023 at 07:21):

I think that I found a relevant thread.

Damiano Testa (Aug 07 2023 at 07:27):

Possibly, at this line a further case could be added for Expr.lit atoms?

Mario Carneiro (Aug 07 2023 at 07:47):

I don't think that's the issue; without a .lit case it would just treat every pair of literals as differing

Mario Carneiro (Aug 07 2023 at 07:48):

I think what is happening is that the diff is traversing partially inside the term 4, so there is no place to show the highlight

Damiano Testa (Aug 07 2023 at 07:49):

Ah, a case of "I found a beautiful diff for your tactic, but this expression is too small to contain it"?

Mario Carneiro (Aug 07 2023 at 07:50):

I'm not sure exactly how to make it work but the diff should be "rounded up" somehow to the nearest displayable subexpression; it should never be the case that a diff is hidden because there isn't a syntax for that subexpression

Damiano Testa (Aug 07 2023 at 07:51):

But why does the diff on a and b work then?

Mario Carneiro (Aug 07 2023 at 07:51):

because a is what changed in that case

Damiano Testa (Aug 07 2023 at 07:52):

and isn't 4 what changed in the second case?

Mario Carneiro (Aug 07 2023 at 07:52):

with 4 what changed is actually the two occurrences of 4 in OfNat Nat 4 (instOfNat 4)

Mario Carneiro (Aug 07 2023 at 07:52):

which are .lit

Damiano Testa (Aug 07 2023 at 07:53):

Ah, I see and I understand you comment now: the change is embedded further inside.

Damiano Testa (Aug 07 2023 at 07:53):

It is "shielded" by the OfNat application, right?

Mario Carneiro (Aug 07 2023 at 07:54):

we want to show a diff that is more fine-grained than we can display

Mario Carneiro (Aug 07 2023 at 07:55):

it would be extra cool if you could see the fine grained diff if you hover over the 4

Damiano Testa (Aug 07 2023 at 07:56):

So now the marker for the beginning and end of changes get updated to the (two) 4s inside the OfNat application, but then the infoview does not show this, right?

Damiano Testa (Aug 07 2023 at 07:56):

whereas the diff should only update the begin/end position once it reaches a displayable location, not any location.

Damiano Testa (Aug 07 2023 at 07:57):

And you are saying that the infoview could highlight 4 in the case above, but then, on hover, highlight the 4's inside the OfNat application?

Damiano Testa (Aug 07 2023 at 07:57):

Am I understanding what is happening?

Damiano Testa (Aug 07 2023 at 07:58):

Something like duplicating the begin/end markers, one for displayble change, one for actual change. Possibly, the current one with the actual change determines the "next-up" available displayable one, though...

Damiano Testa (Aug 07 2023 at 08:01):

In this case,

example : 4 + a = 0 := by
  rw [add_comm]

4 also gets highlighted.

Mario Carneiro (Aug 07 2023 at 08:01):

which validates my diagnosis

Damiano Testa (Aug 07 2023 at 08:02):

In this case, 4 is highlighted because the diff does not enter it? The diff does not enter 4 since the arguments of HAdd.hadd have already different heads?

Damiano Testa (Aug 07 2023 at 08:03):

Ok:

example : Nat.cast 4 + Nat.cast 3 = 0 := by
  rw [add_comm]  -- no, no highlighting here

example : Nat.cast 4 + 3 = 0 := by
  rw [add_comm]  -- yes, highlighting here

Damiano Testa (Aug 07 2023 at 08:04):

So, I think that I now understand better what you said from the very beginning!

Damiano Testa (Aug 07 2023 at 08:13):

Indeed, this highlights the "inner-most" change:

example : @OfNat.ofNat  (Nat.succ Nat.zero) _ + @OfNat.ofNat  (Nat.succ $ Nat.succ Nat.zero) _ = 0 := by
  rw [add_comm]  -- `Nat.zero` vs `Nat.succ Nat.zero`

This is very cool!

Mario Carneiro (Aug 07 2023 at 08:15):

here's another way to see the highlight:

set_option pp.all true
example : 4 + 3 = 0 := by
  rw [Nat.add_comm]

Damiano Testa (Aug 07 2023 at 08:16):

Ah, great! I was doing my own pp.almost_all implementation by hand...

Damiano Testa (Aug 07 2023 at 08:31):

So, when the information about the diff reaches the stage where it should be printed, then either

  • the diff stained a whole node that gets printed with the current settings and thus gets displayed, or
  • the stain is inside something that is displayed and gets ignored, rather than expanding.

I know that this is probably the content of your first comment, Mario, but I am very unaware of how these things happen!

Mario Carneiro (Aug 07 2023 at 08:34):

so the question is then, where is the logic that actually does the rendering and how should it be changed to not ignore changes in subterms

Damiano Testa (Aug 07 2023 at 08:35):

Yes, suddenly I feel like I understand what you say, Mario!

Damiano Testa (Aug 07 2023 at 08:36):

Is the idea that whatever takes care of printing should remember whether a subpart was stained and propagate the stain to the whole?

Sebastian Ullrich (Aug 07 2023 at 08:36):

The answer to the first part is Lean.Widget.Diff


Last updated: Dec 20 2023 at 11:08 UTC