| |
wf.abs

// This file defines environments and the well-formedness
// constraints upon them, and other interesting things
// like searching through class hierarchies for nearest
// fields/methods.

notation syntax rels ;
import syntax ;

// The environment.
//
// Contains both the subclass and interface hierachies
// and variable type declarations. Also contains the type definitions
// of all variables and methods of a class and its interface.
// Declarations consist of class declarations, interface declarations
// and identifier declarations.

datatype MT:varType list × varType option -> methType;
datatype CLASS: (id option ×
id set ×
(id -> varType option) ×
(id × methType) set) -> classDecl
datatype INTERFACE:id set ×
(id × methType) set -> interfaceDecl
//type tyenv == (id,classDecl) pfun ×
// (id,interfaceDecl) pfun;
reserve TE for :tyenv;
reserve C for :id;
reserve i for :id;
def Cdec Cdec((CE,IE):tyenv,C) = PLOOKUP(CE)(C)
def Idec Idec((CE,IE):tyenv,i) = PLOOKUP(IE)(i)

// This relation is useful for characterising the inductive property
// of interfaces induced by the well-formedness conditions
// for environments. It says that an interface is wellfounded
// if it has no superinterfaces or if some superinterface is
// well founded. The equivalent for classes is to say that
// the class is a subclass of Object.

lfp wellfounded_interface
Base [ ]
Idec(TE,i) = SOME(INTERFACE(EMPTY,x1))
// ---------------------------------------------
TE |- i wellfounded_interface
Step [ ]
Idec(TE,i) = SOME(INTERFACE(Is,x1)) &
i' :: Is &
TE |- i' wellfounded_interface
// ---------------------------------------------
TE |- i wellfounded_interface

// Well-formed types - not really used

def Args Args(MT(AT,rt)) = AT
def Res Res(MT(AT,rt)) = rt
lfp wf_simptype
Class [simp,prolog,auto]
// ------------------------------------
TE |- (Class(C)) wf_simptype
Interface [simp,prolog,auto]
// ------------------------------------
TE |- (Interface(i)) wf_simptype
Prim [simp,prolog,auto]
// ------------------------------------
TE |- (PrimT(p)) wf_simptype
def wf_vartype
TE |- VT(st,n) wf_vartype <=> TE |- st wf_simptype
def wf_exptype
TE |- expty wf_exptype <=>
(!vt. expty = SOME(vt) --> TE |- vt wf_vartype);
lfp wf_argtype
argtype [prolog,auto]
(!j. j < LEN(AT) --> TE |- EL(j)(AT) wf_vartype)
// -----------------------------------------
TE |- AT wf_argtype
lfp wf_methtype
methtype
TE |- AT wf_argtype &
(!x. R = SOME(x) --> TE |- x wf_vartype)
// ----------------------------------------
TE |- (MT(AT,R)) wf_methtype

// The subclass relationship.
//
// nb. executable version does not terminate for circular class
// structures.

lfp subclass_of
Refl [simp,auto,prolog]
// ------------------------------------
TE |- C subclass_of C
Step
Cdec(TE,C) = SOME(CLASS(SOME(Csup),x1,x2,x3)) & TE |- Csup subclass_of C''
// -----------------------------------------------------------
TE |- C subclass_of C''

// The implements relationship

lfp implements
Step [simp,auto]
Cdec(TE,C) = SOME(CLASS(x1,Is,x2,x3)) & i :: Is
// -------------------------------------------------------
TE |- C implements i

// The subinterface relationship
//
// nb. executable version does not terminate for circular class
// structures.

lfp subinterface_of
Refl [simp,prolog,auto]
// ------------------------------------
TE |- i subinterface_of i
Step [ ]
Idec(TE,i) = SOME(INTERFACE(Is,x1)) &
i' :: Is &
TE |- i' subinterface_of i''
// ---------------------------------------------
TE |- i subinterface_of i''
thm subclass-trans
TE |- C0 subclass_of C1 & TE |- C1 subclass_of C2
--> TE |- C0 subclass_of C2
thm subinterface-trans
TE |- C0 subinterface_of C1 & TE |- C1 subinterface_of C2
--> TE |- C0 subinterface_of C2
thm wellfounded_interface-trans
TE |- C0 subinterface_of C1 & TE |- C1 wellfounded_interface
--> TE |- C0 wellfounded_interface

// Widening/Narrowing
//
// The purpose of the wellfounded_interface and subclass_of Object
// constraints is to ensure that any narrower type remains
// firmly grounded in the environment (if the wider type
// is). This ensures that transitivity holds when we complete the
// confluent paths down our graph (e.g. C <= I <= Object gives
// C <= Object, and i1 <= i2 <= Object gives i1 <= Object).
//
// This was nasty to figure out...

