@@ -71,6 +71,7 @@ inductive LocalDecl where
7171 have type-incorrect values. This design decision allows metaprograms to not have to think about nondep `ldecl`s,
7272 so long as `LocalDecl` values are consumed through `LocalDecl.isLet` and `LocalDecl.value?` with `(allowNondep := false)`.
7373 **Rule:** never use `(generalizeNondepLet := false)` in `mkBinding`-family functions within a local context you do not own.
74+ See `LocalDecl.setNondep` for some additional discussion.
7475 - Where then do nondep ldecls come from? Common functions are `Meta.mapLetDecl`, `Meta.withLetDecl`, and `Meta.letTelescope`.
7576 The `have` term syntax makes use of a nondep ldecl as well.
7677
@@ -91,7 +92,11 @@ def LocalDecl.binderInfoEx : LocalDecl → BinderInfo
9192 | _ => BinderInfo.default
9293namespace LocalDecl
9394
94- /-- Returns true if this is an `ldecl`. If `allowNondep` is false (the default), then requires that `nondep` be false. -/
95+ /--
96+ Returns true if this is an `ldecl` with a visible value.
97+
98+ If `allowNondep` is true then includes `ldecl`s with `nondep := true`, whose values are normally hidden.
99+ -/
95100def isLet : LocalDecl → (allowNondep : Bool := false ) → Bool
96101 | cdecl .., _ => false
97102 | ldecl (nondep := false ) .., _ => true
@@ -143,17 +148,19 @@ def isImplementationDetail (d : LocalDecl) : Bool :=
143148 d.kind != .default
144149
145150/--
146- Returns the value of the `ldecl`,
147- but if the `ldecl` is nondependent and `allowNondep` is false, returns `none`.
151+ Returns the value of the `ldecl` if it has a visible value.
152+
153+ If `allowNondep` is true, then allows nondependent `ldecl`s, whose values are normally hidden.
148154-/
149155def value? : LocalDecl → (allowNondep : Bool := false ) → Option Expr
150156 | ldecl (nondep := false ) (value := v) .., _ => some v
151157 | ldecl (nondep := true ) (value := v) .., true => some v
152158 | _, _ => none
153159
154160/--
155- Returns the value of the `ldecl`,
156- but if the `ldecl` is nondependent and `allowNondep` is false, panics.
161+ Returns the value of the `ldecl` if it has a visible value.
162+
163+ If `allowNondep` is true, then allows nondependent `ldecl`s, whose values are normally hidden.
157164-/
158165def value : LocalDecl → (allowNondep : Bool := false ) → Expr
159166 | cdecl .., _ => panic! "let declaration expected"
@@ -175,17 +182,36 @@ def setValue : LocalDecl → Expr → LocalDecl
175182
176183/--
177184Sets the `nondep` flag of an `ldecl`, otherwise returns `cdecl`s unchanged.
178- It is the responsibility of the caller to ensure that transitions are correct.
185+
186+ This is a low-level function, and it is the responsibility of the caller to ensure that
187+ transitions of `nondep` are valid.
179188
180189Rules:
181- - Setting `nondep := true` is a way to convert the ldecl into a cdecl.
182- - Caution: be sure any relevant caches are cleared so that the value does not leak.
183- - Caution: be sure that metavariables from before and after the transition are not mixed,
190+ - If the declaration is not under the caller's control, then setting `nondep := false` must not be done.
191+ General nondependent `ldecl`s should be treated like `cdecl`s.
192+ See also the docstring for `LocalDecl.ldecl` about the `value` not necessarily being type correct.
193+ - Setting `nondep := true` is usually fine.
194+ - Caution: be sure any relevant caches are cleared so that the value associated to this `FVarId` does not leak.
195+ - Caution: be sure that metavariables dependent on this declaration created before and after the transition are not mixed,
184196 since unification does not check "`nondep`-compatibility" of local contexts when assigning metavariables.
185- - If the declaration is for a variable whose dependencies are not completely under the caller's control,
186- then setting `nondep := false` must not be done.
187- - Even if the caller does have complete control, setting `nondep := false` should not be done.
188- The cautions about caches and metavariables still apply.
197+
198+ For example, setting `nondep := false` is fine from within a telescope combinator, to update the local context
199+ right before calling `mkLetFVars`:
200+ ```lean
201+ let lctx ← getLCtx
202+ letTelescope e fun xs b => do
203+ let lctx' ← xs.foldlM (init := lctx) fun lctx' x => do
204+ let decl ← x.fvarId!.getDecl
205+ -- Clear the flag if it's not a prop.
206+ let decl' := decl.setNondep <| ← pure decl.isNondep <&&> Meta.isProp decl.type
207+ pure <| lctx'.addDecl decl'
208+ withLCtx' lctx' do
209+ mkLetFVars (usedLetOnly := false) (generalizeNondepLet := false) xs b
210+ ```
211+ 1. The declarations for `xs` are in the control of this metaprogram.
212+ 2. `mkLetFVars` does make use of `MetaM` caches.
213+ 3. Even if `e` has metavariables, these do not include `xs` in their contexts,
214+ so the change of the `nondep` flag does not cause any issues in the `abstractM` system used by `mkLetFVars`.
189215 -/
190216def setNondep : LocalDecl → Bool → LocalDecl
191217 | ldecl idx id n t v _ k, nd => ldecl idx id n t v nd k
0 commit comments