Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park...

38
Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis Vekris (Microsoft Research) (Oracle) (UCSD)

Transcript of Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park...

Page 1: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

Safe & Efficient Gradual Typingfor TypeScript

Aseem RastogiUniversity of Maryland, College Park

Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis Vekris

(Microsoft Research) (Oracle) (UCSD)

Page 2: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

2

Gradual Typing

Combines benefits of static and dynamic typing

Statically-typed

fragment

Dynamically-typed

fragment

Dynamic type any

Runtime checks mediate interaction

Static type errors Performance Typed interface documentation

Rapid prototyping

Flexibility

Page 3: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

3

TypeScript, Dart, Closure, Flow (we focus on TypeScript)

Increase programmer productivity(static type errors, intellisense, code refactoring, modularity …)

Types don’t get in the way of good programmers(retain flavor of programming in JavaScript)

Increasing Adoption in IndustryMainly for JavaScript

Page 4: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

4

TypeScript is Intentionally UnsoundFor All Its Dynamic Idioms, Typing JavaScript is Hard !

Unsound typing rules to support supposedly common idioms(covariant array subtyping, covariant function arguments, …)

Types are uniformly erased during compilation(lightweight compilation, no runtime performance cost, …)(unchecked runtime casts, types don’t guarantee anything)

Page 5: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

5

Programmers Cannot Rely On Typesprivate parseColorCode (c:string) { if (typeof c !== "string") return -1; …}

Snippet from TouchDevelop, a large TypeScript Development

Tools can’t rely on typesRefactoring, compiler optimizations, etc. are not safe

Page 6: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

6

Can we design a gradual type system that is:

Safe

Efficient

Supports idiomatic TypeScript/JavaScriptWe present Safe TypeScript

Page 7: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

7

Safe TypeScript is SoundTypeScript is Intentionally Unsound

Standard variance for arrays and function argumentsSound treatment of JavaScript thisCareful separation of nominal and structural typesEasy local rewriting of unsound idioms in 120,000 line corpus

TypeScript has unsound typing rules to support common idioms

Page 8: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

8

Safe TypeScript is SoundTypeScript is Intentionally Unsound

Safe TypeScript guarantees type safetyCombination of static checking and runtime checksRuntime-type-information (RTTI) based gradual typingEfficiency using two new notions of partial erasureRuntime overhead of only 15% for bootstrapping Safe TypeScript 6.5% for typed Octane benchmarks

TypeScript uniformly erases all types making uses of any unsafe

Page 9: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

9

Formalized core of Safe TypeScript, proven sound class C, interface I, {M;F}, number, any, Erased t

Implemented in a branch of TypeScript v0.9.5Can be invoked with --safe command line flag

Evaluated on 120,000 lines of codeBootstrapped Safe TypeScript compiler, New TypeScript compiler, Octane

Our Contributions

Page 10: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

10

Safe TypeScript TourOverview of RTTI-based Gradual Typing

Values carry Run Time Type Tagsconsistent with their contents

Dynamically-typed code instrumented to respect RTTI tags

Invariant: v : [| v.tag |]

Object with 3 fields and type tag

f = 2g = "s"h = true

tag = {f:number; g:string}

Page 11: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

11

interface Point { x:number }

function g(p:Point) { p.x = p.x + 1;}

function f() { var p:Point = { x = 0 }; g(p);}

Compiles unchanged

No runtime checks

No tagging !

Previous systems tag eagerly

RTTI Tagging in Safe TypeScriptOn-demand and Differential

Safe TypeScript JavaScript

Page 12: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

12

RTTI Tagging in Safe TypeScriptOn-demand

function g(p:any) { p.x = p.x + 1;}

function f() { var p:Point = { x = 0 }; g(p);}

function f() { var p = { x = 0 }; g(shallowTag(p, Point));}

shallowTag(x,t) = x.tag := combine(x.tag, t); x

Safe TypeScript JavaScript

Add RTTI when types lose precision

Page 13: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

13

RTTI Tagging in Safe TypeScriptDifferential

shallowTag(x,t) = x.tag := combine(x.tag, t); x

