Zulip Chat Archive

Stream: lean4

Topic: (Properly) inferring types in meta code


Alex Keizer (Apr 19 2023 at 10:21):

I'm trying to infer the type of an ambiguous let binding, whose type should be able to be inferred by it's usage in a later function.

import Lean
open Lean Meta Elab Term

elab "dbg_type" fv:ident tail:term : term => do
  let name := fv.getId
  let some fv  resolveId? fv
    | panic! ""

  synthesizeSyntheticMVarsNoPostponing
  let ty  inferType fv

  dbg_trace "trace: '{name}' has type '{ty}'"
  if ty.isMVar then
    dbg_trace "{ty} is an MVar"
  else
    dbg_trace "{ty} is not an MVar"
  Elab.Term.elabTerm tail none




def force_nat : Nat  Nat := id

example : True :=
  let n := 2
  let _ := force_nat n
  let _ := dbg_type n 1
  .intro

The infoview shows n : Nat as expected, but the trace just says

trace: 'n' has type '?_uniq.3943'
?_uniq.3943 is an MVar

I get the feeling I need to so more synthesizing of MVars somehow, is there some method stronger than synthesizeSyntheticMVars?

Jannis Limperg (Apr 19 2023 at 11:02):

Looks to me like the mvar is getting assigned just fine, you just need to instantiateMVars ty.

Jannis Limperg (Apr 19 2023 at 11:04):

Yep, that fixes it. It's maybe mildly surprising that inferType doesn't already do this.

Alex Keizer (Apr 19 2023 at 11:16):

Aha, so to make sure I understand correctly: the environment already has a mapping that the mvar ?_uniq.3943 should stand for Nat, and instantiateMVars just goes to check this mapping and replaces any (pre-assigned) mvars with their assigned value, right?

Jannis Limperg (Apr 19 2023 at 11:44):

Yes. Lean does not remember which expressions a metavariable ?m may appear in. So when a metavariable is assigned, these expressions remain unchanged and still contain ?m. You must then manually synchronise the expressions with the assignment by calling instantiateMVars. Forgetting to do this is one of the most common mistakes in tactic code. Many builtin functions (e.g. whnf) also do instantiateMVars for you, but when in doubt it's better to instantiate too much than too little since instantiateMVars is quite well-optimised. In particular, it's an immediate no-op for (sub)expressions which don't contain any metavariables.


Last updated: Dec 20 2023 at 11:08 UTC