blob: c7d17a569ad3b2a96f8738bc24e9581f98dbf3d4 [file]
/-
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