This implements the first half of #3302: It improves the extensible
`apply_rfl` tactic (the one that looks at `refl` attributes, part of
the `rfl` macro) to
* Check itself and ahead of time that the lhs and rhs are defEq, and
give
a nice consistent error message when they don't (instead of just passing
on
the less helpful error message from `apply Foo.refl`), and using the
machinery that `apply` uses to elaborate expressions to highlight diffs
in implicit arguments.
* Also handle `Eq` and `HEq` (built in) and `Iff` (using the attribute)
Care is taken that, as before, the current transparency setting affects
comparing the lhs and rhs, but not the reduction of the relation
So before we had
```lean
opaque P : Nat → Nat → Prop
@[refl] axiom P.refl (n : Nat) : P n n
/--
error: tactic 'apply' failed, failed to unify
P ?n ?n
with
P 42 23
⊢ P 42 23
-/
#guard_msgs in
example : P 42 23 := by apply_rfl
opaque withImplicitNat {n : Nat} : Nat
/--
error: tactic 'apply' failed, failed to unify
P ?n ?n
with
P withImplicitNat withImplicitNat
⊢ P withImplicitNat withImplicitNat
-/
#guard_msgs in
example : P (@withImplicitNat 42) (@withImplicitNat 23) := by apply_rfl
```
and with this PR the messages we get are
```
error: tactic 'apply_rfl' failed, The lhs
42
is not definitionally equal to rhs
23
⊢ P 42 23
```
resp.
```
error: tactic 'apply_rfl' failed, The lhs
@withImplicitNat 42
is not definitionally equal to rhs
@withImplicitNat 23
⊢ P withImplicitNat withImplicitNat
```
A test file checks the various failure modes and error messages.
I believe this `apply_rfl` can serve as the only implementation of
`rfl`, which would then complete #3302, and actually expose these
improved
error messages to the user. But as that seems to require a
non-trivial bootstrapping dance, it’ll be separate.
Sebastian mentioned that the use of the kernel defeq was to work around
a performance issue that was fixed since. Let's see if we can do
without.
This is also a semantic change: Ground terms (no free vars, no mvars)
are reduced at
“all” transparency even if the the transparency setting is default. This
was the case
even before 03f6b87647 switched to the
kernel defeq
checking for performance. It seems that this is rather surprising
behavior from the user
point of view. The fallout on batteries and mathlib is rather limited,
only a few
`rfl` proofs seem to have (inadvertently or not) have relied on this.
The speedcenter reports no significant regressions on core or mathlib.
previously, the empty `MessageData` (`m!""`) was used to indicate “no
message”, and `throwTacticEx` would format the message differently then.
But the semantics of `MessageData.isEmpty` isn't entirely clear in the
presence of lazy message data (e.g. `.ofPPFormat`).
So to avoid wondering what `isEmpty` should do there, let's simply use
an optional argument to `throwTacticEx` and get rid of
`MessageData.isEmpty`.