lfp simpty_widens_to
Prim [prolog,auto,simp]
// ------------------------------------
TE |- PrimT(pt) simpty_widens_to PrimT(pt)
ClassToClass [prolog,auto,simp]
TE |- C subclass_of C'
// -------------------------------------------------
TE |- Class(C) simpty_widens_to Class(C')
InterfaceToInterface [prolog,auto,simp]
TE |- i subinterface_of i'
// ---------------------------------------------------
TE |- Interface(i) simpty_widens_to Interface(i')
InterfaceToObject [prolog,auto,simp]
TE |- i wellfounded_interface
// -----------------------------------------------------
TE |- Interface(i) simpty_widens_to Class(Object)
ClassToInterface [prolog,auto]
TE |- C subclass_of Object &
TE |- C subclass_of C' &
TE |- C' implements i &
TE |- i subinterface_of i'
// ---------------------------------------------------------------
TE |- Class(C) simpty_widens_to Interface(i')
lfp varty_widens_to
ArrayToObject [prolog,auto,simp]
0 < n
// --------------------------------------
TE |- VT(st,n) varty_widens_to VT(Class Object,0)
Simple [prolog,auto,simp]
TE |- st simpty_widens_to st'
// ---------------------------------------------------------
TE |- VT(st,n) varty_widens_to VT(st',n)

// Widening for return types - NONE indicates a void return type.
// nb. voids and nulls are different
//
// bug found: prime missing off vt, making it undefined.

lfp expty_widens_to
Some [prolog,auto,simp]
TE |- vt varty_widens_to vt'
// ------------------------------------
TE |- SOME(vt) expty_widens_to SOME(vt')
None [prolog,auto,simp]
// ------------------------------------
TE |- NONE expty_widens_to NONE

// Search for declarations and methods. Sensibly defined
// for well formed hierarchies of interfaces and classes.
//
// FDec(TE,C,v) indicates the nearest superclass of C (possibly C itself)
// which contains a declaration of the instance variable v, and
// its declared type.

lfp FDec
Hit
Cdec(TE,C) = SOME(CLASS(Csupo,Is,fields,methods)) &
PLOOKUP(fields)(v) = SOME(vt)
// ------------------------------------
FDec(TE,C,v)(C,vt)
Miss
Cdec(TE,C) = SOME(CLASS(SOME(Csup),Is,fields,methods)) &
PLOOKUP(fields)(v) = NONE &
FDec(TE,Csup,v)(res)
// ------------------------------------
FDec(TE,C,v)(res)

// FDecs(TE,C) indicates all the fields in C & all the superclasses of C
// including hidden fields.
//
// For non-cyclic hierarchies, vt is unique for a given (f,C).

lfp FDecs
Hit
Cdec(TE,C) = SOME(CLASS(Csupo,Is,fields,methods)) &
f :: PDOM(fields) &
PLOOKUP(fields)(f) = SOME(vt)
// ------------------------------------
FDecs(TE,C)((C,f),vt)
Super
Cdec(TE,C) = SOME(CLASS(SOME(Csup),Is,fields,methods)) &
FDecs(TE,Csup)((Cf,f),vt)
// ------------------------------------
FDecs(TE,C)((Cf,f),vt)

// MSigs(TE,C,m) indicates all the method declarations (i.e. both the class of
// the declaration and the signature) for method m in class C, or inherited
// from one of its superclasses, and not hidden by any of its superclasses.

lfp MSigsC
Hit
Cdec(TE,C) = SOME(CLASS(Csupo,Is,fields,methods)) &
(m,MT(AT,rt)) :: methods
// ------------------------------------
MSigsC(TE,C)(m,MT(AT,rt))
Miss
Cdec(TE,C) = SOME(CLASS(SOME(Csup),Is,fields,methods)) &
MSigsC(TE,Csup)(m,MT(AT,rt)) &
(!AT' rt'. (m,MT(AT',rt')) :: methods --> AT <> AT')
// ------------------------------------
MSigsC(TE,C)(m,MT(AT,rt))
// When the same methods gets inherited from
// several superinterfaces, there must be a common
// most narrow return type. The well-formedness rule for environments uses
// this.
lfp MSigsI
Hit
Idec(TE,i) = SOME(INTERFACE(Is,methods)) &
(m,mt) :: methods
// ------------------------------------
MSigsI(TE,i)(m,mt)
Miss
Idec(TE,i) = SOME(INTERFACE(Is,methods)) &
((?i'. MSigsI(TE,i')(m,MT(at,rt)) &
!i''. i'' :: Is & MSigsI(TE,i'')(m,MT(at,rt')) --> TE |- rt expty_widens_to rt') |
(Is = EMPTY & MSigsC(TE,Object)(m,MT(at,rt)))) &
(!at' rt'. (m,MT(at',rt')) :: methods --> at' <> at)
// ------------------------------------------------------
MSigsI(TE,i)(m,MT(at,rt))

// This indicates all the method declarations visible from an array
//
// Arrays always support all methods found in Object, unless they are overridden.
// I haven't yet got arrays supporting methods and fields generic to all arrays,
// i.e. size and clone.

lfp MSigsA
Object
MSigsC(TE,Object)(m,mt)
// ------------------------------------
MSigsA(TE)(m,mt)
def MSigs
MSigs(TE, VT(st,dim))(m,mt) <=>
MATCH res.
( 0 < dim andalso res = MSigsA(TE)(m,mt)) |
(?i. dim = 0 & st = Interface(i) andalso res = MSigsI(TE,i)(m,mt)) |
(?C. dim = 0 & st = Class(C) andalso res = MSigsC(TE,C)(m,mt)) |
(?p. dim = 0 & st = PrimT(p) andalso res = F)
|