lean4-htt/src/Lean/Meta/Tactic/Intro.lean
2021-02-01 17:35:48 -08:00

116 lines
4.9 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

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

/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean.Meta.Tactic.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
let lctx ← getLCtx
let rec @[specialize] loop : Nat → LocalContext → Array Expr → Nat → σ → Expr → MetaM (Array Expr × MVarId)
| 0, lctx, fvars, j, _, type =>
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 type := type.headBeta
let newMVar ← mkFreshExprSyntheticOpaqueMVar type tag
let lctx ← getLCtx
let newVal ← mkLambdaFVars fvars newMVar
assignExprMVar mvarId newVal
pure $ (fvars, newMVar.mvarId!)
| (i+1), lctx, fvars, j, s, Expr.letE n type val body _ => do
let type := type.instantiateRevRange j fvars.size fvars
let type := type.headBeta
let val := val.instantiateRevRange j fvars.size fvars
let fvarId ← mkFreshId
let (n, s) ← mkName lctx n true s
let lctx := lctx.mkLetDecl fvarId n type val
let fvar := mkFVar fvarId
let fvars := fvars.push fvar
loop i lctx fvars j s body
| (i+1), lctx, fvars, j, s, Expr.forallE n type body c => do
let type := type.instantiateRevRange j fvars.size fvars
let type := type.headBeta
let fvarId ← mkFreshId
let (n, s) ← mkName lctx n c.binderInfo.isExplicit s
let lctx := lctx.mkLocalDecl fvarId n type c.binderInfo
let fvar := mkFVar fvarId
let fvars := fvars.push fvar
loop i lctx fvars j s body
| (i+1), lctx, fvars, j, s, type =>
let type := type.instantiateRevRange j fvars.size fvars
withReader (fun ctx => { ctx with lctx := lctx }) do
withNewLocalInstances fvars j do
let newType ← whnf type
if newType.isForall then
loop (i+1) lctx fvars fvars.size s newType
else
throwTacticEx `introN mvarId "insufficient number of binders"
let (fvars, mvarId) ← loop n lctx #[] 0 s mvarType
pure (fvars.map Expr.fvarId!, mvarId)
register_builtin_option hygienicIntro : Bool := {
defValue := true
group := "tactic"
descr := "make sure 'intro'-like tactics are hygienic"
}
def getHygienicIntro : MetaM Bool := do
return hygienicIntro.get (← getOptions)
private def mkAuxNameImp (preserveBinderNames : Bool) (hygienic : Bool) (useNamesForExplicitOnly : Bool)
(lctx : LocalContext) (binderName : Name) (isExplicit : Bool) : List Name → MetaM (Name × List Name)
| [] => do
if preserveBinderNames then
pure (binderName, [])
else if hygienic then do
let binderName ← mkFreshUserName binderName;
pure (binderName, [])
else
pure (lctx.getUnusedName binderName, [])
| n :: rest => do
if (!useNamesForExplicitOnly || isExplicit) && n != Name.mkSimple "_" then
pure (n, rest)
else if preserveBinderNames then
pure (binderName, rest)
else if hygienic then
let binderName ← mkFreshUserName binderName
pure (binderName, rest)
else
pure (lctx.getUnusedName binderName, rest)
def introNCore (mvarId : MVarId) (n : Nat) (givenNames : List Name) (useNamesForExplicitOnly : Bool) (preserveBinderNames : Bool)
: MetaM (Array FVarId × MVarId) := do
let hygienic ← getHygienicIntro
if n == 0 then
pure (#[], mvarId)
else
introNImp mvarId n (mkAuxNameImp preserveBinderNames hygienic useNamesForExplicitOnly) givenNames
abbrev 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) :=
introNCore mvarId n [] (useNamesForExplicitOnly := false) (preserveBinderNames := true)
def intro (mvarId : MVarId) (name : Name) : MetaM (FVarId × MVarId) := do
let (fvarIds, mvarId) ← introN mvarId 1 [name]
pure (fvarIds.get! 0, mvarId)
def intro1Core (mvarId : MVarId) (preserveBinderNames : Bool) : MetaM (FVarId × MVarId) := do
let (fvarIds, mvarId) ← introNCore mvarId 1 [] (useNamesForExplicitOnly := false) preserveBinderNames
pure (fvarIds.get! 0, mvarId)
abbrev intro1 (mvarId : MVarId) : MetaM (FVarId × MVarId) :=
intro1Core mvarId false
abbrev intro1P (mvarId : MVarId) : MetaM (FVarId × MVarId) :=
intro1Core mvarId true
end Lean.Meta