feat: improve Code.bind

Add `joinTypes`.
This commit is contained in:
Leonardo de Moura 2022-08-22 21:07:23 -07:00
parent 1f57155eb9
commit 82acc2b39c
4 changed files with 59 additions and 2 deletions

View file

@ -16,12 +16,14 @@ structure Param where
inductive AltCore (Code : Type) where
| alt (ctorName : Name) (params : Array Param) (code : Code)
| default (code : Code)
deriving Inhabited
structure LetDecl where
fvarId : FVarId
binderName : Name
type : Expr
value : Expr
deriving Inhabited
structure FunDeclCore (Code : Type) where
fvarId : FVarId
@ -29,12 +31,14 @@ structure FunDeclCore (Code : Type) where
params : Array Param
type : Expr
value : Code
deriving Inhabited
structure CasesCore (Code : Type) where
typeName : Name
resultType : Expr
discr : FVarId
alts : Array (AltCore Code)
deriving Inhabited
inductive Code where
| let (decl : LetDecl) (k : Code)
@ -44,6 +48,7 @@ inductive Code where
| cases (cases : CasesCore Code)
| return (fvarId : FVarId)
| unreach (type : Expr)
deriving Inhabited
abbrev Alt := AltCore Code
abbrev FunDecl := FunDeclCore Code

View file

@ -24,14 +24,21 @@ where
| .let decl k => return .let decl (← go k)
| .fun decl k => return .fun decl (← go k)
| .jp decl k =>
let decl := { decl with value := (← go decl.value) }
let value ← go decl.value
let type ← value.inferParamType decl.params
let decl := { decl with value, type }
withReader (fun s => s.insert decl.fvarId) do
return .jp decl (← go k)
| .cases c =>
let alts ← c.alts.mapM fun
| .alt ctorName params k => return .alt ctorName params (← go k)
| .default k => return .default (← go k)
return .cases { c with alts }
if alts.isEmpty then
throwError "`Code.bind` failed, empty `cases` found"
let mut resultType ← alts[0]!.inferType
for alt in alts[1:] do
resultType := joinTypes resultType (← alt.inferType)
return .cases { c with alts, resultType }
| .return fvarId => f fvarId
| .jmp fvarId .. =>
unless (← read).contains fvarId do

View file

@ -170,4 +170,14 @@ def Code.inferType (code : Code) : CompilerM Expr := do
| .unreach type => return type
| .cases c => return c.resultType
def Code.inferParamType (params : Array Param) (code : Code) : CompilerM Expr := do
let type ← code.inferType
let xs := params.map fun p => .fvar p.fvarId
InferType.mkForallFVars xs type |>.run {}
def AltCore.inferType (alt : Alt) : CompilerM Expr := do
match alt with
| .default k => k.inferType
| .alt _ params k => k.inferParamType params
end Lean.Compiler.LCNF

View file

@ -183,6 +183,41 @@ partial def compatibleTypes (a b : Expr) : Bool :=
| .const n us, .const m vs => n == m && List.isEqv us vs Level.isEquiv
| _, _ => false
mutual
partial def joinTypes (a b : Expr) : Expr :=
joinTypes? a b |>.getD anyTypeExpr
partial def joinTypes? (a b : Expr) : Option Expr := do
if a.isAnyType then return a
else if b.isAnyType then return b
else if a == b then return a
else if a.erased || b.erased then failure
else
let a' := a.headBeta
let b' := b.headBeta
if a != a' || b != b' then
joinTypes? a' b'
else
match a, b with
| .mdata _ a, b => joinTypes? a b
| a, .mdata _ b => joinTypes? a b
| .app f a, .app g b =>
(do return .app (← joinTypes? f g) (← joinTypes? a b))
<|>
return anyTypeExpr
| .forallE n d₁ b₁ _, .forallE _ d₂ b₂ _ =>
(do return .forallE n (← joinTypes? d₁ d₂) (joinTypes b₁ b₂) .default)
<|>
return anyTypeExpr
| .lam n d₁ b₁ _, .lam _ d₂ b₂ _ =>
(do return .lam n (← joinTypes? d₁ d₂) (joinTypes b₁ b₂) .default)
<|>
return anyTypeExpr
| _, _ => return anyTypeExpr
end
/--
Return `true` if `type` is a LCNF type former type.
-/