| /- | |
| 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.Basic | |
| import Lean.Meta.InferType | |
| namespace Lean.Meta | |
| @[inline] private def checkFunInfoCache (fn : Expr) (maxArgs? : Option Nat) (k : MetaM FunInfo) : MetaM FunInfo := do | |
| let s ← get | |
| let t ← getTransparency | |
| match s.cache.funInfo.find? ⟨t, fn, maxArgs?⟩ with | |
| | some finfo => pure finfo | |
| | none => do | |
| let finfo ← k | |
| modify fun s => { s with cache := { s.cache with funInfo := s.cache.funInfo.insert ⟨t, fn, maxArgs?⟩ finfo } } | |
| pure finfo | |
| @[inline] private def whenHasVar {α} (e : Expr) (deps : α) (k : α → α) : α := | |
| if e.hasFVar then k deps else deps | |
| private def collectDeps (fvars : Array Expr) (e : Expr) : Array Nat := | |
| let rec visit : Expr → Array Nat → Array Nat | |
| | e@(Expr.app f a _), deps => whenHasVar e deps (visit a ∘ visit f) | |
| | e@(Expr.forallE _ d b _), deps => whenHasVar e deps (visit b ∘ visit d) | |
| | e@(Expr.lam _ d b _), deps => whenHasVar e deps (visit b ∘ visit d) | |
| | e@(Expr.letE _ t v b _), deps => whenHasVar e deps (visit b ∘ visit v ∘ visit t) | |
| | Expr.proj _ _ e _, deps => visit e deps | |
| | Expr.mdata _ e _, deps => visit e deps | |
| | e@(Expr.fvar _ _), deps => | |
| match fvars.indexOf? e with | |
| | none => deps | |
| | some i => if deps.contains i.val then deps else deps.push i.val | |
| | _, deps => deps | |
| let deps := visit e #[] | |
| deps.qsort (fun i j => i < j) | |
| /-- Update `hasFwdDeps` fields using new `backDeps` -/ | |
| private def updateHasFwdDeps (pinfo : Array ParamInfo) (backDeps : Array Nat) : Array ParamInfo := | |
| if backDeps.size == 0 then | |
| pinfo | |
| else | |
| -- update hasFwdDeps fields | |
| pinfo.mapIdx fun i info => | |
| if info.hasFwdDeps then info | |
| else if backDeps.contains i then | |
| { info with hasFwdDeps := true } | |
| else | |
| info | |
| private def getFunInfoAux (fn : Expr) (maxArgs? : Option Nat) : MetaM FunInfo := | |
| checkFunInfoCache fn maxArgs? do | |
| let fnType ← inferType fn | |
| withTransparency TransparencyMode.default do | |
| forallBoundedTelescope fnType maxArgs? fun fvars type => do | |
| let mut pinfo := #[] | |
| for i in [:fvars.size] do | |
| let fvar := fvars[i] | |
| let decl ← getFVarLocalDecl fvar | |
| let backDeps := collectDeps fvars decl.type | |
| pinfo := updateHasFwdDeps pinfo backDeps | |
| pinfo := pinfo.push { | |
| backDeps := backDeps, | |
| implicit := decl.binderInfo == BinderInfo.implicit, | |
| instImplicit := decl.binderInfo == BinderInfo.instImplicit | |
| } | |
| let resultDeps := collectDeps fvars type | |
| let pinfo := updateHasFwdDeps pinfo resultDeps | |
| pure { resultDeps := resultDeps, paramInfo := pinfo } | |
| def getFunInfo (fn : Expr) : MetaM FunInfo := | |
| getFunInfoAux fn none | |
| def getFunInfoNArgs (fn : Expr) (nargs : Nat) : MetaM FunInfo := | |
| getFunInfoAux fn (some nargs) | |
| end Lean.Meta |