@@ -122,6 +122,39 @@ 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 newest pure hypothesis in the local context,
126+ which is typically the precondition lifted just before the current spec rule was applied.
127+ This is one defeq check against one hypothesis, not an assumption search.
128+
129+ Goals whose RHS contains metavariables are skipped: the defeq check could otherwise assign
130+ a post abstraction from an unrelated hypothesis. -/
131+ private def tryLiftedHyp (goal : MVarId) (α pre rhs : Expr) : VCGenM (Option (List MVarId)) :=
132+ goal.withContext do
133+ if rhs.hasExprMVar then return none
134+ let some hyp ← (← getLCtx).findDeclRevM? (fun decl => do
135+ if decl.isImplementationDetail then return none
136+ else if ← Meta.isProp decl.type then return some decl
137+ else return none)
138+ | return none
139+ let proof? ← match_expr rhs with
140+ | CompleteLattice.ofProp _l _inst φ => do
141+ if ← isDefEqS φ hyp.type then
142+ pure (some (← mkAppM ``Lean.Order.le_ofProp #[pre, φ, hyp.toExpr]))
143+ else
144+ pure none
145+ | _ => do
146+ if α.isProp then
147+ if ← isDefEqS rhs hyp.type then
148+ pure (some (← mkAppM ``Lean.Order.le_prop #[pre, rhs, hyp.toExpr]))
149+ else
150+ pure none
151+ else
152+ pure none
153+ let some proof := proof? | return none
154+ trace[Elab.Tactic.Do.vcgen] "Solved by lifted hypothesis { hyp.userName} "
155+ goal.assign proof
156+ return some []
157+
125158/--
126159Lift a non-trivial embedded pure precondition `⌜φ⌝` into the local context, leaving `⊤`
127160as the residual precondition. Used before a decomposition step that would duplicate the
@@ -281,20 +314,23 @@ The function performs the following steps in order:
2813142. **Target-let handling** : zeta-substitute duplicable top-level lets, otherwise introduce them.
2823153. **Triple unfolding** : If the target is `⦃P⦄ x ⦃Q; E⦄`, unfold into `P ⊑ wp x Q E`.
2833164. **Syntactic rfl** : close `pre ⊑ rhs` by `PartialOrder.rel_refl` when both sides unify.
284- 5. **State-argument introduction** : If the lattice carrier is a function type
317+ 5. **Lifted-hypothesis discharge** : close `pre ⊑ rhs` with the newest pure hypothesis,
318+ typically the precondition lifted before the previous spec application.
319+ 6. **State-argument introduction** : If the lattice carrier is a function type
285320 `σ₁ → ... → σₙ → Base`, introduce all excess state arguments.
286- 6 . **EPost projection reduction** : reduce an `EPost.Cons.head` RHS to the projected component.
287- 7 . **Lattice decomposition** : decompose `⊓`, `⇨`, `⌜p⌝` and `⊤` RHS connectives.
288- 8 . **WP decomposition** : when the RHS is `wp e post epost s₁ ... sₙ`, in order:
321+ 7 . **EPost projection reduction** : reduce an `EPost.Cons.head` RHS to the projected component.
322+ 8 . **Lattice decomposition** : decompose `⊓`, `⇨`, `⌜p⌝` and `⊤` RHS connectives.
323+ 9 . **WP decomposition** : when the RHS is `wp e post epost s₁ ... sₙ`, in order:
289324 hoist/zeta program-head lets, split `ite`/`dite`/match, zeta-unfold fvar program heads,
290325 reduce projection heads, and finally apply a registered `@[spec]` theorem.
291- 9. **Pure precondition introduction** (last resort): introduce a bare pure precondition (on
292- the `Prop` lattice) so the residual VC has the form `⊤ ⊑ φ`.
293-
294- Pure preconditions are deliberately introduced *late* (step 9, and inside steps 7/8
295- right before a `⊓` or match split duplicates them): introducing them eagerly would turn
296- reflexivity-closable verification conditions such as `Q x ⊑ wp (pure x) Q E` into goals that
297- need an assumption search.
326+ 10. **Pure precondition introduction** (last resort): introduce a bare pure precondition (on
327+ the `Prop` lattice) so the residual VC has the form `⊤ ⊑ φ`.
328+
329+ Pure preconditions are deliberately introduced *late* (step 10, and inside steps 8/9 right
330+ before a `⊓` or match split duplicates them, or before a spec rule with a post or epost VC
331+ loses them): introducing them eagerly would turn reflexivity-closable verification conditions
332+ such as `Q x ⊑ wp (pure x) Q E` into goals that need an assumption search. The lifted fact is
333+ handed back to the handoff VCs by step 5.
298334-/
299335public def solve (scope : VCGen.Scope) (goal : MVarId) : VCGenM SolveResult := goal.withContext do
300336 if ← outOfFuel then return .stop
@@ -318,6 +354,7 @@ public def solve (scope : VCGen.Scope) (goal : MVarId) : VCGenM SolveResult := g
318354 let preIsTop := pre.isAppOf ``Lean.Order.top && pre.getAppNumArgs == 2
319355
320356 if let some gs ← tryRfl goal target pre rhs then return .goals scope gs
357+ if let some gs ← tryLiftedHyp goal α pre rhs then return .goals scope gs
321358
322359 -- Phase 2: introduce excess state arguments and reduce EPost projections, so that the RHS
323360 -- exposes either a lattice connective or a `wp` application.
0 commit comments