lean4-htt/tests/lean/run/noConfusionCtorInjection.lean
Joachim Breitner edf804c70f
feat: heterogeneous noConfusion (#11474)
This PR generalizes the `noConfusion` constructions to heterogeneous
equalities (assuming propositional equalities between the indices). This
lays ground work for better support for applying injection to
heterogeneous equalities in grind.

The `Meta.mkNoConfusion` app builder shields most of the code from these
changes.

Since the per-constructor noConfusion principles are now more
expressive, `Meta.mkNoConfusion` no longer uses the general one.

In `Init.Prelude` some proofs are more pedestrian because `injection`
now needs a bit more machinery.

This is a breaking change for whoever uses the `noConfusion` principle
manually and explicitly for a type with indices.

Fixes #11450.
2025-12-02 15:19:47 +00:00

75 lines
2.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.

inductive L (α : Type u) : Type u where
| nil : L α
| cons (x : α) (xs : L α) : L α
-- Check that L.cons.inj uses the per-ctor noConfusion principle
/--
info: theorem L.cons.inj.{u} : ∀ {α : Type u} {x : α} {xs : L α} {x_1 : α} {xs_1 : L α},
L.cons x xs = L.cons x_1 xs_1 → x = x_1 ∧ xs = xs_1 :=
fun {α} {x} {xs} {x_1} {xs_1} x_2 => L.cons.noConfusion x_2 fun x_eq xs_eq => ⟨x_eq, xs_eq⟩
-/
#guard_msgs in
#print L.cons.inj
-- Check that injection uses the per-ctor noConfusion principle
theorem ex1 (h : L.cons x xs = L.cons y ys) : x = y ∧ xs = ys := by
injection h
repeat constructor <;> assumption
/--
info: theorem ex1.{u_1} : ∀ {α : Type u_1} {x : α} {xs : L α} {y : α} {ys : L α},
L.cons x xs = L.cons y ys → x = y ∧ xs = ys :=
fun {α} {x} {xs} {y} {ys} h => L.cons.noConfusion h fun x_eq xs_eq => ⟨x_eq, xs_eq⟩
-/
#guard_msgs in #print ex1
-- Check that injection does not intro more than it should
theorem ex2 (h : L.cons x xs = L.cons y ys) : Unit → x = y ∧ xs = ys := by
injection h
intro u
repeat constructor <;> assumption
-- Check that grind uses `L.cons.noConfusion`
theorem ex3 (h : L.cons x xs = L.cons y ys) : x = y ∧ xs = ys := by
grind
/--
info: theorem ex3._proof_1_1.{u_1} : ∀ {α : Type u_1} {x : α} {xs : L α} {y : α} {ys : L α},
L.cons x xs = L.cons y ys → x = y ∧ xs = ys :=
fun {α} {x} {xs} {y} {ys} h =>
Classical.byContradiction
(Lean.Grind.intro_with_eq (¬(x = y ∧ xs = ys)) (¬x = y ¬xs = ys) False (Lean.Grind.not_and (x = y) (xs = ys))
fun h_1 =>
id
(Eq.mp
(Eq.trans (Eq.symm (eq_true (L.cons.inj (id h)).1))
(Lean.Grind.eq_false_of_not_eq_true
(Eq.trans
(Eq.symm
(Lean.Grind.or_eq_of_eq_false_right (Lean.Grind.not_eq_of_eq_true (eq_true (L.cons.inj (id h)).2))))
(eq_true h_1))))
True.intro))
-/
#guard_msgs in #print ex3._proof_1_1
-- Check that for numary constructors, we get a trivial inlined “no confusion” principle
inductive AlmostEnum where | a | b | mk (b : Bool)
-- No explicit noConfusion principle for `AlmostEnum.a`:
/-- error: Unknown constant `AlmostEnum.a.noConfusion` -/
#guard_msgs in #print sig AlmostEnum.a.noConfusion
set_option linter.unusedVariables false in
theorem ex4 (h : AlmostEnum.a = AlmostEnum.a) : True := by
injection h
trivial
/--
info: theorem ex4 : AlmostEnum.a = AlmostEnum.a → True :=
fun h => (fun P => P) True.intro
-/
#guard_msgs in #print ex4