Skip to content

Commit afd3aca

Browse files
committed
feat: rw? can discharge side conditions using local hypotheses (#7770)
Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
1 parent 0a44be3 commit afd3aca

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

Mathlib/Tactic/Rewrites.lean

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Mathlib.Tactic.Cache
1212
import Mathlib.Lean.Meta
1313
import Mathlib.Tactic.TryThis
1414
import Mathlib.Control.Basic
15+
import Mathlib.Tactic.SolveByElim
1516

1617
/-!
1718
# The `rewrites` tactic.
@@ -30,6 +31,20 @@ We could try discharging side goals via `assumption` or `solve_by_elim`.
3031

3132
set_option autoImplicit true
3233

34+
namespace Lean.Meta
35+
36+
/-- Extract the lemma, with arguments, that was used to produce a `RewriteResult`. -/
37+
-- This assumes that `r.eqProof` was constructed as:
38+
-- `mkAppN (mkConst ``Eq.ndrec [u1, u2]) #[α, a, motive, h₁, b, h₂]`
39+
-- and we want `h₂`.
40+
def RewriteResult.by? (r : RewriteResult) : Option Expr :=
41+
if r.eqProof.isAppOfArity ``Eq.ndrec 6 then
42+
r.eqProof.getArg! 5
43+
else
44+
none
45+
46+
end Lean.Meta
47+
3348
namespace Mathlib.Tactic.Rewrites
3449

3550
open Lean Meta Std.Tactic.TryThis
@@ -157,6 +172,15 @@ def RewriteResult.computeRfl (r : RewriteResult) : MetaM RewriteResult := do
157172
catch _ =>
158173
pure { r with rfl? := some false }
159174

175+
/-- Shortcut for calling `solveByElim`. -/
176+
def solveByElim (goals : List MVarId) (depth : Nat := 6) : MetaM PUnit := do
177+
-- There is only a marginal decrease in performance for using the `symm` option for `solveByElim`.
178+
-- (measured via `lake build && time lake env lean test/librarySearch.lean`).
179+
let cfg : SolveByElim.Config :=
180+
{ maxDepth := depth, exfalso := false, symm := true }
181+
let [] ← SolveByElim.solveByElim.processSyntax cfg false false [] [] #[] goals
182+
| failure
183+
160184
/--
161185
Find lemmas which can rewrite the goal.
162186
@@ -206,12 +230,19 @@ def rewritesCore (hyps : Array (Expr × Bool × Nat))
206230
trace[Tactic.rewrites] m!"considering {if symm then "" else ""}{expr}"
207231
let some result ← try? do goal.rewrite target expr symm
208232
| return none
209-
return if result.mvarIds.isEmpty then
210-
some ⟨expr, symm, weight, result, none, ← getMCtx⟩
233+
if result.mvarIds.isEmpty then
234+
return some ⟨expr, symm, weight, result, none, ← getMCtx⟩
211235
else
212-
-- TODO Perhaps allow new goals? Try closing them with solveByElim?
213-
-- A challenge is knowing what suggestions to print if we do so!
214-
none
236+
-- There are side conditions, which we try to discharge using local hypotheses.
237+
let some _ ← try? do solveByElim result.mvarIds | return none
238+
-- If we succeed, we need to reconstruct the expression to report that we rewrote by.
239+
let some expr := result.by? | return none
240+
let expr ← instantiateMVars expr
241+
let (expr, symm) := if expr.isAppOfArity ``Eq.symm 4 then
242+
(expr.getArg! 3, true)
243+
else
244+
(expr, false)
245+
return some ⟨expr, symm, weight, result, none, ← getMCtx⟩
215246

216247
/-- Find lemmas which can rewrite the goal. -/
217248
def rewrites (hyps : Array (Expr × Bool × Nat))

test/rewrites.lean

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,22 @@ def zero : Nat := 0
125125
example : zero = 0 := by
126126
rw?
127127
exact test_sorry
128+
129+
-- Discharge side conditions from local hypotheses.
130+
/--
131+
info: Try this: rw [h p]
132+
-- "no goals"
133+
-/
134+
#guard_msgs in
135+
example {P : Prop} (p : P) (h : P → 1 = 2) : 2 = 1 := by
136+
rw?
137+
138+
-- Rewrite in reverse, discharging side conditions from local hypotheses.
139+
/--
140+
info: Try this: rw [← h₁ p]
141+
-- Q a
142+
-/
143+
#guard_msgs in
144+
example {P : Prop} (p : P) (Q : α → Prop) (a b : α) (h₁ : P → a = b) (w : Q a) : Q b := by
145+
rw?
146+
exact w

0 commit comments

Comments
 (0)