nestedrefinement...

Post on 31-May-2020

1 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Nested  Refinement  Types  for  JavaScript  

Ravi  Chugh  

Disserta/on  Defense  −  September  3,  2013  

Types  for  JavaScript  

“Dynamic”  or  Untyped  Features  Enable  Rapid  Prototyping  

2  

Types  for  JavaScript  

“Dynamic”  or  Untyped  Features  Enable  Rapid  Prototyping  

http://stackoverflow.com/tags02-­‐03-­‐13  

Count   Tag  

411,345   C#  

361,080   Java  

337,896   PHP  

321,757   JavaScript  

175,765   C++  

160,768   Python  

83,486   C  

64,345   Ruby  

9,827   Haskell  

1,347   OCaml  

3  

Types  for  JavaScript  

“Dynamic”  or  Untyped  Features  Enable  Rapid  Prototyping  

1.  Development  Tools  2.  Reliability  &  Security  

3.  Performance  

4  

1.  Development  Tools  

5  

op>onal  “type  systems”  unsound  but  provide  some  IDE  support    

2.  Reliability  &  Security  

6  

lightweight  sta>c  checkers  

run-­‐>me  invariant  checkers  

secure  language  subsets  

3.  Performance  

7  

fast  language  subset  to  facilitate  op/miza/ons  

Just-­‐In-­‐Time  (JIT)  engines  perform  sta/c/dynamic  analysis  to  predict  types  

8  

Types  for  JavaScript  

Why  So  Hard?  

9  

implicit  global  object  

scope  manipula/on  

JavaScript  

var  li]ing  

‘,,,’ == new Array(4)

“The  Good  Parts”  

objects  

reflec/on  

arrays  

eval()*  

lambdas  

JavaScript  

implicit  global  object  

scope  manipula/on  

var  li]ing  

‘,,,’ == new Array(4)

10  

“The  Good  Parts”  

objects  

reflec/on  

arrays  

eval()*  

lambdas  

JavaScript  

11  

12  Expressiveness  

Usability   Idioms  of  Dynamic  Languages  

Types  

Verifica>on  Hoare  Logics  

Model  Checking  Abstract  Interpreta/on  

Theorem  Proving  …  

+  Logic  

Thesis  Statement:  

“Refinement  types  can  reason  about  

dynamic  languages  to  verify  the  absence  of  run-­‐/me  errors  …  

13  Expressiveness  

Usability   Idioms  of  Dynamic  Languages  

Types  

Verifica>on  Hoare  Logics  

Model  Checking  Abstract  Interpreta/on  

Theorem  Proving  …  

+  Logic  

Thesis  Statement:  

…  without  resor/ng  to  undecidable  

logics”  

14  Expressiveness  

Usability   Idioms  of  Dynamic  Languages  

Types  

Verifica>on  Hoare  Logics  

Model  Checking  Abstract  Interpreta/on  

Theorem  Proving  …  

+  Logic  Dependent  

JavaScript  (DJS)  [POPL  2012,  OOPSLA  2012]  

Outline  

15  

Mo/va/on  and  Thesis  

Challenges  of  Dynamic  Languages  

Tour  of  Dependent  JavaScript  

Technical  Contribu/ons  

Evalua/on  

Looking  Ahead  

“The  Good  Parts”  

objects  

reflec/on  

arrays  

eval()*  

lambdas  

JavaScript  

16  

Core  Technical  Challenges  

reflec/on  

17  

objects  

Core  Technical  Challenges  

Java  JavaScript  

vs.  

18  

JavaScript  function negate(x) { if (typeof x == “number”) { return 0 - x; } else { return !x;} }

run-­‐/me  type-­‐test  

19  

JavaScript  function negate(x) { if (typeof x == “number”) { return 0 - x; } else { return !x;} }

but  boolean  on  else-­‐branch  

x  should  be  numeric  on  then-­‐branch…  

20  

JavaScript  function negate(x) { if (typeof x == “number”) { return 0 - x; } else { return !x;} }

Java  

✗  

21  

Java  interface NumOrBool { NumOrBool negate(); }class Bool implements NumOrBool { boolean data; Bool(boolean b) { this.data = b; } Bool negate() { return new Bool(!this.data); } }class Num implements NumOrBool { … }

declared  union  type  

22  

JavaScript  function negate(x) { if (typeof x == “number”) { … } else { …} }

Java  interface NumOrBool { NumOrBool negate(); }class Bool implements NumOrBool { boolean data; Bool(boolean b) { this.data = b; } Bool negate() { return new Bool(!this.data); } }class Num implements NumOrBool { … }

ad-­‐hoc  union  type  

declared  union  type  

23  

JavaScript  

ML,  Haskell  a  

function negate(x) { if (typeof x == “number”) { … } else { …} }

24  

datatype NumOrBool = | Num (n:number) | Bool (b:boolean)let negate x = match x with | Num n → Num (0 – n) | Bool b → Bool (!b)

declared  union  type  

ad-­‐hoc  union  type  

JavaScript  function negate(x) { if (typeof x == “number”) { … } else { …} }

Lightweight  Reflec>on

25  

ad-­‐hoc  union  type  

Java  class Person { String first; String last;

Person (String s1, String s2) { this.first = s1; this.last = s2; } void greeting(…) { … } }var john = new Person(“John”, “McCarthy”);var s = john.first + “…”;

var john = { “first” : “John”, “last” : “McCarthy”, “greeting” : … };

var s = john.first + “…”;

JavaScript  

field  names  are  declared  

keys  are  arbitrary  computed  strings    

26  

var john = { “first” : “John”, “last” : “McCarthy”, “greeting” : … };

