Refinement Types for TypeScript Panagiotis Vekris

Published  . 0 views
↓ Download
Refinement Types for TypeScript Panagiotis Vekris
1 / 1
Refinement Types for TypeScript Panagiotis Vekris - slide 1 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 2 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 3 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 4 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 5 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 6 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 7 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 8 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 9 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 10 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 11 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 12 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 13 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 14 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 15 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 16 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 17 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 18 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 19 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 20 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 21 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 22 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 23 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 24 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 25 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 26 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 27 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 28 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 29 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 30 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 31 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 32 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 33 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 34 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 35 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 36 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 37 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 38 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 39 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 40 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 41 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 42 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 43 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 44 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 45 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 46 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 47 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 48 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 49 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 50 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 51 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 52 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 53 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 54 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 55 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 56 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 57 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 58 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 59 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 60 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 61 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 62 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 63 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 64 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 65 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 66 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 67 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 68 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 69 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 70 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 71 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 72 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 73 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 74 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 75 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 76 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 77 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 78 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 79 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 80 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 81 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 82 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 83 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 84 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 85 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 86 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 87 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 88 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 89 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 90 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 91 of 92 Refinement Types for TypeScript Panagiotis Vekris - slide 92 of 92
Description: Refinement Types for TypeScript Panagiotis Vekris Benjamin Cosman Ranjit Jhala University of California, San Diego PLDI16 Thursday, June 16 2 Extensible static analyses for modern scripting languages 3 Extensible static analyses for modern

Related Topics

Download Presentation

"Refinement Types for TypeScript Panagiotis Vekris" is the property of its rightful owner. Permission is granted to download and print the materials on this website for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.

Presentation Transcript

slide1. Refinement Types for TypeScript Panagiotis Vekris Benjamin Cosman Ranjit Jhala University of California, San Diego PLDI’16
Thursday, June 16<br>
slide2. 2 Extensible static analyses for modern scripting languages<br>
slide3. 3 Extensible static analyses for modern scripting languages Higher Order Functions Wide scale PL Interest Object Oriented Looks like Compiles to Generics Optionally Typed<br>
slide4. 4 Extensible static analyses for modern scripting languages Verification Documentation TS No runtime overhead<br>
slide5. 5 Extensible static analyses for modern scripting languages typeof x === 'string'
x === null assert (shape.tag & Circle) User specified invariants Fixed type tests assert (user.auth()) assert (i < a.length)<br>
slide6. Example
Compute the index of the minimum element of an array 6<br>
slide7. reduce folds over the elements of an array function reduce(a, f, x) {
var res = x;
for (var i = 0; i < a.length; i++)
res = f(res, a[i], i);
return res;
} 7<br>
slide8. Calls reduce with an appropriate step function and initialization function reduce(a, f, x) {
var res = x;
for (var i = 0; i < a.length; i++)
res = f(res, a[i], i);
return res;
}

function minIndex(a) {
if (a.length <= 0) return -1;
function step(min, cur, i) {
return cur < a [ min ] ? i : min;
}
return reduce(a, step, 0);
} 8<br>
slide9. Verification goal
Prove that all array accesses are within bounds Example
Compute the index of the minimum element of an array 9<br>
slide10. function reduce(a, f, x) {
var res = x;
for (var i = 0; i < a.length; i++)
res = f(res, a[i], i);
return res;
}

function minIndex(a) {
if (a.length <= 0) return -1;
function step(min, cur, i) {
return cur < a [ min ] ? i : min;
}
return reduce(a, step, 0);
} Array bounds analysis:
0 ≤ min < len a 10<br>
slide11. function reduce(a, f, x) {
var res = x;
for (var i = 0; i < a.length; i++)
res = f(res, a[i], i);
return res;
}

function minIndex(a) {
if (a.length <= 0) return -1;
function step(min, cur, i) {
return cur < a [ min ] ? i : min;
}
return reduce(a, step, 0);
} Array bounds analysis:
0 ≤ min < len a Constraint between two values 11<br>
slide12. function reduce(a, f, x) {
var res = x;
for (var i = 0; i < a.length; i++)
res = f(res, a[i], i);
return res;
}

