Zulip Chat Archive

Stream: lean4

Topic: unknown fvar in MetaM


Adam Topaz (Nov 03 2024 at 21:10):

I came across a somewhat subtle error:

import Mathlib.Algebra.Order.Ring.Defs
import Mathlib.Algebra.Order.Star.Basic

namespace StarOrderedRing

private lemma mul_le_mul_of_nonneg_left {R : Type*} [CommSemiring R] [PartialOrder R]
    [StarRing R] [StarOrderedRing R] {a b c : R} (hab : a  b) (hc : 0  c) : c * a  c * b := by
  rw [StarOrderedRing.nonneg_iff] at hc
  induction hc using AddSubmonoid.closure_induction with
  | mem _ h =>
    obtain x, rfl := h
    simp_rw [mul_assoc, mul_comm x,  mul_assoc]
    exact conjugate_le_conjugate hab x
  | one => simp
  | mul x hx y hy =>
    simp only [ nonneg_iff, add_mul] at hx hy 
    run_tac Lean.Elab.Tactic.withMainContext do
      let lctx  Lean.getLCtx
      for (fvarId, decl) in lctx.fvarIdToDecl do
        let tp := decl.type
        Lean.Meta.forEachExpr tp fun e => do
          println!  Lean.Meta.inferType e
    apply add_le_add <;> aesop

This is taken directly from Mathlib.Algebra.Order.Ring.Star. Here's what I think is going on: It seems that the fvar associated to hy is replaced in the simp only ... step, but it appears in another fvar in the local context. So when I try to traverse the expressions of the types of all fvars and infer the type, I reach the "old" hy at one point, and trying to infer the type causes an error.

I don't necessarily think there is anything to do about this, but I'm just wondering if this behavior is expected and/or known.

Jannis Limperg (Nov 03 2024 at 23:00):

There's definitely something fishy going on. One of the hypotheses is

a : hx * a  hx * b [?_uniq.1256 _uniq.2414 _uniq.2416]

where the stuff in brackets is the actual expression. _uniq.2416 is an fvar that doesn't appear in the context, but ?_uniq.1256 is a metavariable assigned to a function that throws away its second argument, so the fact that _uniq.2416 doesn't exist is 'irrelevant'. Except it isn't when we use forEachExpr because that'll happily visit _uniq.2416.

Here's a version that shows this behaviour more clearly:

import Mathlib.Algebra.Order.Ring.Defs
import Mathlib.Algebra.Order.Star.Basic

namespace StarOrderedRing

open Lean Lean.Meta in
private lemma mul_le_mul_of_nonneg_left {R : Type*} [CommSemiring R] [PartialOrder R]
    [StarRing R] [StarOrderedRing R] {a b c : R} (hab : a  b) (hc : 0  c) : c * a  c * b := by
  rw [StarOrderedRing.nonneg_iff] at hc
  induction hc using AddSubmonoid.closure_induction with
  | mul x hx y hy =>
    simp only [ nonneg_iff, add_mul] at hx hy 
    run_tac Lean.Elab.Tactic.withMainContext do
      for decl in  getLCtx do
        if decl.isImplementationDetail then
          continue
        logInfo m!"== {decl.userName} : {decl.type} [{toString decl.type}]"
        forEachExpr decl.type fun e => do
          logInfo $ toString $ e
          if let .mvar mvarId := e then
            logInfo m!"inst: {← instantiateMVars e}"
          discard $ inferType e
    sorry
  | _ => sorry

Adam Topaz (Nov 03 2024 at 23:04):

Thanks! I figured out that synthesizing synthetic mvars fixes the issue, so my explanation was probably wrong:

    run_tac Lean.Elab.Term.withSynthesize <| Lean.Elab.Tactic.withMainContext do
      let lctx  Lean.getLCtx
      for (fvarId, decl) in lctx.fvarIdToDecl do
        let tp := decl.type
        Lean.Meta.forEachExpr tp fun e => do
          println!  Lean.Meta.inferType e

I'm still investigating and your version of the run_tac is helpful!

Jannis Limperg (Nov 03 2024 at 23:20):

Now that confuses me even more... It's possible that the synthesising just happens to reduce this function application, so the unknown fvar disappears by accident.

Adam Topaz (Nov 03 2024 at 23:26):

I wonder if the missing fvar is in the lctx of the function mvar?

Adam Topaz (Nov 03 2024 at 23:27):

Well, I need to put the computer away for the rest of today. I’ll keep investigating tomorrow.


Last updated: May 02 2025 at 03:31 UTC