lean4-htt/tests/lean/run/wfirred.lean
Joachim Breitner a3ca15d2b2
refactor: back rfl tactic primarily via apply_rfl (#3718)
building upon #3714, this (almost) implements the second half of #3302.

The main effect is that we now get a better error message when `rfl`
fails. For
```lean
example : n+1+m = n + (1+m) := by rfl
```
instead of the wall of text
```
The rfl tactic failed. Possible reasons:
- The goal is not a reflexive relation (neither `=` nor a relation with a @[refl] lemma).
- The arguments of the relation are not equal.
Try using the reflexivity lemma for your relation explicitly, e.g. `exact Eq.refl _` or
`exact HEq.rfl` etc.
n m : Nat
⊢ n + 1 + m = n + (1 + m)
```
we now get
```
error: tactic 'rfl' failed, the left-hand side
  n + 1 + m
is not definitionally equal to the right-hand side
  n + (1 + m)
n m : Nat
⊢ n + 1 + m = n + (1 + m)
```

Unfortunately, because of very subtle differences in semantics (which
transparency setting is used when reducing the goal and whether the
“implicit lambda” feature applies) I could not make this simply the only
`rfl` implementation. So `rfl` remains a macro and is still expanded to
`eq_refl` (difference transparency setting) and `exact Iff.rfl` and
`exact HEq.rfl` (implicit lambda) to not break existing code. This can
be revised later, so this still closes: #3302.

A user might still be puzzled *why* to terms are not defeq. Explaining
that better (“reduced to… and reduces to… etc.”) would also be great,
but that’s not specific to `rfl`, so better left for some other time.
2024-09-25 10:34:42 +00:00

146 lines
2.3 KiB
Text

/-!
Tests that definitions by well-founded recursion are irreducible.
-/
def foo : Nat → Nat
| 0 => 0
| n+1 => foo n
termination_by n => n
/--
error: type mismatch
rfl
has type
foo 0 = foo 0 : Prop
but is expected to have type
foo 0 = 0 : Prop
-/
#guard_msgs in
example : foo 0 = 0 := rfl
/--
error: type mismatch
rfl
has type
foo (n + 1) = foo (n + 1) : Prop
but is expected to have type
foo (n + 1) = foo n : Prop
-/
#guard_msgs in
example : foo (n+1) = foo n := rfl
-- also for closed terms
/--
error: tactic 'rfl' failed, the left-hand side
foo 0
is not definitionally equal to the right-hand side
0
⊢ foo 0 = 0
-/
#guard_msgs in
example : foo 0 = 0 := by rfl
-- It only works on closed terms:
/--
error: tactic 'rfl' failed, the left-hand side
foo (n + 1)
is not definitionally equal to the right-hand side
foo n
n : Nat
⊢ foo (n + 1) = foo n
-/
#guard_msgs in
example : foo (n+1) = foo n := by rfl
section Unsealed
unseal foo
example : foo 0 = 0 := rfl
example : foo 0 = 0 := by rfl
example : foo (n+1) = foo n := rfl
example : foo (n+1) = foo n := by rfl
end Unsealed
--should be sealed again here
/--
error: type mismatch
rfl
has type
foo 0 = foo 0 : Prop
but is expected to have type
foo 0 = 0 : Prop
-/
#guard_msgs in
example : foo 0 = 0 := rfl
def bar : Nat → Nat
| 0 => 0
| n+1 => bar n
termination_by n => n
-- Once unsealed, the full internals are visible. This allows one to prove, for example
/--
error: type mismatch
rfl
has type
foo = foo : Prop
but is expected to have type
foo = bar : Prop
-/
#guard_msgs in
example : foo = bar := rfl
unseal foo bar in
example : foo = bar := rfl
-- Attributes on the definition take precedence
@[semireducible] def baz : Nat → Nat
| 0 => 0
| n+1 => baz n
termination_by n => n
example : baz 0 = 0 := rfl
seal baz in
/--
error: type mismatch
rfl
has type
baz 0 = baz 0 : Prop
but is expected to have type
baz 0 = 0 : Prop
-/
#guard_msgs in
example : baz 0 = 0 := rfl
example : baz 0 = 0 := rfl
@[reducible] def quux : Nat → Nat
| 0 => 0
| n+1 => quux n
termination_by n => n
example : quux 0 = 0 := rfl
set_option allowUnsafeReducibility true in
seal quux in
/--
error: type mismatch
rfl
has type
quux 0 = quux 0 : Prop
but is expected to have type
quux 0 = 0 : Prop
-/
#guard_msgs in
example : quux 0 = 0 := rfl
example : quux 0 = 0 := rfl