fix: free variable in do bind when continuation type depends on bvar (#13396)

This PR fixes #12768, where the new `do` elaborator produced a
"declaration has free variables" kernel error when the bind
continuation's result type was definitionally but not syntactically
independent of the bound variable. The fix moves creation of the result
type metavariable before `withLocalDecl`, so the unifier must reduce
away the dependency.

For example, given `def Quoted (x : Nat) := Nat`, the expression `do let
val ← pure 3; withStuff val do return 3` would fail because `β` was
assigned `Quoted val` rather than `Nat`.
This commit is contained in:
Sebastian Graf 2026-04-13 20:51:45 +02:00 committed by GitHub
parent 4dced0287e
commit cbda692e7e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 18 additions and 5 deletions

View file

@ -384,6 +384,7 @@ def DoElemCont.mkBindUnlessPure (dec : DoElemCont) (e : Expr) : DoElabM Expr :=
let k := dec.k
-- The .ofBinderName below is mainly to interpret `__do_lift` binders as implementation details.
let declKind := .ofBinderName x
let kResultTy ← mkFreshResultType `kResultTy
withLocalDecl x .default eResultTy (kind := declKind) fun xFVar => do
let body ← k
let body' := body.consumeMData
@ -411,7 +412,6 @@ def DoElemCont.mkBindUnlessPure (dec : DoElemCont) (e : Expr) : DoElabM Expr :=
-- else -- would be too aggressive
-- return ← mapLetDecl (nondep := true) (kind := declKind) x eResultTy eRes fun _ => k ref
let kResultTy ← mkFreshResultType `kResultTy
let body ← Term.ensureHasType (← mkMonadicType kResultTy) body
let k ← mkLambdaFVars #[xFVar] body
mkBindApp eResultTy kResultTy e k

View file

@ -101,7 +101,7 @@ would also work here.
error: Application type mismatch: The argument
isDigitEven? n
has type
?m.2 Bool
?m.3 Bool
but is expected to have type
Prop
in the application

View file

@ -0,0 +1,13 @@
module
set_option backward.do.legacy false
set_option linter.unusedVariables.funArgs false in
def Quoted (x : Nat) := Nat
def withStuff (x : Nat) (f : IO (Quoted x)) : IO (Quoted x) := f
def myFunc : IO Nat := do
let val : Nat ← pure 3
withStuff val do
return (3 : Nat)

View file

@ -108,7 +108,7 @@ Hint: Adding type annotations and supplying implicit arguments to functions can
example := do return 42
/--
error: typeclass instance problem is stuck
Bind ?m.23
Bind ?m.22
Note: Lean will not try to resolve this typeclass instance problem because the type argument to `Bind` is a metavariable. This argument must be fully determined before Lean will try to resolve the typeclass.
@ -211,8 +211,8 @@ trace: [Elab.do] let x := 42;
else
let x := x + i;
pure (ForInStep.yield (none, x))
let __r : Option ?m.182 := __s.fst
let x : ?m.182 := __s.snd
let __r : Option ?m.185 := __s.fst
let x : ?m.185 := __s.snd
match __r with
| some r => pure r
| none =>