feat: improve Code.bind
Add `joinTypes`.
This commit is contained in:
parent
1f57155eb9
commit
82acc2b39c
4 changed files with 59 additions and 2 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
-/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue