1 / 52

Nested Refinements: A Logic for Duck Typing

Nested Refinements: A Logic for Duck Typing. ::. Ravi Chugh , Pat Rondon, Ranjit Jhala (UCSD). What are “Dynamic Languages”?. tag tests. affect control flow. dictionary objects. indexed by arbitrary string keys. first-class functions. can appear inside objects.

kioshi
Download Presentation

Nested Refinements: A Logic for Duck Typing

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Nested Refinements: A Logic for Duck Typing :: Ravi Chugh, Pat Rondon, Ranjit Jhala (UCSD)

  2. What are “Dynamic Languages”? tag tests affect control flow dictionary objects indexed by arbitrary string keys first-class functions can appear inside objects 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)

  3. tag tests affect control flow dictionary objects indexed by arbitrary string keys first-class functions can appear inside objects • Problem: Lack of static types • … makes rapid prototyping / multi-language applications easy • … makes reliability / performance / maintenance hard • This Talk: System D • … a type system for these features

  4. tag tests affect control flow dictionary objects indexed by arbitrary string keys first-class functions can appear inside objects Usability Our Approach: Quantifier-free formulas F≤ 1. increase expressiveness 2. retain level of automation ∨, ∧ refinement types nested refinements occurrence types … Coq syntactic approaches dependent approaches Expressiveness

  5. tag tests affect control flow dictionary objects indexed by arbitrary string keys x :: {|tag()=“Int”tag()=“Bool”} {|tag()=“Dict” tag(sel(,“n”))=“Int” tag(sel(,m))=“Int”} d :: first-class functions can appear inside objects Challenge: Functions inside dictionaries

  6. Key Idea: Nested Refinements 1 + d[f](0) • {|tag()=“Dict” • sel(,f):: • } d :: {|tag()=“Int”}  {|tag()=“Int”} uninterpreted predicate“x::U” says“x has-type U” syntactic arrow type…

  7. Key Idea: Nested Refinements 1 + d[f](0) • {|tag()=“Dict” • sel(,f):: • } d :: {|tag()=“Int”}  {|tag()=“Int”} uninterpreted predicate“x::U” says“x has-type U” syntactic arrow type… … but uninterpreted constant in the logic

  8. Key Idea: Nested Refinements • All values described by refinement formulas T ::= {|p} • “Has-type” predicate for arrows in formulas p ::= … | x::y:T1T2 • Can express idioms of dynamic languages • Automatic type checking • Decidable refinement logic • Subtyping = SMT Validity + Syntactic Subtyping

  9. Outline Intro Examples Subtyping Type Soundness Conclusion

  10. 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 tagof :: y:Top{|=tag(y)} y:{|true}

  11. x:IntOrBool{|tag()=tag(x)} let negate x = if tagof x =“Int” then 0 – x else not x type environment Γ  tag(x)=“Int” x :: 0 - x:: x :: IntOrBool {|Int()} {|Int()} ✓ SMT Solver ✓

  12. 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 :: not x:: x :: IntOrBool {|Bool()} {|Bool()} ✓ SMT Solver ✓

  13. Nesting structure hidden with syntactic sugar x:IntOrBool{|tag()=tag(x)} x:  IntOrBool {|tag()=tag(x)} {|:: }

  14. Dictionary Operations Types in terms of McCarthy operators mem :: get :: set :: d:Dictk:Str{| =true has(d,k)} d:Dictk:{|has(d,)}{| =sel(d,k)} d:Dictk:Strx:Top{| =upd(d,k,x)}

  15. d:Dictc:StrInt get d c let getCount d c = if mem d c then toInt (d[c])else 0 safe dictionary key lookup {| =true has(d,c)}

  16. 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 = getCountd c in{d with c = i + 1} set d c (i+1)

  17. Adding Type Constructors T ::= {|p} p ::= … | x::U U ::= y:T1T2 | A | ListT | Null “type terms”

  18. let apply f x = fx ∀A,B.{|::{|::A}{|::B}} {|::A} {|::B} ∀A,B.(AB)AB

  19. let dispatch d f = d[f](d) ∀A,B.d:{|::A}f:{|d[]::AB}{|::B} a form of“bounded quantification” d::A but additional constraints on A ≈ ∀A<:{f:AB}.d::A

  20. ∀A,B. {|::AB}{|::List[A]}{|::List[B]} ∀A,B.(AB)List[A]List[B] letmapfxs = if xs=null then null else new List(fxs[“hd”], map f xs[“tl”]) encode recursive data as dictionaries

  21. let filterfxs = if xs=null then null else if not (f xs[“hd”]) then filterf xs[“tl”] else new List(xs[“hd”], filterf xs[“tl”]) ∀A,B.(x:A{|n=truex::B} List[A]List[B] usual definition,but an interesting type

  22. Outline Intro Examples Subtyping Type Soundness Conclusion

  23. type environment Γ _ | SMT Γ=42tag()=“Int” applyInt (42,negate) applyInt :: negate :: x:IntOrBool{|tag()=tag(x)} (Int,IntInt)Int ✓ Γ {|=42}<Int

  24. type environment Γ …negate::x:IorB{|tag()=tag(x)} …=negate ::IntInt SMT _ | applyInt (42,negate) applyInt :: negate :: x:IntOrBool{|tag()=tag(x)} (Int,IntInt)Int Γ {|=negate}<{|::IntInt}

  25. type environment Γ …negate::x:IorB{|tag()=tag(x)} …=negate ::IntInt SMT _ | applyInt (42,negate) applyInt :: negate :: x:IntOrBool{|tag()=tag(x)} (Int,IntInt)Int distinct uninterpreted constants! ✗ Γ {|=negate}<{|::IntInt}

  26. Invalid, since these are uninterpreted constants ::x:IorB{|tag()=tag(x)}  ::IntInt tag()=“Int” tag()=“Int”  tag()=“Bool” tag()=“Int”tag()=tag(x) tag()=“Int” ✗ Want conventional syntactic subtyping Int <: IorB {|tag()=tag(x)} <: Int ✓ ✓ IorB  {|tag()=tag(x)} <: Int  Int

  27. Subtyping with Nesting To prove pq: 1) Convert qto CNF clauses (q11…)…(qn1…) 2) For each clause, discharge some literal qij as follows: base predicate:pqij anything except x::U e.g. tag()=tag(x) e.g. tag(sel(d,k))=“Int”

  28. Subtyping with Nesting To prove pq: 1) Convert qto CNF clauses (q11…)…(qn1…) 2) For each clause, discharge some literal qij as follows: base predicate:pqij “has-type” predicate:px::U Subtyping Subtyping Arrow Rule Implication Implication U’<:U px::U’ pqij SMT Solver SMT Solver

  29. applyInt (42,negate) …negate::x:IorB{|tag()=tag(x)} …=negate ::x:IorB{|tag()=tag(x)} UninterpretedReasoning _ | + SyntacticReasoning Γ x:IorB{|tag()=tag(x)}<:IntInt _ Γ {|=negate}<{|::IntInt} |

  30. Outline Intro Examples Subtyping Type Soundness Conclusion

  31. x:Tx,Γ e[::T v :: Tx and If SubstitutionLemma Γ[v/x] e[v/x]::T[v/x] then _ _ _ | | | independent of 0, and just echoes the binding from the environment x.x+1 ::{|::IntInt} _ _ _ f:{|::IntInt} 0::{|f::IntInt} | | | 0::{|x.x+1::IntInt}

  32. x:Tx,Γ e[::T v :: Tx and If SubstitutionLemma Γ[v/x] e[v/x]::T[v/x] then _ _ _ | | | SMT =0x.x+1::IntInt 1st attempt ✗ _ 0::{|=0} {|=0}<{|x.x+1::IntInt} | 0::{|x.x+1::IntInt}

  33. x:Tx,Γ e[::T v :: Tx and If SubstitutionLemma ✗ Γ[v/x] e[v/x]::T[v/x] then _ _ _ | | | ✗ SMT =0::U’ + 2nd attempt Arrow U’ <:IntInt _ 0::{|=0} {|=0}<{|x.x+1::IntInt} | 0::{|x.x+1::IntInt}

  34. [S-Valid-Uninterpreted] • Rule not closed under substitution • Interpret formulas by “hooking back” into type system • Stratification to create ordering for induction I I iff = = | | [S-Valid-Interpreted] SMT Γpq x.x+1::{|::IntInt} Γpq n _ | n Γ {|=p}<{|=q} Γ {|=p}<{|=q} _ _ x.x+1::IntInt | | n n-1

  35. Type Soundness StratifiedSubstitutionLemma x:Tx,Γ e[::T If n _ _ _ _ v :: Tx and | | | | n Γ[v/x] e[v/x]::T[v/x] then n+1 • “Level 0” for type checking source programs, • using only [S-Valid-Uninterpreted] Stratified Preservation e  v e[::T and If 0 _ v[::T for some m then | m • artifact of the metatheory

  36. Recap • Dynamic languages make heavy use of: • run-time tag tests, dictionary objects, lambdas • Nested refinements • generalizes refinement type architecture • enables combination of dictionaries and lambdas • Decidable refinement logic • all proof obligations discharged algorithmically • novel subtyping decomposition to retain precision • Syntactic type soundness

  37. Future Work • Imperative Updates • Inheritance (prototypes in JS, classes in Python) • Applications • More local type inference / syntactic sugar • Dictionaries in statically-typed languages

  38. Thanks! D :: ravichugh.com/nested

  39. Extra Slides

  40. Constants

  41. Macros {|::} x:T1T2 x:T1T2 • Types • Formulas • Logical Values EqMod(d,d’,k)  Int has(d,k)  Str(x)  x.k  x[k]  {|tag()=“Int”} tag(x) = “Str” ∀k’. k’!=k sel(d,k)!=sel(d’,k) sel(d,k)!=bot sel(n,“k”) sel(n,k)

  42. Onto functional version of Dojo function 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) ∀A. callbacks:List[TopTop] f:{|=null Str()::ATop} obj:{|::A (f=null::AInt) (Str(f)[f]::AInt)} List[TopTop] onto ::

  43. Onto (2) functional version of Dojo function 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) callbacks:List[TopTop] *f:{g|g=null Str(g)g::{x|x=obj}Top} *obj:{o|(f=nullo::{x|x=o}Int) (Str(f)o[f]::{x|x=o}Int)} List[TopTop] onto ::

  44. Traditional vs. Nested Refinements

  45. Approach: Refinement Types • Reuse refinement type architecture • Find a decidable refinement logic for • Tag-tests • Dictionaries • Lambdas • Define nested refinement type architecture ✓ ✓ ✗ ✓*

  46. Nested Refinements • Refinement formulas over a decidable logic • uninterpreted functions, McCarthy arrays, linear arithmetic • Only base values refined by formulas All values T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | …| x :: U T ::= {|p} | x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … traditional refinements

  47. Nested Refinements • Refinement formulas over a decidable logic • uninterpreted functions, McCarthy arrays, linear arithmetic • Only base values refined by formulas • “has-type” allows “type terms” in formulas All values T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U T ::= {|p} | x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … traditional refinements

  48. Nested Refinements • Refinement formulas over a decidable logic • uninterpreted functions, McCarthy arrays, linear arithmetic • Only base values refined by formulas • “has-type” allows “type terms” in formulas All values T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

  49. Subtyping (Traditional Refinements) T ::= {|p} | x:T1T2 Subtyping traditional refinements tag()=“Int”true Implication Int <: Top SMT Solver

  50. Subtyping (Traditional Refinements) T ::= {|p} | x:T1T2 Subtyping traditional refinements tag()=“Int” true tag()=“Int” tag()=“Int” Implication SMT Solver Int <: Top Int <: Int Top  Int <: Int  Int

More Related