ISSN
02496399
apport
de recherche
THME 1
INSTITUT NATIONAL DE RECHERCHE EN INFORMATIQUE ET EN AUTOMATIQUE
Global abstractionsafe marshalling with hash types
James J. Leifer + Gilles Peskine + Peter Sewell # Keith Wansbrough #
+ INRIA Rocquencourt # University of Cambridge
{First.Last}@inria.fr {First.Last}@cl.cam.ac.uk
N 4851
25 June 2003
Unit de recherche INRIA Rocquencourt
Domaine de Voluceau, Rocquencourt, BP 105, 78153 Le Chesnay Cedex (France)
Tlphone : +33 1 39 63 55 11 --- Tlcopie : +33 1 39 63 53 30
Global abstractionsafe marshalling with hash types
James J. Leifer + Gilles Peskine + Peter Sewell # Keith Wansbrough #
+ INRIA Rocquencourt # University of Cambridge
{First.Last}@inria.fr {First.Last}@cl.cam.ac.uk
Th eme 1 --- R eseaux et syst emes
Projet Moscova
Rapport de recherche n 4851 --- 25 June 2003 --- 86 pages
Abstract: Type abstraction is a key feature of MLlike languages for writing large programs. Marshalling is necessary for
writing distributed programs, exchanging values via network bytestreams or persistent stores. In this report we combine
the two, developing compiletime and runtime semantics for marshalling, that guarantee abstractionsafety between
separatelybuilt programs.
We obtain a namespace for abstract types that is global, i.e. meaningful between programs, by hashing module dec
larations. We examine the scenarios in which values of abstract types are communicated from one program to another,
and ensure, by constructing hashes appropriately, that the dynamic and static notions of type equality mirror each other.
We use singleton kinds to express abstraction in the static semantics; abstraction is tracked in the dynamic semantics by
coloured brackets. These allow us to prove preservation, erasure, and coincidence results. We argue that our proposal
is a good basis for extensions to existing MLlike languages, pragmatically straightforward for language users and for
implementors.
Keywords: programming languages, ML, type theory, abstract types, marshalling, serialisation, modules, singleton
kinds, hashing, distributed programming, lambda calculus
S erialisation avec s
uret e globale des abstractions : utilisation des types de
hachage
R esum e : L'abstraction de types est un trait essentiel des langages de la famille ML pour ecrire les logiciels de taille
importante. La s erialisation est un ingr edient indispensable des programmes distribu es, de la transmission de valeurs
sur un r eseau, et du stockage persistant de donn ees. Dans ce rapport, nous combinons les deux, en d eveloppant des
s emantiques statique et dynamique de la s erialisation qui garantissent la s uret e des abstractions entre des programmes
d evelopp es s epar ement.
Nous obtenons un espace de nommage pour les types abstraits qui est global, c'est adire commun
a tous les pro
grammes, par hachage des d eclarations de modules. Nous examinons les sc enarios dans lesquels des valeurs de types abs
traits sont transmises entre les programmes ; nous garantissons que les notions statique et dynamique d' egalit e de types
co ncident gr ace a la construction de la fonction de hachage. Nous utilisons les singleton kinds pour exprimer les abs
tractions dans la s emantique statique ; ces abstractions sont suivies a la trace par des crochets color es dans la s emantique
dynamique. Cette m ethode nous permet de prouver les th eor emes de pr eservation, d'effacement, et de correspondance.
Nous proposons cette technique comme une base pour etendre les langages
a la ML, car elle est simple et pratique pour
l'utilisateur comme pour l'impl ementeur.
Motscl es : langages de programmation, ML, th eorie des types, types abstraits, marshalling, s erialisation, modules,
singleton kinds, hachage, programmation distribu ee, lambda calcul
Global abstractionsafe marshalling with hash types 3
RR n 4851
4 Leifer, Peskine, Sewell, Wansbrough
Contents
1 Introduction 6
2 Abstraction and interaction: the desired behaviour 7
2.1 Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Respecting types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3 Respecting abstractions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4 Communication between completelyshared sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.5 Communication between partiallyshared sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.6 Guaranteeing compatible invariants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.7 Respecting names (when necessary) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.8 Module dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.9 Mirroring local type sharing: manifest types, functors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.10 Breaking abstractions (simple bidirectional case) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.11 Breaking abstractions (directed case) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.12 Forcing generativity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.13 Effectful module initialisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.14 Marshalling functions and rebinding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3 Solution: hash types as global names 14
3.1 Simple examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.2 Module dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3 Abstractionpreserving reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.4 Modest implementation demands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.5 Lowlevel details of hashes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4 Formal system 18
4.1 Relation to the informal discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.2 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.3 Static and dynamic semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.3.1 Singleton kinds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.3.2 Hash formation, type equality of hashes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.3.3 Compiletime reduction and coloured brackets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.3.4 Expression reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.3.5 Marshalling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.3.6 Programs and networks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.4 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
5 Related work 23
6 Conclusions and future work 24
6.1 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
6.2 Future work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
A Introduction to the complete definitions and proofs 26
A.1 Differences between the main body and the appendices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
A.2 Correspondence between the theorems in the main body and in the appendices . . . . . . . . . . . . . . . . . . . . . 26
B Syntax 26
C Static judgements 29
C.1 # /
# domE nonclash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
C.2 # hm ok hash correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
C.3 E #hm ok environment correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
C.4 E #hm K ok kind correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
C.5 E #hm K == K # kind equality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
C.6 E #hm K <: K # subkinding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
C.7 E #hm T :K kind of a type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
C.8 E #hm T == T # type equivalence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
C.9 E #hm S ok signature correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
INRIA
Global abstractionsafe marshalling with hash types 5
C.10 E #hm S == S # signature equivalence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
C.11 E #hm S <: S # subsignaturing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
C.12 E #hm e:T type of an expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
C.13 E #hm M :S signature of a module expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
C.14 E #hm U :S signature of a module variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
C.15 E #hm m:T type of a machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
C.16 # n ok network correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
D Reduction rules and structural congruence 33
D.1 m -# c m # compiletime reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
D.2 e -#hm e # expression reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
D.3 n # n # network structural congruence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
D.4 n -# n # network reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
E General definitions and lemmas 34
E.1 Proofs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
E.2 Correctness of parts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
E.3 Variables and colours . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
F Type preservation by substitution 39
G Type decomposition and type preservation for reduction 52
H Progress 60
H.1 Classical progress theorems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
H.2 Determinism of reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
I Compilation 65
I.1 Decidability of type checking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
I.2 Bracket elimination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
J Coincidence of undyntime type checking and static type checking 76
K Table of theorems and definitions 82
References 85
RR n 4851
6 Leifer, Peskine, Sewell, Wansbrough
This technical report is a long version of the paper [LPSW03]: James J. Leifer, Gilles Peskine, Peter Sewell,
Keith Wansbrough. ``Global abstractionsafe marshalling with hash types''. Proc. 8th ICFP. 2003. (Available
from http://pauillac.inria.fr/~leifer/research.html.)
1 Introduction
Problem Type abstraction is a basic tool for modular programming, allowing the programmer to separate the interface
and the implementation of an abstract data type, and to limit the scope in which the implementation details are visible.
Work on MLstyle module systems, including [Mac84, MTH90, HL94, Ler94], has led to expressive language constructs
for controlling abstraction, with modules (structures) that can export abstract types, and also parameterised modules
(functors); they have rich notions of type equality to deal with generativity and sharing. This work has largely been in
the nondistributed context, concerned only with isolated executions of single programs. There, buildtime type checking
suffices to guarantee both typesafety and abstractionsafety --- the property that values of an abstract type can only be
inspected or constructed by the code of its definition, and hence that any invariants of this code hold of all values. At
runtime, type information can be erased.
In the distributed setting, abstractionsafety is more subtle. One may need to exchange values between multiple
executions of the same build, between executions of different builds of the same sources, and between executions of builds
of different sources (sharing some modules, perhaps, but not all). This interaction might be by network communication
or via a persistent store; in either case, some runtime check is clearly needed to guarantee safety. For abstractionsafety,
it does not suffice to check only the underlying representation type; intuitively, we need also that the sender and receiver
have compatible invariants. This can be enforced by requiring that they have the same code, but in general, where there is
only partial sharing, we shall see that the design of an appropriate check is delicate.
We focus in particular on language support for marshalling a value to a byte string and unmarshalling such strings
back to values. With these, one can implement a variety of useful mechanisms above the standard (bytestring) primitives
for network communication and persistence. For example: (1) In the existing distributed languages JoCaml [JoC] and
Nomadic Pict [SWP99] a single program can dynamically distribute computations, which can then interact via typed
channels, but unsafe ``name servers'' are required to bootstrap connections between programs. Type and abstraction
safe marshalling would enable such name servers to be expressed in a safe way. (2) More generally, safe marshalling
would enable one to code up a variety of communication abstractions, such as typed channels with differing behaviour
(asynchronous, unicast, multicast,. . . ), within a highlevel language; they would then be automatically guaranteed to be
safe.
Contribution We present a type system and semantics (both compiletime and runtime) for marshalling and unmar
shalling values between separate programs. Our solution:
. covers modules that declare abstract types, and ancillary typesharing constraints;
. involves a dynamic typecheck at unmarshal time that guarantees both typesafety and abstractionsafety;
. ensures the resulting dynamic notion of type equality coincides with the usual static notion, so that distributed pro
gramming is a smooth extension of local programming;
. ``just works'' in standard cases for interaction between programs that share some modules, without requiring any shared
data beyond the source code for these modules;
. supports controlled abstractionbreaking, where required; and
. is efficiently implementable.
It is therefore a good basis for extensions to existing MLlike languages, pragmatically straightforward for language users
and for implementors.
Approach The basic idea of our solution is to construct a global namespace for abstract types, meaningful across all
programs, by hashing module declarations. Hash types do not appear in source programs, but are constructed at compile
time. For example, consider a module called N with the body struct type t=Trep let x=... end and the published
interface sig type t val x:... end. The hash h =
hash(module N=struct type t=Trep let x= ... end
: sig type t val x: ... end, t)
INRIA
Global abstractionsafe marshalling with hash types 7
would be constructed to give a runtime analogue of the compiletime abstract type name N.t. By constructing hashes
carefully, we ensure that a simple runtime syntactic type equality check, at unmarshaltime, corresponds to the compile
time notion of type equivalence used in typechecking.
The standard operational semantics for existentials forgets abstraction. In contrast, we give a runtime semantics that
records which subterms can see through which abstractions using coloured brackets, adapting a device of [GMZ00]. For
example, within the code of N.x, even after it has been substituted into its usage sites, the type equality h ==Trep can be
used. This enables us to prove type and abstractionpreservation, progress, and the coincidence result mentioned above.
We prove also that an implementation may safely erase all coloured brackets outside hashes at runtime.
Nongoals Our focus in this report is on what mechanisms are required to guarantee abstractionsafety. We do not
address the full ML language; instead, we focus on a core language based on simplytyped #calculus with abstract and
manifest modules, although we argue that our formal system may be cleanly extended. Dynamic rebinding of identifiers
within marshalled values is considered in [BHS + 03]. Moreover, we are not here concerned with lowlevel representations
of marshalled values; we assume some fixed scheme for marshalling simplytyped values. Finally, we protect against
confusion, not malice.
Outline We begin in Section 2 by examining scenarios in which values of abstract types are communicated between
programs, identifying the desired constructs and behaviour from the programmer's point of view. Section 3 outlines our
solution informally, shows why it provides the desired behaviour, and shows it can be implemented efficiently. In Section 4
we present a formal calculus, # hash , that covers the novel aspects of our solution. It describes networks of interacting
separatelybuilt modular programs. In Section 5 and Section 6 we discuss related and future work and conclude.
2 Abstraction and interaction: the desired behaviour
In this section we discuss the desired behaviour of marshalling in a distributed setting, with a series of informal examples
in an MLlike language. Our solution, in the following section, shows how this ideal can be achieved.
We consider an MLlike language in which a program consists of two parts: first a sequence of module declarations,
each of which can introduce abstract types; then an expression (the main body of the program). We are concerned with
interaction between whole programs, usually built separately. This interaction is via network communication, though
it could equally be via a persistent store; in either case, the underlying mechanism simply transmits byte strings. For
concreteness, most of our examples involve networks consisting of two machines, pauillac and glia, running programs,
say Pa and Pb . These network configurations are written pauillac[Pa ] | glia[Pb ]. It then suffices to consider a single
communication channel (such as a TCP connection between fixed ports); the language has communication primitives
send : string>unit receive : unit>string
We can now explore the desired behaviour of marshal(e :T ) and unmarshal(e :T ), which marshal to and from string.
2.1 Communication
The simplest example is that of sending a value of a nonabstract type between separatelybuilt programs. Consider the
two programs
P1a = send (marshal (5 : int))
P1b = print_int (unmarshal (receive ():int))
If these are built and then executed on the two machines the communication and unmarshal should succeed:
pauillac[P1a ] | glia[P1b ] #
2.2 Respecting types
On the other hand, if one machine sends a string that the other attempts to unmarshal as an int there should obviously
be a runtime failure.
RR n 4851
8 Leifer, Peskine, Sewell, Wansbrough
P2a = send (marshal ("five":string))
P2b = print_int (unmarshal (receive ():int))
pauillac[P2a ] | glia[P2b ]
To ease debugging, it is desirable for that failure to occur as early as possible (at unmarshaltime rather than when the
string is used later) and to be trapped cleanly, raising an exception rather than giving unpredictable behaviour. The
implementation must therefore send some form of type representation. The following examples explore the constraints
on what this must be.
2.3 Respecting abstractions
Now consider an example with an abstract type. Here the EvenCounter module declares a type EvenCounter.t which
has a representation type of int but externally is abstract, as declared in its signature. The operations of EvenCounter
enforce the invariant that values of EvenCounter.t are always represented by even integers. If we allowed an arbitrary
integer to be unmarshalled as an EvenCounter.t then the abstraction, and this invariant, would be broken; the unmarshal
should therefore fail.
P3a = send (marshal(5:int))
P3b = module EvenCounter =
struct sig
type t=int type t
let start=0 : val start:t
let get x = x val get:t>int
let up x = x+2 val up:t>t
end end
print_int (EvenCounter.get
(unmarshal (receive ()):EvenCounter.t))
pauillac[P3a ] | glia[P3b ]
Marshalling from a different abstract type --- say a TripleCounter.t --- to EvenCounter.t should fail similarly.
2.4 Communication between completelyshared sources
For communication between two instances of the same build, which therefore have identical source code, the problem is
relatively simple. Below, P4 declares an abstract type IntSet.t of sets of integers, representing them as binary search
trees. It makes a runtime determination of which machine it is on and then sends or receives an IntSet.t; the unmarshal
should succeed. We will develop this example later --- suppose this first implementation orders subtrees by <, and has a
union operation that does not remove duplicate entries.
INRIA
Global abstractionsafe marshalling with hash types 9
P4 =
module IntSet =
struct
type t = int tree
let singleton = singletoncode
9 > > > > > = > > > > > ;
IntSetStruct
let mem = memcode
...
end : sig
type t
val singleton : int > t
val mem : int > t > bool
9 > > > > > > > > > = > > > > > > > > > ;
IntSetSig
val empty : t
val add : int > t > t
val union : t > t > t
end
if ...onmachinepauillac... then
send (marshal (IntSet.singleton 17 : IntSet.t))
else
if IntSet.mem 17 (unmarshal(receive():IntSet.t))
then print "y" else print "n"
pauillac[P4 ] | glia[P4 ] #
By default this should still succeed even if the two machines execute different builds of the same source.
2.5 Communication between partiallyshared sources
More generally, one may need communication between programs which share only some modules (perhaps ubiquitous
standard libraries, or applicationspecific libraries). Here P5a and P5b share the IntSet module from before, but other
wise have different module declarations and main body expressions; their communication of an IntSet.t should succeed.
P5a =
module IntSet = IntSetStruct :IntSetSig
send (marshal (IntSet.singleton 17 : IntSet.t))
P5b =
module IntSet = IntSetStruct :IntSetSig
module M =
struct let haszero x = IntSet.mem 0 x end
: sig val haszero : IntSet.t > bool end
if M.haszero (unmarshal (receive () : IntSet.t))
then print "y" else print "n"
pauillac[P5a ] | glia[P5b ] #
2.6 Guaranteeing compatible invariants
In the previous example the two programs had syntactically identical IntSet implementations. Since IntSet does not
depend on any other modules, this is a sufficient condition to guarantee that the two abstract types have compatible
invariants, i.e. that any value of either will be correctly acted upon by the operations of the other. Moreover, it can be
automatically checked, whereas compatibility of invariants cannot even be stated without specifing the behaviour of the
two modules, and would then require general theoremproving to verify. Note that it would not be sufficient to require that
the two implementations use the same representation type, or even to require that the implementations are (in the absence
of marshalling) observationally equivalent.
For example, suppose that IntSetStructGt is similar to IntSetStruct but orders subtrees with > rather than <.
RR n 4851
10 Leifer, Peskine, Sewell, Wansbrough
P6a =
module IntSet = IntSetStructGt :IntSetSig
send (marshal (IntSet.add 0 (IntSet.add 1 (IntSet.add 2 IntSet.empty)) : IntSet.t))
When communicating with P5b , which contains the original IntSetStruct , the unmarshal should fail, as otherwise
an erroneous result could be produced.
pauillac[P6a ] | glia[P5b ]
Later we shall see that a mechanism for intentionally circumventing this restriction, in a controlled way, is sometimes
desirable.
2.7 Respecting names (when necessary)
In some cases one has modules with identical implementations that nonetheless provide conceptually different abstract
types, for example in the Euro and Pound modules below. Unmarshalling should respect this difference, so the example
should fail (just as, within a single ML program, types Euro.t and Pound.t would be incompatible).
P7a =
module Euro =
struct type t=int let of_int x = x ... end
: sig type t val of_int : int > t ... end
send (marshal (Euro.of_int 17 : Euro.t))
P7b =
module Pound =
struct type t=int let of_int x = x ... end
: sig type t val of_int : int > t ... end
unmarshal (receive (): Pound.t)
pauillac[P7a ] | glia[P7b ]
This restriction is not always useful (e.g. whether an integer set module is called IntSet or Set Int is likely irrelevant),
so the language should support some syntactic way of indicating whether a module name is significant or not.
2.8 Module dependencies
Consider now modules that depend on abstract types declared by other modules. In P8a below there is a module IntSet,
providing an abstract type IntSet.t, followed by a module SummedIntSet, providing an abstract type of sets of integers
augmented with a running sum. The expression part constructs, marshals and sends a value of the SummedIntSet.t
abstract type. This SummedIntSet depends on IntSet in three ways: (1) IntSet.t occurs in its representation type
IntSet.t # int; (2) IntSet.t occurs in the type of an operation in its signature; and (3) operations from IntSet occur
in the definitions of its operations. Any such dependency means that substantive changes to the definition of IntSet
must propagate through to give distinct SummedIntSet.t types. On the other hand, any module declarations that are not
(transitively) depended upon should have no effect on SummedIntSet.t.
For example, consider also P8b below. It has exactly the same text as SummedIntSet but a different implementation of
IntSet --- suppose IntSetStruct' has a different representation type from IntSetStruct , or the same representation
but incompatible invariants, or different externallyobservable behaviour. The P8a and P8b SummedIntSet.t types
should be incompatible, so the unmarshal should fail.
INRIA
Global abstractionsafe marshalling with hash types 11
P8a =
module IntSet = IntSetStruct :IntSetSig
module SummedIntSet =
struct
type t = IntSet.t * int
let empty = (IntSet.empty,0)
let sum (x,y) = y
...
end : sig
type t
val empty : t
val singleton : int > t
val sum : t > int
val to_intset : t > IntSet.t
...
end
send(marshal((SummedIntSet.singleton 2)
: SummedIntSet.t ))
P8b =
module IntSet = IntSetStruct ':IntSetSig
module SummedIntSet = ...same text as above...
SummedIntSet.sum
(unmarshal (receive () : SummedIntSet.t))
pauillac[P8a ] | glia[P8b ]
2.9 Mirroring local type sharing: manifest types, functors
The examples in this and subsequent subsections are not covered by the formal calculus of Section 4. Nonetheless we
argue informally in Section 6.2 how they can be treated by straightforward extensions of our main techniques and earlier
work.
ML module systems include parametric modules, known as functors, for largescale software structuring and code
reuse. In the singleprogram world there are a number of subtle typeequality issues, related to how generative functors
are, and how one can express type sharing constraints [MTH90, Ler94, HL94, SH00]. Our marshalling primitives should
correctly reflect these subtleties in interprogram communication.
For example, the module SummedIntSet above, which explicitly references IntSet, might be reexpressed in terms
of a functor F which takes any argument structure U with interface IntSetSig and builds a SummedIntSet:
module IntSet = IntSetStruct :IntSetSig
module F = functor (U:IntSetSig ) >
struct type t=U.t*int ... end
: sig type t ... end
module SummedIntSet = F(IntSet)
The functor F generates an abstract type, so we must consider when that type should be compatible with others. If two
separate programs contain this preamble, they should be able to exchange values of their respective SummedIntSet.t
types. This mirrors the behaviour of OCaml's applicative functors [Ler95], in which another instance of the application
F(IntSet) within the same program would have a type compatible with SummedIntSet.t.
Should the functorised and nonfunctorised (P8a ) SummedIntSet.t be compatible? Again following existing module
systems, we should make them incompatible, as otherwise static type equality would depend on module substitution.
Type sharing allows functors to express type equalities between their argument and result; unmarshalling should
respect these static type equalities. The example F' below constructs a type t but, in contrast to F, does not make that
type abstract; instead it makes it manifestly equal to the product of its argument type U.t and int.
RR n 4851
12 Leifer, Peskine, Sewell, Wansbrough
module F' = functor (U:IntSetSig ) >
struct type t=U.t*int ... end
: sig type t=U.t*int ... end
The application of F' to a module IntSet creates a static type equality F'(IntSet).t==IntSet.t*int, which
should also be admitted at runtime.
2.10 Breaking abstractions (simple bidirectional case)
In ongoing software evolution, implementations of an abstract type may need to be changed, to fix bugs or add function
ality, while values of that type exist on other machines or in a persistent store. It is often impractical to simultaneously
upgrade all machines to a new implementation version.
A simple case is that in which the representation of the abstract type is unchanged and where the programmer asserts
that the two versions have compatible invariants, so it is legitimate to exchange values in both directions. This may be the
case even if the two are not identical, e.g. for an efficiency improvement or bug fix. Here there should be some mechanism
for forcing the old and new types to be identical, breaking the Section 2.6 restriction.
For example, consider the improved IntSetStructDeDup implementation below, in which the operations are sim
ilar to IntSetStruct , the only difference being that union removes duplicates. The compiler cannot verify that
IntSetStructDeDup has all the semantic properties that the programmer requires of IntSetStruct . Hence we provide
a way of explicitly declaring that these modules provide compatible types. In P10a below, IntSet'.t is made equal to
IntSet.t by the strong coercion ...with t =! IntSet.t. The compiler checks only that the old and new types have
compatible representations (here int tree), but should respect further abstractions within those representation types.
This is based on our earlier work of [Sew01].
P10a =
module IntSet = IntSetStruct :IntSetSig
module IntSet' =
struct
type t = int tree
9 > > = > > ;
IntSetStructDeDup
...improved operations...
end
: IntSetSig with t =! IntSet.t
send (marshal (IntSet'.singleton 17 : IntSet'.t))
P10b =
module IntSet = IntSetStruct :IntSetSig
if IntSet.mem 0 (unmarshal(receive():IntSet.t))
then print "y" else print "n"
pauillac[P10a ] | glia[P10b ] #
2.11 Breaking abstractions (directed case)
In the more complex case where the old and new invariants are not compatible, or where the two representation types
differ, the programmer will have to write an upgrade function. The same strong coercion can be used to make this possible.
For example, suppose we have a program that uses stored values of IntSetStruct and we wish to upgrade both the
implementation and the stored values, changing the representation type from binary search trees to redblack trees. The
new implementation would have a module declaration:
INRIA
Global abstractionsafe marshalling with hash types 13
module IntSet2 =
struct
type t = int rbtree
9 > > = > > ;
IntSetStructRBT
...
end
: IntSetSig
A program to upgrade the stored values can be expressed as below, with an Upgrade module that has both types, coerced
respectively to be equal to the old and new abstract types. (We are not proposing machinery to automatically apply the
upgrade function.)
module IntSet = IntSetStruct :IntSetSig
module IntSet2 = IntSetStructRBT : IntSetSig
module Upgrade =
struct
type t1 = int tree
type t2 = int rbtree
let upgrade = ...
end : sig
type t1
type t2
val upgrade : t1 > t2
end
with t1 =! Intset.t and t2 =! Intset2.t
...map Upgrade.upgrade over the stored values...
Note that the coercion does not require the signature of Upgrade to coincide with those of IntSet and IntSet2. The
compiler only checks that IntSet.t is represented by int tree and IntSet2.t by int rbtree.
2.12 Forcing generativity
Dually, sometimes it is desirable to force a type change between builds even when the code remains identical, to prevent
confusion between old and new communicated values. For example, one may have several distributed deployments of the
same application which should be kept logically isolated.
2.13 Effectful module initialisation
In our previous examples the components of modules are all values. Generalising this to arbitrary expressions (as ML
does), an abstract type definition can be dependent on some computation with side effects.
For example, consider an NCounter module that reads its step value from standard input when initialised; the invariant
of any instance is then that any value of its NCounter.t is a multiple of this step. Two instances of the module can
obviously have different invariants, and so marshalling from one to another should fail. Thus each run of a program
containing NCounter should have an incompatible type NCounter.t.
2.14 Marshalling functions and rebinding
In this report we deal only with marshalling of closed values; the semantics ensures that all module and expression
declarations are substituted in before a marshal operation takes place. Marshalling of functions is therefore semantically
straightforward.
A full language should, however, provide some form of dynamic rebinding of identifiers when they are unmarshalled,
both to achieve the desired semantics where local resources have different behaviour in different contexts, and for per
formance reasons where much code is shared (and so should not be communicated). The paper [BHS + 03] addresses
dynamic rebinding, in the absence of type abstraction.
RR n 4851
14 Leifer, Peskine, Sewell, Wansbrough
3 Solution: hash types as global names
This section introduces our solution informally, from both implementation and semantic viewpoints.
As we have seen, typesafe and abstractionsafe unmarshalling requires some runtime type representation in mar
shalled values, to permit a dynamic type comparison.
Our solution is based on the observation that hashing module definitions provides a global namespace for abstract
types: if an identical module is hashed during builds of two different programs at different sites, the same hash will be
obtained. Thus the programs share names for any abstract type provided they share the source code of the module that
declares the type (and of its dependencies); no communication (e.g. of GUIDs) is needed at build time.
We regard hashes literally as types --- hashes appear as a clause in the type grammar. They do not appear in source
programs, but are inserted during compilation; as we shall see in more detail, the compiler replaces occurrences of an
abstract type such as IntSet.t by the hash of the definition of IntSet that is in scope. Semantically, we work with
ideal hashing, with a formal syntactic construction hash(...). Implementations would realise this with an actual hash
function; we discuss the lowlevel properties of hashes in Section 3.5.
At runtime, after this compiletime type substitution, the types in marshal(e :T ) and unmarshal(e :T' ) are
closed, without free module identifiers or type variables. They can therefore be easily represented as byte strings, com
municated across the network or stored in a persistent store, and can be compared with simple string equality.
We ensure that this dynamic equality precisely mirrors the static notion of provable type equality by carefully tuning
the way in which hashes are generated and used; we show below that our system achieves this. Unmarshalling is therefore
not only typesafe, but also abstractionsafe.
The standard operational semantics for abstract types forgets about abstraction as computation proceeds, substituting
in representation types and operations. Here, in contrast, we need a runtime semantics that maintains abstraction through
out, both (1) so that our type preservation theorems tell us that abstractions are not broken; and (2) to support the proof
that static and dynamic type equality coincide. After a module is reduced away, module code (which may see through
the abstract type of that module) is intermixed with body code (which must treat the type as abstract). We therefore use
a syntactic construct, coloured brackets, adapted from the work of [GMZ00], to delimit the regions in which different
type equivalences hold. This is not purely a proof technique, however: in some subtle cases the coloured brackets within
hashes are needed in compiletime hash generation to correctly distinguish abstract types that would otherwise be aliased.
We show that implementations can erase coloured brackets outside hashes after compilation.
3.1 Simple examples
We illustrate the use of hashes in a simple case by referring back to the example of Section 2.4, in which a single
program, P4 , was built and run on the two machines. The build process is modelled in our semantics by typechecking,
as usual, followed by reductions that substitute out module definitions, inserting hashes as required. Hash generation is
deterministic, and hence the result of building P4 on the two machines is identical. The program has a single module
definition. It has a compiletime reduction as below, to an `executable' P4' . (Note that for clarity of exposition, we
omit coloured brackets from all reductions until Section 3.3; the example reductions as stated are not all typepreserving
without them.)
P4 =
module IntSet = IntSetStruct :IntSetSig
if ...onmachinepauillac... then
send (marshal (IntSet.singleton 17 : IntSet.t))
else
if IntSet.mem 17 (unmarshal(receive():IntSet.t))
then print "y" else print "n"
-# c (compilation)
if ...onmachinepauillac... then
send (marshal (singletoncode 17 : h ))
else
if memcode 17 (unmarshal (receive () : h ))
then print "y" else print "n"
= P4'
INRIA
Global abstractionsafe marshalling with hash types 15
where
h = hash(module IntSet=IntSetStruct :IntSetSig,t).
Here the definitions of IntSet.singleton and IntSet.mem have been substituted for their occurrences, and the
global name h has been substituted for type IntSet.t. Notice that h is constructed from the entire definition of IntSet,
including the textual name IntSet, the implementation structure IntSetStruct , the interface IntSetSig , and the type
field name t. In this simple example IntSet has no dependencies, so one can think of hashing its source text; we will
discuss later the more interesting case of modules with dependencies, and also the question of exactly what form the hash
function takes. Our liberal use of substitution is, of course, a semantic device --- in practice compilation would use other
representations.
At runtime, the two machines pauillac and glia execute their independentlycompiled copies of P4' . Their shared
knowledge of the hash h acts as a certificate that they may safely share values of their respective abstract types IntSet.t
and IntSet.t.
pauillac[P4' ] | glia[P4' ]
-# # (local computation on pauillac and glia)
pauillac[send(marshal(singletoncode 17:h ))]
| glia[if memcode 17 (unmarshal(receive():h ))
then print "y" else print "n"]
-# # (local computation on pauillac, to get v )
pauillac[send(marshalled( v :h ))]
| glia[if memcode 17 (unmarshal(receive():h ))
then print "y" else print "n"]
-# (communication)
pauillac[ () ]
| glia[if memcode 17 (unmarshal(marshalled(v :h ):h ))
then print "y" else print "n"]
-# (on glia: dynamic type check h =h , succeeds)
pauillac[ () ]
| glia[if memcode 17 v
then print "y" else print "n"]
-# # (on glia: computation, prints "y")
pauillac[ () ] | glia[ () ]
Ultimately, only strings may be communicated across a network. The notation marshalled (v :T ) denotes a string
literal containing representations of value v and its type T . This is only meaningful, and only used, where v and T are
both closed.
Notice that the dynamic check is simple: just that the type h sent from pauillac is identical to the type h written into
the unmarshal on glia at compile time. Yet, by virtue of the construction of these hashes, this is sufficient to guarantee
both typesafety and abstractionsafety.
Consider now the programs of Section 2.1--2.7. How do hashes of modules provide the desired behaviour? In the case
of concrete types, the comparison is obvious. For P1 , int=int; for P2 , string #=int; for P3 , for no hash h do we have
int=h . As we have already seen, in the P4 case the two programs share an identical hash h . For P5 , in P5a and P5b
the computed hash h for IntSet.t is identical (in fact the same h as above). Thus the h substituted for IntSet.t in
P5a 's call to marshal will be identical to that in P5b 's call to unmarshal, and the communication will again succeed,
exactly as we desire.
Although P6a (Section 2.6) contains a type IntSet.t, it is clear that the hash h' of the modified module IntSet
differs from the hash h of the original module, correctly reflecting the difference in the modules' behaviour. The two
programs will, correctly, be unable to communicate; an exception will be raised at the point of the unmarshal.
The example of Section 2.7 shows why one might wish the textual name (in general, the path) of a module to be
included in its hash, along with the module body. The two modules Euro and Pound are identical in all but name, and so a
hash that did not include the name would treat them as interchangeable, clearly leading to dangerous economic confusion,
and furthermore differing from the usual semantics of MLlike languages. On the other hand, the programmer should also
be able to specify that a name is not to be considered part of the module's identity. This can be done simply by having an
additional form of module declaration, module* N = ... , for which hashing uses a canonical name *, not admissible
RR n 4851
16 Leifer, Peskine, Sewell, Wansbrough
in source programs, instead of the actual name N. In this simple scheme both sender and receiver must use the *'d form,
of course.
3.2 Module dependencies
The example of Section 2.8 shows that the same module text defines a different abstract type if its dependencies change,
which means that the hash of a module must depend on the hashes of its dependencies. In our substitutive reduction
semantics, type dependencies are handled automatically: we have substituted hashes for any types of earlier modules
before constructing the hash of a module that depends on them. We shall see how term dependencies are also automatically
taken into account. Consider the following (a simplification of P8a ):
module A=struct type t=bool let x=true end
: sig type t val x:t end
module B=struct type t=A.t*int let x=(A.x,3) end
: sig type t val x:t end
send (marshal (B.x : B.t))
-# c (compilation)
module B=struct type t=h *int let x=(true,3) end
: sig type t val x:t end
send (marshal (B.x : B.t))
-# c (compilation)
send (marshal ((true,3) : h' ))
where
h = hash (
module A=struct type t=bool let x=true end
: sig type t val x:t end,t)
h' = hash (
module B=struct type t=h *int let x=(true,3) end
: sig type t val x:t end,t)
Here the hash h' for B is constructed after the hash h for A has been substituted for A.t, and after the term part true has
been substituted for A.x. It is clear that if A changed, h would change, and so h' would change. This would still be true
in the (unlikely) case that B mentions A.t but not A.x.
We must also ensure h' depends on h in the (common) case that B mentioned A.x but not A.t, i.e. where A is used in
B only to implement an internal computation. The coloured brackets of the following section will conveniently suffice for
this.
3.3 Abstractionpreserving reduction
Some reductions in Section 3.1, 3.2 require nonstandard type equalities to make them typepreserving. For example,
to type the intermediate state in Section 3.2 we must have (true,3) of type h *int, hence we need a type equality
identifying h with its representation type bool.
We could allow this type equality to be used anywhere, but instead prefer to delimit more precisely which
subterms can see through any particular abstraction. We introduce coloured brackets, adapted from the work of
[GMZ00], during module reduction. In the previous example, the first reduction will actually replace (A.x, 3)
by ([true] h
h ,3) instead of just (true,3). The brackets serve two purposes. First, the lower annotation (the
colour) is a hash h , indicating that the additional type equivalence h == bool is available when typing the in
side of the bracketed expression. This equivalence is drawn from the structure of h , viz. h =hash(module A=
struct type t=bool...end:...,t). Thus, inside the brackets we have true:h . Second, the upper h annotation
is the type of the bracketed expression as seen from the outside, thus reduction is type preserving. (One would often have
a more complex type in the upper annotation, not just a hash, e.g. [(true,3)] h *int
h .)
The reduction semantics of our formal system moves brackets around as required to ensure that abstraction is preserved
throughout reduction, and so our type preservation result (Theorem 4.1) covers abstraction. If we did not use brackets but
INRIA
Global abstractionsafe marshalling with hash types 17
allowed hash type equalities to be used freely, abstraction would become invisible after reduction. The use of brackets also
simplifies the statement of our result relating static and dynamic type equality (Theorem 4.7). Moreover, when compiling
a module that refers to a term field of a previous one, the presence of brackets ensures that the hash of the later module
does indeed depend on the hash of the earlier module.
3.4 Modest implementation demands
Few changes are required in an MLlike language to support the strategy outlined above.
Theorem 4.5 shows that type checking is decidable and that hashes play no role in compiletime typechecking of
source code. In particular, we can use traditional type checking and inference algorithms essentially unchanged. Compile
time reduction only builds hashes, without ever looking inside one. Runtime reduction only ever compares hashes by
string equality.
Theorem 4.6 shows that almost all coloured brackets and type information can be erased before runtime, with the
exception of course of marshal and unmarshal type annotations, and brackets within hashes.
MLlike languages usually support separate compilation of modules. Typically, a compilation phase takes a mod
ule and the signatures of the modules it imports and generates code parameterised by these dependencies. For # hash ,
the compilation phase would also generate a hash parameterised by the hashes of the imported modules, in other words
a hashtohash function. An appropriate compositional implementation of hashing must be used to make these effi
ciently representable. Typically, linking instantiates the parameterised code with jumps to the code of previous modules.
For # hash , the linking phase would do two further things. First, it would patch the type annotations for marshal and
unmarshal in the code by replacing references to module types by their hashes. Second, it would calculate the hash of
the module by applying the hashtohash function (generated by compilation) to the hashes of previous modules.
3.5 Lowlevel details of hashes
In our semantics, we work with ideal hashing, taking a free constructor hash(...) which can be applied to elements
of the abstract syntax. We can think of hash as a function whose injectivity guarantees abstractionsafety. To avoid
communicating large quantities of source code, an implementation would reify hash with a fixedlength hash function,
giving a safety guarantee that is only as strong as the probability of the absense of collisions.
This must be chosen so that (1) collisions are rare, and (2) hashes are not too costly to compute.
Both MD5 (RFC1321, 128bit) and SHA1 (RFC3174, 160bit) are sufficiently cheap, and may be considered random
functions for this application [Rob96]. Let us consider the likelihood of collisions. For n abstract types and N possible
hash values, the probability of a collision is approximately n 2 /2N . Pessimistically assuming 10 10 programmers in the
world, writing 300 lines of code per day with one abstract type per 100 loc, the probability of a collision in a century of
abstract types (using MD5) would then be (10 15 ) 2 /2 129
# 10 -9 . This is much less than the probability of a cosmicray
induced processor error in this period.
It may be desirable to have an absolute guarantee of typesafety, while accepting probabilistic abstractionsafety. To
achieve this, one could pair hashes with the corresponding underlying representation types. At the other extreme, one
could accept a probabilistic guarantee even at simple types, by sending only a hash of the marshalled type. These choices
must depend on a risk assessment.
Note that our proposal is aiming to protect only against accidental errors during programming and software deploy
ment, not against malicious attack, and so we are not concerned with deliberate searches for collisions. Protecting against
spoofed messages requires largely orthogonal techniques, e.g. message signatures and/or encryption, that are not in the
scope of this report. Moreover, we do not address the problem of communication between untrusting peers, where one
must check not just that the type advertised by the peer is compatible with the local type, but also the validity of the byte
string's claim to represent a value of the advertised type (see, e.g., [PS00]).
We hash elements of the abstract syntax, not concrete syntax, for two reasons. Firstly, it ensures hashes are not
dependent on, e.g., the choice of newline or newline/CR, or on comments. Secondly, it fits well with the rest of the
semantics --- recall we must calculate hashes of modules that are the results of module substitutions. In practice optimised
calculations would be possible, without requiring the explicit construction of canonical representatives of abstract syntax
elements.
Hashing abstract syntax, which we take up to alphaequivalence, has the (benign) consequence that abstract type
equality is not dependent on the names of function parameters. We have both internal (alphaconvertible) and external
module names in the semantics; external names must be meaningful between programs.
RR n 4851
18 Leifer, Peskine, Sewell, Wansbrough
4 Formal system
Our calculus describes networks of machines. Each machine executes a program; a program consists of a sequence
of module declarations followed by an expression. The expression language consists of a simplytyped callbyvalue
#calculus with module field references, marshalling, and communication of strings.
Consider a program containing a module declaring an abstract type. There is an abstraction boundary between the
module's body and the rest of the program. Inside the boundary, the type's representation is visible; thus the type is
said to be transparent. Outside, the type's representation is not visible, thus the type is opaque. Our calculus tracks this
abstraction boundary as reduction proceeds. Compilation replaces the abstract type by a hash h and wraps the code e
that comes from inside the module definition with coloured brackets decorated by h , as in [e] T
h . The distinction between
opaque and transparent views is therefore witnessed by the brackets: inside the brackets, we view h as transparent; when
outside h is opaque.
In order to express this distinction in our inference rules, we decorate each judgement with a colour hm , as in E #hm
e:T . The colour has one of two forms: it can be a hash h , in which case h is transparent and all other hashes are opaque;
or it can be the empty colour ., in which case all hashes are opaque.
The appendices present a systematic development of the formal definitions and theorems complete with proofs.
4.1 Relation to the informal discussion
For brevity, we take a module language in which structures are type/term pairs, rather than general dependent records
from the earlier informal development. The following table summarises the correspondence between the informal and
formal module syntax.
struct type t = T0 let y = v . end # [T0 , v . ]
sig type t val y : T end # [X :Type, T ]
sig type t = T1 val y : T end # [X :Eq(T1 ), T ]
We split module names into two parts, an external name N and an alphaconvertible name U . We write module declara
tions as moduleNU = M :S in m , where U binds in m and N neither binds nor is subject to binding. The user would
write only one identifier, which would be used for both. External names play no role in the static type system; they are
used in hash construction and hence in dynamic type checks.
The formal system omits =! coercions and runtime generativity, which should be straightforward extensions. Func
tors are also omitted, though we include most of the technical machinery they require, expressing abstract and manifest
types in signatures using singleton kinds. In Section 6.2 we propose extensions for treating these omissions.
4.2 Syntax
We let x , X and U range over expression, type and module variables.
Networks:
n ::= 0 | m | n|n
Machines (whole programs):
m ::= e | moduleNU = M :S in m (U binds in m)
Modules:
M ::= [T , v . ] structure (v . is a value)
S ::= [X :K , T ] signature (X binds in T )
Types:
T ::= UNIT | INT | STRING base types
| X | T#T | T # ... # T variable, function, product
| U .TYPE type part of a module
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
| h hash
Hashes:
h ::= hash(N , M :[X :Type, T ]) hash
hm ::= h | . colour (``hash maybe'')
INRIA
Global abstractionsafe marshalling with hash types 19
Kinds:
K ::= Type kind of all types
| Eq(T ) kind of types statically equal to T
Expressions:
e ::= () | n unit, integers
| (e, ..., e) | proj i e tuple, projection
| x | #x :T .e | e e lambda calculus (x binds in e)
| U .term value part of a module
| mar (e:T ) marshalling primitive
| unmar e:T unmarshalling primitive
| ! e | ? send and receive
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
| marshalled (e:T ) result of marshalling
| UnmarFailure exception caused by unmar
| [e] T
hm coloured bracket
User source programs are closed terms of the m grammar which do not contain any of the constructs below the dotted
lines.
Values v hm are indexed by a colour. They are defined formally below; they include usual #calculus values,
marshalled (v . :T ) and ``necessary'' brackets around values. For closed v . , the value marshalled (v . :T ) is a string,
the sequence of bits that represents the value v . and the type T .
We work up to alphaconversion. We write substitutions as follows: {x#e}A replaces x by e in A; we also define
substitutions on module components, as in {U .TYPE T , U .term e}A.
4.3 Static and dynamic semantics
The static type system for programs has judgements for subkinding, type equality, and subsignaturing relations. Module
structures M and names U have signatures S , expressions and machines have types T , and types have kinds K . The
system also defines correctness of colours hm , environments E , kinds K , and signatures S .
E #hm K <: K # E #hm T == T # E #hm S <: S #
E #hm M :S E #hm U :S E #hm e:T
E # . m:T E #hm T :K # hm ok
E #hm ok E #hm K ok E #hm S ok
The typing rules are largely standard; the novel rules will be explained below. Recall that judgements are annotated by a
colour hm , i.e. an optional hash --- the idea being that derivations of judgements annotated by a hash h can make use of
the equality between the abstract type h and its implementation.
Type environments may contain bindings for module, type and expression variables. Earlier variables bind in later
types, kinds and signatures.
E ::= nil | E , x :T | E , X :K | E , U :S
Static typing of networks, # n ok, simply means that all machines are wellformed.
We define compiletime reductions m -# c m # of machines (performed after type checking), and runtime reductions
e -#hm e # and n -# n # for expressions and networks.
4.3.1 Singleton kinds
Following [Ler94, HL94, SH00], we use singleton kinds to handle abstract and concrete signatures in a uniform way. We
have two families of kinds: Type is the kind of all types; and, for any type T , Eq(T ) is the singleton kind of all types
that are provably equal to T .
A module consists of a structure [T 0 , v . ] and a signature [X :K , T ]. The structure has a representation type T 0 and a
value v . --- think of a tuple of operations. This v . must have the type {X T 0 }T , and the implementation type T 0 must
have the kind K . This is made precise by the following rule:
E #hm T 0 :K E , X :K #hm T :Type
E #hm v . :T # E , X :Eq(T 0 ) #hm T # == T
E #hm [T 0 , v . ]:[X :K , T ] (MS.struct)
RR n 4851
20 Leifer, Peskine, Sewell, Wansbrough
For an abstract module we have K = Type, revealing no information about the representation type, whereas for a
concrete module, commonly K = Eq(T 0 ), revealing it. This is captured with the type equality relation: in the context
of a module declaration moduleNU = M :[X :K , T ] in , one can use the path U .TYPE to refer to the type part of the
module. If it is concrete, with K = Eq(T 0 ), one can further use the type equality U .TYPE == T 0 , whereas if it is
abstract U .TYPE is typically not equal to any other type.
The subkinding relation K <: K # places Type above all singleton kinds. This is used to define subsignaturing and
hence, using subsumption, allows a concrete module can be used as if it had an abstract signature.
4.3.2 Hash formation, type equality of hashes
At runtime, we need globally meaningful type names for abstract types, corresponding to the U .TYPE paths used in
compiletime type checking. We construct these global names by hashing (welltyped) closed abstract modules, together
with the associated external name.
# . [T 0 , v . ]:[X :Type, T ]
# hash(N , [T 0 , v . ]:[X :Type, T ]) ok (hmok.hash)
As explained informally earlier, judgements annotated by a hash permit an additional type equality: under the colour
h = hash(N , [T 0 , v . ]:[X :Type, T ]), h is equal to its implementation T 0 :
E # h ok
E # h h == T 0
(Teq.hash)
These two rules examine the internal structure of hashes, which might be thought to be computationally problematic.
However, while they are semantically necessary, they play no role in user program typechecking (Theorem 4.5) or in
execution.
4.3.3 Compiletime reduction and coloured brackets
Module reduction constructs the type representations that will be used at runtime in marshalling and unmarshalling.
Reducing a concrete module is simple: we replace references to its type component by its manifest type, and references
to its term component by the value inside the module.
moduleNU = [T 0 , v . ]:[X :Eq(T 1 ), T ] in m -# c {U .TYPE T 1 , U .term v . }m (mred.Eq)
When it comes to abstract types, things are more interesting. Given an abstract module declaration moduleNU =
[T 0 , v . ]:[X :Type, T ], we normally have no way of referring to its type other than by name, i.e. U .TYPE. How
ever U is not meaningful on other machines, which motivates the introduction of the hash of the module, i.e. h =
hash(N , [T 0 , v . ]:[X :Type, T ]). Then module reduction replaces references to the type component by h . References to
the term component are replaced by the value suitably protected by hcoloured brackets, which embody the abstraction
boundary around the module's body as discussed above.
moduleNU = [T 0 , v . ]:[X :Type, T ] in m -# c {U .TYPE h, U .term [v . ] {X h}T
h }m (mred.Type)
In general, in a bracket expression [e] T
hm , the lower annotation hm is a colour that indicates what type equalities may
be used to type e. If hm = hash(N , [T 0 , v . ]:[X :Type, T ]), then the equality hm == T 0 is available when typing e,
through (Teq.hash) (Section 4.3.2). If hm = ., e is typable without any extra equalities. The upper annotation T is the
externally visible type of e . The following rule (the only typing rule that mentions brackets) shows this colour change
formally.
E # hm # T :Type E #hm e:T
E # hm # [e] T
hm :T (eT.col)
4.3.4 Expression reduction
Expression reduction is based on a standard callbyvalue #calculus semantics. In this subsection, we give the function
application rule and bracketpushing rules. In later subsections, we show the rules for marshalling and communication.
INRIA
Global abstractionsafe marshalling with hash types 21
As we show in Theorem 4.6, brackets can be erased before runtime reduction. However, the brackets' presence is
necessary for type preservation (Theorem 4.1). Given their presence, we need reduction rules to ``push'' them inwards
so that the brackets do not interfere with computationally significant reductions (Theorem 4.3). To describe the bracket
pushing rules, and to achieve type preservation, it is necessary to index the reduction relation, class of values, and reduction
contexts by colours.
We write v hm for a value of colour hm . Brackets may appear in a value when used to build a value of an abstract type
out of a value of the corresponding implementation type, for example [3] h
h , where the implementation type of h is INT.
v hm ::= n | () | (v hm , ..., v hm ) | #x :T .e
| marshalled (v . :T ) | [v h1 ] h1
h1 where h 1 #= hm
The following bookkeeping rules push brackets with manifestly decomposable types inside expressions, and remove them
where not necessary.
[n] INT
hm # -#hm n (ered.col.int)
[()] UNIT
hm # -#hm () (ered.col.unit)
[(v hm
1 , ..., v hm
j )] T1#...#T j
hm # -#hm ([v hm
1 ] T1
hm # , ..., [v hm
j ] T j
hm # ) (ered.col.tuple)
[#x :T .e] T # #T ##
hm # -#hm #x :T # .[{x #[x ] T #
hm }e] T ##
hm # (ered.col.fun)
[marshalled (v . :T )] STRING
hm # -#hm marshalled (v . :T ) (ered.col.marshalled)
[[v h1 ] h1
h1 ] h1
h2 -#hm [v h1 ] h1
h1 if h 1 #= h 2 # h 2 #= hm (ered.col.col)
[v hm 1 ] h2
hm 1 -#hm v hm 1 if hm 1 = hm # hm 1 = . (ered.col.le)
Function application introduces brackets to protect the argument, since the formal parameter may itself be used under a
bracket in the body of the function. This is a variant of [GMZ00], where the formal parameter has to be used at the colour
of the function itself.
(#x :T .e) v hm
-#hm {x#[v hm ] T
hm }e (ered.ap)
4.3.5 Marshalling
As in [ACPP91], mar (e:T ) ``tags'' the value of e with a type annotation T , producing a result of type STRING. The dual
construct unmar e:T produces a value of type T , which the type tag in e must (dynamically) match.
E #hm e:T
E #hm mar (e:T ):STRING (eT.mar)
E #hm T :Type E #hm e:STRING
E #hm (unmar e:T ):T (eT.unmar)
There is a subtlety here: in the conclusion of (eT.mar), the fact that e has the type T may require the extra type equality
provided by hm . Hence we introduce marshalled (e # :T ), which requires the argument to be not only closed but typable
in ., i.e. everywhere. Reduction transforms mar (v hm :T ) into marshalled ([v hm ] T
hm :T ), where the brackets serve to
ensure that any type equality provided by hm is always available to type v hm (even after sending the marshalled value to
another machine). Note that before reducing mar (v hm :T ), both v hm and T will have been closed by substitution.
mar (v hm :T ) -#hm marshalled ([v hm ] T
hm :T ) (ered.mar)
E #hm ok # . e:T
E #hm marshalled (e:T ):STRING (eT.marshalled)
The unmarshalling of a string first extracts the type tag T from the string and compares it with the tag for the expected
type T # . Since T is a valid type for v . in ., it is also one in hm . The type tags T and T # are compared by syntactic
equality: if the types match, the original value is extracted from the string; otherwise an exception is raised. This dynamic
type equivalence is closely related to static equivalence (Theorem 4.7).
unmar (marshalled (v . :T ):T # )
-#hm v . if T = T #
-#hm UnmarFailure otherwise
RR n 4851
22 Leifer, Peskine, Sewell, Wansbrough
4.3.6 Programs and networks
A machine consists of a series of module declarations followed by an expression. Each module declaration may refer to
the previous ones.
E # . T :Type E # . M :S E , U :S # . m:T
E # . (moduleNU = M :S in m):T (mT.let)
A network is a parallel juxtaposition of machines. Note that each machine has its own environment: there is no explicit
scope that encompasses more than one machine.
# n 1 ok # n 2 ok
# n 1 | n 2 ok (nok.par) # . m:UNIT
# m ok (nok.mach)
We assume that there is a single channel, which carries values of type STRING. The expression ! e sends the value of
e over that channel, and ? reads a value from that channel. Communication is straightforward as all the work required to
make values and types intercomprehensible is done by the marshalling apparatus; for suitable evaluation contexts CC . hm 1
and CC . hm 2
we have just the rule below, writing context application with a dot.
CC . hm 1 .! v hm 1
| CC . hm 2 .? -# CC . hm 1 .() | CC . hm 2 .v hm 1 (nred.comm)
4.4 Results
First, our calculus enjoys type preservation and progress properties.
Theorem 4.1 (type preservation for compiletime, expression, and network reduction) (See Theorem G.15 (type
preservation for expression reduction), Theorem G.18 (type preservation for machine reduction), Corollary G.17 (type
preservation for network reduction).)
. if m -# c m # and # . m:T then # . m # :T ;
. if e -#hm e # and #hm e:T then #hm e # :T ; and
. if n -# n # and # n ok then # n # ok.
Theorem 4.2 (progress for compiletime reduction)
(See Theorem H.8 (progress of machines).)
If # . m:UNIT then either
. m is an expression; or
. m reduces, i.e. there exists m # such that m -# c m # .
Moreover, compiletime reduction is terminating.
Theorem 4.3 (progress for expressions)
(See Theorem H.6 (progress of expressions).)
If #hm e:T then one of the following holds:
. e is a value, i.e. there exists v hm such that e = v hm ;
. e reduces, i.e. there exists e # such that e -#hm e # ;
. e is blocked waiting for I/O, i.e. there exists CC hm
hm 2
and e # such that e = CC hm
hm 2
.! e # or e = CC hm
hm 2
.?; or
. e has thrown an exception, i.e. there exists CC hm
hm 2
such that e = CC hm
hm 2 .UnmarFailure.
In addition, we have proved a normalisation result for expressions, showing that the rules for coloured brackets do not
introduce any divergencies.
Both compiletime machine reduction and runtime expression reduction are deterministic (network reduction is not,
of course):
Theorem 4.4 (determinacy for compiletime and expression reduction)
(See Theorem H.11 (determinism of expression reduction), Discussion H.12 (strength of determinism), Theorem H.9
(determinism of machine reduction).)
If m -# c m # and m -# c m ## then m # = m ## and both reductions apply the same rule to the same redex. if
e -#hm e # and e -#hm e ## then e # = e ## and both reductions apply the same rule to the same redex.
For static type checking:
INRIA
Global abstractionsafe marshalling with hash types 23
Theorem 4.5 (decidability of type checking)
(See Theorem I.14 (decidability of type checking), Discussion I.16 (decidability of type checking for user programs).)
Type checking is decidable. Furthermore, user source programs can be typed by derivations involving no hashes or
coloured brackets.
At runtime, all type annotations except those on mar , marshalled , and unmar can be erased. Moreover, all
coloured brackets can be erased except for those that occur within a hash within one of those remaining annotations.
More precisely, we define erase(e) to be e with all type annotations and brackets erased except that the type annotations
on mar , marshalled , and unmar are left unchanged. We define ---# erase
to be like -#hm by taking the eraseimage
of the left and righthand sides of each rule (and removing rules that would become e ---# erase
e).
Theorem 4.6 (erasure preserves reduction outcomes)
(See Theorem I.30 (type erasure).)
Assume # . e:T . We have that e -# . e # implies erase(e) ---# erase
61 erase(e # ). Conversely, erase(e) ---# erase
e 0 implies
that there exists e # such that erase(e # ) = e 0 and e -# >1
.
e # .
Note that brackets are needed in module reduction, to keep track of a module's ancestors as we build its hash.
Finally we show that, under reasonable conditions, static and dynamic type equality coincide. Let D be a module
declaration context:
moduleN 0 U0 = M 0 :S 0 in ...module N j U j
= M j :S j in
in the user source language (with no brackets or hashes). Consider a machine D .C .e for some expression context C and
an expression e = (unmar (mar (e 0 :T 0 ):T 1 )). One would like this dynamic type check to succeed if and only if T 0
and T 1 are statically provably equal, i.e. iff U 0 :S 0 , ..., U j :S j # .
T 0 == T 1 .
Write #D for the accumulated substitution defined by the module reduction rules for D (we omit an explicit definition
for lack of space). The dynamic check is then #D T 0 = #D T 1 . We have:
Theorem 4.7 (coincidence between dynamic and static type checking)
(See Corollary J.21 (coincidence between undyntime and static type checking with nonrepeated external names).)
Suppose that D .C .e is well formed (i.e. # .
D .C .e:UNIT), that it contains no hashes, and that its external names
N 0 , ..., N j are distinct. Let E = U 0 :S 0 , ..., U j :S j be the associated environment. Assume that T 0 and T 1 contain no
hashes and E # . T i :Type for i = 0, 1. Then E # . T 0 == T 1 iff #D T 0 = #D T 1 .
The requirement that the external names N 0 , ..., N j be distinct rules out the rather pathological programs in which
there are two module definitions with the same name, one shadowing the other, which have identical structures, signatures,
and dependencies. The exclusion of hashes is automatic for user source programs.
One can imagine stronger theorems, relating type equality between two programs that share a common (DAG)prefix
of module definitions, but their statements become rather elaborate.
5 Related work
Modules and generativity There is an extensive literature on MLstyle modules, including [Mac84, MTH90, HL94,
Ler94, SH00, DCH03], much of it discussing subtle questions of generativity versus applicativity. To our knowledge,
however, none deals with the interprogram case. In [Sew01], fresh type names are generated during callbyvalue module
reduction, with #binders that can extrude across distributed scope. This allows interprogram sharing, and also a with!
coercion, but at the pragmaticallyawkward cost of requiring particular object files to be shared.
Type dynamic Our marshal and unmarshal operations are essentially constructors and destructors for values of
dynamic type; mar is just dynamic, and unmar is a restricted form of typecase. Our dynamic values have
type STRING, emphasising that they may be communicated readily. Type Dynamic was first formalised by Abadi et
al. [ACPP91, ACPR95], who also gives a historical survey. Intensional polymorphism [HM95, Wei00] permits runtime
type analysis of all values.
Marshalling abstract types The problem of marshalling values of abstract (existential [MP88]) type has not been
satisfactorily addressed theoretically before. In several systems, abstract types are run or buildtime generative, so that
two executions or builds of the same source will yield distinct types. While communication within such a program can be
RR n 4851
24 Leifer, Peskine, Sewell, Wansbrough
abstractionsafe, successful communication between builds can only be at the representation type, and hence abstraction
unsafe. This is true, for instance, of [ACPR95], TMAL [Dug02], Modula3 [B + 94, BNOW95], Alice [Ali03], and the
typedchannel languages listed below.
Weirich [Wei02] exposes an existential's representation type to type analysis, permitting a typesafe polytypic mar
shalling function to be written. As future work we hope to expose our global type names at term level (cf. [HWC00]),
permitting an abstractionsafe polytypic marshalling function to be written. Furuse and Weis [FW00] argue for ignoring
abstraction altogether, checking representation types only.
A number of programming languages feature some form of builtin marshalling (pickling, serialisation, etc.): for
example Modula3, Alice, Java, .NET, and OCaml. Most of these languages serialise the type along with the value in
order to permit a check at unmarshal time, and represent the type by a hash. Languages differ, however, in exactly what
is hashed --- i.e., in what is considered when deciding type equality.
In Modula3, abstract types are made opaque by branding, which may be either by a literal string (analogous to an
external name) or a compilergenerated unique identifier. The latter are unique within a program but not necessarily related
between programs, so explicit brands must be used for interprogram communication; however, they do not guarantee
abstractionsafety for that case. Revelation can be used to make an abstraction transparent.
In Alice, abstract type creation is runtime generative, meaning that abstract types from different executions are always
distinct. This vacuous abstractionsafety forces the use of representation types for pickling between different programs.
In Java serialisation [Sun02], class equivalence is on fullyqualified class name, the representation type of all fields,
and the types of all nonprivate methods; the implementation is not considered in type equality. A strong coercion
(Section 2.10) is provided (although compatibility of representation types is not checked until unmarshal time).
In .NET serialisation [Mic01], class equivalence is on the textual name along with the implementation of the entire
assembly in which it is defined (a single DLL or EXE, which may comprise many source files). This guarantees data
structure invariants are maintained, as in our approach; however, we work on the much finer scale of individual modules,
and furthermore we require only source code to be shared, not object files.
Java and .NET both support controlled relaxation of type equivalence checking, the use of which clearly voids any
abstractionsafety guarantees made by the type system.
OCaml [OCa] does no typechecking for marshalling at all, and hence is not even typesafe. When unmarshalling a
function, it verifies (by a hash) that the communicating builds are identical, thus allowing the code pointers of all closures
to be communicated literally.
Coloured brackets Coloured brackets were introduced in [ZGM99, GMZ00]; we differ in that we permit a variable
to occur in a colour other than the one where it is defined. Our proofs are harder, our #rule has to introduce extra
brackets, but our brackets carry only a single optional hash, rather than a list of hashes. Rossberg [Ros02], like us, is
concerned to preserve the opacity of abstract types under reduction due to the presence of typecase. His coercions serve
the same purpose as our brackets, but his use of the closedscope open construct instead of dot notation [CL90] prevents
any possibility of sharing values of abstract type between instances.
Typed channels Several languages, e.g. JoCaml [JoC], Nomadic Pict [SWP99], Facile [TLK96, Kna95], implement
typed channels. These permit type and abstractionsafe communication once the channel is established. Establishing
a channel at an abstract type, however, requires the endpoints somehow to share the type already; in the case that the
endpoints reside in different programs or instances, this requires an unsafe cast, usually performed (outside the language)
by a name server.
6 Conclusions and future work
6.1 Summary
We have proposed a novel and expressive design for guaranteeing type and abstractionsafe marshalling of data sent
between distributed ML programs, that can uniformly treat manifest, abstract, and generative types. The key technical
idea is to use hashes of module declarations as globallymeaningful type names, which are inserted at compiletime
and then compared dynamically when unmarshalling. We add coloured brackets to delimit the ``abstraction boundary''
within which hashes are transparent, tracking these brackets through the reductions so as to achieve type and abstraction
preservation. Our proposal is a smooth extension of existing MLlike languages: type checking is unchanged, most type
information can be erased before runtime, and the dynamic type check closely mirrors static ML type equivalence.
INRIA
Global abstractionsafe marshalling with hash types 25
6.2 Future work
In the future, we aim to broaden our solution to be applicable to fullscale languages.
The following extensions will be required to cope with the examples in Section 2.9--2.13. The strong coercion (Sec
tion 2.10 and 2.11) used for forcing an abstract type to have the same hash as an earlier module, has a simple compiletime
implementation: check the representation types of the two are provably equal, then simply reuse the hash of the earlier
module as the type name for the new. This requires the compiler to keep a mapping from hashes to representation types,
which is straightforward. Programmerrequested generativity (Section 2.12) can be dealt with in an implementation by
generating a fresh global name (say a random bit string of the same length as hashes) at compile time; its semantics
can be modelled by #binding. Both this and the strong coercion are very similar to the constructs in our earlier work
[Sew01]. Sideeffectinduced generativity (Section 2.13) requires a way to identify simple pure computations in structure
bodies that the programmer can easily understand; abstract types of structures with pure computations should be hashes,
whereas those of structures with effectful computations should have freshlygenerated names. Functors (Section 2.9) are
a more substantial extension, but, at least for a restricted but useful class, should be straightforward. Consider firstorder
applicative functors [Ler95] and module expressions that are either (i) an explicit structure, possibly multiplyabstracted,
or (ii) pure, i.e. constructed from module identifiers, abstraction and application. These give rise to functions from hashes
to hashes; applying these functions gives runtime representations of the compiletime pathbased type names.
Other substantial extensions also need to be considered. Dependent record structures, i.e. module structures with
multiple fields also appear in this report's informal examples; they should be conceptually straightforward. Parametric
and substructuring polymorphism within the dynamic check would allow receivers to accept a more general type than
that offered by the sender. This is a more substantial extension; it will be a challenge to minimise the transmitted type
information required for these dynamic ``subtype'' checks. One may want to rebind (Section 2.14) identifiers within a
transmitted value to avoid the overhead of sending code already available at the other end, or to obtain locationspecific
behaviour; here we aim to integrate hash types with [BHS + 03]. Marshalling reference cells exhibits related problems:
should the reference be rebound, made remote, or duplicated? More generally, one must consider values mentioning other
machine resources: screens, files. . .
We wish to integrate our work with existing systems for distributed programming which have statically typed channels
for normal operation but no safe way of initiating communication, such as JoCaml [JoC] and Nomadic Pict [SWP99]. We
also wish to test the expressiveness of our marshalling primitives by using them to write libraries for safe distributed
communication and persistence.
Acknowledgments We acknowledge support from a Royal Society University Research Fellowship (Sewell), EPSRC
grant GRN24872 (Wansbrough), EC FETGC project IST200133234 PEPITO, and APPSEM 2. The authors thank
Georges Gonthier, JeanJacques L evy, Luc Maranget, and the anonymous referees for their suggestions.
RR n 4851
26 Leifer, Peskine, Sewell, Wansbrough
A Introduction to the complete definitions and proofs
A.1 Differences between the main body and the appendices
The following appendices present the full formal system with all proofs. There are slight differences between these and
the main body of the report:
Type system Some admissible rules were omitted from the main body. They are (Ssub.refl) and (Ssub.tran) (section
C.11). We now also formalise the /
#dom relation (section C.1), and define a kind equality (section C.5) which
is used in the rules for subkinding. For the sake of completeness, we define a signature equality relation (section
C.10).
Integer constants We now omit the rules for the INT type and integer constants. They (and other base types) can be
trivially added to the system on the model given by UNIT and ().
A.2 Correspondence between the theorems in the main body and in the appendices
Main body Appendices
Theorem 4.1 Theorem G.15 (type preservation for expression reduction),
Theorem G.18 (type preservation for machine reduction),
Corollary G.17 (type preservation for network reduction)
Theorem 4.2 Theorem H.8 (progress of machines)
Theorem 4.3 Theorem H.6 (progress of expressions)
Theorem 4.4 Theorem H.11 (determinism of expression reduction),
Discussion H.12 (strength of determinism),
Theorem H.9 (determinism of machine reduction)
Theorem 4.5 Theorem I.14 (decidability of type checking),
Discussion I.16 (decidability of type checking for user programs)
Theorem 4.6 Theorem I.30 (type erasure)
Theorem 4.7 Corollary J.21 (coincidence between undyntime and static type checking with non
repeated external names)
B Syntax
e ::= expression
() unit
(e 1 , ..., e j ) tuple (2 6 j )
proj i e projection
x variable
#x :T .e abstraction (x binds in e)
e e application
mar (e:T ) dynamic
marshalled (e:T ) closed, colourindependent dynamic
unmar e:T undynamic
! e send
? receive
U .term termpart of a module
[e] T
hm type colouring
UnmarFailure T undyn failure
INRIA
Global abstractionsafe marshalling with hash types 27
v hm 0 ::= hm 0 value, i.e. value in the colour hm 0
() unit
(v hm 0
1 , ..., v hm 0
j ) tuple (2 6 j )
#x :T .e abstraction (x binds in e)
marshalled (v . :T ) closed dynamic value
[v h1 ] h1
h1 type colouring, where h 1 #= hm 0
We sometimes omit the colour annotation on values, when it is irrelevant.
C hm 1
hm 2
::= singlelevel evaluation context
(v hm 1
1 , .., v hm 1
i-1 , , e i+1 , .., e j ) tuple (2 6 j and 1 6 i 6 j ), if hm 1 = hm 2
proj i projection, if hm 1 = hm 2
e application left, if hm 1 = hm 2
v hm 1 application right, if hm 1 = hm 2
mar ( :T ) dynamic, if hm 1 = hm 2
marshalled ( :T ) colourindependent dynamic, if hm 2 = 0
unmar :T undynamic, if hm 1 = hm 2
! send, if hm 1 = hm 2
[ ] T
hm 2
coloured bracket
CC hm 1
hm 2
::= coloured evaluation context
CC hm 1
hm # .C hm #
hm 2
extra level
identity, if hm 1 = hm 2
T ::= type
UNIT unit
T 1 # ... # T j tuple (2 6 j )
X variable
T#T function
STRING dynamic
U .TYPE typepart of a module
h hash
TC ::= firstlevel constructed type context
UNIT unit
STRING dynamic
1 # 2 function
1 # ... # j tuple (2 6 j )
hm ::= hash option
. none
h some hash
h ::=hash(N , M :[X :Type, T ]) hash
N external name
RR n 4851
28 Leifer, Peskine, Sewell, Wansbrough
K ::= kind
Type opaque
Eq(T ) singleton
M ::=[T , v ] module structure (typepart, termpart)
S ::=[X :K , T ] module signature (X binds in T )
m ::= machine
e expression
moduleNU = M :S in m module declaration (U binds in m)
n ::= network
0 null
n | n parallel composition
e expression (on one machine)
# ::= variable
x expression variable
X type variable
U module variable
# ::= substitutable entity
X type variable
U .TYPE typepart of a module
x expression variable
U .term termpart of a module
U module variable
...
X ::= type substitutable entity
X type variable
U .TYPE typepart of a module
... x ::= expression substitutable entity
x expression variable
U .term termpart of a module
E ::= environment
E , x :T expression variable binding
E , X :K type variable binding
E , U :S module variable binding
nil empty
INRIA
Global abstractionsafe marshalling with hash types 29
J ::= colourable statement
ok environment correctness
K ok kind correctness
K == K # kind equivalence
K <: K # subkinding
T :K kind of a type
T == T # type equivalence
S ok signature correctness
S == S # signature equivalence
S <: S # subsignaturing
e:T type of an expression
M :S signature of a module expression
U :S signature of a module variable
m:T type of a machine
CJ ::=E #hm J couloured judgement
MJ ::= monochrome judgement
# hm ok hash correctness
# n ok network correctness
AJ ::= judgement
# /
# domE nonclash judgement
E #hm J coloured judgement
MJ monochrome judgement
Additionally, we use the following notations:
#:# ::= x :T | X :K | U :S variable has sort
#:# ::= e:T | T :K | M :S term has sort
# ok ::= T :Type | K ok | S ok sort is correct
= syntactic equality
#, substitutions
# derivation (i.e. proof tree)
{# #}# substitution: replace # by # in #
fv free variables (U , X , x )
fse free substitutable entities (U , U .TYPE, U .term, X , x )
(if U .TYPE # fse # or U .term # fse # then U # fse #)
(and more, introduced as they are defined...)
Note that in particular external names (N ) are not variables or substitutable entities, so they are never ``free'' nor can
substitution touch them: fv N = fse N = ? and #N = N .
C Static judgements
C.1 # /
# domE nonclash
# /
# dom nil (clash.nil)
# /
# domE # #= # #
# /
# dom (E , # # :# ) (clash.cons)
For any two distinct variables # and # # , # #= # # is an axiom.
RR n 4851
30 Leifer, Peskine, Sewell, Wansbrough
C.2 # hm ok hash correctness
nil # . M :[X :Type, T ]
# hash(N , M :[X :Type, T ]) ok (hmok.hash)
# . ok (hmok.zero)
Note that N may be any external name.
Note that we demand that a module have an opaque type in order to take its hash.
C.3 E # hm ok environment correctness
# hm ok
nil #hm ok (envok.nil)
E #hm T :Type
x /
# domE
E , x :T #hm ok (envok.x)
E #hm K ok
X /
# domE
E , X :K #hm ok (envok.X)
E #hm S ok
U /
# domE
E , U :S #hm ok (envok.U)
An alternate way of stating (envok.?) could be:
E #hm # ok # /
# domE
E , #:# #hm ok
C.4 E # hm K ok kind correctness
E #hm ok
E #hm Type ok (Kok.Type)
E #hm T :Type
E #hm Eq(T ) ok (Kok.Eq)
C.5 E # hm K == K # kind equality
E #hm ok
E #hm Type == Type (Keq.Type)
E #hm T == T #
E #hm Eq(T ) == Eq(T # ) (Keq.Eq)
C.6 E # hm K <: K # subkinding
E #hm T :Type
E #hm Eq(T ) <: Type (Ksub.Eq)
E #hm K == K #
E #hm K <: K # (Ksub.refl)
E #hm K <: K #
E #hm K # <: K ##
E #hm K <: K ## (Ksub.tran)
Note that (Ksub.tran) is currently derivable.
C.7 E # hm T :K kind of a type
E #hm T :K
E #hm K <: K #
E #hm T :K # (TK.sub)
E #hm T == T #
E #hm T :Eq(T # ) (TK.Eq)
# h ok
E #hm ok
E #hm h:Type (TK.hash)
E #hm ok
E #hm UNIT:Type
(TK.unit)
E #hm ok
E #hm STRING:Type
(TK.mar)
E #hm T :Type
E #hm T # :Type
E #hm T#T # :Type (TK.fun)
E #hm T i :Type #i .1 6 i 6 j
E #hm T 1 # ... # T j :Type (TK.tuple)
E , X :K , E # #hm ok
E , X :K , E # #hm X :K (TK.var)
E #hm U :[X :K , T ]
E #hm U .TYPE:K
(TK.mod)
INRIA
Global abstractionsafe marshalling with hash types 31
C.8 E # hm T == T # type equivalence
E #hm T :Eq(T # )
E #hm T == T # (Teq.Eq)
E # h ok
E # h h == T
where h = hash(N , [T , v hm ]:[X :Type, T # ])
(Teq.hash)
The rule (Teq.hash) is the rule that introduces type equivalences (see Lemma G.11 (type decomposition)). Other rules
serve to propagate equivalences. Of course another way to obtain a type equivalence is to have an explicit Eq(T ) in the
judgement and use (Teq.Eq).
E #hm T :Type
E #hm T == T (Teq.refl)
E #hm T == T #
E #hm T # == T (Teq.sym)
E #hm T == T #
E #hm T # == T ##
E #hm T == T ## (Teq.tran)
E #hm T 0 == T #
0
E #hm T 1 == T #
1
E #hm T 0 #T 1 == T #
0 #T #
1
(Teq.cong.fun)
E #hm T i == T #
i 1 6 i 6 j
E #hm T 1 # ... # T j == T #
1 # ... # T #
j
(Teq.cong.tuple)
C.9 E # hm S ok signature correctness
E , X :K #hm T :Type
E #hm [X :K , T ] ok (Sok)
C.10 E # hm S == S # signature equivalence
Note that we never use signature equivalence.
E #hm K == K # E , X :K #hm T == T #
E #hm [X :K , T ] == [X :K # , T # ] (Seq.struct)
Signature equivalence is an equivalence relation since kind equivalence and type equivalence are.
C.11 E # hm S <: S # subsignaturing
E #hm K <: K #
E , X :K #hm T == T #
E #hm [X :K , T ] <: [X :K # , T # ] (Ssub.struct)
E #hm S ok
E #hm S <: S (Ssub.refl)
E #hm S <: S #
E #hm S # <: S ##
E #hm S <: S ## (Ssub.tran)
Note that (Ssub.refl) and (Ssub.tran) are derivable.
C.12 E # hm e:T type of an expression
E #hm e:T
E #hm T == T #
E #hm e:T # (eT.eq)
E , x :T , E # #hm ok
E , x :T , E # #hm x :T (eT.var)
E #hm U :[X :K , T ]
E #hm T :Type
E #hm U .term:T (eT.mod)
Note that in (eT.mod), the condition E #hm T :Type guarantees that X /
# fv T .
E #hm e # :T#T #
E #hm e:T
E #hm e # e:T # (eT.ap)
E , x :T #hm e:T #
E #hm #x :T .e:T#T # (eT.fun)
RR n 4851
32 Leifer, Peskine, Sewell, Wansbrough
E #hm e i :T i #i .1 6 i 6 j
E #hm (e 1 , .., e j ):T 1 # ... # T j
(eT.tuple)
E #hm e:T 1 # ... # T j 1 6 i 6 j
E #hm proj i e:T i
(eT.proj)
E #hm ok
E #hm ():UNIT (eT.unit)
E #hm e:STRING
E #hm ! e:UNIT (eT.send)
E #hm ok
E #hm ?:STRING (eT.recv)
E #hm e:T
E #hm mar (e:T ):STRING (eT.mar)
E #hm ok
nil # . e:T
E #hm marshalled (e:T ):STRING (eT.marred)
E #hm T :Type
E #hm e:STRING
E #hm (unmar e:T ):T (eT.unmar)
E #hm T :Type
E #hm UnmarFailure T :T
(eT.Undynfailure)
For (eT.unmar), the condition E #hm T :Type ensures T is wellformed. Of course, nothing forces T to be closed;
as usual reduction will transform it into something closed before (ered.unmar) happens.
E #hm T :Type
E # hm # e:T
E #hm [e] T
hm # :T (eT.col)
Note that, when reading the rule backwards, hm # replaces hm: the brackets denote a colour change.
C.13 E # hm M :S signature of a module expression
E #hm T :K
E , X :K #hm T # :Type
E , X :Eq(T ) #hm T ## == T #
E #hm v hm :T ##
E #hm [T , v hm ]:[X :K , T # ] (MS.struct)
Remark: in (MS.struct), the type T ## and the premise E #hm v hm :T ## are there to ensure that X is not free in v hm ,
even though its interesting type T # may contain X .
The premise E , X :K #hm T # :Type is implied by the premise E , X :Eq(T ) #hm T ## == T # , since the correctness
of T # only requires that the environment provide X , not that it be given any particular kind. (See Lemma F.9 (types are
ok provided their hashes are).)
We might be worried that there should be a (MS.sub), but this would be doing subsignaturing at compile time, and we
have subsignaturing at run time via (US.sub) which seems to subsume it.
We require the expression component of the module to be a value. This is to dispel any concern over the time at which
a module is initialised. Note that if an arbitrary expression e is desired, it can be encoded as #x :UNIT.e, with the type of
the module changed from T # to UNIT#T # , and its uses changed from U .term to U .term ().
C.14 E # hm U :S signature of a module variable
E , U :S , E # #hm ok
E , U :S , E # #hm U :S (US.var)
E #hm U :S
E #hm S <: S #
E #hm U :S # (US.sub)
E #hm U :[X :K , T ]
E #hm U :[X :Eq(U .TYPE), T ] (US.self)
The way we prove things about the type of U .term is quite interesting. Here is an example: what are the possible types T such that
E #. U .term:T with E = (U :[X :Type, X ])? Let us look at all the possible derivations (arguing slightly informally, i.e. without
verifying everything, on the ``the proof has to be of this form'' bit).
#
E #. T :Type
#
E #. U :[X :K 4 , T 3 ]
E #. U :[X :K 3 , T 3 ]
(US.self)
#
E #. K 3 <: K 2
#
E , X :K 3 #. T 3 == T
E #. [X :K 3 , T 3 ] <: [X :K 2 , T ]
(Seq.struct)
E #. U :[X :K 2 , T ]
(US.sub)
E #. U .term:T
(eT.mod)
INRIA
Global abstractionsafe marshalling with hash types 33
We can check that any proof of E #. U .term:T can be shortened to a proof of this form. The only alternative is not to use
(US.self), but we can verify that this does not lead to any proof of E #. U :[X :K3 , T3 ]. (If the signature of U was [X :Eq(T1 ), X ],
we could usefully use (US.var) there, and (US.sub) would rewrite the X into T1 , so we would get T = T1 ). At this point, we still get
to choose T , K2 , K3 , K4 and T3 , but the derivations of (#), (#), (#) and (#) constrain these choices.
In # we see that fv T # {U }. In (#), all we have left to do (assuming as stated a minimal proof) is apply (US.var), so K4 = Type
and T3 = X . In (#) we have that K3 is Eq(U .TYPE). In (#) we have the only constraint on K2 , and we might as well take
K2 = Type. In (#), we need to prove that X == T , and since X does not appear in T , the equivalence must come from the
environment, hence K3 = Eq(T ). Unifying the constraints on K3 yields T = U .TYPE as the one possible type for U .term.
C.15 E # hm m:T type of a machine
E # .
e:T
E # . e:T (mT.expr)
E # . T :Type
E # . M :S
E , U :S # . m:T
E # . (moduleNU = M :S in m):T (mT.let)
In (mT.expr), the premise is a ``type of an expression'' judgement, while the conclusion is a ``type of a machine''
judgement.
Note: in (mT.let), the first premise is saying that U is not free in T .
C.16 # n ok network correctness
# n i ok i = 1, 2
# n 1 | n 2 ok (nok.par)
# 0 ok (nok.zero)
nil # . e:UNIT
# e ok (nok.expr)
D Reduction rules and structural congruence
D.1 m -# c m # compiletime reduction
moduleNU = [T , v . ]:[X :Type, T # ] in m -# c {U .TYPE h, U .term [v . ] {X h}T #
h }m (mred.Type)
where h = hash(N , [T , v . ]:[X :Type, T # ])
moduleNU = [T , v hm ]:[X :Eq(T ## ), T # ] in m -# c {U .TYPE T ## , U .term v hm
}m (mred.Eq)
D.2 e -# hm e # expression reduction
Note that we don't rewrite types at all (unlike Grossman et al., p13 rule 7).
proj i (v hm
1 , .., v hm
j ) -#hm v hm
i if 1 6 i 6 j (ered.proj)
(otherwise stuck)
(#x :T .e) v hm
-#hm {x#[v hm ] T
hm }e (ered.ap)
(Note that (as Grossman et al.) we introduce a bracket around the argument of the function. This is needed e.g.,
because if h = hash(N , [INT, 3]:[X :Type, X ]) then nil # h (#x :INT.[x ] INT
.
)[3] h
h :INT is derivable, yet [[3] h
h ] INT
.
is not
welltyped.)
mar (v hm :T ) -#hm marshalled ([v hm ] T
hm :T ) (ered.mar)
unmar (marshalled (v . :T ):T # ) -#hm ( v . if T = T #
UnmarFailure T otherwise (ered.unmar)
RR n 4851
34 Leifer, Peskine, Sewell, Wansbrough
Note that we use syntactic equality (up to alphaconversion (inside hashes)) to compare the types (which are closed). In
practice, we could use a md5style checksum of the alphanormalized type expression.
[()] UNIT
hm # -#hm () (ered.col.unit)
(and all base types when we have them)
[(v hm #
1 , ..., v hm #
j )] T1#...#T j
hm # -#hm ([v hm #
1 ] T1
hm # , ..., [v hm #
j ] T j
hm # ) (ered.col.tuple)
[#x :T .e] T # #T ##
hm # -#hm #x :T # .[{x #[x ] T #
hm }e] T ##
hm # (ered.col.fun)
[marshalled (v . :T )] STRING
hm # -#hm marshalled (v . :T ) (ered.col.marred)
[[v h0 ] h0
h0 ] h0
h1 -#hm [v h0 ] h0
h0 (ered.col.col)
for h 0 #= h 1 and h 1 #= hm .
We used to have this rule for an arbitrary type T , but in fact it is only ever necessary for T = h 0 .
[v hm 1 ] h2
hm 1 -#hm v hm 1 (ered.col.le)
for hm 1 4 hm . (See Definition E.13 (partial order on colours).)
We used to have this rule with an arbitrary type T rather than h 2 , but the other (ered.col.*) rules deal with the case when
T is a constructed type.
e -#hm e #
C hm #
hm .e -# hm # C hm #
hm .e #
(ered.cong)
D.3 n # n # network structural congruence
0 | n # n (nsc.id)
n 1 | n 2 # n 2 | n 1
(nsc.commut)
n 1 | (n 2 | n 3 ) # (n 1 | n 2 ) | n 3
(nsc.assoc)
Plus reflexivity, symmetry and transitivity of #.
D.4 n -# n # network reduction
e -# . e #
e -# e # (nred.expr)
n -# n #
n | n ## -# n # | n ## (nred.par)
n # n 0 -# n # 0 # n #
n -# n # (nred.strcong)
CC . hm .! v hm
| CC . hm # .? -# CC . hm .() | CC . hm # .v hm (nred.comm)
Note that the value that is sent is a value in the domain from which it is sent, but just by looking at this rule, it might
not be a value in the domain where it is received. In fact, typing will ensure that v hm = marshalled (v . :T ) and this is
a value in any domain.
E General definitions and lemmas
E.1 Proofs
We use the words ``proof'' and ``derivation'' indifferently, to mean a natural deductionstyle tree of inference steps leading
to a judgement.
Definition E.1 (smaller proof) A proof # is smaller than a proof # # iff # contains at most as many inference steps as
# # , i.e. the number of nodes in the tree # is smaller.
A subproof is a particular case of a smaller proof.
Note that any proof is a subproof of itself and is smaller than itself. We will use the wordings ``proper subproof'' and
``strictly smaller proof'' to exclude equality (respectively, equal size).
INRIA
Global abstractionsafe marshalling with hash types 35
E.2 Correctness of parts
Definition E.2 (domain of an environment) The domain of an environment E , written domE , is a set of variables
defined by induction as follows:
. dom nil = ?
. dom (E , #:#) = domE # {#}
Lemma E.3 (nonmembership in domain is interpreted trivially) The judgement # /
# domE is provable iff # is not a
member of the domain of E .
Proof. Induct on the derivation of # /
# domE . The rules (clash.nil) and (clash.cons) trivially maintain this property.
We will freely make use of this lemma in the remainder of this section.
Lemma E.4 (colours have to be ok) If E #hm J then # hm ok by a proper subproof.
Proof. Induct on the derivation of E #hm J . All rules whose conclusion is a coloured judgement have at least one
premise that is a similarly coloured judgement, so induction applies. This leaves only the rule (envok.nil), which has
# hm ok as a premise.
Lemma E.5 (hashes have to be ok) If E #hm J or # hm ok is derivable by a proof # and h is a subterm of E #hm J
or # hm ok then # h ok by a subproof of #.
Proof. Induct on the structure of #. Most metavariables in the conclusion of rules whose conclusion is a coloured judge
ment also appear in at least one premise that is a coloured judgement. If h is in the instantiation of such a metavariable
then we have the desired result by induction. We list the remaining cases (including ``exposed'' hashes).
Case subterm of hash(N , M :S ) in (TK.hash): One premise is # hash(N , M :S ) ok. If h = hash(N , M :S ) we have
the desired result. Otherwise induction gives the desired result.
Case hm in (envok.nil): Trivial by induction.
Case N (in (mT.let)): Trivial (fv N = ?).
Case (hmok.hash): The conclusion is # hash(N , M :S ) ok. If h = hash(N , M :S ) we have the desired result. Other
wise induction gives the desired result.
Case (hmok.zero): Trivial.
Lemma E.6 (environments have to be ok) If E #hm J then E #hm ok by a subproof.
Proof. Simultaneously with the following lemma.
Lemma E.7 (prefixes of ok environments are ok) If E , b #hm ok then E #hm ok by a subproof.
Proof. Induct simultaneously on the derivation of E #hm J and E , b #hm ok. Note that E , b #hm ok can only be
derived from a judgement of the form E #hm J , hence the result of the second lemma follows by induction from the first
lemma. We now turn to the first lemma.
Most rules whose conclusion is a coloured judgement have at least one premise that is a coloured judgement with the
same environment, and so we apply the induction hypothesis to that premise. We list the remaining cases.
Cases (envok.nil), (envok.x), (envok.X), (envok.U): Trivial.
Case (eT.fun): There exist x , T , T # , e such that J = #x :T .e:T#T # . The premise is E , x :T #hm e:T # . By induction,
E , x :T #hm ok by a subproof, hence E #hm ok by the second lemma, as desired.
Lemma E.8 (ok environments have no repetition in the domain) If E , E # #hm ok then domE # domE # = ?.
RR n 4851
36 Leifer, Peskine, Sewell, Wansbrough
Proof. Induct on the length of E # . If E # = nil, then domE # = ?, so domE # domE # = ?. Otherwise write
E # = (E ## , #:#). Then E , E # #hm ok must have been derived by the appropriate (envok.*) rule, with the premises
E , E ## #hm # ok and # /
# dom (E , E ## ). From the first premise, by Lemma E.6 (environments have to be ok), we get
E , E ## #hm ok by a subproof, whence domE # domE ## = ? by induction. Then domE # domE # = (domE #
domE ## ) # (domE # {#}) = ? # ? = ? as desired.
Lemma E.9 (free variables of a judgement come from the environment) If E #hm J then fv (J ) # dom (E ). For
completeness's sake: if # hm ok then fv (hm) # ?; if # n ok then fv (n) # ?.
Proof. We freely use Lemma E.3 (nonmembership in domain is interpreted trivially).
Induct on the size of the derivation # of the judgement.
Most rules whose conclusion is a coloured judgement have the following property: every metavariable in the right
hand side of the conclusion E #hm J is present in the righthand side, not under a binder, of a premise that is a coloured
judgement with the same environment as the conclusion. Then, by induction on the premise, every free variable in the
subterm matched by that metavariable is present in the domain of the environment.
Most rules whose conclusion is the correctness of a network have the following property: every metavariable in the
conclusion is also present in one of the premises which is a network correctness judgement. Then, by induction, there is
no free variable in the subterm matched by that metavariable.
We list the remaining cases.
Case (TK.hash): The conclusion is E #hm hash(N , M :S ):Type. One premise is # hash(N , M :S ). By induction we
have fv (hash(N , M :S )) = ?, so fv (hash(N , M :S )) # domE .
Case (Teq.hash): The conclusion is E # h h == T where h = hash(N , [T , v hm ]:S ). The premise is E # h ok. By
Lemma E.4 (colours have to be ok), # h by a proper subproof. By induction, we have fv h = ? and in particular
fv T = ?, so fv (h == T ) = ? # domE .
Case (hmok.hash): The conclusion is # hash(N , M :S ) ok and the premise is nil # . M :S . By induction we have
fv (hash(N , M :S )) = dom nil = ? as desired.
Case (hmok.zero): Trivial.
Cases T in (Sok); T and T # (Seq.struct) and (Ssub.struct); e in (eT.fun); m in (mT.let): These rules have a
metavariable # in the conclusion that is under a binder for some variable #. In each case, there is a premise of the
form E , #:# #hm J # with # appearing not under a binder in J # . By induction, we get that fv # # domE # {#}.
Since # is bound in the occurence of # in the conclusion, this is the desired result.
Cases K in (Sok); T in (eT.fun): In each case, there is a premise of the form E , #:# #hm J # where E and hm are the
environment and the colour of the conclusion and # is the metavariable under consideration. By Lemma E.6 (envi
ronments have to be ok) and reversing the appropriate (envok.*) rule, we have, by a proper subproof, respectively,
E #hm K ok, E #hm T :Type, E #hm M :S . In each case, by induction, we get fv # # domE .
Case T # in (eT.fun): By induction as in the case of e, we get that fv T # # domE # {x}. By Lemma E.5 (hashes
have to be ok), for any hash h that is a subterm of T # , we have # h ok by a (proper) subproof of #. Thus, by
induction, fv h = ? and in particular x /
# fv h . Given the syntax of types, the only place where T # might have a
free expression variable is inside a hash, so x /
# fv T # . Hence fv T # # domE as desired.
Cases (TK.var), (eT.var), (US.var): The variable (X , x or U respectively) that the similarly written metavariable instan
tiates to is obviously present in the environment.
Case (eT.col): The conclusion is E #hm [e] T
hm # :T . All that remains to be shown is that fv hm # # domE . One premise
of the rule is E # hm # e:T . By Lemma E.4 (colours have to be ok), we have # hm # ok by a proper subproof, so by
induction fv hm # = ? whence the desired result.
Case N (in (mT.let)): Trivial as fv N = ?.
Case (nok.expr): The conclusion is # e ok and the premise is nil # . e:UNIT. By induction we have fv e # dom nil = ?
as desired.
INRIA
Global abstractionsafe marshalling with hash types 37
Definition E.10 (correctness judgement) A correctness judgement is a coloured judgement whose righthand side is of
one of the following forms:
ok, K ok, T :Type, S ok. (1)
Note that a derivation of a correctness judgement may involve other sorts of judgements. For example, in order to
derive U :S #hm U .TYPE:Type, one has to use (TK.mod), with a premise of the form U :S #hm U :S # .
Definition E.11 (type world judgement) A type world judgement is a coloured judgement whose righthand side is of
one of the following forms:
ok, K ok, K <: K # , K == K # , T == T # , T :K , S ok, S == S # , S <: S # , U :S . (2)
Note that any derivation of a type world judgement contains only type world judgements and nonclash judgement,
except in the proof of correctness of hashes.
E.3 Variables and colours
Definition E.12 (hashes in something) The hashes in a syntactic entity are the subterms that are hash(N , M :S ) and
that are not themselves subterms of a hash.
Definition E.13 (partial order on colours) We call topped colours the set formed by all colours (i.e. hm) plus a point #
that is distinct from any colour.
We define a partial order on topped colours as follows: hm 4 hm # iff hm = hm # or hm = . or hm # = #.
Note that 4 defines a poset with all greatest lower bounds, with . as the minimum element and # as the maximum
element.
Definition E.14 (pvu) Let # be a proof of a coloured judgement E #hm J , and let # be any variable. The set of colours
at which the variable # is used in the proof #, written pvu # (#), is defined as follows.
Consider the last rule used in the proof. The environment of its conclusion is an environment pattern. Take all the
metavariables # in this pattern whose instantiation in the last step of # contains # as a variable bound by the environment.
Then pvu # (#) is the union over all # of the following sets:
. If # occurs in the righthand side of the conclusion of the rule, anywhere but under an explicit bracket, then {hm},
else ?.
. For every occurence of # in the righthand side of the conclusion of the rule under an explicit bracket, the colour
that the subscript of the bracket instantiates to.
. For every occurence of # in the environment part of a premise which is a coloured judgement, pvu # (# # ) where # #
is the subproof of # that leads to said premise.
Note that with our current rules:
. Since (as we will prove) ok environments have no repetition in the domain, only one metavariable # is concerned.
It may be either a variable metavariable (
#) or an environment metavariable (
E ).
. If # /
# domE then there is no #, thus pvu # (#) = ?.
. The first case only arises if # is a variable metavariable, and the rule is one of (*.var) introducing that variable.
. The second case never arises (the only rule with an explicit bracket is (eT.col), and it has nothing from the environ
ment inside the bracket).
Definition E.15 (alternate, informal definition of pvu) Consider a proof # of a coloured judgement of the form
E 0 , #:#, E #hm J . The set of colours at which the variable # is pulled from the environment in #, written pvu # (#),
is the set of colours hm such that the judgement E 0 , #:#, E # #hm #:# appears in the proof as a conclusion of a varrule
((eT.var), (TK.var) or (US.var)).
If # is not in the domain of the conclusion of #, then we define pvu # (#) to be the empty set.
Lemma E.16 (monotonicity of pvu) If # # is a subproof of # then pvu # (# # ) # pvu # (#). Hence min pvu # (#) 4
min pvu # (# # ) .
RR n 4851
38 Leifer, Peskine, Sewell, Wansbrough
Proof. Trivial from the first definition.
Definition E.17 (substitution) Some potentially interesting cases:
#(mar (e 0 :T 0 )) = mar (#e 0 :#T 0 )
#(marshalled (e 0 :T 0 )) = marshalled (#e 0 :#T 0 )
#(unmar e 0 :T 0 ) = unmar#e 0 :#T 0
#([e 0 ] T
hm 0
) = [#e 0 ] #T
#hm 0
{U .TYPE T}U .TYPE = T
{U .term e}U .term = e
{U U # }U .TYPE = U # .TYPE
{U#U # }U .term = U # .term
Note that substitution performs all necessary alphaconversions. We generally leave alphaconversion implicit.
Lemma E.18 (stability of values by substitution) Let # be any substitution, hm be a colour and v hm be any hmvalue
with correct hashes. Then #v hm is an hmvalue.
Proof. Induct on the structure of v hm . As per the syntax of values, the only places where a value may contain free
variables are inside hashes or under a #. Since the hashes in v hm are assumed to be correct, they are closed by Lemma
E.9 (free variables of a judgement come from the environment). As for #'s, they allow an arbitrary expression, hence they
are stable by substitution.
Lemma E.19 (computing the pvu of a type world judgement) Let # be a proof of a type world judgement
E 0 , #:#, E #hm J . Then hm 4 min pvu # (#) .
Proof. Induct on the structure of #. We freely use Lemma E.6 (environments have to be ok) and Lemma E.8 (ok
environments have no repetition in the domain).
Consider first the rules whose conclusion is a type world judgement but for which J #= ok. Each premise has one of
the following properties:
1. The premise is a type world judgement whose colour is the same as in the conclusion and whose environment
contains the conclusion's.
2. The premise is either not a coloured judgement or a coloured judgement with an empty environment.
Suppose that the conclusion of # is obtained by such a rule. Then consider any subproof # # of # leading to a premise
of the aforementioned conclusion. One of the alternatives holds:
Case 1: By induction, hm 4 min pvu # (# # ) .
Case 2: Then pvu # (# # ) = ? whence hm 4 # = min pvu # (# # ) .
The set pvu # (#) is the union over all the premises of the pvu # (# # )'s, plus hm if the rule under consideration is (TK.var)
or (US.var) introducing #. Hence hm 4 min pvu # (#) .
Let us turn to the (envok.*) rules. We distinguish as to whether # is the variable being added to the environment.
Case (envok.*) not adding #: There exist E # , # # , and # # such that the conclusion is E 0 , #:#, E # , # # :# # #hm ok, and
the premises are # # /
# dom (E 0 , #:#, E # ) and E 0 , #:#, E # #hm # ok. Let # # be the subproof leading to the latter
judgement. Then by induction hm 4 min pvu # (# # ) , whence the desired result as pvu # (#) = pvu # (# # ).
Case (envok.*) adding #: The conclusion is E 0 , #:# #hm ok. The only premise that is a coloured judgement is E 0 #hm
# ok, which does not contain #. So pvu # (#) = ? whence hm 4 # = min pvu # (#) .
INRIA
Global abstractionsafe marshalling with hash types 39
Note that this lemma does not hold for expression typing judgements. We suspect that it would hold for shortest
proofs, for some notion of shortest proof. Here is a counter example, where the problem is the use of X in a ``useless''
fashion.
. . .
X :Eq(UNIT) # hm ok
(envok.X)
X :Eq(UNIT) # hm ():UNIT
. . .
X :Eq(UNIT) # hm X :Eq(UNIT)
(TK.var)
X :Eq(UNIT) # hm X == UNIT
X :Eq(UNIT) # hm UNIT == X
(Teq.sym)
X :Eq(UNIT) # hm ():X
. . .
X :Eq(UNIT) # hm X :Eq(UNIT)
(TK.var)
X :Eq(UNIT) # hm X == UNIT
X :Eq(UNIT) # hm ():UNIT
Lemma E.20 (connection between fv and fse) Let # be anything in the syntax. Then fv # # fse #. If x # fse # then
x # fv #. If X # fse # then X # fv #. If U # fse # or U .term # fse # or U .TYPE # fse # then U # fv #.
We may use this lemma implicitly.
Proof. Trivial from the definition of fv and fse .
Lemma E.21 (types do not contain free expression variables) If E #hm T :Type then fse T does not contain any
expression substitutable entity (i.e. ...
x ). Also, if E #hm K ok (respectively E #hm S ok) then fse K (respectively fse S )
does not contain any expression substitutable entity.
Note that fse # not containing any expression substitutable entity implies that fv # does not contain any free expression
variable.
Proof. Let us first prove this lemma for a type T . Induct on the structure of T . Most cases are either obvious (X ,
U .TYPE) or obvious by induction (constructed type). The only nontrivial case is a hash h . By Lemma E.5 (hashes have
to be ok), # h ok. By Lemma E.9 (free variables of a judgement come from the environment), fv h = ?, whence by
Lemma E.20 (connection between fv and fse) fse h = ?.
If E #hm Eq(T ) ok, then by reversing (Kok.Eq) we get E #hm T :Type, whence by the first part of this lemma
fse K = fse T has the desired property. The case E #hm Type ok is trivial (fse Type = ?).
If E #hm [X :K , T ] ok, then by reversing (Sok) we get E , X :K #hm T :Type. By the previous two paragraphs,
neither fse K nor fse T contains any expression substitutable entity, so the same holds for fse S = fse K # (fse T \ X ).
Lemma E.22 (environments do not contain free expression variables) If E 0 , E 1 #hm ok then fse E 1 does not contain
any expression substitutable entity.
Note that in particular fv E 1 does not contain any expression variable.
Proof. Induct on the length of E 1 . If E 1 = nil the conclusion is obvious. Otherwise there exist E #
1 , # and # such that
E 1 = E #
1 , #:# . By reversing the appropriate (envok.*) rule, we get E 0 , E #
1 #hm # ok. By Lemma E.6 (environments have
to be ok), we have E 0 , E #
1 #hm ok. By induction, we have ... x /
# fse E #
1 . Also, by Lemma E.21 (types do not contain free
expression variables), ... x /
# fse # (whether # is a type, kind or signature). Hence ... x /
# fse E 1 .
Lemma E.23 (expression substitution in environment) If E 0 , E 1 #hm ok and ... x is an expression substitutable entity
(i.e. an expression variable or U .term for some U ) then {
... x##}E 1 = E 1 .
Proof. Trivial consequence of Lemma E.22 (environments do not contain free expression variables).
F Type preservation by substitution
Lemma F.1 (``type of a machine'' judgements are not used to prove other coloured judgements)
Proof. No rule whose conclusion is a coloured judgement other than ``type of a machine'' has a premise that is a ``type of
a machine'' judgement.
Lemma F.2 (colour stripping judgements) If E #hm J and # hm # ok and hm 4 hm # then E # hm # J for all coloured
statements J other than ``type of a machine''.
RR n 4851
40 Leifer, Peskine, Sewell, Wansbrough
Proof. Induct on the derivation of E #hm J . In most rules where the conclusion is a coloured judgement, all the premises
either:
. do not involve the colour of the conclusion; or
. are a coloured judgement of the same colour, other than ``type of a machine'', so we can use induction to prove
them. Note that by Lemma F.1 (``type of a machine'' judgements are not used to prove other coloured judgements),
a premise that is a coloured judgement is never a ``type of a machine'' judgement.
If every premise of the last rule used in the derivation enjoys one of these properties, and if furthermore the rule applies
to arbitrary colours, (so that replacing hm by hm # does yield an instance of the rule again), we have E # hm # J . We list
the remaining cases.
Case (Teq.hash): Then hm #= ., so hm # = hm .
Case (TK.hash): Trivial (# hm # ok is assumed in this lemma).
Case (envok.nil): Trivial (# hm # ok is assumed in this lemma).
Case (eT.marred): Trivial.
Case (eT.col): Trivial.
Lemma F.3 (weakening) If E , E # , E ## #hm ok and E , E ## #hm J then E , E # , E ## #hm J .
Furthermore, if # # domE # and E , E # , E ## #hm ok is derived by a proof # such that pvu # (#) = ?, then there is a
proof # # of E , E # , E ## #hm J such that pvu # (# # ) = ?.
Proof. We freely use Lemma E.3 (nonmembership in domain is interpreted trivially).
Consider the variables that appear in the derivation of E , E ## #hm J but not in the judgement E , E ## #hm J itself. We
can alphaconvert them to variables that are not present in dom (E , E # , E ## ).
Induct on the derivation of E , E ## #hm J .
Note that the inductive rules that define derivable coloured judgements are all rewriting rules (in other words, there is
no side condition). Most rules have the following properties:
1. There is a distinguished environment metavariable
E such that the conclusion is a judgement with this metavariable
at the leftmost position and no other.
2. For each premise, one of the following conditions holds:
(a) The premise is a coloured judgement whose environment is either the same as the conclusion's or the one in
the conclusion followed by exactly one more binding.
(b) The premise is
# /
# dom
E for some
# that is in the domain of the conclusion.
(c) The premise does not mention
E .
Suppose that E , E ## #hm J was derived by an instance # of such a rule. There are two cases, depending on whether
the instantiation of
E (as per condition 1) includes the whole of E or not.
Case
E is instantiated by E , E ### : Then there exists E #### such that E ## = E ### , E #### .
Since we have a raw term rewriting system, we get an instance # of the same rule by instantiating
E by E , E # , E ###
and other variables as in #.
Let us prove that all the premises of # hold. Consider a premise in #, depending on which case of condition 2
holds:
INRIA
Global abstractionsafe marshalling with hash types 41
Case 2a: The premise is of the form E , E ## , E i #hm i
J i , where E i is of length at most one. By Lemma E.6
(environments have to be ok), E , E ## , E i #hm i
ok by a subproof.
If E i is empty, then we have E , E # , E ## , E i #hm i
ok. Otherwise there exist # and # such that E i = #:# .
The judgement E , E ## , #:# must have been derived by the appropriate (envok.*) rule from E , E ## #hm i # ok
and # /
# dom (E , E ## ). By induction, we have E , E # , E ## #hm i # ok, whence by the same (envok.*) rule
as previously: E , E # , E ## , #:# #hm i
ok (recalling that we performed alphaconversion on the proof so that
# /
# domE ## whence # /
# dom (E , E # , E ## )). If furthermore # # domE # and pvu # (#) = ?, then the
induction gives a proof # ## of E , E # , E ## , x :T #hm i
ok such that pvu # (# ## ) = ?.
In any case, E , E # , E ## , E i #hm i
ok, so we can apply induction, getting E , E # , E ## , E i #hm i
J i as desired.
If # # domE # and pvu # (#) = ?, then we have obtained a proof # ## of E , E # , E ## , E i #hm i
ok such that
pvu # (# ## ) = ?, and the last induction gives a proof # # of E , E # , E ## , E i #hm i
J i such that pvu # (# # ) = ?.
Case 2b: The premise is # # /
# dom (E , E ### ) with # # in dom (E , E ### , E #### ). Hence # # # domE #### . Since
E , E # , E ### , E #### #hm ok, by Lemma E.8 (ok environments have no repetition in the domain), we have
# /
# dom (E , E # , E ### ) as desired.
Case 2c: The premise in # is exactly the premise in #.
We have a derivation of all the premises in #, so we get a proof # # of its conclusion. Note further that if # # domE #
and pvu # (#) = ?, we do get that pvu # (# # ) = ?. (If # is an instance of a (*.var) rule, then # is not the variable
being introduced by # # domE # and Lemma E.8 (ok environments have no repetition in the domain).)
Case
E is instantiated by a proper prefix E ### of E : Only the following cases are concerned:
Case (envok.*): Trivial (take # # = #).
Case (*.var): Then there exists E #### such that E = E ### , #:#, E #### . By assumption, we have a proof # of
E ### , # # :#, E #### , E # , E ## #hm ok. By (*.var) we get a proof # # of E ### , # # :#, E #### , E # , E ## #hm # # :# as de
sired.
If # # domE # and pvu # (#) = ?, then pvu # (# # ) = ?, because # #= # # since # # domE # and Lemma E.8
(ok environments have no repetition in the domain).
The only rule whose conclusion is a coloured judgement that does not match the conditions above is (envok.nil). If the
last step of the derivation uses this rule, then its conclusion is nil #hm ok, and we desire a proof of E # #hm ok, which
holds by assumption: take # # = #.
Lemma F.4 (merging environments) If E , E # #hm ok and E , E ## #hm ok and domE # # domE ## = ? then
E , E # , E ## #hm ok.
Furthermore, if # # domE # and E , E # #hm ok is derived by a proof # such that pvu # (#) = ?, then there is a proof
# # of E , E # , E ## #hm ok such that pvu # (# # ) = ?.
Proof. We freely use Lemma E.3 (nonmembership in domain is interpreted trivially).
We induct on the length of E ## . If E ## = ?, the results are trivial. Now let us assume the lemma holds for E ## , #:# ,
and we have E , E ## , #:# #hm ok and domE # # dom (E ## , #:#) = ?.
By reversing the appropriate (envok.*) rule, we get E , E ## #hm # ok. By Lemma E.6 (environments have to be ok),
we have E , E ## #hm ok. By induction, we get E , E # , E ## #hm ok. By Lemma F.3 (weakening), we have E , E # , E ## #hm
# ok. Then by applying the appropriate (envok.*) rule we get E , E # , E ## , #:# #hm ok as desired.
Suppose furthermore that # # domE # and pvu # (#) = ?. Then the proof of E , E # , E ## #hm ok obtained above by
induction and that of E , E # , E ## #hm # ok obtained by Lemma F.3 (weakening) have an empty pvu for #, so the proof # #
of E , E # , E ## , #:# that we build satisfies pvu # (# # ) = ?.
Lemma F.5 (combined weakening) If E , E # #hm ok and E , E ## #hm J and domE # # domE ## = ? then
E , E # , E ## #hm J .
Furthermore, if # # domE # and E , E # #hm ok is derived by a proof # such that pvu # (#) = ?, then there is a proof
# # of E , E # , E ## #hm J such that pvu # (# # ) = ?.
Proof. Trivial combination of Lemma F.4 (merging environments) and Lemma F.3 (weakening).
Lemma F.6 (kinds are smaller than Type) If E #hm K ok then E #hm K <: Type.
RR n 4851
42 Leifer, Peskine, Sewell, Wansbrough
Proof. If K = Type, then we get E #hm Type <: Type by reversing (Kok.Type) and applying (Keq.Type) and
(Ksub.refl). Otherwise there exists T such that K = Eq(T ). Then by reversing (Kok.Eq) and applying (Ksub.Eq) we get
E #hm Eq(T ) <: Type.
Lemma F.7 (relating typeiskind and subkinding) If E #hm T :K then E #hm Eq(T ) <: K .
Proof. If K = Type, then we get the desired result by (Ksub.Eq). Otherwise there exists T # such that K = Eq(T # ).
Then by (Teq.Eq), (Keq.Eq) and (Ksub.refl) we get E #hm Eq(T ) <: Eq(T # ) as desired.
Lemma F.8 (components of modules are ok) If E #hm [T , v hm ]:[X :K , T # ] then there exists T ## such that E #hm T :K
and E , X :K #hm T # :Type and E , X :Eq(T ) #hm T ## == T # and E #hm v hm :T ## and E #hm K ok.
Proof. Reverse (MS.struct) to get the first four judgements. As for the last one, since E , X :K #hm T # :Type, by Lemma
E.6 (environments have to be ok) and reversing (envok.X), we get E #hm K ok.
Lemma F.9 (types are ok provided their hashes are) E #hm T :Type iff fv T # domE and E #hm ok and all the
hashes in T are ok.
Proof. Suppose that fv T # E and all the hashes in T are ok. We prove that E #hm T :Type by induction on the syntax
of T .
Case T = UNIT or T = STRING: Trivial by (TK.unit) or (TK.mar).
Case there exist T 1 , ..., T j such that T = T 1 # ... # T j : Note that fv T i # fv T # domE . By induction, E #hm T i
for 1 6 i 6 j . By (TK.tuple), we have E #hm T 1 # ... # T j :Type.
Case there exist T 1 , T 2 such that T = T 1 #T 2 : Note that fv T i # fv T # domE . By induction, E #hm T i for
1 6 i 6 2. By (TK.fun), we have E #hm T 1 #T 2 :Type.
Case T is a hash h: The hash h is ok by assumption, so we get E #hm h:Type by (TK.hash).
Case T is a type variable X : Since {X } = fv T # domE , there exist E 1 , K and E 2 such that E = E 1 , X :K , E 2 . By
(TK.var), we get E #hm X :K . By Lemma E.7 (prefixes of ok environments are ok) and reversing (envok.X), we
have E 1 #hm K ok, whence by Lemma F.3 (weakening) E #hm K ok. By Lemma F.6 (kinds are smaller than
Type), we have E #hm K <: Type, whence by (TK.sub) E #hm X :Type as desired.
Case there exists U such that T = U .TYPE: Since {U } = fv T # domE , there exist E 1 , K , T # and E 2 such that
E = E 1 , U :[X :K , T # ], E 2 . By (US.var) and (TK.mod), we get E #hm U .TYPE:K . By Lemma E.7 (prefixes of ok
environments are ok) and reversing (envok.U), we have E 1 #hm [X :K , T # ] ok, whence by Lemma F.3 (weakening)
E #hm [X :K , T # ] ok. By reversing (Sok), we have E #hm K ok. By Lemma F.6 (kinds are smaller than Type), we
have E #hm K <: Type, whence by (TK.sub) E #hm U .TYPE:Type as desired.
Now suppose E #hm T :Type. Then fv T # domE by Lemma E.9 (free variables of a judgement come from the
environment). Also all the hashes in T are ok by Lemma E.5 (hashes have to be ok).
Lemma F.10 (colour change preserves type okedness) If nil #hm 0
T :Type and nil #hm 1
ok then nil #hm 1
T :Type.
Proof. Trivial application of Lemma F.9 (types are ok provided their hashes are).
Definition F.11 (unresolved free variables of an environment) The unresolved free variables of an environment, written
ufv E , are defined as follows:
ufv nil = ?
ufv (#:#, E ) = (ufv (E ) \ {#}) # fv #
It is immediate that ufv E # ufv (E , E # ).
Lemma F.12 (computing unresolved free variables) ufv (E , E # ) = ufv E # (ufv E # \ domE )
INRIA
Global abstractionsafe marshalling with hash types 43
Proof. Induct on the length of E . The result is trivial if E is empty. If E = #:#, E ## , then ufv (E , E # ) = (ufv (E ## , E # ) \
{#})#fv # . By induction, ufv (E ## , E # ) = ufv E ## #(ufv E # \domE ## ). So ufv (E , E # ) = (ufv E ## #(ufv E # \domE ## )\
{#}) # fv # = (ufv E ## \ {#}) # (ufv E # \ (domE ## # {#})) # fv # = ufv E # (ufv E # \ domE ) as desired.
Lemma F.13 (ok environments have no unresolved free variables) If E #hm ok then ufv E = ?.
Proof. We prove by induction on the derivation size that E #hm J implies ufv E = ?. Most rules whose conclusion
is a coloured judgement E #hm J have at least one premise that is a coloured judgement whose environment is E , E #
for some E # , whence the induction hypothesis gives the desired result. Also, rules that have a conclusion of the form
nil #hm J are trivial.
The remaining rules are (envok.*). If we write the conclusion as E , #:# #hm ok, one premise is E #hm # ok. We
have ufv E = ? by induction. By Lemma E.9 (free variables of a judgement come from the environment), we have
fv # # domE . By Lemma F.12 (computing unresolved free variables), we have ufv (E , #:#) = ufv E # (ufv (#:#) \
domE ) = ? # (fv # \ domE ) thus ufv (E , #:#) = ? as desired.
Lemma F.14 (type preservation by substitution) If E 0 , #:#, E #hm J by a proof # such that hm # 4 min pvu # (#)
and E 0 # hm # #:# then E 0 , #E #hm #J where # = {###} and #:# is an expression or type binding.
Proof. Induct on the derivation # of E 0 , #:#, E #hm J .
Note that the inductive rules that define derivable coloured judgements are all rewriting rules (in other words, there is
no side condition). Most rules have the following properties:
1. There is a distinguished environment metavariable
E such that the conclusion is a judgement with this metavariable
at the leftmost position and no other.
2. For each premise, one of the following conditions holds:
(a) The premise is a judgement with
E in the leftmost position, and in no other place.
(b) The premise is
# /
# dom
E for some
#.
(c) The premise is a judgement with an empty environment and does not mention
E .
Suppose that E 0 , #:#, E #hm J was derived by an instance # of such a rule. Without loss of generality, # is not
in a binding position (including the domain of an environment) anywhere in E 0 , #:#, E #hm J except where shown;
furthermore # is not in a binding position in any premise either, except in instances of
E if and where this includes
E 0 , #:# . By condition 1, there are two possibilities:
General case: The instance # was obtained by instantiating the metavariable
E with E 0 , #:#, E ## , where E ## is an envi
ronment. Hence E is of the form E ## , E # , where E # is an environment.
Since we have a raw term rewriting system, we also get an instance # of the same rule by instantiating
E by E 0 , E ##
and other metavariables as in #. Note that # does not appear in any binding position in #.
Note that the only places in the syntax where an expression (respectively type) variable is required are:
. in binders, which doesn't matter for # as it does not affect variables that are bound in #. (+)
. in the lefthand side of a nonclash judgement. These only occur in (envok.*) rules, in the form
# /
# dom
E .
Let us write # # for the instantiation of
#. Then # # #= # as # # /
# dom (E 0 , #:#, E ## ) is derivable.
Note furthermore that welltyped values are stable by substitution, as per Lemma E.18 (stability of values by
substitution). 1 Hence # is a wellsorted raw term substitution on # or any subterm thereof, so applying # to # yields
another instance # of the rule. Note that the conclusion of # is #E 0 , #E ## #hm #J , which is also E 0 , #E ## #hm J
as # /
# fv E 0 by Lemma E.6 (environments have to be ok), Lemma E.7 (prefixes of ok environments are ok) and
Lemma F.13 (ok environments have no unresolved free variables).
Consider the premises in #, depending on which case of condition 2 holds:
Case 2a: The premise is of the form E 0 , #:#, E ## , E #
i #hm i
J i . Given Lemma E.16 (monotonicity of pvu), we
can apply induction, getting E 0 , #E ## , #E #
i #hm i
#J i , which is the corresponding premise in # (recall that
#E 0 = E 0 ).
1 This is needed for (MS.struct), which requires a value in one place.
RR n 4851
44 Leifer, Peskine, Sewell, Wansbrough
Case 2b: The premise is of the form # # /
# dom (E 0 , #:#, E ## ), and # # is not # (see (+) above). We need to prove that
# # /
# dom (E 0 , #E ## ). This follows easily, given that dom (E 0 , #E ## ) = dom (E 0 , E ## ) # dom (E 0 , #:#, E ## ).
Case 2c: The premise is a judgement AJ with an empty environment, so by Lemma E.9 (free variables of a judge
ment come from the environment) # is not free in AJ. Hence #AJ = AJ. Furthermore the premise does not
include any instantation of
E , so it is in fact exactly the premise needed in #.
As all the premises of # are derivable, its conclusion holds. It reads: E 0 , #E ## , #E # #hm #J , which is what we set
out to prove.
Special cases: The instance was obtained by instantiating the metavariable
E to a prefix E 1 of E 0 : so there is E 2 such
that E 0 = E 1 , E 2 . Only the following cases of the following rules are concerned.
Cases (envok.*): Then E = nil and E 2 = nil. The proof obligation is E 1 #hm ok, i.e. E 0 #hm ok, which holds
by Lemma E.7 (prefixes of ok environments are ok).
Cases (eT.var), (TK.var): # is of the form
E 0 , #:#, E # #hm ok
E 0 , #:#, E # #hm #:#
and # = {# #}, and we have E 0 # hm # #:# with hm # 4 min pvu # (#) 4 hm . By induction (which we can
apply thanks to Lemma E.16 (monotonicity of pvu)), we have E 0 , #E # #hm ok.
Furthermore, since # hm ok by Lemma E.4 (colours have to be ok), E 0 #hm #:# by Lemma F.2 (colour
stripping judgements). By Lemma F.3 (weakening) we get E 0 , #E # #hm #:# as desired.
Every remaining rule is inapplicable because the environment in the conclusion must be empty.
Lemma F.15 (strengthening) If E 0 , #:#, E #hm J and # /
# fv E # fv J and #:# is a type or expression variable binding
then E 0 , E #hm J .
Proof. By Lemma E.6 (environments have to be ok) and Lemma E.7 (prefixes of ok environments are ok), we have
E 0 , #:# #hm ok. Let us then reverse the rule (envok.*) that was applied to obtain this latter judgement:
Case #:# is X :K : Then we have E 0 #hm K ok. If K = Type, by (TK.unit), we have E 0 #hm UNIT:K ; let # be
UNIT. Otherwise there exists a type # such that K = Eq(#); by reversing (Kok.Eq), we get E 0 #hm #:Type. By
Lemma F.10 (colour change preserves type okedness), we have E 0 # . #:Type. By (Teq.refl) and (TK.Eq), we get
E 0 #hm #:K .
Case #:# is x :T : Then we have E 0 #hm T :Type, whence by Lemma F.10 (colour change preserves type okedness):
E 0 # . T :Type. Let # be UnmarFailure T . By (eT.Undynfailure), we have E 0 # . #:T .
In any case, we have E 0 # . #:# . By Lemma F.14 (type preservation by substitution), we have E 0 , #E #hm #J where
# = {# #}. However, by assummption, # /
# fv E # fv J . Hence #E = E and #J = J , so we get E 0 , E #hm J as
desired.
This proof of strengthening calls the main substitution lemma. This has two inconveniences:
. It does not work for module variables. In fact, if we expanded the proof of the substitution lemma, we would see
that the (envok.*) case dealing with # is never invoked, so it does not matter than the substitution lemma does not
have such a case for module variables.
. It requires that kinds and types not be empty, which is true for a convoluted reason (all our kinds happen to be
nonempty, and each of our types T contains the exception UnmarFailure T ).
Definition F.16 (visible typepart of a module)
typepart (N , [T , v hm ]:[X :K , T # ]) = ( hash(N , [T , v hm ]:[X :K , T # ]) if K = Type
T 0 if K = Eq(T 0 ) for some T 0
INRIA
Global abstractionsafe marshalling with hash types 45
Definition F.17 (visible termpart of a module)
termpart (N , [T , v hm ]:[X :K , T # ]) = ( [v hm ] {X#h}T #
h if K = Type
v hm if K = Eq(T 0 ) for some T 0
where h = hash(N , [T , v hm ]:[X :Type, T # ]).
Definition F.18 (set of equations used to type a module)
equations (N , [T , v hm ]:[X :K , T # ]) = ( hash(N , [T , v hm ]:[X :K , T # ]) if K = Type
. if K = Eq(T 0 ) for some T 0
Lemma F.19 (reflexivity of kind equivalence) If E #hm K ok then E #hm K == K .
Proof. If K = Type then this lemma holds by (Keq.Type). Otherwise there exists T such that K = Eq(T ). The
judgement E #hm K ok must have been derived by (Kok.Eq), from E #hm T :Type. Then by (Teq.refl) followed by
(Keq.Eq) we have E #hm Eq(T ) == Eq(T ) as desired.
Lemma F.20 (weakening kind to ok kind in the environment) If E 0 #hm K <: K # and E 0 #hm K ok and
E 0 , X :K # , E 1 #hm J and J is a type world judgement righthand side then E 0 , X :K , E 1 #hm J .
Note that the hypothesis E 0 #hm K ok is in fact superfluous (see Lemma (weakening kind in the environment) below).
Proof. Since E 0 #hm K ok, by (envok.X), E 0 , Y :K #hm ok where Y is fresh. By Lemma F.3 (weakening), from
E 0 , Y :K #hm ok and E 0 #hm K # ok, we get E 0 , Y :K #hm K # ok. By (envok.X), E 0 , Y :K , X :K # #hm ok.
By Lemma F.5 (combined weakening), E 0 , Y :K , X :K # , E 1 #hm J .
From E 0 , Y :K #hm ok, by (TK.var), we get E 0 , Y :K #hm Y :K . By Lemma F.3 (weakening), we also get
E 0 , Y :K #hm K <: K # . By (TK.sub), we get E 0 , Y :K #hm Y :K # . By Lemma F.14 (type preservation by substi
tution), using Lemma E.19 (computing the pvu of a type world judgement) E 0 , Y :K # , {X Y }E 1 #hm {X Y }J . By
alphaconversion, we have E 0 , X :K # , E 1 #hm J as desired.
Lemma F.21 (things have to be ok) If E #hm T :K then E #hm K ok.
If E #hm T == T # then E #hm T :Type and E #hm T # :Type.
If E #hm K == K # or E #hm K <: K # then E #hm K ok and E #hm K # ok.
If E #hm S == S # or E #hm S <: S # then E #hm S ok and E #hm S # ok.
If E #hm e:T or E #hm m:T then E #hm T :Type.
If E #hm M :S or E #hm U :S then E #hm S ok.
Proof. Induct on the size of the derivation of the hypothesis. Consider the last rule used in said derivation.
Case (TK.sub): The conclusion is E #hm T :K # and one of the premises is E #hm K <: K # . By induction, we get
E #hm K # ok.
Case (TK.Eq): The conclusion is E #hm T :Eq(T # ). The premise is E #hm T == T # . By induction we have
E #hm T # :Type, hence E #hm Eq(T # ) ok by (Kok.Eq).
Case (TK.mod): The conclusion is E #hm U .TYPE:K . The premise is E #hm U :[X :K , T ]. By induction we have
E #hm [X :K , T ] ok. This must have been obtained by applying (Sok), with the premise E , X :K #hm T :Type.
By Lemma E.6 (environments have to be ok), we have E , X :K #hm ok that is smaller. Hence, by reversing
(envok.X), we get a proof of E #hm K ok.
Cases (TK.unit), (TK.fun), (TK.mar), (TK.tuple), (TK.hash): The conclusion is of the form E #hm T :Type for some
T . By Lemma E.6 (environments have to be ok), E #hm ok. By (Kok.Type), we have E #hm Type ok.
Case (TK.var): The conclusion is of the form E , X :K , E # #hm X :K . The premise is E , X :K , E # #hm ok. By Lemma
E.7 (prefixes of ok environments are ok) and reversing (envok.X), we get E #hm K ok. By Lemma F.3 (weakening),
we get E , X :K , E # #hm K ok as desired.
Note that the proof may be bigger, since the part that proves K has to be duplicated...
RR n 4851
46 Leifer, Peskine, Sewell, Wansbrough
Case (Teq.Eq): The conclusion is E #hm T == T # . The premise is E #hm T :Eq(T # ). By induction we have
E #hm Eq(T # ) ok, which must have been derived by (Kok.Eq) from E #hm T # :Type. Also, from this, we get
E #hm Eq(T # ) <: Type by (Ksub.Eq). We can apply (TK.sub) to get E #hm T :Type.
Note that this may well be the shortest way to obtain E #hm T :Type (take T = U .TYPE).
Case (Teq.hash): The conclusion is E #hm hm == T , and hm = h = hash(N , [T , v hm 1 ]:S ). The premise is
E #hm ok. By Lemma E.4 (colours have to be ok), we get # hash(N , [T , v hm 1 ]:S ) ok. By reversing (hmok.hash)
and (MS.struct), we get nil # . T :Type. By Lemma F.3 (weakening), we get E #hm T :Type. We also have
E # h h:Type by (TK.hash).
Case (Teq.refl): Trivial.
Cases (Teq.sym), (Teq.tran): Trivial by induction.
Case (Teq.cong.fun): The conclusion is E #hm T 0 #T 1 == T #
0 #T #
1 . By induction on the premises, we get
E #hm T j :Type and E #hm T #
j :Type for j = 0, 1. By (TK.fun), we get E #hm T 0 #T 1 :Type and
E #hm T #
0 #T #
1 :Type.
Case (Teq.cong.tuple): Similar to case (Teq.cong.fun).
Case (Ksub.Eq): The conclusion is E #hm Eq(T ) <: Type. The premise is E #hm T :Type. From this, by (Kok.Eq),
we get E #hm Eq(T ) ok. By Lemma E.6 (environments have to be ok), we have E #hm ok. Thus, by (Kok.Type),
we have E #hm Type ok.
Cases (Ksub.refl), (Ksub.tran): Trivial by induction.
Case (Keq.Type): The premise is E #hm ok. By (Kok.Type), we get E #hm Type ok.
Case (Keq.Eq): The conclusion is E #hm Eq(T ) == Eq(T # ). The premise is E #hm T == T # . By induction we get
E #hm T :Type and E #hm T # :Type, whence by (Kok.Eq), E #hm Eq(T ) ok and E #hm Eq(T # ) ok
Case (Ssub.struct): The conclusion is E #hm [X :K , T ] <: [X :K # , T # ]. One premise is E , X :K #hm T == T # . By
induction, we get E , X :K #hm T :Type and E #hm T # :Type, whence the desired results by (Sok).
Case (Seq.struct): Similar to case (Ssub.struct).
Case (Ssub.refl): Trivial.
Case (Ssub.tran): Trivial.
Case (eT.var): Similar to case (TK.var).
Case (eT.eq): The conclusion is E #hm e:T # . One premise is E #hm T == T # . By induction we get E #hm
T # :Type.
Case (eT.mod): The conclusion is E #hm U .term:T . One premise is E #hm T :Type.
Case (eT.ap): The conclusion is E #hm e e # :T # . One premise is E #hm e # :T#T # . By induction we get E #hm
T#T # :Type. By Lemma F.9 (types are ok provided their hashes are) applied to E #hm T#T # then to E #hm T # ,
we get E #hm T # :Type as desired.
Case (eT.fun): The conclusion is E #hm #x :T .e:T#T # . The premise is E , x :T #hm e:T # . By induction, we get
E , x :T #hm T # :Type by a proof #. By Lemma E.21 (types do not contain free expression variables), x /
# fv T # .
By Lemma E.6 (environments have to be ok), we have E #hm ok. By Lemma F.9 (types are ok provided their
hashes are) applied once in each direction, we get first that the hashes in T # are ok and fv T # # domE # {fv }
(hence fv T # # domE ), then that E #hm T # ok. Also, by Lemma E.6 (environments have to be ok), we get
E , x :T #hm ok, whence E #hm T :Type by reversing (envok.x). By (TK.fun), we get E #hm T#T # :Type.
Cases (eT.send), (eT.recv), (eT.mar), (eT.marred), (eT.unit): By Lemma E.6 (environments have to be ok), we have
E #hm ok. Then (TK.unit) or (TK.mar) gives the desired result.
Cases (eT.unmar), (eT.Undynfailure), (eT.col): Trivial (one of the premises is what we need to prove).
INRIA
Global abstractionsafe marshalling with hash types 47
Case (eT.tuple): The conclusion is E #hm (e 1 , ..., e j ):T 1 # ... # T j . The premises are E #hm e i :T i for 1 6 i 6 j . By
induction, we have E #hm T i :Type for all i , whence by (TK.tuple): E #hm T 1 # ... # T j :Type.
Case (eT.proj): Similar to (eT.ap).
Case (MS.struct): The conclusion is E #hm M :[X :K , T ]. One premise is E , X :K #hm T :Type, whence by (Sok):
E #hm [X :K , T ] ok.
Case (US.var): Similar to case (TK.var).
Case (US.sub): The conclusion is E #hm U :S # . One premise is E #hm S <: S # . By induction, we have E #hm S # ok.
Case (US.self): The conclusion is E #hm U :[X :Eq(U .TYPE), T ]. The premise is E #hm U :[X :K , T ]. By (TK.mod),
we have E #hm U .TYPE:K . And by induction we get E #hm [X :K , T ] ok, whence by reversing (Sok):
E , X :K #hm T :Type.
By Lemma E.6 (environments have to be ok) and reversing (envok.X), we have E #hm K ok. By Lemma F.6
(kinds are smaller than Type), we get E #hm K <: Type. By (TK.sub), given that E #hm U .TYPE:K , we have
E #hm U .TYPE:Type, whence by (Kok.Eq): E #hm Eq(U .TYPE) ok.
If K = Type, by Lemma F.6 (kinds are smaller than Type), we get E #hm Eq(U .TYPE) <: Type. Otherwise
there exists T 1 such that K = Eq(T 1 ). From E #hm U .TYPE:Eq(T 1 ), by (Teq.Eq), (Keq.Eq) and (Ksub.refl), we
get E #hm Eq(U .TYPE) <: Eq(T 1 ). In either case we have E #hm Eq(U .TYPE) <: K .
By Lemma F.20 (weakening kind to ok kind in the environment), E , X :Eq(U .TYPE) #hm T :Type. Hence by
(Sok) we have E #hm [X :Eq(U .TYPE), T ] ok.
Cases (mT.expr), (mT.let): Trivial by induction.
Lemma F.22 (weakening kind in the environment) If E 0 #hm K <: K # and E 0 , X :K # , E 1 #hm J and J is a type
world judgement righthand side then E 0 , X :K , E 1 #hm J .
Proof. By Lemma F.21 (things have to be ok), E 0 #hm K ok. By Lemma F.20 (weakening kind to ok kind in the
environment), we get the desired result.
Lemma F.23 (type preservation by guarded expression variable substitution) If E 0 , x :T , E #hm J and E 0 # hm # e:T
and E 0 # .
ok then E 0 , #E #hm #J where # = {x#[e] T
hm # }.
Proof. E 0 # hm # T :Type by Lemma F.21 (things have to be ok). By Lemma F.9 (types are ok provided their hashes are)
applied one in each direction, we get E 0 # . T :Type. Applying (eT.col) to this and E 0 # hm # e:T yields E 0 # . [e] T
hm # :T .
We can now apply Lemma F.14 (type preservation by substitution) to get the desired result.
Lemma F.24 (type equivalence is a congruence) If E #hm T # == T ## and E , X :Type #hm T :Type then E #hm
{X#T # }T == {X#T ## }T .
Proof. Induct on the structure of T .
Case T = UNIT or T = STRING or T = U .TYPE or T = Y #= X or T = h 1 : Then X /
# fv T (if T = h 1 , this is be
cause fv T = ? by Lemma E.5 (hashes have to be ok) and Lemma E.9 (free variables of a judgement come
from the environment)). By Lemma F.9 (types are ok provided their hashes are), the hashes of T are ok and
fv T # domE # {X }. By Lemma F.9 (types are ok provided their hashes are) in the other direction, since
fv T # E , we have E #hm T :Type. By (Teq.refl), we get E #hm T == T which is the desired result.
Case T = X : We have E #hm T ## == T ## as desired.
Case T = T 1 #T 2 : By induction, we have E #hm {X#T # }T i == {X#T ## }T i for i = 1, 2. By (Teq.cong.fun), we
get E #hm {X#T # }T == {X#T ## }T as desired.
Case T = T 1 # ... # T j : By induction, we have E #hm {X#T # }T i == {X#T ## }T i for i = 1, ..., j . By
(Teq.cong.tuple), we get E #hm {X#T # }T == {X#T ## }T as desired.
RR n 4851
48 Leifer, Peskine, Sewell, Wansbrough
Lemma F.25 (type substitution in equivalence) If E #hm {X T 0 }T == {X T 0 }T # and E = E 0 , X :Eq(T 0 ), E 1
then E #hm okT == T # .
Proof. By (TK.var) and (Teq.Eq), we have E #hm X == T 0 . Let Y be a fresh variable, i.e. Y /
# domE . By Lemma
E.6 (environments have to be ok) and (Kok.Type) and (envok.X), we have E , Y :Type #hm ok. By Lemma F.9 (types
are ok provided their hashes are) applied once in each direction, we get that E , Y :Type #hm {X Y }T :Type. Then,
by Lemma F.24 (type equivalence is a congruence), we get E #hm {Y X }{X Y }T == {Y T 0 }{X Y }T , i.e.
E #hm T == {X T 0 }T .
Similarly, we have E #hm T # == {X T 0 }T # . By (Teq.sym), we get E #hm {X T 0 }T # == T # .
Finally, by two applications of (Teq.tran), we get E #hm T == T # as desired.
Lemma F.26 (reversing subsignaturing judgement) If E #hm [X :K , T ] <: [X :K # , T # ] then E #hm K <: K # and
E , X :K #hm T == T # .
Proof. Induct on the derivation of E #hm [X :K , T ] <: [X :K # , T # ].
Case (Ssub.refl): The premise is E #hm [X :K , T ] ok, which must have been derived by (Sok) from E , X :K #hm
T :Type. By (Teq.refl), we have E , X :K #hm T == T . By Lemma E.6 (environments have to be ok), we
have E , X :K #hm ok. By reversing (envok.X), we get E #hm K ok whence E #hm K <: K by Lemma F.19
(reflexivity of kind equivalence) and (Ksub.refl).
Case (Ssub.tran): The premises are E #hm [X :K , T ] <: [X :K ## , T ## ] and E #hm [X :K ## , T ## ] <: [X :K # , T # ]. By
induction twice, we have: E #hm K <: K ## , E , X :K #hm T == T ## , E #hm K ## <: K # and E , X :K ## #hm
T ## == T # . By (Ksub.tran), we have E #hm K <: K # . By Lemma F.22 (weakening kind in the environment), we
get E , X :K #hm T == T # as desired.
Case (Ssub.struct): The premises are the desired judgements.
Lemma F.27 (reversing module value variable typing judgement) If E #hm U :S then there exist E 0 , E 1 , K , T such
that E = E 0 , U :[X :K , T ], E 1 and E #hm [X :Eq(U .TYPE), T ] <: S .
Proof. Induct on the derivation of E #hm U :S .
Case (US.var): Then there exist E 0 , E 1 , K , T such that E = E 0 , U :[X :K , T ], E 1 and S = [X :K , T ]. The premise
is E #hm ok. By (US.self) and (TK.mod), we have E #hm U .TYPE:K . By Lemma F.7 (relating typeiskind
and subkinding), we get E #hm Eq(U .TYPE) <: K . By Lemma F.21 (things have to be ok) and reversing (Sok),
we get E , X :K #hm T :Type. By Lemma F.9 (types are ok provided their hashes are) applied once in each
direction, given that E , X :Eq(U .TYPE) #hm ok by Lemma F.21 (things have to be ok) and (envok.X), we get
E , X :Eq(U .TYPE) #hm T :Type. By (Ssub.struct), we get E #hm [X :Eq(U .TYPE), T ] <: S as desired.
Case (US.sub): There exists S # such that the premises are E #hm U :S # and E #hm S # <: S . By induction,
we have E = E 0 , U :[X :K , T ], E 1 and E #hm [X :Eq(U .TYPE), T ] <: S # . By (Ssub.tran) we get E #hm
[X :Eq(U .TYPE), T ] <: S as desired.
Case (US.self): There exist K # and T # such that S = [Eq(U .TYPE), T # ] and the premise is E #hm U :[X :K # , T # ].
By induction we have E = E 0 , U :[X :K , T ], E 1 and E #hm [X :Eq(U .TYPE), T ] <: [X :K # , T # ]. By Lemma
F.26 (reversing subsignaturing judgement), we have E , X :Eq(U .TYPE) #hm T == T # . Given that we also have
E #hm Eq(U .TYPE) <: Eq(U .TYPE) (by Lemma F.21 (things have to be ok), (Teq.refl), (Keq.Eq) and (Ksub.refl)),
by (Ssub.struct), we get E #hm [X :Eq(U .TYPE), T ] <: S as desired.
Lemma F.28 (obtaining module value variable typing judgement) If E 0 , U :[X :K , T ], E 1 #hm
[X :Eq(U .TYPE), T ] <: S then E 0 , U :[X :K , T ], E 1 #hm U :S .
INRIA
Global abstractionsafe marshalling with hash types 49
Proof. Write E = E 0 , U :[X :K , T ], E 1 . By Lemma E.6 (environments have to be ok), (US.var) and (US.self), we have
E #hm U :[X :Eq(U .TYPE), T ]. By (US.sub), we get E #hm U :S as desired.
Lemma F.29 (type preservation by module substitution in coloured judgements) Suppose E 0 , U :[X :K , T ], E #hm J
and z and Z are fresh and # = {U .TYPE Z , U .term z }.
If J = U :S # for some S # then E 0 , Z :K , z :{X #Z}T , #E #hm [X :Eq(Z ), T ] <: #S # .
Otherwise E 0 , Z :K , z :{X #Z}T , #E #hm #J
Proof. Write S = [X :K , T ]. Without loss of generality, we assume that X /
# domE . We induct on the derivation # of
E 0 , U :S , E #hm J .
Note that the inductive rules that define derivable coloured judgements are all rewriting rules (in other words, there is
no side condition). Most rules have the following properties:
1. There is a distinguished environment metavariable
E such that the conclusion is a judgement with this metavariable
at the leftmost position and no other.
2. For each premise, one of the following conditions holds:
(a) The premise is a judgement with
E in the leftmost position, and in no other place. Also the righthand side of
the premise is not U :S # for any S # .
(b) The premise is
# /
# dom
E for some
#.
(c) The premise is a judgement with an empty environment and does not mention
E .
Suppose that E 0 , U :S , E #hm J was derived by an instance # of such a rule. Without loss of generality, U is not in a
binding position (including the domain of an environment) anywhere in # except as the first binding in an instance of
E .
We distinguish two possibilities, using 1:
General case: The instance # was obtained by instantiating the metavariable
E with E 0 , U :S , E ## , where E ## is an
environment. Hence E is of the form E ## , E # , where E # is an environment. Also, in this part of the proof, we assume
that J is not of the form U :S # , and that the rule is not one of (TK.mod) or (eT.mod) with U in the conclusion.
Since we have a raw term rewriting system, we also get an instance # of the same rule by instantiating
E by
E 0 , Z :K , z :{X #Z}T , E ## and other metavariables as in #. Note that U does not appear in any binding position
in #.
Note that # is a wellsorted raw term substitution on # or any subterm thereof, so applying # to # yields another
instance # of the rule. Note that #(Z :K , z :{X #Z}T , E ## ) = Z :K , z :{X #Z}T , #E ## .
Consider the premises in #, depending on which case of condition 2 holds:
Case 2a: The premise is of the form E 0 , U :S , E ## , E #
i #hm i
J i . Furthermore J i is not U :S # for any S # , be
cause we have excluded the rules (TK.mod) and (eT.mod) in the problematic case. By induction, we get
E 0 , Z :K , z :{X #Z}T , #E ## , #E #
i #hm i #J i , which is the corresponding premise in #.
Case 2b: The premise is of the form # # /
# dom (U :S , E ## ) for some # # . Given that dom#E ## =
domE ## # dom (U :S , E ## ), we have # # /
# dom#E ## . Since Z and z are fresh, we have # # /
#
dom (Z :K , z :{X #Z}T , #E ## ).
Case 2c: The premise is a judgement AJ with an empty environment, so by Lemma E.9 (free variables of a judge
ment come from the environment) U is not free in AJ. Hence #AJ = AJ. Furthermore the premise does not
include any instantation of
E , so it is in fact exactly the premise needed in #.
As all the premises of # are derivable, its conclusion holds. It reads: E 0 , Z :K , z :{X #Z}T , #E ## , #E # #hm #J ,
which is what we set out to prove.
Case
E is instantiated to a prefix of E 0 and J is not U :S # for any S # : Only the following cases of the following rules
are concerned.
Case (envok.U): We have E 0 , U :S #hm ok, and one of the premises is nil #hm S ok. By reversing (Sok), we
have E 0 , X :K #hm T :Type. By alphaconversion, we get E 0 , Z :K #hm {X Z}T :Type. By (envok.x),
we have E 0 , Z :K , z :{X Z}T #hm ok as desired.
RR n 4851
50 Leifer, Peskine, Sewell, Wansbrough
Case (US.var): Impossible: J would be U :S .
Case (TK.mod) where J = U .TYPE:K # for some K # : Then there exists T # such that the premise is E 0 , U :S , E #hm
U :[X :K # , T # ]. By induction, we get E 0 , Z :K , z :{X Z}T , #E #hm [X :Eq(Z ), T ] <: #[X :K # , T # ]. By
Lemma F.26 (reversing subsignaturing judgement), we get E 0 , Z :K , z :{X Z}T , #E #hm Eq(Z ) <: #K # .
By Lemma E.6 (environments have to be ok), (TK.var) and (TK.sub), we get E 0 , Z :K , z :{X Z}T , #E #hm
Z :Type. By (Teq.refl), and (TK.Eq), we get E 0 , Z :K , z :{X Z}T , #E #hm Z :Eq(Z ). By (TK.sub), we get
E 0 , Z :K , z :{X Z}T , #E #hm Z :#K # .
Case (eT.mod) where J = U .term:T # for some T # : Then there exists K # such that the premises are
E 0 , U :S , E #hm U :[X :K # , T # ] and E 0 , U :S , E #hm T # :Type. By applying induction, we get that
E 0 , Z :K , z :{X Z}T , #E #hm [X :Eq(Z ), T ] <: #[X :K # , T # ]. By Lemma F.26 (reversing subsignatur
ing judgement), we have E 0 , Z :K , z :{X Z}T , #E , X :Eq(Z ) #hm T == #T # .
By Lemma E.6 (environments have to be ok), Lemma E.7 (prefixes of ok environments are ok) and
(TK.var), we have E 0 , Z :K , z :{X Z}T , #E #hm Z :K . By Lemma F.21 (things have to be ok), we have
E 0 , Z :K , z :{X Z}T , #E #hm K ok. By Lemma F.6 (kinds are smaller than Type) and (TK.sub), we have
E 0 , Z :K , z :{X Z}T , #E #hm Z :Type. By (Teq.refl) and (TK.Eq), we have E 0 , Z :K , z :{X Z}T , #E #hm
Z :Eq(Z ).
By Lemma F.14 (type preservation by substitution), given Lemma E.19 (computing the pvu of a type world judge
ment), we get E 0 , Z :K , z :{X Z}T , #E #hm {X Z}T == {X Z}{U .TYPE Z , U .term z}T # . Since
E 0 , U :S , E #hm T # :Type, by Lemma E.9 (free variables of a judgement come from the environment), we have
X /
# fv T # , so we have E 0 , Z :K , z :{X Z}T , #E #hm {X Z}T == #T # .
By Lemma E.6 (environments have to be ok) and (eT.var), we have E 0 , Z :K , z :{X Z}T , #E #hm z :{X Z}T .
By (eT.eq), we get E 0 , Z :K , z :{X Z}T , #E #hm z :#T # as desired.
Case J = U :S # for some S # : We have E 0 , U :S , E #hm U :S # .
Subcase (US.var): We have E 0 , U :S , E #hm U :S (thanks to Lemma E.8 (ok environments have no repetition in
the domain)). The premise is E 0 , U :S , E #hm ok.
By induction, we have E 0 , Z :K , z :{X Z}T , #E #hm ok.
By (TK.var) E 0 , Z :K , z :{X Z}T , #E #hm Z :K . By Lemma F.7 (relating typeiskind and subkinding),
we have E 0 , Z :K , z :{X Z}T , #E #hm Eq(Z ) <: K .
By Lemma E.6 (environments have to be ok), Lemma E.7 (prefixes of ok environments are ok), reversing
(envok.U) and Lemma F.21 (things have to be ok), we have nil #hm S ok. By reversing (Sok), we get
X :K #hm T :Type. By Lemma E.6 (environments have to be ok), we have X :K #hm ok. By reversing
(envok.X) and Lemma F.3 (weakening), we have X :K #hm K ok, so by (envok.X), we get E 0 , Z :K , X :K #hm
ok. By Lemma F.3 (weakening), we have E 0 , Z :K , X :K #hm T :Type.
By Lemma E.7 (prefixes of ok environments are ok), and by (TK.var) and Lemma F.7 (relating typeiskind
and subkinding) as before, we have E 0 , Z :K #hm Eq(Z ) <: K . By Lemma F.22 (weakening kind in the
environment), we have E 0 , Z :K , X :Eq(Z ) #hm T :Type.
By (TK.var), Lemma F.21 (things have to be ok), Lemma F.6 (kinds are smaller than Type) and
(TK.sub), we have E 0 , Z :K , z :{X Z}T , #E #hm Z :Type. Thus, by (Kok.Eq) and (envok.X), we have
E 0 , Z :K , z :{X Z}T , #E , X :Eq(Z ) #hm ok.
By Lemma F.3 (weakening), we have E 0 , Z :K , z :{X Z}T , #E , X :Eq(Z ) #hm T :Type. By (Teq.refl),
we get E 0 , Z :K , z :{X Z}T , #E , X :Eq(Z ) #hm T == T .
By (Ssub.struct), we get E 0 , Z :K , z :{X Z}T , #E #hm [X :Eq(Z ), T ] <: [X :K , T ].
By Lemma E.9 (free variables of a judgement come from the environment), U /
# fv S . So we have
E 0 , Z :K , z :{X Z}T , #E #hm [X :Eq(Z ), T ] <: #S as desired.
Subcase (US.sub): We have E 0 , U :S , E #hm U :S # , and there exists S ## such that the premises are
E 0 , U :S , E #hm U :S ## and E 0 , U :S , E #hm S ## <: S # . By induction over each premise, we get
E 0 , Z :K , z :{X Z}T , #E #hm [X :Eq(Z ), T ] <: #S ## and E 0 , Z :K , z :{X Z}T , #E #hm #S ## <: #S # .
By (Ssub.tran), we get E 0 , Z :K , z :{X Z}T , #E #hm [X :Eq(Z ), T ] <: #S # as desired.
INRIA
Global abstractionsafe marshalling with hash types 51
Subcase (US.self): We have E 0 , U :S , E #hm U :[X :Eq(U .TYPE), T # ]. There exists K # such that the
premise is E 0 , U :S , E #hm U :[X :K # , T # ]. By induction, we get E 0 , Z :K , z :{X #Z}T , #E #hm
[X :Eq(Z ), T ] <: #[X :K # , T # ]. By Lemma F.26 (reversing subsignaturing judgement), we get
E 0 , Z :K , z :{X #Z}T , #E , X :Eq(Z ) #hm T == #T # .
By Lemma E.6 (environments have to be ok) and (TK.var), we have E 0 , Z :K , z :{X Z}T , #E #hm
Z :K . By Lemma F.21 (things have to be ok) and Lemma F.6 (kinds are smaller than Type), we
have E 0 , Z :K , z :{X Z}T , #E #hm Z :Type. By (Teq.refl), (Keq.Eq) and (Ksub.refl), we have
E 0 , Z :K , z :{X Z}T , #E #hm Eq(Z ) <: Eq(Z ).
By (Ssub.struct), we get E 0 , Z :K , z :{X Z}T , #E #hm [X :Eq(Z ), T ] <: [X :Eq(Z ), #T # ] as desired.
Every remaining rule is inapplicable because the environment in the conclusion must be empty.
Lemma F.30 (type world judgements do not contain free expression variables) If E #hm J is a derivable type world
judgement then fse E # fse J does not contain any free expression substitutable entity.
Proof. Given Lemma F.21 (things have to be ok), every free substitutable entity in J is free in a type, kind or signature
that is correct in E under hm . Thus, by Lemma E.21 (types do not contain free expression variables), no free substitutable
entity in J is an expression substitutable entity. Also, by Lemma E.6 (environments have to be ok), E #hm ok, so by
Lemma E.22 (environments do not contain free expression variables), E does not have any free substitutable entity.
Lemma F.31 (type preservation by module substitution in coloured judgements for type world judgements) Sup
pose E 0 , U :[X :K , T ], E #hm J is a derivable type world judgement and J is not of the form U :S # for any S # and Z is
fresh and # = {U .TYPE Z}. Then E 0 , Z :K , #E #hm #J .
Proof. By Lemma F.29 (type preservation by module substitution in coloured judgements), for Z and z fresh, we have
E 0 , Z :K , z :{X Z}T , E # #hm J # where E # = {U .TYPE Z , U .term z}E and J # = {U .TYPE Z , U .term z}J .
Given the syntax of environments and type world judgements, z may appear free in E # or J # only inside a hash. Given
Lemma E.5 (hashes have to be ok), any hash in E # or J # is ok, and by Lemma E.9 (free variables of a judgement come
from the environment), none of these hashes has a free occurence of z . Therefore z /
# fv E # and z /
# fv J # . Thus
we can write the judgement in question as E 0 , Z :K , z :{X Z}T , {U .TYPE Z}E #hm {U .TYPE Z}J . Given that
z /
# fv {U .TYPE Z}E # fv {U .TYPE Z}J , by Lemma F.15 (strengthening), we get E 0 , Z :K , {U .TYPE Z}E #hm
{U .TYPE Z}J .
Lemma F.32 (simplified module and type equality substitution for type world judgements) Suppose
U :[X :Eq(T ), T # ], E #hm J and # = U .TYPE, or X :Eq(T ), E #hm J and # = X , where both are type world
judgements and J is not of the form U # :S # . Then {# T}E #hm {# T}J .
Proof. We consider each case.
U :[X :Eq(T ), T # ], E #hm J : By Lemma F.31 (type preservation by module substitution in coloured judgements for type
world judgements), this case reduces to the other case.
X :Eq(T ), E #hm J by some proof #: By Lemma E.6 (environments have to be ok), X :Eq(T ), E #hm ok. By
Lemma E.7 (prefixes of ok environments are ok), X :Eq(T ) #hm ok. By (TK.var) and (Teq.Eq), nil #hm
T :Eq(T ). By Lemma E.19 (computing the pvu of a type world judgement) applied to #, we have hm 4
min (pvu X (#)). By Lemma F.14 (type preservation by substitution), {X#T}E #hm {X#T}J , as desired.
Lemma F.33 (type preservation by fully carried out module substitution)
If U :[X :Type, T 1 ], E # . J and J is not U :S for any S and nil # . [T 0 , v . ]:[X :Type, T 1 ]
then #E # . #J , where # = {U .TYPE#h, U .term#[v . ] {X#h}T1 h }, where h = hash(N , [T 0 , v . ]:[X :Type, T 1 ]), for
any N .
Proof. From nil # . [T 0 , v . ]:[X :Type, T 1 ], Lemma F.8 (components of modules are ok), there exists T 2 such that
X :Eq(T 0 ) # . T 2 == T 1 and X :Type # . T 1 :Type and nil # . T 0 :Type and nil # . v . :T 2 . Also, by (hmok.hash),
we get # h ok.
From nil # . v . :T 2 , by Lemma F.2 (colour stripping judgements), we get nil # h v . :T 2 . By Lemma E.6 (environments
have to be ok), X :Eq(T 0 ) # . ok, and note that any proof of this finishes with (envok.X) and therefore has an empty pvu
RR n 4851
52 Leifer, Peskine, Sewell, Wansbrough
for X . By Lemma F.2 (colour stripping judgements), we get X :Eq(T 0 ) # h ok, also by a proof with an empty pvu for X .
From nil # h v . :T 2 , by Lemma F.3 (weakening), we get X :Eq(T 0 ) # h v . :T 2 by a proof # such that pvu X (#) = ?.
From X :Eq(T 0 ) # . T 2 == T 1 , by Lemma F.2 (colour stripping judgements), we get X :Eq(T 0 ) # h T 2 == T 1 . By
Lemma E.19 (computing the pvu of a type world judgement), any proof # # of this judgement is such that pvu X (# # ) #
{h}. We can combine # and # # by (eT.eq) to get a proof # ## of X :Eq(T 0 ) # h v . :T 1 , such that h 4 min (pvu X (# ## )).
By (Teq.hash) and (TK.Eq), we have nil # h h:Eq(T 0 ). By Lemma F.14 (type preservation by substitution), we get
nil # h v . :{X #h}T 1 .
Now, by applying Lemma F.29 (type preservation by module substitution in coloured judgements) to
U :[X :Type, T 1 ], E # .
J and performing alphaconversion, we have X :Type, x :T 1 , #U E # . #U J , where #U =
{U .TYPE X , U .term x}.
From the latter judgement and nil # .
h:Type, apply Lemma F.14 (type preservation by substitution). We get
x :{X h}T 1 , {X h}#U E # . {X h}#U J .
Finally, we can apply Lemma F.23 (type preservation by guarded expression variable substitution) to the
latter judgement combined with nil # h v . :{X h}T 1 . We obtain {x [v . ] {X h}T1
h }{X h}#U E # .
{x [v . ] {X h}T1
h }{X h}#U J , i.e. #E # . #J , as desired.
G Type decomposition and type preservation for reduction
Lemma G.1 (shortening typing proof) If E #hm e:T then there exists T # such that E #hm e:T # by a subproof that
does not have (eT.eq) as the last rule used and E #hm T # == T .
Proof. Induct on the structure of the derivation # of E #hm e:T .
If the proof E #hm e:T does not have an instance of (eT.eq) as the last step, then we have the desired result, given
that E #hm T :Type by Lemma F.21 (things have to be ok), whereupon we can apply (Teq.refl).
Otherwise there is T # such that E #hm e:T is derived from E #hm e:T # and E #hm T # == T . By applying
induction to the (proper) subproof # # leading to E #hm e:T # , we get that there is T ## such that E #hm e:T ## by
a subproof of # # that does not have (eT.eq) as the last step used, and E #hm T ## == T # . By (Teq.tran), we have
E #hm T ## == T , which completes our proof obligation.
Lemma G.2 (reversing typing proof through a context) If nil # hm # CC hm #
hm .e:T # then there exists T such that nil #hm
e:T . If furthermore nil #hm e 1 :T then nil # hm # CC hm #
hm .e 1 :T # .
Proof. Induct on the structure of CC hm #
hm . By Lemma G.1 (shortening typing proof), there exists T 0 such that nil # hm #
T 0 == T # , and nil # hm # CC hm #
hm .e:T 0 by a proof # that does not end with (eT.eq).
Case CC hm #
hm = : Trivial.
Case CC hm #
hm = C hm #
hm 1
.CC hm 1
hm
: Then # ends with an application of (eT.tuple), (eT.proj), (eT.ap), (eT.mar), (eT.marred),
(eT.unmar), (eT.send) or (eT.col) (depending on C hm #
hm 1
). In any case, one premise is nil #hm 1
CC hm 1
hm .e:T 1 for
some T 1 . By induction we get nil #hm e:T for some T .
If furthermore nil #hm e 1 :T , then we have nil #hm 1 CC hm 1
hm .e 1 :T 1 by induction. Each of the (eT.*) rules
considered above is linear with respect to the expression metavariable instantiated by CC hm 1
hm .e, with exactly one
occurence above the line and one below. Instantiating this metavariable by CC hm 1
hm .e 1 yields another instance
of the rule. By replacing in # the derivation leading to nil #hm 1 CC hm 1
hm .e:T 1 by that leading to nil #hm 1
CC hm 1
hm .e 1 :T 1 , we get a derivation of nil # hm # CC hm #
hm .e 1 :T 0 . By (eT.eq), since nil # hm # T 0 == T # , we have
nil # hm # CC hm #
hm .e 1 :T # as desired.
Lemma G.3 (transitivity of kind equivalence) If E #hm K == K # and E #hm K # == K ## then E #hm K == K ## .
Proof. Both hypotheses have to be derived by the same rule.
Case (Keq.Type): Trivial.
Case (Keq.Eq): Trivial by (Teq.tran) and (Keq.Eq).
INRIA
Global abstractionsafe marshalling with hash types 53
Lemma G.4 (discreteness of subkinding below Type) If E #hm K <: Eq(T # ) then E #hm K == Eq(T # ) by a
subproof.
Proof. Induct on the derivation of E #hm K <: Eq(T # ). If the last rule in the proof is (Ksub.tran), then the result holds
by induction and Lemma G.3 (transitivity of kind equivalence). Otherwise the last rule is (Ksub.refl) and the premise is
the desired result.
Definition G.5 (bare bones environment) A bare bones environment is one that contains only bindings of the form
X :Type.
Definition G.6 (purely abstract environment) A purely abstract environment is one that contains only bindings of the
form U :[X :Type, T ] or X :Type.
Lemma G.7 (signature rewriting in a type world judgement) If E 0 , U :[X :K , T ], E 1 #hm J is a derivable type world
judgement and J is not of the form U :S # for any S # and E 0 #hm [X :K , T # ] ok then E 0 , U :[X :K , T # ], E 1 #hm J .
Proof. By (envok.U), E 0 , U # :[X :K , T # ] #hm ok where U # is fresh. By Lemma F.5 (combined weakening),
E 0 , U # :[X :K , T # ], U :[X :K , T ], E 1 #hm J . By Lemma F.31 (type preservation by module substitution in coloured
judgements for type world judgements), for Z fresh, we have E 0 , U # :[X :K , T # ], Z :K , {U .TYPE Z}E 1 #hm
{U .TYPE Z}J .
By (US.var) and (TK.mod), from E 0 , U # :[X :K , T # ] #hm ok, we get E 0 , U # :[X :K , T # ] #hm U # .TYPE:K . By
Lemma E.19 (computing the pvu of a type world judgement) and Lemma F.14 (type preservation by substitution), we
get E 0 , U # :[X :K , T # ], {Z U # .TYPE}{U .TYPE Z}E 1 #hm {Z U # .TYPE}{U .TYPE Z}J . Since Z is fresh, we
have E 0 , U # :[X :K , T # ], {U .TYPE U # .TYPE}E 1 #hm {U .TYPE U # .TYPE}J .
By Lemma F.30 (type world judgements do not contain free expression variables), U .term /
# fse E 1 # fse J .
Furthermore, J is not of the form U :S # for any S # , so U only appears in J as U .TYPE. Hence we have
E 0 , U # :[X :K , T # ], {U U # }E 1 #hm {U U # }J . By alphaconversion, we get E 0 , U :[X :K , T # ], E 1 #hm J as desired.
Lemma G.8 (type substitution in a purely abstract environment) If E 0 , E 1 #hm J is a derivable type world judgement
and J is not of the form U :S for any U , S and E 0 , E 2 #hm ok and E 1 and E 2 are purely abstract and E 1 and E 2 bind the
same variables in the same order then E 0 , E 2 #hm J .
Proof. Induct on the length of E 1 .
Case E 1 = nil: Trivial.
Case E 1 = X :Type, E #
1 and E 2 = X :Type, E #
2 : Trivial by induction (incorporating X :Type at the tail of E 0 ).
Case E 1 = U :[X :Type, T 1 ], E #
1 and E 2 = U :[X :Type, T 2 ], E #
2 : By Lemma E.6 (environments have to be ok) and
Lemma E.7 (prefixes of ok environments are ok) and reversing (envok.U), we get E 0 #hm [X :Type, T 2 ] ok. Then,
by Lemma G.7 (signature rewriting in a type world judgement), we have E 0 , U :[X :Type, T 2 ], E #
1 #hm J . By
induction (incorporating U :[X :Type, T 2 ] at the tail of E 0 ), we get E 0 , U :[X :Type, T 2 ], E #
2 #hm J as desired.
Lemma G.9 (equality kinding in an uncontributing environment) If E #hm T :Eq(T # ) and E is a bare bones envi
ronment then E #hm T == T # by a strictly smaller proof.
Note that if E was allowed to contain module bindings, we might not be able to obtain a strictly smaller proof. For
example, take T = T # = U .TYPE, with a proof whose last steps are (US.var), (US.self) and lastly (TK.mod). To prove
that E #hm U .TYPE == U .TYPE, we can't do any better than starting at E #hm ok and using (US.var), (TK.mod) and
(Teq.refl). This gives an equal size proof, not a strictly smaller proof.
Proof. Induct on the structure of the proof.
RR n 4851
54 Leifer, Peskine, Sewell, Wansbrough
Case (TK.sub): The premises are nil #hm T :K and nil #hm K <: Eq(T # ). By Lemma G.4 (discreteness of sub
kinding below Type), nil #hm K == Eq(T # ) by a subproof, whence by reversing (Keq.Eq) there exists T ## such
that K = Eq(T ## ) and nil #hm T ## == T # , the latter being derived by a proper subproof of the original proof.
By induction on nil #hm T :Eq(T ## ), we get nil #hm T == T ## by a smaller proof. By (Teq.tran), we get
nil #hm T == T # , by a proof that is at least one step smaller than the original proof.
Case (TK.Eq): Trivial.
Case (TK.var): Impossible since E only contains type variable bindings with the kind Type.
Case (TK.mod): Impossible by Lemma E.9 (free variables of a judgement come from the environment), since E contains
no module variable binding.
Lemma G.10 (equivalence of small types in an uncontributing environment) If E # h T 0 == T 1 and E is a bare
bones environment and h = hash(N , [T , v ]:S ) and T is not a subterm of T 0 or T is not a subterm of T 1 then T 0 = T 1 .
Proof. Induct on the derivation of E # h T 0 == T 1 .
Case (Teq.Eq): Then by Lemma G.9 (equality kinding in an uncontributing environment), E # h T 0 == T 1 by a strictly
smaller proof, so we get the desired result by induction.
Case (Teq.hash): We have h = T 0 and T = T 1 . T is a subterm of h , so T is a subterm of both T 0 and T 1 , which is
impossible.
Case (Teq.refl): Trivial.
Case (Teq.sym): Trivial by induction.
Case (Teq.tran): There exists T 2 such that the premises are E # h T 0 == T 2 and E # h T 2 == T 1 . Apply induction to
the premise containing T i , T i being the one of T 0 and T 1 that does not contain T : we get T 2 = T i . Then apply
induction to the other premise: we get T 1-i = T 2 , hence T 0 = T 1 as desired.
Case (Teq.cong.fun): Then there are T #
0 , T ##
0 , T #
1 and T ##
1 such that T i = T #
i #T ##
i for i = 0, 1. The premises are
E # h T #
0 == T #
1 and E # h T ##
0 == T ##
1 . Suppose that T is not a subterm of T i (i = 0 or i = 1). Then T is not a
subterm of T #
i nor of T ##
i , so by induction we get that T #
0 = T #
1 and T ##
0 = T ##
1 , hence T 0 = T 1 as desired.
Case (Teq.cong.tuple): Similar to the (Teq.cong.fun) case.
Lemma G.11 (type decomposition) Let E be a purely abstract environment.
1. If E #hm T 0 == TC (T 1 , ..., T j ) or E #hm TC (T 1 , ..., T j ) == T 0 then there exist T #
1 , ..., T #
j such that
E #hm T #
i == T i for 1 6 i 6 j and either T 0 = TC (T #
1 , ..., T #
j ) or there exist v and T ## and N such that
T 0 = hm = hash(N , [TC (T #
1 , ..., T #
j ), v ]:[X :Type, T ## ]).
2. If E #hm T 0 == h 1 or E #hm h 1 == T 0 then one of the following cases holds:
(a) There are T # and v and N such that hm = h 1 = hash(N , [T 0 , v ]:[X :Type, T # ]).
(b) There are T # and v and N such that T 0 = hm = hash(N , [h 1 , v ]:[X :Type, T # ]).
(c) T 0 = h 1 .
Proof. Let us first prove the case when E is a bare bones environment. We induct on the size of the derivation of the
hypothesis. We write the hypothesis as E #hm T 0 == T or E #hm T == T 0 .
Consider the last step of the proof of the hypothesis.
Case (Teq.Eq): By Lemma G.9 (equality kinding in an uncontributing environment), E #hm T 0 == T (or the converse)
by a strictly smaller proof, so we can apply induction.
INRIA
Global abstractionsafe marshalling with hash types 55
Case (Teq.hash): One of the following cases holds:
Case E #hm T 0 == TC (T 1 , ..., T j ) and T 0 = hm: We almost have the second alternative of the conclusion
of the lemma (with T #
i = T i ); all that remains to be proved is E #hm T i == T i . Write hm =
hash(N , [TC (T 1 , ..., T j ), v ]:S ).
The premise of (Teq.hash) is E #hm ok. By Lemma E.4 (colours have to be ok) and reversing (hmok.hash)
and Lemma F.8 (components of modules are ok), we get E # . TC (T 1 , ..., T j ):Type. By Lemma F.9 (types
are ok provided their hashes are) applied to TC (T 1 , ..., T j ) then to each T i , we get that E # . T i :Type,
whence E #hm T i == T i by Lemma F.2 (colour stripping judgements) and (Teq.refl). This completes the
proof of this subcase.
Case E #hm TC (T 1 , ..., T j ) == T 0 and TC (T 1 , ..., T j ) = hm: Contradictory.
Case E #hm T 0 == h 1 and T 0 = hm: Also hm = hash(N , [h 1 , v ]:S ) for some v and S and N . We have case
2b of the conclusion of the lemma.
Case E #hm h 1 == T 0 and h 1 = hm: Also hm = hash(N , [T 0 , v ]:S ) for some v and S and N . We have case
2a of the conclusion of the lemma.
Case (Teq.refl): Then T = T 0 . This completes the proof for statements 2 and 1 if j = 0. If j #= 0, take T #
i = T i .
By Lemma F.21 (things have to be ok), E #hm T 0 :Type, i.e. E #hm TC (T #
1 , ..., T #
j ):Type. By Lemma F.9
(types are ok provided their hashes are) applied to T 0 and then to each T #
i , we get E #hm T #
i :Type, whence
E #hm T #
i == T #
i by (Teq.refl).
Case (Teq.sym): Trivial by induction.
Case (Teq.tran): There exists T ## such that the premises are E #hm T 0 == T ## and E #hm T ## == T , or they are
E #hm T ## == T 0 and E #hm T == T ## . We call # # the subproof leading to the premise referring to T 0 .
We apply induction to the subproof leading to E #hm T ## == T or its converse. One of the following cases holds:
Case same constructor in 1: There exist T ##
1 , ..., T ##
j such that E #hm T ##
i == T i (or the converse) for 1 6 i 6 j
and T ## = TC (T ##
1 , ..., T ##
j ). Apply induction to # # . There exist T #
1 , ..., T #
j such that E #hm T ##
i == T #
i (or
the converse) for 1 6 i 6 j ; by (Teq.tran), we get E #hm T #
i == T i (or the converse) for 1 6 i 6 j ; and
one of the cases of the lemma holds.
Case use of hash in 1: There exist T #
1 , ..., T #
j , v , T ### and N such that E #hm T #
i == T i (or the converse) for
1 6 i 6 j and T ## = hm = hash(N , [TC (T #
1 , ..., T #
j ), v ]:[X :Type, T ### ]). We have E #hm T 0 == hm
(or the converse). By induction, one of the following cases holds:
Case hm = hash(N , [T 0 , v # ]:[X :Type, T #### ]): Then hash(N , [TC (T #
1 , ..., T #
j ), v ]:[X :Type, T ### ]) =
hm = hash(N , [T 0 , v # ]:[X :Type, T #### ]), therefore T 0 = TC (T #
1 , ..., T #
j ), and we have the desired
result.
Case T 0 = hm: Then we have the desired result.
Case use of hash (2a) in 2: Then hm = h 1 and they are implemented by T ## . Write hm = h 1 =
hash(N 1 , [T ## , v ]:[X :Type, T ### ]). One of the following cases holds, We do case analysis on the structure
of T ## .
Case T ## = h 2 for some h 2 : Apply induction to # # . One of the following cases holds:
Case hm = h 2 = hash(N 2 , [T 0 , v # ]:[X :Type, ]): Since hm = hash(N 1 , [T ## , v ]:[X :Type, T ### ]),
we have T 0 = T ## = h 2 which is impossible.
Case T 0 = hm = hash(N 2 , [h 2 , v # ]:[X :Type, ]): We have T 0 = h 1 , i.e. we have alternative 2c of the
conclusion of the lemma.
Case T 0 = h 2 : Then T ## = T 0 , and we have alternative 2a of the conclusion of the lemma.
Case T ## is of the form TC ## (T ##
1 , ..., T ## j ## ): Apply induction to # # (using part 1 of the lemma). There exist
T #
1 , ..., T # j ## such that E #hm T #
i == T ##
i for 1 6 i 6 j ## and one of the following cases holds:
Case T 0 = TC ## (T #
1 , ..., T # j ## ): For any i , T ##
i is a proper subterm of T ## which is a subterm of hm ,
therefore hm is not a subterm of T ##
i , hence by Lemma G.10 (equivalence of small types in an
uncontributing environment) T #
i = T ##
i . Thus T 0 = T ## , and we have the first alternative of the
conclusion of the lemma.
RR n 4851
56 Leifer, Peskine, Sewell, Wansbrough
Case use of hash: Then T 0 = hm = h 1 and we have the second alternative of the conclusion of the
lemma.
Case T ## = hm = hash(N , [h 1 , v ]:S ) (2b) in 2: Apply induction to # # . One of the following cases holds:
Case hm = hash(N , [T 0 , v # ]:S # ) (2a): We have T 0 = h 1 , i.e. alternative 2c of the conclusion of the lemma.
Case T 0 = hm = hash(N , [hm, v # ]:S # ) (2b): Impossible.
Case T 0 = hm (2c): Then T 0 = hm = hash(N , [h 1 , v ]:S ), i.e. we have alternative 2b of the lemma.
Case T ## = h 1 (2c) in 2: Apply induction to # # .
Case (Teq.cong.fun): We treat the case E #hm T 0 == T , the converse is similar. We must be in part 1 of the lemma,
with TC = 1 # 2 , and there exist T #
0 and T ##
0 such that the conclusion of the rule is E #hm T #
1 #T #
2 == T 1 #T 2
and the premises are E #hm T #
i == T i for i = 1, 2. This proves the first alternative of the conclusion of the
lemma.
Case (Teq.cong.tuple): Similar to the (Teq.cong.fun) case.
We now address the possibility of E containing module bindings. We give the proof for the case when E #hm T 0 ==
T ; a symmetric proof applies to the symmetric case. We induct on the number of module bindings in E . The base case
(no module binding) has already been proved. Consider now the case E = E 0 , U :[X :Type, T # ], E 1 where E 1 contains
only type variable bindings.
Let Z and z be fresh variables. By applying Lemma F.29 (type preservation by module substitution in coloured judge
ments), given that U is not free in E 1 , we get E 0 , Z :Type, z :{X Z}T # , E 1 #hm {U .TYPE Z , U .term z}T 0 ==
{U .TYPE Z , U .term z }T . By Lemma E.21 (types do not contain free expression variables), z /
# fv T 0 #fv T . Hence,
by Lemma F.15 (strengthening), E 0 , Z :Type, E 1 #hm {U .TYPE Z}T 0 == {U .TYPE Z}T . Apply induction to that
last judgement.
Case proving 1: We get T #
1 , ..., T #
j such that E 0 , Z :Type, E 1 #hm T #
i == {U .TYPE Z}T i for all i . By
Lemma E.6 (environments have to be ok) and Lemma E.7 (prefixes of ok environments are ok), we have
E 0 , U :[X :Type, T # ] #hm ok. By Lemma F.5 (combined weakening), given that U /
# fv E 0 # fv E 1 by
Lemma E.8 (ok environments have no repetition in the domain), we have E 0 , U :[X :Type, T # ], Z :Type, E 1 #hm
T #
i == T i . Let # be a proof of this last judgement. By Lemma E.19 (computing the pvu of a type world
judgement), we have hm 4 min pvu # (#) . Since E 0 , U :[X :Type, T # ] #hm ok, by (TK.mod), we have
E 0 , U :[X :Type, T # ] #hm U .TYPE:Type. Then by Lemma F.14 (type preservation by substitution), we have
E #hm {Z#U .TYPE}T #
i == T i (note that {Z#U .TYPE}{U .TYPE#Z}T i = T i since Z /
# fv T i ).
Furthermore, by the same induction, we get one of the following properties: {Z#U .TYPE}T 0 = TC (T #
1 , ..., T #
j )
or {Z#U .TYPE}T 0 = hm = hash(N , [TC (T #
1 , ..., T #
j ), v ]:[X :Type, T ## ]). Since Z was chosen fresh,
{U .TYPE#Z} is injective. Therefore we have T 0 = TC ({Z#U .TYPE}T #
1 , ..., {Z#U .TYPE}T #
j ) or T 0 =
hm = hash(N , [TC (T #
1 , ..., T #
j ), v ]:[X :Type, T ## ]) (using Lemma E.4 (colours have to be ok) and Lemma E.9
(free variables of a judgement come from the environment)).
Case proving 2: Here T = h 1 . One of the following properties holds:
hm = {U .TYPE#Z}h 1 = hash(N , [{U .TYPE#Z}T 0 , v ]:[X :Type, T # ])
or {U .TYPE#Z}T 0 = hm = hash(N , [{U .TYPE#Z}h 1 , v ]:[X :Type, T # ])
or {U .TYPE#Z}T 0 = {U .TYPE#Z}h 1 .
In any case, given Lemma E.5 (hashes have to be ok) and Lemma E.9 (free variables of a judgement come from
the environment), fv h 1 = ? and fv T 0 = ? (since fv {U .TYPE#Z}T 0 = ?). So in the properties above,
{U .TYPE#Z} is the identity, and we have the desired disjunction.
Lemma G.12 (decomposition of type equivalence) If nil #hm TC (T 1 , ..., T j ) == TC (T 1 , ..., T #
j ) then nil #hm
T i == T #
i for 1 6 i 6 j .
Proof. Trivial consequence of part 1 of Lemma G.11 (type decomposition).
Lemma G.13 (structural dependence of values on their types) Suppose nil #hm v hm :T 0 and nil #hm T 0 ==
TC (T 1 , ..., T j ). Consider the possible forms of TC .
INRIA
Global abstractionsafe marshalling with hash types 57
1. If TC = 1 # 2 , i.e. we have nil #hm T 0 == T 1 #T 2 , then there exists e and T #
1 such that v hm = #x :T #
1 .e and
nil #hm T #
1 == T 1 .
2. If TC = 1 # ... # j , i.e. we have nil #hm T 0 == T 1 # ... # T j then there exists v hm
1 , ..., v hm
j such that
v hm = (v hm
1 , ..., v hm
j ).
3. If TC = (), i.e. we have nil #hm T 0 == UNIT then v hm = ().
4. If TC = STRING, i.e. we have nil #hm T 0 == STRING then there exist v . and T such that nil # . T :Type and
nil # . v . :T and v hm = marshalled (v . :T ).
Proof. Induct on the size of the derivation of nil #hm v hm :T 0 .
Consider the last step of the derivation of nil #hm v hm :T 0 . The rules not mentionned here cannot have been used
because v hm is a value.
Case (eT.eq): There is T #
0 such that nil #hm T #
0 == T 0 , and nil #hm v hm :T #
0 by a smaller proof compared with
nil #hm v hm :T 0 . Using (Teq.tran), we get nil #hm T #
0 == TC (T 1 , ..., T j ). By induction we get the desired
result.
Case (eT.fun): There exist e, T #
1 and T #
2 such that v hm = #x :T #
1 .e and T 0 = T #
1 #T #
2 . By Lemma G.11 (type decom
position), we are proving case 1, and we have nil #hm T 1 == T #
1 .
Case (eT.unit): Then v hm = () and T 0 = UNIT. By Lemma G.11 (type decomposition), we are proving case 3.
Case (eT.tuple): There exist T #
1 , ..., T #
j , v hm
1 , ..., v hm
j such that v hm = (v hm
1 , ..., v hm
j ) and T 0 = T #
1 # ... # T #
2 . By
Lemma G.11 (type decomposition), we are proving case 2.
Case (eT.marred): There exist v . and T such that v hm = (marshalled v . :T ) and T 0 = STRING. By Lemma G.11
(type decomposition), we are proving case 4. One premise of (eT.marred) is nil # .
v . :T . By Lemma F.21 (things
have to be ok), we have nil # .
T :Type.
Case (eT.col): Given that v hm is a value that is a bracket expression, T 0 can be but a hash h 0 . By Lemma G.11 (type
decomposition), this can only happen if there are T #
1 , ..., T #
j and v hm such that hm = h and T 0 = h , with h =
hash(N , [TC (T #
1 , ..., T #
j ), v hm ]:[X :Type, X ]). However T 0 = hm is impossible as per the definition of values.
Lemma G.14 (triviality of type equivalence in a trivial environment) If nil # . T == T # then T = T # .
Proof. Induct on the structure of T .
Case T is of the form TC (T 1 , ..., T j ): By Lemma G.11 (type decomposition) and the trivial colour of the hypothesis,
there exist T #
1 , ..., T #
j such that nil # .
T i == T #
i for 1 6 i 6 j and T # = TC (T #
1 , ..., T #
j ). (We're possibly making
use of (Teq.sym) here.) By induction on nil # . T i == T #
i for 1 6 i 6 j we have T i = T #
i hence T = T # as
desired.
Case T is of the form h: By Lemma G.11 (type decomposition) and the trivial colour of the hypothesis, T = T # .
Case T is of the form U .TYPE or X : Impossible by Lemma E.9 (free variables of a judgement come from the environ
ment)
Theorem G.15 (type preservation for expression reduction) If nil #hm e:T and e -#hm e # then nil #hm e # :T .
Proof. Note that by Lemma G.1 (shortening typing proof), there exists T # such that nil #hm T # == T and nil #hm
e:T # by a proof that does not end in (eT.eq). In the discussion below, we will often make use of the fact that apart
from (eT.eq), typing of expressions is syntaxdirected. Also, note that by Lemma F.21 (things have to be ok), we have
nil #hm T # :Type, and by Lemma E.6 (environments have to be ok), we have nil #hm ok.
We induct on the derivation of the reduction.
RR n 4851
58 Leifer, Peskine, Sewell, Wansbrough
Case (ered.proj): There exist v hm
1 , ..., v hm
j and i such that e = proj i (v hm
1 , ..., v hm
j ). Then nil #hm e:T # must have
been derived by (eT.proj), and the i th premise is nil #hm v hm
i :T # , i.e. nil #hm e # :T # .
Case (ered.ap): There exist e 1 , v hm
2 and T 2 such that e = (#x :T 2 .e 1 ) v hm
2 and e # = {x [v hm
2 ] T2
hm }e 1 . nil #hm e:T #
must have been derived by (eT.ap), with the premises nil #hm v hm
2 :T 2 and nil #hm (#x :T 2 .e 1 ):T 2 #T # .
By Lemma G.1 (shortening typing proof), there exists T ## such that nil #hm (#x :T 2 .e 1 ):T ## by a proof that does
not end in (eT.eq), and nil #hm T ## == T 2 #T # . By reversing (eT.fun), there exists T 1 such that T ## = T 2 #T 1
and x :T 2 #hm e 1 :T 1 . By Lemma G.12 (decomposition of type equivalence), we have nil #hm T 1 == T # .
By Lemma F.23 (type preservation by guarded expression variable substitution), we have nil #hm
{x [v hm
2 ] T2
hm }e 1 :T 1 . By (eT.eq), we get nil #hm e # :T # .
Case (ered.mar): There exist v hm
1 and T 1 such that e = mar (v hm
1 :T 1 ), and e # = marshalled ([v hm
1 ] T1
hm :T 1 ). nil #hm
e:T # must have been derived by (eT.mar), with the premise nil #hm v hm
1 :T 1 ; also T # = STRING.
By Lemma F.21 (things have to be ok) and Lemma F.10 (colour change preserves type okedness), nil # . T 1 :Type.
By (eT.col), we get nil # . [v hm
1 ] T1
hm :T 1 . By Lemma E.6 (environments have to be ok), we have nil #hm ok. By
(eT.marred), we get nil #hm e # :STRING.
Case (ered.unmar): There exist v hm
1 , T 1 and T 2 such that e = unmar (marshalled (v hm
1 :T 1 )):T 2 . By reversing
(eT.unmar), we get nil #hm T 2 :Type and nil #hm marshalled (v hm
1 :T 1 ):STRING; also T # = T 2 . There are
two possible outcomes.
Case e # is UnmarFailure T # : By Lemma F.21 (things have to be ok), nil #hm T # :Type, hence nil #hm
UnmarFailure T # :T # by (eT.Undynfailure).
Case e # is the value v hm
1 and T 1 = T # : By Lemma G.1 (shortening typing proof) and reversing (eT.marred), we
get nil # . v hm
1 :T 1 . By Lemma F.2 (colour stripping judgements), this implies that nil #hm v hm
1 :T 1 , i.e.
nil #hm v hm
1 :T # .
Cases (ered.col.*): There exist hm # and e 0 such that e = [e 0 ] T #
hm # . By reversing (eT.col), we get nil # hm # e 0 :T # . Note
than # hm ok and # hm # ok by Lemma E.4 (colours have to be ok).
Case (ered.col.unit): Then T # = UNIT and e 0 = () and e # = (). By (eT.unit), nil #hm e # :UNIT.
Case (ered.col.tuple): Then there exist T 1 , ..., T j , e 1 , ..., e j such that T # = T 1 # ... # T j and e 0 = (e 1 , ..., e j )
and e # = ([e 1 ] T1
hm # , ..., [e j ] T j
hm # ). Hence T # = T . By Lemma G.1 (shortening typing proof) and reversing
(eT.tuple), there exist T #
1 , ..., T #
j such that nil # hm # T #
1 # ... # T #
j == T # and nil # hm # e i :T #
i for 1 6 i 6 j .
By Lemma G.12 (decomposition of type equivalence), we have nil # hm # T #
i == T i for every i . Hence,
by applying (eT.eq) j times, we get nil # hm # e i :T i for every i . By Lemma F.9 (types are ok provided their
hashes are) applied to T # then to each T i , we get nil #hm T i :Type for every i , whence by (eT.col) and
(eT.tuple): nil #hm e # :T # .
Case (ered.col.fun): Then there exist T 0 , T 1 , T 2 and e 1 such that T # = T 2 #T 1 and e 0 = #x :T 0 .e 1 and e # =
#x :T 2 .[{x #[x ] T2
hm }e 1 ] T1
hm # . By Lemma G.1 (shortening typing proof) and reversing (eT.fun), there exists
T 3 such that x :T 0 # hm # e 1 :T 3 and nil # hm # T 0 #T 3 == T # . By Lemma G.12 (decomposition of type
equivalence), we have nil # hm # T 0 == T 2 (possibly using (Teq.sym)) and nil # hm # T 3 == T 1 .
By Lemma F.21 (things have to be ok), nil # hm # T 2 :Type. By Lemma F.10 (colour change preserves type
okedness), we also have nil # . T 2 :Type and nil #hm T 2 :Type. By (envok.x), we get y :T 2 #hm ok and
y :T 2 # . ok and y :T 2 #hm ok. By (eT.var), we get y :T 2 #hm y :T 2 .
By Lemma F.21 (things have to be ok), we get nil # hm # T 1 :Type. By Lemma F.10 (colour change preserves
type okedness), we have nil #hm T 1 :Type. By Lemma F.3 (weakening), we get y :T 2 #hm T 1 :Type.
We have y :T 2 # .
ok and y :T 2 #hm y :T 2 and y :T 2 , x :T 0 # hm # e 1 :T 3 . By Lemma F.23 (type preservation
by guarded expression variable substitution), we get y :T 2 # hm # {x#[y ] T2
hm }e 1 :T 3 .
y :T 2 #hm T 1 :Type y :T 2 # hm # T 3 == T 1 y :T 2 # hm # {x#[y ] T2
hm }e 1 :T 3
y :T 2 # hm # {x#[y ] T2
hm }e 1 :T 1
(eT.eq)
y :T 2 #hm [{x#[y ] T2
hm }e 1 ] T1
hm # :T 1
(eT.col)
nil #hm #y :T 2 .[{x #[y ] T2
hm }e 1 ] T1
hm # :T 2 #T 1
(eT.fun)
INRIA
Global abstractionsafe marshalling with hash types 59
By alphaconversion, we get nil #hm e # :T 2 #T 1 .
Case (ered.col.marred): Then there exist v .
1 and T 1 such that T # = STRING and e 0 = marshalled (v .
1 :T 1 ) = e # .
Since nil # hm # e 0 :T # , by Lemma G.1 (shortening typing proof) and reversing (eT.marred), we have nil # .
v .
1 :T 1 . Since nil #hm ok, by (eT.marred), we have nil #hm e # :STRING.
Case (ered.col.col): Then there exist h 0 , h 1 and e 1 such that T # = h 0 and hm # = h 1 and e 0 = [e 1 ] h0
h0 . By Lemma
G.1 (shortening typing proof) and reversing (eT.col), we get nil # h0 e 1 :h 0 . By Lemma E.5 (hashes have to be
ok), we have # h 0 ok, whence nil #hm h 0 :Type by (TK.hash). Then, by (eT.col), we get nil #hm [e 1 ] h0
h0 :T # .
Case (ered.col.le): Then hm # 4 hm and e # = e 0 . Since nil # hm # e 0 :T # , i.e. nil # hm # e # :T # , by Lemma F.2
(colour stripping judgements), we have nil # hm # e # :T .
Case (ered.cong): There exist hm 0 , C hm
hm 0
, e 0 and e #
0 such that e = C hm
hm 0 .e 0 and e # = C hm
hm 0 .e #
0 and e 0 -#hm 0
e #
0 by a
proper subproof. Recall that we have nil #hm e:T # . By the first part of Lemma G.2 (reversing typing proof through
a context), there exists T 0 such that nil #hm 0
e 0 :T 0 . By induction, we get nil #hm 0
e # 0 :T 0 . By the second part of
Lemma G.2 (reversing typing proof through a context), we get nil #hm e # :T # .
In any case, we have nil #hm e # :T # , whence by (eT.eq), nil #hm e # :T .
Lemma G.16 (type preservation for network structural congruence) If # n ok and n # n # then # n # ok.
Proof. Induct on the derivation of n # n # .
Case (nsc.id): We have n = 0 | n # . By reversing (nok.par), we get # n # ok.
Case (nsc.commut): There exist n 1 and n 2 such that n = n 1 | n 2 and n # = n 2 | n 1 . By reversing (nok.par) and applying
it with the premises swapped, from # n ok, we get # n # ok.
Case (nsc.assoc): There exist n 1 , n 2 , n 3 such that n = n 1 | (n 2 | n 3 ) and n # = (n 1 | n 2 ) | n 3 . By reversing (nok.par) twice,
from # n ok, we get # n i ok for 1 6 i 6 3, whence by (nok.par) twice # n # ok.
Reflexivity, symmetry, transitivity: Trivial (the latter two, by induction).
Corollary G.17 (type preservation for network reduction) If # n ok and n -# n # then # n # ok.
Proof. Induct on the derivation of the reduction n -# n # .
Case (nred.expr): Trivial by Theorem G.15 (type preservation for expression reduction).
Case (nred.par): There exist n 0 , n 1 , n 2 such that n = n 0 | n 2 and n # = n 1 | n 2 . The premise is n 0 -# n 1 . By reversing
(nok.par), we have # n 0 ok and # n 2 ok. By induction we have # n 1 ok. By (nok.par), we have # n # ok.
Case (nred.strcong): There exist n 0 and n 1 such that n # n 0 -# n 1 # n # . By Lemma G.16 (type preservation for
network structural congruence), we get # n 0 ok. By induction we get # n 1 ok. By Lemma G.16 (type preservation
for network structural congruence), we get # n # ok.
Case (nred.comm): There exist CC . hm , v hm , CC . hm # such that n = CC . hm .! v hm
| CC . hm # .? and n # = CC . hm .() |
CC . hm # .v hm . By reversing (nok.par), then (nok.expr) twice, we get nil # . CC . hm .! v hm :UNIT and nil # .
CC . hm # .?:UNIT.
From nil # .
CC . hm .! v hm , by Lemma G.2 (reversing typing proof through a context), we get nil #hm ! v hm :T # for
some T # . By Lemma G.1 (shortening typing proof) and reversing (eT.send), we get nil #hm v hm :mar , and we
see that nil #hm ! v hm :UNIT and nil #hm UNIT == T # . By Lemma E.6 (environments have to be ok), (eT.unit)
and (eT.eq), we get nil #hm ():T # , so by the second part of Lemma G.2 (reversing typing proof through a context),
we get nil # . CC . hm .():UNIT.
By Lemma G.13 (structural dependence of values on their types), there exists v . and T 0 such that v hm =
marshalled (v . :T 0 ) and nil # . T 0 :Type and nil # . v . :T 0 .
From nil # . CC . hm # .?:UNIT, by Lemma G.2 (reversing typing proof through a context), we get nil # hm # ?:T ## for
some T ## . By Lemma G.1 (shortening typing proof) and reversing (eT.recv), we get nil # hm # ok and nil # hm #
RR n 4851
60 Leifer, Peskine, Sewell, Wansbrough
STRING == T ## . By (eT.marred), we get nil # hm # marshalled (v . :T 0 ):STRING, so by the second part of Lemma
G.2 (reversing typing proof through a context), we get nil # . CC . hm # .v hm :UNIT.
By (mT.expr) twice, then (nok.par), we get # CC . hm .() | CC . hm # .v hm ok as desired.
Theorem G.18 (type preservation for machine reduction) If nil # . m:T and m -# c m # then nil # . m # :T .
Proof. Consider each rule.
Case (mred.Type): We have that m is of the form moduleNU = [T 0 , v . ]:[X :Type, T 1 ] in m 0 and m # is of the
form #m 0 where # = {U .TYPE h, U .term [v . ] {X h}T1
h } and h = hash(N , [T 0 , v . ]:[X :Type, T 1 ]). The
judgement nil # . m:T can only be derived by (mT.let) with the following premises: nil # . T :Type and nil # .
[T 0 , v . ]:[X :Type, T 1 ] and U :[X :Type, T 1 ] # . m 0 :T .
By Lemma F.33 (type preservation by fully carried out module substitution), we have nil # . #(m 0 :T ), as desired.
Case (mred.Eq): We have that m is of the form Let U = [T 0 , v . ]:[X :Eq(T 3 ), T 1 ] in m 0 and m # is of the form #m 0
where # = {U .TYPE T 3 , U .term v . }. The judgement nil # .
m:T can only be derived by (mT.let) with the
following premises: nil # .
T :Type and nil # .
[T 0 , v . ]:[X :Eq(T 3 ), T 1 ] and U :[X :Eq(T 3 ), T 1 ] # .
m 0 :T .
From nil # .
[T 0 , v . ]:[X :Eq(T 3 ), T 1 ], by Lemma F.8 (components of modules are ok), there exists T 2 such that
X :Eq(T 0 ) # .
T 2 == T 1 and X :Eq(T 3 ) # .
T 1 :Type and nil # .
T 0 :Eq(T 3 ) and nil # .
v . :T 2 .
By Lemma F.29 (type preservation by module substitution in coloured judgements) and alphaconversion we have
X :Eq(T 3 ), x :T 1 # . #U (m 0 :T ), where #U = {U .TYPE#X , U .term#x}.
By Lemma E.6 (environments have to be ok), X :Eq(T 3 ) # . ok, whence by reversing (envok.X) nil # . T 3 :Type,
so nil # . T 3 :Eq(T 3 ) by (Teq.refl) and (TK.Eq). Therefore, by Lemma F.14 (type preservation by substitution), we
have x :{X #T 3 }T 1 # . {U .TYPE#T 3 , U .term#x}(m 0 :T ).
From nil # . v . :T 2 (given that X :Eq(T 0 ) # . ok by Lemma E.6 (environments have to be ok)) by Lemma F.3
(weakening), we get X :Eq(T 0 ) # . v . :T 2 . By (eT.eq), we get X :Eq(T 0 ) # . v . :T 1 .
From nil # . T 0 :Eq(T 3 ), by (Teq.Eq), (Teq.sym) and (TK.Eq), we get nil # . T 3 :Eq(T 0 ). By Lemma F.14 (type
preservation by substitution), we get nil # . v . :{X #T 3 }T 1 . By Lemma F.14 (type preservation by substitution),
we get nil # . {U .TYPE#T 3 , U .term#v . }(m 0 :T ) as desired.
H Progress
H.1 Classical progress theorems
Definition H.1 (waiting for communication) An expression e is waiting for communication iff one of the following
cases holds:
. e is ready to output, i.e. there exists CC hm #
hm and v hm such that e = CC hm #
hm .! v hm
. e is ready to input, i.e. there exists CC hm #
hm such that e = CC hm #
hm .?
Definition H.2 (dormant) An expression e is dormant iff one of the following cases holds:
. e is waiting for communication
. e is dead, i.e. there exists CC hm #
hm and T such that e = CC hm #
hm .UnmarFailure T .
Lemma H.3 (dormancy in context) If e is dormant and CC hm #
hm is a coloured evaluation context then CC hm #
hm .e is
dormant.
Proof. Composing coloured evaluation contexts yields a coloured evaluation context.
INRIA
Global abstractionsafe marshalling with hash types 61
Lemma H.4 (reduction in context) If e -#hm and CC hm #
hm is an evaluation context then CC hm #
hm .e -# hm # .
Proof. Apply (ered.cong) as many times as the size of CC hm #
hm requires.
Definition H.5 (legitimately stuck expressions) An expression e is legitimately stuck in hm iff one of the following
cases holds:
. e is a hmvalue
. e is dormant.
Theorem H.6 (progress of expressions) If nil #hm e:T then one of the following cases holds:
. e is legitimately stuck in hm .
. e can reduce, i.e. there exists e # such that e -#hm e # .
Proof. Induct on the type derivation. Consider the rule used in the last step of the proof.
Cases (eT.var) and (eT.mod): Impossible by Lemma E.9 (free variables of a judgement come from the environment)
since the environment is empty.
Case (eT.eq): The inductive hypothesis is the desired result.
Case (eT.ap): There exists e 0 , e 1 , T 1 such that e = e 0 e 1 and nil #hm e 0 :T 1 #T and nil #hm e 1 :T 1 . Apply the
inductive hypothesis to e 0 .
Case e 0 can reduce: there exists e #
0 such that e 0 -#hm e #
0 . By (ered.cong), e -#hm e #
0 e 1 .
Case e 0 is ready to output: there exist CC hm
hm # and v hm # such that e 0 = CC hm
hm # .! v hm # , thus e =
( e 1 ).CC hm
hm # .! v hm # is ready to output.
Case e 0 is ready to input: similar to the output case.
Case e 0 is dead: then e is dead.
Case e 0 is a hmvalue: Apply the inductive hypothesis to e 1 . Note that e 0 is an evaluation context.
Case e 1 can reduce: there exists e #
1 such that e 1 -#hm e #
1 . By (ered.cong), e -#hm e 0 e #
1 .
Case e 1 is ready to output: there exist CC hm
hm # and v hm # such that e 1 = CC hm
hm # .! v hm # , thus e =
(e 0 ).CC hm
hm # .! v hm # is ready to output.
Case e 1 is ready to input: similar to the output case.
Case e 1 is dead: then e is dead.
Case e 1 is a hmvalue: By Lemma G.13 (structural dependence of values on their types), there exists e 2 such
that e 0 = #x :T 1 .e 2 . Then e = (#x :T 1 .e 2 ) e 1 . By (ered.ap), e -#hm {x [e 1 ] T1
hm }e 2 .
Case (eT.fun): e is a value.
Case (eT.send): e is ready to output.
Case (eT.recv): e is ready ot input.
Case (eT.mar): There exist an e 0 and a T 0 such that e = mar (e 0 :T 0 ), and T = STRING. If e 0 is dormant or reduces
then the same holds for e by Lemma H.4 (reduction in context) and Lemma H.3 (dormancy in context). Otherwise,
by the inductive hypothesis on e 0 , e 0 is a hmvalue, so by (ered.mar), e -#hm marshalled ([e 0 ] T
hm
:T ).
Case (eT.marred): There exist an e 0 and a T 0 such that e = marshalled (e 0 :T 0 ), and T = STRING. If e 0 is dormant
or reduces then the same holds for e by Lemma H.4 (reduction in context) and Lemma H.3 (dormancy in context),
since marshalled ( :T 0 ) is an evaluation context. Otherwise, by the inductive hypothesis on e 0 , e 0 is a hmvalue,
so e is an hmvalue.
Case (eT.unmar): There is an e 0 such that e = (unmar e 0 :T ). If e 0 is dormant or reduces then the same holds for e by
Lemma H.4 (reduction in context) and Lemma H.3 (dormancy in context). Otherwise, by the inductive hypothesis
on e 0 , e 0 is a value. Its type is STRING, so by Lemma G.13 (structural dependence of values on their types), there
is a v . and a T 0 such that e 0 = marshalled (v . :T 0 ). Then e reduces by (ered.unmar).
RR n 4851
62 Leifer, Peskine, Sewell, Wansbrough
Case (eT.Undynfailure): e is dormant.
Case (eT.unit): e is a value.
Case (eT.tuple): There are e 1 , ..., e j such that e = (e 1 , ..., e j ). Let i be the smallest index k such that e 1 through e k-1
are values. If i = j + 1 then e is a value. Otherwise, apply the inductive hypothesis to e i . Since e i is not a value,
it is dormant or reduces, and in either case, the same holds for e by Lemma H.3 (dormancy in context) and Lemma
H.4 (reduction in context), as (e 1 , ..., e i-1 , , e i+1 , ..., e j ) is an evaluation context.
Case (eT.proj): There is an e # such that e = proj i e # , and there are T 1 , ..., T j such that nil #hm e # :T 1 # ... # T j . If
e # is dormant or reduces, then the same holds for e since proj i is an evaluation context. Otherwise, apply the
inductive hypothesis to e # : it is a value. By Lemma G.13 (structural dependence of values on their types), there are
v hm
1 , ..., v hm
j such that e # = (v hm
1 , ..., v hm
j ). Then e -#hm v hm
i by (ered.proj).
Case (eT.col): There is an e 0 and an hm 0 such that e = [e 0 ] T
hm 0
. Apply the inductive hypothesis to e 0 ; if e 0 is a value,
the discussion depends on its form and that of hm 0 .
By Lemma G.1 (shortening typing proof), there is a type T # such that nil #hm 0 e 0 :T # by a smaller proof that does
not use (eT.eq) as its last step and nil #hm 0 T # == T .
Case e 0 is dormant: e is dormant.
Case e 0 reduces: There is an e # 0 such that e 0 -#hm 0 e #
0 . By (ered.cong), e -#hm [e #
0 ] T
hm 0
.
Case e 0 is an hm 0 value that is not a bracket expression: Then, by reversing the appropriate rule amongst
(eT.unit), (eT.tuple), (eT.fun) or (eT.marred), we have that T # is some constructed type TC (T #
1 , ..., T #
j
).
Since nil #hm 0
T # == T , by Lemma G.11 (type decomposition), one of the following cases holds:
Case T is a constructed type: There exist T 1 , ..., T j such that nil #hm T #
i == T i for all i and
T = TC (T 1 , ..., T j ). Then e reduces by the appropriate rule amongst (ered.col.unit), (ered.col.tuple),
(ered.col.fun) or (ered.col.marred).
Case T = hm 0 : If hm 0 4 hm then e = [e 0 ] hm 0
hm 0
reduces by (ered.col.le). Otherwise e is a value.
Case e 0 = [v h1 ] h1
h1
for some h 1 and hm 0 = .: We have e = [[v h1 ] h1
h1
] T
. . By Lemma G.1 (shortening typing proof)
and reversing (eT.col), we have nil # . h 1 == T # . By (Teq.tran), we have nil # . h 1 == T . By Lemma G.14
(triviality of type equivalence in a trivial environment), h 1 = T . Then e -#hm e 0 by (ered.col.le).
Case e 0 = [v h1 ] h1
h1 for some h 1 and hm 0 #= .: We have nil #hm 0 [v h1 ] h1
h1 :T . Then nil #hm 0 [v h1 ] h1
h1 :T # must
have been obtained by an application of (eT.col), so T # = h 1 . Since nil #hm 0 h 1 == T , by Lemma G.11
(type decomposition) and some more pattern matching, one of the following cases holds:
Case T = h 1 #= hm 0 and hm 0 #= hm: Then e = [[v h1 ] h1
h1 ] h1
hm 0
. By (ered.col.col), e -#hm [v h1 ] h1
h1 (recall
that hm 0 #= .).
Case T = h 1 #= hm 0 and hm 0 = hm: Then e = [[v h1 ] h1
h1 ] h1
hm . By (ered.col.le), e -#hm e 0 .
Case hm 0 = h 1 : Then e = [[v h1 ] h1
h1 ] T
h1 . By (ered.col.le), [v h1 ] h1
h1 -# h1 v h1 . Hence, by (ered.cong), e -#hm
[v h1 ] T
h1 .
Corollary H.7 (progress of networks) If # n ok then one of the following cases holds:
. n is stopped, i.e. there exists n () and n fail such that n # n () | n fail .
. n is waiting to input, i.e. there exists n () and n fail and n ? such that n # n () | n fail | n ?
. n is waiting to output, i.e. there exists n () and n fail and n ! such that n # n () | n fail | n !
. n can reduce, i.e. there exists n # such that n -# n #
INRIA
Global abstractionsafe marshalling with hash types 63
where
n () ::=0 null
n () | n () parallel composition
() unit
n fail ::=0 null
n fail | n fail parallel composition
CC . hm .UnmarFailure T dead
n ? ::=n ? | n ? parallel composition
CC . hm .? waiting to input
n ! ::=n ! | n ! parallel composition
CC . hm .! v waiting to output
Proof. Induct on the derivation of # n ok.
Case (nok.zero): Trivial.
Case (nok.par): There exist n 0 and n 1 such that n = n 0 | n 1 . If either n 0 or n 1 reduces then n reduces. If n 0 is stopped
then n has the same form as n 1 , and vice versa. If n 0 and n 1 are both waiting to input (or both to output) then so is
n . Otherwise n 0 # n () | n fail | n ? and n 1 # n () | n fail | n ! (or the converse): then n reduces by (nred.comm).
Case (nok.expr): By Theorem H.6 (progress of expressions), one of the following cases holds:
Case n is a .value: By (nok.expr), the value n has type UNIT. By Lemma G.13 (structural dependence of values
on their types), n is an n () .
Case n is dead: n is an n fail .
Case n is waiting for input: n is an n ? .
Case n is waiting for output: n is an n ! .
Case n reduces: n reduces.
Theorem H.8 (progress of machines) If nil # . m:T then either m is an expression or it reduces under -# c .
Proof. Induct on the type derivation.
Case (mT.expr): Trivial.
Case (mT.let): It is obvious that m reduces, by either (mred.Type) or (mred.Eq).
H.2 Determinism of reduction
Theorem H.9 (determinism of machine reduction) Reduction of machines is deterministic, i.e. if m -# c m 1 and
m -# c m 2 then m 1 = m 2 and both reductions use the same rule on the same redex.
Proof. Induct on the structure of m .
Case m is an expression: Impossible (m does not reduce).
Case m = moduleNU = M :[X :Type, T ] in m # : The only applicable rule is (mred.Type).
RR n 4851
64 Leifer, Peskine, Sewell, Wansbrough
Case m = moduleNU = M :[X :Eq(T # ), T ] in m # : The only applicable rule is (mred.Eq).
Lemma H.10 (values do not reduce) If e -#hm e # then e is not an hmvalue.
Proof. We prove that if e is an hmvalue then e does not reduce in hm . We induct on the structure of values.
Case v hm = (): No reduction rule applies.
Case v hm = (v hm
1 , ..., v hm
j ): The only reduction rule that is not obviously inapplicable is (ered.cong). If that rule applies,
then it is with a context of the form (v hm
1 , ..., v hm
i-1 , , v hm
i+1 , ..., v hm
j ). But then v hm
i -#hm , which is impossible by
induction.
Case v hm = (#x :T .e): No reduction rule applies.
Case v hm = marshalled (v . :T ): The only reduction rule that is not obviously inapplicable is (ered.cong). If that rule
applies, then it is with a context of the form marshalled ( :T ). But then v . -# . , which is impossible by
induction.
Case v hm = [v h1 ] h1
h1
where h 1 #= hm: The rule (ered.col.le) requires h 1 4 hm , which given the definition of 4 implies
that h 1 = hm , a contradiction. The rule (ered.col.col) does not apply as it requires the type and colour annotation
on the bracket to be different. The other (ered.col.*) rules do not apply as they require the type annotation on the
bracket not to be a hash. If (ered.cong) applies, then it is with a context of the form [ ] h1
h1 . But then v h1
-# h1 , which
is impossible by induction.
Theorem H.11 (determinism of expression reduction) Reduction of expressions and machines is deterministic, i.e. if
e -#hm e # and e -#hm e ## then e # = e ## and both reductions use the same rule on the same redex.
Proof. Induct on the structure of e .
Cases e = x , e = U .term, e = UnmarFailure T : No reduction is possible.
Cases e = (), e = (v hm
1 , ..., v hm
j ), e = #x :T .e 0 , e = marshalled (v . :T ): No reduction is possible, by Lemma H.10
(values do not reduce).
Case e = (e 1 , ..., e j ): Let i be the smallest k such that e 1 through e k-1 are hmvalues. The case i = j + 1 has already
been treated. Given Lemma H.10 (values do not reduce), the only possibility of reduction is (ered.cong) with the
context (e 1 , ..., e k-1 , , e k+1 , ..., e j ). By induction, only one reduction is possible.
Case e = proj i e 0 : If e 0 is a hmvalue, given Lemma H.10 (values do not reduce), the only possibility of reduction is
(ered.proj). Otherwise, by induction, only one reduction of e 0 is possible, and the only possibility for e to reduce is
using (ered.cong) with the context proj i .
Case e = e 1 e 2 : If e 1 and e 2 are both hmvalues, given Lemma H.10 (values do not reduce), the only possibility of
reduction is (ered.ap). If e 1 is an hmvalue and e 2 is not an hmvalue, then the only possibility for reduction is to
use (ered.cong) with the context e 1 ; by induction, this yields at most one possible reduction. Similarly, if e 1 is not
an hmvalue, then the only possibility of reduction is (ered.cong) with the context e 2 .
Case e = mar (e 0 :T ): If e 0 is an hmvalue, then e 0 does not reduce by Lemma H.10 (values do not reduce), so
(ered.mar) is the only possibility of reduction. Otherwise the only possibility of reduction is (ered.cong) with the
context mar ( :T ), so by induction, only one reduction is possible.
Case e = marshalled (e 0 :T ): The only possibility of reduction is (ered.cong) with the context marshalled ( :T ), so
by induction, only one reduction is possible.
Case e = unmar e 0 :T : The only possibility of reduction is (ered.unmar), which has only one possible outcome for any
given e 0 and T .
Cases e = ! e 0 , e = ?: No reduction is possible (communication happens at the network level).
INRIA
Global abstractionsafe marshalling with hash types 65
Case e = [v hm 1 ] T
hm 1
where T is not a hash: The rules (ered.col.col) and (ered.col.le) do not apply since T is not a hash.
Also (ered.cong) does not apply since v hm 1 is a value and we have Lemma H.10 (values do not reduce). The only
rules that may apply are the rules to push brackets in ((ered.col.unit), (ered.col.tuple), (ered.col.fun), (ered.col.marred))
which are mutually exclusive.
Case e = [v hm 1 ] h2
hm 1
: By Lemma H.10 (values do not reduce), no reduction can be derived from (ered.cong) since v hm 1
is a value. The only potentially applicable rules are (ered.col.col) and (ered.col.le). If h 2 = hm then (ered.col.col)
does not apply. Otherwise we do not have h 2 4 hm so (ered.col.le) does not apply. In both cases, only one reduction
is possible.
Case e = [e 1 ] T
hm 1
where e 1 is not a value: Then the only possibility of reduction is (ered.cong). Note that (ered.col.col)
is out since its side conditions would force e 1 to be a value. By induction there is at most one way to reduce e 1 , so
there is at most one way to reduce e .
Discussion H.12 (strength of determinism) Recall the rule to remove a bracket around another bracket:
[[v h0 ] h0
h0
] h0
h1 -#hm [v h0 ] h0
h0 if h 0 #= h 1 and h 1 #= hm (ered.col.col)
These side conditions do not in fact affect the reductions possible: we have [[v h0 ] h0
h0 ] h0
h0 -#hm [v h0 ] h0
h0 by (ered.col.le) and
(ered.cong), and [[v h0 ] h0
h0
] h0
h1 -# h1 [v h0 ] h0
h0 by (ered.col.le). We include the side conditions to make our determinism result,
Theorem H.11 (determinism of expression reduction), stronger. Without these side conditions, we could state determinism
in the following way: if e -#hm e 1 and e -#hm e 2 then e 1 = e 2 .
Of course, network reduction is not deterministic, as befits a concurrent system.
I Compilation
I.1 Decidability of type checking
Definition I.1 (revelation of the implementation of a hash) Let h = hash(N , [T 0 , v ]:[X :Type, T 1 ]). The type
reveal h T is obtained by replacing any subterm of T that is equal to h and not itself inside a hash by the implementation
type T 0 . Thus:
. reveal h UNIT = UNIT
. reveal h (T 1 # ... # T j ) = (reveal h T 1 ) # ... # (reveal h T j )
. reveal h (T 1 #T 2 ) = (reveal h T 1 )#(reveal h T 2 )
. reveal h X = X
. reveal h STRING = STRING
. reveal h U .TYPE = U .TYPE
. reveal h h = T 0
. reveal h h # = h # if h # #= h
Also let reveal . T = T .
Definition I.2 (partial type substitution associated to an environment)
partenvsub nil = id
partenvsub E ,x :T = partenvsub E
partenvsub E ,X :Type = partenvsub E
partenvsub E ,X :Eq(T) = partenvsub E {X T}
partenvsub E ,U :[X :Type,T # ] = partenvsub E
partenvsub E ,U :[X :Eq(T),T # ] = partenvsub E {U .TYPE T}
RR n 4851
66 Leifer, Peskine, Sewell, Wansbrough
Recall Definition G.6 (purely abstract environment).
Lemma I.3 (a purely abstract suffix does not change the substitution) If E 1 is a purely abstract environment then
partenvsub E0 ,E1 = partenvsub E0 .
Proof. Trivial from Definition I.2 (partial type substitution associated to an environment).
Lemma I.4 (stability of types through revelation) If E #hm T :Type then E #hm reveal hm T :Type and E #hm
T == reveal hm T and E #hm partenvsub E T :Type and E #hm T == partenvsub E T .
A trivial consequence that we also use is that if E #hm T :Type then E #hm reveal hm partenvsub E T :Type and
E #hm T == reveal hm partenvsub E T . Also, we freely use (Teq.sym) on the conclusion of this lemma.
Proof. Let h = hash(N , [T 0 , v . ]:[X :Type, T 1 ]). The type reveal hm T can be seen as T with T 0 for hm . By similar
reasoning to the proof of Lemma F.24 (type equivalence is a congruence), starting from E #hm h == T 0 obtained
through (Teq.hash), we get E #hm T == reveal hm T .
By applying Lemma E.6 (environments have to be ok), Lemma E.7 (prefixes of ok environments are ok) and Lemma
F.24 (type equivalence is a congruence) to each concrete binding in E , and using various rules, we get that E #hm T ==
partenvsub E T . By Lemma F.21 (things have to be ok), we have E #hm partenvsub E T :Type.
Lemma I.5 (distinction of fresh type variables) If E is purely abstract and E #hm X == T or E #hm T == X or
E #hm X :Eq(T ) or E #hm T :Eq(X ) or E #hm [Y :Eq(T ), T # ] <: [Y :Eq(X ), T ## ] or E #hm [Y :Eq(X ), T ## ] <:
[Y :Eq(T ), T # ] then T = X . Also, if E is purely abstract, then E #hm U :[Y :Eq(X ), T # ] cannot be derived.
Proof. Induct on the derivation of the assumed judgement.
Case (TK.sub), E #hm X :Eq(T ): There exists K such that the premises are E #hm X :K and E #hm K <: Eq(T ).
By Lemma G.4 (discreteness of subkinding below Type) and reversing (Keq.Eq), there exists T 1 such that K =
Eq(T 1 ) and E #hm T 1 == T by a subproof. By induction on the subproof of E #hm X :Eq(T 1 ), we get
T 1 = X . Since E #hm X == T by a subproof, by induction, we get T = X .
Case (TK.sub), E #hm T :Eq(X ): There exists K such that the premises are E #hm T :K and E #hm K <: Eq(X ).
By Lemma G.4 (discreteness of subkinding below Type) and reversing (Keq.Eq), there exists T 1 such that K =
Eq(T 1 ) and E #hm T 1 == X by a subproof. By induction, we get T 1 = X . Since E #hm T :Eq(X ) by a
subproof, by induction, we get T = X .
Case (TK.Eq): Trivial by induction.
Case (TK.mod): There exists U and T # such that the rule derives E #hm U .TYPE:Eq(X ) from E #hm
U :[Y :Eq(X ), T # ]. By induction this is impossible.
Case (TK.var): Impossible since E is purely abstract.
Case (Teq.Eq): Trivial by induction.
Case (Teq.hash): Impossible by Lemma E.4 (colours have to be ok) and Lemma E.9 (free variables of a judgement come
from the environment) applied to # hm ok.
Case (Teq.refl): Then T = X as desired.
Case (Teq.sym): Trivial by induction.
Case (Teq.tran): Then by induction the ``middle type'' is X , whence by induction again T = X .
Case (Ssub.struct): We have either E #hm Eq(T ) <: Eq(X ) or E #hm Eq(X ) <: Eq(T ) by a subproof. By Lemma
G.4 (discreteness of subkinding below Type) and reversing (Keq.Eq), either E #hm T == X or E #hm X == T
by a subproof. By induction we get T = X as desired.
Case (Ssub.refl): Trivial.
Case (Ssub.tran): Similar to (Teq.tran) above.
Case (US.var): Impossible since E is purely abstract.
INRIA
Global abstractionsafe marshalling with hash types 67
Case (US.sub): The conclusion is E #hm U :[Y :Eq(X ), T # ]. The premises are E #hm U :[Y :K , T ## ] and E #hm
[Y :K , T ## ] <: [Y :Eq(X ), T # ]. By Lemma F.26 (reversing subsignaturing judgement), E #hm K <: Eq(X ) by
a subproof. By Lemma G.4 (discreteness of subkinding below Type) and reversing (Keq.Eq), there exists T 1 such
that K = Eq(T 1 ) and E #hm T 1 == X by a subproof. By induction we get T 1 = X . The other premise of the
bottommost rule is therefore E #hm U :[Y :Eq(X ), T ## ], which is impossible by induction.
Case (US.self): Impossible.
Lemma I.6 (open interpretation of type equivalence) E #hm T == T # iff E #hm T :Type and E #hm T # :Type
and reveal hm partenvsub E T = reveal hm partenvsub E T # .
Proof. Assume E #hm T == T # . By Lemma F.21 (things have to be ok), we have E #hm T :Type and E #hm
T # :Type. We will now prove the last statement by induction on the lexically ordered pair (m, n) where m is the length
of E and n is the number of module bindings in E . Let E 1 be the longest bare bones suffix of E (see Definition G.5 (bare
bones environment)).
Case E = E 1 : Then partenvsub E = id, so the proof obligation is reveal hm T = reveal hm T # . Induct on the structure
of T .
Case T = TC (T 1 , ..., T j ): By Lemma G.11 (type decomposition), there exist T #
1 , ..., T #
j such that E #hm T #
i ==
T i for each i . Then, by induction, for each i , we have reveal hm T #
i = reveal hm T i . Furthermore, one of the
following cases holds:
Case T # = TC (T #
1 , ..., T #
j ): Then we have reveal hm T # = reveal hm T .
Case T # = hm = hash(N , [TC (T #
1 , ..., T #
j ), v ]:[X :Type, T ## ]): Then reveal hm T # = TC (T #
1 , ..., T #
j ) =
reveal hm (TC (T #
1 , ..., T #
j )) = T (note that for all i , reveal hm T #
i = T #
i since hm is not a subterm of T #
i ).
Case T = X : By Lemma I.5 (distinction of fresh type variables), we have T # = X = T .
Case T = U .TYPE: Impossible by Lemma E.9 (free variables of a judgement come from the environment).
Case T = h 1 : By Lemma G.11 (type decomposition), one of the following cases holds:
Case hm = h 1 = hash(N , [T # , v ]:[X :Type, T ## ]): Then reveal hm h 1 = T # = reveal hm T # (note that hm
is not a subterm of T # ).
Case T # = hm = hash(N , [h 1 , v ]:[X :Type, T ## ]): Then reveal hm h 1 = h 1 = reveal hm T # .
Case T # = h 1 : Trivial.
Case E = E 0 , x :T 1 , E 1 : By Lemma E.6 (environments have to be ok) and Lemma E.22 (environments do not contain
free expression variables), x /
# fv E 1 . By Lemma E.21 (types do not contain free expression variables), x /
# fv T #
fv T # . Then, by Lemma F.15 (strengthening), we get E 0 , E 1 #hm T == T # . We can apply induction to E 0 , E 1 ,
getting reveal hm partenvsub E0 ,E1 T = reveal hm partenvsub E0 ,E1 T # . Since partenvsub E0 ,E1 = partenvsub E ,
this is the desired result.
Case E = E 0 , X :Eq(T 1 ), E 1 : By Lemma E.19 (computing the pvu of a type world judgement), hm 4
min (pvu X (E 1 )). By Lemma E.7 (prefixes of ok environments are ok) and reversing (envok.X), we have
E 0 #hm T 1 :Type, whence by (Teq.refl) and (TK.Eq), E 0 #hm T 1 :Eq(T 1 ). We can use Lemma F.14 (type preser
vation by substitution) to {X#T 1 }, getting E # #hm {X#T 1 }T == {X#T 1 }T # where E # = E 0 , {X#T 1 }E 1 .
By induction, we get that reveal hm partenvsub E # {X#T 1 }T = reveal hm partenvsub E # {X#T 1 }T # .
By Definition I.2 (partial type substitution associated to an environment), partenvsub E0 ,X :Eq(T1 ) =
partenvsub E0 {X T 1 }. By Lemma I.3 (a purely abstract suffix does not change the substitution), partenvsub E =
partenvsub E0 {X T 1 }. So we have reveal hm partenvsub E T = reveal hm partenvsub E T # , as desired.
Case E = E 0 , U :[X :K , T 1 ], E 1 : Let Z and z be fresh. By Lemma F.29 (type preservation by module sub
stitution in coloured judgements), we get E 0 , Z :Eq(T 1 ), z :{X Z}T 2 , {U .TYPE Z , U .term z}E 1 #hm
{U .TYPE Z , U .term z }T == {U .TYPE Z , U .term z}T # . Since E 1 is purely abstract, we have
{U .TYPE Z , U .term z }E 1 = E 1 . By Lemma E.21 (types do not contain free expression variables), z /
#
fv {U .TYPE Z}T , whence {U .TYPE Z , U .term z}T = {U .TYPE Z}T , and the same holds for T # . By
Lemma F.15 (strengthening), we get E # #hm #T == #T # where E # = E 0 , Z :K , E 1 and # = {U .TYPE Z}.
Now we do case analysis on the structure of K .
RR n 4851
68 Leifer, Peskine, Sewell, Wansbrough
Case K = Type: By induction on the last judgement above, we have reveal hm partenvsub E # #T =
reveal hm partenvsub E # #T # . Now partenvsub E # # = partenvsub E , so we have the desired result.
Case K = Eq(T 0 ): Apply the case E = E 0 , Z :Eq(T 0 ), E 1 above to E # #hm #T == #T # . We get
reveal hm partenvsub E # #T = reveal hm partenvsub E # #T # . Now given Definition I.2 (partial type substitu
tion associated to an environment) and Lemma I.3 (a purely abstract suffix does not change the substitution),
we in fact have partenvsub E = partenvsub E #. So we have the desired result.
We turn to the other half of the proof. Assume that E #hm T :Type and E #hm T # :Type and
reveal hm partenvsub E T = reveal hm partenvsub E T # . We induct on the number of bindings of E that are not of the
form U :[X :Type, ] nor X :Type. We write E 1 for the longest purely abstract suffix of E .
Case E is purely abstract: Induct on the structure of T . Note that partenvsub E = id.
Case T = TC (T 1 , ..., T j ): By definition of reveal hm , one of the following cases holds:
Case T # = UNIT or T # = mar : Then T = T # , so E #hm T == T # by (Teq.refl).
Case T # = TC (T #
1 , ..., T #
j ) with j #= 0: Still by the definition of reveal hm , we have reveal hm T i =
reveal hm T #
i for all i . Then by induction we have E #hm T i == T #
i . By the appropriate rule amongst
(Teq.cong.fun) and (Teq.cong.tuple), we have E #hm T == T # .
Case T # = hm = hash(N , [T , v ]:[X :Type, T ## ]): We have E #hm ok by Lemma E.6 (environments have
to be ok). Then, by (Teq.hash), we get E #hm T # == T , whence E #hm T == T # by (Teq.sym).
Case T = X or T = U .TYPE: Then reveal hm T = T = T # = reveal hm T # . By (Teq.refl), we have E #hm
T == T # .
Case T = hm: By definition of reveal hm , one of the following cases holds:
Case T # = hm: Then E #hm T == T # by (Teq.refl).
Case hm = hash(N , [T # , v ]:[X :Type, T ## ]): We have E #hm ok by Lemma E.6 (environments have to be
ok). Then, by (Teq.hash), we get E #hm T == T # .
Case T is a hash but T #= hm: Then reveal hm T = T . By definition of reveal hm , one of the following cases
holds:
Case T # = hm = hash(N , [T , v ]:[X :Type, T ## ]): We have E #hm ok by Lemma E.6 (environments have
to be ok). Then, by (Teq.hash), we get E #hm T # == T , whence E #hm T == T # by (Teq.sym).
Case T # = T : Then E #hm T == T # by (Teq.refl).
Case E = E 0 , x :T 0 , E 1 : By Lemma E.21 (types do not contain free expression variables), Lemma E.22 (environments
do not contain free expression variables) and Lemma F.15 (strengthening), we have E 0 , E 1 #hm T :Type and
E 0 , E 1 #hm T # :Type. Since furthermore partenvsub E = partenvsub E0 ,E1 , by induction, we get E 0 , E 1 #hm
T == T # . By Lemma E.6 (environments have to be ok) and Lemma E.7 (prefixes of ok environments are ok),
we have E 0 , x :T 0 #hm ok, so E #hm T == T # by Lemma F.5 (combined weakening) (note that x /
# fv E 1 by
Lemma E.8 (ok environments have no repetition in the domain)).
Case E = E 0 , X :Eq(T 0 ), E 1 : Then partenvsub E = partenvsub E0 {X T 0 }. By Lemma E.6 (environments have to
be ok), Lemma E.7 (prefixes of ok environments are ok) and reversing (envok.X) and (Kok.Eq), we have E 0 #hm
T 0 :Type. By Lemma E.19 (computing the pvu of a type world judgement), any proof # of E #hm T :Type
satisfies hm 4 min (pvu X (#)). By Lemma F.14 (type preservation by substitution), we get E 0 , {X#T 0 }E 1 #hm
{X#T 0 }T :Type. Similarily, we have E 0 , {X#T 0 }E 1 #hm {X#T 0 }T # :Type.
By induction, we get E 0 , {X#T 0 }E 1 #hm {X#T 0 }T == {X#T 0 }T # .
Since E 0 , X :Eq(T 0 ) #hm ok and X /
# domE 1 by Lemma E.8 (ok environments have no repetition in the domain),
by Lemma F.5 (combined weakening), we have E 0 , X :Eq(T 0 ), {X#T 0 }E 1 #hm {X#T 0 }T == {X#T 0 }T # .
By Lemma G.8 (type substitution in a purely abstract environment), given the latest judgement and
E 0 , X :Eq(T 0 ), E 1 #hm ok, we get E 0 , X :Eq(T 0 ), E 1 #hm {X#T 0 }T == {X#T 0 }T # .
By Lemma F.25 (type substitution in equivalence), we get E #hm T == T # as desired.
INRIA
Global abstractionsafe marshalling with hash types 69
Case E = E 0 , U :[X :Eq(T 0 ), T 1 ], E 1 : Then partenvsub E = partenvsub E0 {U .TYPE T 0 }. Let Z be a fresh
variable, and let E # = E 0 , Z :Eq(T 0 ), {U .TYPE#Z}E 1 . By the definition of partenvsub, we have
partenvsub E # = partenvsub E0 {Z#T 0 }. Since Z is fresh, we have reveal hm partenvsub E # {U .TYPE#Z}T =
reveal hm partenvsub E # {U .TYPE#Z}T # .
By Lemma F.31 (type preservation by module substitution in coloured judgements for type world judgements), since
E #hm T :Type, we get E # #hm {U .TYPE#Z}T :Type. Similarly we have E # #hm {U .TYPE#Z}T # :Type.
By the previous case, E # #hm {U .TYPE#Z}T == {U .TYPE#Z}T # .
By Lemma E.6 (environments have to be ok) and Lemma E.7 (prefixes of ok environments are ok), we
have E 0 , U :[X :Eq(T 0 ), T 1 ] #hm ok. Using Lemma E.8 (ok environments have no repetition in the do
main), we get U /
# {Z} # dom ({U .TYPE#Z}E 1 ), so by Lemma F.5 (combined weakening), we have
E 0 , U :[X :Eq(T 0 ), T 1 ], Z :Eq(T 0 ), {U .TYPE#Z}E 1 #hm {U .TYPE#Z}T == {U .TYPE#Z}T # .
By (US.var) and (TK.mod), we have E 0 , U :[X :Eq(T 0 ), T 1 ] #hm U .TYPE:Eq(T 0 ). By Lemma E.19 (com
puting the pvu of a type world judgement), we can apply Lemma F.14 (type preservation by substitution).
We get E 0 , U :[X :Eq(T 0 ), T 1 ], {Z U .TYPE}{U .TYPE Z}E 1 #hm {Z U .TYPE}{U .TYPE Z}T ==
{Z U .TYPE}{U .TYPE Z}T # . Since Z was fresh, we have E #hm T == T # , as desired.
Theorem I.7 (semantic interpretation of type world judgements) Let E #hm J be any type world judgement. It is
derivable iff all of the following conditions are met:
1. E has no repetition in the domain and unresolved free variables.
2. All the free variables of J are in domE .
3. All the hashes in E #hm J are correct.
4. The following extra condition is met, depending on the form of J :
Case E #hm ok or E #hm K ok or E #hm T :Type or T #hm S ok: no extra condition.
Case E #hm T == T # or E #hm T :Eq(T # ): reveal hm partenvsub E T = reveal hm partenvsub E T # .
Case E #hm K == K # : either K = K # = Type, or there exist T and T # such that K = Eq(T ) and K # =
Eq(T # ) and E #hm T == T # .
Case E #hm K <: K # : either K # = Type, or there exist T and T # such that K = Eq(T ) and K # = Eq(T # )
and E #hm T == T # .
Case E #hm [X :K , T ] <: [X :K # , T # ]: E #hm K <: K # and E , X :K #hm T == T # .
Case E #hm U :[X :K , T ]: E contains a binding of the form U :[X :K 1 , T 2 ] for some K 1 and T 2 , and E #hm
[X :Eq(U .TYPE), T 2 ] <: [X :K , T ].
Proof. If E #hm J , then E has no repetition in the domain and no unresolved free variables by Lemma E.6 (environments
have to be ok) and Lemma E.8 (ok environments have no repetition in the domain) and Lemma F.13 (ok environments
have no unresolved free variables); all the hashes in J are correct by Lemma E.5 (hashes have to be ok), and all the free
variables of J are in domE by Lemma E.9 (free variables of a judgement come from the environment). We now assume
that conditions 1--3 are met, and prove that E #hm J is derivable iff condition 4 is met.
Cases E #hm ok, E #hm K ok, E #hm T :Type, E #hm [X :K , T ] ok: Since there is no extra condition, we just have
to prove that the judgement is derivable. We induct on the length of E .
Case nil #hm ok: By condition 3 (if hm is a hash) or (hmok.zero) (if hm = .), we can derive # hm ok, whence
we apply (envok.nil).
Case E , #:# #hm ok: Given the (envok.*) rules, this judgement is derivable iff the judgement E #hm #:# is. By
induction, these judgements are derivable.
Case E #hm T :Type: By the previous cases, E #hm ok is derivable. By Lemma F.9 (types are ok provided their
hashes are), E #hm T :Type is derivable.
RR n 4851
70 Leifer, Peskine, Sewell, Wansbrough
Case E #hm Type ok: By the previous cases, E #hm ok is derivable. Then we can derive E #hm Type ok by
(Kok.Type).
Case E #hm Eq(T ) ok: By the previous cases, E #hm ok is derivable. By Lemma F.9 (types are ok provided
their hashes are), E #hm T :Type is derivable. Then we can derive E #hm Eq(T ) ok by (Kok.Eq).
Case E #hm [X :K , T ] ok: By the previous cases, E #hm K ok is derivable. By alphaconversion, we can choose
X not in domE . By (envok.X), we get a proof of E , X :K #hm ok. By Lemma F.9 (types are ok provided
their hashes are), since fv T # fv [X :K , T ] # {X } # domE # {X }, E , X :K #hm T :Type is derivable.
Then, by (Sok), we get E #hm [X :K , T ] ok.
Case E #hm T == T # : Note that by Lemma F.9 (types are ok provided their hashes are), we have E #hm T :Type and
E #hm T # :Type. Apply Lemma I.6 (open interpretation of type equivalence).
Case E #hm T :Eq(T # ): Given (TK.Eq) and (Teq.Eq), this judgement is equivalent to E #hm T == T # . Apply the
previous case.
Case E #hm K == K # : Obvious from (Keq.*).
Case E #hm K <: K # : Subcase K = K # = Type: Trivial.
Subcase K = Eq(T ) and K # = Type: By Lemma F.9 (types are ok provided their hashes are) and (Kok.Eq),
E #hm Eq(T ) ok is derivable. By Lemma E.6 (environments have to be ok) and (Kok.Type), we have
E #hm Type. By (Ksub.Eq), we have E #hm Eq(T ) <: Type.
Subcase K = Type and K # = Eq(T # ): By Lemma G.4 (discreteness of subkinding below Type) and the (Keq.*)
rules, this is impossible.
Subcase K = Eq(T ) and K # = Eq(T # ): If E #hm T == T # then E #hm Eq(T ) <: Eq(T # ) by (Keq.Eq) and
(Ksub.refl). The converse follows from Lemma G.4 (discreteness of subkinding below Type).
Case E #hm [X :K , T ] <: [X :K , T # ]: Apply Lemma F.26 (reversing subsignaturing judgement). Conversely, apply
(Ssub.struct).
Case E #hm U :[X :K , T ]: Apply Lemma F.27 (reversing module value variable typing judgement) and Lemma F.28
(obtaining module value variable typing judgement).
Lemma I.8 (uniqueness of expression typing) If E #hm e:T then E #hm e:T # iff E #hm T == T # .
Proof. If E #hm e:T and E #hm T == T # then E #hm e:T # by (eT.eq). Now we prove the converse by induction on
the structure of e . The crux of the matter is that (1) apart from (eT.eq), the expression typing rules are syntaxdirected
and (2) type equivalence is a congruence.
We have E #hm e:T and E #hm e:T # . By Lemma G.1 (shortening typing proof), there exist T 1 and T #
1 such
that E #hm e:T 1 and E #hm T #
1 by proofs # and # # that do not end with (eT.eq), and E #hm T == T 1 and
E #hm T # == T #
1 . We now prove that E #hm T 1 == T #
1 ; by (Teq.tran) and (Teq.sym) this gives E #hm T == T # as
desired. Note that it is enough to prove that T 1 = T #
1 . We do case analysis on the structure of e; in each case # and # #
have to end with the same rule.
Case e = x (eT.var): Then E contains a binding for x ; by Lemma E.6 (environments have to be ok) and Lemma E.8 (ok
environments have no repetition in the domain), this binding is unique, and the type attributed to x is T 1 = T #
1 .
Case e = U .term (eT.mod): Then there exist K and K # such that E #hm U :[X :K , T 1 ] and E #hm U :[X :K , T #
1 ].
By Theorem I.7 (semantic interpretation of type world judgements) and Lemma F.26 (reversing subsignaturing
judgement), we see that there exists T 2 such that E , X :Eq(U .TYPE) #hm T 2 == T 1 and E , X :Eq(U .TYPE) #hm
T 2 == T #
1 . By (Teq.tran) and (Teq.sym), we get E , X :Eq(U .TYPE) #hm T 1 == T #
1 . Since E #hm T 1 :Type and
E #hm T #
1 :Type, by Lemma E.9 (free variables of a judgement come from the environment), X /
# fv T 1 # fv T #
1 .
Hence, by Lemma F.15 (strengthening), we get E #hm T 1 == T #
1 as desired.
Case e = e 1 e 2 (eT.ap): Then there exist T 2 and T #
2 such that E #hm e 1 :T 2 #T 1 and E #hm e #
1 :T #
2 #T #
1 . By induction,
we get E #hm T 2 #T 1 == T #
2 #T #
1 . By Lemma I.6 (open interpretation of type equivalence) applied once in each
direction, we get E #hm T 1 == T #
1 as desired.
INRIA
Global abstractionsafe marshalling with hash types 71
Case e = #x :T 0 .e 0 (eT.fun): Then there exist T 2 and T #
2 such that T 1 = T 0 #T 2 and T 1 = T 0 #T #
2 and E , x :T 0 #hm
e 0 :T 2 and E , x :T 0 #hm e 0 :T #
2 . By induction we get E , x :T 0 #hm T 2 == T #
2 . By Lemma E.21 (types do not
contain free expression variables) and Lemma F.15 (strengthening), we get E #hm T 2 == T #
2 . By (Teq.refl) and
(Teq.cong.fun), we get E #hm T 1 == T #
1 as desired.
Cases e = ! e 0 , e = () (eT.send, eT.unit): Then T 1 = UNIT = T #
1 .
Cases e = ?, e = mar (e 0 :T 0 ), e = marshalled (e 0 :T 0 ) (eT.recv, eT.mar, eT.marred): Then T 1 = STRING = T #
1 .
Cases e = unmar e 0 :T 0 , e = UnmarFailure T0 , e = [e 0 ] T0
hm 0
(eT.unmar, eT.Undynfailure, eT.col):
Then T 1 = T 0 = T #
1 .
Case e = (e 1 , ..., e j ) (eT.tuple): Similar to the (eT.fun) case, using (Teq.cong.tuple).
Case e = proj i e 0 (eT.proj): Similar to the (eT.ap) case.
Definition I.9 (reconstructed type of an expression) We define the reconstructed type of an expression e in an
environment E and a colour hm , written basictype E
hm e , recursively as follows:
basictype E
hm (x ) = # E
hm T where E = ..., x :T , ...
basictype E
hm (U .term) = # E
hm {X#U .TYPE}T where E = ..., U :[X :K , T ], ...
basictype E
hm (#x :T 0 .e 0 ) = (# E
hm
T 0 )#(basictype E ,x :T0
hm
e 0 )
basictype E
hm (e 1 e 2 ) = T 1 where basictype E
hm e 1 = T 2 #T 1
basictype E
hm ((e 1 , ..., e j )) = basictype E
hm e 1 # ... # basictype E
hm e j
basictype E
hm (proj i e 0 ) = T i where basictype E
hm e 0 = T 1 # ... # T j
basictype E
hm (mar (e 0 :T 0 )) = STRING
basictype E
hm (marshalled (e 0 :T 0 )) = STRING
basictype E
hm (unmar e 0 :T 0 ) = # E
hm T 0
basictype E
hm (! e 0 ) = UNIT
basictype E
hm (?) = STRING
basictype E
hm ([e 0 ] T0
hm 0
) = # E
hm
T 0
basictype E
hm (UnmarFailure T0 ) = # E
hm T 0
where # E
hm = reveal hm partenvsub E .
Note that this definition basictype E
hm is partial: it fails if a subexpression does not have a type of the required form
(cases e 1 e 2 , (e 1 , ..., e j )) or if a variable is not bound by the environment (cases x , U .term).
Lemma I.10 (simplicity of the reconstructed type) If basictype E
hm e is welldefined, it contains no hm , nor does it
contain any variable that is bound concretely in E .
Proof. Trivial by induction.
Lemma I.11 (assurance of correctness of the reconstructed type) If E #hm e:T then basictype E
hm e is welldefined
and E #hm e:basictype E
hm e .
Proof. Induct on the derivation of E #hm e:T . By Lemma G.1 (shortening typing proof), there exists T # such that
E #hm e:T # by a subproof # that does not end in (eT.eq), and E #hm T # == T . Note that by Lemma I.6 (open
interpretation of type equivalence), reveal hm partenvsub E T = reveal hm partenvsub E T # . We discriminate on the last
rule of #.
Case (eT.var): We have E = E 0 , x :T # , E 1 and e = x . By Lemma I.4 (stability of types through revelation), E #hm
T # == reveal hm partenvsub E T # , so by (eT.eq) we get E #hm x:reveal hm partenvsub E T # as desired.
Case (eT.mod): The premises are E #hm U :[X :K , T ] and E #hm T :Type. By Theorem I.7 (semantic interpretation
of type world judgements) and Lemma F.26 (reversing subsignaturing judgement), there exist E 0 , E 1 , K # and T #
such that E = E 0 , U :[X :K # , T # ], E 1 and E , X :Eq(U .TYPE) #hm T # == T . By Lemma E.9 (free variables
of a judgement come from the environment), we have X /
# fv T . By Lemma E.19 (computing the pvu of a type
world judgement) and Lemma F.14 (type preservation by substitution), we have E #hm {X#U .TYPE}T # ==
RR n 4851
72 Leifer, Peskine, Sewell, Wansbrough
T . By Lemma I.4 (stability of types through revelation) and (Teq.tran) and (Teq.sym), we have E #hm T ==
reveal hm partenvsub E {X U .TYPE}T # as desired.
Case (eT.fun): There exist T 1 and T 2 such that e = #x :T 1 .e 1 and T # = T 1 #T 2 , and the premise is
E , x :T 1 #hm e 1 :T 2 . By induction, E , x :T 1 #hm e 1 :basictype E ,x :T1
hm
e 1 . Thus, by (eT.fun), we get E #hm
#x :T 1 .e 1 :T 1 #basictype E ,x :T1
hm e 1 . By Lemma I.4 (stability of types through revelation), we have E #hm
reveal hm partenvsub E T 1 == T 1 , whence the desired result by (Teq.cong.fun).
Case (eT.ap): There exist e 1 , e 2 and T 2 such that e = e 1 e 2 the premises are E #hm e 1 :T 2 #T # and E #hm
e 2 :T 2 . By induction, we have E #hm e 1 :basictype hm
E e 1 . By Lemma I.8 (uniqueness of expression typ
ing), we have E #hm basictype hm
E e 1 == T 2 #T # . By Lemma I.10 (simplicity of the reconstructed type),
partenvsub hm (basictype hm
E e 1 ) = basictype hm
E e 1 . By using Lemma F.14 (type preservation by substitution)
and Lemma F.33 (type preservation by fully carried out module substitution) once for each concrete binding in E ,
we get that E # # basictype hm
E e1 == (partenvsub E T 2 )#(partenvsub E T # ) with E # fully abstract. By Lemma G.11
(type decomposition), and given that basictype hm
E e 1 #= hm by Lemma I.10 (simplicity of the reconstructed type),
basictype hm
E e 1 must have the form T #
2 #T #
1 , with E # #hm T #
1 == T 1 . By Lemma I.6 (open interpretation of type
equivalence) applied once in each direction, we have E #hm T #
1 == T # . Thus E #hm (basictype E
hm e) == T # ,
whence the desired result.
Case (eT.tuple): Similar to the lambdaabstraction case.
Case (eT.proj): Similar to the application case.
Cases (eT.mar), (eT.marred), (eT.send), (eT.recv): Trivial.
Case (eT.unmar), (eT.col), (eT.Undynfailure): Trivial.
Lemma I.12 (validity of the reconstructed type) If basictype E
hm e is welldefined and E #hm ok then E #hm
basictype E
hm e:Type and E #hm e:basictype E
hm e .
Proof. Induct on the structure of e . The rules to define basictype E
hm were chosen on purpose. Some steps apply
reveal hm partenvsub E , which produces an equivalent type by an easy application of Lemma I.6 (open interpretation
of type equivalence).
Corollary I.13 (deciding expression typing through type reconstruction) E #hm e:T is derivable iff basictype E
hm e
is welldefined and reveal hm partenvsub E T = basictype E
hm e and E #hm T :Type.
Proof. If E #hm e:T is derivable then, by Lemma I.11 (assurance of correctness of the reconstructed type),
basictype E
hm e is welldefined and E #hm e:basictype E
hm e . By Lemma I.8 (uniqueness of expression typing),
E #hm T == basictype E
hm e . By Lemma I.10 (simplicity of the reconstructed type) and Lemma I.6 (open inter
pretation of type equivalence), reveal hm partenvsub E T = basictype E
hm e . Finally, E #hm T :Type by Lemma E.6
(environments have to be ok).
Conversely, assume basictype E
hm e is welldefined and reveal hm partenvsub E T = basictype E
hm e and E #hm
T :Type. By Lemma E.6 (environments have to be ok) and Lemma I.12 (validity of the reconstructed type), we have
E #hm e:basictype E
hm e . By Lemma I.10 (simplicity of the reconstructed type) and Lemma I.6 (open interpretation of
type equivalence), E #hm (basictype E
hm e) == T . Thus, by (eT.eq), we have E #hm e:T .
Theorem I.14 (decidability of type checking) There is algorithm that decides whether any given judgement # /
# domE ,
# hm ok, E #hm J or # n ok is derivable.
Note that given Lemma I.12 (validity of the reconstructed type), type checking for expressions does not in fact need to
be given a type, it can infer it. As in the simplytyped lambdacalculus, of course, we need to annotate function arguments;
and we also have explicit type annotations on the dynamic typing constructs and coloured brackets.
INRIA
Global abstractionsafe marshalling with hash types 73
Proof. We explain how to reduce the decidability of a judgement to the decidability of a number of strictly smaller
judgements, the size of a judgement being here the lexically ordered pair (a, b) where a is the number of expression
syntax nodes (including those inside hashes) and b is the total size of the judgement.
By Lemma E.3 (nonmembership in domain is interpreted trivially), we get a decision procedure for checking deriv
ability of # /
# domE judgements, provided we have a decision procedure for checking correctness of embedded hashes.
For type world judgements, Theorem I.7 (semantic interpretation of type world judgements) easily translates into an
algorithm.
Given the rules (hmok.*), (MS.struct), (mT.*), and (nok.*), decidability of derivability for judgements of the form
# hm ok, E #hm M :S , E #hm m:T , and # n ok follows from decidability of smaler type world and expression typing
judgements.
For expression typing, Corollary I.13 (deciding expression typing through type reconstruction) gives a decision pro
cedure: to decide whether E #hm e:T is derivable, construct basictype E
hm e (if this fails, then e has no type), and check
some smaller type world jdugements.
Definition I.15 (user source program) User source programs are programs that contain no hashes or coloured brackets.
Discussion I.16 (decidability of type checking for user programs) User source programs can be type checked without
any computation on hashes. Following the decision procedure given in the previous proofs, type checking does not
introduce extra hashes, hence hashfree programs can be checked without ever encountering hashes.
I.2 Bracket elimination
Definition I.17 (bracket elimination subsystem) The bracket elimination subsystem is a reduction relation -# be
hm on
expressions consisting of (ered.cong) and the (ered.col.*) rules.
Lemma I.18 (determinism of bracket elimination) Bracket elimination is deterministic.
Proof. Trivial consequence of Theorem H.11 (determinism of expression reduction).
Lemma I.19 (termination of bracket elimination) Bracket elimination is strongly normalising.
Proof. Define the bracket elimination weight of an expression w be (e) structurally on the expression.
w be (()) = 1
w be ((e 1 , ..., e j )) = w be (e 1 ) + + w be (e j ) + 1
w be (proj i e) = w be (e) + 1
w be (x ) = 1
w be (#x :T .e) = 1
w be (e 1 e 2 ) = w be (e 1 ) + w be (e 2 ) + 1
w be (mar (e:T )) = w be (e) + 1
w be (marshalled (e:T )) = w be (e) + 1
w be (unmar e:T ) = w be (e) + 1
w be (! e) = w be (e) + 1
w be (?) = 1
w be (U .term) = 1
w be ([e] T
hm
) = 2 w be (e)
w be (UnmarFailure T ) = 1
It is obvious that w be (e) is always a positive integer.
We prove that if e -# be
hm e # then w be (e) > w be (e # ). We induct on the derivation of the reduction.
Case (ered.col.unit): Here e = [()] UNIT
hm # and e # = (). We have w be (e) = 2 > 1 = w be (e # ).
Case (ered.col.tuple): Here e = [(v hm #
1 , ..., v hm #
j )] T1#...#T j
hm # and e # = ([v hm #
1 ] T1
hm # , ..., [v hm #
j ] T j
hm # ). We have w be (e) =
2(1 +
P i w be (v hm #
i )) >
P i
2w be (v hm #
i ) = w be (e # ).
Case (ered.col.fun): Here e = [#x :T .e 0 ] T # #T ##
hm # and e # = #x :T # .[{x #[x ] T #
hm }e 0 ] T ##
hm # . We have w be (e) = 2 > 1 =
w be (e # )
RR n 4851
74 Leifer, Peskine, Sewell, Wansbrough
Case (ered.col.marred): Here e = [marshalled (e 0 :T )] STRING
hm # and e # = marshalled (e 0 :T ). We have w be (e) =
2(1 + w be (e 0 )) > 1 + w be (e 0 ) = w be (e # ).
Case (ered.col.col): Here e = [[v h0 ] h0
h0 ] h0
h1 and e # = [v h0 ] v h 0
v h 0 . We have w be (e) = 2w be (e # ) > w be (e # ).
Case (ered.col.le): Here e = [v hm # ] h ##
hm # and e # = v hm # . We have w be (e) = 2w be (e # ) > w be (e # ).
Case (ered.cong): Here e = C hm
hm 0
e 0 and e # = C hm
hm 0
e #
0 and e 0 -# be
hm 0
e #
0 . By induction, w be (e 0 ) > w be (e #
0 ). If
C hm
hm 0
= [ ] T0
hm 0
, then w be (e) = 2w be (e 0 ) > 2w be (e # 0 ) = w be (e # ). Otherwise, there exists an integer k such that
w be (e) = k + w be (e 0 ) > k + w be (e # 0 ) = w be (e # ).
Since the weight of an expression is a positive integer that decreases at each step of reduction, bracket elimination is
strongly normalising (bracket elimination of e terminates in at most w be (e) steps).
Definition I.20 (bracket erasure) If # is any syntactic entity, erase brackets(#) is # with all brackets outside hashes
erased. In particular, erase brackets(h) = h , and erase brackets([e] T
hm ) = erase brackets(e).
Definition I.21 (colourless proof) A colourless proof is one that does not use (hmok.hash) nor (eT.col).
A colourless expression, type, etc., is one whose validity can be derived by a colourless proof. It is left as an exercise
to the reader to prove that colourless types are those that contain no hashes and colourless expressions are those that
contain no brackets and whose type annotations only use colourless types.
Definition I.22 (bracketless expressions) A bracketless expression is one that does not have any coloured brackets in it.
Ditto for values, contexts, and networks.
Definition I.23 (bracketless reductions) Define e -# nb
e # on bracketless expressions as given by the (ered.*) rules other
than (ered.col.*), with the righthand sides modified to not introduce brackets, namely:
. (ered.ap) becomes (#x :T .e)v -# nb {x v}e;
. (ered.mar) becomes mar (e:T ) -# nb
marshalled (e:T ).
Also define n -# nb
n # for networks in the obvious way.
Lemma I.24 (progress and determinism of bracketless expression reduction) If e is a bracketless expression then
exactly one of the following cases holds:
. e is a bracketless value;
. e is dormant, i.e. is UnmarFailure T or a communication in a bracketless evalution context;
. e reduces by -# nb
; moreover there is exactly one rule with one redex applicable.
Proof. Use Theorem H.6 (progress of expressions) for the ``at least one'' part. Similar to the proof of Theorem H.11
(determinism of expression reduction) for the ``at most one'' part.
Theorem I.25 (bracket erasure preserves expression reduction outcomes) If nil #hm e:T and e -#hm e # then
erase brackets(e) -# nb
? erase brackets(e # ).
Proof. (Sketch.) Induct on the derivation of the reduction. If e -#hm e # by one of the bracket pushing
rules, then erase brackets(e) = erase brackets(e # ) (check each case). If e -#hm e # by another rule, then
erase brackets(e) -# nb
erase brackets(e # ) (check each case, noticing that if v hm 1 is a value then erase brackets(v hm 1 )
is a bracketless value). Finally, the case of (ered.cong) follows by induction.
Theorem I.26 (bracket erasure preserves reduction outcomes) If # n ok and n -# n # then
erase brackets(n) -# nb
? erase brackets(n # ).
Proof. Follows from Theorem I.25 (bracket erasure preserves expression reduction outcomes).
INRIA
Global abstractionsafe marshalling with hash types 75
Theorem I.27 (bracket erasure does not add expression reduction outcomes) If nil #hm e:T and
erase brackets(e) -# nb
e then there exists e # such that erase brackets(e # ) = e and e -# +
hm e #
Proof. By Theorem H.6 (progress of expressions) and Lemma I.19 (termination of bracket elimination), there exists a
sequence of expressions e = e 0 , e 1 , ..., e j such that e i-1 -# be
hm e i for 1 6 i 6 j and e j does not reduce by any bracket
pushing rule. By definition, erase brackets(e) = erase brackets(e j ). Thus by hypothesis, erase brackets(e j ) -# nb
e.
By Theorem H.6 (progress of expressions) one of the following cases holds:
Case e j is an hmvalue: Then erase brackets(e j ) is a bracketless value, so by Lemma I.24 (progress and determinism
of bracketless expression reduction) does not reduce by -# nb
, a contradiction.
Case e j is dormant: Then erase brackets(e j ) is a bracketless dormant expression, so by Lemma I.24 (progress and
determinism of bracketless expression reduction) does not reduce by -# nb
, a contradiction.
Case e j reduces: Therefore there exists e # such that e j -#hm e # , a non bracket pushing reduction. Hence
erase brackets(e j ) -# nb
erase brackets(e # ). By Lemma I.24 (progress and determinism of bracketless expres
sion reduction), erase brackets(e # ) =
e.
Theorem I.28 (bracket erasure does not add reduction outcomes) If # n ok and erase brackets(n) -# nb
n 0 then there
exists n # such that erase brackets(n # ) = n 0 and n -# + n #
This means we can erase all brackets once all the modules have been reduced away. Clearly -# nb
is not type preserving
but it represents a possible implementation strategy.
Proof. Follows from Theorem I.27 (bracket erasure does not add expression reduction outcomes).
We might hope that: If # n ok then n -# # n # iff erase brackets(n) -# nb
# erase brackets(n # ).
This is not true! Counterexample: erase brackets(3) -# nb
= erase brackets([3] INT
h ) but not 3 -# # .
[3] INT
h
Definition I.29 (type erasure) We define erase(e) to be e with all type annotations and brackets erased except that the
type annotations on mar , marshalled , and unmar are left unchanged. Ditto for networks. We define ---# erase
to be like
-#hm by taking the eraseimage of the left and righthand sides of each rule (and removing rules that would become
e ---# erase
e). Ditto for networks.
Note that erased terms do not form a subsyntax of our usual syntax since e.g. erase(#x :T .e) = (#x .e). We will not
make explicit any formal reasoning about erased terms so do not construct this new syntax explicitly.
Note that the only difference between erase(e) and erase brackets(e) is that the former removes type annotations
from lambdaexpressions. Moreover, ---# erase
is the same as -# nb
except that the type annotations in the lambdaexpressions
are erased.
Theorem I.30 (type erasure) Assume # n ok. We have that n -# n # implies erase(n) ---# erase
? erase(n # ). Conversely,
erase(n) ---# erase
n 0 implies that there exists n # such that erase(n # ) = n 0 and n -# + n # .
Proof. By Theorem I.26 (bracket erasure preserves reduction outcomes) and Theorem I.28 (bracket erasure does not add
reduction outcomes), the theorem holds for erase brackets in place of erase. Note that the type annotation T in #x :T .e
never influences -# nb
reduction, as desired.
RR n 4851
76 Leifer, Peskine, Sewell, Wansbrough
J Coincidence of undyntime type checking and static type checking
We prove a theorem relating the undyntyime type checking in a single machine to static typechecking.
Definition J.1 (multiplelet context)
CL ::= multiplelet context
identity
moduleNU = M :S in CL module declaration
Definition J.2 (correct multiplelet context) A multiplelet context CL is correct in E if the following (recursive)
properties hold:
Case CL = : We require E # . ok.
Case CL = moduleNU = M :S in CL # : We require E # . M :S and CL # is correct in E , U :S .
We say CL is correct if CL is correct in nil.
Lemma J.3 (correct multiplelet contexts yield ok environments) If CL is correct in E then E , envofcl CL # . ok.
Proof. Induct on the length of CL.
Case CL = : By the definition of correctness, E # . ok, as desired.
Case CL = moduleNU = M :S in CL # : Then envofcl CL = U :S , envofcl CL # . By definition of correctness,
E , U :S # . ok and CL # is correct in E , U :S . By induction, E , U :S , envofcl CL # # . ok, i.e. E , envofcl CL # . ok
as desired.
Lemma J.4 (machine judgement characterisation of correct multiplelet contexts) CL is a correct multiplelet context
iff nil # . CL():UNIT.
Proof. We prove that CL is correct in E iff E # .
CL():UNIT. We induct on the length of CL.
Case CL = : If CL is correct in E , then E # . ok whence by (eT.unit) E # . ():UNIT. Conversely, assume E # .
():UNIT: by Lemma E.6 (environments have to be ok), we get E # . ok, i.e. CL is correct in E .
Case CL = moduleNU = M :S in CL # , forward direction: We have that E # .
M :S and CL # is correct in E , U :S .
By induction, E , U :S # .
CL # ():UNIT. By (mT.let), we get E # . moduleNU = M :S in CL # ():UNIT, as desired.
Case CL = moduleNU = M :S in CL # , backward direction: We have E # . CL():UNIT. By reversing (mT.let), we
get E # . M :S and E , U :S # . CL # ():UNIT. By induction, CL # is correct in E , U :S . By definition of correctness,
CL is correct in E .
Lemma J.5 (peeling outer let from a multiplelet context preserves correctness) Let CL be a multiplelet context.
1. If CL = moduleNU = [T , v . ]:[X :Eq(T ## ), T # ] in CL # is correct then #CL # is correct, where # =
{U .TYPE T ## , U .term v . }.
2. If CL = moduleNU = [T , v . ]:[X :Type, T # ] in CL # is correct then #CL # is correct where # =
{U .TYPE h, U .term [v . ] {X h}T #
h } and h = hash(N , [T , v . ]:[X :Type, T # ]).
Proof. By Lemma J.4 (machine judgement characterisation of correct multiplelet contexts), the hypotheses are equiv
alent to nil # . CL():UNIT and the conclusions are equivalent to nil # . #CL # ():UNIT. By the definition of machine
reduction CL() -# . #CL # () in both cases. By Theorem G.18 (type preservation for machine reduction), we get
nil # . #CL # ():UNIT, as desired.
Now we define a metafunction hashlistofcl which maps a multiplelet context to a list of the corresponding hashes:
INRIA
Global abstractionsafe marshalling with hash types 77
Definition J.6 (hash list of a multiplelet context)
hashlistofcl = ()
hashlistofcl (moduleNU = [T , v . ]:[X :Eq(T ## ), T # ] in CL) = hashlistofcl ({U .TYPE T ## , U .term v . }CL)
hashlistofcl (moduleNU = [T , v . ]:[X :Type, T # ] in CL) = h, hashlistofcl (#CL)
where h = hash(N , [T , v . ]:[X :Type, T # ]) and # = {U .TYPE h, U .term [v . ] {X h}T #
h }
Definition J.7 (no shadowing in a multiplelet context) There is no shadowing in the multiplelet context CL iff
hashlistofcl CL contains no repetitions.
Definition J.8 (environment corresponding to a multiplelet context)
envofcl = nil
envofcl (moduleNU = M :S in CL) = U :S , envofcl CL
Definition J.9 (substitution corresponding to a multiplelet context)
subofcl = id
subofcl (moduleNU = [T , v . ]:[X :Eq(T ## ), T # ] in CL) = (subofcl #CL )#
where # = {U .TYPE T ## , U .term v . }
subofcl (moduleNU = [T , v . ]:[X :Type, T # ] in CL) = (subofcl #CL )#
where # = {U .TYPE h, U .term [v . ] {X h}T #
h }
and h = hash(N , [T , v . ]:[X :Type, T # ])
Lemma J.10 (substituting through the partial type substitution associated to an environment) Let be any substitu
tion of the form {# 1 # 1 , ..., # j ## j } where (D#R)#domE = ? where D = fv # 1 #...#fv # j and R = fv # 1 #...#fv # j .
Then partenvsub E = partenvsub E .
Proof. Induct on the length of E . The only nontrivial cases are as follows:
Case E = E # , X :Eq(T ): Then partenvsub E = partenvsub E # {X#T}. Since domE # # domE , we can apply
induction to get that the last composition is equal to partenvsub E # {X#T}. Since X /
# D # R, we can further
rewrite the composition as partenvsub E # {X#T} = partenvsub (E # ,X :Eq(T)) , as desired.
Case E = E # , U :[X :Eq(T ), T # ]: similar to the previous.
Note that in the previous result we refer to fv # 0 , not just # 0 , since # 0 could be of the form U .TYPE or U .term.
Lemma J.11 (partial type substitution associated to an environment via left folding) Let partenvsub E be as in
Definition I.2 (partial type substitution associated to an environment). Then
partenvsub nil = id
partenvsub x :T ,E = partenvsub E
partenvsub X :Type,E = partenvsub E
partenvsub X :Eq(T),E = {X T}partenvsub E
partenvsub U :[X :Type,T # ],E = partenvsub E
partenvsub U :[X :Eq(T),T # ],E = {U .TYPE T}partenvsub E
Proof. Follows from the associativity of substitution composition.
Definition J.12 (partially ok environment) An environment E is partially ok if it has no repetition in the domain and
all decompositions E = E 0 , E 1 have the property ufv E 0 # domE 1 = ?.
Lemma J.13 (ok environments are partially ok) If E #hm ok then E is partially ok.
RR n 4851
78 Leifer, Peskine, Sewell, Wansbrough
Proof. If E #hm ok then E has no repetition in the domain by Lemma E.8 (ok environments have no repetition in the
domain). By Lemma E.7 (prefixes of ok environments are ok) and Lemma F.13 (ok environments have no unresolved free
variables), ufv E 0 = ?, whence ufv E 0 # domE 1 = ?.
Lemma J.14 (partial type substitution associated to an environment, alternative characterisation) Let E be a par
tially ok environment. Let partenvsub E be as in Definition I.2 (partial type substitution associated to an environment).
Let
# # nil = id
# #
x :T ,E = # # E
# #
X :Type,E = # # E
# # X :Eq(T),E = # #
{X#T}E {X#T}
# # U :[X :Type,T # ],E = # # E
# #
U :[X :Eq(T),T # ],E = # #
{U .TYPE T}E {U .TYPE T}
Then partenvsub E = # #
E .
Proof. Induct on the length of E . By Lemma J.11 (partial type substitution associated to an environment via left folding)
most cases are trivial, except for the following:
Case E = X :Eq(T ), E # : By Lemma J.11 (partial type substitution associated to an environment via left folding),
partenvsub E = {X T}partenvsub E # . Since E is partially ok, ({X } # fv T ) # domE # = ?. Thus by Lemma
J.10 (substituting through the partial type substitution associated to an environment), we have that the composition
is equal to partenvsub {X T}E # {X T}. Since {X T}E # is also partially ok, by induction the composition is
equal to # #
{X T}E # {X T} = # # X :Eq(T),E # , as desired.
Case E = E # , U :[X :Eq(T ), T # ]: similar.
Lemma J.15 (correspondence between open and hashed interpretation of type equivalence) Let CL be a multiplelet
context. Suppose
1. CL has no shadowing.
2. CL is correct.
3. None of the hashes in CL is in hashlistofcl CL.
4. For all i = 0, 1 we have that none of the hashes in T i is in hashlistofcl CL.
5. For all i = 0, 1 we have that envofcl CL # .
T i :Type.
Let partenvsub E be the substitution from Definition I.2 (partial type substitution associated to an environment). Then
partenvsub envofcl CL T 0 = partenvsub envofcl CL T 1 iff subofcl CLT 0 = subofcl CLT 1 .
Proof. We freely use Lemma J.14 (partial type substitution associated to an environment, alternative characterisation)
with Lemma J.13 (ok environments are partially ok) to reason about partenvsub.
We will prove some useful properties, then consider each of the mutual implications.
Prelude Prelude of the prelude Suppose that CL = moduleNU = M :S in CL # . Write M :S = [T , v . ]:[X :K , T # ].
Let # = {U .TYPE typepart (N , M :S ), U .term termpart (N , M :S )} and CL ## = #CL # .
By hypothesis 2 and Definition J.2 (correct multiplelet context), nil # .
M :S . By Lemma E.9 (free variables
of a judgement come from the environment), U /
# fv M #fv S . Whether S is concrete or abstract, this implies
that U /
# fv typepart (N , M :S ) and U /
# fv termpart (N , U :S ). Hence
{U .term termpart (N , M :S )}{U .TYPE typepart (N , M :S )}
= {U .TYPE typepart (N , M :S ), U .term termpart (N , M :S )}
= {U .TYPE typepart (N , M :S )}{U .term termpart (N , M :S )}.
INRIA
Global abstractionsafe marshalling with hash types 79
We will use this fact freely throughout the proof.
By Lemma E.21 (types do not contain free expression variables), {U .term termpart (N , M :S )}T i = T i ,
whence #T i = {U .TYPE typepart (N , M :S )}T i .
By Lemma E.23 (expression substitution in environment) applied to envofcl CL = (U :S , envofcl CL # )
(which is correct by hypothesis 2 and Lemma J.3 (correct multiplelet contexts yield ok environments)),
{U .term#termpart (N , M :S )}envofcl CL # = envofcl CL # , whence envofcl CL ## = #envofcl CL # =
{U .TYPE#typepart (N , M :S )}envofcl CL # .
We now show that the numbered hypotheses hold for CL ## in place of CL and #T i in place of T i .
Prelude: concrete case: K = Eq(T ## ) 1. By definition, hashlistofcl CL ## = hashlistofcl CL, therefore, CL ##
contains no shadowing since CL contains no shadowing (hypothesis 1).
2. Since CL is correct by hypothesis 2, by Lemma J.5 (peeling outer let from a multiplelet context preserves
correctness), CL ## is correct.
3. Each hash in CL ## in an element of the union of the hashes in T ## and v . and CL # , which is disjoint from
hashlistofcl CL = hashlistofcl CL ## by hypothesis 3.
4. Each hash in #T i = {U .TYPE#T ## }T i is an element of the union of the hashes in T ## and T i , which is
disjoint from hashlistofcl CL = hashlistofcl CL ## by hypotheses 3 (for T ## ) and 4.
5. By hypothesis 5, for i = 0, 1 we have U :[X :Eq(T ## ), T # ], envofcl CL # # .
T i :Type. By
Lemma F.32 (simplified module and type equality substitution for type world judgements),
{U .TYPE#T ## }(envofcl CL # ) # . {U .TYPE#T ## }T i :Type, i.e. envofcl CL ## # . #T i :Type.
Prelude: abstract case: K = Type Let h = hash(N , M :[X :Type, T # ]).
1. By definition, (h, hashlistofcl CL ## ) = hashlistofcl CL, therefore, CL ## contains no shadowing since CL
contains no shadowing (hypothesis 1).
(+) Also, since CL contains no shadowing, h is not in hashlistofcl CL ## (used below).
2. Since CL is correct by hypothesis 2, by Lemma J.5 (peeling outer let from a multiplelet context preserves
correctness), CL ## is correct.
3. Each hash in CL ## in an element of the union of {h} and the hashes in T ## and v . and CL # .
By (+), h does not appear in hashlistofcl CL ## . By hypothesis 3, the hashes in T ## and v . and CL # do not
appear in hashlistofcl CL, hence do not appear in hashlistofcl CL ## .
4. Each hash in #T i is an element of the union of {h} and the hashes in T ## and v . and T i , which is disjoint
from hashlistofcl CL ## , by (+) (for h) and hypothesis 3 (for T ## and v . ) and hypothesis 4 (for T i ).
5. By hypothesis 5, for i = 0, 1 we have envofcl CL # .
T i :Type, i.e. U :[X :Type, T # ], envofcl CL # # .
T i :Type. Given nil # . [T , v . ]:[X :Type, T # ], we can apply Lemma F.33 (type preservation by fully
carried out module substitution) to get #envofcl CL # # . #T i :Type, i.e. envofcl CL ## # . #T i :Type.
We also prove that partenvsub envofcl CL ## # = #partenvsub envofcl CL # .
Let D = {U } be the variables in the domain of #. Let R = fv h # fv ([v . ] {X h}T #
h ) be the free variables in
the range of #. By standard reasoning about free variables and substitutions, R = fv h #fv v . #(fv T # \{X }).
By hypothesis 2 and Definition J.2 (correct multiplelet context), nil # . [T , v . ]:[X :Type, T # ]. By Lemma
E.9 (free variables of a judgement come from the environment) and the definition of free variables, fv v . = ?
and fv T # # {X }. Also, given nil # . [T , v . ]:[X :Type, T # ], we have # h ok by (hmok.hash), whence by
Lemma E.9 (free variables of a judgement come from the environment) fv h = ?.
By Lemma J.3 (correct multiplelet contexts yield ok environments), envofcl CL # . ok. By Lemma E.8 (ok
environments have no repetition in the domain), U /
# domCL # .
In summary, (D # R) # dom (envofcl CL # ) = ?. By Lemma J.10 (substituting through the partial
type substitution associated to an environment), partenvsub envofcl CL ## # = partenvsub #envofcl CL # # =
#partenvsub envofcl CL # .
Direction partenvsub envofcl CL T 0 = partenvsub envofcl CL T 1 implies subofcl CLT 0 = subofcl CLT 1 : Induct on the
length of CL.
Case CL = : By hypothesis, T 0 = T 1 , as desired.
RR n 4851
80 Leifer, Peskine, Sewell, Wansbrough
Concrete case: CL = (moduleNU = [T , v . ]:[X :Eq(T ## ), T # ] in CL # ): We can write the hypothesis as
partenvsub {U .TYPE T ## }(envofcl CL # ) {U .TYPE T ## }T i is constant w.r.t. i # {0, 1}). By the prelude
to the prelude, envofcl CL ## = {U .TYPE T ## }(envofcl CL # ) and #T i = {U .TYPE T ## }T i , so
partenvsub (envofcl CL ## ) #T i is constant w.r.t. i # {0, 1}).
By the prelude (concrete case), we can apply induction. We get that subofcl CL ## #T i is constant w.r.t. i #
{0, 1}). By Definition J.9 (substitution corresponding to a multiplelet context), we have subofcl CLT i is
constant w.r.t. i # {0, 1}) as desired.
Abstract case: CL = (moduleNU = [T , v . ]:[X :Type, T # ] in CL # ): We can write the hypothesis as
partenvsub envofcl CL # T i is constant w.r.t. i # {0, 1}). Thus, #partenvsub envofcl CL # T i is constant w.r.t.
i # {0, 1}), where # = {U .TYPE h, U .term [v . ] {X h}T #
h } and h = hash(N , [T , v . ]:[X :Type, T # ]).
Let CL ## = #CL # . By the prelude (abstract case), #partenvsub envofcl CL # = partenvsub envofcl CL ## #. There
fore partenvsub envofcl CL ## #T i is constant w.r.t. i # {0, 1}).
Given the prelude (abstract case), we can apply induction. We get that subofcl (envofcl (CL ## )) #T i is constant
w.r.t. i # {0, 1}). Hence by definition, subofcl (envofcl CL)T i is constant w.r.t. i # {0, 1}), as desired.
Direction subofcl CLT 0 = subofcl CLT 1 implies partenvsub envofcl CL T 0 = partenvsub envofcl CL T 1 : Induct on the
length of CL.
Case CL = : By hypothesis, T 0 = T 1 , as desired.
Concrete case: CL = (moduleNU = [T , v . ]:[X :Eq(T ## ), T # ] in CL # ): Recall that CL ## = #CL # and # =
{U .TYPE T ## , U .term v . }. We have subofcl CL = subofcl CL ## #. Our hypothesis is therefore that
subofcl CL ## #T i is constant w.r.t. i # {0, 1}).
By the prelude (concrete case), we can apply induction. We get partenvsub envofcl CL ## #T i is constant w.r.t.
i # {0, 1}). By the prelude to the prelude, partenvsub
{U .TYPE T ## }envofcl CL # {U .TYPE T ## }T i is constant
w.r.t. i # {0, 1}).
By Lemma J.14 (partial type substitution associated to an environment, alternative characterisation),
partenvsub envofcl CL = partenvsub
{U .TYPE T ## }envofcl CL # {U .TYPE T ## }.
Thus partenvsub envofcl CL T i is constant w.r.t. i # {0, 1}) as desired.
Abstract case: CL = (moduleNU = [T , v . ]:[X :Type, T # ] in CL # ): By hypothesis, subofcl CL ## #T i is con
stant w.r.t. i # {0, 1}). By the prelude (abstract case), we can apply induction, getting
partenvsub envofcl CL ## #T i is constant w.r.t. i # {0, 1}).
By the prelude to the prelude, partenvsub
{U .TYPE T ## }envofcl CL # {U .TYPE T ## }T i is constant w.r.t. i #
{0, 1}).
By Lemma J.14 (partial type substitution associated to an environment, alternative characterisation),
partenvsub envofcl CL = partenvsub
{U .TYPE T ## }envofcl CL # {U .TYPE T ## }.
Thus partenvsub envofcl CL T i is constant w.r.t. i # {0, 1}) as desired.
Theorem J.16 (coincidence between undyntime and static type checking) Let CL be a multiplelet context. Suppose
. CL has no shadowing.
. CL is correct.
. None of the hashes in CL is in hashlistofcl CL.
. For all i = 0, 1 we have envofcl CL # . T i :Type and that none of the hashes in T i is in hashlistofcl CL.
Then envofcl CL # . T 0 == T 1 iff subofcl CLT 0 = subofcl CLT 1 .
In other words, dynamic type checking corresponds exactly to static type checking when two conditions hold: no two
module have the same hash (i.e. are of identical structure after their ancestors have been substituted in); the hashes in the
modules and in the types being compared are different from the hashes that will be generated by reduction (such as is the
case with a user program that contains no hashes at all).
INRIA
Global abstractionsafe marshalling with hash types 81
Proof. Immediate from Lemma J.15 (correspondence between open and hashed interpretation of type equivalence) and
Lemma I.6 (open interpretation of type equivalence).
Definition J.17 (list of external names in a multiplelet context) Define the list of external names in a multiplelet
context by structural induction:
enlistofcl = ()
enlistofcl (moduleNU = M :S in CL) = (N , enlistofcl CL)
Definition J.18 (external name shadowing) Let CL be a multiplelet context. We say that CL has external name
shadowing iff enlistofcl CL contains duplicates.
Lemma J.19 (nonshadowing through external names) If CL has no external name shadowing then CL has no shad
owing.
Proof. Trivial by induction on the length of CL.
Lemma J.20 (generalised machine judgement characterisation of correct multiplelet contexts) If nil # 0 CL.e:UNIT
then CL is correct.
Proof. By reversing (mT.let) once for each binding in CL, substituting envofcl CL # 0 ():UNIT for envofcl CL # 0 e:UNIT
and reapplying (mT.let)'s again, we get nil # 0 CL.():UNIT. By Lemma J.4 (machine judgement characterisation of
correct multiplelet contexts), CL is correct.
Corollary J.21 (coincidence between undyntime and static type checking with nonrepeated external names) Sup
pose that nil # 0 CL.e:UNIT, that CL contains no hashes, and that CL has no external name shadowing. Assume
that T 0 and T 1 contain no hashes and envofcl CL # . T i :Type for i = 0, 1. Then envofcl CL # . T 0 == T 1 iff
subofcl CLT 0 = subofcl CLT 1 .
Proof. By Lemma J.19 (nonshadowing through external names), CL has no shadowing. By Lemma J.20 (generalised
machine judgement characterisation of correct multiplelet contexts), CL is correct. Thus we can apply Theorem J.16
(coincidence between undyntime and static type checking).
RR n 4851
82 Leifer, Peskine, Sewell, Wansbrough
K Table of theorems and definitions
Th. 4.1 type preservation for compiletime, expression, and network reduction . . . . . . . . . . . . . . . 22
Th. 4.2 progress for compiletime reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Th. 4.3 progress for expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Th. 4.4 determinacy for compiletime and expression reduction . . . . . . . . . . . . . . . . . . . . . . . 22
Th. 4.5 decidability of type checking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Th. 4.6 erasure preserves reduction outcomes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Th. 4.7 coincidence between dynamic and static type checking . . . . . . . . . . . . . . . . . . . . . . . . 23
Def. E.1 smaller proof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Def. E.2 domain of an environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Lem. E.3 nonmembership in domain is interpreted trivially . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Lem. E.4 colours have to be ok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Lem. E.5 hashes have to be ok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Lem. E.6 environments have to be ok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Lem. E.7 prefixes of ok environments are ok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Lem. E.8 ok environments have no repetition in the domain . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Lem. E.9 free variables of a judgement come from the environment . . . . . . . . . . . . . . . . . . . . . . 36
Def. E.10 correctness judgement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Def. E.11 type world judgement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Def. E.12 hashes in something . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Def. E.13 partial order on colours . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Def. E.14 pvu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Def. E.15 alternate, informal definition of pvu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Lem. E.16 monotonicity of pvu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Def. E.17 substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Lem. E.18 stability of values by substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Lem. E.19 computing the pvu of a type world judgement . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Lem. E.20 connection between fv and fse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Lem. E.21 types do not contain free expression variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Lem. E.22 environments do not contain free expression variables . . . . . . . . . . . . . . . . . . . . . . . . 39
Lem. E.23 expression substitution in environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Lem. F.1 ``type of a machine'' judgements are not used to prove other coloured judgements . . . . . . . . . . 39
Lem. F.2 colour stripping judgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Lem. F.3 weakening . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Lem. F.4 merging environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Lem. F.5 combined weakening . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Lem. F.6 kinds are smaller than Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Lem. F.7 relating typeiskind and subkinding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Lem. F.8 components of modules are ok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Lem. F.9 types are ok provided their hashes are . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Lem. F.10 colour change preserves type okedness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Def. F.11 unresolved free variables of an environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Lem. F.12 computing unresolved free variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Lem. F.13 ok environments have no unresolved free variables . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Lem. F.14 type preservation by substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Lem. F.15 strengthening . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Def. F.16 visible typepart of a module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Def. F.17 visible termpart of a module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Def. F.18 set of equations used to type a module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Lem. F.19 reflexivity of kind equivalence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Lem. F.20 weakening kind to ok kind in the environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Lem. F.21 things have to be ok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Lem. F.22 weakening kind in the environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Lem. F.23 type preservation by guarded expression variable substitution . . . . . . . . . . . . . . . . . . . . 47
INRIA
Global abstractionsafe marshalling with hash types 83
Lem. F.24 type equivalence is a congruence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Lem. F.25 type substitution in equivalence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Lem. F.26 reversing subsignaturing judgement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Lem. F.27 reversing module value variable typing judgement . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Lem. F.28 obtaining module value variable typing judgement . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Lem. F.29 type preservation by module substitution in coloured judgements . . . . . . . . . . . . . . . . . . 49
Lem. F.30 type world judgements do not contain free expression variables . . . . . . . . . . . . . . . . . . . 51
Lem. F.31 type preservation by module substitution in coloured judgements for type world judgements . . . . 51
Lem. F.32 simplified module and type equality substitution for type world judgements . . . . . . . . . . . . . 51
Lem. F.33 type preservation by fully carried out module substitution . . . . . . . . . . . . . . . . . . . . . . 51
Lem. G.1 shortening typing proof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Lem. G.2 reversing typing proof through a context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Lem. G.3 transitivity of kind equivalence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Lem. G.4 discreteness of subkinding below Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Def. G.5 bare bones environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Def. G.6 purely abstract environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Lem. G.7 signature rewriting in a type world judgement . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Lem. G.8 type substitution in a purely abstract environment . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Lem. G.9 equality kinding in an uncontributing environment . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Lem. G.10 equivalence of small types in an uncontributing environment . . . . . . . . . . . . . . . . . . . . . 54
Lem. G.11 type decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Lem. G.12 decomposition of type equivalence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Lem. G.13 structural dependence of values on their types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Lem. G.14 triviality of type equivalence in a trivial environment . . . . . . . . . . . . . . . . . . . . . . . . . 57
Th. G.15 type preservation for expression reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Lem. G.16 type preservation for network structural congruence . . . . . . . . . . . . . . . . . . . . . . . . . 59
Cor. G.17 type preservation for network reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Th. G.18 type preservation for machine reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Def. H.1 waiting for communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Def. H.2 dormant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Lem. H.3 dormancy in context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Lem. H.4 reduction in context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Def. H.5 legitimately stuck expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Th. H.6 progress of expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Cor. H.7 progress of networks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Th. H.8 progress of machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Th. H.9 determinism of machine reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Lem. H.10 values do not reduce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Th. H.11 determinism of expression reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Dis. H.12 strength of determinism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Def. I.1 revelation of the implementation of a hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Def. I.2 partial type substitution associated to an environment . . . . . . . . . . . . . . . . . . . . . . . . 65
Lem. I.3 a purely abstract suffix does not change the substitution . . . . . . . . . . . . . . . . . . . . . . . 66
Lem. I.4 stability of types through revelation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Lem. I.5 distinction of fresh type variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Lem. I.6 open interpretation of type equivalence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Th. I.7 semantic interpretation of type world judgements . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Lem. I.8 uniqueness of expression typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Def. I.9 reconstructed type of an expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Lem. I.10 simplicity of the reconstructed type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Lem. I.11 assurance of correctness of the reconstructed type . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Lem. I.12 validity of the reconstructed type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Cor. I.13 deciding expression typing through type reconstruction . . . . . . . . . . . . . . . . . . . . . . . 72
Th. I.14 decidability of type checking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Def. I.15 user source program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
RR n 4851
84 Leifer, Peskine, Sewell, Wansbrough
Dis. I.16 decidability of type checking for user programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Def. I.17 bracket elimination subsystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Lem. I.18 determinism of bracket elimination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Lem. I.19 termination of bracket elimination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Def. I.20 bracket erasure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Def. I.21 colourless proof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Def. I.22 bracketless expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Def. I.23 bracketless reductions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Lem. I.24 progress and determinism of bracketless expression reduction . . . . . . . . . . . . . . . . . . . . 74
Th. I.25 bracket erasure preserves expression reduction outcomes . . . . . . . . . . . . . . . . . . . . . . . 74
Th. I.26 bracket erasure preserves reduction outcomes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Th. I.27 bracket erasure does not add expression reduction outcomes . . . . . . . . . . . . . . . . . . . . . 75
Th. I.28 bracket erasure does not add reduction outcomes . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Def. I.29 type erasure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Th. I.30 type erasure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Def. J.1 multiplelet context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Def. J.2 correct multiplelet context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Lem. J.3 correct multiplelet contexts yield ok environments . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Lem. J.4 machine judgement characterisation of correct multiplelet contexts . . . . . . . . . . . . . . . . . 76
Lem. J.5 peeling outer let from a multiplelet context preserves correctness . . . . . . . . . . . . . . . . . . 76
Def. J.6 hash list of a multiplelet context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Def. J.7 no shadowing in a multiplelet context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Def. J.8 environment corresponding to a multiplelet context . . . . . . . . . . . . . . . . . . . . . . . . . 77
Def. J.9 substitution corresponding to a multiplelet context . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Lem. J.10 substituting through the partial type substitution associated to an environment . . . . . . . . . . . 77
Lem. J.11 partial type substitution associated to an environment via left folding . . . . . . . . . . . . . . . . 77
Def. J.12 partially ok environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Lem. J.13 ok environments are partially ok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Lem. J.14 partial type substitution associated to an environment, alternative characterisation . . . . . . . . . 78
Lem. J.15 correspondence between open and hashed interpretation of type equivalence . . . . . . . . . . . . 78
Th. J.16 coincidence between undyntime and static type checking . . . . . . . . . . . . . . . . . . . . . . 80
Def. J.17 list of external names in a multiplelet context . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Def. J.18 external name shadowing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Lem. J.19 nonshadowing through external names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Lem. J.20 generalised machine judgement characterisation of correct multiplelet contexts . . . . . . . . . . 81
Cor. J.21 coincidence between undyntime and static type checking with nonrepeated external names . . . . 81
INRIA
Global abstractionsafe marshalling with hash types 85
References
[ACPP91] Mart n Abadi, Luca Cardelli, Benjamin Pierce, and Gordon Plotkin. Dynamic typing in a statically typed
language. ACM TOPLAS, 13(2):237--268, 1991.
[ACPR95] Mart n Abadi, Luca Cardelli, Benjamin Pierce, and Didier R emy. Dynamic typing in polymorphic languages.
J. Functional Programming, 5(1):111--130, 1995.
[Ali03] The Alice Project. Alice manual: Pickling. http://www.ps.unisb.de/alice/manual/pickling.
html, 2003.
[B + 94] Andrei Z. Broder et al. Fingerprint.i3. http://research.compaq.com/SRC/m3sources/html/
fingerprint/src/Fingerprint.i3.html, 1994.
[BHS + 03] Gavin Bierman, Michael Hicks, Peter Sewell, Gareth Stoyle, and Keith Wansbrough. Dynamic rebinding
for marshalling and update, with destructtime #. In Proc. ICFP 2003, 2003. Full version available as
UCAMCLTR568. http://www.cl.cam.ac.uk/~pes20/.
[BNOW95] Andrew Birrell, Greg Nelson, Susan Owicki, and Edward Wobber. Network objects. Software -- Practice &
Experience, 25(S4):87--130, 1995. Available in slightly different form as SRC115 revised.
[CL90] Luca Cardelli and Xavier Leroy. Abstract types and the dot notation. Technical Report 56, DEC SRC, March
10 1990.
[DCH03] Derek Dreyer, Karl Crary, and Robert Harper. A type system for higherorder modules. In Proc. 30th POPL,
New Orleans, pages 236--249, 2003.
[Dug02] Dominic Duggan. Typesafe linking with recursive DLLs and shared libraries. ACM TOPLAS, 24(6):711--
804, 2002.
[FW00] Jun Furuse and Pierre Weis. Entr ees/sorties de valeurs en Caml. In J. Francophones des Langages Applicatifs,
2000.
[GMZ00] Dan Grossman, Greg Morrisett, and Steve Zdancewic. Syntactic type abstraction. ACM TOPLAS,
22(6):1037--1080, 2000.
[HL94] Robert Harper and Mark Lillibridge. A typetheoretic approach to higherorder modules with sharing. In
Proc. 21st POPL, 1994.
[HM95] Robert Harper and Greg Morrisett. Compiling polymorphism using intensional type analysis. In Proc. 22nd
POPL, pages 130--141, 1995.
[HWC00] Michael Hicks, Stephanie Weirich, and Karl Crary. Safe and flexible dynamic linking of native code. In
Proc. 3rd Workshop on Types in Compilation, pages 147--176, 2000.
[JoC] JoCaml. http://pauillac.inria.fr/jocaml/.
[Kna95] F. Knabe. Language Support for Mobile Agents. PhD thesis, Carnegie Mellon University, December 1995.
[Ler94] Xavier Leroy. Manifest types, modules, and separate compilation. In Proc. 21st POPL, pages 109--122,
1994.
[Ler95] Xavier Leroy. Applicative functors and fully transparent higherorder modules. In Proc. 22nd POPL, pages
142--153, 1995.
[LPSW03] James J. Leifer, Gilles Peskine, Peter Sewell, and Keith Wansbrough. Global abstractionsafe marshalling
with hash types. In Proc. 8th ICFP, 2003. Available from http://pauillac.inria.fr/~leifer/
research.html.
[Mac84] David MacQueen. Modules for Standard ML. In Proc. 1984 ACM Symp. LISP and Func. Prog., pages
198--207, 1984.
RR n 4851
86 Leifer, Peskine, Sewell, Wansbrough
[Mic01] Microsoft Corporation. .NET Framework developer's guide: Serializing objects. http://msdn.
microsoft.com/library/enus/cpguide/html/cpovrserializingobjects.asp, 2001.
[MP88] John C. Mitchell and Gordon D. Plotkin. Abstract types have existential type. ACM TOPLAS, 10(3):470--502,
July 1988.
[MTH90] R. Milner, M. Tofte, and R. Harper. The Definition of Standard ML. MIT Press, 1990.
[OCa] Objective Caml. http://caml.inria.fr.
[PS00] Benjamin Pierce and Eijiro Sumii. Relating cryptography and polymorphism. http://web.yl.is.s.
utokyo.ac.jp/~sumii/pub/, July 16 2000. Substantially revised version to appear in J. Comp. Security.
[Rob96] M. J. B. Robshaw. On recent results for MD2, MD4 and MD5. RSA Laboratories' Bulletin, (4), November
12 1996.
[Ros02] Andreas Rossberg. Dynamic opacity for abstract types. Technical report, Programming Systems Lab, Uni
versit at des Saarlandes, 2002. http://www.ps.unisb.de/Papers/abstracts/opaque.html.
[Sew01] Peter Sewell. Modules, abstract types, and distributed versioning. In Proc. 28th POPL, pages 236--247,
2001.
[SH00] Christopher A. Stone and Robert Harper. Deciding type equivalence in a language with singleton kinds. In
Proc. 27th POPL, pages 214--227, 2000.
[Sun02] Sun Microsystems. Java object serialization specification 1.4.4. http://java.sun.com/j2se/1.4.1/
docs/guide/serialization/, 2002.
[SWP99] Peter Sewell, Pawel/ T. Wojciechowski, and Benjamin C. Pierce. Locationindependent communication for
mobile agents: a twolevel architecture. In Internet Programming Languages, LNCS 1686, pages 1--31, 1999.
[TLK96] Bent Thomsen, Lone Leth, and TsungMin Kuo. A Facile tutorial. In CONCUR'96, LNCS 1119, pages
278--298, 1996.
[Wei00] Stephanie Weirich. Typesafe cast: Functional pearl. In Proc. ICFP, Montreal, pages 58--67, 2000.
[Wei02] Stephanie Weirich. Higherorder intensional type analysis. In Proc. 11th ESOP, LNCS 2305, Grenoble,
France, 2002.
[ZGM99] Steve Zdancewic, Dan Grossman, and Greg Morrisett. Principals in programming languages: A syntactic
proof technique. In Proc. ICFP, Paris, pages 197--207, Sep 1999.
main body: $Revision: 1.211 $ $Date:#2003/06/25#14:47:25#$
appendices: $Revision:#1.2#$ $Date: 2003/06/25 09:42:26 $
INRIA
Unit de recherche INRIA Rocquencourt
Domaine de Voluceau Rocquencourt BP 105 78153 Le Chesnay Cedex (France)
Unit de recherche INRIA Lorraine : LORIA, Technople de NancyBrabois Campus scientifique
615, rue du Jardin Botanique BP 101 54602 VillerslsNancy Cedex (France)
Unit de recherche INRIA Rennes : IRISA, Campus universitaire de Beaulieu 35042 Rennes Cedex (France)
Unit de recherche INRIA RhneAlpes : 655, avenue de l'Europe 38330 MontbonnotStMartin (France)
Unit de recherche INRIA Sophia Antipolis : 2004, route des Lucioles BP 93 06902 Sophia Antipolis Cedex (France)
diteur
INRIA Domaine de Voluceau Rocquencourt, BP 105 78153 Le Chesnay Cedex (France)
http://www.inria.fr
ISSN 02496399