Type Reconstruction for General Refinement Types Kenn Knowles - - PowerPoint PPT Presentation

type reconstruction for general refinement types
SMART_READER_LITE
LIVE PREVIEW

Type Reconstruction for General Refinement Types Kenn Knowles - - PowerPoint PPT Presentation

Type Reconstruction for General Refinement Types Kenn Knowles University of California, Santa Cruz joint work with: Cormac Flanagan (University of California, Santa Cruz) March 25, 2007 Assertions / Refinement Types The role of assertions in


slide-1
SLIDE 1

Type Reconstruction for General Refinement Types

Kenn Knowles

University of California, Santa Cruz joint work with: Cormac Flanagan (University of California, Santa Cruz)

March 25, 2007

slide-2
SLIDE 2

Assertions / Refinement Types 2

The role of assertions in axiomatic semantics

assert(x > 0) Is the role of “general” refinement types in type systems.

x : {n:Int | n > 0} Predicates are written in the language itself, and are thus also executable contracts on base types.

[Freeman-Pfenning 91, Hayashi 93, Denney 98, Davies-Pfenning 00, Dunfield 02, Mandelbaum et al 03, Ou et al 04]

slide-3
SLIDE 3

Checking Assertions / Refinement Types 3

assert(x > 0) λx : {n:Int | n > 0} x := x + 1 assert(x > 1) let x1 : {n:Int | n > 1} = x + 1 in x := x + 1 assert(x > 2) let x2 : {n:Int | n > 2} = x1 + 1 in x2 Check that x > 0 implies x + 1 > 1 implies x + 2 > 2

slide-4
SLIDE 4

Subtyping 4

3 : {n:Int | n > 0} ?

  • {n:Int | n = 3} <: {n:Int | n > 0} ?
  • n : Int ⊢ (n = 3) ⇒ (n > 0) ?
  • ∀n:Int. if n = 3 −

→∗ true then n > 0 − →∗ true Undecidable in general.

slide-5
SLIDE 5

Dependent types 5

To express pre- and postconditions //@requires(x ≥ 0) //@ensures(retval ≥ 0 ∧ retval ∗ retval − x ≤ 0.001) double sqrt(double x) We use dependent function types. sqrt : x : {r:double | r ≥ 0} → {y:double | y ≥ 0 ∧ y ∗ y − x ≤ 0.001} These are also executable as run-time checks.

[Augustsson 98, Xi-Pfenning 99, Findler-Felleisen 02, Ou et al 04]

slide-6
SLIDE 6

Hybrid Type Checking (HTC) 6

A strategy for enforcing undecidable type systems. e : T? − → HTC − →    × (no) e (yes) T e (maybe) Crucial idea: operational definition of implication links types with run-time checks.

[Flanagan POPL’06, Gronski et al SFP’06, Flanagan et al FOOL’06]

slide-7
SLIDE 7

Breakdown 7

First-Order Imperative Higher-order Functional Specs Assertions Loop Invariants, Pre/Postconditions Refinement Types Dependent Types Dynamic Contracts Type Casts Static Hoare Logic + Theorem Proving (Hybrid) Type Checking + Theorem Proving Automatic Inference Weakest Precond. Strongest Postcond. ??

slide-8
SLIDE 8

Type Reconstruction: Defined 8

Given a program with type variables,

Type reconstruction: Find a replacement of type variables such that the resulting program is well-typed.

i.e. determine if that program is typeable.

Typeability generalizes type checking, so it is definitely undecidable!

slide-9
SLIDE 9

Type Reconstruction: Redefined 9

Given a program with type variables,

Type reconstruction (take 2): Find a replacement of those type variables such that the resulting program is typeable if and only if the original program is.

Usefully generalizes the traditional definition when type checking is undecidable.

Equivalent to traditional definition when type checking is decidable.

slide-10
SLIDE 10

Basic Reconstruction 10

Some parts are easy:

Reconstruction of the underlying simple types unaffected by predicates. let id x = x in id 3

Ideas from type reconstruction with subtypes apply. [Mitchell 83, Fuh-Mishra 88, Aiken-Wimmers 93, Eifrig-Smith 95, Heintze 92, F¨

ahndrich-Aiken 96, Flanagan-Felleisen 97]

slide-11
SLIDE 11

Basic Reconstruction 10

Some parts are easy:

Reconstruction of the underlying simple types unaffected by predicates. let id (x : {n:Int | γ1}) = x in id 3 where (n = 3) ⇒ γ1

Ideas from type reconstruction with subtypes apply. [Mitchell 83, Fuh-Mishra 88, Aiken-Wimmers 93, Eifrig-Smith 95, Heintze 92, F¨

ahndrich-Aiken 96, Flanagan-Felleisen 97]

slide-12
SLIDE 12

Basic Reconstruction 10

Some parts are easy:

