conforms.abs
notation syntax rsyntax rels runtime rstatics conforms ;
import syntax rsyntax statics1 runtime0 wf wfenv rstatics1 ;
reserve C for :id;
reserve FT0 for :ftyenv
reserve FT for :ftyenv
reserve id for :id;
reserve heap for :heap;
reserve frames for :frames;
reserve s for :frames × heap;
reserve prog for :rprog;
reserve mbody for :rmethodbody;
reserve addr for :int;
reserve val for :rval;
// --------------------------------------------------------------------------
// Weak conformance and Value conformance.
//
// This is not part of the runtime model, but is used to correlate
// the static and runtime models.
// --------------------------------------------------------------------------
def wconforms_to
((TE,heap) |- val wconforms_to val_ty) <=>
(?val_ty'. (TE,heap) |- val rval_hastype val_ty' &
TE |- val_ty' varty_widens_to val_ty) ;
def fldvals_wconform_to
((TE,heap) |- fldvals fldvals_wconform_to C) <=>
(!idx vt'. FDecs(TE,C)(idx,vt') -->
(?val. PLOOKUP(fldvals)(idx) = SOME(val) &
(TE,heap) |- val wconforms_to vt') )
def els_wconform_to
((TE,heap) |- vec els_wconform_to vt) <=>
(!j. j < LEN(vec) -->
(TE,heap) |- EL(j)(vec) wconforms_to vt);
lfp val_conforms_to
Prim
(TE,heap) |- RPrim(pval) wconforms_to vt
// ----------------------------------------------------------
(TE,heap) |- RPrim(pval) val_conforms_to vt
Null
(TE,heap) |- RAddr(NONE) wconforms_to vt
// ----------------------------------------------------------
(TE,heap) |- RAddr(NONE) val_conforms_to vt
Object
(TE,heap) |- RAddr(SOME(addr)) wconforms_to vt &
FPLOOKUP(heap)(addr) = SOME(OBJECT(fldvals,C)) &
(TE,heap) |- fldvals fldvals_wconform_to C
// ----------------------------------------------------------
(TE,heap) |- RAddr(SOME(addr)) val_conforms_to vt
Array
(TE,heap) |- RAddr(SOME(addr)) wconforms_to vt &
FPLOOKUP(heap)(addr) = SOME(ARRAY(vt',vec)) &
(TE,heap) |- vec els_wconform_to vt'
// ----------------------------------------------------------
(TE,heap) |- RAddr(SOME(addr)) val_conforms_to vt
thm weak-from-val
(TE,heap) |- val val_conforms_to vt -->
(TE,heap) |- val wconforms_to vt
thm typing-from-val
(TE,heap) |- val val_conforms_to vt -->
?vt'. (TE,heap) |- val rval_hastype vt' & TE |- vt' varty_widens_to vt
thm wconforms-trans
TE wf_tyenv &
(TE,heap) |- val wconforms_to val_ty &
TE |- val_ty varty_widens_to val_ty'
--> (TE,heap) |- val wconforms_to val_ty';
thm weak-from-typing
TE wf_tyenv &
(TE,heap) |- val rval_hastype val_ty
--> (TE,heap) |- val wconforms_to val_ty;
thm val_conforms-trans
TE wf_tyenv &
(TE,heap) |- val val_conforms_to val_ty &
TE |- val_ty varty_widens_to val_ty'
--> (TE,heap) |- val val_conforms_to val_ty';
thm exp_typing-from-weak
TE wf_tyenv &
(TE,heap) |- val wconforms_to valty -->
?expty. (TE,FT,heap) |- RValue(val) rexp_hastype expty &
TE |- expty expty_widens_to SOME(valty)
// Narrowing/enlarging between frames. There is aconflict of
// terminology here. One heap conforms, i.e. is bigger (because more elements
// are defined), or narrower (because where the first is defined the
// second is defined and has narrrower type) than another.
//
// This relation could be defined over a set of active addresses to allow
// a garbage collection rule. At the moment it constrains heaps to be
// monotonically increasing in size
def heap_leq
TE |- heap0 heap_leq heap1 <=>
!addr. addr ::: FPDOM(heap0) -->
!val_ty. (TE,heap0) |- RAddr(SOME(addr)) val_conforms_to val_ty
--> ((TE,heap1) |- RAddr(SOME(addr)) val_conforms_to val_ty) ;
thm heap_leq-refl [simp,auto,prolog] TE |- heap heap_leq heap
// Heap conformance. No heap typing is needed. Again could be
// restricted to a particular set of addresses to allow garbage collection.
def addr_conforms
(TE,heap) |- addr addr_conforms <=>
(!fldvals C.
FPLOOKUP(heap)(addr) = SOME(OBJECT(fldvals,C)) -->
((TE,heap) |- RAddr(SOME(addr)) val_conforms_to VT(Class(C),0)) ) &
(!st dim vec.
FPLOOKUP(heap)(addr) = SOME(ARRAY(VT(st,dim),vec)) -->
((TE,heap) |- RAddr(SOME(addr)) val_conforms_to VT(st,dim+1)) );
def heap_conforms
TE |- heap heap_conforms <=>
!addr. addr ::: FPDOM(heap) --> ((TE,heap) |- addr addr_conforms)
// Heap conformance is enough to give us typing --> value conformance
thm conforms-from-typing
TE wf_tyenv &
TE |- heap heap_conforms &
(TE,heap) |- val rval_hastype val_ty
--> (TE,heap) |- val val_conforms_to val_ty;
// Facts we derive from heap conformance
// this says that if an object conforms, then all its fields weakly conform.
thm object-fields-conform
TE |- heap heap_conforms &
FPLOOKUP(heap)(addr) = SOME(OBJECT(fldvals,C)) &
((C',f),varty) :: FDecs(TE,C) &
PLOOKUP(fldvals)(C',f) = SOME(val)
--> (TE,heap) |- val wconforms_to varty;
// this says that if an array conforms, then all its elements weakly conform.
thm array-elements-conform
TE |- heap heap_conforms &
FPLOOKUP(heap)(addr) = SOME(ARRAY(vt,vec)) &
j < LEN(vec) -->
(TE,heap) |- EL(j)(vec) wconforms_to vt
// Define narrowing/enlarging between frame typings.
def ftyenv_leq
FT0 ftyenv_leq FT1 <=>
LEN(FT0) <= LEN(FT1) & (!j. j < LEN(FT0) --> EL(j)(FT0) = EL(j)(FT1))
// a simple one:
thm ftyenv_leq-refl [simp,auto,prolog]
FT ftyenv_leq FT;
// Lemmas: as heaps and frame typings get narrower, typing judgemsnts
// get narrower.
thm lemma">val-mono-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
TE |- heap0 heap_leq heap1 &
(TE,heap0) |- val rval_hastype val_ty
--> ?val_ty'. (TE,heap1) |- val rval_hastype val_ty' &
TE |- val_ty' varty_widens_to val_ty
thm lemma">exp-mono-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
FT0 ftyenv_leq FT1 &
TE |- heap0 heap_leq heap1 &
(TE,FT0,heap0) |- exp rexp_hastype exp_ty
--> ?exp_ty'. (TE,FT1,heap1) |- exp rexp_hastype exp_ty' &
TE |- exp_ty' expty_widens_to exp_ty
thm lemma">var-mono-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
FT0 ftyenv_leq FT1 &
TE |- heap0 heap_leq heap1 &
(TE,FT0,heap0) |- var rvar_hastype var_ty
--> ?var_ty'. (TE,FT1,heap1) |- var rvar_hastype var_ty' &
TE |- var_ty' varty_widens_to var_ty
thm lemma">stmt-mono-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
FT0 ftyenv_leq FT1 &
TE |- heap0 heap_leq heap1 &
(TE,FT0,heap0) |- stmt rstmt_hastype
--> (TE,FT1,heap1) |- stmt rstmt_hastype
// Stack vars and Fields are not just monotonic up to widening - their types
// remain identical
thm StackVar-mono
FT0 ftyenv_leq FT1 &
TE |- heap0 heap_conforms &
TE |- heap0 heap_leq heap1 &
(TE,FT0,heap0) |- RStackVar(fidx,id) rvar_hastype var_ty
--> (TE,FT1,heap1) |- RStackVar(fidx,id) rvar_hastype var_ty
thm Field-mono
FT0 ftyenv_leq FT1 &
TE |- heap0 heap_conforms &
TE |- heap0 heap_leq heap1 &
(TE,FT0,heap0) |- RField(obj,C,fld) rvar_hastype var_ty
--> (TE,FT1,heap1) |- RField(obj,C,fld) rvar_hastype var_ty
thm lemma">wconforms-mono-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
TE |- heap0 heap_leq heap1 &
(TE,heap0) |- val wconforms_to val_ty
--> (TE,heap1) |- val wconforms_to val_ty
thm lemma">val_conforms-mono-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
TE |- heap0 heap_leq heap1 &
(TE,heap0) |- val val_conforms_to val_ty
--> (TE,heap1) |- val val_conforms_to val_ty
// Frames conformance - connects a frame typing and a state.
def frames_conform_to
((TE,heap) |- frames frames_conform_to FT) <=>
LEN(frames) = LEN(FT) &
!fidx FS. fidx < LEN(frames) & FS = EL(fidx)(FT) -->
!id vt. id :: PDOM(FS) & PLOOKUP(FS)(id) = SOME(vt) -->
(?val. sGetStackVar(frames,fidx,id) = SOME(val) &
(TE,heap) |- val val_conforms_to vt) ;
thm lemma">frames_conform-mono-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
TE |- heap0 heap_leq heap1 &
(TE,heap0) |- frames frames_conform_to FT
--> (TE,heap1) |- frames frames_conform_to FT
// Various operations on the state produce a narrower, conformant state.
// Allocation first.
thm initial-values-conform
TE |- vt wf_vartype
--> (TE,heap) |- initial(vt) wconforms_to vt
// two lemmas about transformations that just add new cells (allocations).
thm lemma">wconforms_preserved-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
heap0 FPSUBFUN heap1 &
(TE,heap0) |- val wconforms_to vt
--> (TE,heap1) |- val wconforms_to vt;
thm lemma">heap_leq-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
heap0 FPSUBFUN heap1
--> TE |- heap0 heap_leq heap1;
thm lemma">alloc-conforms-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
heap0 FPSUBFUN heap1 &
(!addr. addr ::: FPDOM(heap1) & ~(addr ::: FPDOM(heap0)) --> (TE,heap1) |- addr addr_conforms)
--> TE |- heap1 heap_conforms;
// Allocation preserves conformance, if all the conditions are right.
thm lemma">object-alloc-conforms-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
(!fld vt. (fld,vt) :: FDecs(TE,C) --> TE |- vt wf_vartype) &
flds = PGRAPH {fspec | FDecs(TE,C)(fspec)} &
fldvals = initial o_p flds &
heapobj = OBJECT(fldvals,C) &
sAlloc(heap0,heapobj) = (heap1,addr1)
--> TE |- heap1 heap_conforms &
TE |- heap0 heap_leq heap1
// heap1 is conformant because the object rule for conformance for
// the new address is satisfied. This is because every field in
// FDecs(G,C) is given a weakly conforant value by initial.
//
// (But how do we know flds is related to FDecs? The rstatics typing
// rules for RNewClass must refer to FDecs!)
//
// Note we need the lemmas that FDecs produces a PGRAPH for
// a wellformed environment.
// similar, but much lengthier
thm lemma">array-alloc-conforms-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
(val1,heap1) = val_alloc(heap0,st,dimns,ext)
--> TE |- heap1 heap_conforms &
TE |- heap0 heap_leq heap1
// this is a simple corollary of the general result
thm lemma">array-alloc-types-lemma
TE wf_tyenv &
TE |- heap1 heap_conforms &
(val1,heap1) = val_alloc(heap0,st,dimns,ext) &
dim = LEN(dimns)+ext
--> (TE,FT0,heap1) |- RValue(val1) rexp_hastype SOME(VT(st,dim))
// Assignment to local variables preserves conformance,
// if all the conditions are right.
//
// Usable as a rewrite if local variables are instantiated explicitly
//
// NOTES ON PROOF:
// the hard part is to establish that heap1 conforms to heap0
// have (FT1,heap1) |- val val_conforms_to var0_ty // by defn. of conformance
// follows because val/exp0 has a type that widens to var0_ty,
// and because TE |- heap0 conforms to FT (this establishes conformance for
// all the addresses that val/exp0 may contain)
//
// Note if we are only using weak conformance the argument would falter
// here.
thm lemma">stack-assign-conforms-lemma
TE wf_tyenv &
(TE,heap) |- frames0 frames_conform_to FT &
fidx < LEN(FT) &
PLOOKUP(EL(fidx)(FT))(id) = SOME(vty) &
(TE,FT,heap) |- RValue(val) rexp_hastype SOME(ety) &
TE |- ety varty_widens_to vty &
frames1 = sSetStackVar(frames0,fidx,id,val)
--> (TE,heap) |- frames1 frames_conform_to FT
// usable as a rewrite if some variables are instantiated explicitly
thm lemma">field-assign-conforms-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
FPLOOKUP(heap0)(addr) = SOME(OBJECT(fldvals,C')) &
((C,fld),vty) :: FDecs(TE,C') &
(TE,heap0) |- val rval_hastype ety &
TE |- ety varty_widens_to vty &
heap1 = sFieldSet(heap0,addr,C,fld,val)
--> TE |- heap1 heap_conforms &
TE |- heap0 heap_leq heap1
thm typecheck-correct
TE wf_tyenv &
(TE,heap0) |- val rval_hastype ety &
typecheck((TE,heap0),val,vt)
--> (TE,heap0) |- val wconforms_to vt
// usable as a rewrite if some variables are instantiated explicitly
thm lemma">array-assign-conforms-lemma
TE wf_tyenv &
TE |- heap0 heap_conforms &
FPLOOKUP(heap0)(addr) = SOME(ARRAY(arrty,vec)) &
idx < LEN(vec) &
(TE,heap0) |- val rval_hastype ety &
typecheck((TE,heap0),val,arrty) &
heap1 = heap0 <++ (addr,ARRAY(arrty,REPLACE(idx)(vec)(val)))
--> TE |- heap1 heap_conforms &
TE |- heap0 heap_leq heap1
// various relations must be undisturbed by a move to a conformant environment
// i.e. monotonic
//
// Note in the long run conformance (increasing the size of an environment) may cause
// much bigger changes, esp. dynamic linking introducing more classes. These lemmas
// become more complex in that case.
// NOTE: now not needed with static typing environment
// (will be needed with dynamic linking)
//thm lemma">wf_tyenv-mono-lemma
// TE0 wf_tyenv &
// TE0 tyenv_leq TE1 --> TE1 wf_tyenv
//thm lemma">wf_simptype-mono-lemma
// TE0 wf_tyenv &
// TE0 tyenv_leq TE1 &
// TE0 |- st wf_simptype -->
// TE1 |- st wf_simptype;
//thm lemma">varty_widens_to-mono-lemma
// TE0 wf_tyenv &
// TE0 tyenv_leq TE1 &
// TE0 |- vt1 varty_widens_to vt2 -->
// TE1 |- vt1 varty_widens_to vt2;
//thm lemma">subclass_of-mono-lemma
// TE0 wf_tyenv &
// TE0 tyenv_leq TE1 &
// TE0 |- C subclass_of C' -->
// TE1 |- C subclass_of C'
//thm lemma">Cdec-mono-lemma
// TE0 wf_tyenv &
// TE0 tyenv_leq TE1 &
// Cdec(TE0,C) = SOME(cdec) -->
// Cdec(TE1,C) = SOME(cdec)
//thm lemma">MSigsC-mono-lemma
// TE0 wf_tyenv &
// TE0 tyenv_leq TE1 &
// MSigsC(TE0,C)(x) -->
// MSigsC(TE1,C)(x)
//thm lemma">MSigsI-mono-lemma
// TE0 wf_tyenv &
// TE0 tyenv_leq TE1 &
// MSigsI(TE0,C)(x) -->
// MSigsI(TE1,C)(x)