Skip to content

Commit 7f5ec78

Browse files
committed
Search brecOn under projections
1 parent b1434b1 commit 7f5ec78

File tree

2 files changed

+79
-18
lines changed

2 files changed

+79
-18
lines changed

src/Lean/Elab/PreDefinition/Structural/Eqns.lean

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,29 @@ public structure EqnInfo extends EqnInfoCore where
3030
fixedParamPerms : FixedParamPerms
3131
deriving Inhabited
3232

33+
/--
34+
Searches in the lhs of goal for a `.brecOn` application, possibly with extra arguments
35+
and under `PProd` projections. Returns the `.brecOn` application and the context
36+
`(fun x => (x).1.2.3 extraArgs = rhs)`.
37+
-/
38+
partial def findBRecOnLHS (goal : Expr) : MetaM (Expr × Expr) := do
39+
let some (_, lhs, rhs) := goal.eq? | throwError "goal not an equality{indentExpr goal}"
40+
go lhs fun brecOnApp x c =>
41+
return (brecOnApp, ← mkLambdaFVars #[x] (← mkEq c rhs))
42+
where
43+
go {α} (e : Expr) (k : Expr → Expr → Expr → MetaM α) : MetaM α := e.withApp fun f xs => do
44+
if let .proj t n e := f then
45+
return ← go e fun brecOnApp x c => k brecOnApp x (mkAppN (mkProj t n c) xs)
46+
if let .const name _ := f then
47+
if isBRecOnRecursor (← getEnv) name then
48+
let arity ← forallTelescope (← inferType f) fun xs _ => return xs.size
49+
if arity ≤ xs.size then
50+
let brecOnApp := mkAppN f xs[:arity]
51+
let extraArgs := xs[arity:]
52+
return ← withLocalDeclD `x (← inferType brecOnApp) fun x =>
53+
k brecOnApp x (mkAppN x extraArgs)
54+
throwError "could not find `.brecOn` application in{indentExpr e}"
55+
3356
private partial def mkProof (declName : Name) (type : Expr) : MetaM Expr := do
3457
withTraceNode `Elab.definition.structural.eqns (return m!"{exceptEmoji ·} proving:{indentExpr type}") do
3558
prependError m!"failed to generate equational theorem for `{.ofConstName declName}`" do
@@ -45,33 +68,25 @@ where
4568
let mvarId' ← mvarId.withContext do
4669
-- This should now be headed by `.brecOn`
4770
let goal ← mvarId.getType
48-
let some (α, lhs, rhs) := goal.eq? | throwError "goal not an equality\n{MessageData.ofGoal mvarId}"
49-
let brecOn := lhs.getAppFn
50-
unless brecOn.isConst do
51-
throwError "goal not headed by `.brecOn`\n{MessageData.ofGoal mvarId}"
52-
let brecOnName := brecOn.constName!
53-
unless isBRecOnRecursor (← getEnv) brecOnName do
54-
throwError "goal not headed by `.brecOn`\n{MessageData.ofGoal mvarId}"
71+
let (brecOnApp, context) ← findBRecOnLHS goal
72+
let brecOnName := brecOnApp.getAppFn.constName!
73+
let us := brecOnApp.getAppFn.constLevels!
5574
let brecOnThmName := brecOnName.str "eq"
75+
let brecOnAppArgs := brecOnApp.getAppArgs
5676
unless (← hasConst brecOnThmName) do
5777
throwError "no theorem `{brecOnThmName}`\n{MessageData.ofGoal mvarId}"
5878
-- We don't just `← inferType eqThmApp` as that beta-reduces more than we want
59-
let eqThmType ← inferType (mkConst brecOnThmName brecOn.constLevels!)
60-
let eqThmArity ← forallTelescope eqThmType fun xs _ => return xs.size
61-
let mut eqThmApp := mkAppN (mkConst brecOnThmName brecOn.constLevels!) lhs.getAppArgs[:eqThmArity]
62-
let eqThmType ← instantiateForall eqThmType eqThmApp.getAppArgs[:eqThmArity]
79+
let eqThmType ← inferType (mkConst brecOnThmName us)
80+
let eqThmType ← instantiateForall eqThmType brecOnAppArgs
6381
let some (_, _, rwRhs) := eqThmType.eq? | throwError "theorem `{brecOnThmName}` is not an equality\n{MessageData.ofGoal mvarId}"
6482
let recArg := rwRhs.getAppArgs.back!
6583
trace[Elab.definition.structural.eqns] "abstracting{inlineExpr recArg} from{indentExpr rwRhs}"
6684
let mvarId2 ← mvarId.define `r (← inferType recArg) recArg
6785
let (r, mvarId3) ← mvarId2.intro1P
68-
let mut rwRhs := mkApp rwRhs.appFn! (mkFVar r)
69-
for extraArg in lhs.getAppArgs[eqThmArity:] do
70-
rwRhs := mkApp rwRhs extraArg
71-
eqThmApp ← mkCongrFun eqThmApp extraArg
72-
let eqThmAppTrans := mkApp5 (mkConst ``Eq.trans goal.getAppFn.constLevels!) α lhs rwRhs rhs eqThmApp
73-
let [mvarId4] ← mvarId3.applyN eqThmAppTrans 1 |
74-
throwError "rewriting with{inlineExpr eqThmAppTrans} failed\n{MessageData.ofGoal mvarId}"
86+
let mvarId4 ← mvarId3.withContext do
87+
let goal' := mkApp rwRhs.appFn! (mkFVar r)
88+
let thm ← mkCongrArg context (mkAppN (mkConst brecOnThmName us) brecOnAppArgs)
89+
mvarId3.replaceTargetEq (mkApp context goal') thm
7590
pure mvarId4
7691
go mvarId'
7792

tests/lean/run/structuralEqns5.lean

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,49 @@ info: theorem Tree.size_aux.eq_def.{u_1} : ∀ {α : Type u_1} (x : List (Tree
2828
-/
2929
#guard_msgs in
3030
#print sig Tree.size_aux.eq_def
31+
32+
mutual
33+
def Tree.size1 : Tree α → Nat
34+
| .node _ tsf => 1 + size_aux2 (tsf true) + size_aux2 (tsf false)
35+
termination_by structural t => t
36+
def Tree.size2 : Tree α → Nat
37+
| .node _ tsf => 1 + size_aux1 (tsf true) + size_aux1 (tsf false)
38+
termination_by structural t => t
39+
def Tree.size_aux1 : List (Tree α) → Nat
40+
| [] => 0
41+
| t :: ts => size2 t + size_aux2 ts
42+
def Tree.size_aux2 : List (Tree α) → Nat
43+
| [] => 0
44+
| t :: ts => size1 t + size_aux1 ts
45+
end
46+
47+
/--
48+
info: theorem Tree.size1.eq_def.{u_1} : ∀ {α : Type u_1} (x : Tree α),
49+
x.size1 =
50+
match x with
51+
| Tree.node a tsf => 1 + Tree.size_aux2 (tsf true) + Tree.size_aux2 (tsf false)
52+
-/
53+
#guard_msgs in #print sig Tree.size1.eq_def
54+
/--
55+
info: theorem Tree.size2.eq_def.{u_1} : ∀ {α : Type u_1} (x : Tree α),
56+
x.size2 =
57+
match x with
58+
| Tree.node a tsf => 1 + Tree.size_aux1 (tsf true) + Tree.size_aux1 (tsf false)
59+
-/
60+
#guard_msgs in #print sig Tree.size2.eq_def
61+
/--
62+
info: theorem Tree.size_aux1.eq_def.{u_1} : ∀ {α : Type u_1} (x : List (Tree α)),
63+
Tree.size_aux1 x =
64+
match x with
65+
| [] => 0
66+
| t :: ts => t.size2 + Tree.size_aux2 ts
67+
-/
68+
#guard_msgs in #print sig Tree.size_aux1.eq_def
69+
/--
70+
info: theorem Tree.size_aux2.eq_def.{u_1} : ∀ {α : Type u_1} (x : List (Tree α)),
71+
Tree.size_aux2 x =
72+
match x with
73+
| [] => 0
74+
| t :: ts => t.size1 + Tree.size_aux1 ts
75+
-/
76+
#guard_msgs in #print sig Tree.size_aux2.eq_def

0 commit comments

Comments
 (0)