Reconstruction of the underlying simple types unaffected by predicates. let id (x : {n:Int | γ1}) : {n:Int | γ2} = x in id 3 where (n = 3) ⇒ γ1 and γ1 ⇒ γ2

Ideas from type reconstruction with subtypes apply. [Mitchell 83, Fuh-Mishra 88, Aiken-Wimmers 93, Eifrig-Smith 95, Heintze 92, F¨

ahndrich-Aiken 96, Flanagan-Felleisen 97]

slide-13
SLIDE 13

Predicate Reconstruction 11

Some parts are harder:

Lexical scope - na¨ ıve propagation according to dataflow paths will let variables escape their scope.

Dependent types - an implication constraint may be contingent upon particular values of program variables.

(Mutual) Recursion - causes cycles in the dataflow paths.

Our “logic” is the operational semantics of programs. Can it express all solutions?

slide-14
SLIDE 14

Example 12

let fact x = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

slide-15
SLIDE 15

Example 12

let fact (x : {n:Int | γ1}) = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

slide-16
SLIDE 16

Example 12

let fact (x : {n:Int | γ1}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

slide-17
SLIDE 17

Example 12

let fact (x : {n:Int | γ1}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

n : Int ⊢ (n = 3) ⇒ γ1 x : {n:Int | γ1}, n : Int ⊢ (n = x − 1) ⇒ γ1

slide-18
SLIDE 18

Example 12

let fact (x : {n:Int | γ1}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

n : Int ⊢ (n = 3) ⇒ γ1 x : {n:Int | γ1}, n : Int ⊢ (n = x − 1) ⇒ γ1 γ1 := (n = 3) ∨ (n = x − 1) ?

slide-19
SLIDE 19

Example 12

let fact (x : {n:Int | γ1}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

n : Int ⊢ (n = 3) ⇒ γ1 x : {n:Int | γ1}, n : Int ⊢ (n = x − 1) ⇒ γ1

  • n : Int ⊢ (ˆ

∃x : {n:Int | γ1}. n = x−1) ⇒ γ1

slide-20
SLIDE 20

Nondeterministic Existentials 13

Remember, our logic is operational semantics. ˆ ∃x : T. s − → [x := t] s whenever ⊢ t : T With this definition, the classic tautology still holds: x : T ⊢ p ⇒ q

  • ∀t : T. if [x := t] p −

→∗ true then q − →∗ true (x is not free in q)

  • if ˆ

∃x : T. p − →∗ true then q − →∗ true

  • ⊢ (ˆ

∃x : T. p) ⇒ q

slide-21
SLIDE 21

Example 14

let fact (x : {n:Int | γ1}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

n : Int ⊢ (n = 3) ⇒ γ1 x : {n:Int | γ1}, n : Int ⊢ (n = x − 1) ⇒ γ1

  • n : Int ⊢ (ˆ

∃x : {n:Int | γ1}. n = x−1) ⇒ γ1

slide-22
SLIDE 22

Example 14

let fact (x : {n:Int | γ1}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

n : Int ⊢ (n = 3) ⇒ γ1 n : Int ⊢ (ˆ ∃x : {n:Int | γ1}. n = x−1) ⇒ γ1

slide-23
SLIDE 23

Example 14

let fact (x : {n:Int | γ1}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

n : Int ⊢ (n = 3) ⇒ γ1 n : Int ⊢ (ˆ ∃x : {n:Int | γ1}. n = x−1) ⇒ γ1 γ1 := (n = 3) ∨ (ˆ ∃x : {n:Int | γ1}. n = x−1) ?

slide-24
SLIDE 24

Predicate functions 15

γ1 = (n = 3) ∨ (ˆ ∃x : {n:Int | γ1}. n = x − 1)

We desire a solution to the above equation.

Interpret γ1 as a function Fγ1 over fv(γ1) = {n : Int}

Fγ1 : Int → Bool

In the case of cycles, Fγ1 can be recursively defined.

slide-25
SLIDE 25

Predicate functions 15

γ1 = (n = 3) ∨ (ˆ ∃x : {n:Int | γ1}. n = x − 1)

The solution: Fγ1 n = (n = 3) ∨ (ˆ ∃x : {n:Int | Fγ1 n}. n = x−1)

Entirely a syntactic transformation.

Because our logic is very expressive!

As with weakest preconditions/strongest postconditions.

slide-26
SLIDE 26

Predicate functions 15

γ1 = (n = 3) ∨ (ˆ ∃x : {n:Int | γ1}. n = x − 1)

The solution: Fγ1 n = (n = 3) ∨ (ˆ ∃x : {n:Int | Fγ1 n}. n = x−1) = (n = 3) ∨ (n = 2) ∨ (ˆ ∃x. · · · ) = (n = 3) ∨ (n = 2) ∨ (n = 1) ∨ · · · = (n = 3) ∨ (n = 2) ∨ (n = 1) ∨ (n = 0) ∨ · · · = n ≤ 3

slide-27
SLIDE 27

Example 16

let fact (x : {n:Int | n ≤ 3}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

We always infer the strongest predicate

In this program, fact is applied to 3, 2, ...

hence “n ≤ 3”

slide-28
SLIDE 28

Example 16

let fact (x : {n:Int | n ≤ 3}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3 Path-insensitive:

· · · ⊢ (n = 1) ⇒ γ2 · · · ⊢ (n = (fact(x − 1)) ∗ x) ⇒ γ2

slide-29
SLIDE 29

Example 16

let fact (x : {n:Int | n ≤ 3}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3 Path-insensitive:

· · · ⊢ (n = 1) ⇒ γ2 · · · ⊢ (n = (fact(x − 1)) ∗ x) ⇒ γ2 Fγ2 x n = (n = 1) ∨ (ˆ ∃fact : (x′ : {n:Int | n ≤ 3} → {y:Int | Fγ2 x′ y}). n = (fact(x − 1)) ∗ x)

slide-30
SLIDE 30

Path Insensitive Example 17

Fγ2 x n = (n = 1)∨ (ˆ ∃fact : (x′ : {n:Int | n ≤ 3} → {y:Int | Fγ2 x′ y}). n = (fact(x − 1)) ∗ x) = (n = 1) ∨ (n = 2) ∨ (n = 3) ∨ (n = 0) ∨ · · · (n = −∞)∨ (ˆ ∃fact : (x′ : {n:Int | n ≤ 3} → {y:Int | Fγ2 x′ y}). n = (fact(x − 1)) ∗ x) = (n = −∞) ∨ · · · ∨ (n = ∞)∨ (ˆ ∃fact : (x′ : {n:Int | n ≤ 3} → {y:Int | Fγ2 x′ y}). n = (fact(x − 1)) ∗ x) = (n = −∞) ∨ · · · ∨ (n = ∞)

slide-31
SLIDE 31

Example 18

let fact (x : {n:Int | n ≤ 3}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

slide-32
SLIDE 32

Example 18

let fact (x : {n:Int | 1 ≤ n ≤ 3}) : {n:Int | γ2} = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3 Path-sensitive:

· · · ⊢ (x ≤ 1) ∧ (n = 1) ⇒ γ2 · · · ⊢ (x > 1) ∧ (n = (fact(x − 1)) ∗ x) ⇒ γ2 Fγ2 x n = [(x ≤ 1) ∧ (n = 1)] ∨ [ˆ ∃fact : (x′ : {n:Int | 1 ≤ n ≤ 3} → {y:Int | Fγ2 x′ y}). (x > 1) ∧ (n = (fact(x−1)) ∗ x)]

slide-33
SLIDE 33

Path Sensitive Example 19

Fγ2 x n = [(x ≤ 1) ∧ (n = 1)] ∨ [ˆ ∃fact : (x′ : {n:Int | 1 ≤ n ≤ 3} → {y:Int | Fγ2 x′ y}). (x > 1) ∧ (n = (fact(x−1)) ∗ x)] = [(x ≤ 1) ∧ (n = 1)] ∨ [(x > 1) ∧ (x−1 ≤ 1) ∧ (n = 2)]∨ [ˆ ∃fact : (x′ : {n:Int | 1 ≤ n ≤ 3} → {y:Int | Fγ2 x′ y}). (x > 1) ∧ (n = (fact(x−1)) ∗ x)] . . . = [(x ≤ 1) ∧ (n = 1)] ∨ [(x = 2) ∧ (n = 2)] ∨ [(x = 3) ∧ (n = 6)]

slide-34
SLIDE 34

Example 20

let fact (x : {n:Int | 1 ≤ n ≤ 3}) : {n:Int | · · · } = if (x ≤ 1) then 1 else (fact (x − 1)) ∗ x in fact 3

slide-35
SLIDE 35

Properties of our algorithm 21

Nice properties:

The output program is well-typed if and only if the input program is typeable.

We infer the most precise predicate for each refinement.

And they are correct by construction – they need never be inserted as runtime checks. Remaining work:

Automated simplification of inferred refinements.

Weakest predicates for contravariant positions.

More complex language features.

slide-36
SLIDE 36

Breakdown 22

First-Order Imperative Higher-order Functional Specs Assertions Loop Invariants, Pre/Postconditions Refinement Types Dependent Types Dynamic Contracts Type Casts Static Hoare Logic + Theorem Proving (Hybrid) Type Checking + Theorem Proving Automatic Inference Weakest Precond. Strongest Postcond. Strongest predicate reconstruction

slide-37
SLIDE 37

High-level Contributions 23

Type reconstruction (re)defined in a way that is more useful for undecidable type systems.

Type reconstruction solved for a basic calculus with types refined by arbitrary program terms.

Our algorithm achieves for higher-order functional programs what strongest postconditions achieves for first-order imperative programs.