lean4-htt/src/Lean/Meta/Match/CaseValues.lean
Leonardo de Moura b6f242434d fix: fixes #229
2020-11-30 11:51:13 -08:00

101 lines
4.4 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean.Meta.Tactic.Subst
import Lean.Meta.Tactic.Clear
namespace Lean.Meta
structure CaseValueSubgoal where
mvarId : MVarId
newH : FVarId
subst : FVarSubst := {}
instance : Inhabited CaseValueSubgoal :=
⟨{ mvarId := arbitrary, newH := arbitrary }⟩
/--
Split goal `... |- C x` into two subgoals
`..., (h : x = value) |- C value`
`..., (h : x != value) |- C x`
where `fvarId` is `x`s id.
The type of `x` must have decidable equality.
Remark: `subst` field of the second subgoal is equal to the input `subst`. -/
def caseValueAux (mvarId : MVarId) (fvarId : FVarId) (value : Expr) (hName : Name := `h) (subst : FVarSubst := {})
: MetaM (CaseValueSubgoal × CaseValueSubgoal) :=
withMVarContext mvarId do
let tag ← getMVarTag mvarId
checkNotAssigned mvarId `caseValue
let target ← getMVarType mvarId
let xEqValue ← mkEq (mkFVar fvarId) value
let xNeqValue := mkApp (mkConst `Not) xEqValue
let thenTarget := Lean.mkForall hName BinderInfo.default xEqValue target
let elseTarget := Lean.mkForall hName BinderInfo.default xNeqValue target
let thenMVar ← mkFreshExprSyntheticOpaqueMVar thenTarget tag
let elseMVar ← mkFreshExprSyntheticOpaqueMVar elseTarget tag
let val ← mkAppOptM `dite #[none, xEqValue, none, thenMVar, elseMVar]
assignExprMVar mvarId val
let (elseH, elseMVarId) ← intro1P elseMVar.mvarId!
let elseSubgoal := { mvarId := elseMVarId, newH := elseH, subst := subst : CaseValueSubgoal }
let (thenH, thenMVarId) ← intro1P thenMVar.mvarId!
let symm := false
let clearH := false
let (thenSubst, thenMVarId) ← substCore thenMVarId thenH symm subst clearH
withMVarContext thenMVarId do
trace[Meta]! "subst domain: {thenSubst.domain}"
let thenH := (thenSubst.get thenH).fvarId!
trace[Meta]! "searching for decl"
let decl ← getLocalDecl thenH
trace[Meta]! "found decl"
let thenSubgoal := { mvarId := thenMVarId, newH := (thenSubst.get thenH).fvarId!, subst := thenSubst : CaseValueSubgoal }
pure (thenSubgoal, elseSubgoal)
def caseValue (mvarId : MVarId) (fvarId : FVarId) (value : Expr) : MetaM (CaseValueSubgoal × CaseValueSubgoal) := do
let s ← caseValueAux mvarId fvarId value
appendTagSuffix s.1.mvarId `thenBranch
appendTagSuffix s.2.mvarId `elseBranch
pure s
structure CaseValuesSubgoal where
mvarId : MVarId
newHs : Array FVarId := #[]
subst : FVarSubst := {}
instance : Inhabited CaseValuesSubgoal :=
⟨{ mvarId := arbitrary }⟩
/--
Split goal `... |- C x` into values.size + 1 subgoals
1) `..., (h_1 : x = value[0]) |- C value[0]`
...
n) `..., (h_n : x = value[n - 1]) |- C value[n - 1]`
n+1) `..., (h_1 : x != value[0]) ... (h_n : x != value[n-1]) |- C x`
where `n = values.size`
where `fvarId` is `x`s id.
The type of `x` must have decidable equality.
Remark: the last subgoal is for the "else" catchall case, and its `subst` is `{}`.
Remark: the fiels `newHs` has size 1 forall but the last subgoal. -/
def caseValues (mvarId : MVarId) (fvarId : FVarId) (values : Array Expr) (hNamePrefix := `h) : MetaM (Array CaseValuesSubgoal) :=
let rec loop : Nat → MVarId → List Expr → Array FVarId → Array CaseValuesSubgoal → MetaM (Array CaseValuesSubgoal)
| i, mvarId, [], hs, subgoals => throwTacticEx `caseValues mvarId "list of values must not be empty"
| i, mvarId, v::vs, hs, subgoals => do
let (thenSubgoal, elseSubgoal) ← caseValueAux mvarId fvarId v (hNamePrefix.appendIndexAfter i) {}
appendTagSuffix thenSubgoal.mvarId ((`case).appendIndexAfter i)
let thenMVarId ← hs.foldlM
(fun thenMVarId h => match thenSubgoal.subst.get h with
| Expr.fvar fvarId _ => tryClear thenMVarId fvarId
| _ => pure thenMVarId)
thenSubgoal.mvarId
let subgoals := subgoals.push { mvarId := thenMVarId, newHs := #[thenSubgoal.newH], subst := thenSubgoal.subst }
match vs with
| [] => do
appendTagSuffix elseSubgoal.mvarId ((`case).appendIndexAfter (i+1))
pure $ subgoals.push { mvarId := elseSubgoal.mvarId, newHs := hs.push elseSubgoal.newH, subst := {} }
| vs => loop (i+1) elseSubgoal.mvarId vs (hs.push elseSubgoal.newH) subgoals
loop 1 mvarId values.toList #[] #[]
end Lean.Meta