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.