171 lines
6.4 KiB
Text
171 lines
6.4 KiB
Text
/-
|
||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Leonardo de Moura
|
||
-/
|
||
import Lean.Util.ForEachExprWhere
|
||
import Lean.Meta.Basic
|
||
import Lean.Meta.AppBuilder
|
||
import Lean.Meta.PPGoal
|
||
|
||
namespace Lean.Meta
|
||
|
||
/-- Get the user name of the given metavariable. -/
|
||
def _root_.Lean.MVarId.getTag (mvarId : MVarId) : MetaM Name :=
|
||
return (← mvarId.getDecl).userName
|
||
|
||
@[deprecated MVarId.getTag]
|
||
def getMVarTag (mvarId : MVarId) : MetaM Name :=
|
||
mvarId.getTag
|
||
|
||
def _root_.Lean.MVarId.setTag (mvarId : MVarId) (tag : Name) : MetaM Unit := do
|
||
modify fun s => { s with mctx := s.mctx.setMVarUserName mvarId tag }
|
||
|
||
@[deprecated MVarId.setTag]
|
||
def setMVarTag (mvarId : MVarId) (tag : Name) : MetaM Unit := do
|
||
mvarId.setTag tag
|
||
|
||
def appendTag (tag : Name) (suffix : Name) : Name :=
|
||
tag.modifyBase (· ++ suffix.eraseMacroScopes)
|
||
|
||
def appendTagSuffix (mvarId : MVarId) (suffix : Name) : MetaM Unit := do
|
||
let tag ← mvarId.getTag
|
||
mvarId.setTag (appendTag tag suffix)
|
||
|
||
def mkFreshExprSyntheticOpaqueMVar (type : Expr) (tag : Name := Name.anonymous) : MetaM Expr :=
|
||
mkFreshExprMVar type MetavarKind.syntheticOpaque tag
|
||
|
||
def throwTacticEx (tacticName : Name) (mvarId : MVarId) (msg : MessageData) : MetaM α :=
|
||
if msg.isEmpty then
|
||
throwError "tactic '{tacticName}' failed\n{mvarId}"
|
||
else
|
||
throwError "tactic '{tacticName}' failed, {msg}\n{mvarId}"
|
||
|
||
def throwNestedTacticEx {α} (tacticName : Name) (ex : Exception) : MetaM α := do
|
||
throwError "tactic '{tacticName}' failed, nested error:\n{ex.toMessageData}"
|
||
|
||
/-- Throw a tactic exception with given tactic name if the given metavariable is assigned. -/
|
||
def _root_.Lean.MVarId.checkNotAssigned (mvarId : MVarId) (tacticName : Name) : MetaM Unit := do
|
||
if (← mvarId.isAssigned) then
|
||
throwTacticEx tacticName mvarId "metavariable has already been assigned"
|
||
|
||
@[deprecated MVarId.checkNotAssigned]
|
||
def checkNotAssigned (mvarId : MVarId) (tacticName : Name) : MetaM Unit := do
|
||
mvarId.checkNotAssigned tacticName
|
||
|
||
/-- Get the type the given metavariable. -/
|
||
def _root_.Lean.MVarId.getType (mvarId : MVarId) : MetaM Expr :=
|
||
return (← mvarId.getDecl).type
|
||
|
||
@[deprecated MVarId.getType]
|
||
def getMVarType (mvarId : MVarId) : MetaM Expr :=
|
||
mvarId.getType
|
||
|
||
/-- Get the type the given metavariable after instantiating metavariables and reducing to
|
||
weak head normal form. -/
|
||
-- The `instantiateMVars` needs to be on the outside,
|
||
-- since `whnf` can unfold local definitions which may introduce metavariables.
|
||
-- We don't need an `instantiateMVars` before the `whnf`, since it instantiates as necessary.
|
||
def _root_.Lean.MVarId.getType' (mvarId : MVarId) : MetaM Expr := do
|
||
instantiateMVars (← whnf (← mvarId.getType))
|
||
|
||
@[deprecated MVarId.getType']
|
||
def getMVarType' (mvarId : MVarId) : MetaM Expr := do
|
||
mvarId.getType'
|
||
|
||
builtin_initialize registerTraceClass `Meta.Tactic
|
||
|
||
/-- Assign `mvarId` to `sorryAx` -/
|
||
def _root_.Lean.MVarId.admit (mvarId : MVarId) (synthetic := true) : MetaM Unit :=
|
||
mvarId.withContext do
|
||
mvarId.checkNotAssigned `admit
|
||
let mvarType ← mvarId.getType
|
||
let val ← mkSorry mvarType synthetic
|
||
mvarId.assign val
|
||
|
||
@[deprecated MVarId.admit]
|
||
def admit (mvarId : MVarId) (synthetic := true) : MetaM Unit :=
|
||
mvarId.admit synthetic
|
||
|
||
/-- Beta reduce the metavariable type head -/
|
||
def _root_.Lean.MVarId.headBetaType (mvarId : MVarId) : MetaM Unit := do
|
||
mvarId.setType (← mvarId.getType).headBeta
|
||
|
||
@[deprecated MVarId.headBetaType]
|
||
def headBetaMVarType (mvarId : MVarId) : MetaM Unit := do
|
||
mvarId.headBetaType
|
||
|
||
/-- Collect nondependent hypotheses that are propositions. -/
|
||
def _root_.Lean.MVarId.getNondepPropHyps (mvarId : MVarId) : MetaM (Array FVarId) :=
|
||
let removeDeps (e : Expr) (candidates : FVarIdHashSet) : MetaM FVarIdHashSet := do
|
||
let e ← instantiateMVars e
|
||
let visit : StateRefT FVarIdHashSet MetaM FVarIdHashSet := do
|
||
e.forEachWhere Expr.isFVar fun e => modify fun s => s.erase e.fvarId!
|
||
get
|
||
visit |>.run' candidates
|
||
mvarId.withContext do
|
||
let mut candidates : FVarIdHashSet := {}
|
||
for localDecl in (← getLCtx) do
|
||
unless localDecl.isImplementationDetail do
|
||
candidates ← removeDeps localDecl.type candidates
|
||
match localDecl.value? with
|
||
| none => pure ()
|
||
| some value => candidates ← removeDeps value candidates
|
||
if (← isProp localDecl.type) && !localDecl.hasValue then
|
||
candidates := candidates.insert localDecl.fvarId
|
||
candidates ← removeDeps (← mvarId.getType) candidates
|
||
if candidates.isEmpty then
|
||
return #[]
|
||
else
|
||
let mut result := #[]
|
||
for localDecl in (← getLCtx) do
|
||
if candidates.contains localDecl.fvarId then
|
||
result := result.push localDecl.fvarId
|
||
return result
|
||
|
||
@[deprecated MVarId.getNondepPropHyps]
|
||
def getNondepPropHyps (mvarId : MVarId) : MetaM (Array FVarId) :=
|
||
mvarId.getNondepPropHyps
|
||
|
||
partial def saturate (mvarId : MVarId) (x : MVarId → MetaM (Option (List MVarId))) : MetaM (List MVarId) := do
|
||
let (_, r) ← go mvarId |>.run #[]
|
||
return r.toList
|
||
where
|
||
go (mvarId : MVarId) : StateRefT (Array MVarId) MetaM Unit :=
|
||
withIncRecDepth do
|
||
match (← x mvarId) with
|
||
| none => modify fun s => s.push mvarId
|
||
| some mvarIds => mvarIds.forM go
|
||
|
||
def exactlyOne (mvarIds : List MVarId) (msg : MessageData := "unexpected number of goals") : MetaM MVarId :=
|
||
match mvarIds with
|
||
| [mvarId] => return mvarId
|
||
| _ => throwError msg
|
||
|
||
def ensureAtMostOne (mvarIds : List MVarId) (msg : MessageData := "unexpected number of goals") : MetaM (Option MVarId) :=
|
||
match mvarIds with
|
||
| [] => return none
|
||
| [mvarId] => return some mvarId
|
||
| _ => throwError msg
|
||
|
||
/-- Return all propositions in the local context. -/
|
||
def getPropHyps : MetaM (Array FVarId) := do
|
||
let mut result := #[]
|
||
for localDecl in (← getLCtx) do
|
||
unless localDecl.isImplementationDetail do
|
||
if (← isProp localDecl.type) then
|
||
result := result.push localDecl.fvarId
|
||
return result
|
||
|
||
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"
|
||
|
||
inductive TacticResultCNM where
|
||
| closed
|
||
| noChange
|
||
| modified (mvarId : MVarId)
|
||
|
||
end Lean.Meta
|