Nested Refinements: A Logic for Duck Typing :: Ravi Chugh, Pat Rondon, Ranjit Jhala (UCSD)
What are “Dynamic Languages”? affect control flow tag tests indexed by arbitrary string keys dic<onary objects can appear inside objects first‐class func<ons let onto callbacks f obj = if f = null then new List(obj, callbacks) else let cb = if tagof f = “Str” then obj[f] else f in new List(fun () -> cb obj, callbacks) 2
affect control flow tag tests indexed by arbitrary string keys dic<onary objects can appear inside objects first‐class func<ons Problem: Lack of sta<c types … makes rapid prototyping / mul<‐language applica<ons easy … makes reliability / performance / maintenance hard This Talk: System D … a type system for these features 3
affect control flow tag tests indexed by arbitrary string keys dic<onary objects can appear inside objects first‐class func<ons Usability Our Approach: Quan<fier‐free formulas F ≤ 1. increase expressiveness ∨ , ∧ refinement nested occurrence types refinements 2. retain level of automa<on types … Coq syntac<c approaches dependent approaches Expressiveness
affect control flow tag tests indexed by arbitrary string keys dic<onary objects can appear inside objects first‐class func<ons { ν | tag( ν ) = “Int” ∨ tag( ν ) = “Bool” } x :: d :: { ν | tag( ν ) = “Dict” ∧ tag(sel( ν ,“n”)) = “Int” ∧ tag(sel( ν ,m)) = “Int” } Challenge: Func<ons inside dic<onaries 5
Key Idea: Nested Refinements 1 + d[f](0) d :: { ν | tag( ν ) = “Dict” ∧ sel( ν ,f) :: { ν | tag( ν )=“Int” } } → { ν | tag( ν )=“Int” } syntac<c arrow type… uninterpreted predicate “ x :: U ” says “ x has‐type U ” 6
Key Idea: Nested Refinements 1 + d[f](0) d :: { ν | tag( ν ) = “Dict” ∧ sel( ν ,f) :: { ν | tag( ν )=“Int” } } → { ν | tag( ν )=“Int” } syntac<c arrow type… uninterpreted predicate “ x :: U ” says … but uninterpreted “ x has‐type U ” constant in the logic 7
Key Idea: Nested Refinements • All values described by refinement formulas T ::= { ν | p } • “Has‐type” predicate for arrows in formulas p ::= … | x :: y:T 1 → T 2 • Can express idioms of dynamic languages • Automa<c type checking – Decidable refinement logic – Subtyping = SMT Validity + Syntac<c Subtyping 8
Outline Intro Examples Subtyping Type Soundness Conclusion 9
x:{ ν | tag( ν ) = “Int” ∨ tag( ν ) = “Bool” } → { ν | tag( ν ) = tag(x) } x:IntOrBool → { ν | tag( ν ) = tag(x) } let negate x = if tagof x = “Int” then 0 – x else not x y:Top → { ν | ν = tag(y) } tagof :: y:{ ν | true } 10
✓ x:IntOrBool → { ν | tag( ν ) = tag(x) } let negate x = if tagof x = “Int” then 0 – x else not x type environment Γ ∧ tag(x) = “Int” x :: IntOrBool ✓ SMT Solver x :: { ν | Int( ν ) } ✓ 0 - x :: { ν | Int( ν ) } 11
✓ x:IntOrBool → { ν | tag( ν ) = tag(x) } let negate x = if tagof x = “Int” then 0 – x else not x type environment Γ ∧ not (tag(x) = “Int”) x :: IntOrBool ✓ SMT Solver x :: { ν | Bool( ν ) } ✓ not x :: { ν | Bool( ν ) } 12
x:IntOrBool → { ν | tag( ν ) = tag(x) } Nes<ng structure hidden with syntac<c sugar → { ν | ν :: } x: IntOrBool { ν | tag( ν ) = tag(x) } 13
Dic<onary Opera<ons Types in terms of McCarthy operators d:Dict → k:Str → { ν | ν = true ⇔ has(d,k) } mem :: get :: d:Dict → k:{ ν | has(d, ν ) } → { ν | ν = sel(d,k) } d:Dict → k:Str → x:Top → { ν | ν = upd(d,k,x) } set :: 14
d:Dict → c:Str → Int let getCount d c = get d c if mem d c then toInt (d[c]) else 0 safe dic<onary key lookup { ν | ν = true ⇔ has(d,c) } 15
d:Dict → c:Str → Int let getCount d c = if mem d c then toInt (d[c]) else 0 tag(sel( ν ,c)) = “Int” d:Dict → c:Str → { ν | EqMod( ν ,d,c) ∧ Int( ν [c]) } let incCount d c = let i = getCount d c in {d with c = i + 1} set d c (i+1) 16
Adding Type Constructors T ::= { ν | p } p ::= … | x :: U U ::= y:T 1 → T 2 “type terms” | A | List T | Null 17
let apply f x = f x ∀ A,B. { ν | ν :: { ν | ν :: A } → { ν | ν :: B } } → { ν | ν :: A } → { ν | ν :: B } ∀ A,B. (A → B) → A → B 18
let dispatch d f = d[f](d) ∀ A,B. d:{ ν | ν :: A } → f:{ ν | d[ ν ] :: A → B } → { ν | ν :: B } a form of “bounded quan<fica<on” d :: A but addi<onal constraints on A ≈ ∀ A <: {f: A → B}. d :: A 19
∀ A,B. { ν | ν :: A → B } → { ν | ν :: List[A] } → { ν | ν :: List[B] } ∀ A,B. (A → B) → List[A] → List[B] let map f xs = if xs = null then null else new List(f xs[“hd”], map f xs[“tl”]) encode recursive data as dic<onaries 20
let filter f xs = if xs = null then null else if not (f xs[“hd”]) then filter f xs[“tl”] else new List(xs[“hd”], filter f xs[“tl”]) usual defini<on, but an interes<ng type ∀ A,B. (x:A → { ν | ν = true ⇒ x :: B } → List[A] → List[B] 21
Outline Intro Examples Subtyping Type Soundness Conclusion 22
type environment Γ applyInt :: (Int, Int → Int) → Int negate :: x:IntOrBool → { ν | tag( ν ) = tag(x) } applyInt (42, negate) ✓ SMT Γ ∧ ν = 42 ⇒ tag( ν ) = “Int” _ Γ { ν | ν = 42 } < Int | 23
type environment Γ applyInt :: (Int, Int → Int) → Int negate :: x:IntOrBool → { ν | tag( ν ) = tag(x) } applyInt (42, negate) … ∧ negate :: x:IorB → { ν | tag( ν ) = tag(x) } SMT … ∧ ν = negate ⇒ ν :: Int → Int _ Γ { ν | ν = negate } < { ν | ν :: Int → Int } | 24
type environment Γ applyInt :: (Int, Int → Int) → Int negate :: x:IntOrBool → { ν | tag( ν ) = tag(x) } applyInt (42, negate) … ∧ negate :: x:IorB → { ν | tag( ν ) = tag(x) } SMT … ∧ ν = negate ✗ dis<nct ⇒ ν :: Int → Int uninterpreted constants! _ Γ { ν | ν = negate } < { ν | ν :: Int → Int } | 25
Invalid, since these are uninterpreted constants ν :: x:IorB → { ν | tag( ν ) = tag(x) } ✗ ⇒ ν :: Int → Int Want conven<onal syntac<c subtyping ✓ ✓ ⇒ tag( ν ) = “Int” ⇒ tag( ν ) = “Int” tag( ν ) = “Int” ∧ tag( ν ) = tag(x) ⇒ ∨ tag( ν ) = “Bool” ⇒ tag( ν ) = “Int” Int <: IorB { ν | tag( ν ) = tag(x) } <: Int IorB → { ν | tag( ν ) = tag(x) } <: Int → Int 26
Subtyping with Nes<ng To prove p ⇒ q : 1) Convert q to CNF clauses (q 11 ∨ … ) ∧ … ∧ (q n1 ∨ … ) 2) For each clause, discharge some literal q ij as follows: base predicate: p ⇒ q ij anything except x :: U e.g. tag( ν ) = tag(x) e.g. tag(sel(d,k)) = “Int” 27
Subtyping with Nes<ng To prove p ⇒ q : 1) Convert q to CNF clauses (q 11 ∨ … ) ∧ … ∧ (q n1 ∨ … ) 2) For each clause, discharge some literal q ij as follows: base predicate: p ⇒ q ij “has‐type” predicate: p ⇒ x :: U Subtyping Subtyping Arrow Rule Implica<on Implica<on U’ <: U p ⇒ x :: U’ p ⇒ q ij SMT Solver SMT Solver 28
applyInt (42, negate) … ∧ negate :: x:IorB → { ν | tag( ν ) = tag(x) } Uninterpreted … ∧ ν = negate Reasoning ⇒ ν :: x:IorB → { ν | tag( ν ) = tag(x) } + Syntac<c _ Γ x:IorB → { ν | tag( ν ) = tag(x) } <: Int → Int | Reasoning _ Γ { ν | ν = negate } < { ν | ν :: Int → Int } | 29
Outline Intro Examples Subtyping Type Soundness Conclusion 30
_ If x:T x , Γ e[:: T | Subs<tu<on _ and | v :: T x Lemma _ then Γ [v/x] e[v/x] :: T[v/x] | independent of 0 , and just echoes the binding from the environment _ f:{ ν | ν :: Int → Int } | 0 :: { ν | f :: Int → Int } _ λ x.x+1 :: { ν | ν :: Int → Int } | _ | 0 :: { ν | λ x.x+1 :: Int → Int } 31
Recommend
More recommend