package newTypeSystem;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import ast.Ast.MethodType;
import ast.Ast.NormType;
import ast.Ast.Path;
import ast.Ast.Type;
import ast.ErrorMessage;
import ast.ExpCore.ClassB;
import ast.ExpCore.ClassB.MethodWithType;
import ast.ExpCore.ClassB.NestedClass;
import ast.ExpCore.ClassB.Phase;
import auxiliaryGrammar.Functions;
import coreVisitors.From;
import programReduction.Norm;
import programReduction.Program;
import tools.Assertions;
import ast.Ast.Mdf;
public interface TsLibrary extends TypeSystem{
@Override default TOut typeLib(TIn in) {
assert in.phase!=Phase.None;
if(in.phase==Phase.Norm){return libraryShallowNorm(in);}
return libraryWellTyped(in);
}
default TOut libraryShallowNorm(TIn in) {
//(library shallow norm)
//Norm |- p ~> norm(p) //remember: norm ignores meth bodies
////assert forall P in norm(p).Ps p(P).Phase>=Norm
ClassB normP = normTopL(in);
return new TOk(in,normP,Path.Library().toImmNT());
}
default ClassB normTopL(TIn in) throws Error {
ClassB normP;
try{normP=new Norm().norm(in.p);}
catch(RuntimeException exc){
throw exc;
//exceptions from normalization all represents unsolvable
//type errors. Same for cyclic resolve
}
assert normP.getSupertypes().stream().allMatch(
t->{
Phase phase=in.p.extractClassB(t.getNT().getPath()).getPhase();
assert phase!=Phase.None:
t.getNT().getPath();
return phase!=Phase.None;}):
"";
return normP;
}
default TOut libraryWellTyped(TIn in) {
// (library well typed)
// Phase |- p ~> L' //In implementation, if p.top().Phase>=Phase, L'=p.Top()
ClassB top=in.p.top();
assert in.phase.subtypeEq(Phase.Typed):// Phase in {Typed,Coherent}
"";
if(top.getPhase().subtypeEq(in.phase)){
return new TOk(in,top,Path.Library().toImmNT());
}
// L0={interface? implements Ps M1..Mn Phase'}=norm(p)
// L'={interface? implements Ps M1'..Mn' max(Phase',Phase)}
ClassB L0 = normTopL(in);
List<MethodWithType> mwts = L0.mwts();
List<NestedClass> ns = L0.ns();
List<NestedClass> newNs = new ArrayList<>();
// forall i in 1..n
// Phase| p| Ps |- Mi ~> Mi'
TIn inNested=in.withP(in.p.updateTop(L0));
List<MethodWithType> newMwts;
if(in.phase==Phase.Coherent && top.getPhase()==Phase.Typed){
newMwts=new ArrayList<>(mwts);
}
else {
newMwts = new ArrayList<>();
for(MethodWithType mwt:mwts){
TOutM out=memberMethod(inNested,L0.getSupertypes(),mwt);
if(!out.isOk()){return out.toError();}
newMwts.add((MethodWithType)out.toOkM().inner);
}
}
for(NestedClass nt:ns){
TOutM out=memberNested(inNested,nt);
if(!out.isOk()){return out.toError();}
newNs.add((NestedClass)out.toOkM().inner);
}
Phase maxPhase=L0.getPhase();
if(in.phase.subtypeEq(maxPhase)){maxPhase=in.phase;}
ClassB L1=new ClassB(L0.getDoc1(),L0.isInterface(),L0.getSupertypes(),newMwts,newNs,L0.getP(),maxPhase,L0.getUniqueId());
if(in.phase==Phase.Coherent){
boolean isCoh=coherent(in.p.updateTop(L1),true);
if(!isCoh){
return new TErr(in,"",Path.Library().toImmNT(),ErrorKind.LibraryNotCoherent);
}
}
// if Phase=Coherent then coherent(p.pop().evilPush(L'))
// //or error not coherent set of abstr. methods:list
return new TOk(in,L1,Path.Library().toImmNT());
}
default TOutM memberNested(newTypeSystem.TIn in, NestedClass nc) {
//(member nested)
//Phase| p| Ps |-C:L ~> C:L'
// where
// Phase |-p.push(C) ~> L' return null;
Program p1=in.p.push(nc.getName());
TOut res=typeLib(in.withP(p1));
if(!res.isOk()){return res.toError();}
return new TOkM(nc.withInner(res.toOk().annotated));
}
default TOutM memberMethod(TIn in, List<Type> supertypes, MethodWithType mwt) {
//(member method)
//Phase| p| Ps |-M ~> M'
// where
// M =refine? mdf method T m(T1 x1 .. Tn xn)exceptions Ps0 e?
// M'=refine? mdf method T m(T1 x1 .. Tn xn)exceptions Ps0 e?'
// G=this:mdf This0,x1:T1,..,xn:Tn
// if e?=e then
// Typed| p| G |- e ~> e?':_ <=fwd% T | empty;Ps1
// forall P1 in Ps1 exists P0 in Ps0 such that p|-P1<=P0
//else
// e?=e?'
MethodWithType mwt1;
if(!mwt.get_inner().isPresent()){
mwt1=mwt;
}
else{
TIn newIn=in.freshGFromMt(mwt);
TOut out=type(newIn);
if(!out.isOk()){return out.toError();}
for(Path P1: out.toOk().exceptions){
//exists P0 in Ps0 such that p|-P1<=P0
boolean ok=mwt.getMt().getExceptions().stream().anyMatch(
P0->null==TypeSystem.subtype(newIn.p, P1, P0.getNT().getPath()));
if(!ok){return new TErr(newIn,"",P1.toImmNT(),ErrorKind.MethodLeaksExceptions);}
}
if(!out.toOk().returns.isEmpty()){
return new TErr(newIn,"",out.toOk().returns.get(0),ErrorKind.MethodLeaksReturns);
}
mwt1=mwt.with_inner(Optional.of(out.toOk().annotated));
}
if(mwt.getMt().isRefine()){
// refine? = refine <=>
// forall P in Ps such that p(P)(m(x1..xn))[from P]=M0 //that is, is defined
// all of the following hold:
// M0=refine?' mdf method T' m(T'1 x1..T'n xn)exceptions Ps'
// p|-T<= T' //method returns a type which is not a sybtype of its ancestor "name" or worst, ancestor do not define method named m(xs)
// p.equiv(T1,T'1)..p.equiv(Tn,T'n) //invalid type w.r.t. ancestor paramerer xi
// forall Pi in Ps0 exists Pj in Ps' such that p |- Pi<=Pj
// //or error: leaked exception P is not the subtype of a declared exception
// /or method declares an exception (P) which is not a subtype of ancestor exceptions
for(Type t :supertypes){
Path P=t.getNT().getPath();
ClassB cbP=in.p.extractClassB(P);
MethodWithType mwtP=(MethodWithType) cbP._getMember(mwt.getMs());
if(mwtP==null){continue;}
MethodType M0=From.from(mwtP.getMt(),P);
ErrorKind kind=TypeSystem.subtype(in.p, mwt.getMt().getReturnType().getNT(),M0.getReturnType().getNT());
if(kind!=null){
return new TErr(in,"",P.toImmNT(),ErrorKind.InvalidImplements);
}
{int i=-1;for(Type Ti:mwt.getMt().getTs()){i+=1; Type T1i=M0.getTs().get(i);
if(!in.p.equiv(Ti.getNT(),T1i.getNT())){
return new TErr(in,"",P.toImmNT(),ErrorKind.InvalidImplements);
}
}}
for(Type Pi: mwt.getMt().getExceptions()){
//exists Pj in Ps' such that p |- Pi<=Pj
boolean ok=M0.getExceptions().stream().anyMatch(
Pj->null==TypeSystem.subtype(in.p, Pi.getNT().getPath(), Pj.getNT().getPath()));
if(!ok){
return new TErr(in,"",P.toImmNT(),ErrorKind.InvalidImplements);
}
}
}
}
return new TOkM(mwt1);
}
static boolean coherent(Program p,boolean force) {
ClassB top=p.top();
if (top.isInterface()){return true;}
List<MethodWithType> stateC=top.mwts().stream()
.map(m->(MethodWithType)m)
.filter(m->!m.get_inner().isPresent())
.sorted((m1,m2)->m1.getMt().getMdf()==Mdf.Class?-1:1)
.collect(Collectors.toList());
if(stateC.isEmpty()){return true;}
MethodWithType ck=stateC.get(0);
if(!coherentK(p,ck)){
if(force){throw new ErrorMessage.NotOkToStar(top, ck,"invalid candidate factory", ck.getP());}
return false;
}
for(MethodWithType mwt:stateC.subList(1,stateC.size())){
if(!coherentF(p,ck,mwt)){
if(force){throw new ErrorMessage.NotOkToStar(top, ck,"abstract method\n"+sugarVisitors.ToFormattedText.of(mwt)+"\ndo not fit candidate factory", mwt.getP());}
return false;
}
}
return true;
}
static boolean coherentF(Program p,MethodWithType ck, MethodWithType mwt) {
MethodType mt=mwt.getMt();
Mdf m=mt.getMdf();
if(mwt.getMs().getUniqueNum()!=ck.getMs().getUniqueNum()){return false;}
NormType Ti=_extractTi(ck,mwt.getMs().getName());// internally do noFwd
if (Ti==null){return false;}
//if(m==Mdf.Class){return false;}
if(m==Mdf.Readable || m==Mdf.Immutable){//getter
if(!mt.getTs().isEmpty()){return false;}
NormType Ti_=TypeManipulation._toRead(Ti);
if (Ti_==null){return false;}//p|-toRead(Ti)<=T
if(null!=TypeSystem.subtype(p, Ti_,mt.getReturnType().getNT())){return false;}
return true;
}
if(m!=Mdf.Mutable){return false;}
//exposer/setter
if(mt.getTs().isEmpty()){//exposer
NormType Ti_=TypeManipulation.capsuleToLent(Ti);
if (Ti_==null){return false;}//p|-capsuleToLent(Ti)<=T
if(null!=TypeSystem.subtype(p, Ti_,mt.getReturnType().getNT())){return false;}
return true;
}
//setter refine? mut method Void m[n?](T that)
if(!mt.getReturnType().equals(NormType.immVoid)){return false;}
if(mt.getTs().size()!=1){return false;}
if(!mwt.getMs().getNames().get(0).equals("that")){return false;}
NormType T=mt.getTs().get(0).getNT();
if(null!=TypeSystem.subtype(p, Ti,T)){return false;}
if(Ti.getMdf()==Mdf.Readable){
Mdf mT=T.getMdf();
if(mT!=Mdf.Capsule && mT!=Mdf.Immutable){return false;}
}
return true;
}
static NormType _extractTi(MethodWithType ck, String name) {
if(name.startsWith("#")){name=name.substring(1);}
int i=-1;for(String ni:ck.getMs().getNames()){i+=1;
if (ni.equals(name)){return TypeManipulation.noFwd(ck.getMt().getTs().get(i).getNT());}
}
return null;
}
//coherent(n?,p,T1 x1..Tn xn,
//refine? class method T m[n?] (T1' x1..Tn' xn) exception _)
//where
//p|- This0 <=T.P and p|-Ti'<=fwd Ti
//T.mdf!=class and if T.mdf in {imm,capsule}, mut notin (T1..Tn).mdfs
static boolean coherentK(Program p,MethodWithType ck) {
MethodType mt=ck.getMt();
if(mt.getMdf()!=Mdf.Class){return false;}
NormType rt=mt.getReturnType().getNT();
if(null!=TypeSystem.subtype(p, Path.outer(0),rt.getPath())){return false;}
Mdf m=rt.getMdf();
if (m==Mdf.Class){return false;}
boolean immOrC=(m==Mdf.Immutable || m==Mdf.Capsule);
boolean lentOrR=(m==Mdf.Lent || m==Mdf.Readable);
int allowedR=lentOrR?1:0;
for(Type ti:mt.getTs()){
Mdf mi=ti.getNT().getMdf();
if(mi==Mdf.Lent){return false;}
if(mi==Mdf.Readable){
if(allowedR==0){return false;}
allowedR-=1;
}
if(immOrC & (mi==Mdf.Mutable || mi==Mdf.MutableFwd)){return false;}
}
return true;
}
}