Skip to content

Commit 0dd326c

Browse files
committed
feat(translate): automatically infer the (reorder := ...) argument (#31902)
This PR adds the feature to `to_additive` and `to_dual` that if the translation already exists (i.e. when using `existing` or `self`) the attribute will try to guess how to reorder the arguments correctly. If you then provide the same `reorder` argument manually, the linter will tell you that you can remove it.
1 parent 7bf950c commit 0dd326c

File tree

12 files changed

+274
-124
lines changed

12 files changed

+274
-124
lines changed

Mathlib/Algebra/Group/ULift.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ instance smul [SMul α β] : SMul α (ULift β) :=
6969
theorem smul_down [SMul α β] (a : α) (b : ULift.{w} β) : (a • b).down = a • b.down :=
7070
rfl
7171

72-
@[to_additive existing (reorder := 1 2) smul]
72+
@[to_additive existing smul]
7373
instance pow [Pow α β] : Pow (ULift α) β :=
7474
fun x n => up (x.down ^ n)⟩
7575

76-
@[to_additive existing (attr := simp) (reorder := 1 2, 4 5) smul_down]
76+
@[to_additive existing (attr := simp) smul_down]
7777
theorem pow_down [Pow α β] (a : ULift.{w} α) (b : β) : (a ^ b).down = a.down ^ b :=
7878
rfl
7979

Mathlib/Algebra/Notation/Defs.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ attribute [to_additive existing (reorder := 1 2, 5 6) hSMul] HPow.hPow
7878
attribute [to_additive existing (reorder := 1 2, 4 5) smul] Pow.pow
7979

8080
attribute [to_additive (attr := default_instance)] instHSMul
81-
attribute [to_additive existing (reorder := 1 2)] instHPow
81+
attribute [to_additive existing] instHPow
8282

8383
variable {G : Type*}
8484

Mathlib/Algebra/Notation/Prod.lean

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,19 +158,19 @@ variable {E α β : Type*} [Pow α E] [Pow β E]
158158
@[to_additive existing instSMul]
159159
instance instPow : Pow (α × β) E where pow p c := (p.1 ^ c, p.2 ^ c)
160160

161-
@[to_additive existing (attr := simp) (reorder := 6 7) smul_fst]
161+
@[to_additive existing (attr := simp) smul_fst]
162162
lemma pow_fst (p : α × β) (c : E) : (p ^ c).fst = p.fst ^ c := rfl
163163

164-
@[to_additive existing (attr := simp) (reorder := 6 7) smul_snd]
164+
@[to_additive existing (attr := simp) smul_snd]
165165
lemma pow_snd (p : α × β) (c : E) : (p ^ c).snd = p.snd ^ c := rfl
166166

167-
@[to_additive existing (attr := simp) (reorder := 6 7 8) smul_mk]
167+
@[to_additive existing (attr := simp) smul_mk]
168168
lemma pow_mk (a : α) (b : β) (c : E) : Prod.mk a b ^ c = Prod.mk (a ^ c) (b ^ c) := rfl
169169

170-
@[to_additive existing (reorder := 6 7) smul_def]
170+
@[to_additive existing smul_def]
171171
lemma pow_def (p : α × β) (c : E) : p ^ c = (p.1 ^ c, p.2 ^ c) := rfl
172172

173-
@[to_additive existing (attr := simp) (reorder := 6 7) smul_swap]
173+
@[to_additive existing (attr := simp) smul_swap]
174174
lemma pow_swap (p : α × β) (c : E) : (p ^ c).swap = p.swap ^ c := rfl
175175

176176
end Pow

Mathlib/Combinatorics/Quiver/Basic.lean

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,16 @@ instance opposite {V} [Quiver V] : Quiver Vᵒᵖ :=
6161
fun a b => (unop b ⟶ unop a)ᵒᵖ⟩
6262

6363
/-- The opposite of an arrow in `V`. -/
64-
@[to_dual self (reorder := 3 4)]
64+
@[to_dual self]
6565
def Hom.op {V} [Quiver V] {X Y : V} (f : X ⟶ Y) : op Y ⟶ op X := ⟨f⟩
6666

6767
/-- Given an arrow in `Vᵒᵖ`, we can take the "unopposite" back in `V`. -/
68-
@[to_dual self (reorder := 3 4)]
68+
@[to_dual self]
6969
def Hom.unop {V} [Quiver V] {X Y : Vᵒᵖ} (f : X ⟶ Y) : unop Y ⟶ unop X := Opposite.unop f
7070

7171
/-- The bijection `(X ⟶ Y) ≃ (op Y ⟶ op X)`. -/
72-
@[simps, to_dual self (reorder := 3 4)]
73-
def Hom.opEquiv {V} [Quiver V] {X Y : V} :
74-
(X ⟶ Y) ≃ (Opposite.op Y ⟶ Opposite.op X) where
72+
@[simps, to_dual self]
73+
def Hom.opEquiv {V} [Quiver V] {X Y : V} : (X ⟶ Y) ≃ (Opposite.op Y ⟶ Opposite.op X) where
7574
toFun := Opposite.op
7675
invFun := Opposite.unop
7776

@@ -80,7 +79,7 @@ def Empty (V : Type u) : Type u := V
8079

8180
instance emptyQuiver (V : Type u) : Quiver.{u} (Empty V) := ⟨fun _ _ => PEmpty⟩
8281

83-
@[simp, to_dual self (reorder := 2 3)]
82+
@[simp, to_dual self]
8483
theorem empty_arrow {V : Type u} (a b : Empty V) : (a ⟶ b) = PEmpty := rfl
8584

8685
/-- A quiver is thin if it has no parallel arrows. -/
@@ -95,54 +94,54 @@ variable {V : Type*} [Quiver V] {X Y X' Y' : V}
9594

9695
/-- An arrow in a quiver can be transported across equalities between the source and target
9796
objects. -/
98-
@[to_dual self (reorder := 3 4, 5 6, 8 9)]
97+
@[to_dual self (reorder := X Y, X' Y', hX hY)]
9998
def homOfEq (f : X ⟶ Y) (hX : X = X') (hY : Y = Y') : X' ⟶ Y' := by
10099
subst hX hY
101100
exact f
102101

103-
@[simp, to_dual self (reorder := 3 4, 5 6, 8 9, 10 11, 12 13)]
102+
@[simp, to_dual self]
104103
lemma homOfEq_trans (f : X ⟶ Y) (hX : X = X') (hY : Y = Y')
105104
{X'' Y'' : V} (hX' : X' = X'') (hY' : Y' = Y'') :
106105
homOfEq (homOfEq f hX hY) hX' hY' = homOfEq f (hX.trans hX') (hY.trans hY') := by
107106
subst hX hY hX' hY'
108107
rfl
109108

110-
@[to_dual self (reorder := 3 4, 5 6, 7 8)]
109+
@[to_dual self]
111110
lemma homOfEq_injective (hX : X = X') (hY : Y = Y')
112111
{f g : X ⟶ Y} (h : Quiver.homOfEq f hX hY = Quiver.homOfEq g hX hY) : f = g := by
113112
subst hX hY
114113
exact h
115114

116-
@[simp, to_dual self (reorder := 3 4)]
115+
@[simp, to_dual self]
117116
lemma homOfEq_rfl (f : X ⟶ Y) : Quiver.homOfEq f rfl rfl = f := rfl
118117

119-
@[to_dual self (reorder := 3 4, 5 6, 7 8)]
118+
@[to_dual self]
120119
lemma heq_of_homOfEq_ext (hX : X = X') (hY : Y = Y') {f : X ⟶ Y} {f' : X' ⟶ Y'}
121120
(e : Quiver.homOfEq f hX hY = f') : f ≍ f' := by
122121
subst hX hY
123122
rw [Quiver.homOfEq_rfl] at e
124123
rw [e]
125124

126-
@[to_dual self (reorder := 3 4, 5 6, 9 10)]
125+
@[to_dual self]
127126
lemma homOfEq_eq_iff (f : X ⟶ Y) (g : X' ⟶ Y') (hX : X = X') (hY : Y = Y') :
128127
Quiver.homOfEq f hX hY = g ↔ f = Quiver.homOfEq g hX.symm hY.symm := by
129128
subst hX hY; simp
130129

131-
@[to_dual self (reorder := 3 4, 5 6, 9 10)]
130+
@[to_dual self]
132131
lemma eq_homOfEq_iff (f : X ⟶ Y) (g : X' ⟶ Y') (hX : X' = X) (hY : Y' = Y) :
133132
f = Quiver.homOfEq g hX hY ↔ Quiver.homOfEq f hX.symm hY.symm = g := by
134133
subst hX hY; simp
135134

136-
@[to_dual self (reorder := 3 4, 5 6, 7 8)]
135+
@[to_dual self]
137136
lemma homOfEq_heq (hX : X = X') (hY : Y = Y') (f : X ⟶ Y) : homOfEq f hX hY ≍ f :=
138137
(heq_of_homOfEq_ext hX hY rfl).symm
139138

140-
@[to_dual self (reorder := 3 4, 5 6, 9 10)]
139+
@[to_dual self]
141140
lemma homOfEq_heq_left_iff (f : X ⟶ Y) (g : X' ⟶ Y') (hX : X = X') (hY : Y = Y') :
142141
homOfEq f hX hY ≍ g ↔ f ≍ g := by
143142
cases hX; cases hY; rfl
144143

145-
@[to_dual self (reorder := 3 4, 5 6, 9 10)]
144+
@[to_dual self]
146145
lemma homOfEq_heq_right_iff (f : X ⟶ Y) (g : X' ⟶ Y') (hX : X' = X) (hY : Y' = Y) :
147146
f ≍ homOfEq g hX hY ↔ f ≍ g := by
148147
cases hX; cases hY; rfl

Mathlib/Order/Basic.lean

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,12 @@ section Preorder
122122

123123
variable [Preorder α] {a b c d : α}
124124

125-
@[to_dual self (reorder := a b)]
125+
@[to_dual self]
126126
theorem not_lt_iff_not_le_or_ge : ¬a < b ↔ ¬a ≤ b ∨ b ≤ a := by
127127
rw [lt_iff_le_not_ge, Classical.not_and_iff_not_or_not, Classical.not_not]
128128

129129
-- Unnecessary brackets are here for readability
130-
@[to_dual self (reorder := a b)]
130+
@[to_dual self]
131131
lemma not_lt_iff_le_imp_ge : ¬ a < b ↔ (a ≤ b → b ≤ a) := by
132132
simp [not_lt_iff_not_le_or_ge, or_iff_not_imp_left]
133133

@@ -143,10 +143,10 @@ lemma lt_self_iff_false (x : α) : x < x ↔ False := ⟨lt_irrefl x, False.elim
143143
@[to_dual trans_lt'] alias LE.le.trans_lt := lt_of_le_of_lt
144144
@[to_dual trans_le'] alias LT.lt.trans_le := lt_of_lt_of_le
145145

146-
@[to_dual self (reorder := a b)] alias LE.le.lt_of_not_ge := lt_of_le_not_ge
147-
@[to_dual self (reorder := a b)] alias LT.lt.le := le_of_lt
148-
@[to_dual self (reorder := a b)] alias LT.lt.asymm := lt_asymm
149-
@[to_dual self (reorder := a b)] alias LT.lt.not_gt := lt_asymm
146+
@[to_dual self] alias LE.le.lt_of_not_ge := lt_of_le_not_ge
147+
@[to_dual self] alias LT.lt.le := le_of_lt
148+
@[to_dual self] alias LT.lt.asymm := lt_asymm
149+
@[to_dual self] alias LT.lt.not_gt := lt_asymm
150150

151151
@[to_dual ne'] alias LT.lt.ne := ne_of_lt
152152
@[to_dual ge] alias Eq.le := le_of_eq
@@ -161,11 +161,11 @@ lemma lt_self_iff_false (x : α) : x < x ↔ False := ⟨lt_irrefl x, False.elim
161161
@[to_dual ne_of_not_ge]
162162
theorem ne_of_not_le (h : ¬a ≤ b) : a ≠ b := fun hab ↦ h (le_of_eq hab)
163163

164-
@[simp, to_dual self (reorder := a b)]
164+
@[simp, to_dual self]
165165
lemma le_of_subsingleton [Subsingleton α] : a ≤ b := (Subsingleton.elim a b).le
166166

167167
-- Making this a @[simp] lemma causes confluence problems downstream.
168-
@[nontriviality, to_dual self (reorder := a b)]
168+
@[nontriviality, to_dual self]
169169
lemma not_lt_of_subsingleton [Subsingleton α] : ¬a < b := (Subsingleton.elim a b).not_lt
170170

171171
@[to_dual le_of_forall_ge]

Mathlib/Order/Defs/LinearOrder.lean

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,17 @@ def LinearOrder.toDecidableLE' : DecidableLE' α := fun a b => toDecidableLE b a
9292
instance : Std.IsLinearOrder α where
9393
le_total := LinearOrder.le_total
9494

95-
lemma le_total : ∀ a b : α, a ≤ b ∨ b ≤ a := LinearOrder.le_total
95+
@[to_dual self] lemma le_total : ∀ a b : α, a ≤ b ∨ b ≤ a := LinearOrder.le_total
9696

97-
lemma le_of_not_ge : ¬a ≤ b → b ≤ a := (le_total a b).resolve_left
98-
lemma lt_of_not_ge (h : ¬b ≤ a) : a < b := lt_of_le_not_ge (le_of_not_ge h) h
97+
@[to_dual self] lemma le_of_not_ge : ¬a ≤ b → b ≤ a := (le_total a b).resolve_left
98+
@[to_dual self] lemma lt_of_not_ge (h : ¬b ≤ a) : a < b := lt_of_le_not_ge (le_of_not_ge h) h
9999

100100
@[deprecated (since := "2025-05-11")] alias le_of_not_le := le_of_not_ge
101101

102102
@[to_dual gt_trichotomy]
103103
lemma lt_trichotomy (a b : α) : a < b ∨ a = b ∨ b < a := by grind
104104

105+
@[to_dual self]
105106
lemma le_of_not_gt (h : ¬b < a) : a ≤ b :=
106107
match lt_trichotomy a b with
107108
| Or.inl hlt => le_of_lt hlt
@@ -110,12 +111,12 @@ lemma le_of_not_gt (h : ¬b < a) : a ≤ b :=
110111

111112
@[deprecated (since := "2025-05-11")] alias le_of_not_lt := le_of_not_gt
112113

113-
lemma lt_or_ge (a b : α) : a < b ∨ b ≤ a :=
114+
@[to_dual self] lemma lt_or_ge (a b : α) : a < b ∨ b ≤ a :=
114115
if hba : b ≤ a then Or.inr hba else Or.inl <| lt_of_not_ge hba
115116

116117
@[deprecated (since := "2025-05-11")] alias lt_or_le := lt_or_ge
117118

118-
lemma le_or_gt (a b : α) : a ≤ b ∨ b < a := (lt_or_ge b a).symm
119+
@[to_dual self] lemma le_or_gt (a b : α) : a ≤ b ∨ b < a := (lt_or_ge b a).symm
119120

120121
@[deprecated (since := "2025-05-11")] alias le_or_lt := le_or_gt
121122

@@ -125,21 +126,18 @@ lemma lt_or_gt_of_ne (h : a ≠ b) : a < b ∨ b < a := by grind
125126
@[to_dual ne_iff_gt_or_lt]
126127
lemma ne_iff_lt_or_gt : a ≠ b ↔ a < b ∨ b < a := ⟨lt_or_gt_of_ne, (Or.elim · ne_of_lt ne_of_gt)⟩
127128

128-
lemma lt_iff_not_ge : a < b ↔ ¬b ≤ a := ⟨not_le_of_gt, lt_of_not_ge⟩
129+
@[to_dual self] lemma lt_iff_not_ge : a < b ↔ ¬b ≤ a := ⟨not_le_of_gt, lt_of_not_ge⟩
129130

130-
@[simp, push] lemma not_lt : ¬a < b ↔ b ≤ a := ⟨le_of_not_gt, not_lt_of_ge⟩
131-
@[simp, push] lemma not_le : ¬a ≤ b ↔ b < a := lt_iff_not_ge.symm
132-
133-
attribute [to_dual self (reorder := a b)]
134-
le_total le_of_not_ge lt_of_not_ge le_of_not_gt lt_or_ge le_or_gt lt_iff_not_ge not_lt not_le
131+
@[simp, push, to_dual self] lemma not_lt : ¬a < b ↔ b ≤ a := ⟨le_of_not_gt, not_lt_of_ge⟩
132+
@[simp, push, to_dual self] lemma not_le : ¬a ≤ b ↔ b < a := lt_iff_not_ge.symm
135133

136134
@[to_dual eq_or_lt_of_not_gt]
137135
lemma eq_or_gt_of_not_lt (h : ¬a < b) : a = b ∨ b < a :=
138136
if h₁ : a = b then Or.inl h₁ else Or.inr (lt_of_not_ge fun hge => h (lt_of_le_of_ne hge h₁))
139137

140138
@[deprecated (since := "2025-05-11")] alias eq_or_lt_of_not_lt := eq_or_gt_of_not_lt
141139

142-
@[to_dual self (reorder := a b, c d)]
140+
@[to_dual self]
143141
theorem le_imp_le_of_lt_imp_lt {α β} [Preorder α] [LinearOrder β] {a b : α} {c d : β}
144142
(H : d < c → b < a) (h : a ≤ b) : c ≤ d :=
145143
le_of_not_gt fun h' => not_le_of_gt (H h') h

Mathlib/Order/Defs/PartialOrder.lean

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ class Preorder (α : Type*) extends LE α, LT α where
4848
lt := fun a b => a ≤ b ∧ ¬b ≤ a
4949
lt_iff_le_not_ge : ∀ a b : α, a < b ↔ a ≤ b ∧ ¬b ≤ a := by intros; rfl
5050

51-
attribute [to_dual self (reorder := 3 5, 6 7)] Preorder.le_trans
52-
attribute [to_dual self (reorder := 3 4)] Preorder.lt_iff_le_not_ge
51+
attribute [to_dual self (reorder := a c, 6 7)] Preorder.le_trans
52+
attribute [to_dual self] Preorder.lt_iff_le_not_ge
5353

5454
instance [Preorder α] : Std.LawfulOrderLT α where
5555
lt_iff := Preorder.lt_iff_le_not_ge
@@ -71,30 +71,26 @@ lemma le_rfl : a ≤ a := le_refl a
7171
/-- The relation `≤` on a preorder is transitive. -/
7272
@[to_dual ge_trans] lemma le_trans : a ≤ b → b ≤ c → a ≤ c := Preorder.le_trans _ _ _
7373

74-
@[to_dual self (reorder := 3 4)]
74+
@[to_dual self]
7575
lemma lt_iff_le_not_ge : a < b ↔ a ≤ b ∧ ¬b ≤ a := Preorder.lt_iff_le_not_ge _ _
7676

7777
@[deprecated (since := "2025-05-11")] alias lt_iff_le_not_le := lt_iff_le_not_ge
7878

79-
@[to_dual self (reorder := 3 4)]
79+
@[to_dual self]
8080
lemma lt_of_le_not_ge (hab : a ≤ b) (hba : ¬ b ≤ a) : a < b := lt_iff_le_not_ge.2 ⟨hab, hba⟩
8181

8282
@[deprecated (since := "2025-05-11")] alias lt_of_le_not_le := lt_of_le_not_ge
8383

84-
@[to_dual ge_of_eq]
85-
lemma le_of_eq (hab : a = b) : a ≤ b := by rw [hab]
86-
@[to_dual self (reorder := 3 4)]
87-
lemma le_of_lt (hab : a < b) : a ≤ b := (lt_iff_le_not_ge.1 hab).1
88-
@[to_dual self (reorder := 3 4)]
89-
lemma not_le_of_gt (hab : a < b) : ¬ b ≤ a := (lt_iff_le_not_ge.1 hab).2
90-
@[to_dual self (reorder := 3 4)]
91-
lemma not_lt_of_ge (hab : a ≤ b) : ¬ b < a := imp_not_comm.1 not_le_of_gt hab
84+
@[to_dual ge_of_eq] lemma le_of_eq (hab : a = b) : a ≤ b := by rw [hab]
85+
@[to_dual self] lemma le_of_lt (hab : a < b) : a ≤ b := (lt_iff_le_not_ge.1 hab).1
86+
@[to_dual self] lemma not_le_of_gt (hab : a < b) : ¬ b ≤ a := (lt_iff_le_not_ge.1 hab).2
87+
@[to_dual self] lemma not_lt_of_ge (hab : a ≤ b) : ¬ b < a := imp_not_comm.1 not_le_of_gt hab
9288

9389
@[deprecated (since := "2025-05-11")] alias not_le_of_lt := not_le_of_gt
9490
@[deprecated (since := "2025-05-11")] alias not_lt_of_le := not_lt_of_ge
9591

96-
@[to_dual self (reorder := 3 4)] alias LT.lt.not_ge := not_le_of_gt
97-
@[to_dual self (reorder := 3 4)] alias LE.le.not_gt := not_lt_of_ge
92+
@[to_dual self] alias LT.lt.not_ge := not_le_of_gt
93+
@[to_dual self] alias LE.le.not_gt := not_lt_of_ge
9894

9995
@[deprecated (since := "2025-06-07")] alias LT.lt.not_le := LT.lt.not_ge
10096
@[deprecated (since := "2025-06-07")] alias LE.le.not_lt := LE.le.not_gt
@@ -119,11 +115,11 @@ lemma lt_trans : a < b → b < c → a < c := fun h₁ h₂ => lt_of_lt_of_le h
119115

120116
@[to_dual ne_of_gt]
121117
lemma ne_of_lt (h : a < b) : a ≠ b := fun he => absurd h (he ▸ lt_irrefl a)
122-
@[to_dual self (reorder := 3 4)]
118+
@[to_dual self]
123119
lemma lt_asymm (h : a < b) : ¬b < a := fun h1 : b < a => lt_irrefl a (lt_trans h h1)
124120

125-
@[to_dual self (reorder := 3 4)]
126-
alias not_lt_of_gt := lt_asymm
121+
@[to_dual self] alias not_lt_of_gt := lt_asymm
122+
127123
@[deprecated (since := "2025-05-11")] alias not_lt_of_lt := not_lt_of_gt
128124

129125
@[to_dual le_of_lt_or_eq']

Mathlib/Tactic/ToDual.lean

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ attribute [to_dual DecidableLE' /-- `DecidableLE'` is equivalent to `DecidableLE
3333
It is used by `@[to_dual]` in order to deal with `DecidableLE`. -/] DecidableLE
3434

3535
set_option linter.existingAttributeWarning false in
36-
attribute [to_dual self (reorder := 3 4)] ge_iff_le gt_iff_lt
36+
attribute [to_dual self] ge_iff_le gt_iff_lt
3737

3838
attribute [to_dual le_of_eq_of_le''] le_of_eq_of_le
3939
attribute [to_dual le_of_le_of_eq''] le_of_le_of_eq
@@ -46,12 +46,11 @@ attribute [to_dual] Max
4646
namespace Lean.Grind.Order
4747

4848
attribute [to_dual existing le_of_eq_1] le_of_eq_2
49-
attribute [to_dual self (reorder := a b)] le_of_not_le lt_of_not_le le_of_not_lt
49+
attribute [to_dual self] le_of_not_le lt_of_not_le le_of_not_lt
5050
attribute [to_dual self (reorder := 6 7)] eq_of_le_of_le
5151
attribute [to_dual self (reorder := a c, h₁ h₂)] le_trans lt_trans
5252
attribute [to_dual existing (reorder := a c, h₁ h₂) le_lt_trans] lt_le_trans
53-
attribute [to_dual self (reorder := a b)]
54-
le_eq_true_of_lt le_eq_false_of_lt lt_eq_false_of_lt lt_eq_false_of_le
53+
attribute [to_dual self] le_eq_true_of_lt le_eq_false_of_lt lt_eq_false_of_lt lt_eq_false_of_le
5554

5655
/- For now, we don't tag any `grind` lemmas involving offsets, but this may be done in the future.
5756
These offset lemmas are:

0 commit comments

Comments
 (0)