parent
91999d22eb
commit
8335a82aed
78 changed files with 1015 additions and 695 deletions
|
|
@ -1,6 +1,10 @@
|
|||
Unreleased
|
||||
---------
|
||||
|
||||
* Improve `MVarId` methods discoverability. See [issue #1346](https://github.com/leanprover/lean4/issues/1346).
|
||||
We still have to add similar methods for `FVarId`, `LVarId`, `Expr`, and other objects.
|
||||
Many existing methods have been marked as deprecated.
|
||||
|
||||
* Add attribute `[deprecated]` for marking deprecated declarations. Examples:
|
||||
```lean
|
||||
def g (x : Nat) := x + 1
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ private def finalize : M Expr := do
|
|||
synthesizeAppInstMVars
|
||||
/- If `eType != mkMVar outParamMVarId`, then the
|
||||
function is partially applied, and we do not apply default instances. -/
|
||||
if !(← isExprMVarAssigned outParamMVarId) && eType.isMVar && eType.mvarId! == outParamMVarId then
|
||||
if !(← outParamMVarId.isAssigned) && eType.isMVar && eType.mvarId! == outParamMVarId then
|
||||
synthesizeSyntheticMVarsUsingDefault
|
||||
return e
|
||||
else
|
||||
|
|
|
|||
|
|
@ -89,12 +89,12 @@ private def elabOptLevel (stx : Syntax) : TermElabM Level :=
|
|||
withLCtx mvarDecl.lctx mvarDecl.localInstances do
|
||||
throwError "synthetic hole has already been defined and assigned to value incompatible with the current context{indentExpr val}"
|
||||
| none =>
|
||||
if (← isMVarDelayedAssigned mvarId) then
|
||||
if (← mvarId.isDelayedAssigned) then
|
||||
-- We can try to improve this case if needed.
|
||||
throwError "synthetic hole has already beend defined and delayed assigned with an incompatible local context"
|
||||
else if lctx.isSubPrefixOf mvarDecl.lctx then
|
||||
let mvarNew ← mkNewHole ()
|
||||
assignExprMVar mvarId mvarNew
|
||||
mvarId.assign mvarNew
|
||||
return mvarNew
|
||||
else
|
||||
throwError "synthetic hole has already been defined with an incompatible local context"
|
||||
|
|
@ -107,7 +107,7 @@ private def elabOptLevel (stx : Syntax) : TermElabM Level :=
|
|||
| none =>
|
||||
let e ← elabTerm e none
|
||||
let mvar ← mkFreshExprMVar (← inferType e) MetavarKind.syntheticOpaque n.getId
|
||||
assignExprMVar mvar.mvarId! e
|
||||
mvar.mvarId!.assign e
|
||||
-- We use `mkSaveInfoAnnotation` to make sure the info trees for `e` are saved even if `b` is a metavariable.
|
||||
return mkSaveInfoAnnotation (← elabTerm b expectedType?)
|
||||
| _ => throwUnsupportedSyntax
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@ where
|
|||
return mkInaccessible (← eraseInaccessibleAnnotations e)
|
||||
else
|
||||
if e'.isMVar then
|
||||
setMVarTag e'.mvarId! (← read).userName
|
||||
e'.mvarId!.setTag (← read).userName
|
||||
modify fun s => { s with patternVars := s.patternVars.push e' }
|
||||
return e
|
||||
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ private def mkLetRecClosureFor (toLift : LetRecToLift) (freeVars : Array FVarId)
|
|||
let type := Closure.mkForall s.localDecls <| Closure.mkForall s.newLetDecls type
|
||||
let val := Closure.mkLambda s.localDecls <| Closure.mkLambda s.newLetDecls val
|
||||
let c := mkAppN (Lean.mkConst toLift.declName) s.exprArgs
|
||||
assignExprMVar toLift.mvarId c
|
||||
toLift.mvarId.assign c
|
||||
return {
|
||||
ref := toLift.ref
|
||||
localDecls := s.newLocalDecls
|
||||
|
|
|
|||
|
|
@ -24,18 +24,18 @@ partial def expand : Expr → Expr
|
|||
| e => e
|
||||
|
||||
def expandRHS? (mvarId : MVarId) : MetaM (Option MVarId) := do
|
||||
let target ← getMVarType' mvarId
|
||||
let target ← mvarId.getType'
|
||||
let some (_, lhs, rhs) := target.eq? | return none
|
||||
unless rhs.isLet || rhs.isMData do return none
|
||||
return some (← replaceTargetDefEq mvarId (← mkEq lhs (expand rhs)))
|
||||
return some (← mvarId.replaceTargetDefEq (← mkEq lhs (expand rhs)))
|
||||
|
||||
def funext? (mvarId : MVarId) : MetaM (Option MVarId) := do
|
||||
let target ← getMVarType' mvarId
|
||||
let target ← mvarId.getType'
|
||||
let some (_, _, rhs) := target.eq? | return none
|
||||
unless rhs.isLambda do return none
|
||||
commitWhenSome? do
|
||||
let [mvarId] ← apply mvarId (← mkConstWithFreshMVarLevels ``funext) | return none
|
||||
let (_, mvarId) ← intro1 mvarId
|
||||
let [mvarId] ← mvarId.apply (← mkConstWithFreshMVarLevels ``funext) | return none
|
||||
let (_, mvarId) ← mvarId.intro1
|
||||
return some mvarId
|
||||
|
||||
def simpMatch? (mvarId : MVarId) : MetaM (Option MVarId) := do
|
||||
|
|
@ -76,7 +76,7 @@ private def findMatchToSplit? (env : Environment) (e : Expr) (declNames : Array
|
|||
return Expr.FindStep.visit
|
||||
|
||||
partial def splitMatch? (mvarId : MVarId) (declNames : Array Name) : MetaM (Option (List MVarId)) := commitWhenSome? do
|
||||
let target ← getMVarType' mvarId
|
||||
let target ← mvarId.getType'
|
||||
let rec go (badCases : ExprSet) : MetaM (Option (List MVarId)) := do
|
||||
if let some e := findMatchToSplit? (← getEnv) target declNames badCases then
|
||||
try
|
||||
|
|
@ -145,8 +145,8 @@ where
|
|||
ST.Prim.Ref.get ref
|
||||
runST (go e)
|
||||
|
||||
private partial def saveEqn (mvarId : MVarId) : StateRefT (Array Expr) MetaM Unit := withMVarContext mvarId do
|
||||
let target ← getMVarType' mvarId
|
||||
private partial def saveEqn (mvarId : MVarId) : StateRefT (Array Expr) MetaM Unit := mvarId.withContext do
|
||||
let target ← mvarId.getType'
|
||||
let fvarState := collectFVars {} target
|
||||
let fvarState ← (← getLCtx).foldrM (init := fvarState) fun decl fvarState => do
|
||||
if fvarState.fvarSet.contains decl.fvarId then
|
||||
|
|
@ -229,7 +229,7 @@ where
|
|||
/- if let some mvarId ← funext? mvarId then
|
||||
return (← go mvarId) -/
|
||||
|
||||
if (← shouldUseSimpMatch (← getMVarType' mvarId)) then
|
||||
if (← shouldUseSimpMatch (← mvarId.getType')) then
|
||||
if let some mvarId ← simpMatch? mvarId then
|
||||
return (← go mvarId)
|
||||
|
||||
|
|
@ -270,32 +270,32 @@ where
|
|||
return (lctx.mkForall xsNew type, lctx.mkLambda xsNew value)
|
||||
|
||||
/-- Delta reduce the equation left-hand-side -/
|
||||
def deltaLHS (mvarId : MVarId) : MetaM MVarId := withMVarContext mvarId do
|
||||
let target ← getMVarType' mvarId
|
||||
def deltaLHS (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
|
||||
let target ← mvarId.getType'
|
||||
let some (_, lhs, rhs) := target.eq? | throwTacticEx `deltaLHS mvarId "equality expected"
|
||||
let some lhs ← delta? lhs | throwTacticEx `deltaLHS mvarId "failed to delta reduce lhs"
|
||||
replaceTargetDefEq mvarId (← mkEq lhs rhs)
|
||||
mvarId.replaceTargetDefEq (← mkEq lhs rhs)
|
||||
|
||||
def deltaRHS? (mvarId : MVarId) (declName : Name) : MetaM (Option MVarId) := withMVarContext mvarId do
|
||||
let target ← getMVarType' mvarId
|
||||
def deltaRHS? (mvarId : MVarId) (declName : Name) : MetaM (Option MVarId) := mvarId.withContext do
|
||||
let target ← mvarId.getType'
|
||||
let some (_, lhs, rhs) := target.eq? | return none
|
||||
let some rhs ← delta? rhs.consumeMData (· == declName) | return none
|
||||
replaceTargetDefEq mvarId (← mkEq lhs rhs)
|
||||
mvarId.replaceTargetDefEq (← mkEq lhs rhs)
|
||||
|
||||
private partial def whnfAux (e : Expr) : MetaM Expr := do
|
||||
let e ← whnfI e -- Must reduce instances too, otherwise it will not be able to reduce `(Nat.rec ... ... (OfNat.ofNat 0))`
|
||||
let f := e.getAppFn
|
||||
match f with
|
||||
| Expr.proj _ _ s => return mkAppN (f.updateProj! (← whnfAux s)) e.getAppArgs
|
||||
| .proj _ _ s => return mkAppN (f.updateProj! (← whnfAux s)) e.getAppArgs
|
||||
| _ => return e
|
||||
|
||||
/-- Apply `whnfR` to lhs, return `none` if `lhs` was not modified -/
|
||||
def whnfReducibleLHS? (mvarId : MVarId) : MetaM (Option MVarId) := withMVarContext mvarId do
|
||||
let target ← getMVarType' mvarId
|
||||
def whnfReducibleLHS? (mvarId : MVarId) : MetaM (Option MVarId) := mvarId.withContext do
|
||||
let target ← mvarId.getType'
|
||||
let some (_, lhs, rhs) := target.eq? | return none
|
||||
let lhs' ← whnfAux lhs
|
||||
if lhs' != lhs then
|
||||
return some (← replaceTargetDefEq mvarId (← mkEq lhs' rhs))
|
||||
return some (← mvarId.replaceTargetDefEq (← mkEq lhs' rhs))
|
||||
else
|
||||
return none
|
||||
|
||||
|
|
@ -325,12 +325,12 @@ partial def mkUnfoldProof (declName : Name) (mvarId : MVarId) : MetaM Unit := do
|
|||
let tryEqns (mvarId : MVarId) : MetaM Bool :=
|
||||
eqs.anyM fun eq => commitWhen do
|
||||
try
|
||||
let subgoals ← apply mvarId (← mkConstWithFreshMVarLevels eq)
|
||||
let subgoals ← mvarId.apply (← mkConstWithFreshMVarLevels eq)
|
||||
subgoals.allM fun subgoal => do
|
||||
if (← isExprMVarAssigned subgoal) then
|
||||
if (← subgoal.isAssigned) then
|
||||
return true -- Subgoal was already solved. This can happen when there are dependencies between the subgoals
|
||||
else
|
||||
assumptionCore subgoal
|
||||
subgoal.assumptionCore
|
||||
catch _ =>
|
||||
return false
|
||||
let rec go (mvarId : MVarId) : MetaM Unit := do
|
||||
|
|
@ -340,7 +340,7 @@ partial def mkUnfoldProof (declName : Name) (mvarId : MVarId) : MetaM Unit := do
|
|||
-- else if let some mvarId ← funext? mvarId then
|
||||
-- go mvarId
|
||||
|
||||
if (← shouldUseSimpMatch (← getMVarType' mvarId)) then
|
||||
if (← shouldUseSimpMatch (← mvarId.getType')) then
|
||||
if let some mvarId ← simpMatch? mvarId then
|
||||
return (← go mvarId)
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ private partial def mkProof (declName : Name) (type : Expr) : MetaM Expr := do
|
|||
trace[Elab.definition.structural.eqns] "proving: {type}"
|
||||
withNewMCtxDepth do
|
||||
let main ← mkFreshExprSyntheticOpaqueMVar type
|
||||
let (_, mvarId) ← intros main.mvarId!
|
||||
let (_, mvarId) ← main.mvarId!.intros
|
||||
unless (← tryURefl mvarId) do -- catch easy cases
|
||||
go (← deltaLHS mvarId)
|
||||
instantiateMVars main
|
||||
|
|
|
|||
|
|
@ -18,22 +18,22 @@ structure EqnInfo extends EqnInfoCore where
|
|||
fixedPrefixSize : Nat
|
||||
deriving Inhabited
|
||||
|
||||
private partial def deltaLHSUntilFix (mvarId : MVarId) : MetaM MVarId := withMVarContext mvarId do
|
||||
let target ← getMVarType' mvarId
|
||||
private partial def deltaLHSUntilFix (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
|
||||
let target ← mvarId.getType'
|
||||
let some (_, lhs, _) := target.eq? | throwTacticEx `deltaLHSUntilFix mvarId "equality expected"
|
||||
if lhs.isAppOf ``WellFounded.fix then
|
||||
return mvarId
|
||||
else
|
||||
deltaLHSUntilFix (← deltaLHS mvarId)
|
||||
|
||||
private def rwFixEq (mvarId : MVarId) : MetaM MVarId := withMVarContext mvarId do
|
||||
let target ← getMVarType' mvarId
|
||||
private def rwFixEq (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
|
||||
let target ← mvarId.getType'
|
||||
let some (_, lhs, rhs) := target.eq? | unreachable!
|
||||
let h := mkAppN (mkConst ``WellFounded.fix_eq lhs.getAppFn.constLevels!) lhs.getAppArgs
|
||||
let some (_, _, lhsNew) := (← inferType h).eq? | unreachable!
|
||||
let targetNew ← mkEq lhsNew rhs
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew
|
||||
assignExprMVar mvarId (← mkEqTrans h mvarNew)
|
||||
mvarId.assign (← mkEqTrans h mvarNew)
|
||||
return mvarNew.mvarId!
|
||||
|
||||
private def hasWellFoundedFix (e : Expr) : Bool :=
|
||||
|
|
@ -103,8 +103,8 @@ where
|
|||
See comment at `tryToFoldWellFoundedFix`.
|
||||
-/
|
||||
def simpMatchWF? (info : EqnInfo) (us : List Level) (fixedPrefix : Array Expr) (mvarId : MVarId) : MetaM (Option MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
let target ← instantiateMVars (← getMVarType mvarId)
|
||||
mvarId.withContext do
|
||||
let target ← instantiateMVars (← mvarId.getType)
|
||||
let targetNew ← Simp.main target (← Split.getSimpMatchContext) (methods := { pre })
|
||||
let mvarIdNew ← applySimpResultToTarget mvarId target targetNew
|
||||
if mvarId != mvarIdNew then return some mvarIdNew else return none
|
||||
|
|
@ -127,22 +127,22 @@ where
|
|||
| none => return Simp.Step.visit { expr := e }
|
||||
|
||||
private def tryToFoldLHS? (info : EqnInfo) (us : List Level) (fixedPrefix : Array Expr) (mvarId : MVarId) : MetaM (Option MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
let target ← getMVarType' mvarId
|
||||
mvarId.withContext do
|
||||
let target ← mvarId.getType'
|
||||
let some (_, lhs, rhs) := target.eq? | unreachable!
|
||||
let lhsNew ← tryToFoldWellFoundedFix info us fixedPrefix lhs
|
||||
if lhs == lhsNew then return none
|
||||
let targetNew ← mkEq lhsNew rhs
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew
|
||||
assignExprMVar mvarId mvarNew
|
||||
mvarId.assign mvarNew
|
||||
return mvarNew.mvarId!
|
||||
|
||||
/--
|
||||
Given a goal of the form `|- f.{us} a_1 ... a_n b_1 ... b_m = ...`, return `(us, #[a_1, ..., a_n])`
|
||||
where `f` is a constant named `declName`, and `n = info.fixedPrefixSize`.
|
||||
-/
|
||||
private def getFixedPrefix (declName : Name) (info : EqnInfo) (mvarId : MVarId) : MetaM (List Level × Array Expr) := withMVarContext mvarId do
|
||||
let target ← getMVarType' mvarId
|
||||
private def getFixedPrefix (declName : Name) (info : EqnInfo) (mvarId : MVarId) : MetaM (List Level × Array Expr) := mvarId.withContext do
|
||||
let target ← mvarId.getType'
|
||||
let some (_, lhs, _) := target.eq? | unreachable!
|
||||
let lhsArgs := lhs.getAppArgs
|
||||
if lhsArgs.size < info.fixedPrefixSize || !lhs.getAppFn matches .const .. then
|
||||
|
|
@ -155,7 +155,7 @@ private partial def mkProof (declName : Name) (info : EqnInfo) (type : Expr) : M
|
|||
trace[Elab.definition.wf.eqns] "proving: {type}"
|
||||
withNewMCtxDepth do
|
||||
let main ← mkFreshExprSyntheticOpaqueMVar type
|
||||
let (_, mvarId) ← intros main.mvarId!
|
||||
let (_, mvarId) ← main.mvarId!.intros
|
||||
let (us, fixedPrefix) ← getFixedPrefix declName info mvarId
|
||||
let rec go (mvarId : MVarId) : MetaM Unit := do
|
||||
trace[Elab.definition.wf.eqns] "step\n{MessageData.ofGoal mvarId}"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ private def applyDefaultDecrTactic (mvarId : MVarId) : TermElabM Unit := do
|
|||
private def mkDecreasingProof (decreasingProp : Expr) (decrTactic? : Option Syntax) : TermElabM Expr := do
|
||||
let mvar ← mkFreshExprSyntheticOpaqueMVar decreasingProp
|
||||
let mvarId := mvar.mvarId!
|
||||
let mvarId ← cleanup mvarId
|
||||
let mvarId ← mvarId.cleanup
|
||||
match decrTactic? with
|
||||
| none => applyDefaultDecrTactic mvarId
|
||||
| some decrTactic =>
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ private partial def mkPSigmaCasesOn (y : Expr) (codomain : Expr) (xs : Array Exp
|
|||
go s.mvarId s.fields[1]!.fvarId! (ys.push s.fields[0]!)
|
||||
else
|
||||
let ys := ys.push (mkFVar y)
|
||||
assignExprMVar mvarId (value.replaceFVars xs ys)
|
||||
mvarId.assign (value.replaceFVars xs ys)
|
||||
go mvar.mvarId! y.fvarId! #[]
|
||||
instantiateMVars mvar
|
||||
|
||||
|
|
|
|||
|
|
@ -82,10 +82,10 @@ private partial def packValues (x : Expr) (codomain : Expr) (preDefValues : Arra
|
|||
else
|
||||
#[{ varNames := [varNames[i]!] }]
|
||||
let #[s₁, s₂] ← cases mvarId x (givenNames := givenNames) | unreachable!
|
||||
assignExprMVar s₁.mvarId (mkApp preDefValues[i]! s₁.fields[0]!).headBeta
|
||||
s₁.mvarId.assign (mkApp preDefValues[i]! s₁.fields[0]!).headBeta
|
||||
go s₂.mvarId s₂.fields[0]!.fvarId! (i+1)
|
||||
else
|
||||
assignExprMVar mvarId (mkApp preDefValues[i]! (mkFVar x)).headBeta
|
||||
mvarId.assign (mkApp preDefValues[i]! (mkFVar x)).headBeta
|
||||
go mvar.mvarId! x.fvarId! 0
|
||||
instantiateMVars mvar
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ private partial def unpackUnary (preDef : PreDefinition) (prefixSize : Nat) (mva
|
|||
let mut mvarId := mvarId
|
||||
for localDecl in (← Term.getMVarDecl mvarId).lctx, varName in varNames[:prefixSize] do
|
||||
unless localDecl.userName == varName do
|
||||
mvarId ← rename mvarId localDecl.fvarId varName
|
||||
mvarId ← mvarId.rename localDecl.fvarId varName
|
||||
let numPackedArgs := varNames.size - prefixSize
|
||||
let rec go (i : Nat) (mvarId : MVarId) (fvarId : FVarId) : TermElabM MVarId := do
|
||||
trace[Elab.definition.wf] "i: {i}, varNames: {varNames}, goal: {mvarId}"
|
||||
|
|
@ -50,7 +50,7 @@ private partial def unpackUnary (preDef : PreDefinition) (prefixSize : Nat) (mva
|
|||
let #[s] ← cases mvarId fvarId #[{ varNames := [varNames[prefixSize + i]!] }] | unreachable!
|
||||
go (i+1) s.mvarId s.fields[1]!.fvarId!
|
||||
else
|
||||
rename mvarId fvarId varNames.back
|
||||
mvarId.rename fvarId varNames.back
|
||||
go 0 mvarId fvarId
|
||||
|
||||
def getNumCandidateArgs (fixedPrefixSize : Nat) (preDefs : Array PreDefinition) : MetaM (Array Nat) := do
|
||||
|
|
@ -115,16 +115,16 @@ where
|
|||
go (expectedType : Expr) (elements : Array TerminationByElement) : TermElabM α :=
|
||||
withDeclName unaryPreDefName <| withRef (getRefFromElems elements) do
|
||||
let mainMVarId := (← mkFreshExprSyntheticOpaqueMVar expectedType).mvarId!
|
||||
let [fMVarId, wfRelMVarId, _] ← apply mainMVarId (← mkConstWithFreshMVarLevels ``invImage) | throwError "failed to apply 'invImage'"
|
||||
let (d, fMVarId) ← intro1 fMVarId
|
||||
let [fMVarId, wfRelMVarId, _] ← mainMVarId.apply (← mkConstWithFreshMVarLevels ``invImage) | throwError "failed to apply 'invImage'"
|
||||
let (d, fMVarId) ← fMVarId.intro1
|
||||
let subgoals ← unpackMutual preDefs fMVarId d
|
||||
for (d, mvarId) in subgoals, element in elements, preDef in preDefs do
|
||||
let mvarId ← unpackUnary preDef fixedPrefixSize mvarId d element
|
||||
withMVarContext mvarId do
|
||||
let value ← Term.withSynthesize <| elabTermEnsuringType element.body (← getMVarType mvarId)
|
||||
assignExprMVar mvarId value
|
||||
mvarId.withContext do
|
||||
let value ← Term.withSynthesize <| elabTermEnsuringType element.body (← mvarId.getType)
|
||||
mvarId.assign value
|
||||
let wfRelVal ← synthInstance (← inferType (mkMVar wfRelMVarId))
|
||||
assignExprMVar wfRelMVarId wfRelVal
|
||||
wfRelMVarId.assign wfRelVal
|
||||
k (← instantiateMVars (mkMVar mainMVarId))
|
||||
|
||||
generateElements (numArgs : Array Nat) (argCombination : Array Nat) : TermElabM (Array TerminationByElement) := do
|
||||
|
|
|
|||
|
|
@ -705,7 +705,7 @@ partial def findDefaultMissing? [Monad m] [MonadMCtx m] (struct : Struct) : m (O
|
|||
| _ => match field.expr? with
|
||||
| none => unreachable!
|
||||
| some expr => match defaultMissing? expr with
|
||||
| some (.mvar mvarId) => return if (← isExprMVarAssigned mvarId) then none else some field
|
||||
| some (.mvar mvarId) => return if (← mvarId.isAssigned) then none else some field
|
||||
| _ => return none
|
||||
|
||||
def getFieldName (field : Field Struct) : Name :=
|
||||
|
|
@ -811,7 +811,7 @@ partial def tryToSynthesizeDefault (structs : Array Struct) (allStructNames : Ar
|
|||
| none =>
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let val ← ensureHasType mvarDecl.type val
|
||||
assignExprMVar mvarId val
|
||||
mvarId.assign val
|
||||
return true
|
||||
| _ => loop (i+1) dist
|
||||
else
|
||||
|
|
@ -829,7 +829,7 @@ partial def step (struct : Struct) : M Unit :=
|
|||
| some expr =>
|
||||
match defaultMissing? expr with
|
||||
| some (.mvar mvarId) =>
|
||||
unless (← isExprMVarAssigned mvarId) do
|
||||
unless (← mvarId.isAssigned) do
|
||||
let ctx ← read
|
||||
if (← withRef field.ref <| tryToSynthesizeDefault ctx.structs ctx.allStructNames ctx.maxDistance (getFieldName field) mvarId) then
|
||||
modify fun _ => { progress := true }
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ private def resumeElabTerm (stx : Syntax) (expectedType? : Option Expr) (errToSo
|
|||
It returns `true` if it succeeded, and `false` otherwise.
|
||||
It is used to implement `synthesizeSyntheticMVars`. -/
|
||||
private def resumePostponed (savedContext : SavedContext) (stx : Syntax) (mvarId : MVarId) (postponeOnError : Bool) : TermElabM Bool :=
|
||||
withRef stx <| withMVarContext mvarId do
|
||||
withRef stx <| mvarId.withContext do
|
||||
let s ← saveState
|
||||
try
|
||||
withSavedContext savedContext do
|
||||
|
|
@ -35,7 +35,7 @@ private def resumePostponed (savedContext : SavedContext) (stx : Syntax) (mvarId
|
|||
let result ← withRef stx <| ensureHasType expectedType result
|
||||
/- We must perform `occursCheck` here since `result` may contain `mvarId` when it has synthetic `sorry`s. -/
|
||||
if (← occursCheck mvarId result) then
|
||||
assignExprMVar mvarId result
|
||||
mvarId.assign result
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
|
@ -58,7 +58,7 @@ private def resumePostponed (savedContext : SavedContext) (stx : Syntax) (mvarId
|
|||
Similar to `synthesizeInstMVarCore`, but makes sure that `instMVar` local context and instances
|
||||
are used. It also logs any error message produced. -/
|
||||
private def synthesizePendingInstMVar (instMVar : MVarId) : TermElabM Bool :=
|
||||
withMVarContext instMVar do
|
||||
instMVar.withContext do
|
||||
try
|
||||
synthesizeInstMVarCore instMVar
|
||||
catch
|
||||
|
|
@ -73,7 +73,7 @@ private def synthesizePendingInstMVar (instMVar : MVarId) : TermElabM Bool :=
|
|||
private def synthesizePendingCoeInstMVar
|
||||
(auxMVarId : MVarId) (errorMsgHeader? : Option String) (eNew : Expr) (expectedType : Expr) (eType : Expr) (e : Expr) (f? : Option Expr) : TermElabM Bool := do
|
||||
let instMVarId := eNew.appArg!.mvarId!
|
||||
withMVarContext instMVarId do
|
||||
instMVarId.withContext do
|
||||
let eType ← instantiateMVars eType
|
||||
if (← isSyntheticMVar eType) then
|
||||
return false
|
||||
|
|
@ -83,7 +83,7 @@ private def synthesizePendingCoeInstMVar
|
|||
However, it may succeed here because we have more information, for example, metavariables
|
||||
occurring at `expectedType` and `eType` may have been assigned. -/
|
||||
if (← occursCheck auxMVarId e) then
|
||||
assignExprMVar auxMVarId e
|
||||
auxMVarId.assign e
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
|
@ -91,7 +91,7 @@ private def synthesizePendingCoeInstMVar
|
|||
if (← synthesizeCoeInstMVarCore instMVarId) then
|
||||
let eNew ← expandCoe eNew
|
||||
if (← occursCheck auxMVarId eNew) then
|
||||
assignExprMVar auxMVarId eNew
|
||||
auxMVarId.assign eNew
|
||||
return true
|
||||
return false
|
||||
catch
|
||||
|
|
@ -125,8 +125,8 @@ private def synthesizePendingCoeInstMVar
|
|||
Instead of performing a backtracking search that considers all pending metavariables, we improved the `binrel%` elaborator.
|
||||
-/
|
||||
private partial def synthesizeUsingDefaultPrio (mvarId : MVarId) (prio : Nat) : TermElabM Bool :=
|
||||
withMVarContext mvarId do
|
||||
let mvarType := (← Meta.getMVarDecl mvarId).type
|
||||
mvarId.withContext do
|
||||
let mvarType ← mvarId.getType
|
||||
match (← isClass? mvarType) with
|
||||
| none => return false
|
||||
| some className =>
|
||||
|
|
@ -146,7 +146,7 @@ where
|
|||
return false
|
||||
|
||||
synthesizePendingInstMVar' (mvarId : MVarId) : TermElabM Bool :=
|
||||
commitWhen <| withMVarContext mvarId do
|
||||
commitWhen <| mvarId.withContext do
|
||||
try
|
||||
synthesizeInstMVarCore mvarId
|
||||
catch _ =>
|
||||
|
|
@ -240,13 +240,13 @@ def reportStuckSyntheticMVar (mvarId : MVarId) (ignoreStuckTC := false) : TermEl
|
|||
match mvarSyntheticDecl.kind with
|
||||
| .typeClass =>
|
||||
unless ignoreStuckTC do
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
unless (← MonadLog.hasErrors) do
|
||||
throwError "typeclass instance problem is stuck, it is often due to metavariables{indentExpr mvarDecl.type}"
|
||||
| .coe header eNew expectedType eType e f? =>
|
||||
let mvarId := eNew.appArg!.mvarId!
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
throwTypeMismatchError header expectedType eType e f? (some ("failed to create type class instance for " ++ indentExpr mvarDecl.type))
|
||||
| _ => unreachable! -- TODO handle other cases.
|
||||
|
|
@ -360,7 +360,7 @@ mutual
|
|||
-- It would not be incorrect to use `filterM`.
|
||||
let remainingPendingMVars ← pendingMVars.filterRevM fun mvarId => do
|
||||
-- We use `traceM` because we want to make sure the metavar local context is used to trace the message
|
||||
traceM `Elab.postpone (withMVarContext mvarId do addMessageContext m!"resuming {mkMVar mvarId}")
|
||||
traceM `Elab.postpone (mvarId.withContext do addMessageContext m!"resuming {mkMVar mvarId}")
|
||||
let succeeded ← synthesizeSyntheticMVar mvarId postponeOnError runTactics
|
||||
if succeeded then markAsResolved mvarId
|
||||
trace[Elab.postpone] if succeeded then format "succeeded" else format "not ready yet"
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ open Meta
|
|||
|
||||
/-- Assign `mvarId := sorry` -/
|
||||
def admitGoal (mvarId : MVarId) : MetaM Unit :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let mvarType ← inferType (mkMVar mvarId)
|
||||
assignExprMVar mvarId (← mkSorry mvarType (synthetic := true))
|
||||
mvarId.assign (← mkSorry mvarType (synthetic := true))
|
||||
|
||||
def goalsToMessageData (goals : List MVarId) : MessageData :=
|
||||
MessageData.joinSep (goals.map MessageData.ofGoal) m!"\n\n"
|
||||
|
|
@ -48,7 +48,7 @@ structure Context where
|
|||
structure SavedState where
|
||||
term : Term.SavedState
|
||||
tactic : State
|
||||
|
||||
|
||||
abbrev TacticM := ReaderT Context $ StateRefT State TermElabM
|
||||
abbrev Tactic := Syntax → TacticM Unit
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ def setGoals (mvarIds : List MVarId) : TacticM Unit :=
|
|||
|
||||
def pruneSolvedGoals : TacticM Unit := do
|
||||
let gs ← getGoals
|
||||
let gs ← gs.filterM fun g => not <$> isExprMVarAssigned g
|
||||
let gs ← gs.filterM fun g => not <$> g.isAssigned
|
||||
setGoals gs
|
||||
|
||||
def getUnsolvedGoals : TacticM (List MVarId) := do
|
||||
|
|
@ -78,7 +78,7 @@ def getUnsolvedGoals : TacticM (List MVarId) := do
|
|||
Prod.fst <$> x.runCore ctx s
|
||||
|
||||
def run (mvarId : MVarId) (x : TacticM Unit) : TermElabM (List MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let pendingMVarsSaved := (← get).pendingMVars
|
||||
modify fun s => { s with pendingMVars := [] }
|
||||
let aux : TacticM (List MVarId) :=
|
||||
|
|
@ -304,7 +304,7 @@ where
|
|||
loop : List MVarId → TacticM MVarId
|
||||
| [] => throwNoGoalsToBeSolved
|
||||
| mvarId :: mvarIds => do
|
||||
if (← isExprMVarAssigned mvarId) then
|
||||
if (← mvarId.isAssigned) then
|
||||
loop mvarIds
|
||||
else
|
||||
setGoals (mvarId :: mvarIds)
|
||||
|
|
@ -312,7 +312,7 @@ where
|
|||
|
||||
/-- Return the main goal metavariable declaration. -/
|
||||
def getMainDecl : TacticM MetavarDecl := do
|
||||
getMVarDecl (← getMainGoal)
|
||||
(← getMainGoal).getDecl
|
||||
|
||||
/-- Return the main goal tag. -/
|
||||
def getMainTag : TacticM Name :=
|
||||
|
|
@ -324,7 +324,7 @@ def getMainTarget : TacticM Expr := do
|
|||
|
||||
/-- Execute `x` using the main goal local context and instances -/
|
||||
def withMainContext (x : TacticM α) : TacticM α := do
|
||||
withMVarContext (← getMainGoal) x
|
||||
(← getMainGoal).withContext x
|
||||
|
||||
/-- Evaluate `tac` at `mvarId`, and return the list of resulting subgoals. -/
|
||||
def evalTacticAt (tac : Syntax) (mvarId : MVarId) : TacticM (List MVarId) := do
|
||||
|
|
@ -348,7 +348,7 @@ def ensureHasNoMVars (e : Expr) : TacticM Unit := do
|
|||
def closeMainGoal (val : Expr) (checkUnassigned := true): TacticM Unit := do
|
||||
if checkUnassigned then
|
||||
ensureHasNoMVars val
|
||||
assignExprMVar (← getMainGoal) val
|
||||
(← getMainGoal).assign val
|
||||
replaceMainGoal []
|
||||
|
||||
@[inline] def liftMetaMAtMain (x : MVarId → MetaM α) : TacticM α := do
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ private def getOptRotation (stx : Syntax) : Nat :=
|
|||
let mvarIds ← getGoals
|
||||
let mut mvarIdsNew := #[]
|
||||
for mvarId in mvarIds do
|
||||
unless (← isExprMVarAssigned mvarId) do
|
||||
unless (← mvarId.isAssigned) do
|
||||
setGoals [mvarId]
|
||||
try
|
||||
evalTactic stx[1]
|
||||
|
|
@ -134,7 +134,7 @@ private def getOptRotation (stx : Syntax) : Nat :=
|
|||
let mut mvarIdsNew := #[]
|
||||
let mut succeeded := false
|
||||
for mvarId in mvarIds do
|
||||
unless (← isExprMVarAssigned mvarId) do
|
||||
unless (← mvarId.isAssigned) do
|
||||
setGoals [mvarId]
|
||||
try
|
||||
evalTactic stx[1]
|
||||
|
|
@ -181,13 +181,13 @@ partial def evalChoiceAux (tactics : Array Syntax) (i : Nat) : TacticM Unit :=
|
|||
| some msg => withRef stx[0] <| addRawTrace msg
|
||||
|
||||
@[builtinTactic Lean.Parser.Tactic.assumption] def evalAssumption : Tactic := fun _ =>
|
||||
liftMetaTactic fun mvarId => do Meta.assumption mvarId; pure []
|
||||
liftMetaTactic fun mvarId => do mvarId.assumption; pure []
|
||||
|
||||
@[builtinTactic Lean.Parser.Tactic.contradiction] def evalContradiction : Tactic := fun _ =>
|
||||
liftMetaTactic fun mvarId => do Meta.contradiction mvarId; pure []
|
||||
|
||||
@[builtinTactic Lean.Parser.Tactic.refl] def evalRefl : Tactic := fun _ =>
|
||||
liftMetaTactic fun mvarId => do Meta.refl mvarId; pure []
|
||||
liftMetaTactic fun mvarId => do mvarId.refl; pure []
|
||||
|
||||
@[builtinTactic Lean.Parser.Tactic.intro] def evalIntro : Tactic := fun stx => do
|
||||
match stx with
|
||||
|
|
@ -200,7 +200,7 @@ partial def evalChoiceAux (tactics : Array Syntax) (i : Nat) : TacticM Unit :=
|
|||
where
|
||||
introStep (ref : Option Syntax) (n : Name) : TacticM Unit := do
|
||||
let fvar ← liftMetaTacticAux fun mvarId => do
|
||||
let (fvar, mvarId) ← Meta.intro mvarId n
|
||||
let (fvar, mvarId) ← mvarId.intro n
|
||||
pure (fvar, [mvarId])
|
||||
if let some stx := ref then
|
||||
withMainContext do
|
||||
|
|
@ -214,11 +214,11 @@ where
|
|||
@[builtinTactic «intros»] def evalIntros : Tactic := fun stx =>
|
||||
match stx with
|
||||
| `(tactic| intros) => liftMetaTactic fun mvarId => do
|
||||
let (_, mvarId) ← Meta.intros mvarId
|
||||
let (_, mvarId) ← mvarId.intros
|
||||
return [mvarId]
|
||||
| `(tactic| intros $ids*) => do
|
||||
let fvars ← liftMetaTacticAux fun mvarId => do
|
||||
let (fvars, mvarId) ← Meta.introN mvarId ids.size (ids.map getNameOfIdent').toList
|
||||
let (fvars, mvarId) ← mvarId.introN ids.size (ids.map getNameOfIdent').toList
|
||||
return (fvars, [mvarId])
|
||||
withMainContext do
|
||||
for stx in ids, fvar in fvars do
|
||||
|
|
@ -228,7 +228,7 @@ where
|
|||
@[builtinTactic Lean.Parser.Tactic.revert] def evalRevert : Tactic := fun stx =>
|
||||
match stx with
|
||||
| `(tactic| revert $hs*) => do
|
||||
let (_, mvarId) ← Meta.revert (← getMainGoal) (← getFVarIds hs)
|
||||
let (_, mvarId) ← (← getMainGoal).revert (← getFVarIds hs)
|
||||
replaceMainGoal [mvarId]
|
||||
| _ => throwUnsupportedSyntax
|
||||
|
||||
|
|
@ -239,7 +239,7 @@ where
|
|||
let fvarIds ← withMainContext <| sortFVarIds fvarIds
|
||||
for fvarId in fvarIds.reverse do
|
||||
withMainContext do
|
||||
let mvarId ← clear (← getMainGoal) fvarId
|
||||
let mvarId ← (← getMainGoal).clear fvarId
|
||||
replaceMainGoal [mvarId]
|
||||
| _ => throwUnsupportedSyntax
|
||||
|
||||
|
|
@ -263,18 +263,18 @@ def forEachVar (hs : Array Syntax) (tac : MVarId → FVarId → MetaM MVarId) :
|
|||
If none then searches for a metavariable `g` s.t. `tag` is a suffix of its name.
|
||||
If none, then it searches for a metavariable `g` s.t. `tag` is a prefix of its name. -/
|
||||
private def findTag? (mvarIds : List MVarId) (tag : Name) : TacticM (Option MVarId) := do
|
||||
match (← mvarIds.findM? fun mvarId => return tag == (← getMVarDecl mvarId).userName) with
|
||||
match (← mvarIds.findM? fun mvarId => return tag == (← mvarId.getDecl).userName) with
|
||||
| some mvarId => return mvarId
|
||||
| none =>
|
||||
match (← mvarIds.findM? fun mvarId => return tag.isSuffixOf (← getMVarDecl mvarId).userName) with
|
||||
match (← mvarIds.findM? fun mvarId => return tag.isSuffixOf (← mvarId.getDecl).userName) with
|
||||
| some mvarId => return mvarId
|
||||
| none => mvarIds.findM? fun mvarId => return tag.isPrefixOf (← getMVarDecl mvarId).userName
|
||||
| none => mvarIds.findM? fun mvarId => return tag.isPrefixOf (← mvarId.getDecl).userName
|
||||
|
||||
def renameInaccessibles (mvarId : MVarId) (hs : TSyntaxArray ``binderIdent) : TacticM MVarId := do
|
||||
if hs.isEmpty then
|
||||
return mvarId
|
||||
else
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let mut lctx := mvarDecl.lctx
|
||||
let mut hs := hs
|
||||
let mut info := #[]
|
||||
|
|
@ -297,10 +297,10 @@ def renameInaccessibles (mvarId : MVarId) (hs : TSyntaxArray ``binderIdent) : Ta
|
|||
unless hs.isEmpty do
|
||||
logError m!"too many variable names provided"
|
||||
let mvarNew ← mkFreshExprMVarAt lctx mvarDecl.localInstances mvarDecl.type MetavarKind.syntheticOpaque mvarDecl.userName
|
||||
withSaveInfoContext <| withMVarContext mvarNew.mvarId! do
|
||||
withSaveInfoContext <| mvarNew.mvarId!.withContext do
|
||||
for (fvarId, stx) in info do
|
||||
Term.addLocalVarInfo stx (mkFVar fvarId)
|
||||
assignExprMVar mvarId mvarNew
|
||||
mvarId.assign mvarNew
|
||||
return mvarNew.mvarId!
|
||||
|
||||
private def getCaseGoals (tag : TSyntax ``binderIdent) : TacticM (MVarId × List MVarId) := do
|
||||
|
|
@ -318,7 +318,7 @@ private def getCaseGoals (tag : TSyntax ``binderIdent) : TacticM (MVarId × List
|
|||
let (g, gs) ← getCaseGoals tag
|
||||
let g ← renameInaccessibles g hs
|
||||
setGoals [g]
|
||||
setMVarTag g Name.anonymous
|
||||
g.setTag Name.anonymous
|
||||
withCaseRef arr tac do
|
||||
closeUsingOrAdmit (withTacticInfoContext stx (evalTactic tac))
|
||||
setGoals gs
|
||||
|
|
@ -328,12 +328,12 @@ private def getCaseGoals (tag : TSyntax ``binderIdent) : TacticM (MVarId × List
|
|||
| `(tactic| case' $tag $hs* =>%$arr $tac:tacticSeq) => do
|
||||
let (g, gs) ← getCaseGoals tag
|
||||
let g ← renameInaccessibles g hs
|
||||
let mvarTag ← getMVarTag g
|
||||
let mvarTag ← g.getTag
|
||||
setGoals [g]
|
||||
withCaseRef arr tac (evalTactic tac)
|
||||
let gs' ← getUnsolvedGoals
|
||||
if let [g'] := gs' then
|
||||
setMVarTag g' mvarTag
|
||||
g'.setTag mvarTag
|
||||
setGoals (gs' ++ gs)
|
||||
| _ => throwUnsupportedSyntax
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ private def dbg_cache' (cacheRef : IO.Ref Cache) (pos : String.Pos) (mvarId : MV
|
|||
|
||||
private def findCache? (cacheRef : IO.Ref Cache) (mvarId : MVarId) (stx : Syntax) (pos : String.Pos) : TacticM (Option Snapshot) := do
|
||||
let some s := (← cacheRef.get).pre.find? { mvarId, pos } | do dbg_cache "cache key not found"; return none
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let some mvarDeclOld := s.meta.mctx.findDecl? mvarId | return none
|
||||
if equivMVarDecl mvarDecl mvarDeclOld then
|
||||
if stx == s.stx then
|
||||
|
|
|
|||
|
|
@ -43,5 +43,5 @@ def evalCalc : Tactic := fun stx => do
|
|||
return val
|
||||
let val ← instantiateMVars val
|
||||
let mvarId ← getMainGoal
|
||||
assignExprMVar mvarId val
|
||||
mvarId.assign val
|
||||
replaceMainGoal mvarIds
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ def mkConvGoalFor (lhs : Expr) : MetaM (Expr × Expr) := do
|
|||
return (rhs, newGoal)
|
||||
|
||||
def markAsConvGoal (mvarId : MVarId) : MetaM MVarId := do
|
||||
let target ← getMVarType mvarId
|
||||
let target ← mvarId.getType
|
||||
if isLHSGoal? target |>.isSome then
|
||||
return mvarId -- it is already tagged as LHS goal
|
||||
replaceTargetDefEq mvarId (mkLHSGoal (← getMVarType mvarId))
|
||||
mvarId.replaceTargetDefEq (mkLHSGoal (← mvarId.getType))
|
||||
|
||||
/-- Given `lhs`, runs the `conv` tactic with the goal `⊢ lhs = ?rhs`.
|
||||
`conv` should produce no remaining goals that are not solvable with refl.
|
||||
|
|
@ -50,8 +50,8 @@ def convert (lhs : Expr) (conv : TacticM Unit) : TacticM (Expr × Expr) := do
|
|||
return (← instantiateMVars rhs, ← instantiateMVars newGoal)
|
||||
|
||||
def getLhsRhsCore (mvarId : MVarId) : MetaM (Expr × Expr) :=
|
||||
withMVarContext mvarId do
|
||||
let some (_, lhs, rhs) ← matchEq? (← getMVarType mvarId) | throwError "invalid 'conv' goal"
|
||||
mvarId.withContext do
|
||||
let some (_, lhs, rhs) ← matchEq? (← mvarId.getType) | throwError "invalid 'conv' goal"
|
||||
return (lhs, rhs)
|
||||
|
||||
def getLhsRhs : TacticM (Expr × Expr) := do
|
||||
|
|
@ -67,14 +67,14 @@ def getRhs : TacticM Expr :=
|
|||
def updateLhs (lhs' : Expr) (h : Expr) : TacticM Unit := do
|
||||
let rhs ← getRhs
|
||||
let newGoal ← mkFreshExprSyntheticOpaqueMVar (mkLHSGoal (← mkEq lhs' rhs))
|
||||
assignExprMVar (← getMainGoal) (← mkEqTrans h newGoal)
|
||||
(← getMainGoal).assign (← mkEqTrans h newGoal)
|
||||
replaceMainGoal [newGoal.mvarId!]
|
||||
|
||||
/-- Replace `lhs` with the definitionally equal `lhs'`. -/
|
||||
def changeLhs (lhs' : Expr) : TacticM Unit := do
|
||||
let rhs ← getRhs
|
||||
liftMetaTactic1 fun mvarId => do
|
||||
replaceTargetDefEq mvarId (mkLHSGoal (← mkEq lhs' rhs))
|
||||
mvarId.replaceTargetDefEq (mkLHSGoal (← mkEq lhs' rhs))
|
||||
|
||||
@[builtinTactic Lean.Parser.Tactic.Conv.whnf] def evalWhnf : Tactic := fun _ =>
|
||||
withMainContext do
|
||||
|
|
@ -115,11 +115,11 @@ def changeLhs (lhs' : Expr) : TacticM Unit := do
|
|||
|
||||
/-- Mark goals of the form `⊢ a = ?m ..` with the conv goal annotation -/
|
||||
def remarkAsConvGoal : TacticM Unit := do
|
||||
let newGoals ← (← getUnsolvedGoals).mapM fun mvarId => withMVarContext mvarId do
|
||||
let target ← getMVarType mvarId
|
||||
let newGoals ← (← getUnsolvedGoals).mapM fun mvarId => mvarId.withContext do
|
||||
let target ← mvarId.getType
|
||||
if let some (_, _, rhs) ← matchEq? target then
|
||||
if rhs.getAppFn.isMVar then
|
||||
replaceTargetDefEq mvarId (mkLHSGoal target)
|
||||
mvarId.replaceTargetDefEq (mkLHSGoal target)
|
||||
else
|
||||
return mvarId
|
||||
else
|
||||
|
|
@ -135,20 +135,20 @@ def remarkAsConvGoal : TacticM Unit := do
|
|||
let target ← getMainTarget
|
||||
if let some _ := isLHSGoal? target then
|
||||
liftMetaTactic1 fun mvarId =>
|
||||
replaceTargetDefEq mvarId target.mdataExpr!
|
||||
mvarId.replaceTargetDefEq target.mdataExpr!
|
||||
focus do evalTactic seq; remarkAsConvGoal
|
||||
|
||||
private def convTarget (conv : Syntax) : TacticM Unit := withMainContext do
|
||||
let target ← getMainTarget
|
||||
let (targetNew, proof) ← convert target (withTacticInfoContext (← getRef) (evalTactic conv))
|
||||
liftMetaTactic1 fun mvarId => replaceTargetEq mvarId targetNew proof
|
||||
liftMetaTactic1 fun mvarId => mvarId.replaceTargetEq targetNew proof
|
||||
evalTactic (← `(tactic| try rfl))
|
||||
|
||||
private def convLocalDecl (conv : Syntax) (hUserName : Name) : TacticM Unit := withMainContext do
|
||||
let localDecl ← getLocalDeclFromUserName hUserName
|
||||
let (typeNew, proof) ← convert localDecl.type (withTacticInfoContext (← getRef) (evalTactic conv))
|
||||
liftMetaTactic1 fun mvarId =>
|
||||
return some (← replaceLocalDecl mvarId localDecl.fvarId typeNew proof).mvarId
|
||||
return some (← mvarId.replaceLocalDecl localDecl.fvarId typeNew proof).mvarId
|
||||
|
||||
@[builtinTactic Lean.Parser.Tactic.Conv.conv] def evalConv : Tactic := fun stx => do
|
||||
match stx with
|
||||
|
|
|
|||
|
|
@ -40,11 +40,11 @@ private def congrApp (mvarId : MVarId) (lhs rhs : Expr) (addImplicitArgs := fals
|
|||
let proof ← r.getProof
|
||||
unless (← isDefEqGuarded rhs r.expr) do
|
||||
throwError "invalid 'congr' conv tactic, failed to resolve{indentExpr rhs}\n=?={indentExpr r.expr}"
|
||||
assignExprMVar mvarId proof
|
||||
mvarId.assign proof
|
||||
return newGoals.toList
|
||||
|
||||
private def congrImplies (mvarId : MVarId) : MetaM (List MVarId) := do
|
||||
let [mvarId₁, mvarId₂, _, _] ← apply mvarId (← mkConstWithFreshMVarLevels ``implies_congr) | throwError "'apply implies_congr' unexpected result"
|
||||
let [mvarId₁, mvarId₂, _, _] ← mvarId.apply (← mkConstWithFreshMVarLevels ``implies_congr) | throwError "'apply implies_congr' unexpected result"
|
||||
let mvarId₁ ← markAsConvGoal mvarId₁
|
||||
let mvarId₂ ← markAsConvGoal mvarId₂
|
||||
return [mvarId₁, mvarId₂]
|
||||
|
|
@ -57,7 +57,7 @@ def isImplies (e : Expr) : MetaM Bool :=
|
|||
return false
|
||||
|
||||
def congr (mvarId : MVarId) (addImplicitArgs := false) : MetaM (List (Option MVarId)) :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let (lhs, rhs) ← getLhsRhsCore mvarId
|
||||
let lhs := (← instantiateMVars lhs).consumeMData
|
||||
if (← isImplies lhs) then
|
||||
|
|
@ -131,18 +131,18 @@ def extLetBodyCongr? (mvarId : MVarId) (lhs rhs : Expr) : MetaM (Option MVarId)
|
|||
let arg ← mkLambdaFVars #[x] mvarNew
|
||||
return (arg, mvarNew.mvarId!)
|
||||
let val := mkApp6 (mkConst ``let_body_congr [u₁, u₂]) t β f f' v arg
|
||||
assignExprMVar mvarId val
|
||||
mvarId.assign val
|
||||
return some (← markAsConvGoal mvarId')
|
||||
| _ => return none
|
||||
|
||||
private def extCore (mvarId : MVarId) (userName? : Option Name) : MetaM MVarId :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let userNames := if let some userName := userName? then [userName] else []
|
||||
let (lhs, rhs) ← getLhsRhsCore mvarId
|
||||
let lhs ← instantiateMVars lhs
|
||||
if lhs.isForall then
|
||||
let [mvarId, _] ← apply mvarId (← mkConstWithFreshMVarLevels ``forall_congr) | throwError "'apply forall_congr' unexpected result"
|
||||
let (_, mvarId) ← introN mvarId 1 userNames
|
||||
let [mvarId, _] ← mvarId.apply (← mkConstWithFreshMVarLevels ``forall_congr) | throwError "'apply forall_congr' unexpected result"
|
||||
let (_, mvarId) ← mvarId.introN 1 userNames
|
||||
markAsConvGoal mvarId
|
||||
else if let some mvarId ← extLetBodyCongr? mvarId lhs rhs then
|
||||
return mvarId
|
||||
|
|
@ -150,8 +150,8 @@ private def extCore (mvarId : MVarId) (userName? : Option Name) : MetaM MVarId :
|
|||
let lhsType ← whnfD (← inferType lhs)
|
||||
unless lhsType.isForall do
|
||||
throwError "invalid 'ext' conv tactic, function or arrow expected{indentD m!"{lhs} : {lhsType}"}"
|
||||
let [mvarId] ← apply mvarId (← mkConstWithFreshMVarLevels ``funext) | throwError "'apply funext' unexpected result"
|
||||
let (_, mvarId) ← introN mvarId 1 userNames
|
||||
let [mvarId] ← mvarId.apply (← mkConstWithFreshMVarLevels ``funext) | throwError "'apply funext' unexpected result"
|
||||
let (_, mvarId) ← mvarId.introN 1 userNames
|
||||
markAsConvGoal mvarId
|
||||
|
||||
private def ext (userName? : Option Name) : TacticM Unit := do
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ open Meta
|
|||
withRWRulesSeq stx[0] stx[2] fun symm term => do
|
||||
Term.withSynthesize <| withMainContext do
|
||||
let e ← elabTerm term none true
|
||||
let r ← rewrite (← getMainGoal) (← getLhs) e symm (config := config)
|
||||
let r ← (← getMainGoal).rewrite (← getLhs) e symm (config := config)
|
||||
updateLhs r.eNew r.eqProof
|
||||
replaceMainGoal ((← getMainGoal) :: r.mvarIds)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ def deltaLocalDecl (declName : Name) (fvarId : FVarId) : TacticM Unit := do
|
|||
let typeNew ← deltaExpand localDecl.type (· == declName)
|
||||
if typeNew == localDecl.type then
|
||||
throwTacticEx `delta mvarId m!"did not delta reduce '{declName}' at '{localDecl.userName}'"
|
||||
replaceMainGoal [← replaceLocalDeclDefEq mvarId fvarId typeNew]
|
||||
replaceMainGoal [← mvarId.replaceLocalDeclDefEq fvarId typeNew]
|
||||
|
||||
def deltaTarget (declName : Name) : TacticM Unit := do
|
||||
let mvarId ← getMainGoal
|
||||
|
|
@ -24,7 +24,7 @@ def deltaTarget (declName : Name) : TacticM Unit := do
|
|||
let targetNew ← deltaExpand target (· == declName)
|
||||
if targetNew == target then
|
||||
throwTacticEx `delta mvarId m!"did not delta reduce '{declName}'"
|
||||
replaceMainGoal [← replaceTargetDefEq mvarId targetNew]
|
||||
replaceMainGoal [← mvarId.replaceTargetDefEq targetNew]
|
||||
|
||||
/--
|
||||
"delta " ident (location)?
|
||||
|
|
|
|||
|
|
@ -76,8 +76,8 @@ def withCollectingNewGoalsFrom (k : TacticM Expr) (tagSuffix : Name) (allowNatur
|
|||
let newMVarIds ← if allowNaturalHoles then
|
||||
pure newMVarIds.toList
|
||||
else
|
||||
let naturalMVarIds ← newMVarIds.filterM fun mvarId => return (← getMVarDecl mvarId).kind.isNatural
|
||||
let syntheticMVarIds ← newMVarIds.filterM fun mvarId => return !(← getMVarDecl mvarId).kind.isNatural
|
||||
let naturalMVarIds ← newMVarIds.filterM fun mvarId => return (← mvarId.getKind).isNatural
|
||||
let syntheticMVarIds ← newMVarIds.filterM fun mvarId => return !(← mvarId.getKind).isNatural
|
||||
let naturalMVarIds ← filterOldMVars naturalMVarIds mvarCounterSaved
|
||||
logUnassignedAndAbort naturalMVarIds
|
||||
pure syntheticMVarIds.toList
|
||||
|
|
@ -99,7 +99,7 @@ def refineCore (stx : Syntax) (tagSuffix : Name) (allowNaturalHoles : Bool) : Ta
|
|||
unless val == mkMVar mvarId do
|
||||
if val.findMVar? (· == mvarId) matches some _ then
|
||||
throwError "'refine' tactic failed, value{indentExpr val}\ndepends on the main goal metavariable '{mkMVar mvarId}'"
|
||||
assignExprMVar mvarId val
|
||||
mvarId.assign val
|
||||
replaceMainGoal mvarIds'
|
||||
|
||||
@[builtinTactic «refine»] def evalRefine : Tactic := fun stx =>
|
||||
|
|
@ -119,9 +119,9 @@ def refineCore (stx : Syntax) (tagSuffix : Name) (allowNaturalHoles : Bool) : Ta
|
|||
let h := e.getAppFn
|
||||
if h.isFVar then
|
||||
let localDecl ← getLocalDecl h.fvarId!
|
||||
let mvarId ← assert (← getMainGoal) localDecl.userName (← inferType e).headBeta e
|
||||
let (_, mvarId) ← intro1P mvarId
|
||||
let mvarId ← tryClear mvarId h.fvarId!
|
||||
let mvarId ← (← getMainGoal).assert localDecl.userName (← inferType e).headBeta e
|
||||
let (_, mvarId) ← mvarId.intro1P
|
||||
let mvarId ← mvarId.tryClear h.fvarId!
|
||||
replaceMainGoal (mvarId :: mvarIds')
|
||||
else
|
||||
throwError "'specialize' requires a term of the form `h x_1 .. x_n` where `h` appears in the local context"
|
||||
|
|
@ -205,12 +205,12 @@ def getFVarIds (ids : Array Syntax) : TacticM (Array FVarId) := do
|
|||
|
||||
@[builtinTactic Lean.Parser.Tactic.apply] def evalApply : Tactic := fun stx =>
|
||||
match stx with
|
||||
| `(tactic| apply $e) => evalApplyLikeTactic Meta.apply e
|
||||
| `(tactic| apply $e) => evalApplyLikeTactic (·.apply) e
|
||||
| _ => throwUnsupportedSyntax
|
||||
|
||||
@[builtinTactic Lean.Parser.Tactic.constructor] def evalConstructor : Tactic := fun _ =>
|
||||
withMainContext do
|
||||
let mvarIds' ← Meta.constructor (← getMainGoal)
|
||||
let mvarIds' ← (← getMainGoal).constructor
|
||||
Term.synthesizeSyntheticMVarsNoPostponing
|
||||
replaceMainGoal mvarIds'
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ def elabAsFVar (stx : Syntax) (userName? : Option Name := none) : TacticM FVarId
|
|||
let intro (userName : Name) (preserveBinderNames : Bool) : TacticM FVarId := do
|
||||
let mvarId ← getMainGoal
|
||||
let (fvarId, mvarId) ← liftMetaM do
|
||||
let mvarId ← Meta.assert mvarId userName type e
|
||||
let mvarId ← mvarId.assert userName type e
|
||||
Meta.intro1Core mvarId preserveBinderNames
|
||||
replaceMainGoal [mvarId]
|
||||
return fvarId
|
||||
|
|
@ -258,7 +258,7 @@ def elabAsFVar (stx : Syntax) (userName? : Option Name := none) : TacticM FVarId
|
|||
match fvarId? with
|
||||
| none => throwError "failed to find a hypothesis with type{indentExpr type}"
|
||||
| some fvarId => return fvarId
|
||||
replaceMainGoal [← rename (← getMainGoal) fvarId h.getId]
|
||||
replaceMainGoal [← (← getMainGoal).rename fvarId h.getId]
|
||||
| _ => throwUnsupportedSyntax
|
||||
|
||||
/--
|
||||
|
|
|
|||
|
|
@ -55,10 +55,10 @@ def evalAlt (mvarId : MVarId) (alt : Syntax) (remainingGoals : Array MVarId) : T
|
|||
let rhs := getAltRHS alt
|
||||
withCaseRef (getAltDArrow alt) rhs do
|
||||
if isHoleRHS rhs then
|
||||
let gs' ← withMVarContext mvarId $ withRef rhs do
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let gs' ← mvarId.withContext <| withRef rhs do
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let val ← elabTermEnsuringType rhs mvarDecl.type
|
||||
assignExprMVar mvarId val
|
||||
mvarId.assign val
|
||||
let gs' ← getMVarsNoDelayed val
|
||||
tagUntaggedGoals mvarDecl.userName `induction gs'.toList
|
||||
pure gs'
|
||||
|
|
@ -156,12 +156,12 @@ partial def mkElimApp (elimInfo : ElimInfo) (targets : Array Expr) (tag : Name)
|
|||
for mvarId in s.insts do
|
||||
try
|
||||
unless (← Term.synthesizeInstMVarCore mvarId) do
|
||||
setMVarKind mvarId MetavarKind.syntheticOpaque
|
||||
mvarId.setKind .syntheticOpaque
|
||||
others := others.push mvarId
|
||||
catch _ =>
|
||||
setMVarKind mvarId MetavarKind.syntheticOpaque
|
||||
mvarId.setKind .syntheticOpaque
|
||||
others := others.push mvarId
|
||||
let alts ← s.alts.filterM fun alt => return !(← isExprMVarAssigned alt.2)
|
||||
let alts ← s.alts.filterM fun alt => return !(← alt.2.isAssigned)
|
||||
return { elimApp := (← instantiateMVars s.f), alts, others := others }
|
||||
|
||||
/-- Given a goal `... targets ... |- C[targets]` associated with `mvarId`, assign
|
||||
|
|
@ -173,7 +173,7 @@ def setMotiveArg (mvarId : MVarId) (motiveArg : MVarId) (targets : Array FVarId)
|
|||
let motiveType ← inferType (mkMVar motiveArg)
|
||||
unless (← isDefEqGuarded motiverInferredType motiveType) do
|
||||
throwError "type mismatch when assigning motive{indentExpr motive}\n{← mkHasTypeButIsExpectedMsg motiverInferredType motiveType}"
|
||||
assignExprMVar motiveArg motive
|
||||
motiveArg.assign motive
|
||||
|
||||
private def getAltNumFields (elimInfo : ElimInfo) (altName : Name) : TermElabM Nat := do
|
||||
for altInfo in elimInfo.altsInfo do
|
||||
|
|
@ -194,14 +194,14 @@ private def checkAltNames (alts : Array (Name × MVarId)) (altsSyntax : Array Sy
|
|||
/-- Given the goal `altMVarId` for a given alternative that introduces `numFields` new variables,
|
||||
return the number of explicit variables. Recall that when the `@` is not used, only the explicit variables can
|
||||
be named by the user. -/
|
||||
private def getNumExplicitFields (altMVarId : MVarId) (numFields : Nat) : MetaM Nat := withMVarContext altMVarId do
|
||||
let target ← getMVarType altMVarId
|
||||
private def getNumExplicitFields (altMVarId : MVarId) (numFields : Nat) : MetaM Nat := altMVarId.withContext do
|
||||
let target ← altMVarId.getType
|
||||
withoutModifyingState do
|
||||
let (_, bis, _) ← forallMetaBoundedTelescope target numFields
|
||||
return bis.foldl (init := 0) fun r bi => if bi.isExplicit then r + 1 else r
|
||||
|
||||
private def saveAltVarsInfo (altMVarId : MVarId) (altStx : Syntax) (fvarIds : Array FVarId) : TacticM Unit :=
|
||||
withSaveInfoContext <| withMVarContext altMVarId do
|
||||
withSaveInfoContext <| altMVarId.withContext do
|
||||
let useNamesForExplicitOnly := !altHasExplicitModifier altStx
|
||||
let mut i := 0
|
||||
let altVars := getAltVars altStx
|
||||
|
|
@ -277,13 +277,13 @@ where
|
|||
pure none
|
||||
match altStx? with
|
||||
| none =>
|
||||
let mut (_, altMVarId) ← introN altMVarId numFields
|
||||
let mut (_, altMVarId) ← altMVarId.introN numFields
|
||||
match (← Cases.unifyEqs? numEqs altMVarId {}) with
|
||||
| none => pure () -- alternative is not reachable
|
||||
| some (altMVarId', _) =>
|
||||
(_, altMVarId) ← introNP altMVarId' numGeneralized
|
||||
(_, altMVarId) ← altMVarId'.introNP numGeneralized
|
||||
for fvarId in toClear do
|
||||
altMVarId ← tryClear altMVarId fvarId
|
||||
altMVarId ← altMVarId.tryClear fvarId
|
||||
let altMVarIds ← applyPreTac altMVarId
|
||||
if !hasAlts then
|
||||
-- User did not provide alternatives using `|`
|
||||
|
|
@ -304,14 +304,14 @@ where
|
|||
let numFieldsToName ← if altHasExplicitModifier altStx then pure numFields else getNumExplicitFields altMVarId numFields
|
||||
if altVarNames.size > numFieldsToName then
|
||||
logError m!"too many variable names provided at alternative '{altName}', #{altVarNames.size} provided, but #{numFieldsToName} expected"
|
||||
let mut (fvarIds, altMVarId) ← introN altMVarId numFields altVarNames.toList (useNamesForExplicitOnly := !altHasExplicitModifier altStx)
|
||||
let mut (fvarIds, altMVarId) ← altMVarId.introN numFields altVarNames.toList (useNamesForExplicitOnly := !altHasExplicitModifier altStx)
|
||||
saveAltVarsInfo altMVarId altStx fvarIds
|
||||
match (← Cases.unifyEqs? numEqs altMVarId {}) with
|
||||
| none => unusedAlt
|
||||
| some (altMVarId', _) =>
|
||||
(_, altMVarId) ← introNP altMVarId' numGeneralized
|
||||
(_, altMVarId) ← altMVarId'.introNP numGeneralized
|
||||
for fvarId in toClear do
|
||||
altMVarId ← tryClear altMVarId fvarId
|
||||
altMVarId ← altMVarId.tryClear fvarId
|
||||
let altMVarIds ← applyPreTac altMVarId
|
||||
if altMVarIds.isEmpty then
|
||||
unusedAlt
|
||||
|
|
@ -352,7 +352,7 @@ private def getUserGeneralizingFVarIds (stx : Syntax) : TacticM (Array FVarId) :
|
|||
|
||||
-- process `generalizingVars` subterm of induction Syntax `stx`.
|
||||
private def generalizeVars (mvarId : MVarId) (stx : Syntax) (targets : Array Expr) : TacticM (Nat × MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let userFVarIds ← getUserGeneralizingFVarIds stx
|
||||
let forbidden ← mkGeneralizationForbiddenSet targets
|
||||
let mut s ← getFVarSetToGeneralize targets forbidden
|
||||
|
|
@ -363,7 +363,7 @@ private def generalizeVars (mvarId : MVarId) (stx : Syntax) (targets : Array Exp
|
|||
throwError "unnecessary 'generalizing' argument, variable '{mkFVar userFVarId}' is generalized automatically"
|
||||
s := s.insert userFVarId
|
||||
let fvarIds ← sortFVarIds s.toArray
|
||||
let (fvarIds, mvarId') ← Meta.revert mvarId fvarIds
|
||||
let (fvarIds, mvarId') ← mvarId.revert fvarIds
|
||||
return (fvarIds.size, mvarId')
|
||||
|
||||
/--
|
||||
|
|
@ -509,20 +509,20 @@ private def generalizeTargets (exprs : Array Expr) : TacticM (Array Expr) := do
|
|||
let mvarId ← getMainGoal
|
||||
-- save initial info before main goal is reassigned
|
||||
let initInfo ← mkTacticInfo (← getMCtx) (← getUnsolvedGoals) (← getRef)
|
||||
let tag ← getMVarTag mvarId
|
||||
withMVarContext mvarId do
|
||||
let tag ← mvarId.getTag
|
||||
mvarId.withContext do
|
||||
let targets ← addImplicitTargets elimInfo targets
|
||||
checkTargets targets
|
||||
let targetFVarIds := targets.map (·.fvarId!)
|
||||
let (n, mvarId) ← generalizeVars mvarId stx targets
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let result ← withRef stx[1] do -- use target position as reference
|
||||
ElimApp.mkElimApp elimInfo targets tag
|
||||
trace[Elab.induction] "elimApp: {result.elimApp}"
|
||||
let elimArgs := result.elimApp.getAppArgs
|
||||
ElimApp.setMotiveArg mvarId elimArgs[elimInfo.motivePos]!.mvarId! targetFVarIds
|
||||
let optPreTac := getOptPreTacOfOptInductionAlts optInductionAlts
|
||||
assignExprMVar mvarId result.elimApp
|
||||
mvarId.assign result.elimApp
|
||||
ElimApp.evalAlts elimInfo result.alts optPreTac alts initInfo (numGeneralized := n) (toClear := targetFVarIds)
|
||||
appendGoals result.others.toList
|
||||
where
|
||||
|
|
@ -570,18 +570,18 @@ def elabCasesTargets (targets : Array Syntax) : TacticM (Array Expr) :=
|
|||
let mvarId ← getMainGoal
|
||||
-- save initial info before main goal is reassigned
|
||||
let initInfo ← mkTacticInfo (← getMCtx) (← getUnsolvedGoals) (← getRef)
|
||||
let tag ← getMVarTag mvarId
|
||||
withMVarContext mvarId do
|
||||
let tag ← mvarId.getTag
|
||||
mvarId.withContext do
|
||||
let targets ← addImplicitTargets elimInfo targets
|
||||
let result ← withRef targetRef <| ElimApp.mkElimApp elimInfo targets tag
|
||||
let elimArgs := result.elimApp.getAppArgs
|
||||
let targets ← elimInfo.targetsPos.mapM fun i => instantiateMVars elimArgs[i]!
|
||||
let motiveType ← inferType elimArgs[elimInfo.motivePos]!
|
||||
let mvarId ← generalizeTargetsEq mvarId motiveType targets
|
||||
let (targetsNew, mvarId) ← introN mvarId targets.size
|
||||
withMVarContext mvarId do
|
||||
let (targetsNew, mvarId) ← mvarId.introN targets.size
|
||||
mvarId.withContext do
|
||||
ElimApp.setMotiveArg mvarId elimArgs[elimInfo.motivePos]!.mvarId! targetsNew
|
||||
assignExprMVar mvarId result.elimApp
|
||||
mvarId.assign result.elimApp
|
||||
ElimApp.evalAlts elimInfo result.alts optPreTac alts initInfo (numEqs := targets.size) (toClear := targetsNew)
|
||||
|
||||
builtin_initialize
|
||||
|
|
|
|||
|
|
@ -15,16 +15,16 @@ open Meta
|
|||
def rewriteTarget (stx : Syntax) (symm : Bool) (config : Rewrite.Config) : TacticM Unit := do
|
||||
Term.withSynthesize <| withMainContext do
|
||||
let e ← elabTerm stx none true
|
||||
let r ← rewrite (← getMainGoal) (← getMainTarget) e symm (config := config)
|
||||
let mvarId' ← replaceTargetEq (← getMainGoal) r.eNew r.eqProof
|
||||
let r ← (← getMainGoal).rewrite (← getMainTarget) e symm (config := config)
|
||||
let mvarId' ← (← getMainGoal).replaceTargetEq r.eNew r.eqProof
|
||||
replaceMainGoal (mvarId' :: r.mvarIds)
|
||||
|
||||
def rewriteLocalDecl (stx : Syntax) (symm : Bool) (fvarId : FVarId) (config : Rewrite.Config) : TacticM Unit := do
|
||||
Term.withSynthesize <| withMainContext do
|
||||
let e ← elabTerm stx none true
|
||||
let localDecl ← getLocalDecl fvarId
|
||||
let rwResult ← rewrite (← getMainGoal) localDecl.type e symm (config := config)
|
||||
let replaceResult ← replaceLocalDecl (← getMainGoal) fvarId rwResult.eNew rwResult.eqProof
|
||||
let rwResult ← (← getMainGoal).rewrite localDecl.type e symm (config := config)
|
||||
let replaceResult ← (← getMainGoal).replaceLocalDecl fvarId rwResult.eNew rwResult.eqProof
|
||||
replaceMainGoal (replaceResult.mvarId :: rwResult.mvarIds)
|
||||
|
||||
def withRWRulesSeq (token : Syntax) (rwRulesSeqStx : Syntax) (x : (symm : Bool) → (term : Syntax) → TacticM Unit) : TacticM Unit := do
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ def simpLocation (ctx : Simp.Context) (discharge? : Option Simp.Discharge := non
|
|||
go fvarIds simplifyTarget fvarIdToLemmaId
|
||||
| Location.wildcard =>
|
||||
withMainContext do
|
||||
go (← getNondepPropHyps (← getMainGoal)) (simplifyTarget := true) fvarIdToLemmaId
|
||||
go (← (← getMainGoal).getNondepPropHyps) (simplifyTarget := true) fvarIdToLemmaId
|
||||
where
|
||||
go (fvarIdsToSimp : Array FVarId) (simplifyTarget : Bool) (fvarIdToLemmaId : Lean.Meta.FVarIdToLemmaId) : TacticM Unit := do
|
||||
let mvarId ← getMainGoal
|
||||
|
|
@ -297,7 +297,7 @@ def dsimpLocation (ctx : Simp.Context) (loc : Location) : TacticM Unit := do
|
|||
go fvarIds simplifyTarget
|
||||
| Location.wildcard =>
|
||||
withMainContext do
|
||||
go (← getNondepPropHyps (← getMainGoal)) (simplifyTarget := true)
|
||||
go (← (← getMainGoal).getNondepPropHyps) (simplifyTarget := true)
|
||||
where
|
||||
go (fvarIdsToSimp : Array FVarId) (simplifyTarget : Bool) : TacticM Unit := do
|
||||
let mvarId ← getMainGoal
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ open Meta
|
|||
return mvarIds
|
||||
| Location.wildcard =>
|
||||
liftMetaTactic fun mvarId => do
|
||||
let fvarIds ← getNondepPropHyps mvarId
|
||||
let fvarIds ← mvarId.getNondepPropHyps
|
||||
for fvarId in fvarIds do
|
||||
if let some mvarIds ← splitLocalDecl? mvarId fvarId then
|
||||
return mvarIds
|
||||
|
|
|
|||
|
|
@ -562,7 +562,7 @@ def logUnassignedUsingErrorInfos (pendingMVarIds : Array MVarId) (extraMsg? : Op
|
|||
-- To sort the errors by position use
|
||||
-- let sortedErrors := errors.qsort fun e₁ e₂ => e₁.ref.getPos?.getD 0 < e₂.ref.getPos?.getD 0
|
||||
for error in errors do
|
||||
withMVarContext error.mvarId do
|
||||
error.mvarId.withContext do
|
||||
error.logError extraMsg?
|
||||
return hasNewErrors
|
||||
|
||||
|
|
@ -717,7 +717,7 @@ def synthesizeInstMVarCore (instMVar : MVarId) (maxResultSize? : Option Nat := n
|
|||
let result ← trySynthInstance type maxResultSize?
|
||||
match result with
|
||||
| LOption.some val =>
|
||||
if (← isExprMVarAssigned instMVar) then
|
||||
if (← instMVar.isAssigned) then
|
||||
let oldVal ← instantiateMVars (mkMVar instMVar)
|
||||
unless (← isDefEq oldVal val) do
|
||||
if (← containsPendingMVar oldVal <||> containsPendingMVar val) then
|
||||
|
|
@ -1485,7 +1485,7 @@ where
|
|||
match mvarIds with
|
||||
| [] => return result
|
||||
| mvarId :: mvarIds => do
|
||||
if (← isExprMVarAssigned mvarId) then
|
||||
if (← mvarId.isAssigned) then
|
||||
go mvarIds result
|
||||
else if result.contains (mkMVar mvarId) || except mvarId then
|
||||
go mvarIds result
|
||||
|
|
@ -1778,7 +1778,7 @@ def exprToSyntax (e : Expr) : TermElabM Term := withFreshMacroScope do
|
|||
let result ← `(?m)
|
||||
let eType ← inferType e
|
||||
let mvar ← elabTerm result eType
|
||||
assignExprMVar mvar.mvarId! e
|
||||
mvar.mvarId!.assign e
|
||||
return result
|
||||
|
||||
end Term
|
||||
|
|
|
|||
|
|
@ -207,9 +207,9 @@ def mkCongr (h₁ h₂ : Expr) : MetaM Expr := do
|
|||
|
||||
private def mkAppMFinal (methodName : Name) (f : Expr) (args : Array Expr) (instMVars : Array MVarId) : MetaM Expr := do
|
||||
instMVars.forM fun mvarId => do
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let mvarVal ← synthInstance mvarDecl.type
|
||||
assignExprMVar mvarId mvarVal
|
||||
mvarId.assign mvarVal
|
||||
let result ← instantiateMVars (mkAppN f args)
|
||||
if (← hasAssignableMVar result) then throwAppBuilderException methodName ("result contains metavariables" ++ indentExpr result)
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -516,41 +516,69 @@ def shouldReduceAll : MetaM Bool :=
|
|||
def shouldReduceReducibleOnly : MetaM Bool :=
|
||||
return (← getTransparency) == TransparencyMode.reducible
|
||||
|
||||
def findMVarDecl? (mvarId : MVarId) : MetaM (Option MetavarDecl) :=
|
||||
def _root_.Lean.MVarId.findDecl? (mvarId : MVarId) : MetaM (Option MetavarDecl) :=
|
||||
return (← getMCtx).findDecl? mvarId
|
||||
|
||||
def getMVarDecl (mvarId : MVarId) : MetaM MetavarDecl := do
|
||||
match (← findMVarDecl? mvarId) with
|
||||
@[deprecated MVarId.findDecl?]
|
||||
def findMVarDecl? (mvarId : MVarId) : MetaM (Option MetavarDecl) :=
|
||||
mvarId.findDecl?
|
||||
|
||||
def _root_.Lean.MVarId.getDecl (mvarId : MVarId) : MetaM MetavarDecl := do
|
||||
match (← mvarId.findDecl?) with
|
||||
| some d => pure d
|
||||
| none => throwError "unknown metavariable '?{mvarId.name}'"
|
||||
|
||||
@[deprecated MVarId.getDecl]
|
||||
def getMVarDecl (mvarId : MVarId) : MetaM MetavarDecl := do
|
||||
mvarId.getDecl
|
||||
|
||||
def _root_.Lean.MVarId.getKind (mvarId : MVarId) : MetaM MetavarKind :=
|
||||
return (← mvarId.getDecl).kind
|
||||
|
||||
@[deprecated MVarId.getKind]
|
||||
def getMVarDeclKind (mvarId : MVarId) : MetaM MetavarKind :=
|
||||
return (← getMVarDecl mvarId).kind
|
||||
mvarId.getKind
|
||||
|
||||
/-- Reture `true` if `e` is a synthetic (or synthetic opaque) metavariable -/
|
||||
def isSyntheticMVar (e : Expr) : MetaM Bool := do
|
||||
if e.isMVar then
|
||||
return (← getMVarDeclKind e.mvarId!) matches .synthetic | .syntheticOpaque
|
||||
return (← e.mvarId!.getKind) matches .synthetic | .syntheticOpaque
|
||||
else
|
||||
return false
|
||||
|
||||
def setMVarKind (mvarId : MVarId) (kind : MetavarKind) : MetaM Unit :=
|
||||
def _root_.Lean.MVarId.setKind (mvarId : MVarId) (kind : MetavarKind) : MetaM Unit :=
|
||||
modifyMCtx fun mctx => mctx.setMVarKind mvarId kind
|
||||
|
||||
@[deprecated MVarId.setKind]
|
||||
def setMVarKind (mvarId : MVarId) (kind : MetavarKind) : MetaM Unit :=
|
||||
mvarId.setKind kind
|
||||
|
||||
/-- Update the type of the given metavariable. This function assumes the new type is
|
||||
definitionally equal to the current one -/
|
||||
def setMVarType (mvarId : MVarId) (type : Expr) : MetaM Unit := do
|
||||
def _root_.Lean.MVarId.setType (mvarId : MVarId) (type : Expr) : MetaM Unit := do
|
||||
modifyMCtx fun mctx => mctx.setMVarType mvarId type
|
||||
|
||||
def isReadOnlyExprMVar (mvarId : MVarId) : MetaM Bool := do
|
||||
return (← getMVarDecl mvarId).depth != (← getMCtx).depth
|
||||
@[deprecated MVarId.setType]
|
||||
def setMVarType (mvarId : MVarId) (type : Expr) : MetaM Unit := do
|
||||
mvarId.setType type
|
||||
|
||||
def isReadOnlyOrSyntheticOpaqueExprMVar (mvarId : MVarId) : MetaM Bool := do
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
def _root_.Lean.MVarId.isReadOnly (mvarId : MVarId) : MetaM Bool := do
|
||||
return (← mvarId.getDecl).depth != (← getMCtx).depth
|
||||
|
||||
@[deprecated MVarId.isReadOnly]
|
||||
def isReadOnlyExprMVar (mvarId : MVarId) : MetaM Bool := do
|
||||
mvarId.isReadOnly
|
||||
|
||||
def _root_.Lean.MVarId.isReadOnlyOrSyntheticOpaque (mvarId : MVarId) : MetaM Bool := do
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
match mvarDecl.kind with
|
||||
| MetavarKind.syntheticOpaque => return !(← getConfig).assignSyntheticOpaque
|
||||
| _ => return mvarDecl.depth != (← getMCtx).depth
|
||||
|
||||
@[deprecated MVarId.isReadOnlyOrSyntheticOpaque]
|
||||
def isReadOnlyOrSyntheticOpaqueExprMVar (mvarId : MVarId) : MetaM Bool := do
|
||||
mvarId.isReadOnlyOrSyntheticOpaque
|
||||
|
||||
def getLevelMVarDepth (mvarId : LMVarId) : MetaM Nat := do
|
||||
match (← getMCtx).findLevelDepth? mvarId with
|
||||
| some depth => return depth
|
||||
|
|
@ -562,9 +590,13 @@ def isReadOnlyLevelMVar (mvarId : LMVarId) : MetaM Bool := do
|
|||
else
|
||||
return (← getLevelMVarDepth mvarId) != (← getMCtx).depth
|
||||
|
||||
def setMVarUserName (mvarId : MVarId) (newUserName : Name) : MetaM Unit :=
|
||||
def _root_.Lean.MVarId.setUserName (mvarId : MVarId) (newUserName : Name) : MetaM Unit :=
|
||||
modifyMCtx fun mctx => mctx.setMVarUserName mvarId newUserName
|
||||
|
||||
@[deprecated MVarId.setUserName]
|
||||
def setMVarUserName (mvarId : MVarId) (userNameNew : Name) : MetaM Unit :=
|
||||
mvarId.setUserName userNameNew
|
||||
|
||||
def throwUnknownFVar (fvarId : FVarId) : MetaM α :=
|
||||
throwError "unknown free variable '{mkFVar fvarId}'"
|
||||
|
||||
|
|
@ -1184,16 +1216,20 @@ def withLCtx (lctx : LocalContext) (localInsts : LocalInstances) : n α → n α
|
|||
mapMetaM <| withLocalContextImp lctx localInsts
|
||||
|
||||
private def withMVarContextImp (mvarId : MVarId) (x : MetaM α) : MetaM α := do
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
withLocalContextImp mvarDecl.lctx mvarDecl.localInstances x
|
||||
|
||||
/--
|
||||
Execute `x` using the given metavariable `LocalContext` and `LocalInstances`.
|
||||
The type class resolution cache is flushed when executing `x` if its `LocalInstances` are
|
||||
different from the current ones. -/
|
||||
def withMVarContext (mvarId : MVarId) : n α → n α :=
|
||||
def _root_.Lean.MVarId.withContext (mvarId : MVarId) : n α → n α :=
|
||||
mapMetaM <| withMVarContextImp mvarId
|
||||
|
||||
@[deprecated MVarId.withContext]
|
||||
def withMVarContext (mvarId : MVarId) : n α → n α :=
|
||||
mvarId.withContext
|
||||
|
||||
private def withMCtxImp (mctx : MetavarContext) (x : MetaM α) : MetaM α := do
|
||||
let mctx' ← getMCtx
|
||||
setMCtx mctx
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ partial def collectExprAux (e : Expr) : ClosureM Expr := do
|
|||
| Expr.sort u => return e.updateSort! (← collectLevel u)
|
||||
| Expr.const _ us => return e.updateConst! (← us.mapM collectLevel)
|
||||
| Expr.mvar mvarId =>
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let type ← preprocess mvarDecl.type
|
||||
let type ← collect type
|
||||
let newFVarId ← mkFreshFVarId
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ def getMVars (e : Expr) : MetaM (Array MVarId) := do
|
|||
/-- Similar to getMVars, but removes delayed assignments. -/
|
||||
def getMVarsNoDelayed (e : Expr) : MetaM (Array MVarId) := do
|
||||
let mvarIds ← getMVars e
|
||||
mvarIds.filterM fun mvarId => not <$> isMVarDelayedAssigned mvarId
|
||||
mvarIds.filterM fun mvarId => not <$> mvarId.isDelayedAssigned
|
||||
|
||||
def collectMVarsAtDecl (d : Declaration) : StateRefT CollectMVars.State MetaM Unit :=
|
||||
d.forExprM collectMVars
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ private def pushArgs (root : Bool) (todo : Array Expr) (e : Expr) : MetaM (Key
|
|||
if mvarId == tmpMVarId then
|
||||
-- We use `tmp to mark implicit arguments and proofs
|
||||
return (Key.star, todo)
|
||||
else if (← isReadOnlyOrSyntheticOpaqueExprMVar mvarId) then
|
||||
else if (← mvarId.isReadOnlyOrSyntheticOpaque) then
|
||||
return (Key.other, todo)
|
||||
else
|
||||
return (Key.star, todo)
|
||||
|
|
@ -424,7 +424,7 @@ private def getKeyArgs (e : Expr) (isMatch root : Bool) : MetaM (Key × Array Ex
|
|||
This is incorrect because it is equivalent to saying that there is no solution even if
|
||||
the caller assigns `?m` and try again. -/
|
||||
return (Key.star, #[])
|
||||
else if (← isReadOnlyOrSyntheticOpaqueExprMVar mvarId) then
|
||||
else if (← mvarId.isReadOnlyOrSyntheticOpaque) then
|
||||
return (Key.other, #[])
|
||||
else
|
||||
return (Key.star, #[])
|
||||
|
|
|
|||
|
|
@ -125,9 +125,9 @@ def isDefEqStringLit (s t : Expr) : MetaM LBool := do
|
|||
def isEtaUnassignedMVar (e : Expr) : MetaM Bool := do
|
||||
match e.etaExpanded? with
|
||||
| some (Expr.mvar mvarId) =>
|
||||
if (← isReadOnlyOrSyntheticOpaqueExprMVar mvarId) then
|
||||
if (← mvarId.isReadOnlyOrSyntheticOpaque) then
|
||||
pure false
|
||||
else if (← isExprMVarAssigned mvarId) then
|
||||
else if (← mvarId.isAssigned) then
|
||||
pure false
|
||||
else
|
||||
pure true
|
||||
|
|
@ -324,7 +324,7 @@ private def checkTypesAndAssign (mvar : Expr) (v : Expr) : MetaM Bool :=
|
|||
let vType ← inferType v
|
||||
if (← withTransparency TransparencyMode.default <| Meta.isExprDefEqAux mvarType vType) then
|
||||
trace[Meta.isDefEq.assign.final] "{mvar} := {v}"
|
||||
assignExprMVar mvar.mvarId! v
|
||||
mvar.mvarId!.assign v
|
||||
pure true
|
||||
else
|
||||
trace[Meta.isDefEq.assign.typeMismatch] "{mvar} : {mvarType} := {v} : {vType}"
|
||||
|
|
@ -655,7 +655,7 @@ private def addAssignmentInfo (msg : MessageData) : CheckAssignmentM MessageData
|
|||
return m!"{msg} @ {mkMVar ctx.mvarId} {ctx.fvars} := {ctx.rhs}"
|
||||
|
||||
@[inline] def run (x : CheckAssignmentM Expr) (mvarId : MVarId) (fvars : Array Expr) (hasCtxLocals : Bool) (v : Expr) : MetaM (Option Expr) := do
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let ctx := { mvarId := mvarId, mvarDecl := mvarDecl, fvars := fvars, hasCtxLocals := hasCtxLocals, rhs := v : Context }
|
||||
let x : CheckAssignmentM (Option Expr) :=
|
||||
catchInternalIds [outOfScopeExceptionId, checkAssignmentExceptionId]
|
||||
|
|
@ -689,7 +689,7 @@ mutual
|
|||
else match (← getExprMVarAssignment? mvarId) with
|
||||
| some v => check v
|
||||
| none =>
|
||||
match (← findMVarDecl? mvarId) with
|
||||
match (← mvarId.findDecl?) with
|
||||
| none => throwUnknownMVar mvarId
|
||||
| some mvarDecl =>
|
||||
if ctx.hasCtxLocals then
|
||||
|
|
@ -733,7 +733,7 @@ mutual
|
|||
let localInsts := mvarDecl.localInstances.filter fun localInst => toErase.contains localInst.fvar.fvarId!
|
||||
let mvarType ← check mvarDecl.type
|
||||
let newMVar ← mkAuxMVar lctx localInsts mvarType mvarDecl.numScopeArgs
|
||||
assignExprMVar mvarId newMVar
|
||||
mvarId.assign newMVar
|
||||
pure newMVar
|
||||
else
|
||||
traceM `Meta.isDefEq.assign.readOnlyMVarWithBiggerLCtx <| addAssignmentInfo (mkMVar mvarId)
|
||||
|
|
@ -771,7 +771,7 @@ mutual
|
|||
(fun ex => do
|
||||
if !f.isMVar then
|
||||
throw ex
|
||||
else if (← isMVarDelayedAssigned f.mvarId!) then
|
||||
else if (← f.mvarId!.isDelayedAssigned) then
|
||||
throw ex
|
||||
else
|
||||
let eType ← inferType e
|
||||
|
|
@ -878,7 +878,7 @@ def checkAssignment (mvarId : MVarId) (fvars : Array Expr) (v : Expr) : MetaM (O
|
|||
if !v.hasExprMVar && !v.hasFVar then
|
||||
pure (some v)
|
||||
else
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let hasCtxLocals := fvars.any fun fvar => mvarDecl.lctx.containsFVar fvar
|
||||
let ctx ← read
|
||||
let mctx ← getMCtx
|
||||
|
|
@ -949,7 +949,7 @@ private def simpAssignmentArg (arg : Expr) : MetaM Expr := do
|
|||
/-- Assign `mvar := fun a_1 ... a_{numArgs} => v`.
|
||||
We use it at `processConstApprox` and `isDefEqMVarSelf` -/
|
||||
private def assignConst (mvar : Expr) (numArgs : Nat) (v : Expr) : MetaM Bool := do
|
||||
let mvarDecl ← getMVarDecl mvar.mvarId!
|
||||
let mvarDecl ← mvar.mvarId!.getDecl
|
||||
forallBoundedTelescope mvarDecl.type numArgs fun xs _ => do
|
||||
if xs.size != numArgs then
|
||||
pure false
|
||||
|
|
@ -981,7 +981,7 @@ private partial def processConstApprox (mvar : Expr) (args : Array Expr) (patter
|
|||
let rec defaultCase : MetaM Bool := assignConst mvar args.size v
|
||||
let cfg ← getConfig
|
||||
let mvarId := mvar.mvarId!
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let numArgs := args.size
|
||||
if mvarDecl.numScopeArgs != numArgs && !cfg.constApprox then
|
||||
return false
|
||||
|
|
@ -1022,7 +1022,7 @@ private partial def processAssignment (mvarApp : Expr) (v : Expr) : MetaM Bool :
|
|||
traceCtx `Meta.isDefEq.assign do
|
||||
trace[Meta.isDefEq.assign] "{mvarApp} := {v}"
|
||||
let mvar := mvarApp.getAppFn
|
||||
let mvarDecl ← getMVarDecl mvar.mvarId!
|
||||
let mvarDecl ← mvar.mvarId!.getDecl
|
||||
let rec process (i : Nat) (args : Array Expr) (v : Expr) := do
|
||||
let cfg ← getConfig
|
||||
let useFOApprox (args : Array Expr) : MetaM Bool :=
|
||||
|
|
@ -1302,7 +1302,7 @@ private def isDefEqDelta (t s : Expr) : MetaM LBool := do
|
|||
unfoldNonProjFnDefEq tInfo sInfo t s
|
||||
|
||||
private def isAssigned : Expr → MetaM Bool
|
||||
| Expr.mvar mvarId => isExprMVarAssigned mvarId
|
||||
| Expr.mvar mvarId => mvarId.isAssigned
|
||||
| _ => pure false
|
||||
|
||||
private def expandDelayedAssigned? (t : Expr) : MetaM (Option Expr) := do
|
||||
|
|
@ -1335,7 +1335,7 @@ private def expandDelayedAssigned? (t : Expr) : MetaM (Option Expr) := do
|
|||
return some (mkAppRange (mkMVar mvarIdPending) fvars.size tArgs.size tArgs)
|
||||
|
||||
private def isAssignable : Expr → MetaM Bool
|
||||
| Expr.mvar mvarId => do let b ← isReadOnlyOrSyntheticOpaqueExprMVar mvarId; pure (!b)
|
||||
| Expr.mvar mvarId => do let b ← mvarId.isReadOnlyOrSyntheticOpaque; pure (!b)
|
||||
| _ => pure false
|
||||
|
||||
private def etaEq (t s : Expr) : Bool :=
|
||||
|
|
@ -1403,7 +1403,7 @@ private def isDefEqMVarSelf (mvar : Expr) (args₁ args₂ : Array Expr) : MetaM
|
|||
else
|
||||
let cfg ← getConfig
|
||||
let mvarId := mvar.mvarId!
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
if mvarDecl.numScopeArgs == args₁.size || cfg.constApprox then
|
||||
let type ← inferType (mkAppN mvar args₁)
|
||||
let auxMVar ← mkAuxMVar mvarDecl.lctx mvarDecl.localInstances type
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ def forEachExpr (e : Expr) (f : Expr → MetaM Unit) : MetaM Unit :=
|
|||
/-- Return true iff `x` is a metavariable with an anonymous user facing name. -/
|
||||
private def shouldInferBinderName (x : Expr) : MetaM Bool := do
|
||||
match x with
|
||||
| .mvar mvarId => return (← Meta.getMVarDecl mvarId).userName.isAnonymous
|
||||
| .mvar mvarId => return (← mvarId.getDecl).userName.isAnonymous
|
||||
| _ => return false
|
||||
|
||||
/--
|
||||
|
|
@ -82,7 +82,7 @@ def setMVarUserNamesAt (e : Expr) (isTarget : Array Expr) : MetaM (Array MVarId)
|
|||
let arg := args[i]!
|
||||
if arg.isMVar && isTarget.contains arg then
|
||||
let mvarId := arg.mvarId!
|
||||
if (← Meta.getMVarDecl mvarId).userName.isAnonymous then
|
||||
if (← mvarId.getDecl).userName.isAnonymous then
|
||||
forallBoundedTelescope (← inferType e.getAppFn) (some (i+1)) fun xs _ => do
|
||||
if i < xs.size then
|
||||
let mvarId := arg.mvarId!
|
||||
|
|
|
|||
|
|
@ -233,9 +233,9 @@ def mkBelowDecl (ctx : Context) : MetaM Declaration := do
|
|||
partial def backwardsChaining (m : MVarId) (depth : Nat) : MetaM Bool := do
|
||||
if depth = 0 then return false
|
||||
else
|
||||
withMVarContext m do
|
||||
m.withContext do
|
||||
let lctx ← getLCtx
|
||||
let mTy ← getMVarType m
|
||||
let mTy ← m.getType
|
||||
lctx.anyM fun localDecl =>
|
||||
if localDecl.isAuxDecl then
|
||||
return false
|
||||
|
|
@ -243,9 +243,9 @@ partial def backwardsChaining (m : MVarId) (depth : Nat) : MetaM Bool := do
|
|||
commitWhen do
|
||||
let (mvars, _, t) ← forallMetaTelescope localDecl.type
|
||||
if ←isDefEq mTy t then
|
||||
assignExprMVar m (mkAppN localDecl.toExpr mvars)
|
||||
m.assign (mkAppN localDecl.toExpr mvars)
|
||||
mvars.allM fun v =>
|
||||
isExprMVarAssigned v.mvarId! <||> backwardsChaining v.mvarId! (depth - 1)
|
||||
v.mvarId!.isAssigned <||> backwardsChaining v.mvarId! (depth - 1)
|
||||
else return false
|
||||
|
||||
partial def proveBrecOn (ctx : Context) (indVal : InductiveVal) (type : Expr) : MetaM Expr := do
|
||||
|
|
@ -260,16 +260,16 @@ partial def proveBrecOn (ctx : Context) (indVal : InductiveVal) (type : Expr) :
|
|||
instantiateMVars main
|
||||
where
|
||||
intros (m : MVarId) : MetaM (MVarId × BrecOnVariables) := do
|
||||
let (params, m) ← introNP m indVal.numParams
|
||||
let (motives, m) ← introNP m ctx.motives.size
|
||||
let (indices, m) ← introNP m indVal.numIndices
|
||||
let (witness, m) ← intro1P m
|
||||
let (indHyps, m) ← introNP m ctx.motives.size
|
||||
let (params, m) ← m.introNP indVal.numParams
|
||||
let (motives, m) ← m.introNP ctx.motives.size
|
||||
let (indices, m) ← m.introNP indVal.numIndices
|
||||
let (witness, m) ← m.intro1P
|
||||
let (indHyps, m) ← m.introNP ctx.motives.size
|
||||
return (m, ⟨params, motives, indices, witness, indHyps⟩)
|
||||
|
||||
applyIH (m : MVarId) (vars : BrecOnVariables) : MetaM (List MVarId) := do
|
||||
match (← vars.indHyps.findSomeM?
|
||||
fun ih => do try pure <| some <| (←apply m $ mkFVar ih) catch _ => pure none) with
|
||||
fun ih => do try pure <| some <| (← m.apply <| mkFVar ih) catch _ => pure none) with
|
||||
| some goals => pure goals
|
||||
| none => throwError "cannot apply induction hypothesis: {MessageData.ofGoal m}"
|
||||
|
||||
|
|
@ -287,30 +287,30 @@ where
|
|||
then levelZero::levelParams
|
||||
else levelParams
|
||||
let recursor := mkAppN (mkConst recursorInfo.name $ recLevels) $ params ++ motives
|
||||
apply m recursor
|
||||
m.apply recursor
|
||||
|
||||
applyCtors (ms : List MVarId) : MetaM $ List MVarId := do
|
||||
let mss ← ms.toArray.mapIdxM fun _ m => do
|
||||
let m ← introNPRec m
|
||||
(← getMVarType m).withApp fun below args =>
|
||||
withMVarContext m do
|
||||
(← m.getType).withApp fun below args =>
|
||||
m.withContext do
|
||||
args.back.withApp fun ctor _ => do
|
||||
let ctorName := ctor.constName!.updatePrefix below.constName!
|
||||
let ctor := mkConst ctorName below.constLevels!
|
||||
let ctorInfo ← getConstInfoCtor ctorName
|
||||
let (mvars, _, _) ← forallMetaTelescope ctorInfo.type
|
||||
let ctor := mkAppN ctor mvars
|
||||
apply m ctor
|
||||
m.apply ctor
|
||||
return mss.foldr List.append []
|
||||
|
||||
introNPRec (m : MVarId) : MetaM MVarId := do
|
||||
if (← getMVarType m).isForall then introNPRec (←intro1P m).2 else return m
|
||||
if (← m.getType).isForall then introNPRec (← m.intro1P).2 else return m
|
||||
|
||||
closeGoal (maxDepth : Nat) (m : MVarId) : MetaM Unit := do
|
||||
unless (← isExprMVarAssigned m) do
|
||||
unless (← m.isAssigned) do
|
||||
let m ← introNPRec m
|
||||
unless (← backwardsChaining m maxDepth) do
|
||||
withMVarContext m do
|
||||
m.withContext do
|
||||
throwError "couldn't solve by backwards chaining ({``maxBackwardChainingDepth} = {maxDepth}): {MessageData.ofGoal m}"
|
||||
|
||||
def mkBrecOnDecl (ctx : Context) (idx : Nat) : MetaM Declaration := do
|
||||
|
|
|
|||
|
|
@ -128,11 +128,11 @@ def getLevel (type : Expr) : MetaM Level := do
|
|||
match typeType with
|
||||
| Expr.sort lvl => return lvl
|
||||
| Expr.mvar mvarId =>
|
||||
if (← isReadOnlyOrSyntheticOpaqueExprMVar mvarId) then
|
||||
if (← mvarId.isReadOnlyOrSyntheticOpaque) then
|
||||
throwTypeExcepted type
|
||||
else
|
||||
let lvl ← mkFreshLevelMVar
|
||||
assignExprMVar mvarId (mkSort lvl)
|
||||
mvarId.assign (mkSort lvl)
|
||||
return lvl
|
||||
| _ => throwTypeExcepted type
|
||||
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ private def solveEqOfCtorEq (ctorName : Name) (mvarId : MVarId) (h : FVarId) : M
|
|||
match (← injection mvarId h) with
|
||||
| InjectionResult.solved => unreachable!
|
||||
| InjectionResult.subgoal mvarId .. =>
|
||||
(← splitAnd mvarId).forM fun mvarId =>
|
||||
unless (← assumptionCore mvarId) do
|
||||
(← mvarId.splitAnd).forM fun mvarId =>
|
||||
unless (← mvarId.assumptionCore) do
|
||||
throwInjectiveTheoremFailure ctorName mvarId
|
||||
|
||||
private def mkInjectiveTheoremValue (ctorName : Name) (targetType : Expr) : MetaM Expr :=
|
||||
|
|
@ -118,10 +118,10 @@ private def mkInjectiveEqTheoremType? (ctorVal : ConstructorVal) : MetaM (Option
|
|||
private def mkInjectiveEqTheoremValue (ctorName : Name) (targetType : Expr) : MetaM Expr := do
|
||||
forallTelescopeReducing targetType fun xs type => do
|
||||
let mvar ← mkFreshExprSyntheticOpaqueMVar type
|
||||
let [mvarId₁, mvarId₂] ← apply mvar.mvarId! (mkConst ``Eq.propIntro)
|
||||
let [mvarId₁, mvarId₂] ← mvar.mvarId!.apply (mkConst ``Eq.propIntro)
|
||||
| throwError "unexpected number of subgoals when proving injective theorem for constructor '{ctorName}'"
|
||||
let (h, mvarId₁) ← intro1 mvarId₁
|
||||
let (_, mvarId₂) ← intro1 mvarId₂
|
||||
let (h, mvarId₁) ← mvarId₁.intro1
|
||||
let (_, mvarId₂) ← mvarId₂.intro1
|
||||
solveEqOfCtorEq ctorName mvarId₁ h
|
||||
let mvarId₂ ← casesAnd mvarId₂
|
||||
if let some mvarId₂ ← substEqs mvarId₂ then
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ structure Problem where
|
|||
deriving Inhabited
|
||||
|
||||
def withGoalOf {α} (p : Problem) (x : MetaM α) : MetaM α :=
|
||||
withMVarContext p.mvarId x
|
||||
p.mvarId.withContext x
|
||||
|
||||
def Problem.toMessageData (p : Problem) : MetaM MessageData :=
|
||||
withGoalOf p do
|
||||
|
|
|
|||
|
|
@ -41,13 +41,13 @@ private partial def introArrayLit (mvarId : MVarId) (a : Expr) (n : Nat) (xNameP
|
|||
let aEqXsLit ← mkEq a xsLit
|
||||
let aEqLitPrf ← mkAppM ``Array.toArrayLit_eq #[a, mkRawNatLit n, aSizeEqN]
|
||||
withLocalDeclD `hEqALit aEqXsLit fun heq => do
|
||||
let target ← getMVarType mvarId
|
||||
let target ← mvarId.getType
|
||||
let newTarget ← mkForallFVars (xs.push heq) target
|
||||
pure (newTarget, args.push aEqLitPrf)
|
||||
let (newTarget, args) ← loop 0 #[] #[]
|
||||
let tag ← getMVarTag mvarId
|
||||
let tag ← mvarId.getTag
|
||||
let newMVar ← mkFreshExprSyntheticOpaqueMVar newTarget tag
|
||||
assignExprMVar mvarId (mkAppN newMVar args)
|
||||
mvarId.assign (mkAppN newMVar args)
|
||||
pure newMVar.mvarId!
|
||||
|
||||
/--
|
||||
|
|
@ -58,12 +58,12 @@ private partial def introArrayLit (mvarId : MVarId) (a : Expr) (n : Nat) (xNameP
|
|||
n+1) `..., (h_1 : a.size != sizes[0]), ..., (h_n : a.size != sizes[n-1]) |- C a`
|
||||
where `n = sizes.size` -/
|
||||
def caseArraySizes (mvarId : MVarId) (fvarId : FVarId) (sizes : Array Nat) (xNamePrefix := `x) (hNamePrefix := `h) : MetaM (Array CaseArraySizesSubgoal) :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let a := mkFVar fvarId
|
||||
let aSize ← mkAppM `Array.size #[a]
|
||||
let mvarId ← assertExt mvarId `aSize (mkConst `Nat) aSize
|
||||
let (aSizeFVarId, mvarId) ← intro1 mvarId
|
||||
let (hEq, mvarId) ← intro1 mvarId
|
||||
let mvarId ← mvarId.assertExt `aSize (mkConst `Nat) aSize
|
||||
let (aSizeFVarId, mvarId) ← mvarId.intro1
|
||||
let (hEq, mvarId) ← mvarId.intro1
|
||||
let subgoals ← caseValues mvarId aSizeFVarId (sizes.map mkRawNatLit) hNamePrefix
|
||||
subgoals.mapIdxM fun i subgoal => do
|
||||
let subst := subgoal.subst
|
||||
|
|
@ -71,14 +71,14 @@ def caseArraySizes (mvarId : MVarId) (fvarId : FVarId) (sizes : Array Nat) (xNam
|
|||
let hEqSz := (subst.get hEq).fvarId!
|
||||
if h : i.val < sizes.size then
|
||||
let n := sizes.get ⟨i, h⟩
|
||||
let mvarId ← clear mvarId subgoal.newHs[0]!
|
||||
let mvarId ← clear mvarId (subst.get aSizeFVarId).fvarId!
|
||||
withMVarContext mvarId do
|
||||
let mvarId ← mvarId.clear subgoal.newHs[0]!
|
||||
let mvarId ← mvarId.clear (subst.get aSizeFVarId).fvarId!
|
||||
mvarId.withContext do
|
||||
let hEqSzSymm ← mkEqSymm (mkFVar hEqSz)
|
||||
let mvarId ← introArrayLit mvarId a n xNamePrefix hEqSzSymm
|
||||
let (xs, mvarId) ← introN mvarId n
|
||||
let (hEqLit, mvarId) ← intro1 mvarId
|
||||
let mvarId ← clear mvarId hEqSz
|
||||
let (xs, mvarId) ← mvarId.introN n
|
||||
let (hEqLit, mvarId) ← mvarId.intro1
|
||||
let mvarId ← mvarId.clear hEqSz
|
||||
let (subst, mvarId) ← substCore mvarId hEqLit false subst
|
||||
pure { mvarId := mvarId, elems := xs, subst := subst }
|
||||
else
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@ structure CaseValueSubgoal where
|
|||
Remark: `subst` field of the second subgoal is equal to the input `subst`. -/
|
||||
private 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
|
||||
mvarId.withContext do
|
||||
let tag ← mvarId.getTag
|
||||
mvarId.checkNotAssigned `caseValue
|
||||
let target ← mvarId.getType
|
||||
let xEqValue ← mkEq (mkFVar fvarId) (foldPatValue value)
|
||||
let xNeqValue := mkApp (mkConst `Not) xEqValue
|
||||
let thenTarget := Lean.mkForall hName BinderInfo.default xEqValue target
|
||||
|
|
@ -36,14 +36,14 @@ private def caseValueAux (mvarId : MVarId) (fvarId : FVarId) (value : Expr) (hNa
|
|||
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!
|
||||
mvarId.assign val
|
||||
let (elseH, elseMVarId) ← elseMVar.mvarId!.intro1P
|
||||
let elseSubgoal := { mvarId := elseMVarId, newH := elseH, subst := subst : CaseValueSubgoal }
|
||||
let (thenH, thenMVarId) ← intro1P thenMVar.mvarId!
|
||||
let (thenH, thenMVarId) ← thenMVar.mvarId!.intro1P
|
||||
let symm := false
|
||||
let clearH := false
|
||||
let (thenSubst, thenMVarId) ← substCore thenMVarId thenH symm subst clearH
|
||||
withMVarContext thenMVarId do
|
||||
thenMVarId.withContext do
|
||||
trace[Meta] "subst domain: {thenSubst.domain.map (·.name)}"
|
||||
let thenH := (thenSubst.get thenH).fvarId!
|
||||
trace[Meta] "searching for decl"
|
||||
|
|
@ -87,7 +87,7 @@ def caseValues (mvarId : MVarId) (fvarId : FVarId) (values : Array Expr) (hNameP
|
|||
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
|
||||
| Expr.fvar fvarId => thenMVarId.tryClear fvarId
|
||||
| _ => pure thenMVarId)
|
||||
thenSubgoal.mvarId
|
||||
let subgoals ← if substNewEqs then
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ def assignGoalOf (p : Problem) (e : Expr) : MetaM Unit :=
|
|||
let eType ← inferType e
|
||||
unless (← isDefEq mvarType eType) do
|
||||
throwError "dependent elimination failed, type mismatch when solving alternative with type{indentExpr eType}\nbut expected{indentExpr mvarType}"
|
||||
assignExprMVar p.mvarId e
|
||||
p.mvarId.assign e
|
||||
|
||||
structure State where
|
||||
used : Std.HashSet Nat := {} -- used alternatives
|
||||
|
|
@ -173,7 +173,7 @@ private def processLeaf (p : Problem) : StateRefT State MetaM Unit := do
|
|||
/- TODO: allow users to configure which tactic is used to close leaves. -/
|
||||
unless (← contradictionCore p.mvarId {}) do
|
||||
trace[Meta.Match.match] "missing alternative"
|
||||
admit p.mvarId
|
||||
p.mvarId.admit
|
||||
modify fun s => { s with counterExamples := p.examples :: s.counterExamples }
|
||||
| alt :: _ =>
|
||||
-- TODO: check whether we have unassigned metavars in rhs
|
||||
|
|
@ -465,7 +465,7 @@ private def processConstructor (p : Problem) : MetaM (Array Problem) := do
|
|||
match subgoals? with
|
||||
| none => return #[{ p with vars := xs }]
|
||||
| some subgoals =>
|
||||
subgoals.mapM fun subgoal => withMVarContext subgoal.mvarId do
|
||||
subgoals.mapM fun subgoal => subgoal.mvarId.withContext do
|
||||
let subst := subgoal.subst
|
||||
let fields := subgoal.fields.toList
|
||||
let newVars := fields ++ xs
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Lean.Meta
|
|||
Helper method for `proveCondEqThm`. Given a goal of the form `C.rec ... xMajor = rhs`,
|
||||
apply `cases xMajor`. -/
|
||||
partial def casesOnStuckLHS (mvarId : MVarId) : MetaM (Array MVarId) := do
|
||||
let target ← getMVarType mvarId
|
||||
let target ← mvarId.getType
|
||||
if let some (_, lhs, _) ← matchEq? target then
|
||||
if let some fvarId ← findFVar? lhs then
|
||||
return (← cases mvarId fvarId).map fun s => s.mvarId
|
||||
|
|
@ -196,7 +196,7 @@ partial def trySubstVarsAndContradiction (mvarId : MVarId) : MetaM Bool :=
|
|||
|
||||
private def processNextEq : M Bool := do
|
||||
let s ← get
|
||||
withMVarContext s.mvarId do
|
||||
s.mvarId.withContext do
|
||||
-- If the goal is contradictory, the hypothesis is redundant.
|
||||
if (← contradiction s.mvarId) then
|
||||
return false
|
||||
|
|
@ -256,11 +256,11 @@ end SimpH
|
|||
private partial def simpH? (h : Expr) (numEqs : Nat) : MetaM (Option Expr) := withDefault do
|
||||
let numVars ← forallTelescope h fun ys _ => pure (ys.size - numEqs)
|
||||
let mvarId := (← mkFreshExprSyntheticOpaqueMVar h).mvarId!
|
||||
let (xs, mvarId) ← introN mvarId numVars
|
||||
let (eqs, mvarId) ← introN mvarId numEqs
|
||||
let (xs, mvarId) ← mvarId.introN numVars
|
||||
let (eqs, mvarId) ← mvarId.introN numEqs
|
||||
let (r, s) ← SimpH.go |>.run { mvarId, xs := xs.toList, eqs := eqs.toList }
|
||||
if r then
|
||||
withMVarContext s.mvarId do
|
||||
s.mvarId.withContext do
|
||||
let eqs := s.eqsNew.reverse.toArray.map mkFVar
|
||||
let mut r ← mkForallFVars eqs (mkConst ``False)
|
||||
/- We only include variables in `xs` if there is a dependency. -/
|
||||
|
|
@ -273,7 +273,7 @@ private partial def simpH? (h : Expr) (numEqs : Nat) : MetaM (Option Expr) := wi
|
|||
else
|
||||
return none
|
||||
|
||||
private def substSomeVar (mvarId : MVarId) : MetaM (Array MVarId) := withMVarContext mvarId do
|
||||
private def substSomeVar (mvarId : MVarId) : MetaM (Array MVarId) := mvarId.withContext do
|
||||
for localDecl in (← getLCtx) do
|
||||
if let some (_, lhs, rhs) ← matchEq? localDecl.type then
|
||||
if lhs.isFVar then
|
||||
|
|
@ -291,13 +291,13 @@ partial def proveCondEqThm (matchDeclName : Name) (type : Expr) : MetaM Expr :=
|
|||
forallTelescope type fun ys target => do
|
||||
let mvar0 ← mkFreshExprSyntheticOpaqueMVar target
|
||||
trace[Meta.Match.matchEqs] "proveCondEqThm {mvar0.mvarId!}"
|
||||
let mvarId ← deltaTarget mvar0.mvarId! (· == matchDeclName)
|
||||
let mvarId ← mvar0.mvarId!.deltaTarget (· == matchDeclName)
|
||||
withDefault <| go mvarId 0
|
||||
mkLambdaFVars ys (← instantiateMVars mvar0)
|
||||
where
|
||||
go (mvarId : MVarId) (depth : Nat) : MetaM Unit := withIncRecDepth do
|
||||
trace[Meta.Match.matchEqs] "proveCondEqThm.go {mvarId}"
|
||||
let mvarId' ← modifyTargetEqLHS mvarId whnfCore
|
||||
let mvarId' ← mvarId.modifyTargetEqLHS whnfCore
|
||||
let mvarId := mvarId'
|
||||
let subgoals ←
|
||||
(do applyRefl mvarId; return #[])
|
||||
|
|
@ -347,7 +347,7 @@ private def injectionAnyCandidate? (type : Expr) : MetaM (Option (Expr × Expr))
|
|||
return none
|
||||
|
||||
private def injectionAny (mvarId : MVarId) : MetaM InjectionAnyResult :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
for localDecl in (← getLCtx) do
|
||||
if let some (lhs, rhs) ← injectionAnyCandidate? localDecl.type then
|
||||
unless (← isDefEq lhs rhs) do
|
||||
|
|
@ -580,9 +580,9 @@ where
|
|||
| InjectionAnyResult.subgoal mvarId => proveSubgoalLoop mvarId
|
||||
|
||||
proveSubgoal (mvarId : MVarId) : MetaM Unit := do
|
||||
trace[Meta.Match.matchEqs] "subgoal {mkMVar mvarId}, {repr (← getMVarDecl mvarId).kind}, {← isExprMVarAssigned mvarId}\n{MessageData.ofGoal mvarId}"
|
||||
let (_, mvarId) ← intros mvarId
|
||||
let mvarId ← tryClearMany mvarId (alts.map (·.fvarId!))
|
||||
trace[Meta.Match.matchEqs] "subgoal {mkMVar mvarId}, {repr (← mvarId.getDecl).kind}, {← mvarId.isAssigned}\n{MessageData.ofGoal mvarId}"
|
||||
let (_, mvarId) ← mvarId.intros
|
||||
let mvarId ← mvarId.tryClearMany (alts.map (·.fvarId!))
|
||||
proveSubgoalLoop mvarId
|
||||
|
||||
/--
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ partial def normExpr (e : Expr) : M Expr := do
|
|||
| Expr.mdata _ b => return e.updateMData! (← normExpr b)
|
||||
| Expr.proj _ _ b => return e.updateProj! (← normExpr b)
|
||||
| Expr.mvar mvarId =>
|
||||
if !(← isExprMVarAssignable mvarId) then
|
||||
if !(← mvarId.isAssignable) then
|
||||
return e
|
||||
else
|
||||
let s ← get
|
||||
|
|
@ -749,8 +749,8 @@ def synthInstance (type : Expr) (maxResultSize? : Option Nat := none) : MetaM Ex
|
|||
(fun _ => throwError "failed to synthesize{indentExpr type}")
|
||||
|
||||
@[export lean_synth_pending]
|
||||
private def synthPendingImp (mvarId : MVarId) : MetaM Bool := withIncRecDepth <| withMVarContext mvarId do
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
private def synthPendingImp (mvarId : MVarId) : MetaM Bool := withIncRecDepth <| mvarId.withContext do
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
match mvarDecl.kind with
|
||||
| MetavarKind.syntheticOpaque =>
|
||||
return false
|
||||
|
|
@ -773,10 +773,10 @@ private def synthPendingImp (mvarId : MVarId) : MetaM Bool := withIncRecDepth <|
|
|||
| none =>
|
||||
return false
|
||||
| some val =>
|
||||
if (← isExprMVarAssigned mvarId) then
|
||||
if (← mvarId.isAssigned) then
|
||||
return false
|
||||
else
|
||||
assignExprMVar mvarId val
|
||||
mvarId.assign val
|
||||
return true
|
||||
|
||||
builtin_initialize
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ def rewriteUnnormalized (mvarId : MVarId) : MetaM Unit := do
|
|||
congrTheorems := (← getSimpCongrTheorems)
|
||||
config := Simp.neutralConfig
|
||||
}
|
||||
let tgt ← getMVarType mvarId
|
||||
let tgt ← mvarId.getType
|
||||
let res ← Simp.main tgt simpCtx (methods := { post })
|
||||
let newGoal ← applySimpResultToTarget mvarId tgt res
|
||||
applyRefl newGoal
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ private def isTarget (lhs rhs : Expr) : MetaM Bool := do
|
|||
Close the given goal if `h` is a proof for an equality such as `as = a :: as`.
|
||||
Inductive datatypes in Lean are acyclic.
|
||||
-/
|
||||
def acyclic (mvarId : MVarId) (h : Expr) : MetaM Bool := withMVarContext mvarId do
|
||||
def acyclic (mvarId : MVarId) (h : Expr) : MetaM Bool := mvarId.withContext do
|
||||
let type ← whnfD (← inferType h)
|
||||
trace[Meta.Tactic.acyclic] "type: {type}"
|
||||
let some (_, lhs, rhs) := type.eq? | return false
|
||||
|
|
@ -42,7 +42,7 @@ where
|
|||
let heq ← mkCongrArg sizeOf_lhs.appFn! (← mkEqSymm h)
|
||||
let hlt_self ← mkAppM ``Nat.lt_of_lt_of_eq #[hlt, heq]
|
||||
let hlt_irrelf ← mkAppM ``Nat.lt_irrefl #[sizeOf_lhs]
|
||||
assignExprMVar mvarId (← mkFalseElim (← getMVarType mvarId) (mkApp hlt_irrelf hlt_self))
|
||||
mvarId.assign (← mkFalseElim (← mvarId.getType) (mkApp hlt_irrelf hlt_self))
|
||||
trace[Meta.Tactic.acyclic] "succeeded"
|
||||
return true
|
||||
catch ex =>
|
||||
|
|
|
|||
|
|
@ -35,18 +35,18 @@ def synthAppInstances (tacticName : Name) (mvarId : MVarId) (newMVars : Array Ex
|
|||
throwTacticEx tacticName mvarId "failed to assign synthesized instance"
|
||||
|
||||
def appendParentTag (mvarId : MVarId) (newMVars : Array Expr) (binderInfos : Array BinderInfo) : MetaM Unit := do
|
||||
let parentTag ← getMVarTag mvarId
|
||||
let parentTag ← mvarId.getTag
|
||||
if newMVars.size == 1 then
|
||||
-- if there is only one subgoal, we inherit the parent tag
|
||||
setMVarTag newMVars[0]!.mvarId! parentTag
|
||||
newMVars[0]!.mvarId!.setTag parentTag
|
||||
else
|
||||
unless parentTag.isAnonymous do
|
||||
newMVars.size.forM fun i => do
|
||||
let newMVarId := newMVars[i]!.mvarId!
|
||||
unless (← isExprMVarAssigned newMVarId) do
|
||||
let mvarIdNew := newMVars[i]!.mvarId!
|
||||
unless (← mvarIdNew.isAssigned) do
|
||||
unless binderInfos[i]!.isInstImplicit do
|
||||
let currTag ← getMVarTag newMVarId
|
||||
setMVarTag newMVarId (appendTag parentTag currTag)
|
||||
let currTag ← mvarIdNew.getTag
|
||||
mvarIdNew.setTag (appendTag parentTag currTag)
|
||||
|
||||
def postprocessAppMVars (tacticName : Name) (mvarId : MVarId) (newMVars : Array Expr) (binderInfos : Array BinderInfo) : MetaM Unit := do
|
||||
synthAppInstances tacticName mvarId newMVars binderInfos
|
||||
|
|
@ -92,10 +92,13 @@ private def reorderGoals (mvars : Array Expr) : ApplyNewGoals → MetaM (List MV
|
|||
structure ApplyConfig where
|
||||
newGoals := ApplyNewGoals.nonDependentFirst
|
||||
|
||||
def apply (mvarId : MVarId) (e : Expr) (cfg : ApplyConfig := {}) : MetaM (List MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `apply
|
||||
let targetType ← getMVarType mvarId
|
||||
/--
|
||||
Close the give goal using `apply e`.
|
||||
-/
|
||||
def _root_.Lean.MVarId.apply (mvarId : MVarId) (e : Expr) (cfg : ApplyConfig := {}) : MetaM (List MVarId) :=
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `apply
|
||||
let targetType ← mvarId.getType
|
||||
let eType ← inferType e
|
||||
let mut (numArgs, hasMVarHead) ← getExpectedNumArgsAux eType
|
||||
unless hasMVarHead do
|
||||
|
|
@ -105,23 +108,27 @@ def apply (mvarId : MVarId) (e : Expr) (cfg : ApplyConfig := {}) : MetaM (List M
|
|||
unless (← isDefEq eType targetType) do throwApplyError mvarId eType targetType
|
||||
postprocessAppMVars `apply mvarId newMVars binderInfos
|
||||
let e ← instantiateMVars e
|
||||
assignExprMVar mvarId (mkAppN e newMVars)
|
||||
let newMVars ← newMVars.filterM fun mvar => not <$> isExprMVarAssigned mvar.mvarId!
|
||||
mvarId.assign (mkAppN e newMVars)
|
||||
let newMVars ← newMVars.filterM fun mvar => not <$> mvar.mvarId!.isAssigned
|
||||
let otherMVarIds ← getMVarsNoDelayed e
|
||||
let newMVarIds ← reorderGoals newMVars cfg.newGoals
|
||||
let otherMVarIds := otherMVarIds.filter fun mvarId => !newMVarIds.contains mvarId
|
||||
let result := newMVarIds ++ otherMVarIds.toList
|
||||
result.forM headBetaMVarType
|
||||
result.forM (·.headBetaType)
|
||||
return result
|
||||
|
||||
partial def splitAnd (mvarId : MVarId) : MetaM (List MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `splitAnd
|
||||
let type ← getMVarType' mvarId
|
||||
@[deprecated MVarId.apply]
|
||||
def apply (mvarId : MVarId) (e : Expr) (cfg : ApplyConfig := {}) : MetaM (List MVarId) :=
|
||||
mvarId.apply e cfg
|
||||
|
||||
partial def splitAndCore (mvarId : MVarId) : MetaM (List MVarId) :=
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `splitAnd
|
||||
let type ← mvarId.getType'
|
||||
if !type.isAppOfArity ``And 2 then
|
||||
return [mvarId]
|
||||
else
|
||||
let tag ← getMVarTag mvarId
|
||||
let tag ← mvarId.getTag
|
||||
let rec go (type : Expr) : StateRefT (Array MVarId) MetaM Expr := do
|
||||
let type ← whnf type
|
||||
if type.isAppOfArity ``And 2 then
|
||||
|
|
@ -134,21 +141,31 @@ partial def splitAnd (mvarId : MVarId) : MetaM (List MVarId) :=
|
|||
modify fun s => s.push mvar.mvarId!
|
||||
return mvar
|
||||
let (val, s) ← go type |>.run #[]
|
||||
assignExprMVar mvarId val
|
||||
mvarId.assign val
|
||||
return s.toList
|
||||
|
||||
/--
|
||||
Apply `And.intro` as much as possible to goal `mvarId`.
|
||||
-/
|
||||
abbrev _root_.Lean.MVarId.splitAnd (mvarId : MVarId) : MetaM (List MVarId) :=
|
||||
splitAndCore mvarId
|
||||
|
||||
@[deprecated MVarId.splitAnd]
|
||||
def splitAnd (mvarId : MVarId) : MetaM (List MVarId) :=
|
||||
mvarId.splitAnd
|
||||
|
||||
def applyRefl (mvarId : MVarId) (msg : MessageData := "refl failed") : MetaM Unit :=
|
||||
withMVarContext mvarId do
|
||||
let some [] ← observing? do apply mvarId (mkConst ``Eq.refl [← mkFreshLevelMVar])
|
||||
mvarId.withContext do
|
||||
let some [] ← observing? do mvarId.apply (mkConst ``Eq.refl [← mkFreshLevelMVar])
|
||||
| throwTacticEx `refl mvarId msg
|
||||
|
||||
def exfalso (mvarId : MVarId) : MetaM MVarId :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `exfalso
|
||||
let target ← instantiateMVars (← getMVarType mvarId)
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `exfalso
|
||||
let target ← instantiateMVars (← mvarId.getType)
|
||||
let u ← getLevel target
|
||||
let mvarIdNew ← mkFreshExprSyntheticOpaqueMVar (mkConst ``False) (tag := (← getMVarTag mvarId))
|
||||
assignExprMVar mvarId (mkApp2 (mkConst ``False.elim [u]) target mvarIdNew)
|
||||
let mvarIdNew ← mkFreshExprSyntheticOpaqueMVar (mkConst ``False) (tag := (← mvarId.getTag))
|
||||
mvarId.assign (mkApp2 (mkConst ``False.elim [u]) target mvarIdNew)
|
||||
return mvarIdNew.mvarId!
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -13,44 +13,56 @@ namespace Lean.Meta
|
|||
/--
|
||||
Convert the given goal `Ctx |- target` into `Ctx |- type -> target`.
|
||||
It assumes `val` has type `type` -/
|
||||
def assert (mvarId : MVarId) (name : Name) (type : Expr) (val : Expr) : MetaM MVarId :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `assert
|
||||
let tag ← getMVarTag mvarId
|
||||
let target ← getMVarType mvarId
|
||||
def _root_.Lean.MVarId.assert (mvarId : MVarId) (name : Name) (type : Expr) (val : Expr) : MetaM MVarId :=
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `assert
|
||||
let tag ← mvarId.getTag
|
||||
let target ← mvarId.getType
|
||||
let newType := Lean.mkForall name BinderInfo.default type target
|
||||
let newMVar ← mkFreshExprSyntheticOpaqueMVar newType tag
|
||||
assignExprMVar mvarId (mkApp newMVar val)
|
||||
pure newMVar.mvarId!
|
||||
mvarId.assign (mkApp newMVar val)
|
||||
return newMVar.mvarId!
|
||||
|
||||
@[deprecated MVarId.assert]
|
||||
def assert (mvarId : MVarId) (name : Name) (type : Expr) (val : Expr) : MetaM MVarId :=
|
||||
mvarId.assert name type val
|
||||
|
||||
/--
|
||||
Convert the given goal `Ctx |- target` into `Ctx |- let name : type := val; target`.
|
||||
It assumes `val` has type `type` -/
|
||||
def define (mvarId : MVarId) (name : Name) (type : Expr) (val : Expr) : MetaM MVarId := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `define
|
||||
let tag ← getMVarTag mvarId
|
||||
let target ← getMVarType mvarId
|
||||
def _root_.Lean.MVarId.define (mvarId : MVarId) (name : Name) (type : Expr) (val : Expr) : MetaM MVarId := do
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `define
|
||||
let tag ← mvarId.getTag
|
||||
let target ← mvarId.getType
|
||||
let newType := Lean.mkLet name type val target
|
||||
let newMVar ← mkFreshExprSyntheticOpaqueMVar newType tag
|
||||
assignExprMVar mvarId newMVar
|
||||
pure newMVar.mvarId!
|
||||
mvarId.assign newMVar
|
||||
return newMVar.mvarId!
|
||||
|
||||
@[deprecated MVarId.define]
|
||||
def define (mvarId : MVarId) (name : Name) (type : Expr) (val : Expr) : MetaM MVarId := do
|
||||
mvarId.define name type val
|
||||
|
||||
/--
|
||||
Convert the given goal `Ctx |- target` into `Ctx |- (hName : type) -> hName = val -> target`.
|
||||
It assumes `val` has type `type` -/
|
||||
def assertExt (mvarId : MVarId) (name : Name) (type : Expr) (val : Expr) (hName : Name := `h) : MetaM MVarId := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `assert
|
||||
let tag ← getMVarTag mvarId
|
||||
let target ← getMVarType mvarId
|
||||
def _root_.Lean.MVarId.assertExt (mvarId : MVarId) (name : Name) (type : Expr) (val : Expr) (hName : Name := `h) : MetaM MVarId := do
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `assert
|
||||
let tag ← mvarId.getTag
|
||||
let target ← mvarId.getType
|
||||
let u ← getLevel type
|
||||
let hType := mkApp3 (mkConst `Eq [u]) type (mkBVar 0) val
|
||||
let newType := Lean.mkForall name BinderInfo.default type $ Lean.mkForall hName BinderInfo.default hType target
|
||||
let newMVar ← mkFreshExprSyntheticOpaqueMVar newType tag
|
||||
let rflPrf ← mkEqRefl val
|
||||
assignExprMVar mvarId (mkApp2 newMVar val rflPrf)
|
||||
pure newMVar.mvarId!
|
||||
mvarId.assign (mkApp2 newMVar val rflPrf)
|
||||
return newMVar.mvarId!
|
||||
|
||||
@[deprecated MVarId.assertExt]
|
||||
def assertExt (mvarId : MVarId) (name : Name) (type : Expr) (val : Expr) (hName : Name := `h) : MetaM MVarId := do
|
||||
mvarId.assertExt name type val hName
|
||||
|
||||
structure AssertAfterResult where
|
||||
fvarId : FVarId
|
||||
|
|
@ -61,11 +73,11 @@ structure AssertAfterResult where
|
|||
Convert the given goal `Ctx |- target` into a goal containing `(userName : type)` after the local declaration with if `fvarId`.
|
||||
It assumes `val` has type `type`, and that `type` is well-formed after `fvarId`.
|
||||
Note that `val` does not need to be well-formed after `fvarId`. That is, it may contain variables that are defined after `fvarId`. -/
|
||||
def assertAfter (mvarId : MVarId) (fvarId : FVarId) (userName : Name) (type : Expr) (val : Expr) : MetaM AssertAfterResult := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `assertAfter
|
||||
let tag ← getMVarTag mvarId
|
||||
let target ← getMVarType mvarId
|
||||
def _root_.Lean.MVarId.assertAfter (mvarId : MVarId) (fvarId : FVarId) (userName : Name) (type : Expr) (val : Expr) : MetaM AssertAfterResult := do
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `assertAfter
|
||||
let tag ← mvarId.getTag
|
||||
let target ← mvarId.getType
|
||||
let localDecl ← getLocalDecl fvarId
|
||||
let lctx ← getLCtx
|
||||
let localInsts ← getLocalInstances
|
||||
|
|
@ -78,11 +90,15 @@ def assertAfter (mvarId : MVarId) (fvarId : FVarId) (userName : Name) (type : Ex
|
|||
let mvarNew ← mkFreshExprMVarAt lctxNew localInstsNew targetNew MetavarKind.syntheticOpaque tag
|
||||
let args := (fvarIds.filter fun fvarId => !(lctx.get! fvarId).isLet).map mkFVar
|
||||
let args := #[val] ++ args
|
||||
assignExprMVar mvarId (mkAppN mvarNew args)
|
||||
let (fvarIdNew, mvarIdNew) ← intro1P mvarNew.mvarId!
|
||||
let (fvarIdsNew, mvarIdNew) ← introNP mvarIdNew fvarIds.size
|
||||
mvarId.assign (mkAppN mvarNew args)
|
||||
let (fvarIdNew, mvarIdNew) ← mvarNew.mvarId!.intro1P
|
||||
let (fvarIdsNew, mvarIdNew) ← mvarIdNew.introNP fvarIds.size
|
||||
let subst := fvarIds.size.fold (init := {}) fun i subst => subst.insert fvarIds[i]! (mkFVar fvarIdsNew[i]!)
|
||||
pure { fvarId := fvarIdNew, mvarId := mvarIdNew, subst := subst }
|
||||
return { fvarId := fvarIdNew, mvarId := mvarIdNew, subst := subst }
|
||||
|
||||
@[deprecated MVarId.assertAfter]
|
||||
def assertAfter (mvarId : MVarId) (fvarId : FVarId) (userName : Name) (type : Expr) (val : Expr) : MetaM AssertAfterResult := do
|
||||
mvarId.assertAfter fvarId userName type val
|
||||
|
||||
structure Hypothesis where
|
||||
userName : Name
|
||||
|
|
@ -92,18 +108,22 @@ structure Hypothesis where
|
|||
/--
|
||||
Convert the given goal `Ctx |- target` into `Ctx, (hs[0].userName : hs[0].type) ... |-target`.
|
||||
It assumes `hs[i].val` has type `hs[i].type`. -/
|
||||
def assertHypotheses (mvarId : MVarId) (hs : Array Hypothesis) : MetaM (Array FVarId × MVarId) := do
|
||||
def _root_.Lean.MVarId.assertHypotheses (mvarId : MVarId) (hs : Array Hypothesis) : MetaM (Array FVarId × MVarId) := do
|
||||
if hs.isEmpty then
|
||||
return (#[], mvarId)
|
||||
else withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `assertHypotheses
|
||||
let tag ← getMVarTag mvarId
|
||||
let target ← getMVarType mvarId
|
||||
else mvarId.withContext do
|
||||
mvarId.checkNotAssigned `assertHypotheses
|
||||
let tag ← mvarId.getTag
|
||||
let target ← mvarId.getType
|
||||
let targetNew := hs.foldr (init := target) fun h targetNew =>
|
||||
mkForall h.userName BinderInfo.default h.type targetNew
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew tag
|
||||
let val := hs.foldl (init := mvarNew) fun val h => mkApp val h.value
|
||||
assignExprMVar mvarId val
|
||||
introNP mvarNew.mvarId! hs.size
|
||||
mvarId.assign val
|
||||
mvarNew.mvarId!.introNP hs.size
|
||||
|
||||
@[deprecated MVarId.assertHypotheses]
|
||||
def assertHypotheses (mvarId : MVarId) (hs : Array Hypothesis) : MetaM (Array FVarId × MVarId) := do
|
||||
mvarId.assertHypotheses hs
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -17,15 +17,25 @@ def findLocalDeclWithType? (type : Expr) : MetaM (Option FVarId) := do
|
|||
else
|
||||
return none
|
||||
|
||||
def assumptionCore (mvarId : MVarId) : MetaM Bool :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `assumption
|
||||
match (← findLocalDeclWithType? (← getMVarType mvarId)) with
|
||||
/-- Return `true` if managed to close goal `mvarId` using an assumption. -/
|
||||
def _root_.Lean.MVarId.assumptionCore (mvarId : MVarId) : MetaM Bool :=
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `assumption
|
||||
match (← findLocalDeclWithType? (← mvarId.getType)) with
|
||||
| none => return false
|
||||
| some fvarId => assignExprMVar mvarId (mkFVar fvarId); return true
|
||||
| some fvarId => mvarId.assign (mkFVar fvarId); return true
|
||||
|
||||
def assumption (mvarId : MVarId) : MetaM Unit :=
|
||||
unless (← assumptionCore mvarId) do
|
||||
@[deprecated MVarId.assumptionCore]
|
||||
def assumptionCore (mvarId : MVarId) : MetaM Bool :=
|
||||
mvarId.assumptionCore
|
||||
|
||||
/-- Close goal `mvarId` using an assumption. Throw error message if failed. -/
|
||||
def _root_.Lean.MVarId.assumption (mvarId : MVarId) : MetaM Unit :=
|
||||
unless (← mvarId.assumptionCore) do
|
||||
throwTacticEx `assumption mvarId ""
|
||||
|
||||
@[deprecated MVarId.assumption]
|
||||
def assumption (mvarId : MVarId) : MetaM Unit :=
|
||||
mvarId.assumption
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -43,19 +43,19 @@ private partial def withNewEqs (targets targetsNew : Array Expr) (k : Array Expr
|
|||
loop 0 #[] #[]
|
||||
|
||||
def generalizeTargetsEq (mvarId : MVarId) (motiveType : Expr) (targets : Array Expr) : MetaM MVarId :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `generalizeTargets
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `generalizeTargets
|
||||
let (typeNew, eqRefls) ←
|
||||
forallTelescopeReducing motiveType fun targetsNew _ => do
|
||||
unless targetsNew.size == targets.size do
|
||||
throwError "invalid number of targets #{targets.size}, motive expects #{targetsNew.size}"
|
||||
withNewEqs targets targetsNew fun eqs eqRefls => do
|
||||
let type ← getMVarType mvarId
|
||||
let type ← mvarId.getType
|
||||
let typeNew ← mkForallFVars eqs type
|
||||
let typeNew ← mkForallFVars targetsNew typeNew
|
||||
pure (typeNew, eqRefls)
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar typeNew (← getMVarTag mvarId)
|
||||
assignExprMVar mvarId (mkAppN (mkAppN mvarNew targets) eqRefls)
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar typeNew (← mvarId.getTag)
|
||||
mvarId.assign (mkAppN (mkAppN mvarNew targets) eqRefls)
|
||||
pure mvarNew.mvarId!
|
||||
|
||||
structure GeneralizeIndicesSubgoal where
|
||||
|
|
@ -83,10 +83,10 @@ structure GeneralizeIndicesSubgoal where
|
|||
- `fvarId`: `h'` id
|
||||
- `numEqs`: number of equations in the target -/
|
||||
def generalizeIndices (mvarId : MVarId) (fvarId : FVarId) : MetaM GeneralizeIndicesSubgoal :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let lctx ← getLCtx
|
||||
let localInsts ← getLocalInstances
|
||||
checkNotAssigned mvarId `generalizeIndices
|
||||
mvarId.checkNotAssigned `generalizeIndices
|
||||
let fvarDecl ← getLocalDecl fvarId
|
||||
let type ← whnf fvarDecl.type
|
||||
type.withApp fun f args => matchConstInduct f (fun _ => throwTacticEx `generalizeIndices mvarId "inductive type expected") fun val _ => do
|
||||
|
|
@ -104,17 +104,17 @@ def generalizeIndices (mvarId : MVarId) (fvarId : FVarId) : MetaM GeneralizeIndi
|
|||
withLocalDeclD `h newEqType fun newEq => do
|
||||
let newEqs := newEqs.push newEq
|
||||
/- auxType `forall (j' : J) (h' : I A j'), j == j' -> h == h' -> target -/
|
||||
let target ← getMVarType mvarId
|
||||
let tag ← getMVarTag mvarId
|
||||
let target ← mvarId.getType
|
||||
let tag ← mvarId.getTag
|
||||
let auxType ← mkForallFVars newEqs target
|
||||
let auxType ← mkForallFVars #[h'] auxType
|
||||
let auxType ← mkForallFVars newIndices auxType
|
||||
let newMVar ← mkFreshExprMVarAt lctx localInsts auxType MetavarKind.syntheticOpaque tag
|
||||
/- assign mvarId := newMVar indices h refls -/
|
||||
assignExprMVar mvarId (mkAppN (mkApp (mkAppN newMVar indices) fvarDecl.toExpr) newRefls)
|
||||
let (indicesFVarIds, newMVarId) ← introNP newMVar.mvarId! newIndices.size
|
||||
let (fvarId, newMVarId) ← intro1P newMVarId
|
||||
pure {
|
||||
mvarId.assign (mkAppN (mkApp (mkAppN newMVar indices) fvarDecl.toExpr) newRefls)
|
||||
let (indicesFVarIds, newMVarId) ← newMVar.mvarId!.introNP newIndices.size
|
||||
let (fvarId, newMVarId) ← newMVarId.intro1P
|
||||
return {
|
||||
mvarId := newMVarId,
|
||||
indicesFVarIds := indicesFVarIds,
|
||||
fvarId := fvarId,
|
||||
|
|
@ -182,7 +182,7 @@ private def elimAuxIndices (s₁ : GeneralizeIndicesSubgoal) (s₂ : Array Cases
|
|||
indicesFVarIds.foldlM (init := s) fun s indexFVarId =>
|
||||
match s.subst.get indexFVarId with
|
||||
| Expr.fvar indexFVarId' =>
|
||||
(do let mvarId ← clear s.mvarId indexFVarId'; pure { s with mvarId := mvarId, subst := s.subst.erase indexFVarId })
|
||||
(do let mvarId ← s.mvarId.clear indexFVarId'; pure { s with mvarId := mvarId, subst := s.subst.erase indexFVarId })
|
||||
<|>
|
||||
(pure s)
|
||||
| _ => pure s
|
||||
|
|
@ -203,7 +203,7 @@ partial def unifyEqs? (numEqs : Nat) (mvarId : MVarId) (subst : FVarSubst) (case
|
|||
if numEqs == 0 then
|
||||
return some (mvarId, subst)
|
||||
else
|
||||
let (eqFVarId, mvarId) ← intro1 mvarId
|
||||
let (eqFVarId, mvarId) ← mvarId.intro1
|
||||
if let some { mvarId, subst, numNewEqs } ← unifyEq? mvarId eqFVarId subst acyclic caseName? then
|
||||
unifyEqs? (numEqs - 1 + numNewEqs) mvarId subst caseName?
|
||||
else
|
||||
|
|
@ -221,19 +221,18 @@ private def unifyCasesEqs (numEqs : Nat) (subgoals : Array CasesSubgoal) : MetaM
|
|||
}
|
||||
|
||||
private def inductionCasesOn (mvarId : MVarId) (majorFVarId : FVarId) (givenNames : Array AltVarNames) (ctx : Context)
|
||||
: MetaM (Array CasesSubgoal) := do
|
||||
withMVarContext mvarId do
|
||||
: MetaM (Array CasesSubgoal) := mvarId.withContext do
|
||||
let majorType ← inferType (mkFVar majorFVarId)
|
||||
let (us, params) ← getInductiveUniverseAndParams majorType
|
||||
let casesOn := mkCasesOnName ctx.inductiveVal.name
|
||||
let ctors := ctx.inductiveVal.ctors.toArray
|
||||
let s ← induction mvarId majorFVarId casesOn givenNames
|
||||
let s ← mvarId.induction majorFVarId casesOn givenNames
|
||||
return toCasesSubgoals s ctors majorFVarId us params
|
||||
|
||||
def cases (mvarId : MVarId) (majorFVarId : FVarId) (givenNames : Array AltVarNames := #[]) : MetaM (Array CasesSubgoal) := do
|
||||
try
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `cases
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `cases
|
||||
let context? ← mkCasesContext? majorFVarId
|
||||
match context? with
|
||||
| none => throwTacticEx `cases mvarId "not applicable to the given hypothesis"
|
||||
|
|
@ -260,7 +259,7 @@ def cases (mvarId : MVarId) (majorFVarId : FVarId) (givenNames : Array AltVarNam
|
|||
|
||||
def casesRec (mvarId : MVarId) (p : LocalDecl → MetaM Bool) : MetaM (List MVarId) :=
|
||||
saturate mvarId fun mvarId =>
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
for localDecl in (← getLCtx) do
|
||||
if (← p localDecl) then
|
||||
let r? ← observing? do
|
||||
|
|
@ -285,8 +284,8 @@ structure ByCasesSubgoal where
|
|||
fvarId : FVarId
|
||||
|
||||
def byCases (mvarId : MVarId) (p : Expr) (hName : Name := `h) : MetaM (ByCasesSubgoal × ByCasesSubgoal) := do
|
||||
let mvarId ← assert mvarId `hByCases (mkOr p (mkNot p)) (mkEM p)
|
||||
let (fvarId, mvarId) ← intro1 mvarId
|
||||
let mvarId ← mvarId.assert `hByCases (mkOr p (mkNot p)) (mkEM p)
|
||||
let (fvarId, mvarId) ← mvarId.intro1
|
||||
let #[s₁, s₂] ← cases mvarId fvarId #[{ varNames := [hName] }, { varNames := [hName] }] |
|
||||
throwError "'byCases' tactic failed, unexpected number of subgoals"
|
||||
return ((← toByCasesSubgoal s₁), (← toByCasesSubgoal s₂))
|
||||
|
|
|
|||
|
|
@ -8,24 +8,17 @@ import Lean.Meta.Tactic.Clear
|
|||
|
||||
namespace Lean.Meta
|
||||
|
||||
/--
|
||||
Auxiliary tactic for cleaning the local context. It removes local declarations (aka hypotheses) that are *not* relevant.
|
||||
We say a variable `x` is "relevant" if
|
||||
- It occurs in the target type, or
|
||||
- There is a relevant variable `y` that depends on `x`, or
|
||||
- The type of `x` is a proposition and it depends on a relevant variable `y`.
|
||||
-/
|
||||
partial def cleanup (mvarId : MVarId) : MetaM MVarId := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `cleanup
|
||||
private partial def cleanupCore (mvarId : MVarId) : MetaM MVarId := do
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `cleanup
|
||||
let used ← collectUsed |>.run' (false, {})
|
||||
let mut lctx ← getLCtx
|
||||
for localDecl in lctx do
|
||||
unless used.contains localDecl.fvarId do
|
||||
lctx := lctx.erase localDecl.fvarId
|
||||
let localInsts := (← getLocalInstances).filter fun inst => used.contains inst.fvar.fvarId!
|
||||
let mvarNew ← mkFreshExprMVarAt lctx localInsts (← instantiateMVars (← getMVarType mvarId)) MetavarKind.syntheticOpaque (← getMVarTag mvarId)
|
||||
assignExprMVar mvarId mvarNew
|
||||
let mvarNew ← mkFreshExprMVarAt lctx localInsts (← instantiateMVars (← mvarId.getType)) .syntheticOpaque (← mvarId.getTag)
|
||||
mvarId.assign mvarNew
|
||||
return mvarNew.mvarId!
|
||||
where
|
||||
addUsedFVars (e : Expr) : StateRefT (Bool × FVarIdSet) MetaM Unit := do
|
||||
|
|
@ -59,8 +52,22 @@ where
|
|||
collectProps
|
||||
|
||||
collectUsed : StateRefT (Bool × FVarIdSet) MetaM FVarIdSet := do
|
||||
addUsedFVars (← instantiateMVars (← getMVarType mvarId))
|
||||
addUsedFVars (← instantiateMVars (← mvarId.getType))
|
||||
collectProps
|
||||
return (← get).2
|
||||
|
||||
/--
|
||||
Auxiliary tactic for cleaning the local context. It removes local declarations (aka hypotheses) that are *not* relevant.
|
||||
We say a variable `x` is "relevant" if
|
||||
- It occurs in the target type, or
|
||||
- There is a relevant variable `y` that depends on `x`, or
|
||||
- The type of `x` is a proposition and it depends on a relevant variable `y`.
|
||||
-/
|
||||
abbrev _root_.Lean.MVarId.cleanup (mvarId : MVarId) : MetaM MVarId := do
|
||||
cleanupCore mvarId
|
||||
|
||||
@[deprecated MVarId.cleanup]
|
||||
abbrev cleanup (mvarId : MVarId) : MetaM MVarId := do
|
||||
mvarId.cleanup
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -7,18 +7,21 @@ import Lean.Meta.Tactic.Util
|
|||
|
||||
namespace Lean.Meta
|
||||
|
||||
def clear (mvarId : MVarId) (fvarId : FVarId) : MetaM MVarId :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `clear
|
||||
/--
|
||||
Erase the given free variable from the goal `mvarId`.
|
||||
-/
|
||||
def _root_.Lean.MVarId.clear (mvarId : MVarId) (fvarId : FVarId) : MetaM MVarId :=
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `clear
|
||||
let lctx ← getLCtx
|
||||
unless lctx.contains fvarId do
|
||||
throwTacticEx `clear mvarId m!"unknown variable '{mkFVar fvarId}'"
|
||||
let tag ← getMVarTag mvarId
|
||||
let tag ← mvarId.getTag
|
||||
lctx.forM fun localDecl => do
|
||||
unless localDecl.fvarId == fvarId do
|
||||
if (← localDeclDependsOn localDecl fvarId) then
|
||||
throwTacticEx `clear mvarId m!"variable '{localDecl.toExpr}' depends on '{mkFVar fvarId}'"
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
if (← exprDependsOn mvarDecl.type fvarId) then
|
||||
throwTacticEx `clear mvarId m!"target depends on '{mkFVar fvarId}'"
|
||||
let lctx := lctx.erase fvarId
|
||||
|
|
@ -27,13 +30,33 @@ def clear (mvarId : MVarId) (fvarId : FVarId) : MetaM MVarId :=
|
|||
| none => localInsts
|
||||
| some idx => localInsts.eraseIdx idx
|
||||
let newMVar ← mkFreshExprMVarAt lctx localInsts mvarDecl.type MetavarKind.syntheticOpaque tag
|
||||
assignExprMVar mvarId newMVar
|
||||
mvarId.assign newMVar
|
||||
pure newMVar.mvarId!
|
||||
|
||||
def tryClear (mvarId : MVarId) (fvarId : FVarId) : MetaM MVarId :=
|
||||
clear mvarId fvarId <|> pure mvarId
|
||||
|
||||
@[deprecated MVarId.clear]
|
||||
def clear (mvarId : MVarId) (fvarId : FVarId) : MetaM MVarId :=
|
||||
mvarId.clear fvarId
|
||||
|
||||
/--
|
||||
Try to erase the given free variable from the goal `mvarId`. It is no-op if the free variable
|
||||
cannot be erased due to forward dependencies.
|
||||
-/
|
||||
def _root_.Lean.MVarId.tryClear (mvarId : MVarId) (fvarId : FVarId) : MetaM MVarId :=
|
||||
mvarId.clear fvarId <|> pure mvarId
|
||||
|
||||
@[deprecated MVarId.tryClear]
|
||||
def tryClear (mvarId : MVarId) (fvarId : FVarId) : MetaM MVarId :=
|
||||
mvarId.tryClear fvarId
|
||||
|
||||
/--
|
||||
Try to erase the given free variables from the goal `mvarId`.
|
||||
-/
|
||||
def _root_.Lean.MVarId.tryClearMany (mvarId : MVarId) (fvarIds : Array FVarId) : MetaM MVarId := do
|
||||
fvarIds.foldrM (init := mvarId) fun fvarId mvarId => mvarId.tryClear fvarId
|
||||
|
||||
@[deprecated MVarId.tryClearMany]
|
||||
def tryClearMany (mvarId : MVarId) (fvarIds : Array FVarId) : MetaM MVarId := do
|
||||
fvarIds.foldrM (init := mvarId) fun fvarId mvarId => tryClear mvarId fvarId
|
||||
mvarId.tryClearMany fvarIds
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -10,27 +10,31 @@ import Lean.Meta.Tactic.Apply
|
|||
namespace Lean.Meta
|
||||
|
||||
/--
|
||||
When the goal `mvarId` is an inductive datatype,
|
||||
When the goal `mvarId` type is an inductive datatype,
|
||||
`constructor` calls `apply` with the first matching constructor.
|
||||
-/
|
||||
def constructor (mvarId : MVarId) (cfg : ApplyConfig := {}) : MetaM (List MVarId) := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `constructor
|
||||
let target ← getMVarType' mvarId
|
||||
def _root_.Lean.MVarId.constructor (mvarId : MVarId) (cfg : ApplyConfig := {}) : MetaM (List MVarId) := do
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `constructor
|
||||
let target ← mvarId.getType'
|
||||
matchConstInduct target.getAppFn
|
||||
(fun _ => throwTacticEx `constructor mvarId "target is not an inductive datatype")
|
||||
fun ival us => do
|
||||
for ctor in ival.ctors do
|
||||
try
|
||||
return ← apply mvarId (Lean.mkConst ctor us) cfg
|
||||
return ← mvarId.apply (Lean.mkConst ctor us) cfg
|
||||
catch _ =>
|
||||
pure ()
|
||||
throwTacticEx `constructor mvarId "no applicable constructor found"
|
||||
|
||||
def existsIntro (mvarId : MVarId) (w : Expr) : MetaM MVarId := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `exists
|
||||
let target ← getMVarType' mvarId
|
||||
@[deprecated MVarId.constructor]
|
||||
def constructor (mvarId : MVarId) (cfg : ApplyConfig := {}) : MetaM (List MVarId) := do
|
||||
mvarId.constructor cfg
|
||||
|
||||
def _root_.Lean.MVarId.existsIntro (mvarId : MVarId) (w : Expr) : MetaM MVarId := do
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `exists
|
||||
let target ← mvarId.getType'
|
||||
matchConstStruct target.getAppFn
|
||||
(fun _ => throwTacticEx `exists mvarId "target is not an inductive datatype with one constructor")
|
||||
fun _ us cval => do
|
||||
|
|
@ -41,8 +45,12 @@ def existsIntro (mvarId : MVarId) (w : Expr) : MetaM MVarId := do
|
|||
let (mvars, _, _) ← forallMetaTelescopeReducing ctorType (some (cval.numFields-2))
|
||||
let f := mkAppN ctor mvars
|
||||
checkApp f w
|
||||
let [mvarId] ← apply mvarId <| mkApp f w
|
||||
let [mvarId] ← mvarId.apply <| mkApp f w
|
||||
| throwTacticEx `exists mvarId "unexpected number of subgoals"
|
||||
pure mvarId
|
||||
|
||||
@[deprecated MVarId.existsIntro]
|
||||
def existsIntro (mvarId : MVarId) (w : Expr) : MetaM MVarId := do
|
||||
mvarId.existsIntro w
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ structure Contradiction.Config where
|
|||
Return `true` iff the goal has been closed.
|
||||
-/
|
||||
private def nestedFalseElim (mvarId : MVarId) : MetaM Bool := do
|
||||
let target ← getMVarType mvarId
|
||||
let target ← mvarId.getType
|
||||
if let some falseElim := target.find? fun e => e.isAppOfArity ``False.elim 2 && !e.appArg!.hasLooseBVars then
|
||||
let falseProof := falseElim.appArg!
|
||||
assignExprMVar mvarId (← mkFalseElim (← getMVarType mvarId) falseProof)
|
||||
mvarId.assign (← mkFalseElim (← mvarId.getType) falseProof)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
|
@ -62,7 +62,7 @@ partial def elim (mvarId : MVarId) (fvarId : FVarId) : M Bool := do
|
|||
trace[Meta.Tactic.contradiction] "elimEmptyInductive, number subgoals: {subgoals.size}"
|
||||
for subgoal in subgoals do
|
||||
-- If one of the fields is uninhabited, then we are done
|
||||
let found ← withMVarContext subgoal.mvarId do
|
||||
let found ← subgoal.mvarId.withContext do
|
||||
for field in subgoal.fields do
|
||||
let field := subgoal.subst.apply field
|
||||
if field.isFVar then
|
||||
|
|
@ -77,7 +77,7 @@ partial def elim (mvarId : MVarId) (fvarId : FVarId) : M Bool := do
|
|||
end ElimEmptyInductive
|
||||
|
||||
private def elimEmptyInductive (mvarId : MVarId) (fvarId : FVarId) (fuel : Nat) : MetaM Bool := do
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
if (← isElimEmptyInductiveCandidate fvarId) then
|
||||
commitWhen do
|
||||
ElimEmptyInductive.elim (← exfalso mvarId) fvarId |>.run' fuel
|
||||
|
|
@ -139,16 +139,16 @@ private def processGenDiseq (mvarId : MVarId) (localDecl : LocalDecl) : MetaM Bo
|
|||
let falseProof ← instantiateMVars (mkAppN localDecl.toExpr args)
|
||||
if (← hasAssignableMVar falseProof) then
|
||||
return none
|
||||
return some (← mkFalseElim (← getMVarType mvarId) falseProof)
|
||||
return some (← mkFalseElim (← mvarId.getType) falseProof)
|
||||
if let some val := val? then
|
||||
assignExprMVar mvarId val
|
||||
mvarId.assign val
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
||||
def contradictionCore (mvarId : MVarId) (config : Contradiction.Config) : MetaM Bool := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `contradiction
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `contradiction
|
||||
if (← nestedFalseElim mvarId) then
|
||||
return true
|
||||
for localDecl in (← getLCtx) do
|
||||
|
|
@ -156,12 +156,12 @@ def contradictionCore (mvarId : MVarId) (config : Contradiction.Config) : MetaM
|
|||
-- (h : ¬ p) (h' : p)
|
||||
if let some p ← matchNot? localDecl.type then
|
||||
if let some pFVarId ← findLocalDeclWithType? p then
|
||||
assignExprMVar mvarId (← mkAbsurd (← getMVarType mvarId) (mkFVar pFVarId) localDecl.toExpr)
|
||||
mvarId.assign (← mkAbsurd (← mvarId.getType) (mkFVar pFVarId) localDecl.toExpr)
|
||||
return true
|
||||
-- (h : x ≠ x)
|
||||
if let some (_, lhs, rhs) ← matchNe? localDecl.type then
|
||||
if (← isDefEq lhs rhs) then
|
||||
assignExprMVar mvarId (← mkAbsurd (← getMVarType mvarId) (← mkEqRefl lhs) localDecl.toExpr)
|
||||
mvarId.assign (← mkAbsurd (← mvarId.getType) (← mkEqRefl lhs) localDecl.toExpr)
|
||||
return true
|
||||
let mut isEq := false
|
||||
-- (h : ctor₁ ... = ctor₂ ...)
|
||||
|
|
@ -170,7 +170,7 @@ def contradictionCore (mvarId : MVarId) (config : Contradiction.Config) : MetaM
|
|||
if let some lhsCtor ← matchConstructorApp? lhs then
|
||||
if let some rhsCtor ← matchConstructorApp? rhs then
|
||||
if lhsCtor.name != rhsCtor.name then
|
||||
assignExprMVar mvarId (← mkNoConfusion (← getMVarType mvarId) localDecl.toExpr)
|
||||
mvarId.assign (← mkNoConfusion (← mvarId.getType) localDecl.toExpr)
|
||||
return true
|
||||
let mut isHEq := false
|
||||
-- (h : HEq (ctor₁ ...) (ctor₂ ...))
|
||||
|
|
@ -180,7 +180,7 @@ def contradictionCore (mvarId : MVarId) (config : Contradiction.Config) : MetaM
|
|||
if let some rhsCtor ← matchConstructorApp? rhs then
|
||||
if lhsCtor.name != rhsCtor.name then
|
||||
if (← isDefEq α β) then
|
||||
assignExprMVar mvarId (← mkNoConfusion (← getMVarType mvarId) (← mkEqOfHEq localDecl.toExpr))
|
||||
mvarId.assign (← mkNoConfusion (← mvarId.getType) (← mkEqOfHEq localDecl.toExpr))
|
||||
return true
|
||||
-- (h : p) s.t. `decide p` evaluates to `false`
|
||||
if config.useDecide && !localDecl.type.hasFVar then
|
||||
|
|
@ -191,7 +191,7 @@ def contradictionCore (mvarId : MVarId) (config : Contradiction.Config) : MetaM
|
|||
let r ← withDefault <| whnf d
|
||||
if r.isConstOf ``false then
|
||||
let hn := mkAppN (mkConst ``of_decide_eq_false) <| d.getAppArgs.push (← mkEqRefl d)
|
||||
assignExprMVar mvarId (← mkAbsurd (← getMVarType mvarId) localDecl.toExpr hn)
|
||||
mvarId.assign (← mkAbsurd (← mvarId.getType) localDecl.toExpr hn)
|
||||
return true
|
||||
catch _ =>
|
||||
pure ()
|
||||
|
|
|
|||
|
|
@ -23,14 +23,28 @@ def deltaExpand (e : Expr) (p : Name → Bool) : CoreM Expr :=
|
|||
| some e' => return TransformStep.visit e'
|
||||
| none => return TransformStep.visit e
|
||||
|
||||
def deltaTarget (mvarId : MVarId) (p : Name → Bool) : MetaM MVarId :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `delta
|
||||
change mvarId (← deltaExpand (← getMVarType mvarId) p) (checkDefEq := false)
|
||||
/--
|
||||
Delta expand declarations that satisfy `p` at `mvarId` type.
|
||||
-/
|
||||
def _root_.Lean.MVarId.deltaTarget (mvarId : MVarId) (p : Name → Bool) : MetaM MVarId :=
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `delta
|
||||
mvarId.change (← deltaExpand (← mvarId.getType) p) (checkDefEq := false)
|
||||
|
||||
@[deprecated MVarId.deltaTarget]
|
||||
def deltaTarget (mvarId : MVarId) (p : Name → Bool) : MetaM MVarId :=
|
||||
mvarId.deltaTarget p
|
||||
|
||||
/--
|
||||
Delta expand declarations that satisfy `p` at `fvarId` type.
|
||||
-/
|
||||
def _root_.Lean.MVarId.deltaLocalDecl (mvarId : MVarId) (fvarId : FVarId) (p : Name → Bool) : MetaM MVarId :=
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `delta
|
||||
mvarId.changeLocalDecl fvarId (← deltaExpand (← mvarId.getType) p) (checkDefEq := false)
|
||||
|
||||
@[deprecated MVarId.deltaLocalDecl]
|
||||
def deltaLocalDecl (mvarId : MVarId) (fvarId : FVarId) (p : Name → Bool) : MetaM MVarId :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `delta
|
||||
changeLocalDecl mvarId fvarId (← deltaExpand (← getMVarType mvarId) p) (checkDefEq := false)
|
||||
mvarId.deltaLocalDecl fvarId p
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ partial def generalize
|
|||
(mvarId : MVarId) (args : Array GeneralizeArg)
|
||||
-- (pred : (parent? : Option Expr) → (e : Expr) → MetaM Bool := fun _ _ => return true)
|
||||
: MetaM (Array FVarId × MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `generalize
|
||||
let tag ← getMVarTag mvarId
|
||||
let target ← instantiateMVars (← getMVarType mvarId)
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `generalize
|
||||
let tag ← mvarId.getTag
|
||||
let target ← instantiateMVars (← mvarId.getType)
|
||||
let rec go (i : Nat) : MetaM Expr := do
|
||||
if i < args.size then
|
||||
let arg := args[i]!
|
||||
|
|
@ -40,8 +40,8 @@ partial def generalize
|
|||
let es := args.map (·.expr)
|
||||
if !args.any fun arg => arg.hName?.isSome then
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew tag
|
||||
assignExprMVar mvarId (mkAppN mvarNew es)
|
||||
introNP mvarNew.mvarId! args.size
|
||||
mvarId.assign (mkAppN mvarNew es)
|
||||
mvarNew.mvarId!.introNP args.size
|
||||
else
|
||||
let (rfls, targetNew) ← forallBoundedTelescope targetNew args.size fun xs type => do
|
||||
let rec go' (i : Nat) : MetaM (List Expr × Expr) := do
|
||||
|
|
@ -64,7 +64,7 @@ partial def generalize
|
|||
let (rfls, type) ← go' 0
|
||||
return (rfls, ← mkForallFVars xs type)
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew tag
|
||||
assignExprMVar mvarId (mkAppN (mkAppN mvarNew es) rfls.toArray)
|
||||
introNP mvarNew.mvarId! (args.size + rfls.length)
|
||||
mvarId.assign (mkAppN (mkAppN mvarNew es) rfls.toArray)
|
||||
mvarNew.mvarId!.introNP (args.size + rfls.length)
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ private partial def finalize
|
|||
(mvarId : MVarId) (givenNames : Array AltVarNames) (recursorInfo : RecursorInfo)
|
||||
(reverted : Array FVarId) (major : Expr) (indices : Array Expr) (baseSubst : FVarSubst) (recursor : Expr)
|
||||
: MetaM (Array InductionSubgoal) := do
|
||||
let target ← getMVarType mvarId
|
||||
let target ← mvarId.getType
|
||||
let initialArity := getTargetArity target
|
||||
let recursorType ← inferType recursor
|
||||
let numMinors := recursorInfo.produceMotive.length
|
||||
|
|
@ -73,7 +73,7 @@ private partial def finalize
|
|||
loop (pos+1+indices.size) minorIdx recursor recursorType true subgoals
|
||||
else
|
||||
-- consume motive
|
||||
let tag ← getMVarTag mvarId
|
||||
let tag ← mvarId.getTag
|
||||
if minorIdx ≥ numMinors then throwTacticEx `induction mvarId "ill-formed recursor"
|
||||
match recursorType with
|
||||
| Expr.forallE n d _ c =>
|
||||
|
|
@ -101,9 +101,9 @@ private partial def finalize
|
|||
let recursor := mkApp recursor mvar
|
||||
let recursorType ← getTypeBody mvarId recursorType mvar
|
||||
-- Try to clear major premise from new goal
|
||||
let mvarId' ← tryClear mvar.mvarId! major.fvarId!
|
||||
let (fields, mvarId') ← introN mvarId' nparams minorGivenNames.varNames (useNamesForExplicitOnly := !minorGivenNames.explicit)
|
||||
let (extra, mvarId') ← introNP mvarId' nextra
|
||||
let mvarId' ← mvar.mvarId!.tryClear major.fvarId!
|
||||
let (fields, mvarId') ← mvarId'.introN nparams minorGivenNames.varNames (useNamesForExplicitOnly := !minorGivenNames.explicit)
|
||||
let (extra, mvarId') ← mvarId'.introNP nextra
|
||||
let subst := reverted.size.fold (init := baseSubst) fun i (subst : FVarSubst) =>
|
||||
if i < indices.size + 1 then subst
|
||||
else
|
||||
|
|
@ -115,17 +115,17 @@ private partial def finalize
|
|||
| _ => unreachable!
|
||||
else
|
||||
unless consumedMajor do throwTacticEx `induction mvarId "ill-formed recursor"
|
||||
assignExprMVar mvarId recursor
|
||||
mvarId.assign recursor
|
||||
pure subgoals
|
||||
loop (recursorInfo.paramsPos.length + 1) 0 recursor recursorType false #[]
|
||||
|
||||
private def throwUnexpectedMajorType {α} (mvarId : MVarId) (majorType : Expr) : MetaM α :=
|
||||
throwTacticEx `induction mvarId m!"unexpected major premise type{indentExpr majorType}"
|
||||
|
||||
def induction (mvarId : MVarId) (majorFVarId : FVarId) (recursorName : Name) (givenNames : Array AltVarNames := #[]) : MetaM (Array InductionSubgoal) :=
|
||||
withMVarContext mvarId do
|
||||
def _root_.Lean.MVarId.induction (mvarId : MVarId) (majorFVarId : FVarId) (recursorName : Name) (givenNames : Array AltVarNames := #[]) : MetaM (Array InductionSubgoal) :=
|
||||
mvarId.withContext do
|
||||
trace[Meta.Tactic.induction] "initial\n{MessageData.ofGoal mvarId}"
|
||||
checkNotAssigned mvarId `induction
|
||||
mvarId.checkNotAssigned `induction
|
||||
let majorLocalDecl ← getLocalDecl majorFVarId
|
||||
let recursorInfo ← mkRecursorInfo recursorName
|
||||
let some majorType ← whnfUntil majorLocalDecl.type recursorInfo.typeName | throwUnexpectedMajorType mvarId majorLocalDecl.type
|
||||
|
|
@ -152,14 +152,14 @@ def induction (mvarId : MVarId) (majorFVarId : FVarId) (recursorName : Name) (gi
|
|||
if (← localDeclDependsOn idxDecl arg.fvarId!) then
|
||||
throwTacticEx `induction mvarId m!"'{idx}' is an index in major premise, but it depends on index occurring at position #{i+1}"
|
||||
pure idx
|
||||
let target ← getMVarType mvarId
|
||||
let target ← mvarId.getType
|
||||
if (← pure !recursorInfo.depElim <&&> exprDependsOn target majorFVarId) then
|
||||
throwTacticEx `induction mvarId m!"recursor '{recursorName}' does not support dependent elimination, but conclusion depends on major premise"
|
||||
-- Revert indices and major premise preserving variable order
|
||||
let (reverted, mvarId) ← revert mvarId ((indices.map Expr.fvarId!).push majorFVarId) true
|
||||
let (reverted, mvarId) ← mvarId.revert ((indices.map Expr.fvarId!).push majorFVarId) true
|
||||
-- Re-introduce indices and major
|
||||
let (indices', mvarId) ← introNP mvarId indices.size
|
||||
let (majorFVarId', mvarId) ← intro1P mvarId
|
||||
let (indices', mvarId) ← mvarId.introNP indices.size
|
||||
let (majorFVarId', mvarId) ← mvarId.intro1P
|
||||
-- Create FVarSubst with indices
|
||||
let baseSubst := Id.run do
|
||||
let mut subst : FVarSubst := {}
|
||||
|
|
@ -173,8 +173,8 @@ def induction (mvarId : MVarId) (majorFVarId : FVarId) (recursorName : Name) (gi
|
|||
let indices := indices'.map mkFVar
|
||||
let majorFVarId := majorFVarId'
|
||||
let major := mkFVar majorFVarId
|
||||
withMVarContext mvarId do
|
||||
let target ← getMVarType mvarId
|
||||
mvarId.withContext do
|
||||
let target ← mvarId.getType
|
||||
let targetLevel ← getLevel target
|
||||
let targetLevel ← normalizeLevel targetLevel
|
||||
let majorLocalDecl ← getLocalDecl majorFVarId
|
||||
|
|
@ -206,6 +206,10 @@ def induction (mvarId : MVarId) (majorFVarId : FVarId) (recursorName : Name) (gi
|
|||
| _ =>
|
||||
throwTacticEx `induction mvarId "major premise is not of the form (C ...)"
|
||||
|
||||
@[deprecated MVarId.induction]
|
||||
def induction (mvarId : MVarId) (majorFVarId : FVarId) (recursorName : Name) (givenNames : Array AltVarNames := #[]) : MetaM (Array InductionSubgoal) :=
|
||||
mvarId.induction majorFVarId recursorName givenNames
|
||||
|
||||
builtin_initialize registerTraceClass `Meta.Tactic.induction
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ inductive InjectionResultCore where
|
|||
| subgoal (mvarId : MVarId) (numNewEqs : Nat)
|
||||
|
||||
def injectionCore (mvarId : MVarId) (fvarId : FVarId) : MetaM InjectionResultCore :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `injection
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `injection
|
||||
let decl ← getLocalDecl fvarId
|
||||
let type ← whnf decl.type
|
||||
let go (type prf : Expr) : MetaM InjectionResultCore := do
|
||||
|
|
@ -35,13 +35,13 @@ def injectionCore (mvarId : MVarId) (fvarId : FVarId) : MetaM InjectionResultCor
|
|||
| some (_, a, b) =>
|
||||
let a ← whnf a
|
||||
let b ← whnf b
|
||||
let target ← getMVarType mvarId
|
||||
let target ← mvarId.getType
|
||||
let env ← getEnv
|
||||
match a.isConstructorApp? env, b.isConstructorApp? env with
|
||||
| some aCtor, some bCtor =>
|
||||
let val ← mkNoConfusion target prf
|
||||
if aCtor.name != bCtor.name then
|
||||
assignExprMVar mvarId val
|
||||
mvarId.assign val
|
||||
return InjectionResultCore.solved
|
||||
else
|
||||
let valType ← inferType val
|
||||
|
|
@ -49,10 +49,10 @@ def injectionCore (mvarId : MVarId) (fvarId : FVarId) : MetaM InjectionResultCor
|
|||
match valType with
|
||||
| Expr.forallE _ newTarget _ _ =>
|
||||
let newTarget := newTarget.headBeta
|
||||
let tag ← getMVarTag mvarId
|
||||
let tag ← mvarId.getTag
|
||||
let newMVar ← mkFreshExprSyntheticOpaqueMVar newTarget tag
|
||||
assignExprMVar mvarId (mkApp val newMVar)
|
||||
let mvarId ← tryClear newMVar.mvarId! fvarId
|
||||
mvarId.assign (mkApp val newMVar)
|
||||
let mvarId ← newMVar.mvarId!.tryClear fvarId
|
||||
/- Recall that `noConfusion` does not include equalities for
|
||||
propositions since they are trivial due to proof irrelevance. -/
|
||||
let numPropFields ← getCtorNumPropFields aCtor
|
||||
|
|
@ -78,11 +78,11 @@ def injectionIntro (mvarId : MVarId) (numEqs : Nat) (newNames : List Name) (tryT
|
|||
| 0, mvarId, fvarIds, remainingNames =>
|
||||
return InjectionResult.subgoal mvarId fvarIds remainingNames
|
||||
| n+1, mvarId, fvarIds, name::remainingNames => do
|
||||
let (fvarId, mvarId) ← intro mvarId name
|
||||
let (fvarId, mvarId) ← mvarId.intro name
|
||||
let (fvarId, mvarId) ← heqToEq mvarId fvarId tryToClear
|
||||
go n mvarId (fvarIds.push fvarId) remainingNames
|
||||
| n+1, mvarId, fvarIds, [] => do
|
||||
let (fvarId, mvarId) ← intro1 mvarId
|
||||
let (fvarId, mvarId) ← mvarId.intro1
|
||||
let (fvarId, mvarId) ← heqToEq mvarId fvarId tryToClear
|
||||
go n mvarId (fvarIds.push fvarId) []
|
||||
go numEqs mvarId #[] newNames
|
||||
|
|
@ -93,7 +93,7 @@ def injection (mvarId : MVarId) (fvarId : FVarId) (newNames : List Name := []) :
|
|||
| InjectionResultCore.subgoal mvarId numEqs => injectionIntro mvarId numEqs newNames
|
||||
|
||||
partial def injections (mvarId : MVarId) (maxDepth : Nat := 5) : MetaM (Option MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let fvarIds := (← getLCtx).getFVarIds
|
||||
go maxDepth fvarIds.toList mvarId
|
||||
where
|
||||
|
|
@ -112,7 +112,7 @@ where
|
|||
match (← injection mvarId fvarId) with
|
||||
| InjectionResult.solved => return none
|
||||
| InjectionResult.subgoal mvarId newEqs _ =>
|
||||
withMVarContext mvarId <| go d (newEqs.toList ++ fvarIds) mvarId
|
||||
mvarId.withContext <| go d (newEqs.toList ++ fvarIds) mvarId
|
||||
catch _ => cont
|
||||
else cont
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import Lean.Meta.Tactic.Util
|
|||
namespace Lean.Meta
|
||||
|
||||
@[inline] private partial def introNImp {σ} (mvarId : MVarId) (n : Nat) (mkName : LocalContext → Name → Bool → σ → MetaM (Name × σ)) (s : σ)
|
||||
: MetaM (Array FVarId × MVarId) := withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `introN
|
||||
let mvarType ← getMVarType mvarId
|
||||
: MetaM (Array FVarId × MVarId) := mvarId.withContext do
|
||||
mvarId.checkNotAssigned `introN
|
||||
let mvarType ← mvarId.getType
|
||||
let lctx ← getLCtx
|
||||
let rec @[specialize] loop (i : Nat) (lctx : LocalContext) (fvars : Array Expr) (j : Nat) (s : σ) (type : Expr) : MetaM (Array Expr × MVarId) := do
|
||||
match i, type with
|
||||
|
|
@ -18,13 +18,13 @@ namespace Lean.Meta
|
|||
let type := type.instantiateRevRange j fvars.size fvars
|
||||
withReader (fun ctx => { ctx with lctx := lctx }) do
|
||||
withNewLocalInstances fvars j do
|
||||
let tag ← getMVarTag mvarId
|
||||
let tag ← mvarId.getTag
|
||||
let type := type.headBeta
|
||||
let newMVar ← mkFreshExprSyntheticOpaqueMVar type tag
|
||||
let newVal ← mkLambdaFVars fvars newMVar
|
||||
assignExprMVar mvarId newVal
|
||||
mvarId.assign newVal
|
||||
return (fvars, newMVar.mvarId!)
|
||||
| i+1, Expr.letE n type val body _ =>
|
||||
| i+1, .letE n type val body _ =>
|
||||
let type := type.instantiateRevRange j fvars.size fvars
|
||||
let type := type.headBeta
|
||||
let val := val.instantiateRevRange j fvars.size fvars
|
||||
|
|
@ -34,7 +34,7 @@ namespace Lean.Meta
|
|||
let fvar := mkFVar fvarId
|
||||
let fvars := fvars.push fvar
|
||||
loop i lctx fvars j s body
|
||||
| i+1, Expr.forallE n type body c =>
|
||||
| i+1, .forallE n type body c =>
|
||||
let type := type.instantiateRevRange j fvars.size fvars
|
||||
let type := type.headBeta
|
||||
let fvarId ← mkFreshFVarId
|
||||
|
|
@ -100,39 +100,82 @@ def introNCore (mvarId : MVarId) (n : Nat) (givenNames : List Name) (useNamesFor
|
|||
else
|
||||
introNImp mvarId n (mkAuxNameImp preserveBinderNames hygienic useNamesForExplicitOnly) givenNames
|
||||
|
||||
abbrev introN (mvarId : MVarId) (n : Nat) (givenNames : List Name := []) (useNamesForExplicitOnly := false) : MetaM (Array FVarId × MVarId) :=
|
||||
/--
|
||||
Introduce `n` binders in the goal `mvarId`.
|
||||
-/
|
||||
abbrev _root_.Lean.MVarId.introN (mvarId : MVarId) (n : Nat) (givenNames : List Name := []) (useNamesForExplicitOnly := false) : MetaM (Array FVarId × MVarId) :=
|
||||
introNCore mvarId n givenNames (useNamesForExplicitOnly := useNamesForExplicitOnly) (preserveBinderNames := false)
|
||||
|
||||
abbrev introNP (mvarId : MVarId) (n : Nat) : MetaM (Array FVarId × MVarId) :=
|
||||
@[deprecated MVarId.introN]
|
||||
abbrev introN (mvarId : MVarId) (n : Nat) (givenNames : List Name := []) (useNamesForExplicitOnly := false) : MetaM (Array FVarId × MVarId) :=
|
||||
mvarId.introN n givenNames useNamesForExplicitOnly
|
||||
|
||||
/--
|
||||
Introduce `n` binders in the goal `mvarId`. The new hypotheses are named using the binder names.
|
||||
The suffix `P` stands for "preserving`.
|
||||
-/
|
||||
abbrev _root_.Lean.MVarId.introNP (mvarId : MVarId) (n : Nat) : MetaM (Array FVarId × MVarId) :=
|
||||
introNCore mvarId n [] (useNamesForExplicitOnly := false) (preserveBinderNames := true)
|
||||
|
||||
def intro (mvarId : MVarId) (name : Name) : MetaM (FVarId × MVarId) := do
|
||||
let (fvarIds, mvarId) ← introN mvarId 1 [name]
|
||||
@[deprecated MVarId.introNP]
|
||||
abbrev introNP (mvarId : MVarId) (n : Nat) : MetaM (Array FVarId × MVarId) :=
|
||||
mvarId.introNP n
|
||||
|
||||
/--
|
||||
Introduce one binder using `name` as the the new hypothesis name.
|
||||
-/
|
||||
def _root_.Lean.MVarId.intro (mvarId : MVarId) (name : Name) : MetaM (FVarId × MVarId) := do
|
||||
let (fvarIds, mvarId) ← mvarId.introN 1 [name]
|
||||
return (fvarIds[0]!, mvarId)
|
||||
|
||||
@[deprecated MVarId.intro]
|
||||
def intro (mvarId : MVarId) (name : Name) : MetaM (FVarId × MVarId) := do
|
||||
mvarId.intro name
|
||||
|
||||
def intro1Core (mvarId : MVarId) (preserveBinderNames : Bool) : MetaM (FVarId × MVarId) := do
|
||||
let (fvarIds, mvarId) ← introNCore mvarId 1 [] (useNamesForExplicitOnly := false) preserveBinderNames
|
||||
return (fvarIds[0]!, mvarId)
|
||||
|
||||
abbrev intro1 (mvarId : MVarId) : MetaM (FVarId × MVarId) :=
|
||||
/--
|
||||
Introduce one binder.
|
||||
-/
|
||||
abbrev _root_.Lean.MVarId.intro1 (mvarId : MVarId) : MetaM (FVarId × MVarId) :=
|
||||
intro1Core mvarId false
|
||||
|
||||
abbrev intro1P (mvarId : MVarId) : MetaM (FVarId × MVarId) :=
|
||||
@[deprecated MVarId.intro1]
|
||||
abbrev intro1 (mvarId : MVarId) : MetaM (FVarId × MVarId) :=
|
||||
mvarId.intro1
|
||||
|
||||
/--
|
||||
Introduce one binder. The new hypothesis is named using the binder name.
|
||||
-/
|
||||
abbrev _root_.Lean.MVarId.intro1P (mvarId : MVarId) : MetaM (FVarId × MVarId) :=
|
||||
intro1Core mvarId true
|
||||
|
||||
private def getIntrosSize : Expr → Nat
|
||||
| Expr.forallE _ _ b _ => getIntrosSize b + 1
|
||||
| Expr.letE _ _ _ b _ => getIntrosSize b + 1
|
||||
| Expr.mdata _ b => getIntrosSize b
|
||||
| _ => 0
|
||||
@[deprecated MVarId.intro1P]
|
||||
abbrev intro1P (mvarId : MVarId) : MetaM (FVarId × MVarId) :=
|
||||
mvarId.intro1P
|
||||
|
||||
def intros (mvarId : MVarId) : MetaM (Array FVarId × MVarId) := do
|
||||
let type ← Meta.getMVarType mvarId
|
||||
private def getIntrosSize : Expr → Nat
|
||||
| .forallE _ _ b _ => getIntrosSize b + 1
|
||||
| .letE _ _ _ b _ => getIntrosSize b + 1
|
||||
| .mdata _ b => getIntrosSize b
|
||||
| _ => 0
|
||||
|
||||
/--
|
||||
Introduce as many binders as possible without unfolding definitions.
|
||||
-/
|
||||
def _root_.Lean.MVarId.intros (mvarId : MVarId) : MetaM (Array FVarId × MVarId) := do
|
||||
let type ← mvarId.getType
|
||||
let type ← instantiateMVars type
|
||||
let n := getIntrosSize type
|
||||
if n == 0 then
|
||||
return (#[], mvarId)
|
||||
else
|
||||
Meta.introN mvarId n
|
||||
mvarId.introN n
|
||||
|
||||
@[deprecated MVarId.intros]
|
||||
def intros (mvarId : MVarId) : MetaM (Array FVarId × MVarId) := do
|
||||
mvarId.intros
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -8,10 +8,19 @@ import Lean.Meta.Tactic.Util
|
|||
|
||||
namespace Lean.Meta
|
||||
|
||||
def refl (mvarId : MVarId) : MetaM Unit := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `apply
|
||||
let targetType ← getMVarType' mvarId
|
||||
private def useKernel (lhs rhs : Expr) : MetaM Bool := do
|
||||
if lhs.hasFVar || lhs.hasMVar || rhs.hasFVar || rhs.hasMVar then
|
||||
return false
|
||||
else
|
||||
return (← getTransparency) matches TransparencyMode.default | TransparencyMode.all
|
||||
|
||||
/--
|
||||
Close given goal using `Eq.refl`.
|
||||
-/
|
||||
def _root_.Lean.MVarId.refl (mvarId : MVarId) : MetaM Unit := do
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `refl
|
||||
let targetType ← mvarId.getType'
|
||||
unless targetType.isAppOfArity ``Eq 3 do
|
||||
throwTacticEx `rfl mvarId m!"equality expected{indentExpr targetType}"
|
||||
let lhs ← instantiateMVars targetType.appFn!.appArg!
|
||||
|
|
@ -24,12 +33,10 @@ def refl (mvarId : MVarId) : MetaM Unit := do
|
|||
throwTacticEx `rfl mvarId m!"equality lhs{indentExpr lhs}\nis not definitionally equal to rhs{indentExpr rhs}"
|
||||
let us := targetType.getAppFn.constLevels!
|
||||
let α := targetType.appFn!.appFn!.appArg!
|
||||
assignExprMVar mvarId (mkApp2 (mkConst ``Eq.refl us) α lhs)
|
||||
where
|
||||
useKernel (lhs rhs : Expr) : MetaM Bool := do
|
||||
if lhs.hasFVar || lhs.hasMVar || rhs.hasFVar || rhs.hasMVar then
|
||||
return false
|
||||
else
|
||||
return (← getTransparency) matches TransparencyMode.default | TransparencyMode.all
|
||||
mvarId.assign (mkApp2 (mkConst ``Eq.refl us) α lhs)
|
||||
|
||||
@[deprecated MVarId.refl]
|
||||
def refl (mvarId : MVarId) : MetaM Unit := do
|
||||
mvarId.refl
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -7,11 +7,18 @@ import Lean.Meta.Tactic.Util
|
|||
|
||||
namespace Lean.Meta
|
||||
|
||||
def rename (mvarId : MVarId) (fvarId : FVarId) (newUserName : Name) : MetaM MVarId := withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `rename
|
||||
let lctxNew := (← getLCtx).setUserName fvarId newUserName
|
||||
let mvarNew ← mkFreshExprMVarAt lctxNew (← getLocalInstances) (← getMVarType mvarId) MetavarKind.syntheticOpaque (← getMVarTag mvarId)
|
||||
assignExprMVar mvarId mvarNew
|
||||
/--
|
||||
Rename the user-face naming for the free variable `fvarId` at `mvarId`.
|
||||
-/
|
||||
def _root_.Lean.MVarId.rename (mvarId : MVarId) (fvarId : FVarId) (userNameNew : Name) : MetaM MVarId := mvarId.withContext do
|
||||
mvarId.checkNotAssigned `rename
|
||||
let lctxNew := (← getLCtx).setUserName fvarId userNameNew
|
||||
let mvarNew ← mkFreshExprMVarAt lctxNew (← getLocalInstances) (← mvarId.getType) MetavarKind.syntheticOpaque (← mvarId.getTag)
|
||||
mvarId.assign mvarNew
|
||||
return mvarNew.mvarId!
|
||||
|
||||
@[deprecated MVarId.rename]
|
||||
def rename (mvarId : MVarId) (fvarId : FVarId) (newUserName : Name) : MetaM MVarId :=
|
||||
mvarId.rename fvarId newUserName
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -17,19 +17,23 @@ namespace Lean.Meta
|
|||
/--
|
||||
Convert the given goal `Ctx |- target` into `Ctx |- targetNew` using an equality proof `eqProof : target = targetNew`.
|
||||
It assumes `eqProof` has type `target = targetNew` -/
|
||||
def replaceTargetEq (mvarId : MVarId) (targetNew : Expr) (eqProof : Expr) : MetaM MVarId :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `replaceTarget
|
||||
let tag ← getMVarTag mvarId
|
||||
def _root_.Lean.MVarId.replaceTargetEq (mvarId : MVarId) (targetNew : Expr) (eqProof : Expr) : MetaM MVarId :=
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `replaceTarget
|
||||
let tag ← mvarId.getTag
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew tag
|
||||
let target ← getMVarType mvarId
|
||||
let target ← mvarId.getType
|
||||
let u ← getLevel target
|
||||
let eq ← mkEq target targetNew
|
||||
let newProof ← mkExpectedTypeHint eqProof eq
|
||||
let val := mkAppN (Lean.mkConst `Eq.mpr [u]) #[target, targetNew, newProof, mvarNew]
|
||||
assignExprMVar mvarId val
|
||||
mvarId.assign val
|
||||
return mvarNew.mvarId!
|
||||
|
||||
@[deprecated MVarId.replaceTargetEq]
|
||||
def replaceTargetEq (mvarId : MVarId) (targetNew : Expr) (eqProof : Expr) : MetaM MVarId :=
|
||||
mvarId.replaceTargetEq targetNew eqProof
|
||||
|
||||
/--
|
||||
Convert the given goal `Ctx | target` into `Ctx |- targetNew`. It assumes the goals are definitionally equal.
|
||||
We use the proof term
|
||||
|
|
@ -37,35 +41,32 @@ def replaceTargetEq (mvarId : MVarId) (targetNew : Expr) (eqProof : Expr) : Meta
|
|||
@id target mvarNew
|
||||
```
|
||||
to create a checkpoint. -/
|
||||
def replaceTargetDefEq (mvarId : MVarId) (targetNew : Expr) : MetaM MVarId :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `change
|
||||
let target ← getMVarType mvarId
|
||||
def _root_.Lean.MVarId.replaceTargetDefEq (mvarId : MVarId) (targetNew : Expr) : MetaM MVarId :=
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `change
|
||||
let target ← mvarId.getType
|
||||
if target == targetNew then
|
||||
return mvarId
|
||||
else
|
||||
let tag ← getMVarTag mvarId
|
||||
let tag ← mvarId.getTag
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew tag
|
||||
let newVal ← mkExpectedTypeHint mvarNew target
|
||||
assignExprMVar mvarId newVal
|
||||
mvarId.assign newVal
|
||||
return mvarNew.mvarId!
|
||||
|
||||
/--
|
||||
Replace type of the local declaration with id `fvarId` with one with the same user-facing name, but with type `typeNew`.
|
||||
This method assumes `eqProof` is a proof that type of `fvarId` is equal to `typeNew`.
|
||||
This tactic actually adds a new declaration and (try to) clear the old one.
|
||||
If the old one cannot be cleared, then at least its user-facing name becomes inaccessible.
|
||||
Remark: the new declaration is added immediately after `fvarId`.
|
||||
`typeNew` must be well-formed at `fvarId`, but `eqProof` may contain variables declared after `fvarId`. -/
|
||||
def replaceLocalDecl (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) (eqProof : Expr) : MetaM AssertAfterResult :=
|
||||
withMVarContext mvarId do
|
||||
@[deprecated MVarId.replaceTargetDefEq]
|
||||
def replaceTargetDefEq (mvarId : MVarId) (targetNew : Expr) : MetaM MVarId :=
|
||||
mvarId.replaceTargetDefEq targetNew
|
||||
|
||||
private def replaceLocalDeclCore (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) (eqProof : Expr) : MetaM AssertAfterResult :=
|
||||
mvarId.withContext do
|
||||
let localDecl ← getLocalDecl fvarId
|
||||
let typeNewPr ← mkEqMP eqProof (mkFVar fvarId)
|
||||
-- `typeNew` may contain variables that occur after `fvarId`.
|
||||
-- Thus, we use the auxiliary function `findMaxFVar` to ensure `typeNew` is well-formed at the position we are inserting it.
|
||||
let (_, localDecl') ← findMaxFVar typeNew |>.run localDecl
|
||||
let result ← assertAfter mvarId localDecl'.fvarId localDecl.userName typeNew typeNewPr
|
||||
(do let mvarIdNew ← clear result.mvarId fvarId
|
||||
let result ← mvarId.assertAfter localDecl'.fvarId localDecl.userName typeNew typeNewPr
|
||||
(do let mvarIdNew ← result.mvarId.clear fvarId
|
||||
pure { result with mvarId := mvarIdNew })
|
||||
<|> pure result
|
||||
where
|
||||
|
|
@ -78,53 +79,108 @@ where
|
|||
else
|
||||
return e.hasFVar
|
||||
|
||||
def replaceLocalDeclDefEq (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) : MetaM MVarId := do
|
||||
withMVarContext mvarId do
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
/--
|
||||
Replace type of the local declaration with id `fvarId` with one with the same user-facing name, but with type `typeNew`.
|
||||
This method assumes `eqProof` is a proof that type of `fvarId` is equal to `typeNew`.
|
||||
This tactic actually adds a new declaration and (try to) clear the old one.
|
||||
If the old one cannot be cleared, then at least its user-facing name becomes inaccessible.
|
||||
Remark: the new declaration is added immediately after `fvarId`.
|
||||
`typeNew` must be well-formed at `fvarId`, but `eqProof` may contain variables declared after `fvarId`. -/
|
||||
abbrev _root_.Lean.MVarId.replaceLocalDecl (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) (eqProof : Expr) : MetaM AssertAfterResult :=
|
||||
replaceLocalDeclCore mvarId fvarId typeNew eqProof
|
||||
|
||||
@[deprecated MVarId.replaceLocalDecl]
|
||||
abbrev replaceLocalDecl (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) (eqProof : Expr) : MetaM AssertAfterResult :=
|
||||
mvarId.replaceLocalDecl fvarId typeNew eqProof
|
||||
|
||||
/--
|
||||
Replace the type of `fvarId` at `mvarId` with `typeNew`.
|
||||
Remark: this method assumes that `typeNew` is definitionally equal to the current type of `fvarId`.
|
||||
-/
|
||||
def _root_.Lean.MVarId.replaceLocalDeclDefEq (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) : MetaM MVarId := do
|
||||
mvarId.withContext do
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
if typeNew == mvarDecl.type then
|
||||
return mvarId
|
||||
else
|
||||
let lctxNew := (← getLCtx).modifyLocalDecl fvarId (·.setType typeNew)
|
||||
let mvarNew ← mkFreshExprMVarAt lctxNew (← getLocalInstances) mvarDecl.type mvarDecl.kind mvarDecl.userName
|
||||
assignExprMVar mvarId mvarNew
|
||||
mvarId.assign mvarNew
|
||||
return mvarNew.mvarId!
|
||||
|
||||
def change (mvarId : MVarId) (targetNew : Expr) (checkDefEq := true) : MetaM MVarId := withMVarContext mvarId do
|
||||
let target ← getMVarType mvarId
|
||||
@[deprecated MVarId.replaceLocalDeclDefEq]
|
||||
def replaceLocalDeclDefEq (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) : MetaM MVarId := do
|
||||
mvarId.replaceLocalDeclDefEq fvarId typeNew
|
||||
|
||||
/--
|
||||
Replace the target type of `mvarId` with `typeNew`.
|
||||
If `checkDefEq = false`, this method assumes that `typeNew` is definitionally equal to the current target type.
|
||||
If `checkDefEq = true`, throw an error if `typeNew` is not definitionally equal to the current target type.
|
||||
-/
|
||||
def _root_.Lean.MVarId.change (mvarId : MVarId) (targetNew : Expr) (checkDefEq := true) : MetaM MVarId := mvarId.withContext do
|
||||
let target ← mvarId.getType
|
||||
if checkDefEq then
|
||||
unless (← isDefEq target targetNew) do
|
||||
throwTacticEx `change mvarId m!"given type{indentExpr targetNew}\nis not definitionally equal to{indentExpr target}"
|
||||
replaceTargetDefEq mvarId targetNew
|
||||
mvarId.replaceTargetDefEq targetNew
|
||||
|
||||
def changeLocalDecl (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) (checkDefEq := true) : MetaM MVarId := do
|
||||
checkNotAssigned mvarId `changeLocalDecl
|
||||
let (xs, mvarId) ← revert mvarId #[fvarId] true
|
||||
withMVarContext mvarId do
|
||||
@[deprecated MVarId.change]
|
||||
def change (mvarId : MVarId) (targetNew : Expr) (checkDefEq := true) : MetaM MVarId := mvarId.withContext do
|
||||
mvarId.change targetNew checkDefEq
|
||||
|
||||
/--
|
||||
Replace the type of the free variable `fvarId` with `typeNew`.
|
||||
If `checkDefEq = false`, this method assumes that `typeNew` is definitionally equal to `fvarId` type.
|
||||
If `checkDefEq = true`, throw an error if `typeNew` is not definitionally equal to `fvarId` type.
|
||||
-/
|
||||
def _root_.Lean.MVarId.changeLocalDecl (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) (checkDefEq := true) : MetaM MVarId := do
|
||||
mvarId.checkNotAssigned `changeLocalDecl
|
||||
let (xs, mvarId) ← mvarId.revert #[fvarId] true
|
||||
mvarId.withContext do
|
||||
let numReverted := xs.size
|
||||
let target ← getMVarType mvarId
|
||||
let target ← mvarId.getType
|
||||
let check (typeOld : Expr) : MetaM Unit := do
|
||||
if checkDefEq then
|
||||
unless (← isDefEq typeNew typeOld) do
|
||||
throwTacticEx `changeHypothesis mvarId m!"given type{indentExpr typeNew}\nis not definitionally equal to{indentExpr typeOld}"
|
||||
let finalize (targetNew : Expr) : MetaM MVarId := do
|
||||
let mvarId ← replaceTargetDefEq mvarId targetNew
|
||||
let (_, mvarId) ← introNP mvarId numReverted
|
||||
let mvarId ← mvarId.replaceTargetDefEq targetNew
|
||||
let (_, mvarId) ← mvarId.introNP numReverted
|
||||
pure mvarId
|
||||
match target with
|
||||
| Expr.forallE n d b c => do check d; finalize (mkForall n c typeNew b)
|
||||
| Expr.letE n t v b _ => do check t; finalize (mkLet n typeNew v b)
|
||||
| .forallE n d b c => do check d; finalize (mkForall n c typeNew b)
|
||||
| .letE n t v b _ => do check t; finalize (mkLet n typeNew v b)
|
||||
| _ => throwTacticEx `changeHypothesis mvarId "unexpected auxiliary target"
|
||||
|
||||
def modifyTarget (mvarId : MVarId) (f : Expr → MetaM Expr) : MetaM MVarId := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `modifyTarget
|
||||
change mvarId (← f (← getMVarType mvarId)) (checkDefEq := false)
|
||||
@[deprecated MVarId.changeLocalDecl]
|
||||
def changeLocalDecl (mvarId : MVarId) (fvarId : FVarId) (typeNew : Expr) (checkDefEq := true) : MetaM MVarId := do
|
||||
mvarId.changeLocalDecl fvarId typeNew checkDefEq
|
||||
|
||||
def modifyTargetEqLHS (mvarId : MVarId) (f : Expr → MetaM Expr) : MetaM MVarId := do
|
||||
modifyTarget mvarId fun target => do
|
||||
/--
|
||||
Modify `mvarId` target type using `f`.
|
||||
-/
|
||||
def _root_.Lean.MVarId.modifyTarget (mvarId : MVarId) (f : Expr → MetaM Expr) : MetaM MVarId := do
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `modifyTarget
|
||||
mvarId.change (← f (← mvarId.getType)) (checkDefEq := false)
|
||||
|
||||
@[deprecated modifyTarget]
|
||||
def modifyTarget (mvarId : MVarId) (f : Expr → MetaM Expr) : MetaM MVarId := do
|
||||
mvarId.modifyTarget f
|
||||
|
||||
/--
|
||||
Modify `mvarId` target type left-hand-side using `f`.
|
||||
Throw an error if target type is not an equality.
|
||||
-/
|
||||
def _root_.Lean.MVarId.modifyTargetEqLHS (mvarId : MVarId) (f : Expr → MetaM Expr) : MetaM MVarId := do
|
||||
mvarId.modifyTarget fun target => do
|
||||
if let some (_, lhs, rhs) ← matchEq? target then
|
||||
mkEq (← f lhs) rhs
|
||||
else
|
||||
throwTacticEx `modifyTargetEqLHS mvarId m!"equality expected{indentExpr target}"
|
||||
|
||||
@[deprecated MVarId.modifyTargetEqLHS]
|
||||
def modifyTargetEqLHS (mvarId : MVarId) (f : Expr → MetaM Expr) : MetaM MVarId := do
|
||||
mvarId.modifyTargetEqLHS f
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -7,11 +7,14 @@ import Lean.Meta.Tactic.Clear
|
|||
|
||||
namespace Lean.Meta
|
||||
|
||||
def revert (mvarId : MVarId) (fvarIds : Array FVarId) (preserveOrder : Bool := false) : MetaM (Array FVarId × MVarId) := do
|
||||
/--
|
||||
Revert free variables `fvarIds` at goal `mvarId`.
|
||||
-/
|
||||
def _root_.Lean.MVarId.revert (mvarId : MVarId) (fvarIds : Array FVarId) (preserveOrder : Bool := false) : MetaM (Array FVarId × MVarId) := do
|
||||
if fvarIds.isEmpty then
|
||||
pure (#[], mvarId)
|
||||
else withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `revert
|
||||
else mvarId.withContext do
|
||||
mvarId.checkNotAssigned `revert
|
||||
for fvarId in fvarIds do
|
||||
if (← getLocalDecl fvarId) |>.isAuxDecl then
|
||||
throwError "failed to revert {mkFVar fvarId}, it is an auxiliary declaration created to represent recursive definitions"
|
||||
|
|
@ -22,22 +25,26 @@ def revert (mvarId : MVarId) (fvarIds : Array FVarId) (preserveOrder : Bool := f
|
|||
let mut toRevertNew := #[]
|
||||
for x in toRevert do
|
||||
if (← getLocalDecl x.fvarId!) |>.isAuxDecl then
|
||||
mvarId ← clear mvarId x.fvarId!
|
||||
mvarId ← mvarId.clear x.fvarId!
|
||||
else
|
||||
toRevertNew := toRevertNew.push x
|
||||
let tag ← getMVarTag mvarId
|
||||
let tag ← mvarId.getTag
|
||||
-- TODO: the following code can be optimized because `MetavarContext.revert` will compute `collectDeps` again.
|
||||
-- We should factor out the relevat part
|
||||
|
||||
-- Set metavariable kind to natural to make sure `revert` will assign it.
|
||||
setMVarKind mvarId MetavarKind.natural
|
||||
mvarId.setKind .natural
|
||||
let (e, toRevert) ←
|
||||
try
|
||||
liftMkBindingM <| MetavarContext.revert toRevertNew mvarId preserveOrder
|
||||
finally
|
||||
setMVarKind mvarId MetavarKind.syntheticOpaque
|
||||
mvarId.setKind .syntheticOpaque
|
||||
let mvar := e.getAppFn
|
||||
setMVarTag mvar.mvarId! tag
|
||||
mvar.mvarId!.setTag tag
|
||||
return (toRevert.map Expr.fvarId!, mvar.mvarId!)
|
||||
|
||||
@[deprecated MVarId.revert]
|
||||
def revert (mvarId : MVarId) (fvarIds : Array FVarId) (preserveOrder : Bool := false) : MetaM (Array FVarId × MVarId) := do
|
||||
mvarId.revert fvarIds preserveOrder
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -16,10 +16,13 @@ structure RewriteResult where
|
|||
eqProof : Expr
|
||||
mvarIds : List MVarId -- new goals
|
||||
|
||||
def rewrite (mvarId : MVarId) (e : Expr) (heq : Expr)
|
||||
/--
|
||||
Rewrite goal `mvarId`
|
||||
-/
|
||||
def _root_.Lean.MVarId.rewrite (mvarId : MVarId) (e : Expr) (heq : Expr)
|
||||
(symm : Bool := false) (occs : Occurrences := Occurrences.all) (config := { : Rewrite.Config }) : MetaM RewriteResult :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `rewrite
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `rewrite
|
||||
let heqType ← instantiateMVars (← inferType heq)
|
||||
let (newMVars, binderInfos, heqType) ← forallMetaTelescopeReducing heqType
|
||||
let heq := mkAppN heq newMVars
|
||||
|
|
@ -45,7 +48,7 @@ def rewrite (mvarId : MVarId) (e : Expr) (heq : Expr)
|
|||
let eqRefl ← mkEqRefl e
|
||||
let eqPrf ← mkEqNDRec motive eqRefl heq
|
||||
postprocessAppMVars `rewrite mvarId newMVars binderInfos
|
||||
let newMVarIds ← newMVars.map Expr.mvarId! |>.filterM (not <$> isExprMVarAssigned ·)
|
||||
let newMVarIds ← newMVars.map Expr.mvarId! |>.filterM fun mvarId => not <$> mvarId.isAssigned
|
||||
let otherMVarIds ← getMVarsNoDelayed eqPrf
|
||||
let otherMVarIds := otherMVarIds.filter (!newMVarIds.contains ·)
|
||||
let newMVarIds := newMVarIds ++ otherMVarIds
|
||||
|
|
@ -64,4 +67,9 @@ def rewrite (mvarId : MVarId) (e : Expr) (heq : Expr)
|
|||
| none =>
|
||||
cont heq heqType
|
||||
|
||||
@[deprecated MVarId.rewrite]
|
||||
def rewrite (mvarId : MVarId) (e : Expr) (heq : Expr)
|
||||
(symm : Bool := false) (occs : Occurrences := Occurrences.all) (config := { : Rewrite.Config }) : MetaM RewriteResult :=
|
||||
mvarId.rewrite e heq symm occs config
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -759,8 +759,8 @@ partial def dischargeEqnThmHypothesis? (e : Expr) : MetaM (Option Expr) := do
|
|||
where
|
||||
go? (mvarId : MVarId) : MetaM (Option MVarId) :=
|
||||
try
|
||||
let (fvarId, mvarId) ← intro1 mvarId
|
||||
withMVarContext mvarId do
|
||||
let (fvarId, mvarId) ← mvarId.intro1
|
||||
mvarId.withContext do
|
||||
let localDecl ← getLocalDecl fvarId
|
||||
if localDecl.type.isEq || localDecl.type.isHEq then
|
||||
if let some { mvarId, .. } ← unifyEq? mvarId fvarId {} then
|
||||
|
|
@ -824,21 +824,21 @@ def dsimp (e : Expr) (ctx : Simp.Context) : MetaM Expr := do profileitM Exceptio
|
|||
-/
|
||||
def applySimpResultToTarget (mvarId : MVarId) (target : Expr) (r : Simp.Result) : MetaM MVarId := do
|
||||
match r.proof? with
|
||||
| some proof => replaceTargetEq mvarId r.expr proof
|
||||
| some proof => mvarId.replaceTargetEq r.expr proof
|
||||
| none =>
|
||||
if target != r.expr then
|
||||
replaceTargetDefEq mvarId r.expr
|
||||
mvarId.replaceTargetDefEq r.expr
|
||||
else
|
||||
return mvarId
|
||||
|
||||
/-- See `simpTarget`. This method assumes `mvarId` is not assigned, and we are already using `mvarId`s local context. -/
|
||||
def simpTargetCore (mvarId : MVarId) (ctx : Simp.Context) (discharge? : Option Simp.Discharge := none) (mayCloseGoal := true) : MetaM (Option MVarId) := do
|
||||
let target ← instantiateMVars (← getMVarType mvarId)
|
||||
let target ← instantiateMVars (← mvarId.getType)
|
||||
let r ← simp target ctx discharge?
|
||||
if mayCloseGoal && r.expr.isConstOf ``True then
|
||||
match r.proof? with
|
||||
| some proof => assignExprMVar mvarId (← mkOfEqTrue proof)
|
||||
| none => assignExprMVar mvarId (mkConst ``True.intro)
|
||||
| some proof => mvarId.assign (← mkOfEqTrue proof)
|
||||
| none => mvarId.assign (mkConst ``True.intro)
|
||||
return none
|
||||
else
|
||||
applySimpResultToTarget mvarId target r
|
||||
|
|
@ -847,8 +847,8 @@ def simpTargetCore (mvarId : MVarId) (ctx : Simp.Context) (discharge? : Option S
|
|||
Simplify the given goal target (aka type). Return `none` if the goal was closed. Return `some mvarId'` otherwise,
|
||||
where `mvarId'` is the simplified new goal. -/
|
||||
def simpTarget (mvarId : MVarId) (ctx : Simp.Context) (discharge? : Option Simp.Discharge := none) (mayCloseGoal := true) : MetaM (Option MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `simp
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `simp
|
||||
simpTargetCore mvarId ctx discharge? mayCloseGoal
|
||||
|
||||
/--
|
||||
|
|
@ -859,8 +859,8 @@ def simpTarget (mvarId : MVarId) (ctx : Simp.Context) (discharge? : Option Simp.
|
|||
def applySimpResultToProp (mvarId : MVarId) (proof : Expr) (prop : Expr) (r : Simp.Result) (mayCloseGoal := true) : MetaM (Option (Expr × Expr)) := do
|
||||
if mayCloseGoal && r.expr.isConstOf ``False then
|
||||
match r.proof? with
|
||||
| some eqProof => assignExprMVar mvarId (← mkFalseElim (← getMVarType mvarId) (← mkEqMP eqProof proof))
|
||||
| none => assignExprMVar mvarId (← mkFalseElim (← getMVarType mvarId) proof)
|
||||
| some eqProof => mvarId.assign (← mkFalseElim (← mvarId.getType) (← mkEqMP eqProof proof))
|
||||
| none => mvarId.assign (← mkFalseElim (← mvarId.getType) proof)
|
||||
return none
|
||||
else
|
||||
match r.proof? with
|
||||
|
|
@ -890,9 +890,9 @@ def applySimpResultToLocalDeclCore (mvarId : MVarId) (fvarId : FVarId) (r : Opti
|
|||
| some (value, type') =>
|
||||
let localDecl ← getLocalDecl fvarId
|
||||
if localDecl.type != type' then
|
||||
let mvarId ← assert mvarId localDecl.userName type' value
|
||||
let mvarId ← tryClear mvarId localDecl.fvarId
|
||||
let (fvarId, mvarId) ← intro1P mvarId
|
||||
let mvarId ← mvarId.assert localDecl.userName type' value
|
||||
let mvarId ← mvarId.tryClear localDecl.fvarId
|
||||
let (fvarId, mvarId) ← mvarId.intro1P
|
||||
return some (fvarId, mvarId)
|
||||
else
|
||||
return some (fvarId, mvarId)
|
||||
|
|
@ -903,9 +903,9 @@ def applySimpResultToLocalDeclCore (mvarId : MVarId) (fvarId : FVarId) (r : Opti
|
|||
def applySimpResultToLocalDecl (mvarId : MVarId) (fvarId : FVarId) (r : Simp.Result) (mayCloseGoal : Bool) : MetaM (Option (FVarId × MVarId)) := do
|
||||
if r.proof?.isNone then
|
||||
-- New result is definitionally equal to input. Thus, we can avoid creating a new variable if there are dependencies
|
||||
let mvarId ← replaceLocalDeclDefEq mvarId fvarId r.expr
|
||||
let mvarId ← mvarId.replaceLocalDeclDefEq fvarId r.expr
|
||||
if mayCloseGoal && r.expr.isConstOf ``False then
|
||||
assignExprMVar mvarId (← mkFalseElim (← getMVarType mvarId) (mkFVar fvarId))
|
||||
mvarId.assign (← mkFalseElim (← mvarId.getType) (mkFVar fvarId))
|
||||
return none
|
||||
else
|
||||
return some (fvarId, mvarId)
|
||||
|
|
@ -913,8 +913,8 @@ def applySimpResultToLocalDecl (mvarId : MVarId) (fvarId : FVarId) (r : Simp.Res
|
|||
applySimpResultToLocalDeclCore mvarId fvarId (← applySimpResultToFVarId mvarId fvarId r mayCloseGoal)
|
||||
|
||||
def simpLocalDecl (mvarId : MVarId) (fvarId : FVarId) (ctx : Simp.Context) (discharge? : Option Simp.Discharge := none) (mayCloseGoal := true) : MetaM (Option (FVarId × MVarId)) := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `simp
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `simp
|
||||
let localDecl ← getLocalDecl fvarId
|
||||
let type ← instantiateMVars localDecl.type
|
||||
applySimpResultToLocalDeclCore mvarId fvarId (← simpStep mvarId (mkFVar fvarId) type ctx discharge? mayCloseGoal)
|
||||
|
|
@ -922,8 +922,8 @@ def simpLocalDecl (mvarId : MVarId) (fvarId : FVarId) (ctx : Simp.Context) (disc
|
|||
abbrev FVarIdToLemmaId := FVarIdMap Name
|
||||
|
||||
def simpGoal (mvarId : MVarId) (ctx : Simp.Context) (discharge? : Option Simp.Discharge := none) (simplifyTarget : Bool := true) (fvarIdsToSimp : Array FVarId := #[]) (fvarIdToLemmaId : FVarIdToLemmaId := {}) : MetaM (Option (Array FVarId × MVarId)) := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `simp
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `simp
|
||||
let mut mvarId := mvarId
|
||||
let mut toAssert := #[]
|
||||
let mut replaced := #[]
|
||||
|
|
@ -940,22 +940,22 @@ def simpGoal (mvarId : MVarId) (ctx : Simp.Context) (discharge? : Option Simp.Di
|
|||
| some (value, type) => toAssert := toAssert.push { userName := localDecl.userName, type := type, value := value }
|
||||
| none =>
|
||||
if r.expr.isConstOf ``False then
|
||||
assignExprMVar mvarId (← mkFalseElim (← getMVarType mvarId) (mkFVar fvarId))
|
||||
mvarId.assign (← mkFalseElim (← mvarId.getType) (mkFVar fvarId))
|
||||
return none
|
||||
-- TODO: if there are no forwards dependencies we may consider using the same approach we used when `r.proof?` is a `some ...`
|
||||
-- Reason: it introduces a `mkExpectedTypeHint`
|
||||
mvarId ← replaceLocalDeclDefEq mvarId fvarId r.expr
|
||||
mvarId ← mvarId.replaceLocalDeclDefEq fvarId r.expr
|
||||
replaced := replaced.push fvarId
|
||||
if simplifyTarget then
|
||||
match (← simpTarget mvarId ctx discharge?) with
|
||||
| none => return none
|
||||
| some mvarIdNew => mvarId := mvarIdNew
|
||||
let (fvarIdsNew, mvarIdNew) ← assertHypotheses mvarId toAssert
|
||||
let (fvarIdsNew, mvarIdNew) ← mvarId.assertHypotheses toAssert
|
||||
let toClear := fvarIdsToSimp.filter fun fvarId => !replaced.contains fvarId
|
||||
let mvarIdNew ← tryClearMany mvarIdNew toClear
|
||||
let mvarIdNew ← mvarIdNew.tryClearMany toClear
|
||||
return (fvarIdsNew, mvarIdNew)
|
||||
|
||||
def simpTargetStar (mvarId : MVarId) (ctx : Simp.Context) (discharge? : Option Simp.Discharge := none) : MetaM TacticResultCNM := withMVarContext mvarId do
|
||||
def simpTargetStar (mvarId : MVarId) (ctx : Simp.Context) (discharge? : Option Simp.Discharge := none) : MetaM TacticResultCNM := mvarId.withContext do
|
||||
let mut ctx := ctx
|
||||
for h in (← getPropHyps) do
|
||||
let localDecl ← getLocalDecl h
|
||||
|
|
@ -965,36 +965,36 @@ def simpTargetStar (mvarId : MVarId) (ctx : Simp.Context) (discharge? : Option S
|
|||
match (← simpTarget mvarId ctx discharge?) with
|
||||
| none => return TacticResultCNM.closed
|
||||
| some mvarId' =>
|
||||
if (← getMVarType mvarId) == (← getMVarType mvarId') then
|
||||
if (← mvarId.getType) == (← mvarId'.getType) then
|
||||
return TacticResultCNM.noChange
|
||||
else
|
||||
return TacticResultCNM.modified mvarId'
|
||||
|
||||
def dsimpGoal (mvarId : MVarId) (ctx : Simp.Context) (simplifyTarget : Bool := true) (fvarIdsToSimp : Array FVarId := #[]) : MetaM (Option MVarId) := do
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `simp
|
||||
mvarId.withContext do
|
||||
mvarId.checkNotAssigned `simp
|
||||
let mut mvarId := mvarId
|
||||
for fvarId in fvarIdsToSimp do
|
||||
let localDecl ← getLocalDecl fvarId
|
||||
let type ← instantiateMVars localDecl.type
|
||||
let typeNew ← dsimp type ctx
|
||||
if typeNew.isConstOf ``False then
|
||||
assignExprMVar mvarId (← mkFalseElim (← getMVarType mvarId) (mkFVar fvarId))
|
||||
mvarId.assign (← mkFalseElim (← mvarId.getType) (mkFVar fvarId))
|
||||
return none
|
||||
if typeNew != type then
|
||||
mvarId ← replaceLocalDeclDefEq mvarId fvarId typeNew
|
||||
mvarId ← mvarId.replaceLocalDeclDefEq fvarId typeNew
|
||||
if simplifyTarget then
|
||||
let target ← getMVarType mvarId
|
||||
let target ← mvarId.getType
|
||||
let targetNew ← dsimp target ctx
|
||||
if targetNew.isConstOf ``True then
|
||||
assignExprMVar mvarId (mkConst ``True.intro)
|
||||
mvarId.assign (mkConst ``True.intro)
|
||||
return none
|
||||
if let some (_, lhs, rhs) := targetNew.eq? then
|
||||
if (← withReducible <| isDefEq lhs rhs) then
|
||||
assignExprMVar mvarId (← mkEqRefl lhs)
|
||||
mvarId.assign (← mkEqRefl lhs)
|
||||
return none
|
||||
if target != targetNew then
|
||||
mvarId ← replaceTargetDefEq mvarId targetNew
|
||||
mvarId ← mvarId.replaceTargetDefEq targetNew
|
||||
return some mvarId
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ structure State where
|
|||
abbrev M := StateRefT State MetaM
|
||||
|
||||
private def initEntries : M Unit := do
|
||||
let hs ← withMVarContext (← get).mvarId do getPropHyps
|
||||
let hsNonDeps ← getNondepPropHyps (← get).mvarId
|
||||
let hs ← (← get).mvarId.withContext do getPropHyps
|
||||
let hsNonDeps ← (← get).mvarId.getNondepPropHyps
|
||||
let mut simpThms := (← get).ctx.simpTheorems
|
||||
for h in hs do
|
||||
let localDecl ← getLocalDecl h
|
||||
|
|
@ -114,15 +114,15 @@ def main : M (Option MVarId) := do
|
|||
else
|
||||
let mvarId := (← get).mvarId
|
||||
let entries := (← get).entries
|
||||
let (_, mvarId) ← assertHypotheses mvarId <| entries.filterMap fun e =>
|
||||
let (_, mvarId) ← mvarId.assertHypotheses <| entries.filterMap fun e =>
|
||||
-- Do not assert `True` hypotheses
|
||||
if e.type.isConstOf ``True then none else some { userName := e.userName, type := e.type, value := e.proof }
|
||||
tryClearMany mvarId (entries.map fun e => e.fvarId)
|
||||
mvarId.tryClearMany (entries.map fun e => e.fvarId)
|
||||
|
||||
end SimpAll
|
||||
|
||||
def simpAll (mvarId : MVarId) (ctx : Simp.Context) : MetaM (Option MVarId) := do
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
SimpAll.main.run' { mvarId := mvarId, ctx := ctx }
|
||||
|
||||
end Lean.Meta
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ where
|
|||
| some r => return r
|
||||
| none => return Simp.Step.visit { expr := e }
|
||||
|
||||
def simpMatchTarget (mvarId : MVarId) : MetaM MVarId := withMVarContext mvarId do
|
||||
let target ← instantiateMVars (← getMVarType mvarId)
|
||||
def simpMatchTarget (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
|
||||
let target ← instantiateMVars (← mvarId.getType)
|
||||
let r ← simpMatch target
|
||||
applySimpResultToTarget mvarId target r
|
||||
|
||||
|
|
@ -51,12 +51,12 @@ where
|
|||
return Simp.Step.visit { expr := e }
|
||||
|
||||
private def simpMatchTargetCore (mvarId : MVarId) (matchDeclName : Name) (matchEqDeclName : Name) : MetaM MVarId := do
|
||||
withMVarContext mvarId do
|
||||
let target ← instantiateMVars (← getMVarType mvarId)
|
||||
mvarId.withContext do
|
||||
let target ← instantiateMVars (← mvarId.getType)
|
||||
let r ← simpMatchCore matchDeclName matchEqDeclName target
|
||||
match r.proof? with
|
||||
| some proof => replaceTargetEq mvarId r.expr proof
|
||||
| none => replaceTargetDefEq mvarId r.expr
|
||||
| some proof => mvarId.replaceTargetEq r.expr proof
|
||||
| none => mvarId.replaceTargetDefEq r.expr
|
||||
|
||||
private partial def withEqs (lhs rhs : Array Expr) (k : Array Expr → Array Expr → MetaM α) : MetaM α := do
|
||||
go 0 #[] #[]
|
||||
|
|
@ -99,7 +99,7 @@ where
|
|||
⊢ g x = 2 * x + 1
|
||||
```
|
||||
-/
|
||||
private partial def generalizeMatchDiscrs (mvarId : MVarId) (matcherDeclName : Name) (motiveType : Expr) (discrs : Array Expr) : MetaM (Array FVarId × Array FVarId × MVarId) := withMVarContext mvarId do
|
||||
private partial def generalizeMatchDiscrs (mvarId : MVarId) (matcherDeclName : Name) (motiveType : Expr) (discrs : Array Expr) : MetaM (Array FVarId × Array FVarId × MVarId) := mvarId.withContext do
|
||||
if discrs.all (·.isFVar) then
|
||||
return (discrs.map (·.fvarId!), #[], mvarId)
|
||||
let some matcherInfo ← getMatcherInfo? matcherDeclName | unreachable!
|
||||
|
|
@ -138,18 +138,18 @@ private partial def generalizeMatchDiscrs (mvarId : MVarId) (matcherDeclName : N
|
|||
altsNew := altsNew.push altNew
|
||||
return .done { matcherApp with alts := altsNew }.toExpr
|
||||
transform (← instantiateMVars e) pre
|
||||
let targetNew ← mkNewTarget (← getMVarType mvarId)
|
||||
let targetNew ← mkNewTarget (← mvarId.getType)
|
||||
unless (← foundRef.get) do
|
||||
throwError "'applyMatchSplitter' failed, did not find discriminants"
|
||||
let targetNew ← mkForallFVars (discrVars ++ eqs) targetNew
|
||||
unless (← isTypeCorrect targetNew) do
|
||||
throwError "'applyMatchSplitter' failed, failed to generalize target"
|
||||
return (targetNew, rfls)
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew (← getMVarTag mvarId)
|
||||
let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew (← mvarId.getTag)
|
||||
trace[Meta.Tactic.split] "targetNew:\n{mvarNew.mvarId!}"
|
||||
assignExprMVar mvarId (mkAppN (mkAppN mvarNew discrs) rfls)
|
||||
let (discrs', mvarId') ← introNP mvarNew.mvarId! discrs.size
|
||||
let (discrEqs, mvarId') ← introNP mvarId' discrs.size
|
||||
mvarId.assign (mkAppN (mkAppN mvarNew discrs) rfls)
|
||||
let (discrs', mvarId') ← mvarNew.mvarId!.introNP discrs.size
|
||||
let (discrEqs, mvarId') ← mvarId'.introNP discrs.size
|
||||
return (discrs', discrEqs, mvarId')
|
||||
where
|
||||
/--
|
||||
|
|
@ -183,7 +183,7 @@ where
|
|||
k altEqsNew subst
|
||||
go 0 #[] #[]
|
||||
|
||||
private def substDiscrEqs (mvarId : MVarId) (fvarSubst : FVarSubst) (discrEqs : Array FVarId) : MetaM MVarId := withMVarContext mvarId do
|
||||
private def substDiscrEqs (mvarId : MVarId) (fvarSubst : FVarSubst) (discrEqs : Array FVarId) : MetaM MVarId := mvarId.withContext do
|
||||
let mut mvarId := mvarId
|
||||
let mut fvarSubst := fvarSubst
|
||||
for fvarId in discrEqs do
|
||||
|
|
@ -208,14 +208,14 @@ def applyMatchSplitter (mvarId : MVarId) (matcherDeclName : Name) (us : Array Le
|
|||
let (discrFVarIds, discrEqs, mvarId) ← generalizeMatchDiscrs mvarId matcherDeclName motiveType discrs
|
||||
trace[Meta.Tactic.split] "after generalizeMatchDiscrs\n{mvarId}"
|
||||
let mvarId ← generalizeTargetsEq mvarId motiveType (discrFVarIds.map mkFVar)
|
||||
withMVarContext mvarId do trace[Meta.Tactic.split] "discrEqs after generalizeTargetsEq: {discrEqs.map mkFVar}"
|
||||
mvarId.withContext do trace[Meta.Tactic.split] "discrEqs after generalizeTargetsEq: {discrEqs.map mkFVar}"
|
||||
trace[Meta.Tactic.split] "after generalize\n{mvarId}"
|
||||
let numEqs := discrs.size
|
||||
let (discrFVarIdsNew, mvarId) ← introN mvarId discrs.size
|
||||
let (discrFVarIdsNew, mvarId) ← mvarId.introN discrs.size
|
||||
trace[Meta.Tactic.split] "after introN\n{mvarId}"
|
||||
let discrsNew := discrFVarIdsNew.map mkFVar
|
||||
let mvarType ← getMVarType mvarId
|
||||
let elimUniv ← withMVarContext mvarId <| getLevel mvarType
|
||||
let mvarType ← mvarId.getType
|
||||
let elimUniv ← mvarId.withContext <| getLevel mvarType
|
||||
let us ← if let some uElimPos := info.uElimPos? then
|
||||
pure <| us.set! uElimPos elimUniv
|
||||
else
|
||||
|
|
@ -223,17 +223,17 @@ def applyMatchSplitter (mvarId : MVarId) (matcherDeclName : Name) (us : Array Le
|
|||
throwError "match-splitter can only eliminate into `Prop`"
|
||||
pure us
|
||||
let splitter := mkAppN (mkConst matchEqns.splitterName us.toList) params
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let motive ← mkLambdaFVars discrsNew mvarType
|
||||
let splitter := mkAppN (mkApp splitter motive) discrsNew
|
||||
check splitter
|
||||
trace[Meta.Tactic.split] "after check splitter"
|
||||
let mvarIds ← apply mvarId splitter
|
||||
let mvarIds ← mvarId.apply splitter
|
||||
unless mvarIds.length == matchEqns.size do
|
||||
throwError "'applyMatchSplitter' failed, unexpected number of goals created after applying splitter for '{matcherDeclName}'."
|
||||
let (_, mvarIds) ← mvarIds.foldlM (init := (0, [])) fun (i, mvarIds) mvarId => do
|
||||
let numParams := matchEqns.splitterAltNumParams[i]!
|
||||
let (_, mvarId) ← introN mvarId numParams
|
||||
let (_, mvarId) ← mvarId.introN numParams
|
||||
trace[Meta.Tactic.split] "before unifyEqs\n{mvarId}"
|
||||
match (← Cases.unifyEqs? (numEqs + info.getNumDiscrEqs) mvarId {}) with
|
||||
| none => return (i+1, mvarIds) -- case was solved
|
||||
|
|
@ -289,7 +289,7 @@ end Split
|
|||
open Split
|
||||
|
||||
partial def splitTarget? (mvarId : MVarId) (splitIte := true) : MetaM (Option (List MVarId)) := commitWhenSome? do
|
||||
let target ← instantiateMVars (← getMVarType mvarId)
|
||||
let target ← instantiateMVars (← mvarId.getType)
|
||||
let rec go (badCases : ExprSet) : MetaM (Option (List MVarId)) := do
|
||||
if let some e := findSplit? (← getEnv) target splitIte badCases then
|
||||
if e.isIte || e.isDIte then
|
||||
|
|
@ -305,15 +305,15 @@ partial def splitTarget? (mvarId : MVarId) (splitIte := true) : MetaM (Option (L
|
|||
go {}
|
||||
|
||||
def splitLocalDecl? (mvarId : MVarId) (fvarId : FVarId) : MetaM (Option (List MVarId)) := commitWhenSome? do
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
if let some e := findSplit? (← getEnv) (← instantiateMVars (← inferType (mkFVar fvarId))) then
|
||||
if e.isIte || e.isDIte then
|
||||
return (← splitIfLocalDecl? mvarId fvarId).map fun (mvarId₁, mvarId₂) => [mvarId₁, mvarId₂]
|
||||
else
|
||||
let (fvarIds, mvarId) ← revert mvarId #[fvarId]
|
||||
let (fvarIds, mvarId) ← mvarId.revert #[fvarId]
|
||||
let num := fvarIds.size
|
||||
let mvarIds ← splitMatch mvarId e
|
||||
let mvarIds ← mvarIds.mapM fun mvarId => return (← introNP mvarId num).2
|
||||
let mvarIds ← mvarIds.mapM fun mvarId => return (← mvarId.introNP num).2
|
||||
return some mvarIds
|
||||
else
|
||||
return none
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ def simpIfLocalDecl (mvarId : MVarId) (fvarId : FVarId) : MetaM MVarId := do
|
|||
unreachable!
|
||||
|
||||
def splitIfTarget? (mvarId : MVarId) (hName? : Option Name := none) : MetaM (Option (ByCasesSubgoal × ByCasesSubgoal)) := commitWhenSome? do
|
||||
if let some (s₁, s₂) ← splitIfAt? mvarId (← getMVarType mvarId) hName? then
|
||||
if let some (s₁, s₂) ← splitIfAt? mvarId (← mvarId.getType) hName? then
|
||||
let mvarId₁ ← simpIfTarget s₁.mvarId
|
||||
let mvarId₂ ← simpIfTarget s₂.mvarId
|
||||
if s₁.mvarId == mvarId₁ && s₂.mvarId == mvarId₂ then
|
||||
|
|
@ -106,7 +106,7 @@ def splitIfTarget? (mvarId : MVarId) (hName? : Option Name := none) : MetaM (Opt
|
|||
return none
|
||||
|
||||
def splitIfLocalDecl? (mvarId : MVarId) (fvarId : FVarId) (hName? : Option Name := none) : MetaM (Option (MVarId × MVarId)) := commitWhenSome? do
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
if let some (s₁, s₂) ← splitIfAt? mvarId (← inferType (mkFVar fvarId)) hName? then
|
||||
let mvarId₁ ← simpIfLocalDecl s₁.mvarId fvarId
|
||||
let mvarId₂ ← simpIfLocalDecl s₂.mvarId fvarId
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ import Lean.Meta.Tactic.FVarSubst
|
|||
namespace Lean.Meta
|
||||
|
||||
def substCore (mvarId : MVarId) (hFVarId : FVarId) (symm := false) (fvarSubst : FVarSubst := {}) (clearH := true) (tryToSkip := false) : MetaM (FVarSubst × MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
let tag ← getMVarTag mvarId
|
||||
checkNotAssigned mvarId `subst
|
||||
mvarId.withContext do
|
||||
let tag ← mvarId.getTag
|
||||
mvarId.checkNotAssigned `subst
|
||||
let hFVarIdOriginal := hFVarId
|
||||
let hLocalDecl ← getLocalDecl hFVarId
|
||||
match (← matchEq? hLocalDecl.type) with
|
||||
|
|
@ -31,9 +31,9 @@ def substCore (mvarId : MVarId) (hFVarId : FVarId) (symm := false) (fvarSubst :
|
|||
trace[Meta.Tactic.subst] "substituting {a} (id: {aFVarId.name}) with {b}"
|
||||
if (← exprDependsOn b aFVarId) then
|
||||
throwTacticEx `subst mvarId m!"'{a}' occurs at{indentExpr b}"
|
||||
let (vars, mvarId) ← revert mvarId #[aFVarId, hFVarId] true
|
||||
let (vars, mvarId) ← mvarId.revert #[aFVarId, hFVarId] true
|
||||
trace[Meta.Tactic.subst] "after revert {MessageData.ofGoal mvarId}"
|
||||
let (twoVars, mvarId) ← introNP mvarId 2
|
||||
let (twoVars, mvarId) ← mvarId.introNP 2
|
||||
trace[Meta.Tactic.subst] "after intro2 {MessageData.ofGoal mvarId}"
|
||||
trace[Meta.Tactic.subst] "reverted variables {vars.map (·.name)}"
|
||||
let aFVarId := twoVars[0]!
|
||||
|
|
@ -44,20 +44,20 @@ def substCore (mvarId : MVarId) (hFVarId : FVarId) (symm := false) (fvarSubst :
|
|||
let skip ← if !tryToSkip || vars.size != 2 then
|
||||
pure false
|
||||
else
|
||||
let mvarType ← getMVarType mvarId
|
||||
let mvarType ← mvarId.getType
|
||||
if (← exprDependsOn mvarType aFVarId) then pure false
|
||||
else if (← exprDependsOn mvarType hFVarId) then pure false
|
||||
else pure true
|
||||
if skip then
|
||||
if clearH then
|
||||
let mvarId ← clear mvarId hFVarId
|
||||
let mvarId ← clear mvarId aFVarId
|
||||
let mvarId ← mvarId.clear hFVarId
|
||||
let mvarId ← mvarId.clear aFVarId
|
||||
pure ({}, mvarId)
|
||||
else
|
||||
pure ({}, mvarId)
|
||||
else
|
||||
withMVarContext mvarId do
|
||||
let mvarDecl ← getMVarDecl mvarId
|
||||
mvarId.withContext do
|
||||
let mvarDecl ← mvarId.getDecl
|
||||
let type := mvarDecl.type
|
||||
let hLocalDecl ← getLocalDecl hFVarId
|
||||
match (← matchEq? hLocalDecl.type) with
|
||||
|
|
@ -70,14 +70,14 @@ def substCore (mvarId : MVarId) (hFVarId : FVarId) (symm := false) (fvarSubst :
|
|||
let newMVar ← mkFreshExprSyntheticOpaqueMVar newType tag
|
||||
let minor := newMVar
|
||||
let newVal ← if depElim then mkEqRec motive minor major else mkEqNDRec motive minor major
|
||||
assignExprMVar mvarId newVal
|
||||
mvarId.assign newVal
|
||||
let mvarId := newMVar.mvarId!
|
||||
let mvarId ← if clearH then
|
||||
let mvarId ← clear mvarId hFVarId
|
||||
clear mvarId aFVarId
|
||||
let mvarId ← mvarId.clear hFVarId
|
||||
mvarId.clear aFVarId
|
||||
else
|
||||
pure mvarId
|
||||
let (newFVars, mvarId) ← introNP mvarId (vars.size - 2)
|
||||
let (newFVars, mvarId) ← mvarId.introNP (vars.size - 2)
|
||||
trace[Meta.Tactic.subst] "after intro rest {vars.size - 2} {MessageData.ofGoal mvarId}"
|
||||
let fvarSubst ← newFVars.size.foldM (init := fvarSubst) fun i (fvarSubst : FVarSubst) =>
|
||||
let var := vars[i+2]!
|
||||
|
|
@ -120,7 +120,7 @@ def substCore (mvarId : MVarId) (hFVarId : FVarId) (symm := false) (fvarSubst :
|
|||
If `h` is not of the give form, then just return `(h, mvarId)`
|
||||
-/
|
||||
def heqToEq (mvarId : MVarId) (fvarId : FVarId) (tryToClear : Bool := true) : MetaM (FVarId × MVarId) :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let decl ← getLocalDecl fvarId
|
||||
let type ← whnf decl.type
|
||||
match type.heq? with
|
||||
|
|
@ -129,16 +129,16 @@ def heqToEq (mvarId : MVarId) (fvarId : FVarId) (tryToClear : Bool := true) : Me
|
|||
if (← isDefEq α β) then
|
||||
let pr ← mkEqOfHEq (mkFVar fvarId)
|
||||
let eq ← mkEq a b
|
||||
let mut mvarId ← assert mvarId decl.userName eq pr
|
||||
let mut mvarId ← mvarId.assert decl.userName eq pr
|
||||
if tryToClear then
|
||||
mvarId ← tryClear mvarId fvarId
|
||||
let (fvarId, mvarId') ← intro1P mvarId
|
||||
mvarId ← mvarId.tryClear fvarId
|
||||
let (fvarId, mvarId') ← mvarId.intro1P
|
||||
return (fvarId, mvarId')
|
||||
else
|
||||
return (fvarId, mvarId)
|
||||
|
||||
partial def subst (mvarId : MVarId) (h : FVarId) : MetaM MVarId :=
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let localDecl ← getLocalDecl h
|
||||
match (← matchEq? localDecl.type) with
|
||||
| some _ => substEq mvarId h
|
||||
|
|
@ -152,13 +152,13 @@ partial def subst (mvarId : MVarId) (h : FVarId) : MetaM MVarId :=
|
|||
| none => findEq mvarId h
|
||||
where
|
||||
/-- Give `h : Eq α a b`, try to apply `substCore` -/
|
||||
substEq (mvarId : MVarId) (h : FVarId) : MetaM MVarId := withMVarContext mvarId do
|
||||
substEq (mvarId : MVarId) (h : FVarId) : MetaM MVarId := mvarId.withContext do
|
||||
let localDecl ← getLocalDecl h
|
||||
let some (_, lhs, rhs) ← matchEq? localDecl.type | unreachable!
|
||||
let substReduced (newType : Expr) (symm : Bool) : MetaM MVarId := do
|
||||
let mvarId ← assert mvarId localDecl.userName newType (mkFVar h)
|
||||
let (hFVarId', mvarId) ← intro1P mvarId
|
||||
let mvarId ← clear mvarId h
|
||||
let mvarId ← mvarId.assert localDecl.userName newType (mkFVar h)
|
||||
let (hFVarId', mvarId) ← mvarId.intro1P
|
||||
let mvarId ← mvarId.clear h
|
||||
return (← substCore mvarId hFVarId' (symm := symm) (tryToSkip := true)).2
|
||||
let rhs' ← whnf rhs
|
||||
if rhs'.isFVar then
|
||||
|
|
@ -177,7 +177,7 @@ where
|
|||
throwTacticEx `subst mvarId m!"invalid equality proof, it is not of the form (x = t) or (t = x){indentExpr localDecl.type}"
|
||||
|
||||
/-- Try to find an equation of the form `heq : h = rhs` or `heq : lhs = h` -/
|
||||
findEq (mvarId : MVarId) (h : FVarId) : MetaM MVarId := withMVarContext mvarId do
|
||||
findEq (mvarId : MVarId) (h : FVarId) : MetaM MVarId := mvarId.withContext do
|
||||
let localDecl ← getLocalDecl h
|
||||
if localDecl.isLet then
|
||||
throwTacticEx `subst mvarId m!"variable '{mkFVar h}' is a let-declaration"
|
||||
|
|
@ -212,7 +212,7 @@ def trySubst (mvarId : MVarId) (hFVarId : FVarId) : MetaM MVarId := do
|
|||
| some mvarId => return mvarId
|
||||
| none => return mvarId
|
||||
|
||||
def substSomeVar? (mvarId : MVarId) : MetaM (Option MVarId) := withMVarContext mvarId do
|
||||
def substSomeVar? (mvarId : MVarId) : MetaM (Option MVarId) := mvarId.withContext do
|
||||
for localDecl in (← getLCtx) do
|
||||
if let some mvarId ← subst? mvarId localDecl.fvarId then
|
||||
return some mvarId
|
||||
|
|
|
|||
|
|
@ -30,13 +30,13 @@ where
|
|||
| _ => return Simp.Step.done r
|
||||
return Simp.Step.visit { expr := e }
|
||||
|
||||
def unfoldTarget (mvarId : MVarId) (declName : Name) : MetaM MVarId := withMVarContext mvarId do
|
||||
let target ← instantiateMVars (← getMVarType mvarId)
|
||||
def unfoldTarget (mvarId : MVarId) (declName : Name) : MetaM MVarId := mvarId.withContext do
|
||||
let target ← instantiateMVars (← mvarId.getType)
|
||||
let r ← unfold target declName
|
||||
if r.expr == target then throwError "tactic 'unfold' failed to unfold '{declName}' at{indentExpr target}"
|
||||
applySimpResultToTarget mvarId target r
|
||||
|
||||
def unfoldLocalDecl (mvarId : MVarId) (fvarId : FVarId) (declName : Name) : MetaM MVarId := withMVarContext mvarId do
|
||||
def unfoldLocalDecl (mvarId : MVarId) (fvarId : FVarId) (declName : Name) : MetaM MVarId := mvarId.withContext do
|
||||
let localDecl ← getLocalDecl fvarId
|
||||
let r ← unfold (← instantiateMVars localDecl.type) declName
|
||||
if r.expr == localDecl.type then throwError "tactic 'unfold' failed to unfold '{declName}' at{indentExpr localDecl.type}"
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ private def heqToEq' (mvarId : MVarId) (eqDecl : LocalDecl) : MetaM MVarId := do
|
|||
/- Convert heterogeneous equality into a homegeneous one -/
|
||||
let prf ← mkEqOfHEq (mkFVar eqDecl.fvarId)
|
||||
let aEqb ← whnf (← inferType prf)
|
||||
let mvarId ← assert mvarId eqDecl.userName aEqb prf
|
||||
clear mvarId eqDecl.fvarId
|
||||
let mvarId ← mvarId.assert eqDecl.userName aEqb prf
|
||||
mvarId.clear eqDecl.fvarId
|
||||
|
||||
structure UnifyEqResult where
|
||||
mvarId : MVarId
|
||||
|
|
@ -38,7 +38,7 @@ def unifyEq? (mvarId : MVarId) (eqFVarId : FVarId) (subst : FVarSubst := {})
|
|||
(acyclic : MVarId → Expr → MetaM Bool := fun _ _ => return false)
|
||||
(caseName? : Option Name := none)
|
||||
: MetaM (Option UnifyEqResult) := do
|
||||
withMVarContext mvarId do
|
||||
mvarId.withContext do
|
||||
let eqDecl ← getLocalDecl eqFVarId
|
||||
if eqDecl.type.isHEq then
|
||||
let mvarId ← heqToEq' mvarId eqDecl
|
||||
|
|
@ -58,7 +58,7 @@ def unifyEq? (mvarId : MVarId) (eqFVarId : FVarId) (subst : FVarSubst := {})
|
|||
return some { mvarId, subst }
|
||||
else if (← isDefEq a b) then
|
||||
/- Skip equality -/
|
||||
return some { mvarId := (← clear mvarId eqFVarId), subst }
|
||||
return some { mvarId := (← mvarId.clear eqFVarId), subst }
|
||||
else if (← acyclic mvarId (mkFVar eqFVarId)) then
|
||||
return none -- this alternative has been solved
|
||||
else
|
||||
|
|
@ -77,8 +77,8 @@ def unifyEq? (mvarId : MVarId) (eqFVarId : FVarId) (subst : FVarSubst := {})
|
|||
/- Reduced lhs/rhs of current equality -/
|
||||
let prf := mkFVar eqFVarId
|
||||
let aEqb' ← mkEq a' b'
|
||||
let mvarId ← assert mvarId eqDecl.userName aEqb' prf
|
||||
let mvarId ← clear mvarId eqFVarId
|
||||
let mvarId ← mvarId.assert eqDecl.userName aEqb' prf
|
||||
let mvarId ← mvarId.clear eqFVarId
|
||||
return some { mvarId, subst, numNewEqs := 1 }
|
||||
else
|
||||
match caseName? with
|
||||
|
|
@ -97,7 +97,7 @@ def unifyEq? (mvarId : MVarId) (eqFVarId : FVarId) (subst : FVarSubst := {})
|
|||
| a, b =>
|
||||
if (← isDefEq a b) then
|
||||
/- Skip equality -/
|
||||
return some { mvarId := (← clear mvarId eqFVarId), subst }
|
||||
return some { mvarId := (← mvarId.clear eqFVarId), subst }
|
||||
else
|
||||
injection a b
|
||||
|
||||
|
|
|
|||
|
|
@ -11,18 +11,26 @@ import Lean.Meta.PPGoal
|
|||
namespace Lean.Meta
|
||||
|
||||
/-- Aka user name -/
|
||||
def getMVarTag (mvarId : MVarId) : MetaM Name :=
|
||||
return (← getMVarDecl mvarId).userName
|
||||
def _root_.Lean.MVarId.getTag (mvarId : MVarId) : MetaM Name :=
|
||||
return (← mvarId.getDecl).userName
|
||||
|
||||
def setMVarTag (mvarId : MVarId) (tag : Name) : MetaM Unit := do
|
||||
@[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 ← getMVarTag mvarId
|
||||
setMVarTag mvarId (appendTag tag suffix)
|
||||
let tag ← mvarId.getTag
|
||||
mvarId.setTag (appendTag tag suffix)
|
||||
|
||||
def mkFreshExprSyntheticOpaqueMVar (type : Expr) (tag : Name := Name.anonymous) : MetaM Expr :=
|
||||
mkFreshExprMVar type MetavarKind.syntheticOpaque tag
|
||||
|
|
@ -36,33 +44,64 @@ def throwTacticEx (tacticName : Name) (mvarId : MVarId) (msg : MessageData) : Me
|
|||
def throwNestedTacticEx {α} (tacticName : Name) (ex : Exception) : MetaM α := do
|
||||
throwError "tactic '{tacticName}' failed, nested error:\n{ex.toMessageData}"
|
||||
|
||||
def checkNotAssigned (mvarId : MVarId) (tacticName : Name) : MetaM Unit := do
|
||||
if (← isExprMVarAssigned mvarId) then
|
||||
/--
|
||||
Throw error message if `mvarId` is already 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"
|
||||
|
||||
def getMVarType (mvarId : MVarId) : MetaM Expr :=
|
||||
return (← getMVarDecl mvarId).type
|
||||
@[deprecated MVarId.checkNotAssigned]
|
||||
def checkNotAssigned (mvarId : MVarId) (tacticName : Name) : MetaM Unit := do
|
||||
mvarId.checkNotAssigned tacticName
|
||||
|
||||
def _root_.Lean.MVarId.getType (mvarId : MVarId) : MetaM Expr :=
|
||||
return (← mvarId.getDecl).type
|
||||
|
||||
@[deprecated MVarId.getType]
|
||||
def getMVarType (mvarId : MVarId) : MetaM Expr :=
|
||||
mvarId.getType
|
||||
|
||||
def _root_.Lean.MVarId.getType' (mvarId : MVarId) : MetaM Expr := do
|
||||
whnf (← instantiateMVars (← mvarId.getType))
|
||||
|
||||
@[deprecated MVarId.getType']
|
||||
def getMVarType' (mvarId : MVarId) : MetaM Expr := do
|
||||
whnf (← instantiateMVars (← getMVarDecl mvarId).type)
|
||||
mvarId.getType'
|
||||
|
||||
builtin_initialize registerTraceClass `Meta.Tactic
|
||||
|
||||
/-- Assign `mvarId` to `sorryAx` -/
|
||||
def admit (mvarId : MVarId) (synthetic := true) : MetaM Unit :=
|
||||
withMVarContext mvarId do
|
||||
checkNotAssigned mvarId `admit
|
||||
let mvarType ← getMVarType mvarId
|
||||
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
|
||||
assignExprMVar mvarId val
|
||||
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
|
||||
setMVarType mvarId (← getMVarType mvarId).headBeta
|
||||
mvarId.headBetaType
|
||||
|
||||
/-- Collect nondependent hypotheses that are propositions. -/
|
||||
def getNondepPropHyps (mvarId : MVarId) : MetaM (Array FVarId) :=
|
||||
withMVarContext mvarId do
|
||||
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.forEach fun
|
||||
| Expr.fvar fvarId => modify fun s => s.erase fvarId
|
||||
| _ => pure ()
|
||||
get
|
||||
visit |>.run' candidates
|
||||
mvarId.withContext do
|
||||
let mut candidates : FVarIdHashSet := {}
|
||||
for localDecl in (← getLCtx) do
|
||||
unless localDecl.isAuxDecl do
|
||||
|
|
@ -72,7 +111,7 @@ def getNondepPropHyps (mvarId : MVarId) : MetaM (Array FVarId) :=
|
|||
| some value => candidates ← removeDeps value candidates
|
||||
if (← isProp localDecl.type) && !localDecl.hasValue then
|
||||
candidates := candidates.insert localDecl.fvarId
|
||||
candidates ← removeDeps (← getMVarType mvarId) candidates
|
||||
candidates ← removeDeps (← mvarId.getType) candidates
|
||||
if candidates.isEmpty then
|
||||
return #[]
|
||||
else
|
||||
|
|
@ -81,15 +120,10 @@ def getNondepPropHyps (mvarId : MVarId) : MetaM (Array FVarId) :=
|
|||
if candidates.contains localDecl.fvarId then
|
||||
result := result.push localDecl.fvarId
|
||||
return result
|
||||
where
|
||||
removeDeps (e : Expr) (candidates : FVarIdHashSet) : MetaM FVarIdHashSet := do
|
||||
let e ← instantiateMVars e
|
||||
let visit : StateRefT FVarIdHashSet MetaM FVarIdHashSet := do
|
||||
e.forEach fun
|
||||
| Expr.fvar fvarId => modify fun s => s.erase fvarId
|
||||
| _ => pure ()
|
||||
get
|
||||
visit |>.run' candidates
|
||||
|
||||
@[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 #[]
|
||||
|
|
|
|||
|
|
@ -337,14 +337,22 @@ def isLevelMVarAssigned [Monad m] [MonadMCtx m] (mvarId : LMVarId) : m Bool := d
|
|||
return (← getMCtx).lAssignment.contains mvarId
|
||||
|
||||
/-- Return `true` if the give metavariable is already assigned. -/
|
||||
def isExprMVarAssigned [Monad m] [MonadMCtx m] (mvarId : MVarId) : m Bool := do
|
||||
def _root_.Lean.MVarId.isAssigned [Monad m] [MonadMCtx m] (mvarId : MVarId) : m Bool := do
|
||||
markUsedAssignment
|
||||
return (← getMCtx).eAssignment.contains mvarId
|
||||
|
||||
def isMVarDelayedAssigned [Monad m] [MonadMCtx m] (mvarId : MVarId) : m Bool := do
|
||||
@[deprecated MVarId.isAssigned]
|
||||
def isExprMVarAssigned [Monad m] [MonadMCtx m] (mvarId : MVarId) : m Bool := do
|
||||
mvarId.isAssigned
|
||||
|
||||
def _root_.Lean.MVarId.isDelayedAssigned [Monad m] [MonadMCtx m] (mvarId : MVarId) : m Bool := do
|
||||
markUsedAssignment
|
||||
return (← getMCtx).dAssignment.contains mvarId
|
||||
|
||||
@[deprecated MVarId.isDelayedAssigned]
|
||||
def isMVarDelayedAssigned [Monad m] [MonadMCtx m] (mvarId : MVarId) : m Bool := do
|
||||
mvarId.isDelayedAssigned
|
||||
|
||||
def isLevelMVarAssignable [Monad m] [MonadMCtx m] (mvarId : LMVarId) : m Bool := do
|
||||
markUsedAssignment
|
||||
let mctx ← getMCtx
|
||||
|
|
@ -357,12 +365,16 @@ def MetavarContext.getDecl (mctx : MetavarContext) (mvarId : MVarId) : MetavarDe
|
|||
| some decl => decl
|
||||
| none => panic! "unknown metavariable"
|
||||
|
||||
def isExprMVarAssignable [Monad m] [MonadMCtx m] (mvarId : MVarId) : m Bool := do
|
||||
def _root_.Lean.MVarId.isAssignable [Monad m] [MonadMCtx m] (mvarId : MVarId) : m Bool := do
|
||||
markUsedAssignment
|
||||
let mctx ← getMCtx
|
||||
let decl := mctx.getDecl mvarId
|
||||
return decl.depth == mctx.depth
|
||||
|
||||
@[deprecated MVarId.isAssignable]
|
||||
def isExprMVarAssignable [Monad m] [MonadMCtx m] (mvarId : MVarId) : m Bool := do
|
||||
mvarId.isAssignable
|
||||
|
||||
/-- Return true iff the given level contains an assigned metavariable. -/
|
||||
def hasAssignedLevelMVar [Monad m] [MonadMCtx m] : Level → m Bool
|
||||
| Level.succ lvl => pure lvl.hasMVar <&&> hasAssignedLevelMVar lvl
|
||||
|
|
@ -385,7 +397,7 @@ def hasAssignedMVar [Monad m] [MonadMCtx m] : Expr → m Bool
|
|||
| Expr.lit _ => return false
|
||||
| Expr.mdata _ e => pure e.hasMVar <&&> hasAssignedMVar e
|
||||
| Expr.proj _ _ e => pure e.hasMVar <&&> hasAssignedMVar e
|
||||
| Expr.mvar mvarId => isExprMVarAssigned mvarId <||> isMVarDelayedAssigned mvarId
|
||||
| Expr.mvar mvarId => mvarId.isAssigned <||> mvarId.isDelayedAssigned
|
||||
|
||||
/-- Return true iff the given level contains a metavariable that can be assigned. -/
|
||||
def hasAssignableLevelMVar [Monad m] [MonadMCtx m] : Level → m Bool
|
||||
|
|
@ -409,7 +421,7 @@ def hasAssignableMVar [Monad m] [MonadMCtx m] : Expr → m Bool
|
|||
| Expr.lit _ => return false
|
||||
| Expr.mdata _ e => pure e.hasMVar <&&> hasAssignableMVar e
|
||||
| Expr.proj _ _ e => pure e.hasMVar <&&> hasAssignableMVar e
|
||||
| Expr.mvar mvarId => isExprMVarAssignable mvarId
|
||||
| Expr.mvar mvarId => mvarId.isAssignable
|
||||
|
||||
/--
|
||||
Add `mvarId := u` to the universe metavariable assignment.
|
||||
|
|
@ -426,9 +438,13 @@ This method does not check whether `mvarId` is already assigned, nor it checks w
|
|||
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 assignExprMVar [MonadMCtx m] (mvarId : MVarId) (val : Expr) : m Unit :=
|
||||
def _root_.Lean.MVarId.assign [MonadMCtx m] (mvarId : MVarId) (val : Expr) : m Unit :=
|
||||
modifyMCtx fun m => { m with eAssignment := m.eAssignment.insert mvarId val, usedAssignment := true }
|
||||
|
||||
@[deprecated MVarId.assign]
|
||||
def assignExprMVar [MonadMCtx m] (mvarId : MVarId) (val : Expr) : m Unit :=
|
||||
mvarId.assign val
|
||||
|
||||
def assignDelayedMVar [MonadMCtx m] (mvarId : MVarId) (fvars : Array Expr) (mvarIdPending : MVarId) : m Unit :=
|
||||
modifyMCtx fun m => { m with dAssignment := m.dAssignment.insert mvarId { fvars, mvarIdPending }, usedAssignment := true }
|
||||
|
||||
|
|
@ -531,7 +547,7 @@ partial def instantiateExprMVars [Monad m] [MonadMCtx m] [STWorld ω m] [MonadLi
|
|||
match (← getExprMVarAssignment? mvarId) with
|
||||
| some newE => do
|
||||
let newE' ← instantiateExprMVars newE
|
||||
assignExprMVar mvarId newE'
|
||||
mvarId.assign newE'
|
||||
pure newE'
|
||||
| none => pure e
|
||||
| e => pure e
|
||||
|
|
@ -1024,7 +1040,7 @@ mutual
|
|||
A potential disadvantage is that `isDefEq` will not eagerly use `synthPending` for natural metavariables.
|
||||
That being said, we should try this approach as soon as we have an extensive test suite.
|
||||
-/
|
||||
let newMVarKind := if !(← isExprMVarAssignable mvarId) then MetavarKind.syntheticOpaque else mvarDecl.kind
|
||||
let newMVarKind := if !(← mvarId.isAssignable) then MetavarKind.syntheticOpaque else mvarDecl.kind
|
||||
let args ← args.mapM (visit xs)
|
||||
let toRevert ← collectForwardDeps mvarLCtx toRevert
|
||||
let newMVarLCtx := reduceLocalContext mvarLCtx toRevert
|
||||
|
|
@ -1041,7 +1057,7 @@ mutual
|
|||
ngen := s.ngen.next
|
||||
}
|
||||
if !mvarDecl.kind.isSyntheticOpaque then
|
||||
assignExprMVar mvarId result
|
||||
mvarId.assign result
|
||||
else
|
||||
/- If `mvarId` is the lhs of a delayed assignment `?m #[x_1, ... x_n] := ?mvarPending`,
|
||||
then `nestedFVars` is `#[x_1, ..., x_n]`.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ def delabBVar : Delab := do
|
|||
@[builtinDelab mvar]
|
||||
def delabMVar : Delab := do
|
||||
let Expr.mvar n ← getExpr | unreachable!
|
||||
let mvarDecl ← getMVarDecl n
|
||||
let mvarDecl ← n.getDecl
|
||||
let n :=
|
||||
match mvarDecl.userName with
|
||||
| Name.anonymous => n.name.replacePrefix `_uniq `m
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ where
|
|||
| Name.anonymous => false
|
||||
|
||||
def mvarName (mvar : Expr) : MetaM Name :=
|
||||
return (← getMVarDecl mvar.mvarId!).userName
|
||||
return (← mvar.mvarId!.getDecl).userName
|
||||
|
||||
def containsBadMax : Level → Bool
|
||||
| Level.succ u .. => containsBadMax u
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ macro "obviously1" : tactic => `(exact sorryAx _)
|
|||
theorem result1 : False := by obviously1
|
||||
|
||||
elab "obviously2" : tactic =>
|
||||
liftMetaTactic1 (Meta.admit · *> pure none)
|
||||
liftMetaTactic1 fun mvarId => mvarId.admit *> pure none
|
||||
|
||||
theorem result2 : False := by obviously2
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ open Lean Meta
|
|||
#eval do
|
||||
let e ← withLetDecl `y (mkConst ``Nat) (mkConst ``Nat.zero) fun y => do
|
||||
let m ← mkFreshExprMVar (mkConst ``Nat)
|
||||
assignExprMVar m.mvarId! y
|
||||
m.mvarId!.assign y
|
||||
let e := mkApp2 (mkConst ``Nat.add) m y
|
||||
-- goal: construct λ y, e
|
||||
dbg_trace (← ppExpr (← mkLambdaFVars #[y] e)) -- doesn't work: creates let
|
||||
|
|
@ -17,7 +17,7 @@ open Lean Meta
|
|||
#eval
|
||||
withLetDecl `y (mkConst ``Nat) (mkConst ``Nat.zero) fun y => do
|
||||
let m ← mkFreshExprMVar (mkConst ``Nat)
|
||||
assignExprMVar m.mvarId! y
|
||||
m.mvarId!.assign y
|
||||
let e := mkApp2 (mkConst ``Nat.add) m y
|
||||
-- goal: construct λ y, e
|
||||
dbg_trace (← instantiateMVars <| -- doesn't work: contains free variable
|
||||
|
|
@ -31,6 +31,6 @@ open Lean Meta
|
|||
dbg_trace (← ppExpr (← abstract e #[y]))
|
||||
let e ← instantiateMVars <| -- doesn't work: contains free variable
|
||||
mkLambda `y BinderInfo.default (mkConst ``Nat) (← abstract e #[y])
|
||||
assignExprMVar m.mvarId! (mkApp2 (mkConst ``Nat.add) y y)
|
||||
m.mvarId!.assign (mkApp2 (mkConst ``Nat.add) y y)
|
||||
return (e, m)
|
||||
dbg_trace (← ppExpr (← instantiateMVars e))
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ open Lean.Meta in
|
|||
def test : MetaM Unit := do
|
||||
let type := (← getConstInfo ``ex).type
|
||||
let mvar ← mkFreshExprMVar type
|
||||
let (#[p, q, h], mvarId) ← introNP mvar.mvarId! 3 | throwError "unexpected"
|
||||
let (#[p, q, h], mvarId) ← mvar.mvarId!.introNP 3 | throwError "unexpected"
|
||||
trace[Meta.debug] "{MessageData.ofGoal mvarId}"
|
||||
let (s₁, s₂) ← byCases mvarId (mkFVar p) `hAux
|
||||
trace[Meta.debug] "{MessageData.ofGoal s₁.mvarId}\n------\n{MessageData.ofGoal s₂.mvarId}"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue