SLIDE 1
Liquid Type Inference under the Hood Micha Reiser Seminar Program - - PowerPoint PPT Presentation
Liquid Type Inference under the Hood Micha Reiser Seminar Program - - PowerPoint PPT Presentation
Liquid Type Inference under the Hood Micha Reiser Seminar Program Analysis & Transformation University of Applied Sciences Rapperswil 1 Motivation Liquid Type Inference Conclusion 2 Motivation Motivation for Liquid Types Proof
SLIDE 2
SLIDE 3
Motivation
SLIDE 4
Motivation for Liquid Types
- Proof fine-granular invariants
3
SLIDE 5
Motivation for Liquid Types
- Proof fine-granular invariants
- . . . by using Dependent Types
3
SLIDE 6
Motivation for Liquid Types
- Proof fine-granular invariants
- . . . by using Dependent Types
- . . . but with Type Inference
The more interesting your types get, the less fun it is to write them down [1].
- Benjamin Pierce
3
SLIDE 7
The List-Average Example
avg :: [Int] -> Int avg xs = total `div` n where total = sum xs n = length xs main = do putStrLn "Enter List" list <- readLn putStrLn ("The Avg is: " ++ (show (avg list)))
4
SLIDE 8
What can possibly go wrong, it is too easy!
./avglist Enter List [1, 5, 10] The Avg is: 5
5
SLIDE 9
Quite a Lot. . .
./avglist Enter List [] avglist: divide by zero
6
SLIDE 10
Liquid Haskell Catches these Errors for You
avglist.hs:2:10-22: Error: Liquid Type Mismatch 2 | avg xs = total `div` n ^^^^^^^^^^^^^ Inferred type VV : {VV : Int | VV >= 0 && VV == len xs && VV == n} not a subtype of Required type VV : {VV : Int | VV /= 0} In Context xs : {v : [Int] | len v >= 0} n : {n : Int | n >= 0
7
SLIDE 11
Liquid Type Inference
SLIDE 12
The Goal
. . . is to infer the unknown refinement predicates p of the dependent types T in the program.
8
SLIDE 13
The Structure of a Dependent Type
{ν : B | p}
- ν: The special value-variable
- B: Base Type like int, bool, char. . .
- p: The refinement predicate
9
SLIDE 14
What is a Liquid Type?
A liquid type is a dependent type where the refinement predicate is a conjunction of qualifiers from Q. Q = {0 ≤ ν, ⋆ ≤ ν, ν < ⋆}
Dependent Types (over 𝐹) Liquid Types (over ℚ)
10
SLIDE 15
What is a Liquid Type?
A liquid type is a dependent type where the refinement predicate is a conjunction of qualifiers from Q. Q = {0 ≤ ν, ⋆ ≤ ν, ν < ⋆} {ν : int | 0 ≤ ν}
- Dependent Types (over 𝐹)
Liquid Types (over ℚ)
10
SLIDE 16
What is a Liquid Type?
A liquid type is a dependent type where the refinement predicate is a conjunction of qualifiers from Q. Q = {0 ≤ ν, ⋆ ≤ ν, ν < ⋆} {ν : int | 0 ≤ ν}
- {ν : int | 0 ≤ ν ∧ n ≤ ν}
- Dependent Types (over 𝐹)
Liquid Types (over ℚ)
10
SLIDE 17
What is a Liquid Type?
A liquid type is a dependent type where the refinement predicate is a conjunction of qualifiers from Q. Q = {0 ≤ ν, ⋆ ≤ ν, ν < ⋆} {ν : int | 0 ≤ ν}
- {ν : int | 0 ≤ ν ∧ n ≤ ν}
- {ν : int | ν = 0 ∧ 0 ≤ ν}
✗
Dependent Types (over 𝐹) Liquid Types (over ℚ)
10
SLIDE 18
What is a Liquid Type?
A liquid type is a dependent type where the refinement predicate is a conjunction of qualifiers from Q. Q = {0 ≤ ν, ⋆ ≤ ν, ν < ⋆} {ν : int | 0 ≤ ν}
- {ν : int | 0 ≤ ν ∧ n ≤ ν}
- {ν : int | ν = 0 ∧ 0 ≤ ν}
✗ {ν : int | 0 ≤ ν = ⇒ c ≤ ν} ✗
Dependent Types (over 𝐹) Liquid Types (over ℚ)
10
SLIDE 19
The Approach
Do you still remember these: If Alice doubles her age, she would still be 10 years younger than Bob, who was born in 1952. How old are Alice and Bob? [2]
11
SLIDE 20
The Approach
Do you still remember these: If Alice doubles her age, she would still be 10 years younger than Bob, who was born in 1952. How old are Alice and Bob? [2]
- 1. Create Templates for the Unknown:
Alice’s age: a Bob’s age: b
11
SLIDE 21
The Approach
Do you still remember these: If Alice doubles her age, she would still be 10 years younger than Bob, who was born in 1952. How old are Alice and Bob? [2]
- 1. Create Templates for the Unknown:
Alice’s age: a Bob’s age: b
- 2. Constraints on Templates:
2a = b − 10 b = 2016 − 1952
11
SLIDE 22
The Approach
Do you still remember these: If Alice doubles her age, she would still be 10 years younger than Bob, who was born in 1952. How old are Alice and Bob? [2]
- 1. Create Templates for the Unknown:
Alice’s age: a Bob’s age: b
- 2. Constraints on Templates:
2a = b − 10 b = 2016 − 1952
- 3. Solve constraints: a = 27, b = 64
11
SLIDE 23
Let’s apply this to the sum function
In Haskell sum :: Int -> Int sum n = if n < 0 then 0 else n + sum (n - 1) In L1 let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n
12
SLIDE 24
Step 1: Template Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n
13
SLIDE 25
Step 1: Template Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n n : int → int ML-Type
13
SLIDE 26
Step 1: Template Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n n : int → int ML-Type n : {ν : int |?} → {ν : int |?} Liquid-Type
13
SLIDE 27
Step 1: Template Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n n : int → int ML-Type n : {ν : int |?} → {ν : int |?} Liquid-Type n : {ν : int | κn} → {ν : int | κret} Template
13
SLIDE 28
Step 1: Template Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n n : int → int ML-Type n : {ν : int |?} → {ν : int |?} Liquid-Type n : {ν : int | κn} → {ν : int | κret} Template Definition A Liquid Type Variable κ is a placeholder for the unknown refinements
13
SLIDE 29
Two Kind Of Constraints
Definition Well-Formedness Constraints define which variables can be used in a refinement predicate. Γ ⊢ T Definition Subtyping Constraints capture proof a subtyping relation between two types (and therefore, the data flow of values). Γ ⊢ T1 <: T2
14
SLIDE 30
Step 2: Well-Formedness Constraint Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n Template sum :: n : {ν : int | κn} → {ν : int | κret} Well-Formedness Constraints:
15
SLIDE 31
Step 2: Well-Formedness Constraint Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n Template sum :: n : {ν : int | κn} → {ν : int | κret} Well-Formedness Constraints: ∅ ⊢ κn
15
SLIDE 32
Step 2: Well-Formedness Constraint Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n Template sum :: n : {ν : int | κn} → {ν : int | κret} Well-Formedness Constraints: ∅ ⊢ κn n : {ν : int | κn} ⊢ κret
15
SLIDE 33
Step 2: Subtyping Constraint Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n Template sum :: n : {ν : int | κn} → {ν : int | κret} The then branch flows into the result:
16
SLIDE 34
Step 2: Subtyping Constraint Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n Template sum :: n : {ν : int | κn} → {ν : int | κret} The then branch flows into the result:
sum : . . . , n : {ν : int | κn} , n < 0 ⊢ {ν : int | ν = 0} <: {ν : int | κret}
16
SLIDE 35
Step 2: Subtyping Constraint Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum(n − 1) in s + n Template sum :: n : {ν : int | κn} → {ν : int | κret} The then branch flows into the result:
sum : . . . , n : {ν : int | κn} , n < 0 ⊢ {ν : int | ν = 0} <: {ν : int | κret} n : κn , n < 0 ⊢ ν = 0 <: κret
16
SLIDE 36
Step 2: Subtyping Constraint Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum( n − 1 ) in s + n Template sum :: n : {ν : int | κn} → {ν : int | κret} n − 1 flows into the argument of sum: n : κn , ¬ n < 0 ⊢ ν = n − 1 <: κn
17
SLIDE 37
Step 2: Subtyping Constraint Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum( n − 1 ) in s + n Template sum :: n : {ν : int | κn} → {ν : int | κret} The type of sum(n − 1) (s): {ν : int ⊢ κret [ n − 1 / n ]}
18
SLIDE 38
Step 2: Subtyping Constraint Generation
let rec sum = n ⇒ if n < 0 then 0 else let s = sum( n − 1 ) in s + n Template sum :: n : {ν : int | κn} → {ν : int | κret} The else branch flows into the result n : κn , s : κret [ n − 1 / n ], ¬ n < 0 ⊢ ν = s + n <: κret
19
SLIDE 39
Step 2: Constraints
Well-Formedness ∅ ⊢ κn n : κn ⊢ κret Subtyping n : κn, n < 0 ⊢ ν = 0 <: κret n : κn, ¬n < 0 ⊢ ν = n − 1 <: κn n : κn, s : κret[n − 1/n], ¬n < 0 ⊢ ν = s + n <: κret
20
SLIDE 40
Step 3: Solve Constraints
- 1. Initial assignment map A(κ) with all Qualifiers Q
- 2. Remove qualifiers that do not satisfy a constraint
21
SLIDE 41
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ κret 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ Well-Formedness Constraint ∅ ⊢ κn n : κn ⊢ κret
22
SLIDE 42
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν , ⋆ ≤ ν, ν ≤ ⋆ κret 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ Well-Formedness Constraint ∅ ⊢ κn SAT
22
SLIDE 43
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν, ⋆ ≤ ν , ν ≤ ⋆ κret 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ Well-Formedness Constraint ∅ ⊢ κn UNSAT: No free variables allowed
22
SLIDE 44
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν, ✘✘
✘ ❳❳ ❳
⋆ ≤ ν , ν ≤ ⋆ κret 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ Well-Formedness Constraint ∅ ⊢ κn UNSAT: No free variables allowed
22
SLIDE 45
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν, ν ≤ ⋆ κret 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ Well-Formedness Constraint ∅ ⊢ κn UNSAT: No free variables allowed
22
SLIDE 46
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν, ✘✘
✘ ❳❳ ❳
ν ≤ ⋆ κret 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ Well-Formedness Constraint ∅ ⊢ κn UNSAT: No free variables allowed
22
SLIDE 47
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν κret 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ Well-Formedness Constraint n : κn ⊢ κret
22
SLIDE 48
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν κret 0 ≤ ν , ⋆ ≤ ν, ν ≤ ⋆ Well-Formedness Constraint n : κn ⊢ κret SAT
22
SLIDE 49
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν κret 0 ≤ ν, ⋆ ≤ ν , ν ≤ ⋆ Well-Formedness Constraint n : κn ⊢ κret SAT
22
SLIDE 50
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν κret 0 ≤ ν, n ≤ ν , ν ≤ ⋆ Well-Formedness Constraint n : κn ⊢ κret SAT
22
SLIDE 51
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν κret 0 ≤ ν, n ≤ ν, ν ≤ ⋆ Well-Formedness Constraint n : κn ⊢ κret SAT
22
SLIDE 52
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν κret 0 ≤ ν, n ≤ ν, ν ≤ n Well-Formedness Constraint n : κn ⊢ κret SAT
22
SLIDE 53
Step 3: Solve Well-Formedness Constraints
Assignment Map A(κ) / Current Solution κn 0 ≤ ν κret 0 ≤ ν, n ≤ ν, ν ≤ n Well-Formedness Constraint ∅ ⊢ κn n : κn ⊢ κret
22
SLIDE 54
Step 3: Solve Subtyping Constraint
Subtyping-Constraint Γ ⊢ {ν : τ | P} <: {ν : τ | κx} Embedding (Γ ∧ P) = ⇒ q, q ∈ A(κx) Valid?1 Yes = ⇒ Keep q No = ⇒ Drop q
1Use SAT-Solver like Z3, Yices
23
SLIDE 55
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn 0 ≤ ν κret 0 ≤ ν, n ≤ ν, ν ≤ n Subtyping Constraint T1 <: T2: n : κn, ¬n < 0 ⊢ ν = n − 1 <: κn
24
SLIDE 56
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn 0 ≤ ν κret 0 ≤ ν, n ≤ ν, ν ≤ n Subtyping Constraint T1 <: T2: n : κn, ¬n < 0 ⊢ ν = n − 1 <: κn Embedding: 0 ≤ n ∧ ¬n < 0 ∧ ν = n − 1 = ⇒ q
24
SLIDE 57
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn 0 ≤ ν κret 0 ≤ ν, n ≤ ν, ν ≤ n Subtyping Constraint T1 <: T2: n : κn, ¬n < 0 ⊢ ν = n − 1 <: κn Embedding: 0 ≤ n ∧ ¬n < 0 ∧ ν = n − 1 = ⇒ 0 ≤ ν UNSAT: (If n = 0 then n − 1 = ⇒ ν < 0)
24
SLIDE 58
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn ✘✘
✘ ❳❳ ❳
0 ≤ ν κret 0 ≤ ν, n ≤ ν, ν ≤ n Subtyping Constraint T1 <: T2: n : κn, ¬n < 0 ⊢ ν = n − 1 <: κn Embedding: 0 ≤ n ∧ ¬n < 0 ∧ ν = n − 1 = ⇒ 0 ≤ ν UNSAT: (If n = 0 then n − 1 = ⇒ ν < 0)
24
SLIDE 59
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn κret 0 ≤ ν, n ≤ ν, ν ≤ n Subtyping Constraint T1 <: T2: n : κn, n < 0 ⊢ ν = 0 <: κret Embedding: n < 0 ∧ ν = 0 = ⇒ q
24
SLIDE 60
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn κret 0 ≤ ν , n ≤ ν, ν ≤ n Subtyping Constraint T1 <: T2: n : κn, n < 0 ⊢ ν = 0 <: κret Embedding: n < 0 ∧ ν = 0 = ⇒ 0 ≤ ν SAT
24
SLIDE 61
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn κret 0 ≤ ν, n ≤ ν , ν ≤ n Subtyping Constraint T1 <: T2: n : κn, n < 0 ⊢ ν = 0 <: κret Embedding: n < 0 ∧ ν = 0 = ⇒ n ≤ ν SAT
24
SLIDE 62
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn κret 0 ≤ ν, n ≤ ν, ν ≤ n Subtyping Constraint T1 <: T2: n : κn, n < 0 ⊢ ν = 0 <: κret Embedding: n < 0 ∧ ν = 0 = ⇒ ν ≤ n UNSAT
24
SLIDE 63
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn κret 0 ≤ ν, n ≤ ν, ✘✘✘
❳❳❳
ν ≤ n Subtyping Constraint T1 <: T2: n : κn, n < 0 ⊢ ν = 0 <: κret Embedding: n < 0 ∧ ν = 0 = ⇒ ν ≤ n UNSAT
24
SLIDE 64
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn κret 0 ≤ ν, n ≤ ν Subtyping Constraint T1 <: T2: n : κn, n < 0 ⊢ ν = 0 <: κret Embedding: n < 0 ∧ ν = 0 = ⇒ ν ≤ n UNSAT
24
SLIDE 65
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn κret 0 ≤ ν, n ≤ ν Subtyping Constraint T1 <: T2: n : κn, s : κret[n − 1/n], ¬n < 0 ⊢ ν = s + n <: κret Embedding: 0 ≤ s ∧ n − 1 ≤ s ∧ ¬n < 0 ∧ ν = s + n = ⇒ q
24
SLIDE 66
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn κret 0 ≤ ν , n ≤ ν Subtyping Constraint T1 <: T2: n : κn, s : κret[n − 1/n], ¬n < 0 ⊢ ν = s + n <: κret Embedding: 0 ≤ s ∧ n − 1 ≤ s ∧ ¬n < 0 ∧ ν = s + n = ⇒ 0 ≤ ν SAT (s ≥ 0, n ≥ 0)
24
SLIDE 67
Step 3: Solve Subtyping Constraint
Assignment Map A(κ) / Current Solution: κn κret 0 ≤ ν, n ≤ ν Subtyping Constraint T1 <: T2: n : κn, s : κret[n − 1/n], ¬n < 0 ⊢ ν = s + n <: κret Embedding: 0 ≤ s ∧ n − 1 ≤ s ∧ ¬n < 0 ∧ ν = s + n = ⇒ n ≤ ν SAT (s ≥ 0 = ⇒ s + n ≥ n)
24
SLIDE 68
Final Solution
Assignment Map A(κ) κn κret 0 ≤ ν, n ≤ ν Template sum :: n : {ν : int | κn} → {ν : int | κret} Liquid Type sum :: n : int → {ν : int | 0 ≤ ν ∧ n ≤ ν}
25
SLIDE 69
Conclusion
SLIDE 70
Conclusion
- Reveals the power of Dependent Types
- . . . without having the burden to write them down
- Supports
- Polymorphism
- Higher Order Functions
- Recursive Data Types
- Very well supported by Liquid Haskell
- Implementations for imperative languages exist [3], [4]
26
SLIDE 71
Further Resources
- Original Liquid Types Paper [2]
- Programming with Refinement Types [5]
27
SLIDE 72
Questions and Discussion
27
SLIDE 73
References I
- B. C. Pierce, Types and programming languages - the next
generation, 2003. [Online]. Available: http://www.cis.upenn.edu/~bcpierce/papers/tng- lics2003-slides.pdf (visited on 11/30/2016).
- J. Ranjit. (Jul. 2008), Liquid Types, [Online]. Available:
https://www.microsoft.com/en- us/research/video/liquid-types/ (visited on 10/28/2016).
SLIDE 74
References II
- P. Rondon, A. Bakst, M. Kawaguchi, and R. Jhala, “CSolve:
Verifying C with Liquid Types”, in Proceedings of the 24th International Conference on Computer Aided Verification, ser. CAV’12, Berkeley, CA: Springer-Verlag, 2012, pp. 744–750, isbn: 978-3-642-31423-0. doi: 10.1007/978-3-642-31424-7_59. [Online]. Available: http://dx.doi.org/10.1007/978-3-642-31424-7_59.
- P. Vekris, B. Cosman, and R. Jhala, “Refinement Types for
TypeScript”, SIGPLAN Not., vol. 51, no. 6, pp. 310–325, Jun. 2016, issn: 0362-1340. doi: 10.1145/2980983.2908110. [Online]. Available: http://doi.acm.org/10.1145/2980983.2908110.
SLIDE 75
References III
- R. Jhala, E. Seidel, and N. Vazou, Programming with
Refinement Types. 2016. [Online]. Available: https://ucsd- progsys.github.io/liquidhaskell-tutorial/book.pdf (visited on 09/28/2016).
SLIDE 76
Why does it Work
- Liquid Types are a small subset of Dependent Types
- Therefore, the solution space is much smaller
- The used implications are simple
- . . . and therefore, can be efficiently solved by (some) SMT
solvers
SLIDE 77
Why are Dependent Types not Inferable
if x = 0 then ... else ... Subtyping Constraint Tthen <: Tif Telse <: Telse Embedding (Env ∧ ν = 0) = ⇒ ????
- Qualifiers of Liquid Types can be enumerate
- The Qualifiers of Dependent Types not