statics2.abs

notation syntax rels ;
import syntax wf statics1 ;

reserve TE for :tyenv;
reserve VE for :varenv;
reserve G for :tyenv × varenv;
reserve C for :id;
reserve id for :id;



//

lfp ApplMeths A LEN(AT) = n & MSigs(TE,vt)(m,MT') & LEN(Args(MT')) = n & (!i. i < n --> TE |- EL(i)(AT) varty_widens_to EL(i)(Args(MT'))) // -------------------------------------------------------------------- ApplMethsC(TE,vt,m,AT)(MT') lfp more_special_than A LEN(AT) = n & LEN(AT') = n & (!j. j < n --> TE |- EL(j)(AT) varty_widens_to EL(j)(AT')) // ------------------------------------------------------ TE |- (AT,res)) more_special_thanI (AT',res') // find the minima of the more special partial order. There // may be more than one, though this is a type error. lfp MostSpec A ApplMeths(TE,vt,m,AT)(MT') & (!C'' MT''. ApplMeths(TE,vt,m,AT)(MT'') & TE |- MT'' more_special_than MT' --> MT' = MT'') // --------------------------------------------------------- MostSpec(TE,vt,m,AT)(MT') // bug detected: input/output analysis told me of a mistyped // variable // // Expressions can type to void (== NONE) because a method // call may not return a value, and a method call can be // part of an expression. lfp exp_hastype Id PLOOKUP(VE)(x) = SOME(vt) // ----------------------------------------------- (TE,VE) |- Id(x) var_hastype vt Access (TE,VE) |- arr exp_hastype SOME(VT(st,dim)) & 0 < dim & (TE,VE) |- e exp_hastype SOME(VT(PrimT(intT),0)) // ---------------------------------------------------- (TE,VE) |- Access(arr,e) var_hastype VT(st,dim-1) Field (TE,VE) |- obj exp_hastype SOME(VT(Class(C),0)) & FDec(TE,C,f)(C',vt') // ---------------------------------------------------- (TE,VE) |- Field(obj,f) var_hastype vt' Var (TE,VE) |- v var_hastype vt // --------------------------------------- (TE,VE) |- Var(v) exp_hastype SOME(vt) Void // -------------------------------- (TE,VE) |- Void exp_hastype NONE Prim p prim_hastype pt // ---------------------------------------- (TE,VE) |- Prim(p) exp_hastype SOME(VT(PrimT(pt),0)) NewClass TE |- C reachable_class & (!fld vt. (fld,vt) :: FDecs(TE,C) --> TE |- vt wf_vartype); // ---------------------------------------------- (TE,VE) |- NewClass(C) exp_hastype SOME(VT(Class(C),0)) NewArray 0 < LEN(dims)+ext & TE |- st wf_simptype & (!j. j < LEN(dims) --> (TE,VE) |- EL(j)(dims) exp_hastype SOME(VT(PrimT(intT),0))) // --------------------------------------------------------------------- (TE,VE) |- NewArray(st,dims,ext) exp_hastype SOME(VT(st,LEN(dims)+ext)) // should rationalise these rules into one! Call LEN(Es) = n & LEN(Vts) = n & (!j. j < n --> (TE,VE) |- EL(j)(Es) exp_hastype SOME(EL(j)(Vts))) & (TE,VE) |- e exp_hastype SOME(vt) & MostSpecC(TE,vt,m,Vts)(mt) & (!y. MostSpecC(TE,vt,m,Vts)(y) --> mt = y) // ---------------------------------------------------- (TE,VE) |- Call(e,m,Es) exp_hastype Res(mt) // Execution: The CCall and ICall rules are tricky, because the third // line incrmentally creates an array Vts, i.e. we have < new // pattern variables. We need explicit support for variable // sized collections of pattern variables, indexed by numbers. This // is like building in primitives for arrays in programming languages. // // We make LEN(pvar) = exp a declaration of an array of pattern // variables, and EL(exp)(pvar) an acceptable declaration of // a pattern variable. // // Nb. whether an array access is an instance of a pattern variable // or an expression is statically undecidable: extra information // needs to be provided by the user. // // Could broaden this to pattern vars indexed by any finite set??

// stmt_hastype // // env |- stmt stmt_hastype <varType option> // // options used for void types, which are not regular types.

// bug detected: redesigned stmt_hastype so it doesn't actually // return a type. Detected because of difficulty of evaluating // the constructions used. // // BUG: For the moment I am forcing Expr() constructs to type to :void. lfp stmt_hastype Assign (TE,VE) |- v var_hastype vt & (TE,VE) |- e exp_hastype SOME(vt') & TE |- vt' varty_widens_to vt // ----------------------------------------------- (TE,VE) |- Assign(v,e) stmt_hastype If (TE,VE) |- stmt1 stmt_hastype & (TE,VE) |- stmt2 stmt_hastype & (TE,VE) |- e exp_hastype SOME(VT(PrimT(boolT),0)) // ------------------------------------------------------------------ (TE,VE) |- If(e,stmt1,stmt2) stmt_hastype Block !j. j < LEN(stmts) --> (TE,VE) |- EL(j)(stmts) stmt_hastype // ------------------------------------------------------------------ (TE,VE) |- Block(stmts) stmt_hastype Expr (TE,VE) |- e exp_hastype NONE // ---------------------------------------- (TE,VE) |- Expr(e) stmt_hastype // bug detected: case when no return statement was specifed was // screwy lfp body_hastype body (TE,VE) |- stmt stmt_hastype & (TE,VE) |- exp exp_hastype vt // --------------------------------------------------------------- (TE,VE) |- (stmt,exp) body_hastype vt

// method_hastype // // // The complex FOLDL expression iterates through the bound variables, // replacing each by a fresh variable, and adding the new variable // to the environment.

// // bug found: AT was undeclared. //lfp method_hastype //(mbody) // LEN(Xs) = n & // (!j1. j1 < n --> // !j2. j2 < n --> // EL(j1)(Xs) = EL(j2)(Xs) --> j1 = j2) & // FOLDL( LAM(G,body). LAM(Xname,Xty). // ( LAMZname. (Vadd(G,Zname,Xty), // body_subst(Xname,Zname) body)) // (fresh(Bvars G))) (G,body) Xs = (G',body') & // G' |- body' body_hastype rt' & // G |- rt' expty_widens_to rt // // ------------------------------------------------------------------- // G |- (Xs,body) method_hastype MT(MAP(SND)(Xs),rt) // lfp method_hastype mbody ELS(Xord) = PDOM(Xtys) & ORDERING(Xord) = T & (TE,Xtys <+ (this, VT(Class(C),0))) |- body body_hastype rt' & TE |- rt' expty_widens_to rt // ------------------------------------------------------------------- (C,TE) |- ((Xord,Xtys),body) method_hastype MT(MAP(PAPPLY(Xtys))(Xord),rt) // BUG: we don't check that everything in class has a decl. We do // check it the other way around. // // bug found by execution: this was getting assigned the wrong type. lfp class_hastype cbody Cdec(TE,C) = SOME(CLASS(Csupo,Is,fields,methods)) & (!m mt. (m,mt) :: methods --> ?mbody. (m,mbody) :: ELS(mbodies) & (C,TE) |- mbody method_hastype mt) // ------------------------------------------------------------------- TE |- (C,(Csupo,mbodies)) class_hastype (Csupo,Is,fields,methods) lfp prog_hastype prog (!C ctyp. C :: PDOM(FST(TE)) & Cdec(TE,C) = SOME(CLASS(ctyp)) --> ?cbody. cbody :: ELS(prog) & TE |- cbody class_hastype ctyp) & (!cbody. cbody :: ELS(prog) --> ?C ctyp. C :: PDOM(FST(TE)) & Cdec(TE,C) = SOME(CLASS(ctyp)) & TE |- cbody class_hastype ctyp) // ------------------------------------------------------------------- TE |- (prog:prog) prog_hastype