lean4-htt/tests/lean/run/change.lean
Kyle Miller 764386734c
fix: improvements to change tactic (#6022)
This PR makes the `change` tactic and conv tactic use the same
elaboration strategy. It works uniformly for both the target and local
hypotheses. Now `change` can assign metavariables, for example:
```lean
example (x y z : Nat) : x + y = z := by
  change ?a = _
  let w := ?a
  -- now `w : Nat := x + y`
```
2024-11-16 07:08:29 +00:00

211 lines
4.5 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

private axiom test_sorry : ∀ {α}, α
set_option linter.missingDocs false
set_option pp.mvars false
example : n + 2 = m := by
change n + 1 + 1 = _
guard_target =ₛ n + 1 + 1 = m
exact test_sorry
example (h : n + 2 = m) : False := by
change _ + 1 = _ at h
guard_hyp h :ₛ n + 1 + 1 = m
exact test_sorry
example : n + 2 = m := by
fail_if_success change true
fail_if_success change _ + 3 = _
fail_if_success change _ * _ = _
change (_ : Nat) + _ = _
exact test_sorry
-- `change ... at ...` allows placeholders to mean different things at different hypotheses
example (h : n + 3 = m) (h' : n + 2 = m) : False := by
change _ + 1 = _ at h h'
guard_hyp h :ₛ n + 2 + 1 = m
guard_hyp h' :ₛ n + 1 + 1 = m
exact test_sorry
-- `change ... at ...` preserves dependencies
example (p : n + 2 = m → Type) (h : n + 2 = m) (x : p h) : false := by
change _ + 1 = _ at h
guard_hyp x :ₛ p h
exact test_sorry
noncomputable example : Nat := by
fail_if_success change Type 1
exact test_sorry
def foo (a b c : Nat) := if a < b then c else 0
/-!
The first `change` would fail with `typeclass instance problem is stuck` if we did not have
the `Term.synthesizeSyntheticMVars (postpone := .partial); discard <| isDefEq p e` hint
-/
example : foo 1 2 3 = 3 := by
change (if _ then _ else _) = _
change ite _ _ _ = _
change (if _ < _ then _ else _) = _
change _ = (if true then 3 else 4)
rfl
example (h : foo 1 2 3 = 4) : True := by
change ite _ _ _ = _ at h
guard_hyp h :ₛ ite (1 < 2) 3 0 = 4
trivial
example (h : foo 1 2 3 = 4) : True := by
change (if _ then _ else _) = _ at h
guard_hyp h : (if 1 < 2 then 3 else 0) = 4
trivial
example (α : Type) [LT α] (x : α) (h : x < x) : x < id x := by
change _ < _ -- can defer LT typeclass lookup, just like `show`
change _ < _ at h -- can defer LT typeclass lookup at h too
guard_target =ₛ x < id x
change _ < x
guard_target =ₛ x < x
exact h
/-!
basic failure
-/
/--
error: 'change' tactic failed, pattern
m = ?_
is not definitionally equal to target
n = m
-/
#guard_msgs in example : n = m := by
change m = _
/-!
`change` can create new metavariables and assign them
-/
/--
info: x y z : Nat
w : Nat := x + y
⊢ x + y = z
-/
#guard_msgs in
example (x y z : Nat) : x + y = z := by
change ?a = _
let w := ?a
trace_state
exact test_sorry
/-!
`change` is allowed to create new goals.
Motivation: sometimes there are proof arguments that need to be filled in, and it is easier to do so as a new goal.
-/
example (x y : Nat) (h : x = y) : True := by
change (if 1 < 2 then x else ?z) = y at h
· trivial
· exact 22
example : let x := 22; let y : Nat := x; let z : Fin (y + 1) := 0; z.1 < y + 1 := by
intro x y z -- `z` was previously erroneously marked as unused
change _ at y
exact z.2
/-!
`change` reorders hypotheses if necessary
-/
/--
info: x y z w : Nat
a : Nat := x + y
h : a = z + w
⊢ True
-/
#guard_msgs in
example (x y z w : Nat) (h : x + y = z + w) : True := by
let a := x + y
change a = _ at h
trace_state
trivial
/-!
`change` inserts a coercion when types are incompatible.
-/
example (ty : {α : Prop // Nonempty α}) : ty.val := by
change ty
guard_target =ₛ ty.val
exact test_sorry
/-!
Fails, type hint can't hint enough since `.some _` is postponed.
-/
/--
error: invalid dotted identifier notation, expected type is not of the form (... → C ...) where C is a constant
?_
-/
#guard_msgs in example : some true = (some true).map id := by
change _ = .some _
/-!
That works with a mild type hint.
-/
example : some true = (some true).map id := by
change _ = (.some _ : Option _)
rfl
/-!
## Conv `change`
-/
/-!
conv `change` test
-/
example (m n : Nat) : m + 2 = n := by
conv => enter [1]; change m + (1 + 1)
guard_target =ₛ m + (1 + 1) = n
exact test_sorry
/-!
conv `change` test failure
-/
/--
error: 'change' tactic failed, pattern
m + n
is not definitionally equal to target
m + 2
-/
#guard_msgs in
example (m n : Nat) : m + 2 = n := by
conv => enter [1]; change m + n
/-!
conv `change` unsolved metavariables
-/
/--
error: don't know how to synthesize placeholder for argument 'e'
context:
case a
m n : Nat
⊢ Nat
---
error: unsolved goals
m n : Nat
⊢ m + 2 = n
-/
#guard_msgs in
example (m n : Nat) : m + 2 = n := by
conv => enter [1]; change if True then m + 2 else ?a
/-!
conv `change` to create a metavariable
-/
/--
info: a b c d : Nat
e : Nat := a + b
⊢ a + b + c = d
-/
#guard_msgs in
example (a b c d : Nat) : a + b + c = d := by
conv => enter [1,1]; change ?mvar
let e := ?mvar
trace_state
exact test_sorry