Zulip Chat Archive
Stream: lean4
Topic: Error: unknown free variable and Qq
Arend Mellendijk (Apr 01 2025 at 15:57):
I ran into the following error message yesterday while writing meta code with Qq: unknown free variable '_fvar.541'
. I spent far too much time scratching my head trying to see what I did wrong. I've minimised the issue down to this
import Qq
set_option autoImplicit false
open Lean Qq
inductive ExSum : Type
| add {v : Level} (A : Q(Type v)) {a : Q($A)} : ExSum
def f {v : Level} (A : Q(Type v)) (a : Q($A)) : Unit × (Q($a = $a)) := sorry
example {v : Level} {A : Q(Type v)} {a : Q($A)} :
ExSum → Unit
| .add A =>
let ⟨_, _⟩ := f A a
()
The problem here is that the a
in the let statement belongs to the A
that has been shadowed by the match statement. What I had intended to write was .add A (a := a)
, but the error message made this mistake difficult to debug.
I haven't been able to minimise any further. Removing the universe levels removes the error message completely, and removing Qq gives the expected type error.
Is this a known bug?
Vasilii Nesterov (Apr 02 2025 at 13:31):
The real problem is that v
in the example's type and v
in the type of A
in the matching branch are not the same. This works for example:
example : ExSum → Unit
| @ExSum.add _ A a =>
let ⟨_, _⟩ := f A a
()
Jovan Gerbscheid (Apr 02 2025 at 14:59):
If you want Lean to automatically figure out that the v
in ExSum.add
is the same v
then you should make v
and A
an argument of the type ExSum
:
import Qq
set_option autoImplicit false
open Lean Qq
inductive ExSum (v : Level) (A : Q(Type v)) : Type
| add (a : Q($A)) : ExSum v A
def f {v : Level} (A : Q(Type v)) (a : Q($A)) : Unit × (Q($a = $a)) := sorry
example {v : Level} {A : Q(Type v)} {a : Q($A)} :
ExSum v A → Unit
| .add a =>
let ⟨_, _⟩ := f A a
()
Arend Mellendijk (Apr 02 2025 at 15:55):
This was actually the case in the un-minimised code. Here's something slightly less minimised that still gives the same error. It seems it's able to figure out that the v
and A
are the same as in the type of the ExSum
but struggles with the a
:
import Qq
open Lean Qq
inductive ExSum : ∀ {v: Lean.Level} (A : Q(Type v)), (e : Q($A)) → Type
| zero {w : Lean.Level} {A : Q(Type w)} (z : Q($A)) : ExSum A z
| one : ExSum q(Nat) q((1 : Nat))
| add {v w : Lean.Level} {A : Q(Type w)} {a : Q($A)} :
ExSum A q($a)
def f {v : Level} (A : Q(Type v)) (a : Q($A)) : Unit × Q($a = $a) := sorry
example {u v : Level} {A : Q(Type v)} {a : Q($A)}
(va : ExSum A a) :
Unit :=
match va with
| .zero z =>
()
| .one =>
()
| .add =>
let ⟨_, _⟩ := f A a
()
Weirdly this error is really unstable. Removing any of the constructors either gives a much clearer error message or makes the message go away completely.
To be clear I was eventually able to solve the issue in my case, but the error message made it much harder than it needed to be. I'm really just trying to figure out if this is a failure of error handling.
Jovan Gerbscheid (Apr 02 2025 at 15:59):
I don't know why, but replacing A
with q($A)
in the definition of ExSum.add
seems to help
Jovan Gerbscheid (Apr 02 2025 at 16:02):
I've also often seen unknown variables when using Qq in the form of some _fvar.451 appearing in the expression, but without having an actual error.
Eric Wieser (Apr 02 2025 at 16:37):
In general replacing x
with q($x)
leads to better behavior in Qq, as it forces x
to actually be elaborated into the expected type, either emitting error messages or assigning (universe) metavariables
Eric Wieser (Apr 02 2025 at 16:38):
(obviously this doesn't apply recursively to q($(q($(... x))))
)
Last updated: May 02 2025 at 03:31 UTC