var s = john.first + “…”;

JavaScript  

john[“first”]  

obj.f      means      obj[“f”]Objects  are  Dic>onaries

27  

Java  class Person { String first; String last;

Person (String s1, String s2) { this.first = s1; this.last = s2; } void greeting(…) { … } }var john = new Person(“John”, “McCarthy”);var s = john.first + “…”;

Java  class Person { String first; String last;

Person (String s1, String s2) { this.first = s1; this.last = s2; } void greeting(…) { … } }var john = new Person(“John”, “McCarthy”);var s = john.first + “…”;

var john = {};

john.first = “John”; john.last = “McCarthy”; john.greeting = …;

JavaScript  

incrementally  extend  object  

“sealed”  a]er  ini/aliza/on    

28  

var john = {};

john.first = “John”; john.last = “McCarthy”; john.greeting = …;

// much later in the code john.anotherKey = …;

addMoreKeys(john);

if (…) { addEvenMoreKeys(john); }

JavaScript  

Objects  are  Extensible29  

Java  class Person { String first; String last;

Person (String s1, String s2) { this.first = s1; this.last = s2; } void greeting(…) { … } }var john = new Person(“John”, “McCarthy”);var s = john.first + “…”;

Java  

30  

class Person { String first; String last;

Person (String s1, String s2) { this.first = s1; this.last = s2; } void greeting(…) { … } }var john = new Person(“John”, “McCarthy”);var s = john.first + “…”;class TuringWinner extends Person {

int year; TuringWinner (…) { … } }var twJohn = new TuringWinner(…);twJohn.greeting();

inherit  from  superclass  

Java  

31  

class Person { String first; String name;

Person (String s1, String s2) { this.first = s1; this.last = s2; } void greeting(…) { … } }var john = new Person(“John”, “McCarthy”);...... s = john.first + “…”;class TuringWinner extends Person {

int year; TuringWinner (…) { … } }var twJohn = new TuringWinner(…);twJohn.greeting();

inheritance  chain  declared  

JavaScript  

var john = { “first” : “John”, “last” : “McCarthy”, “greeting” : … };

var twJohn = { “year” : 1971, “__proto__” : john };

twJohn.greeting();

inheritance  chain  computed  

Objects  Inherit  from  Prototypes

var john = { “first” : “John”, “last” : “McCarthy”, “greeting” : … };

var twJohn = { “year” : 1971, “__proto__” : john };

twJohn.greeting();

JavaScript  

32  

Objects  Inherit  from  Prototypes

Objects  are  Extensible

Objects  are  Dic>onaries

Lightweight  Reflec>on

Core  Technical  Challenges  

33  

Refinement  Types  

Dependent  JavaScript  (DJS)  [POPL  ’12,  OOPSLA  ’12]  

C#  

✓  ✓  ✓  ✓  

✓  *  ✓  

✗  

✗  

✗  

✗  

✗  

✗  

Java  

Haskell  

Scala  

lightweight  reflec/on  

objects  are  dic/onaries  

objects  are  extensible  

prototype  inheritance  

34  

Outline  

35  

Mo/va/on  and  Thesis  

Challenges  of  Dynamic  Languages  

Tour  of  Dependent  JavaScript  

Technical  Contribu/ons  

Evalua/on  

Looking  Ahead  

36  

typeof true // “boolean”

typeof 0.1 // “number” typeof 0 // “number”

typeof {} // “object” typeof [] // “object” typeof null // “object”

37  

typeof  returns  run-­‐/me  “tags”  

Tags  are  very  coarse-­‐grained  types  

“undefined”

“boolean”  

“string”  

“number”  

“object”

“function”  

Refinement  Types  

38  

{ x | p }“set  of  values  x  s.t.  formula  p  is  true”  

{ n | tag(n) = “number” }Num ≡

{ v | tag(v) = “number” ∨ tag(v) = “boolean” }NumOrBool ≡

{ i | tag(i) = “number” ∧ integer(i) }Int ≡

{ x | true }Any ≡

39  

{ n | tag(n) = “number” }Num ≡

{ v | tag(v) = “number” ∨ tag(v) = “boolean” }NumOrBool ≡

{ i | tag(i) = “number” ∧ integer(i) }Int ≡

{ x | true }Any ≡

Syntac/c  Sugar  for  Common  Types  

Refinement  Types  

3 ::{ n | n = 3 } { n | n > 0 } 3 ::{ n | tag(n) = “number” ∧ integer(n) } 3 ::{ n | tag(n) = “number” } 3 ::

Refinement  Types  

40  

{ n | n = 3 } { n | n > 0 } { n | tag(n) = “number” ∧ integer(n) } { n | tag(n) = “number” }

<:⊆.  ⊆.  ⊆.  

Subtyping  is  Implica/on  

Refinement  Types  

41  

{ n | n = 3 } { n | n > 0 } { n | tag(n) = “number” ∧ integer(n) } { n | tag(n) = “number” }

⇒⇒⇒⇒

Subtyping  is  Implica/on  

Refinement  Types  

42  

Refinement  Types  

SMT  Solver  or  Theorem  

Prover  

Refinement  Type  

Checker  

p ⇒ q  ?

Yes  /  No  

43  

Subtyping  is  Implica/on  

44  

Mutable  Objects  Dic/onary  Objects  Tag-­‐Tests   Prototypes  

45  

Mutable  Objects  Dic/onary  Objects  Tag-­‐Tests   Prototypes  

function negate(x) { if (typeof x == “number”) { return 0 - x; } else { return !x;} }

Type  Annota>on  in  Comments  

//: negate :: (x:NumOrBool) → NumOrBool

