leanprover / leanprover/lean4

`isDefEq` does not always assign goals

Open
#2,054 5 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

P-low
Dominant language
Lean
Stars
9.2k
Forks
990
Avg merge
1d 17h
Merged PRs (30d)
175

Description

The documentation on assign says:

/--
Add `mvarId := x` to the metavariable assignment.
This method does not check whether `mvarId` is already assigned, nor it checks whether
a cycle is being introduced, or whether the expression has the right type.
This is a low-level API, and it is safer to use `isDefEq (mkMVar mvarId) x`.
-/
def _root_.Lean.MVarId.assign [MonadMCtx m] (mvarId : MVarId) (val : Expr) : m Unit :=

However the suggested pattern isDefEq (mkMVar mvarId) x does not assign mvarId if the type of mvarId is a proposition. This is the source of several bugs in mathlib tactics, and at least one bug in core:

import Lean
open Lean Elab Tactic

elab "my_infer_instance" : tactic => do
  (← getMainGoal).inferInstance
  replaceMainGoal []

class Foo : Prop
instance : Foo := sorry
example : Foo := by my_infer_instance
-- (kernel) declaration has metavariables '_example'

This is because inferInstance doesn't actually assign the mvar:

def _root_.Lean.MVarId.inferInstance (mvarId : MVarId) : MetaM Unit := mvarId.withContext do
  mvarId.checkNotAssigned `infer_instance
  let synthVal ← synthInstance (← mvarId.getType)
  unless (← isDefEq (mkMVar mvarId) synthVal) do
    throwTacticEx `infer_instance mvarId "`infer_instance` tactic failed to assign instance"

The current workaround is to do isDefEq first and then call mvarId.assign val afterward. It would probably be good to have an API function for this (and point users to it in MVarId.assign).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Lean.MVarId.assign, MVarId.inferInstance, and the isDefEq call shown in the issue. Trace how proposition-typed metavariables are handled, then define or document an API that reliably assigns them and update the guidance in MVarId.assign; verify the example no longer leaves declaration metavariables.

Written by the indexing model from the issue text.

Assessment

Domain
compilers
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.