interface 2dPoint extends Point { y:number}

function h(p:any) { .. }

function g(p:Point) { h(p);}

function f() { var p:2dPoint = { x = 0; y = 0 }; g(p);}

function g(p) { h(shallowTag(p, Point));}

function f() { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number }));}

Safe TypeScript JavaScript

Add Minimum Required RTTI

Page 14: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

14

RTTI Tagging in Safe TypeScript

shallowTag(x,t) = x.tag := combine(x.tag, t); x

function g(p) { h(shallowTag(p, Point));}

function f() { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number }));}

JavaScript

Add Minimum Required RTTI

x = 0y = 0

Page 15: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

15

RTTI Tagging in Safe TypeScript

shallowTag(x,t) = x.tag := combine(x.tag, t); x

function g(p) { h(shallowTag(p, Point));}

function f() { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number }));}

JavaScript

Add Minimum Required RTTI

x = 0y = 0

tag = {y:number}

x = 0y = 0

Page 16: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

16

RTTI Tagging in Safe TypeScript

shallowTag(x,t) = x.tag := combine(x.tag, t); x

function g(p) { h(shallowTag(p, Point));}

function f() { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number }));}

JavaScript

Add Minimum Required RTTIx = 0y = 0

tag = {x:number; y:number}

x = 0y = 0

tag = {y:number}

x = 0y = 0

Page 17: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

17

Differential Subtyping

t1 <: t2 ~> d d = 0 | t

d is loss in precision that must be captured in the RTTI

Differential SubtypingTechnical Device for On-Demand and Differential Tagging

Page 18: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

18

t <: t ~> 0

{x:number;y:number} <: {x:number} ~> {y:number}

{x:number;y:number} <: any ~> {x:number;y:number}

Primitive RTTI Aware: number <: any ~> 0

Differential Subtypingt1 <: t2 ~> d d is loss in precision

Page 19: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

19

Γ |- e : t2 ~> e’t2 <: t1 ~> d

Γ |- e : t1 ~> shallowTag(e’, d) T-Sub

Differential Subtypingt1 <: t2 ~> d d is loss in precision

Page 20: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

20

Instrumentation of Dynamically Typed Code

function g(p:any) { p.x = "boom";}

function f() { var p:Point = { x = 0 }; g(p); assert(typeof p.x === "number");}

function f() { .. }

function g(p) { write(p, "x", "boom");}

write(o,f,v) = let t = o.tag; o[f] = check(v, t[f]);

(Recall that f tags p with type Point)

// Fails

Safe TypeScript JavaScript

Page 21: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

21

Differential Tagging Useful, But Not Ideal

function g(p) { return p.x; }

function f(p) { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number }));}

Safe TypeScript JavaScript

function g(p:Point) { return p.x;}

Unnecessary shallowTag

function f() { var p:2dPoint = { x = 0; y = 0 }; g(p);}

Page 22: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

22

Reason: Need Conservative Tagging

Previous gradual type systems: t anyfor all static types t

Incurs tagging even for statically typed code

Relaxing it opens opportunities for sound type erasure

Page 23: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

23

A new type modality: Erased tErased t cannot be cast to any

Statically a tbut may not have an RTTI at runtime

Erased TypesProgrammer-controlled Tagging Behavior

Page 24: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

24

t1 <: t2 ~> dt1 <: Erased t2 ~> 0

Erased t <\: any

Subtyping for Erased Types

// Zero delta

// Ensure full erasure is safe

Page 25: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

25

Erased Types Example: No Tagging

Safe TypeScript JavaScript

function g(p) { return p.x; }

function f(p) { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number }));}

function g(p:Point) { return p.x;}

Unnecessary shallowTag

function f() { var p:2dPoint = { x = 0; y = 0 }; g(p);}

Page 26: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

26

Erased Types Example: No Tagging

function g(p) { return p.x; }

function f(p) { var p = { x = 0; y = 0 }; g(p);}

Safe TypeScript JavaScript

function g(p:Erased Point) { return p.x;}

