Skip to content

Commit e3eb965

Browse files
committed
chore: various fixes
1 parent 79370a9 commit e3eb965

9 files changed

Lines changed: 446 additions & 421 deletions

File tree

src/Lean/Elab/Tactic/Do/Internal/VCGen/Context.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ public structure VCGen.IntroRules where
8888
/-- The backward rule for `Lean.Order.ofProp_le`. Introduces an embedded pure
8989
precondition `⌜p⌝` on any complete lattice. -/
9090
ofPropPreIntro : BackwardRule
91+
/-- The backward rule for `Lean.Order.true_le`. Replaces a `True` precondition
92+
with `⊤` on the `Prop` lattice. -/
93+
truePreIntro : BackwardRule
9194

9295
public structure VCGen.Context where
9396
/-- Pre-built backward rules for the introduction steps of `solve`. -/

src/Lean/Elab/Tactic/Do/Internal/VCGen/Frontend.lean

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,13 @@ public def mkContext (lemmas : Syntax) (goal : MVarId) (ignoreStarArg := false)
116116
let topStateArgIntro ← mkBackwardRuleFromDecl ``Lean.Order.top_le_of_forall_top_le
117117
let propPreIntro ← mkBackwardRuleFromDecl ``Lean.Order.prop_le
118118
let ofPropPreIntro ← mkBackwardRuleFromDecl ``Lean.Order.ofProp_le
119+
let truePreIntro ← mkBackwardRuleFromDecl ``Lean.Order.true_le
119120
let elimPreRule ← mkBackwardRuleFromDecl ``Lean.Order.top_le_prop
120121
let andIntroRule ← mkBackwardRuleFromDecl ``And.intro
121122
let specThmsNew ← SymM.run <| migrateSpecTheoremsDatabase specThms simpThms
122123
let ctx : VCGen.Context := {
123-
introRules := { tripleIntro, stateArgIntro, topStateArgIntro, propPreIntro, ofPropPreIntro },
124+
introRules := { tripleIntro, stateArgIntro, topStateArgIntro, propPreIntro, ofPropPreIntro,
125+
truePreIntro },
124126
elimPreRule,
125127
andIntroRule,
126128
}

