parent
5e25d9148a
commit
ad98df80fe
8 changed files with 51 additions and 6 deletions
|
|
@ -676,6 +676,9 @@ theorem Iff.symm (h : a ↔ b) : b ↔ a :=
|
|||
theorem Iff.comm : (a ↔ b) ↔ (b ↔ a) :=
|
||||
Iff.intro Iff.symm Iff.symm
|
||||
|
||||
theorem Iff.of_eq (h : a = b) : a ↔ b :=
|
||||
h ▸ Iff.refl _
|
||||
|
||||
theorem And.comm : a ∧ b ↔ b ∧ a := by
|
||||
constructor <;> intro ⟨h₁, h₂⟩ <;> exact ⟨h₂, h₁⟩
|
||||
|
||||
|
|
|
|||
|
|
@ -589,6 +589,13 @@ def mkLE (a b : Expr) : MetaM Expr := mkBinaryRel ``LE ``LE.le a b
|
|||
/-- Return `a < b`. This method assumes `a` and `b` have the same type. -/
|
||||
def mkLT (a b : Expr) : MetaM Expr := mkBinaryRel ``LT ``LT.lt a b
|
||||
|
||||
/-- Given `h : a = b`, return a proof for `a ↔ b`. -/
|
||||
def mkIffOfEq (h : Expr) : MetaM Expr := do
|
||||
if h.isAppOfArity ``propext 3 then
|
||||
return h.appArg!
|
||||
else
|
||||
mkAppM ``Iff.of_eq #[h]
|
||||
|
||||
builtin_initialize do
|
||||
registerTraceClass `Meta.appBuilder
|
||||
registerTraceClass `Meta.appBuilder.result (inherited := true)
|
||||
|
|
|
|||
|
|
@ -18,5 +18,6 @@ builtin_initialize registerTraceClass `Meta.Tactic.simp.discharge (inherited :=
|
|||
builtin_initialize registerTraceClass `Meta.Tactic.simp.rewrite (inherited := true)
|
||||
builtin_initialize registerTraceClass `Meta.Tactic.simp.unify (inherited := true)
|
||||
builtin_initialize registerTraceClass `Debug.Meta.Tactic.simp
|
||||
builtin_initialize registerTraceClass `Debug.Meta.Tactic.simp.congr (inherited := true)
|
||||
|
||||
end Lean
|
||||
|
|
|
|||
|
|
@ -488,7 +488,11 @@ where
|
|||
let val ← mkLambdaFVars zs r.expr
|
||||
unless (← isDefEq m val) do
|
||||
throwCongrHypothesisFailed
|
||||
unless (← isDefEq h (← mkLambdaFVars xs (← r.getProof))) do
|
||||
let mut proof ← r.getProof
|
||||
if hType.isAppOf ``Iff then
|
||||
try proof ← mkIffOfEq proof
|
||||
catch _ => throwCongrHypothesisFailed
|
||||
unless (← isDefEq h (← mkLambdaFVars xs proof)) do
|
||||
throwCongrHypothesisFailed
|
||||
/- We used to return `false` if `r.proof? = none` (i.e., an implicit `rfl` proof) because we
|
||||
assumed `dsimp` would also be able to simplify the term, but this is not true
|
||||
|
|
@ -515,6 +519,7 @@ where
|
|||
let (xs, bis, type) ← forallMetaTelescopeReducing (← inferType thm)
|
||||
if c.hypothesesPos.any (· ≥ xs.size) then
|
||||
return none
|
||||
let isIff := type.isAppOf ``Iff
|
||||
let lhs := type.appFn!.appArg!
|
||||
let rhs := type.appArg!
|
||||
let numArgs := lhs.getAppNumArgs
|
||||
|
|
@ -545,7 +550,10 @@ where
|
|||
trace[Meta.Tactic.simp.congr] "{c.theoremName} synthesizeArgs failed"
|
||||
return none
|
||||
let eNew ← instantiateMVars rhs
|
||||
let proof ← instantiateMVars (mkAppN thm xs)
|
||||
let mut proof ← instantiateMVars (mkAppN thm xs)
|
||||
if isIff then
|
||||
try proof ← mkAppM ``propext #[proof]
|
||||
catch _ => return none
|
||||
congrArgs { expr := eNew, proof? := proof } extraArgs
|
||||
else
|
||||
return none
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ builtin_initialize congrExtension : SimpleScopedEnvExtension SimpCongrTheorem Si
|
|||
def mkSimpCongrTheorem (declName : Name) (prio : Nat) : MetaM SimpCongrTheorem := withReducible do
|
||||
let c ← mkConstWithLevelParams declName
|
||||
let (xs, bis, type) ← forallMetaTelescopeReducing (← inferType c)
|
||||
match type.eq? with
|
||||
match type.eqOrIff? with
|
||||
| none => throwError "invalid 'congr' theorem, equality expected{indentExpr type}"
|
||||
| some (_, lhs, rhs) =>
|
||||
| some (lhs, rhs) =>
|
||||
lhs.withApp fun lhsFn lhsArgs => rhs.withApp fun rhsFn rhsArgs => do
|
||||
unless lhsFn.isConst && rhsFn.isConst && lhsFn.constName! == rhsFn.constName! && lhsArgs.size == rhsArgs.size do
|
||||
throwError "invalid 'congr' theorem, equality left/right-hand sides must be applications of the same function{indentExpr type}"
|
||||
|
|
@ -67,9 +67,9 @@ def mkSimpCongrTheorem (declName : Name) (prio : Nat) : MetaM SimpCongrTheorem :
|
|||
for x in xs, bi in bis do
|
||||
if bi.isExplicit && !foundMVars.contains x.mvarId! then
|
||||
let rhsFn? ← forallTelescopeReducing (← inferType x) fun ys xType => do
|
||||
match xType.eq? with
|
||||
match xType.eqOrIff? with
|
||||
| none => pure none -- skip
|
||||
| some (_, xLhs, xRhs) =>
|
||||
| some (xLhs, xRhs) =>
|
||||
let mut j := 0
|
||||
for y in ys do
|
||||
let yType ← inferType y
|
||||
|
|
|
|||
|
|
@ -46,6 +46,12 @@ namespace Expr
|
|||
@[inline] def iff? (p : Expr) : Option (Expr × Expr) :=
|
||||
p.app2? ``Iff
|
||||
|
||||
@[inline] def eqOrIff? (p : Expr) : Option (Expr × Expr) :=
|
||||
if let some (_, lhs, rhs) := p.app3? ``Eq then
|
||||
some (lhs, rhs)
|
||||
else
|
||||
p.iff?
|
||||
|
||||
@[inline] def not? (p : Expr) : Option Expr :=
|
||||
p.app1? ``Not
|
||||
|
||||
|
|
|
|||
16
tests/lean/1763.lean
Normal file
16
tests/lean/1763.lean
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
axiom P : Prop → Prop
|
||||
|
||||
@[congr]
|
||||
axiom P_congr (a b : Prop) (h : a ↔ b) : P a ↔ P b
|
||||
|
||||
theorem ex1 {p q : Prop} (h : p ↔ q) (h' : P q) : P p := by
|
||||
simp [h]
|
||||
assumption
|
||||
|
||||
#print ex1
|
||||
|
||||
theorem ex2 {p q : Prop} (h : p = q) (h' : P q) : P p := by
|
||||
simp [h]
|
||||
assumption
|
||||
|
||||
#print ex2
|
||||
4
tests/lean/1763.lean.expected.out
Normal file
4
tests/lean/1763.lean.expected.out
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
theorem ex1 : ∀ {p q : Prop}, (p ↔ q) → P q → P p :=
|
||||
fun {p q} h h' => Eq.mpr (id (propext (P_congr p q h))) h'
|
||||
theorem ex2 : ∀ {p q : Prop}, p = q → P q → P p :=
|
||||
fun {p q} h h' => Eq.mpr (id (propext (P_congr p q (Iff.of_eq h)))) h'
|
||||
Loading…
Add table
Reference in a new issue