{ v | tag(v) = “number” ∨ tag(v) = “boolean” }

NumOrBool ≡

Syntac>c  Sugar  for  Common  Types  

46  

Mutable  Objects  Dic/onary  Objects  Tag-­‐Tests   Prototypes  

function negate(x) { if (typeof x == “number”) { return 0 - x; } else { return !x;} }

//: negate :: (x:NumOrBool) → NumOrBool

{ x | tag(x) = “number” }

“expected  args”  

⊆   { x | tag(x) = “number” }

⇒{ x | tag(x) = “number” } { x | tag(x) = “number” }✓  

47  

Mutable  Objects  Dic/onary  Objects  Tag-­‐Tests   Prototypes  

function negate(x) { if (typeof x == “number”) { return 0 - x; } else { return !x;} }

//: negate :: (x:NumOrBool) → NumOrBool

“expected  args”  

⊆   { x | tag(x) = “boolean” }

✓  { x | not(tag(x) = “number”) { x | ∧ (tag(x) = “number” ∨{ x | tag(x) = “boolean”) }

48  

Mutable  Objects  Dic/onary  Objects  Tag-­‐Tests   Prototypes  

function negate(x) { if (typeof x == “number”) { return 0 - x; } else { return !x;} }

//: negate :: (x:NumOrBool) → NumOrBool✓  

Refinement  Types  Enable  Path  Sensi/vity  

49  

Mutable  Objects  Dic/onary  Objects  Tag-­‐Tests   Prototypes  

function negate(x) { if (typeof x == “number”) { return 0 - x; } else { return !x;} }

Output  type  depends  on  input  

value  

//: negate :: (x:NumOrBool) → { y|tag(y) = tag(x) }

✓  

50  

if (“quack” in duck) return “Duck says ” + duck.quack();else return “This duck can’t quack!”;

What  is  “Duck  Typing”?  

Mutable  Objects  Tag-­‐Tests   Dic/onary  Objects   Prototypes  

51  

if (“quack” in duck) return “Duck says ” + duck.quack();else return “This duck can’t quack!”;

What  is  “Duck  Typing”?  

(+) :: (Num,Num) → Num(+) :: (Str,Str) → Str

Mutable  Objects  Tag-­‐Tests   Dic/onary  Objects   Prototypes  

52  

if (“quack” in duck) return “Duck says ” + duck.quack();else return “This duck can’t quack!”;

What  is  “Duck  Typing”?  

Can  dynamically  test  the  presence  of  a  method  

but  not  its  type  

Mutable  Objects  Tag-­‐Tests   Dic/onary  Objects   Prototypes  

53  

if (“quack” in duck) return “Duck says ” + duck.quack();else return “This duck can’t quack!”;

{ d | tag(d) = “object” ∧ { v | has(d,“quack”) ⇒{ v | sel(d,“quack”) :: () → Str }

Operators  from  McCarthy  theory  of  arrays  

Mutable  Objects  Tag-­‐Tests   Dic/onary  Objects   Prototypes  

54  

if (“quack” in duck) return “Duck says ” + duck.quack();else return “This duck can’t quack!”;

{ d | tag(d) = “object” ∧ { v | has(d,“quack”) ⇒{ v | sel(d,“quack”) :: () → Str }

Call  produces  Str,  so  concat  well-­‐typed  

✓  

Mutable  Objects  Tag-­‐Tests   Dic/onary  Objects   Prototypes  

55  

var x = {};x.f = 7;x.f + 2;

x0:Empty

x1:{d|d = upd(x0,“f”,7)}

DJS  is  Flow  Sensi/ve  

McCarthy  operator  DJS  verifies  that  x.f  is  definitely  a  number  

Dic/onary  Objects  Tag-­‐Tests   Mutable  Objects   Prototypes  

56  

var x = {};x.f = 7;x.f + 2;

x0:Empty

x1:{d|d = upd(x0,“f”,7)}

DJS  is  Flow  Sensi/ve  

Strong  updates  to  singleton  objects  

Weak  updates  to  collec/ons  of  objects  

Dic/onary  Objects  Tag-­‐Tests   Mutable  Objects   Prototypes  

child

parent

...

grandpa

null

Upon  construc/on,  each  object  links  to  a  prototype  object  

57  

Dic/onary  Objects  Tag-­‐Tests   Prototypes  Mutable  Objects  

If  child  contains  k,  then          Read  k  from  child

Else  if  parent  contains  k,  then          Read  k  from  parent

Else  if  grandpa  contains  k,  then          Read  k  from  grandpa

Else  if  …  

Else          Return  undefined

child

parent

...

grandpa

null

var k = “first”; child[k];Seman/cs  of  Key  Lookup  

58  

Dic/onary  Objects  Tag-­‐Tests   Prototypes  Mutable  Objects  

...

child

parent

grandpa

null

H  

(Rest  of  Heap)  

var k = “first”; child[k];Seman/cs  of  Key  Lookup  

If  child  contains  k,  then          Read  k  from  child

Else  if  parent  contains  k,  then          Read  k  from  parent

Else  if  grandpa  contains  k,  then          Read  k  from  grandpa

Else  if  …  

Else          Return  undefined

{ v | if has(child,k) then{ v | ifv = sel(child,k)

59  

Dic/onary  Objects  Tag-­‐Tests   Prototypes  Mutable  Objects  

...

child

parent

grandpa

null

H  

(Rest  of  Heap)  

var k = “first”; child[k];Seman/cs  of  Key  Lookup  

If  child  contains  k,  then          Read  k  from  child

Else  if  parent  contains  k,  then          Read  k  from  parent

Else  if  grandpa  contains  k,  then          Read  k  from  grandpa

Else  if  …  

Else          Return  undefined

{ v | if has(child,k) then{ v | ifv = sel(child,k)

{ v | else if has(parent,k) then{ v | ifv = sel(parent,k)

60  

Dic/onary  Objects  Tag-­‐Tests   Prototypes  Mutable  Objects  

If  child  contains  k,  then          Read  k  from  child

Else  if  parent  contains  k,  then          Read  k  from  parent

Else  if  grandpa  contains  k,  then          Read  k  from  grandpa

Else  if  …  

Else          Return  undefined

...

{ v | if has(child,k) then{ v | ifv = sel(child,k)

{ v | else if has(parent,k) then{ v | ifv = sel(parent,k)

child

parent

grandpa ???

null

H  

(Rest  of  Heap)  

var k = “first”; child[k];Seman/cs  of  Key  Lookup  

61  

Dic/onary  Objects  Tag-­‐Tests   Prototypes  Mutable  Objects  

...

{ v | if has(child,k) then{ v | ifv = sel(child,k)

{ v | else if has(parent,k) then{ v | ifv = sel(parent,k)

{ v | else{ v | ifv = HeapSel(H,grandpa,k)) }

child

parent

grandpa ???

null

H  

(Rest  of  Heap)  

var k = “first”; child[k];Seman/cs  of  Key  Lookup  

Abstract  predicate  to  summarize  the  unknown  por>on  

of  the  prototype  chain  

62  

Dic/onary  Objects  Tag-­‐Tests   Prototypes  Mutable  Objects  

...

{ v | if has(child,k) then{ v | ifv = sel(child,k)

{ v | else if has(parent,k) then{ v | ifv = sel(parent,k)

{ v | else{ v | ifv = HeapSel(H,grandpa,k)) }

{ “first” : “John” }child

parent { “first” : “Ida” , “last” : “McCarthy” }

grandpa ???

null

H  

(Rest  of  Heap)  

<:

{ v | v = “John” }

var k = “first”; child[k];

63  

Dic/onary  Objects  Tag-­‐Tests   Prototypes  Mutable  Objects  

...

{ v | if has(child,k) then{ v | ifv = sel(child,k)

{ v | else if has(parent,k) then{ v | ifv = sel(parent,k)

{ v | else{ v | ifv = HeapSel(H,grandpa,k)) }

{ “first” : “John” }child

parent { “first” : “Ida” , “last” : “McCarthy” }

grandpa ???

null

H  

(Rest  of  Heap)  

var k = “last”; child[k];

<:

{ v | v = “McCarthy” }

64  

Dic/onary  Objects  Tag-­‐Tests   Prototypes  Mutable  Objects  

Key  Idea:  

Reduce  prototype  seman/cs  to  decidable  

theory  of  arrays  

Prototype  Chain  Unrolling  

65  

Dic/onary  Objects  Tag-­‐Tests   Prototypes  Mutable  Objects  

“The  Good  Parts”  

reflec/on  

arrays  

eval()*  

lambdas  

JavaScript  

66  

objects  

✓  ✓  

✓  

EXTRA  SLIDES  

Outline  

67  

Mo/va/on  and  Thesis  

Challenges  of  Dynamic  Languages  

Tour  of  Dependent  JavaScript  

Technical  Contribu/ons  

Evalua/on  

Looking  Ahead  

lambdas  dic/onaries  

tag  tests  

muta/on  

prototypes  

68  

Transla/on  à  la  Guha  et  al.  (ECOOP  2010)  

Dependent  JavaScript  (DJS)  

Our  Strategy:  

Build  an  expressive  type  system  for  core  language  

69  

lambdas  dic/onaries  

tag  tests  

muta/on  

prototypes  

(POPL  2012)  

(OOPSLA  2012)  

System  D  

System  !D  

System  DJS   (OOPSLA  2012)  

Dependent  JavaScript  (DJS)  Dependent  JavaScript  (DJS)  

Prior  Refinement  Types  

70  

Types  

T ::= { x:B | p } | x:T1 → T2 | [ f1:T1; … ] | Map[A,B] | Ref(T)

base  type  (e.g.  Int,  Bool,  Str)  dependent  func/on  type  

object  type  (a.k.a.  record,  struct)  

dic/onary  type  (a.k.a.  map,  hash  table)  

reference  type  (a.k.a.  pointer)  

Predicates  refine  only  base  types  

71  

Prior  Refinement  

Types  

C#  System  DJS  

✓  ✓  ✓  ✓  

✓  *  ✓  

✗  

✗  

✗  

✗  

✗  

✗  

Java  

Haskell  

Scala  

lightweight  reflec/on  

objects  are  dic/onaries  

objects  are  extensible  

prototype  inheritance  

72  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

*  ✓  ✗  

✗  

objects  are  dic/onaries  

objects  are  extensible  

prototype  inheritance  

✓  ✓  ✓  

73  

Key  Challenge:  

Func/on  Subtyping  as  Logical  Implica/on  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

74  

42 + negate (17)

⊆   { f | f :: }(x:Num) → Num “expected  func/on”  

{ f | f :: } (x:NumOrBool) → { y|tag(y) = tag(x) }

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

{ f | f :: }

75  

(x:NumOrBool) → { y|tag(y) = tag(x) }

{ f | f :: }(x:Num) → Num⇒

How  to  Prove  

?  How  to  Encode  Type  System  Inside  Logic?  

Prior  Refinement  Systems  Disallow  Func/on  Types  Inside  Logic!  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

76  

T ::= { x | p } | T1 → T2

Types   Refinement  Logic  

Sa/sfiability  Modulo  Theories  (SMT)  

SAT  +  Decidable  Theories  

p ⇒ q ✓  

✗  SMT  Solver  (e.g.  Z3)  

[Prior  State-­‐of-­‐the-­‐Art]  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

77  

T ::= { x | p } | T1 → T2

p ::= p ∧ q | p ∨ q | ¬p | x = y | x > y | … | tag(x) = “number” | … | sel(x,k) = 17 | …

Types   Refinement  Logic  

•   Boolean  Connec/ves  •   Equality  •   Linear  Arithme/c  •   Uninterpreted  Func/ons  •   McCarthy  Arrays  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

78  

T ::= { x | p } | T1 → T2

p ::= p ∧ q | p ∨ q | ¬p | x = y | x > y | … | tag(x) = “number” | … | sel(x,k) = 17 | …

Types   Refinement  Logic  

{ v | tag(v) = “number” ∨ tag(v) = “boolean” }NumOrBool ≡

Enables  Union  Types  and  Lightweight  Reflec>on  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

79  

T ::= { x | p } | T1 → T2

p ::= p ∧ q | p ∨ q | ¬p | x = y | x > y | … | tag(x) = “number” | … | sel(x,k) = 17 | …

Types   Refinement  Logic  

Enables  Dic>onary  Types  with  Dynamic  Keys  …  

{ d | tag(sel(d,k)) = “boolean” ∧

{ d | tag(sel(d,“f”)) = “function” ∧

{ d | sel(d,“f”) ??? }

But  Disallows  Func/ons  in  Dic/onaries!  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

80  

p ::= p ∧ q | p ∨ q | ¬p | x = y | x > y | … | tag(x) = “number” | … | sel(x,k) = 17 | … | sel(x,k) :: T1 → T2 | …

Types   Refinement  Logic  

Goal:  Refer  to  Type  System  Inside  Logic  Goal:  Without  Giving  up  Decidability  

T ::= { x | p } | T1 → T2

Solu/on:  Nested  Refinements!  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

81  

T ::= { x | p } p ::= p ∧ q | p ∨ q | ¬p | x = y | x > y | … | tag(x) = “number” | … | sel(x,k) = 17 | … | sel(x,k) :: T1 → T2 | …

Nested  Refinements  [POPL  ’12]  1.    Decidable  Encoding  2.    Precise  Subtyping  3.    Type  Soundness  Proof  

Types   Refinement  Logic  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

82  

{ f | f :: } (x:NumOrBool) → { y|tag(y) = tag(x) }

{ f | f :: }(x:Num) → Num⇒

Decidable  Encoding  

Uninterpreted  Predicate  in  Logic  

Dis/nct  Uninterpreted  Constants  in  Logic…  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

{ f | f :: }

83  

(x:NumOrBool) → { y|tag(y) = tag(x) }

{ f | f :: }(x:Num) → Num⇒

Decidable  Encoding  

Uninterpreted  Predicate  in  Logic  

w/  Types  Nested  Inside  

Dis/nct  Uninterpreted  Constants  in  Logic…  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

84  

Decidable  Encoding  

{ f | f :: } (x:NumOrBool) → { y|tag(y) = tag(x) }

{ f | f :: }(x:Num) → Num⇒

✗  SMT  Solver  

Trivially  Decidable,  but  Imprecise  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

p ⇒ f ::(x:S1) → S2

85  

⊆   { f | f :: }(x:T1) → T2{ f | p }

Precise  Subtyping  

Step  1:  

Step  2:  

Find                                                  such  that  (x:S1) → S2

SMT  Solver  ✓  

T1 S1⊆   ✓  ✓  S2 T2⊆  x:T1 ∧

Compare                                                and  (x:S1) → S2 (x:T1) → T2

✓  

“contra-­‐variance”  

“co-­‐variance”  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

86  

⊆   { f | f :: }(x:Num) → Num{ f | f = negate }

Precise  Subtyping  

Step  1:  

Step  2:  

f = negate ⇒ f ::(x:NumOrBool) → { y|tag(y) = tag(x) }SMT  

Solver  ✓  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

87  

⊆   { f | f :: }(x:Num) → Num{ f | f = negate }

Precise  Subtyping  

Step  1:  

Step  2:  

f = negate ⇒ f ::(x:NumOrBool) → { y|tag(y) = tag(x) }

Num NumOrBool⊆   ✓  ✓  { y | tag(y) = tag(x) } Num⊆  x:Num ∧

✓  SMT  Solver  ✓  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

88  

Precise  Subtyping  

Step  1:  

Step  2:  

Decidable  Reasoning  via  SMT  

Precise  Func/on  Subtyping  via  Syntac/c  Techniques  

+  

⊆   { f | f :: }{ f | f = negate } ✓  (x:Num) → Num

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

89  

Type  Soundness  Proof  

Logic  0  

Conven/onal  Proofs  Require  Logic  to  be  an  Oracle  …  

…  but  Nes/ng  Introduces  Circularity  That  Prevents  Typical  Induc/ve  Proofs  

Type  System  0  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

Type  System  ∞  

90  

Type  Soundness  Proof  

Logic  0  

Logic  1  

Logic  2  

Type  System  1  

Type  System  2  

Type  System  0  

…   …  

Proof  Technique:  Stra>fy  into  Infinite  Hierarchy  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

91  

Key  to  Encode  Dic/onary  Objects  (Even  in  Sta/cally  Typed  Languages!)  

T ::= { x | p } p ::= p ∧ q | p ∨ q | ¬p | x = y | x > y | … | tag(x) = “number” | … | sel(x,k) = 17 | … | sel(x,k) :: T1 → T2 | …

Nested  Refinements  [POPL  ’12]  

Types   Refinement  Logic  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

92  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

var x = {};x.f = 7;x.f + 2;

let x = new {} in

(*x).f = 7;

(*x).f + 2;

Allocates  ptr  x :: Ref(Dict)    

Heap  update  doesn’t  affect  type    

So  key  lookup  doesn’t  type  check!    

Key  Issue:  

“Invariant”  Reference  Types  

93  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

let x = new {} in

(*x).f = 7;

(*x).f + 2;

Lx |-> d0:{d|d =empty}

Lx |-> d1:{d|d = upd(d0,“f”,7)}

Allocates  heap  loca>on  Lx  and  x :: Ref(Lx)Type  of  pointer  doesn’t  change  …  

But  types  of  heap  loca/ons  can!    

✓  

94  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

x:T1 / h1 → T2 / h2

output  type  

input  type  

95  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

x:T1 / h1 → T2 / h2

output  type  

input  type  

input  heap  

output  heap  

96  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

x:T1 / h1 → T2 / h2Our  Formula/on  Extends:  

  Alias  Types  (Smith  et  al.,  ESOP  2000)     syntac>c  types  for  higher-­‐order  programs  

      Low-­‐Level  Liquid  Types  (Rondon  et  al.,  POPL  2010)     refinement  types  for  first-­‐order  programs  

97  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

let swap (x, y) = let tmp = *x in *x = *y; *y = tmp in …

//: swap :: (x:Ref(Lx), y:Ref(Ly))//: / H + (Lx |-> a:Any) + (Ly |-> b:Any) //: → Void//: / H + (Lx |-> a’:Any{a’= b})//: + (Ly |-> b’:Any{b’= a})

98  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

//: getKey :: (x:Ref(Lx), k:Str)//: / H + (Lx |-> d:Dict > Lx’) //: → { y | if has(d,k)//: then y = sel(d, k)//: else y = HeapHas(H, Lx’, k)}//: / H + (Lx |-> d’:Dict{d’= d} > Lx’)

Prototype  Inheritance  

x[k] getKey(*x, k)

99  

JavaScript  Encodings  Flow-­‐Sensi/ve  Refinements  Nested  Refinements  

Primi>ve  Operators  (Avoid  Implicit  Coercion)  

JavaScript  Arrays  (Several  Unusual  Issues)  

Prototype  Inheritance  

Outline  

100  

Mo/va/on  and  Thesis  

Challenges  of  Dynamic  Languages  

Tour  of  Dependent  JavaScript  

Technical  Contribu/ons  

Evalua/on  

Looking  Ahead  

101  

313  

a  

421  

(+35%)  

LOC  before/a]er  

14  Excerpts  from:        JavaScript,  Good  Parts        SunSpider  Benchmark  Suite        Google  Closure  Library  

Benchmarks  

Chosen  to  Stretch  the  Limits  of  DJS  

102  

313  

a  

421  

(+35%)  

LOC  before/a]er  

14  Excerpts  from:        JavaScript,  Good  Parts        SunSpider  Benchmark  Suite        Google  Closure  Library  

Benchmarks  

9  Browser  Extensions  from:        [Guha  et  al.  Oakland  ’11]      

321  

a  

383  

(+19%)  

1,003  

a  

1,027  

(+2%)  2  Examples  from:        Google  Gadgets  

1,637   1,831  

(+12%)  TOTALS  

103  

LOC  before/a]er  

14  Excerpts  from:        JavaScript,  Good  Parts        SunSpider  Benchmark  Suite        Google  Closure  Library  

313  

a  

421  

(+35%)  

Benchmarks  

9  Browser  Extensions  from:        [Guha  et  al.  Oakland  ’11]      

321  

a  

383  

(+19%)  

2  Examples  from:        Google  Gadgets  

1,003  

a  

1,027  

(+2%)  

1,637   1,831  

(+12%)  

11  sec  

Running  Time  

3  sec  

19  sec  

33  sec  TOTALS   1,831  

(+12%)  

33  sec  

>>> Skip Optimizations >>>

Reducing  Annota>on  Burden  •  Bidirec/onal  (local)  type  inference  – Several  aspects  unique  to  this  sezng  

•  Op/onal  var  declara/on  invariants  – Auto  add  to  types  of  subsequent  closures  

104  

var i /*: Int */ = 0;…//: f :: T1 / H1 + (Li |-> i1:Int) //: → T2 / H2 + (Li |-> i2:Int)var f(…) { … i … }

func/on  refers  to  mutable  variable  i,  so  heaps  must  describe  

the  loca/on

Reducing  Annota>on  Burden  •  Bidirec/onal  (local)  type  inference  – Several  aspects  unique  to  this  sezng  

•  Op/onal  var  declara/on  invariants  – Auto  add  to  types  of  subsequent  closures  

105  

var i /*: Int */ = 0;…//: f :: T1 / H1//: → T2 / H2var f(…) { … i … }

copy  the  annota/on,  if  any  

Reducing  Annota>on  Burden  •  Bidirec/onal  (local)  type  inference  – Several  aspects  unique  to  this  sezng  

•  Op/onal  var  declara/on  invariants  – Auto  add  to  types  of  subsequent  closures  

106  

var i /*: Int */ = 0;…//: f :: T1 / H1 + (Li |-> i1:Int) //: → T2 / H2 + (Li |-> i2:Int)var f(…) { … i … }

copy  the  annota/on,  if  any  

Reducing  Annota>on  Burden  •  Bidirec/onal  (local)  type  inference  – Several  aspects  unique  to  this  sezng  

•  Op/onal  var  declara/on  invariants  – Auto  add  to  types  of  subsequent  closures  

107  

no  annota/on  means  “do  not  modify”  var i = 0;…//: f :: T1 / H1 + (Li |-> i1:{x | x = 0}) //: → T2 / H2 + (Li |-> i2:{x | x = 0})var f(…) { … i … }

Improving  Performance  

108  

17 :: { x:Int | x = 17 }

if b then “hi” else 17 :: { x | b = true ⇒ x = “hi”if b then 17 else “hi” :: { x ∧ b = false ⇒ x = 17 }

track  syntac>c  types  for  specialized  cases  …  

…  fall  back  on  refinement  types  for  general  case

•  Avoid  making  SMT  queries  when  possible  

Improving  Performance  •  Can  reduce  precision  for  if-­‐expressions  

109  

var n = 0;if (b) { n = n + 1;else { n = n + 2;}

Ln |-> m:{ x | b = true ⇒ x = 1Ln |-> m: {x ∧ b = false ⇒ x = 2 }

“exact  joins”  by  default  …

…  annota/on  on  var  triggers  “inexact  joins”

Improving  Performance  •  Can  reduce  precision  for  if-­‐expressions  

110  

var n /*: Int */ = 0;if (b) { n = n + 1;else { n = n + 2;}

Ln |-> m:Int

“exact  joins”  by  default  …

…  annota/on  on  var  triggers  “inexact  joins”

111  

Plenty  of  Room  for  Improvement  

1,637  TOTALS   33  sec  1,831  

(+12%)  

Rela/vely  Modest  Op/miza/ons  Have  Made  Significant  Impact  

Outline  

112  

Mo/va/on  and  Thesis  

Challenges  of  Dynamic  Languages  

Tour  of  Dependent  JavaScript  

Technical  Contribu/ons  

Evalua/on  

Looking  Ahead  

Immediate  Direc>ons  

• Type  Soundness  –   proven  for  System  D,  but  not  for  !D  or  DJS  

• Expressiveness  –   e.g.  mutual  recursion,  recursion  through  heap  

• Usability  –   annota/on  burden,  performance,  error  messages  

• Integra/on  with  Run-­‐Time  Contracts  –   invariants  before  and  a]er  eval()

113  

114  

Expressiveness  

Usability  

Verifica>on  

Dependent  JavaScript  (DJS)  

TypeScript  Lightweight  (unsound)  sta/c  checking  tools  becoming  popular  

Translate  for  addi/onal  checking  and  IDE  support  

“Gradual  Gradual  Typing”  

115  

Way  Behind  Tools  for  Java,  etc.  

•   Sta/c  Types  in  DJS  Enable  Refactoring,  •   Documenta/on  Tools,  Code  Comple/on  

•   Web-­‐Based  Interfaces  to  Collect  Sta>s>cs  •   about  Programming  Pa{erns,  Errors  

Web  Development  Tools  

candidate  annota/ons  

User  or  

Test  Cases  or  

Heuris>cs  

116  

Itera>ve  Inference  Global  inference  (e.g.  via  Liquid  Types)  would  be  nice,  but  no  basic  type  structure  to  start  with  

unannotated  program  

✓  

✗  

Verifica>on  Condi>on  Genera>on  

Coarsen  Types  

117  

Browser  Extension  Security  

Security  =  Refinement  

Type  Checking  à  la  Swamy  et  al.  (ESOP  2010)  and  Guha  et  al.  (Oakland  2011)  

Dependent  JavaScript  (DJS)  

Third-­‐Party  Code  

Policy  

Browser  APIs  

Secure  Reference  Monitor  via  Refinements  

Thanks!  

118  

Nested  Refinements  +  Dependent  JavaScript  

Ranjit  Jhala  Pat  Rondon  Dave  Herman  Panos  Vekris  

Other  Projects  

Sorin  Lerner  Jan  Voung  Jeff  Meister  Nikhil  Swamy  Juan  Chen  

119  

EXTRA  SLIDES  

“The  Good  Parts”  

reflec/on  

arrays  

eval()*  

lambdas  

JavaScript  

120  

objects  

121  

var nums = [0,1,2];while (…) { nums[nums.length] = 17;}

A  finite  tuple…  

…  extended  to  unbounded  collec/on  

122  

var nums = [0,1,2];while (…) { nums[nums.length] = 17;}

delete nums[1];

for (i = 0; i < nums.length; i++) { sum += nums[i]; }

A  “hole”  in  the  array  

Missing  element  within  “length”  

123  

Track  types,  “packedness,”  and  length  of  arrays  where  possible  

{ a | a :: Arr(T) { a |∧ packed(a)

{ a |∧ len(a) = 10 }

X   T   T   T   T  …   X   …  …  

T?   T?   T?   T?   T?  …   T?   …  …  

T? ≡ { x | T(x) ∨ x = undefined }

-­‐1   0   1   2   len(a)  

X ≡ { x | x = undefined }

124  

{ a | a :: Arr(Any) { a | ∧ packed(a) ∧ len(a) = 2

{ a | ∧ Int(sel(a,0)) { a | ∧ Str(sel(a,1)) }

Encode  tuples  as  arrays  

var tup = [17, “cacti”];

125  

var tup = [17, “cacti”];tup[tup.length] = true;

{ a | a :: Arr(Any) { a | ∧ packed(a) ∧ len(a) = 3

{ a | ∧ … }

“The  Good  Parts”  

reflec/on  

arrays  

eval()*  

lambdas  

JavaScript  

126  

objects  

What  About  eval?  

127  

Arbitrary  code  loading  

eval(“…”);

Old  Types  

What  About  eval?  

128  

eval(“…”);//: #assume …

Old  Types  

New  Types  New  Types  

Future  Work:  Integrate  DJS  with  “Contract  Checking”  at  Run-­‐/me  

aka  “Gradual  Typing”  

129  Expressiveness  

Usability   Idioms  of  Dynamic  Languages  

Verifica>on  Hoare  Logics  

Model  Checking  Abstract  Interpreta/on  

Theorem  Proving  …  

Func/on  Subtyping…  

130  

{ d | sel(d,“f”) :: } (x:Any) → { y|y = x }{ d | sel(d,“f”) :: }(x:Num) → Num<:

Higher-­‐Order  Refinements  

Func/on  Subtyping…  

131  

{ d | sel(d,“f”) :: }(x:Num) → Num{ d | sel(d,“f”) :: } (x:Any) → { y|y = x }

Higher-­‐Order  Refinements  

Func/on  Subtyping…  

132  

{ d | sel(d,“”)f :: }(x:Num) → Num{ d | sel(d,“ ”f :: } (x:Any) → { y|y = x }

…  With  Quan/fiers  ∀x,y. true ∧ y = f(x) ⇒ y = x

∀x,y. Num(x) ∧ y = f(x) ⇒ Num(y)✓  Valid,  but  First-­‐Order  Logic  is  Undecidable  

Higher-­‐Order  Refinements  

133  

Heap  Updates…  

…  With  Quan/fiers  

var x = {};x.f = 7; h1

h2

h0

∧ …

∧ sel(h1,x) = empty ∧ ∀y. x ≠ y ⇒ sel(h1,y) = sel(h0,y)

∧ sel(h2,x) = upd(sel(h1,x),“f”,7) ∧ ∀y. x ≠ y ⇒ sel(h2,y) = sel(h1,y)

Encode  Heap  w/  McCarthy  Operators  

Higher-­‐Order  Refinements  

Subtyping  with  Nes>ng  

134  

e.g.  tag(x) = tag(y)

e.g.  tag(sel(d,k)) = “number”

1)  Convert  q  to  CNF  clauses  (q11 ∨ … ) ∧ … ∧ (qn1 ∨ … )2)  For  each  clause,  discharge  some  literal  qij as  follows:

base  predicate: p  ⇒  qij

anything  except  HasType(x,U)

Subtyping  with  Nes>ng  

135  

Implica/on  

SMT  Solver  

Subtyping   Arrow  Rule  

base  predicate: p  ⇒  qij p  ⇒  x :: U  

Implica/on  

SMT  Solver  

Subtyping  

p  ⇒  x :: U’  

U’  <:  U

p  ⇒  qij  

1)  Convert  q  to  CNF  clauses  (q11 ∨ … ) ∧ … ∧ (qn1 ∨ … )2)  For  each  clause,  discharge  some  literal  qij as  follows:

Type  Soundness  with  Nes>ng  

136  

137  

0 ::    { ν | λx.x+1 :: Int → Int }_  |  

λx.x+1 ::    { ν | ν :: Int → Int }_  |  

f:{ ν | ν :: Int → Int } 0 ::    { ν | f :: Int → Int }_  |  

Subs/tu/on  Lemma  

_  |   v :: Txand  If   x:Tx, Γ e[::    T_  |  

Γ[v/x] e[v/x] ::    T[v/x]_  |  then  

independent  of  0,  and  just  echoes  the  binding  from  the  environment  

138  

0 ::    { ν | λx.x+1 :: Int → Int }_  |  

SMT   ν = 0 ⇒ λx.x+1 :: Int → Int✗  

{ ν | ν = 0 } <    { ν | λx.x+1 :: Int → Int }0 ::    { ν | ν = 0 }

Subs/tu/on  Lemma  

_  |   v :: Txand  If   x:Tx, Γ e[::    T_  |  

Γ[v/x] e[v/x] ::    T[v/x]_  |  then  

1st  a{empt  

139  

0 ::    { ν | λx.x+1 :: Int → Int }_  |  

{ ν | ν = 0 } <    { ν | λx.x+1 :: Int → Int }0 ::    { ν | ν = 0 }

Subs/tu/on  Lemma  

_  |   v :: Txand  If   x:Tx, Γ e[::    T_  |  

Γ[v/x] e[v/x] ::    T[v/x]_  |  then  ✗  SMT   ν = 0 ⇒ ν :: U’

Arrow   U’ <:    Int → Int

+2nd  a{empt  ✗  

140  

λx.x+1 :: Int → Int|=I

λx.x+1 :: { ν | ν :: Int → Int }|_  

SMT   Γ ∧ p ⇒ q

Γ { ν | ν = p } <    { ν | ν = q }_  |  

[S-­‐Valid-­‐Uninterpreted]  

|=I Γ ∧ p ⇒ q

Γ { ν | ν = p } <    { ν | ν = q }_  |  

[S-­‐Valid-­‐Interpreted]  

iff  

•  Rule  not  closed  under  subs/tu/on  

•  Interpret  formulas  by  “hooking  back”  into  type  system  

•  Stra/fica/on  to  create  ordering  for  induc/on  

n

n-1

n

n

Type  Soundness  with  Nes>ng  

141  

Stra/fied  Subs/tu/on  Lemma  

_  |   v :: Txand  If   x:Tx, Γ e[::    T_  |  

Γ[v/x] e[v/x] ::    T[v/x]_  |  then   n+1

nn

Stra/fied  Preserva/on  

e vand  If   e[::    T_  |   0_  |  then   v[::    Tm for  some  m  

“Level  0”  for  type  checking  source  programs,  

using  only  [S-­‐Valid-­‐Uninterpreted]  

ar/fact  of  the  metatheory  

142  

</Ph.D.>  

top related