function f() { var p:2dPoint = { x = 0; y = 0 }; g(p);}

// No tagging

Recall shallowTag for non-erased types

Page 27: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

27

Erased Types Example: No Tagging

function f(p) { var p = { x = 0; y = 0 }; g(p);}

Safe TypeScript JavaScript

function g(p:Erased Point) { return h(p);}

function f() { var p:2dPoint = { x = 0; y = 0 }; g(p);}

// No tagging

function h(p:any) { .. }

Static Type Error

Page 28: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

28

Obey a fully static type discipline(Sound type erasure, type abstraction, …)(Loss in expressiveness: not all code can be turned dynamic)

Other advantages of Erased typesWorking with external libraries that may not have RTTIAdding new features to the type system (e.g. Polymorphism)See our paper for more details

Erased Types

Page 29: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

29

Soundness Theorem: Forward Simulation

Checks introduced by Safe TypeScript:

Catch any dynamic type errorDo not alter the semantics of type safe code

Tag heap evolution invariant

Page 30: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

30

Implemented in a branch of TypeScript v0.9.5Invoke our type checker with --safe flag

10,000 Lines of Code

Compiles to plain JavaScript (with instrumented checks)

(recursive interfaces, inheritance, overloading, generics, arrays, external libs, …)

Safe TypeScript ImplementationOpen Source on Github

Page 31: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

Bootstrapping Safe TypeScript

90,000 Lines of Code, heavily class based, carefully annotated Number of Errors

Covariant method arguments

130

Variable scoping 128

Potential unsound use of this

52

Bivariant array subtyping

98

... …

Total 478 Static Type Errors found in Safe TypeScript Code

Page 32: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

Bootstrapping Safe TypeScript

90,000 Lines of Code, heavily class based, carefully annotated

Static Type Errors found in Safe TypeScript Code

All cases in one file using visitor pattern, easily rewritten

Sloppy use of var declarations, easily fixed

Projection of methods, easily fixed by making them functions

Fixed by introducing array mutability qualifiers

Number of Errors

Covariant method arguments

130

Variable scoping 128

Potential unsound use of this

52

Bivariant array subtyping

98

... …

Total 478

Page 33: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

Bootstrapping Safe TypeScript

90,000 Lines of Code, heavily class based, carefully annotated

478 Static type errors

26 failed runtime downcasts; 5 in our own code !

15% runtime overhead of type safety

Page 34: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

Octane Benchmarks (6 / 17)22x (ave.) and 72x (max.) overhead with no type annotations

Down to 6.5% after adding type annotationsNo overhead for statically-typed code

Found a variable scoping bug in navier-stokesIt has since been fixed

Efficiency conditioned on precise type inferenceTypeScript quite conservative

Page 35: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

35

Nominal handling of prototype-based classesSound handling of thisAbstraction theorem for Erased { }Zero-subtyping to avoid object identity issuesMore experiments(TypeScript v1.1, Octane benchmarks, Different tagging schemes)

Also in the paper …

Page 36: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

36

When to use Safe TypeScript ?For mature TypeScript projects, improved code qualityGood in development setting for finding early bugsBaseline for JS analyses focusing on deeper properties

Safe TypeScript SummarySafe & Efficient Gradual Typing for TypeScript

Significant value for type annotations at a modest cost

(runtime checks at least during development and testing)

Give it a go !

Page 37: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

37

interface Point {..}

interface 2dPoint {..}

Erased Types Example: Type Abstraction

function g(p:Point) { write(p, "y", 3);}

function f() {..}

RTTI of p at write is {y:number}

write succeeds: abstraction violation

function g(p:Point) { (<any> p).y = 3;}

function f() { var p:2dPoint = {x = 0;y = 0}; g(p);}

Safe TypeScript JavaScript

Page 38: Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

38

function g(p:Point) { (<any> p).y = 3;}

function f() { var p:2dPoint = {x = 0;y = 0}; g(p);}

interface Point extends Erased {..}

interface 2dPoint extends Point {..}

Static Type Error

Erased Types Example: Type Abstraction

Safe TypeScript JavaScript