lean4-htt/tests/lean/run/rflTacticErrors.lean
Joachim Breitner fc963ffceb
feat: apply_rfl tactic: handle Eq, HEq, better error messages (#3714)
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.
2024-09-20 08:25:10 +00:00

445 lines
9.8 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.

/-!
This file tests the `rfl` tactic:
* Extensibility
* Error messages
* Effect of `with_reducible`
-/
-- First, let's see what `rfl` does:
/--
error: 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.
⊢ false = true
-/
#guard_msgs in
example : false = true := by rfl
-- Now to `apply_rfl`.
-- A plain reflexive predicate
inductive P : αα → Prop where | refl : P a a
attribute [refl] P.refl
-- Plain error
/--
error: tactic 'apply_rfl' failed, The lhs
42
is not definitionally equal to rhs
23
⊢ P 42 23
-/
#guard_msgs in
example : P 42 23 := by apply_rfl
-- Revealing implicit arguments
opaque withImplicitNat {n : Nat} : Nat
/--
error: tactic 'apply_rfl' failed, The lhs
@withImplicitNat 42
is not definitionally equal to rhs
@withImplicitNat 23
⊢ P withImplicitNat withImplicitNat
-/
#guard_msgs in
example : P (@withImplicitNat 42) (@withImplicitNat 23) := by apply_rfl
-- Exhaustive testing of various combinations:
-- In addition to Eq, HEq and Iff we test four relations:
-- Defeq to relation `P` at reducible transparency
abbrev Q : αα → Prop := P
-- Defeq to relation `P` at default transparency
def Q' : αα → Prop := P
-- No refl attribute
inductive R : αα → Prop where | refl : R a a
/-
Now we systematically test all relations with
* syntactic equal arguments
* reducibly equal arguments
* semireducibly equal arguments
* nonequal arguments
and all using `apply_rfl` and `with_reducible apply_rfl`
-/
-- Syntactic equal
example : true = true := by apply_rfl
example : HEq true true := by apply_rfl
example : True ↔ True := by apply_rfl
example : P true true := by apply_rfl
example : Q true true := by apply_rfl
/--
error: rfl failed, no @[refl] lemma registered for relation
Q'
-/
#guard_msgs in example : Q' true true := by apply_rfl -- Error
/--
error: rfl failed, no @[refl] lemma registered for relation
R
-/
#guard_msgs in example : R true true := by apply_rfl -- Error
example : true = true := by with_reducible apply_rfl
example : HEq true true := by with_reducible apply_rfl
example : True ↔ True := by with_reducible apply_rfl
example : P true true := by with_reducible apply_rfl
example : Q true true := by with_reducible apply_rfl
/--
error: rfl failed, no @[refl] lemma registered for relation
Q'
-/
#guard_msgs in
example : Q' true true := by with_reducible apply_rfl -- Error
/--
error: rfl failed, no @[refl] lemma registered for relation
R
-/
#guard_msgs in
example : R true true := by with_reducible apply_rfl -- Error
-- Reducibly equal
abbrev true' := true
abbrev True' := True
example : true' = true := by apply_rfl
example : HEq true' true := by apply_rfl
example : True' ↔ True := by apply_rfl
example : P true' true := by apply_rfl
example : Q true' true := by apply_rfl
/--
error: rfl failed, no @[refl] lemma registered for relation
Q'
-/
#guard_msgs in
example : Q' true' true := by apply_rfl -- Error
/--
error: rfl failed, no @[refl] lemma registered for relation
R
-/
#guard_msgs in
example : R true' true := by apply_rfl -- Error
example : true' = true := by with_reducible apply_rfl
example : HEq true' true := by with_reducible apply_rfl
example : True' ↔ True := by with_reducible apply_rfl
example : P true' true := by with_reducible apply_rfl
example : Q true' true := by with_reducible apply_rfl -- NB: No error, Q and true' reducible
/--
error: rfl failed, no @[refl] lemma registered for relation
Q'
-/
#guard_msgs in
example : Q' true' true := by with_reducible apply_rfl -- Error
/--
error: rfl failed, no @[refl] lemma registered for relation
R
-/
#guard_msgs in
example : R true' true := by with_reducible apply_rfl -- Error
-- Equal at default transparency only
def true'' := true
def True'' := True
example : true'' = true := by apply_rfl
example : HEq true'' true := by apply_rfl
example : True'' ↔ True := by apply_rfl
example : P true'' true := by apply_rfl
example : Q true'' true := by apply_rfl
/--
error: rfl failed, no @[refl] lemma registered for relation
Q'
-/
#guard_msgs in
example : Q' true'' true := by apply_rfl -- Error
/--
error: rfl failed, no @[refl] lemma registered for relation
R
-/
#guard_msgs in
example : R true'' true := by apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
true''
is not definitionally equal to rhs
true
⊢ true'' = true
-/
#guard_msgs in
example : true'' = true := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply' failed, failed to unify
@HEq ?α ?a ?α ?a
with
@HEq Bool true'' Bool true
⊢ HEq true'' true
-/
#guard_msgs in
example : HEq true'' true := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
True''
is not definitionally equal to rhs
True
⊢ True'' ↔ True
-/
#guard_msgs in
example : True'' ↔ True := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
true''
is not definitionally equal to rhs
true
⊢ P true'' true
-/
#guard_msgs in
example : P true'' true := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
true''
is not definitionally equal to rhs
true
⊢ Q true'' true
-/
#guard_msgs in
example : Q true'' true := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
true''
is not definitionally equal to rhs
true
⊢ Q' true'' true
-/
#guard_msgs in
example : Q' true'' true := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
true''
is not definitionally equal to rhs
true
⊢ R true'' true
-/
#guard_msgs in
example : R true'' true := by with_reducible apply_rfl -- Error
-- Unequal
/--
error: tactic 'apply_rfl' failed, The lhs
false
is not definitionally equal to rhs
true
⊢ false = true
-/
#guard_msgs in
example : false = true := by apply_rfl -- Error
/--
error: tactic 'apply' failed, failed to unify
HEq ?a ?a
with
HEq false true
⊢ HEq false true
-/
#guard_msgs in
example : HEq false true := by apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
False
is not definitionally equal to rhs
True
⊢ False ↔ True
-/
#guard_msgs in
example : False ↔ True := by apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
false
is not definitionally equal to rhs
true
⊢ P false true
-/
#guard_msgs in
example : P false true := by apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
false
is not definitionally equal to rhs
true
⊢ Q false true
-/
#guard_msgs in
example : Q false true := by apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
false
is not definitionally equal to rhs
true
⊢ Q' false true
-/
#guard_msgs in
example : Q' false true := by apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
false
is not definitionally equal to rhs
true
⊢ R false true
-/
#guard_msgs in
example : R false true := by apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
false
is not definitionally equal to rhs
true
⊢ false = true
-/
#guard_msgs in
example : false = true := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply' failed, failed to unify
HEq ?a ?a
with
HEq false true
⊢ HEq false true
-/
#guard_msgs in
example : HEq false true := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
False
is not definitionally equal to rhs
True
⊢ False ↔ True
-/
#guard_msgs in
example : False ↔ True := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
false
is not definitionally equal to rhs
true
⊢ P false true
-/
#guard_msgs in
example : P false true := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
false
is not definitionally equal to rhs
true
⊢ Q false true
-/
#guard_msgs in
example : Q false true := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
false
is not definitionally equal to rhs
true
⊢ Q' false true
-/
#guard_msgs in
example : Q' false true := by with_reducible apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
false
is not definitionally equal to rhs
true
⊢ R false true
-/
#guard_msgs in
example : R false true := by with_reducible apply_rfl -- Error
-- Inheterogeneous unequal
/--
error: tactic 'apply' failed, failed to unify
HEq ?a ?a
with
HEq true 1
⊢ HEq true 1
-/
#guard_msgs in
example : HEq true 1 := by apply_rfl -- Error
/--
error: tactic 'apply' failed, failed to unify
HEq ?a ?a
with
HEq true 1
⊢ HEq true 1
-/
#guard_msgs in
example : HEq true 1 := by with_reducible apply_rfl -- Error
-- Rfl lemma with side condition:
-- Error message should show left-over goal
inductive S : Bool → Bool → Prop where | refl : a = true → S a a
attribute [refl] S.refl
/--
error: tactic 'apply_rfl' failed, The lhs
true
is not definitionally equal to rhs
false
⊢ S true false
-/
#guard_msgs in
example : S true false := by apply_rfl -- Error
/--
error: tactic 'apply_rfl' failed, The lhs
true
is not definitionally equal to rhs
false
⊢ S true false
-/
#guard_msgs in
example : S true false := by with_reducible apply_rfl -- Error
/--
error: unsolved goals
case a
⊢ true = true
-/
#guard_msgs in
example : S true true := by apply_rfl -- Error (left-over goal)
/--
error: unsolved goals
case a
⊢ true = true
-/
#guard_msgs in
example : S true true := by with_reducible apply_rfl -- Error (left-over goal)
/--
error: unsolved goals
case a
⊢ false = true
-/
#guard_msgs in
example : S false false := by apply_rfl -- Error (left-over goal)
/--
error: unsolved goals
case a
⊢ false = true
-/
#guard_msgs in
example : S false false := by with_reducible apply_rfl -- Error (left-over goal)