@@ -110,16 +110,68 @@ builtin_dsimproc paramMatcher (_) := fun e => do
110110 let matcherApp' := { matcherApp with discrs := discrs', alts := alts' }
111111 return .continue <| matcherApp'.toExpr
112112
113- /-- `let x := (wfParam e); body[x] ==> let x := e; body[wfParam y]`
114- Also accepts non-Prop `have`s as well. -/
113+ private def anyLetValueIsWfParam (e : Expr) : Bool :=
114+ match e with
115+ | .letE _ _ v b _ => (isWfParam? v).isSome || anyLetValueIsWfParam b
116+ | _ => false
117+
118+ private def numLetsWithValueNotIsWfParam (e : Expr) (acc := 0 ) : Nat :=
119+ match e with
120+ | .letE _ _ v b _ => if (isWfParam? v).isSome then acc else numLetsWithValueNotIsWfParam b (acc + 1 )
121+ | _ => acc
122+
123+ private partial def processParamLet (e : Expr) : MetaM Expr := do
124+ if let .letE _ t v b _ := e then
125+ if let some v := isWfParam? v then
126+ if ← Meta.isProp t then
127+ processParamLet <| e.updateLetE! t v b
128+ else
129+ let u ← getLevel t
130+ let b' := b.instantiate1 <| mkApp2 (.const ``wfParam [u]) t (.bvar 0 )
131+ processParamLet <| e.updateLetE! t v b'
132+ else
133+ let num := numLetsWithValueNotIsWfParam e
134+ assert! num > 0
135+ letBoundedTelescope e num fun xs b => do
136+ let b' ← processParamLet b
137+ mkLetFVars (usedLetOnly := false ) (generalizeNondepLet := false ) xs b'
138+ else
139+ return e
140+
141+ /--
142+ `let x : T := (wfParam e); body[x] ==> let x : T := e; body[wfParam y]` if `T` is not a proposition,
143+ otherwise `... ==> let x : T := e; body[x]`. (Applies to `have`s too.)
144+
145+ Note: simprocs are provided the head of a let telescope, but not intermediate lets.
146+ -/
115147builtin_dsimproc paramLet (_) := fun e => do
116- let .letE _ t v b _ := e | return .continue
117- let some v := isWfParam? v | return .continue
118- if ← Meta.isProp t then return .continue <| e.updateLetE! t v b
119- let u ← getLevel t
120- let body' := b.instantiate1 <|
121- mkApp2 (.const ``wfParam [u]) t (.bvar 0 )
122- return .continue <| e.updateLetE! t v body'
148+ unless e.isLet || anyLetValueIsWfParam e do return .continue
149+ return .continue (← processParamLet e)
150+
151+ /--
152+ Transforms non-Prop `have`s to `let`s, so that the values can be used in GuessLex and decreasing-by proofs.
153+ These `have`s may have been introdued by `simp`, which converts `let`s to `have`s.
154+ -/
155+ private def nonPropHaveToLet (e : Expr) : MetaM Expr := do
156+ Meta.transform e (pre := fun e => do
157+ if (← Meta.isProof e) then
158+ return .done e
159+ else if e.isLet then
160+ -- Recall that `Meta.transform` processes entire let telescopes,
161+ -- so we need to handle the telescope all at once.
162+ let lctx ← getLCtx
163+ let e' ← letTelescope e fun xs b => do
164+ let lctx' ← xs.foldlM (init := lctx) fun lctx' x => do
165+ let decl ← x.fvarId!.getDecl
166+ -- Clear the flag if it's not a prop.
167+ let decl' := decl.setNondep <| ← pure decl.isNondep <&&> Meta.isProp decl.type
168+ pure <| lctx'.addDecl decl'
169+ withLCtx' lctx' do
170+ mkLetFVars (usedLetOnly := false ) (generalizeNondepLet := false ) xs b
171+ return .continue e'
172+ else
173+ return .continue
174+ )
123175
124176def preprocess (e : Expr) : MetaM Simp.Result := do
125177 unless wf.preprocess.get (← getOptions) do
@@ -143,9 +195,13 @@ def preprocess (e : Expr) : MetaM Simp.Result := do
143195 if h : as.size ≥ 2 then
144196 return .continue (mkAppN as[1 ] as[2 :])
145197 return .continue
198+
199+ -- Transform `have`s to `let`s for non-propositions.
200+ let e'' ← nonPropHaveToLet e''
201+
146202 let result := { result with expr := e'' }
147203
148- trace[Elab.definition.wf] "Attach-introduction:{indentExpr e'}\n to{indentExpr result.expr}\n cleaned up as{indentExpr e''} "
204+ trace[Elab.definition.wf] "Attach-introduction:{indentExpr e'}\n to{indentExpr result.expr}"
149205 result.addLambdas xs
150206
151207end Lean.Elab.WF
0 commit comments