function minIndex(a) {
if (a.length <= 0) return -1;
function step(min, cur, i) {
return cur < a [ min ] ? i : min;
}
return reduce(a, step, 0);
} Constraint between two values 12 Array bounds analysis:
0 ≤ min < len a Constraint between value and closure<br>
slide13. function reduce(a, f, x) {
var res = x;
for (var i = 0; i < a.length; i++)
res = f(res, a[i], i);
return res;
}

function minIndex(a) {
if (a.length <= 0) return -1;
function step(min, cur, i) {
return cur < a [ min ] ? i : min;
}
return reduce(a, step, 0);
} Constraint carries over through call to function parameters Constraint between value and closure 13<br>
slide14. function reduce(a, f, x) {
var res = x;
for (var i = 0; i < a.length; i++)
res = f(res, a[i], i);
return res;
} Constraint carries over through call to function parameters 14 Problem
To check array access we must track
relations between closures and values Solution
Refinement types<br>
slide15. Refinement Types { v: b | p } “Set of values v of type b such that formula p is true” Value variable Base type Logical predicate E.g.: { v: number | 0 ≤ v  v < len a }
“Set of valid indexes for an array a” 15<br>
slide16. function reduce(a, f, x) { ... } How can we type reduce? Acc Basic typing offers some guarantees 16<br>
slide17. function reduce<A,B>(a: A[ ], f: (B, A, number) => B, x: B): B { ... } function reduce(a, f, x) { ... } TypeScript type How can we type reduce? Does not capture:
“valid index of a” Basic typing offers some guarantees
but not value related ones a 17<br>
slide18. function reduce<A,B>(a: A[ ], f: (B, A, number) => B, x: B): B { ... } function reduce(a, f, x) { ... } TypeScript type How can we type reduce to account for valid indexes? 18<br>
slide19. function reduce<A,B>(a: A[ ], f: (B, A, number) => B, x: B): B { ... } function reduce(a, f, x) { ... } TypeScript type How can we type reduce to account for valid indexes? Refinement type function reduce<A,B>(a: A[ ], f: (B, A, idx<a>) => B, x: B): B { ... } 19 Captures the relation between closure and value<br>
slide20. Our contribution
Design a refinement type system for TypeScript 20<br>
slide21. 21<br>
slide22. 22<br>
slide23. 23<br>
slide24. 24 Assignments
while (i < n) { i++; }<br>
slide25. function reduce(a, f, x) {
var r = x;
for (var i = 0; i < a.length; i++)
r = f(r, a[i], i);
return r;
} function reduce(a, f, x) {
var r = x;
var i = 0;
while (i < a.length) {
r = f(r, a[i], i);
i = i + 1;
}
return r;
} - - + + + + + 25 What is the type of i?<br>
slide26. function reduce(a, f, x) {
var r = x;
var i = 0;
while (i < a.length) {
r = f(r, a[i], i);
i = i + 1;
}
return r;
} Types for i What is the type of i? i1: { number | v = 0 } 26<br>
slide27. function reduce(a, f, x) {
var r = x;
var i = 0;
while (i < a.length) {
r = f(r, a[i], i);
i = i + 1;
}
return r;
} Types for i What is the type of i? i2: { number | 0 ≤ v ≤ len a } i1: { number | v = 0 } 27<br>
slide28. function reduce(a, f, x) {
var r = x;
var i = 0;
while (i < a.length) {
r = f(r, a[i], i);
i = i + 1;
}
return r;
} Types for i What is the type of i? i3: { number | v = i + 1 } i2: { number | 0 ≤ v ≤ len a } i1: { number | v = 0 } 28<br>
slide29. function reduce(a, f, x) {
var r = x;
var i = 0;
while (i < a.length) {
r = f(r, a[i], i);
i = i + 1;
} // i
return r;
} Types for i What is the type of i? i1: { number | v = len a } i3: { number | v = i + 1 } i2: { number | 0 ≤ v ≤ len a } i1: { number | v = 0 } 29<br>
slide30. function reduce(a, f, x) {
var r = x;
var i = 0;
while (i < a.length) {
r = f(r, a[i], i);
i = i + 1;
} // i
return r;
} Types for i Νo single type for i i1: { number | v = len a } i3: { number | v = i + 1 } i2: { number | 0 ≤ v ≤ len a } i1: { number | v = 0 } 30 What is the type of i?<br>
slide31. Joining types of i causes loss of precision Use different versions of i Νο single type for i 31<br>
slide32. Joining types of i causes loss of precision Use different versions of i Νο single type for i 32<br>
slide33. function reduce(a, f, x) {
var r = x;
var i = 0;
while (i < a.length) {
r = f(r, a[i], i);
i = i + 1;
} // i
return r;
} Types for i Use different versions of i i1: { number | v = len a } i3: { number | v = i + 1 } i2: { number | 0 ≤ v ≤ len a } i1: { number | v = 0 } 33<br>
slide34. function reduce(a, f, x) {
var r = x;
var i1 = 0;
while (i2 < a.length) {
r = f(r, a[i2], i2);
i3 = i2 + 1;
} // i4
return r;
} i3: { number | v = i2 + 1 } i2: { number | 0 ≤ v ≤ len a } i1: { number | v = 0 } Use different versions of i Types for i1-i4 i1: { number | v = len a } 34<br>
slide35. function reduce(a, f, x) {
var r = x;
var i1 = 0;
while (i2 < a.length) {
r = f(r, a[i2], i2);
i3 = i2 + 1;
} // i4
return r;
} i4: { number | v = len a } i3: { number | v = i2 + 1 } i2: { number | 0 ≤ v ≤ len a } i1: { number | v = 0 } Use different versions of i Types for i1-i4 35 Each version of i has a single precise type & gets assigned once Static Single Assignment (SSA) How do we check these types?<br>
slide36. x = e generates subtyping constraint Type(e) <: Type(x) Assignment 36 Reminder<br>
slide37. Subtyping Constraints Generated constraints 37 function reduce(a, f, x) {
var r = x;
var i1 = 0;
while (i2 < a.length) {
r = f(r, a[i2], i2);
i3 = i2 + 1;
} // i4
return r;
} Type(0) Type(i1) <:<br>
slide38. Subtyping Constraints i: loop induction variable
i2 = φ(i1,i3) Generated constraints 38 function reduce(a, f, x) {
var r = x;
var i1 = 0;
while (i2 < a.length) {
r = f(r, a[i2], i2);
i3 = i2 + 1;
} // i4
return r;
} Type(0) Type(i1) <: Type(i2) Type(i1) <:<br>
slide39. Subtyping Constraints i: loop induction variable
i2 = φ(i1,i3) Generated constraints Loop condition Path Sensitivity 39 function reduce(a, f, x) {
var r = x;
var i1 = 0;
while (i2 < a.length) {
r = f(r, a[i2], i2);
i3 = i2 + 1;
} // i4
return r;
} i2 < len a Type(0) Type(i1) <: loop_cond Type(i3) ⊢ Type(i2) <: Type(i2) Type(i1) <:<br>
slide40. Subtyping Constraints Generated constraints Loop condition 40 function reduce(a, f, x) {
var r = x;
var i1 = 0;
while (i2 < a.length) {
r = f(r, a[i2], i2);
i3 = i2 + 1;
} // i4
return r;
} i2 < len a Type(0) Type(i1) <: loop_cond Type(i3) ⊢ Type(i2) <: Type(i3) Type(i2 + 1) loop_cond ⊢ <: Type(i2) Type(i1) <:<br>
slide41. Subtyping Constraints Generated constraints Safe Array Access Loop condition i2 < len a 41 function reduce(a, f, x) {
var r = x;
var i1 = 0;
while (i2 < a.length) {
r = f(r, a[i2], i2);
i3 = i2 + 1;
} // i4
return r;
} Type(0) Type(i1) <: loop_cond Type(i3) ⊢ Type(i2) <: Type(i3) Type(i2 + 1) loop_cond ⊢ <: idx<a> Type(i2) loop_cond ⊢ <: Type(i2) Type(i1) <:<br>
slide42. Subtyping Constraints Generated constraints Loop condition i1: { number | v = 0 }
i2: { number | 0 ≤ v ≤ len a }
i3: { number | v = i2 + 1 }
i4: { number | v = len a } Substitute 42 Type(0) Type(i1) <: loop_cond Type(i3) ⊢ Type(i2) <: Type(i3) Type(i2 + 1) loop_cond ⊢ <: idx<a> Type(i2) loop_cond ⊢ <: i2 < len a Type(i2) Type(i1) <:<br>
slide43. Subtyping Constraints { num | v = 0 } <: { num | 0 ≤ v ≤ len a } { num | v = 0 } <: { num | v = 0 } i2 < len a ⊢ { num | v = i2 + 1 } <: { num | v = i2 + 1 } i2 < len a ⊢ { num | 0 ≤ v ≤ len a } <: { num | 0 ≤ v < len a } i2 < len a ⊢ { num | v = i2 + 1 } <: { num | 0 ≤ v ≤ len a } After substitution 43<br>
slide44. Subtyping Constraints { num | v = 0 } <: { num | 0 ≤ v ≤ len a } { num | v = 0 } <: { num | v = 0 } i2 < len a ⊢ { num | v = i2 + 1 } <: { nu m | v = i2 + 1 } i2 < len a ⊢ { num | 0 ≤ v ≤ len a } <: { num | 0 ≤ v < len a } i2 < len a ⊢ { num | v = i2 + 1 } <: { num | 0 ≤ v ≤ len a } Convert to logical implications Solved via SMT ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ 44<br>
slide45. 45<br>
slide46. Mutability
var x = { f: 1 };
x.f = 2; 46<br>
slide47. Why is the access a[i] safe? i is initialized to 0
i is bounded by a’s length
i increases only
Length of a does not mutate in loop 47 1 2 function reduce(a, f, x) {
var res = x;
for (var i = 0; i < a.length; i++)
res = f(res, a[i], i);
return res;
} 4 3<br>
slide48. function reduce(a, f, x) {
var res = x;
for (var i = 0; i < a.length; i++) {
a.pop();
res = f(res, a[i], i);
}
return res;
} Silently
updates
a.length interface Array<T> {
/**
* Removes the last element from an array and returns it.
*/
pop(): T:
} Check becomes stale lib.d.ts Unsafe access! 48 What if array’s length mutates in loop?<br>
slide49. Problem: stale checks break value reasoning Silently
updates
a.length interface Array<T> {
/**
* Removes the last element from an array and returns it.
*/
pop(): T:
} lib.d.ts 49 function reduce(a, f, x) {
var res = x;
for (var i = 0; i < a.length; i++) {
a.pop();
res = f(res, a[i], i);
}
return res;
} Check becomes stale Unsafe access!<br>
slide50. Extend type system to enforce immutability constraints 50<br>
slide51. M. Tschantz and M. D. Ernst. Javari: Adding reference immutability to Java. OOPSLA, 2005.
Y. Zibin, A. Potanin, M. Ali, S. Artzi, A. Kiezun, and M. D. Ernst. Object and Reference Immutability using Java Generics. ESEC/FSE, 2007.
Y. Zibin, A. Potanin, P. Li, M. Ali, and M. D. Ernst. Ownership and Immutability in Generic Java. OOPSLA, 2010.
C. S. Gordon, M. J. Parkinson, J. Parsons, A. Bromfield, and J. Duffy. Uniqueness & Reference Immutability for Safe Parallelism. OOPSLA, 2012.
C. S. Gordon, M. D. Ernst, and D. Grossman. Rely-Guarantee References for Refinement Types over Aliased Mutable Data. PLDI, 2013.
F. Militão, J. Aldrich, and L. Caires. Rely-Guarantee Protocols. ECOOP, 2014. Literature in Object & Reference Immutability 51<br>
slide52. M. Tschantz and M. D. Ernst. Javari: Adding reference immutability to Java. OOPSLA, 2005.
Y. Zibin, A. Potanin, M. Ali, S. Artzi, A. Kiezun, and M. D. Ernst. Object and Reference Immutability using Java Generics. ESEC/FSE, 2007. Literature in Object & Reference Immutability Simple extension to type system
Encoded in base types – refinements leverage immutability guarantees 52<br>
slide53. ReadOnly Mutable Immutable Immutability Generic Java [Zibin’07] Mutability as
type parameter Only immutable portions in refinement function reduce<A,B>(a: Array<Immutable,A>,
f: (B,A,idx<a>) => B,
x: B): B {
var res = x;
for (let i = 0; i < a.length; i++)
res = f(res, a[i], i);
return res;
} 53<br>
slide54. Immutability Generic Java [Zibin’07] interface Array<M extends ReadOnly, T> {
/**
* Removes the last element from an array and returns it.
*/
/*@ Mutable */ pop(): T;
} lib-IGJ.d.ts function reduce<A,B>(a: Array<Immutable,A>,
f: (B,A,idx<a>) => B,
x: B): B {
var res = x;
for (let i = 0; i < a.length; i++) {
a.pop();
res = f(res, a[i], i);
}
return res;
} Call to pop is flagged as an error,
because pop may only be
applied to Mutable receivers 54<br>
slide55. 55<br>
slide56. Overloading
foo(x: number): number
foo(x: boolean): boolean Value Based 56<br>
slide57. Value Based Overloading Function reflects upon and behaves according to types of its arguments function $reduce(a, f, x?) {
if (arguments.length === 3)
return reduce(a, f, x);
else
return reduce(a.slice(1), f, a[0]);
} 2nd behavior – 2 args:
x is of type undefined 1st behavior – 3 args:
x is of type B 57 <A> (a: A[]+, f: (A,A,idx<a>) => A ): A <A,B>(a: A[] , f: (B,A,idx<a>) => B, x: B): B<br>
slide58. Q1: What makes it challenging?
Q2: How pervasive is it? Value Based Overloading Function reflects upon and behaves according to types of its arguments 58<br>
slide59. function $reduce(a, f, x?) {
if (arguments.length === 3)
return reduce(a, f, x);
else
return reduce(a.slice(1), f, a[0]);
} Type Analysis
(base types) Value Analysis
(refinements) Refinements use invariants established by base types
E.g. tracking the .length access requires arguments to be array Type reasoning requires tracking logical relationships
E.g. base type of x depends on the value of arguments.length Circular dependency complicates formal reasoning & implementation 59 Q1: What makes it challenging?<br>
slide60. Q2: How pervasive is it? 60 Study set:
DefinitelyTyped: The repository for high quality TypeScript type definitions http://definitelytyped.org/<br>
slide61. How do we check overloaded functions? function $reduce<A> (a: A[]+, f: (A,A,idx<a>) => A ): A
function $reduce<A,B>(a: A[] , f: (B,A,idx<a>) => B, x: B): B
function $reduce(a, f, x?) {
if (arguments.length === 3)
return reduce(a, f, x);
else
return reduce(a.slice(1), f, a[0]);
} Phase 1a. Make clones of body for each overload function $reduce<A>(a: A[]+, f: (A,A,idx<a>) => A): A {
if (arguments.length === 3)
return reduce(a, f, x);
else
return reduce(a.slice(1), f, a[0]);
} function $reduce<A,B>(a: A[] , f: (B,A,idx<a>) => B, x: B): B {
if (arguments.length === 3)
return reduce(a, f, x);
else
return reduce(a.slice(1), f, a[0]);
} 61 Two-Phased Typing [ECOOP’15]<br>
slide62. How do we check overloaded functions? Phase 1b. Check body under clone signature function $reduce#1<A>(a: A[]+, f: (A,A,idx<a>) => A): A {
if (arguments.length === 3)
return reduce(a, f, x);
else
return reduce(a.slice(1), f, a[0]);
} Error: expecting type A, passed x of type undefined 62 Two-Phased Typing [ECOOP’15] Value- and path-insensitive type-checking<br>
slide63. How do we check overloaded functions? function $reduce#1<A>(a: A[]+, f: (A,A,idx<a>) => A): A {
if (arguments.length === 3)
return assert(false );
else
return reduce(a.slice(1), f, a[0]);
} Replace errors with assert(false), trusting they are indeed dead-code 63 Two-Phased Typing [ECOOP’15] Phase 1b. Check body under clone signature<br>
slide64. function $reduce#1<A>(a: A[]+, f: (A,A,idx<a>) => A): A {
if (arguments.length === 3)
return assert(false );
else
return reduce(a.slice(1), f, a[0]);
} How do we check overloaded functions? Phase 2. Refinement Type Checking Prove dead-code with flow- and path-sensitive analysis Signature implies: arguments.length = 2 Condition makes branch’s environment inconsistent 64 Two-Phased Typing [ECOOP’15]<br>
slide65. Also in the paper… Scaling to TypeScript
Type features
Object literal types
Interface types
Primitive types
Unsound features
Undefined & null types
Co- & Contra-variant subtyping
Unchecked overloads
any type 65 Formal Results
Refinement type safety for core language Array support
Flexible object initialization
Internal: Constructors
External: Unique references<br>
slide66. Experimental Evaluation 66<br>
slide67. Benchmark suite 67<br>
slide68. Benchmark suite Octane
NavierStokes: 2D fluid motion simulator
Splay: splay tree implementation
Richards: OS kernel simulator
Raytrace: ray trace renderer 68<br>
slide69. Benchmark suite Transducers
Composable algorithmic transformations 69 Octane
NavierStokes: 2D fluid motion simulator
Splay: splay tree implementation
Richards: OS kernel simulator
Raytrace: ray trace renderer<br>
slide70. Benchmark suite D3: A JavaScript visualization library
Array operations Transducers
Composable algorithmic transformations 70 Octane
NavierStokes: 2D fluid motion simulator
Splay: splay tree implementation
Richards: OS kernel simulator
Raytrace: ray trace renderer<br>
slide71. Microsoft’s TypeScript compiler
Parts of core.ts and checker.ts Benchmark suite 71 D3: A JavaScript visualization library
Array operations Transducers
Composable algorithmic transformations Octane
NavierStokes: 2D fluid motion simulator
Splay: splay tree implementation
Richards: OS kernel simulator
Raytrace: ray trace renderer<br>
slide72. Annotation Overhead * * Programs need to be fully typed – no any type in signatures 72<br>
slide73. Performance 73 More than 100 static array access sites with dynamically computed indexes<br>
slide74. Properties Tested Property accesses
Array bounds checks
Overloads
Safe Downcasts
Class based
Ad hoc type hierarchies
User specified value properties. E.g. a function:
returns a positive number
accepts non-empty arrays 74 Safe Downcasts Ad hoc type hierarchies Example taken from:
TypeScript compiler - v1.0.1.0 - src/compiler/types.ts<br>
slide75. IType IAny IObject IInterface IClass interface IType {…}
interface IClass extends IType {…}
interface IAny extends IType {…}
interface IObject extends IType {…}
interface IInterface extends IObject {…} TypeScript interfaces are plain JavaScript objects
no type information at runtime 75<br>
slide76. interface IType { flags:TypeFlags; }
interface IClass extends IType {…}
interface IAny extends IType {…}
interface IObject extends IType {…}
interface IInterface extends IObject {…}

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} TypeScript interfaces are plain JavaScript objects
no type information at runtime Explicit field (flags) to encode type info
needed for dynamic tests 76 IType IAny IObject IInterface IClass<br>
slide77. interface IType { flags:TypeFlags; } 77 interface IClass extends IType {…}
interface IAny extends IType {…}
interface IObject extends IType {…}
interface IInterface extends IObject {…} const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} ... Invariants IType IAny IObject IInterface IClass<br>
slide78. t.flags & 0x0400 ≠ 0 ⇒ t: IClass Invariants 78 interface IType { flags:TypeFlags; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} IType IAny IObject IInterface IClass<br>
slide79. t.flags & 0x0400 ≠ 0 ⇒ t: IClass t.flags & (0x0400|0x0800|…) ≠ 0 ⇒ t: IObject ... Invariants 79 interface IType { flags:TypeFlags; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} IType IAny IObject IInterface IClass<br>
slide80. t.flags & 0x0400 ≠ 0 ⇒ t: IClass Problem
Unchecked invariants t.flags & (0x0400|0x0800|…) ≠ 0 ⇒ t: IObject ... 80 interface IType { flags:TypeFlags; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} var t: IType = …
if (t.flags & TypeFlags.Class) {
var o = <IClass> t;
}<br>
slide81. t.flags & 0x0400 ≠ 0 ⇒ t: IClass t.flags & (0x0400|0x0800|…) ≠ 0 ⇒ t: IObject ... 81 interface IType { flags:TypeFlags; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} var t: IType = …
if (t.flags & TypeFlags.Class) {
var o = <IAny> t;
} No static or
dynamic error Problem
Unchecked invariants<br>
slide82. 82 interface IType { flags:TypeFlags; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} Solution
Encode invariants in refinement types var t: IType = …
if (t.flags & TypeFlags.Class) {
var o = <IAny> t;
} No static or
dynamic error Problem
Unchecked invariants<br>
slide83. x: S  implements(x, 'S') Encode type information in logic interface S {…} 83<br>
slide84. interface IType { flags:TypeFlagInv; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} 84 type TypeFlagInv = TypeFlags IType IAny IObject IInterface IClass Type for flags accounts for possible sub-interfaces<br>
slide85. interface IType { flags:TypeFlagInv; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} 85 Bitwise AND The containing object type TypeFlagInv = { TypeFlags |
mask(v,0x0001) ⇒ implements(this, 'IAny')

} Type for flags accounts for possible sub-interfaces IType IAny IObject IInterface IClass<br>
slide86. 86 interface IType { flags:TypeFlagInv; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} type TypeFlagInv = { TypeFlags |
mask(v,0x0001) ⇒ implements(this, 'IAny')
Λ mask(v,0x0400) ⇒ implements(this, 'IClass')

} Type for flags accounts for possible sub-interfaces IType IAny IObject IInterface IClass<br>
slide87. interface IType { flags:TypeFlagInv; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} Check downcast 87 type TypeFlagInv = { TypeFlags |
mask(v,0x0001) ⇒ implements(this, 'IAny')
Λ mask(v,0x0400) ⇒ implements(this, 'IClass')
Λ mask(v,0x0800) ⇒ implements(this, 'IInterface')
Λ … } var t: IType = …
if (t.flags & TypeFlags.Class) {
var o = <IClass> t;
}<br>
slide88. interface IType { flags:TypeFlagInv; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} var t: IType = …
if (t.flags & TypeFlags.Class) {
var o = <IClass> t;
} Check downcast 88 type TypeFlagInv = { TypeFlags |
mask(v,0x0001) ⇒ implements(this, 'IAny')
Λ mask(v,0x0400) ⇒ implements(this, 'IClass')
Λ mask(v,0x0800) ⇒ implements(this, 'IInterface')
Λ … } Invariant for IType<br>
slide89. interface IType { flags:TypeFlagInv; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} Check downcast 89 type TypeFlagInv = { TypeFlags |
mask(v,0x0001) ⇒ implements(this, 'IAny')
Λ mask(v,0x0400) ⇒ implements(this, 'IClass')
Λ mask(v,0x0800) ⇒ implements(this, 'IInterface')
Λ … } Invariant for IType Path condition:
t.flags & 0x0400 ≠ 0 Λ var t: IType = …
if (t.flags & TypeFlags.Class) {
var o = <IClass> t;
}<br>
slide90. interface IType { flags:TypeFlagInv; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} Check downcast 90 Invariant for IType Path condition:
t.flags & 0x0400 ≠ 0 Λ implements(t, 'IClass') ⇒ var t: IType = …
if (t.flags & TypeFlags.Class) {
var o = <IClass> t;
} type TypeFlagInv = { TypeFlags |
mask(v,0x0001) ⇒ implements(this, 'IAny')
Λ mask(v,0x0400) ⇒ implements(this, 'IClass')
Λ mask(v,0x0800) ⇒ implements(this, 'IInterface')
Λ … }<br>
slide91. interface IType { flags:TypeFlagInv; }
...

const enum TypeFlags {
Any = 0x0001,
Class = 0x0400,
Interface = 0x0800,
ObjType = Class
| Interface
| ...
} Check downcast 91 Invariant for IType Path condition:
t.flags & 0x0400 ≠ 0 Λ t: IClass ⇒ var t: IType = …
if (t.flags & TypeFlags.Class) {
var o = <IClass> t;
} Encode type information in logic type TypeFlagInv = { TypeFlags |
mask(v,0x0001) ⇒ implements(this, 'IAny')
Λ mask(v,0x0400) ⇒ implements(this, 'IClass')
Λ mask(v,0x0800) ⇒ implements(this, 'IInterface')
Λ … }<br>
slide92. 92 Extensible static analysis for a modern scripting language Fixed type tests
User specified invariants Source: github.com/UCSD-PL/refscript Demo: goto.ucsd.edu/~pvekris/refscript Thanks! Refinement Types for TypeScript<br>