src/Lean/Elab/Tactic/Do/Internal/VCGen/Solve.lean

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -122,46 +122,48 @@ private def tryRfl (goal : MVarId) (target pre rhs : Expr) : VCGenM (Option (Lis
122122
goal.assign (mkApp3 refl relArgs[0]! relArgs[1]! pre)
123123
return some []
124124

125-
/-- Strategy 5: close `pre ⊑ rhs` against the most recently lifted pure precondition,
126-
cached in `Scope.lastLiftedPre?`. This is one defeq check against one hypothesis, not an
127-
assumption search.
125+
/-- Strategy 10: close `pre ⊑ φ` on the `Prop` lattice against the most recently lifted pure
126+
precondition, cached in `Scope.lastLiftedPre?`. Runs after lattice decomposition, so `φ` is an
127+
opaque proposition rather than a lattice connective. This is one defeq check against one
128+
hypothesis, not an assumption search.
128129
129130
Goals whose RHS contains metavariables are skipped: the defeq check could otherwise assign
130131
a post abstraction from an unrelated hypothesis. -/
131132
private def tryLiftedHyp (scope : VCGen.Scope) (goal : MVarId) (α pre rhs : Expr) :
132133
VCGenM (Option (List MVarId)) :=
133134
goal.withContext do
135+
unless α.isProp do return none
134136
if rhs.hasExprMVar then return none
135137
let some fvarId := scope.lastLiftedPre? | return none
136138
let some hyp := (← getLCtx).find? fvarId | return none
137-
let proof? ← match_expr rhs with
138-
| CompleteLattice.ofProp _l _inst φ => do
139-
if ← isDefEqS φ hyp.type then
140-
pure (some (← mkAppM ``Lean.Order.le_ofProp #[pre, φ, hyp.toExpr]))
141-
else
142-
pure none
143-
| _ => do
144-
if α.isProp then
145-
if ← isDefEqS rhs hyp.type then
146-
pure (some (← mkAppM ``Lean.Order.le_prop #[pre, rhs, hyp.toExpr]))
147-
else
148-
pure none
149-
else
150-
pure none
151-
let some proof := proof? | return none
139+
unless ← isDefEqS rhs hyp.type do return none
152140
trace[Elab.Tactic.Do.vcgen] "Solved by lifted hypothesis {hyp.userName}"
153-
goal.assign proof
141+
goal.assign (← mkAppM ``Lean.Order.le_prop #[pre, rhs, hyp.toExpr])
154142
return some []
155143

156-
/-- Strategy 6: lift an embedded pure precondition `⌜φ⌝` into the local context, leaving `⊤`
144+
/-- Close a bare `Prop` residual, such as the subgoal of the `⌜φ⌝` lattice rule, against the
145+
most recently lifted pure precondition. Runs when the target is not a lattice entailment,
146+
just before it would be classified as a VC. -/
147+
private def tryLiftedHypBare (scope : VCGen.Scope) (goal : MVarId) (target : Expr) :
148+
VCGenM (Option (List MVarId)) :=
149+
goal.withContext do
150+
if target.hasExprMVar then return none
151+
let some fvarId := scope.lastLiftedPre? | return none
152+
let some hyp := (← getLCtx).find? fvarId | return none
153+
unless ← isDefEqS target hyp.type do return none
154+
trace[Elab.Tactic.Do.vcgen] "Solved by lifted hypothesis {hyp.userName}"
155+
goal.assign hyp.toExpr
156+
return some []
157+
158+
/-- Strategy 5: lift an embedded pure precondition `⌜φ⌝` into the local context, leaving `⊤`
157159
as the residual precondition. Runs before state-argument introduction, which would otherwise
158160
leave `⌜φ⌝` applied to the introduced arguments. Returns the new goal and the hypothesis. -/
159161
private def tryOfPropPreIntro (goal : MVarId) (pre : Expr) : VCGenM (Option (MVarId × FVarId)) := do
160162
let_expr CompleteLattice.ofProp _l _inst φ := pre | return none
161163
if φ.isTrue then return none
162164
return some (← introPre (ofProp := true) goal)
163165

164-
/-- Strategy 8: decompose a supported lattice connective on the RHS. -/
166+
/-- Strategy 9: decompose a supported lattice connective on the RHS. -/
165167
private def tryLattice (goal : MVarId) (target rhs : Expr) (preIsTop : Bool) :
166168
VCGenM (Option (List MVarId)) := do
167169
solveLatticeConnective? goal target rhs preIsTop
@@ -197,13 +199,13 @@ private def substOrHoistLet (goal : MVarId) (target : Expr) (info : WPInfo)
197199
| throwError "Failed to intro hoisted let"
198200
return goal
199201

200-
/-- Strategy 7a: hoist or zeta-substitute a `let` from the program head. -/
202+
/-- Strategy 11a: hoist or zeta-substitute a `let` from the program head. -/
201203
private def tryWPLet (goal : MVarId) (target : Expr) (info : WPInfo) : VCGenM (Option MVarId) := do
202204
let .letE name type val body nondep := info.prog.getAppFn | return none
203205
return some (← substOrHoistLet goal target info name type val body nondep
204206
info.prog.getAppRevArgs)
205207

206-
/-- Strategy 7b: split an `ite`/`dite`/match program, or iota-reduce a matcher with a concrete
208+
/-- Strategy 11b: split an `ite`/`dite`/match program, or iota-reduce a matcher with a concrete
207209
discriminant. -/
208210
private def tryWPMatch (goal : MVarId) (target : Expr) (info : WPInfo) :
209211
VCGenM (Option (List MVarId)) := do
@@ -222,7 +224,7 @@ private def tryWPMatch (goal : MVarId) (target : Expr) (info : WPInfo) :
222224
| .closed => continue
223225
return some simpGoals.toList
224226

225-
/-- Strategy 7c: zeta-unfold a local let-bound fvar used as the program head. -/
227+
/-- Strategy 11c: zeta-unfold a local let-bound fvar used as the program head. -/
226228
private def tryWPFVarZeta (goal : MVarId) (target : Expr) (info : WPInfo) :
227229
VCGenM (Option MVarId) := do
228230
let f := info.prog.getAppFn
@@ -232,7 +234,7 @@ private def tryWPFVarZeta (goal : MVarId) (target : Expr) (info : WPInfo) :
232234
let prog ← shareCommonInc (val.betaRev info.prog.getAppRevArgs)
233235
return some (← replaceProgDefEq goal target info prog)
234236

235-
/-- Strategy 7d: reduce a projection head in the program. -/
237+
/-- Strategy 11d: reduce a projection head in the program. -/
236238
private def tryWPHeadReduce (goal : MVarId) (target : Expr) (info : WPInfo) :
237239
VCGenM (Option MVarId) := do
238240
let f := info.prog.getAppFn
@@ -242,7 +244,7 @@ private def tryWPHeadReduce (goal : MVarId) (target : Expr) (info : WPInfo) :
242244
let prog ← betaRevS f' info.prog.getAppRevArgs
243245
return some (← replaceProgDefEq goal target info prog)
244246

245-
/-- Strategy 7e: look up a registered `@[spec]` theorem (triple or simp) for the program head
247+
/-- Strategy 11e: look up a registered `@[spec]` theorem (triple or simp) for the program head
246248
and apply its cached backward rule. -/
247249
private def applySpec (scope : VCGen.Scope) (goal : MVarId) (target : Expr) (info : WPInfo) :
248250
VCGenM SolveResult := do
@@ -293,23 +295,24 @@ The function performs the following steps in order:
293295
2. **Target-let handling**: zeta-substitute duplicable top-level lets, otherwise introduce them.
294296
3. **Triple unfolding**: If the target is `⦃P⦄ x ⦃Q; E⦄`, unfold into `P ⊑ wp x Q E`.
295297
4. **Syntactic rfl**: close `pre ⊑ rhs` by `PartialOrder.rel_refl` when both sides unify.
296-
5. **Lifted-hypothesis discharge**: close `pre ⊑ rhs` against the most recently lifted
297-
precondition, cached in `Scope.lastLiftedPre?`.
298-
6. **Embedded pure precondition introduction**: lift a `⌜φ⌝` precondition into the local
298+
5. **Embedded pure precondition introduction**: lift a `⌜φ⌝` precondition into the local
299299
context, before state-argument introduction would apply it to the introduced arguments.
300-
7. **State-argument introduction**: If the lattice carrier is a function type
300+
6. **State-argument introduction**: If the lattice carrier is a function type
301301
`σ₁ → ... → σₙ → Base`, introduce all excess state arguments.
302-
8. **Bare pure precondition introduction**: on the `Prop` lattice, lift a non-`⊤`
303-
precondition into the local context.
304-
9. **EPost projection reduction**: reduce an `EPost.Cons.head` RHS to the projected component.
305-
10. **Lattice decomposition**: decompose `⊓`, `⇨`, `⌜p⌝` and `⊤` RHS connectives.
302+
7. **Bare pure precondition introduction**: on the `Prop` lattice, replace a `True`
303+
precondition by `⊤` and lift any other precondition into the local context.
304+
8. **EPost projection reduction**: reduce an `EPost.Cons.head` RHS to the projected component.
305+
9. **Lattice decomposition**: decompose `⊓`, `⇨`, `⌜p⌝` and `⊤` RHS connectives.
306+
10. **Lifted-hypothesis discharge**: close a residual `pre ⊑ φ` entailment against the most
307+
recently lifted precondition, cached in `Scope.lastLiftedPre?`.
306308
11. **WP decomposition**: when the RHS is `wp e post epost s₁ ... sₙ`, in order:
307309
hoist/zeta program-head lets, split `ite`/`dite`/match, zeta-unfold fvar program heads,
308310
reduce projection heads, and finally apply a registered `@[spec]` theorem.
309311
310-
Pure preconditions are lifted as soon as they arise (steps 6 and 8). The lifted hypothesis is
311-
cached in `Scope.lastLiftedPre?`, and step 5 closes the handoff VCs of subsequent spec
312-
applications against it with a single defeq check.
312+
Pure preconditions are lifted as soon as they arise (steps 5 and 7). The lifted hypothesis is
313+
cached in `Scope.lastLiftedPre?`. Step 10 closes residual entailments against it with a single
314+
defeq check, and bare `Prop` targets, such as the subgoal of the `⌜φ⌝` lattice rule, are
315+
checked against it before being classified as VCs.
313316
-/
314317
public def solve (scope : VCGen.Scope) (goal : MVarId) : VCGenM SolveResult := goal.withContext do
315318
if ← outOfFuel then return .stop
@@ -329,11 +332,12 @@ public def solve (scope : VCGen.Scope) (goal : MVarId) : VCGenM SolveResult := g
329332
if let some g ← tryTripleUnfold goal target then return .goals scope [g]
330333
if let some g ← tryBareWP goal target then return .goals scope [g]
331334

332-
let_expr PartialOrder.rel α inst pre rhs := target | return .noEntailment target
335+
let some (α, inst, pre, rhs) := target.app4? ``PartialOrder.rel
336+
| if let some gs ← tryLiftedHypBare scope goal target then return .goals scope gs
337+
else return .noEntailment target
333338
let preIsTop := pre.isAppOf ``Lean.Order.top && pre.getAppNumArgs == 2
334339

335340
if let some gs ← tryRfl goal target pre rhs then return .goals scope gs
336-
if let some gs ← tryLiftedHyp scope goal α pre rhs then return .goals scope gs
337341

338342
-- Phase 2: lift pure preconditions as they arise, introduce excess state arguments, and
339343
-- reduce EPost projections, so that the RHS exposes a lattice connective or a `wp`
@@ -342,6 +346,10 @@ public def solve (scope : VCGen.Scope) (goal : MVarId) : VCGenM SolveResult := g
342346
return .goals { scope with lastLiftedPre? := some h } [g]
343347
if α.isForall then return .goals scope [← introStateArgs preIsTop goal]
344348
if !preIsTop && α.isProp then
349+
if pre.isTrue then
350+
let .goals [g] ← (← read).introRules.truePreIntro.applyChecked goal
351+
| throwError "Failed to apply {.ofConstName ``Lean.Order.true_le} to{indentExpr target}"
352+
return .goals scope [g]
345353
let (g, h) ← introPre (ofProp := false) goal
346354
return .goals { scope with lastLiftedPre? := some h } [g]
347355
if let some g ← reduceEPostHead? goal target α inst pre rhs then return .goals scope [g]
@@ -350,8 +358,10 @@ public def solve (scope : VCGen.Scope) (goal : MVarId) : VCGenM SolveResult := g
350358
-- (`tryWPMatch`, `tryLattice`) or apply a registered spec (`applySpec`).
351359
let scope ← scope.collectLocalSpecs goal
352360

353-
-- Phase 3: lattice connective decomposition.
361+
-- Phase 3: lattice connective decomposition, then lifted-hypothesis discharge of the
362+
-- residual entailments.
354363
if let some gs ← tryLattice goal target rhs preIsTop then return .goals scope gs
364+
if let some gs ← tryLiftedHyp scope goal α pre rhs then return .goals scope gs
355365

356366
-- Phase 4: wp decomposition. The program-shape steps below all consume one unit of fuel
357367
-- (the `stepLimit` config option) when they make progress.

src/Std/Internal/Do/Order/Basic.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,9 @@ theorem le_prop (x y : Prop) : y → x ⊑ y :=
273273
theorem of_top_le_prop {x : Prop} : (⊤ : Prop) ⊑ x → x :=
274274
fun h => h (le_top True trivial)
275275

276+
theorem true_le (x : Prop) : ((⊤ : Prop) ⊑ x) → (True : Prop) ⊑ x :=
277+
fun h => le_prop True x (of_top_le_prop h)
278+
276279
@[simp] theorem iInf_prop_eq_forall {ι : Type u} (f : ι → Prop) :
277280
(iInf f : Prop) = (∀ i, f i) := by
278281
apply propext

0 commit comments

Comments
 (0)