123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274(* The meaning of keywords [strict] and [never_returns_normally] is defined in
terms of abstract values as follows:
relaxed (default): nor = Safe and exn = Top and div = Top strict: nor = Safe
and exn = Safe and div = Safe never_returns_normally: nor = Bot and exn = Top
and div = Top
where [nor] means normal return of the call, [exn] means return via an
exception, [div] means diverging (non-terminating) executions, and the
meaning and order of elements is:
Top may allocate Safe does not allocate on any execution paths Bot
unreachable
Using more than one keyword means intersection (i.e., meet of the elements,
pointwise lifted to tuples), so we get the following:
[@zero_alloc assume] nor = Safe and exn = Top and div = Top [@zero_alloc
assume strict] nor = Safe and exn = Safe and div = Safe [@zero_alloc assume
strict never_returns_normally] nor = Bot and exn = Safe and div = Safe
[@zero_alloc assume never_returns_normally] nor = Bot and exn = Top and div =
Top
See [Value] and [Annotation] in [backend/checkmach.ml]. *)(* CR gyorsh: should we move [Value] and [Annotation] here or maybe "utils" and
use them directly, instead of the weird compare function that abstracts them?
Perhaps we should translate "strict" and "never_returns_normally" directly
into (nor,exn,div) *)moduletypeWS=sigtypetvalempty:tvaljoin:t->t->tvalmeet:t->t->tvallessequal:t->t->boolvalprint:Format.formatter->t->unitvalcompare:t->t->intendmoduletypeComponent=sigtypettypewitnessesvaltop:witnesses->tvalsafe:tvalbot:tvallessequal:t->t->boolvaljoin:t->t->tvalmeet:t->t->tvalcompare:t->t->intvalprint:witnesses:bool->Format.formatter->t->unitendmoduleMake_component(Witnesses:WS)=struct(* keep in sync with "resolved" values in Checkmach. *)typet=|TopofWitnesses.t|Safe|Botletbot=Botlettopw=Topwletsafe=Safeletjoinc1c2=matchc1,c2with|Bot,Bot->Bot|Safe,Safe->Safe|Topw1,Topw2->Top(Witnesses.joinw1w2)|Safe,Bot|Bot,Safe->Safe|Topw1,Bot|Topw1,Safe|Bot,Topw1|Safe,Topw1->Topw1letmeetc1c2=matchc1,c2with|Bot,Bot->Bot|Safe,Safe->Safe|Topw1,Topw2->Top(Witnesses.meetw1w2)|Safe,Bot|Bot,Safe->Bot|Top_,Bot|Bot,Top_->Bot|Top_,Safe|Safe,Top_->Safeletlessequalv1v2=matchv1,v2with|Bot,Bot->true|Safe,Safe->true|Topw1,Topw2->Witnesses.lessequalw1w2|Bot,Safe->true|Bot,Top_->true|Safe,Top_->true|Top_,(Bot|Safe)->false|Safe,Bot->falseletcomparet1t2=matcht1,t2with|Bot,Bot->0|Safe,Safe->0|Topw1,Topw2->Witnesses.comparew1w2|Bot,(Safe|Top_)->-1|(Safe|Top_),Bot->1|Safe,Top_->-1|Top_,Safe->1letprint~witnessesppf=function|Bot->Format.fprintfppf"bot"|Topw->Format.fprintfppf"top";ifwitnessesthenFormat.fprintfppf" (%a)"Witnesses.printw|Safe->Format.fprintfppf"safe"endmoduleMake_value(Witnesses:WS)(V:Componentwithtypewitnesses:=Witnesses.t)=struct(** Lifts V to triples *)typet={nor:V.t;exn:V.t;div:V.t}letbot={nor=V.bot;exn=V.bot;div=V.bot}letlessequalv1v2=V.lessequalv1.norv2.nor&&V.lessequalv1.exnv2.exn&&V.lessequalv1.divv2.divletjoinv1v2={nor=V.joinv1.norv2.nor;exn=V.joinv1.exnv2.exn;div=V.joinv1.divv2.div}letmeetv1v2={nor=V.meetv1.norv2.nor;exn=V.meetv1.exnv2.exn;div=V.meetv1.divv2.div}letnormal_return={botwithnor=V.safe}letexn_escape={botwithexn=V.safe}letdiverges={botwithdiv=V.safe}letsafe={nor=V.safe;exn=V.safe;div=V.safe}lettopw={nor=V.topw;exn=V.topw;div=V.topw}letrelaxedw={nor=V.safe;exn=V.topw;div=V.topw}letof_annotation~strict~never_returns_normally~never_raises=letres=ifstrictthensafeelserelaxedWitnesses.emptyinletres=ifnever_raisesthen{reswithexn=V.bot}elseresinifnever_returns_normallythen{reswithnor=V.bot}elseresletprint~witnessesppf{nor;exn;div}=letpp=V.print~witnessesinFormat.fprintfppf"{ nor=%a;@ exn=%a;@ div=%a }@,"ppnorppexnppdivletcompare{nor=n1;exn=e1;div=d1}{nor=n2;exn=e2;div=d2}=letc=V.comparen1n2inifc<>0thencelseletc=V.comparee1e2inifc<>0thencelseV.compared1d2endmoduleAssume_info=structmoduleWitnesses=structtypet=unitletjoin__=()letlessequal__=trueletmeet__=()letprint__=()letempty=()letcompare__=0endmoduleV=Make_component(Witnesses)moduleValue=Make_value(Witnesses)(V)typet=|No_assume|AssumeofValue.t|Assume_inferredofValue.t(* CR ccasinghino: consider extending this time to also capture "check"
attributes, and using it everywhere in typed tree instead of sometimes
having a check_attribute and sometimes having this type. *)letcomparet1t2=matcht1,t2with|No_assume,No_assume->0|Assumev1,Assumev2->Value.comparev1v2|Assume_inferredv1,Assume_inferredv2->Value.comparev1v2|No_assume,(Assume_|Assume_inferred_)->-1|Assume_inferred_,Assume_->-1|Assume_,Assume_inferred_->1|(Assume_|Assume_inferred_),No_assume->1letequalt1t2=comparet1t2=0letprintppf=function|No_assume->()|Assumev->Format.fprintfppf"%a"(Value.print~witnesses:false)v|Assume_inferredv->Format.fprintfppf"(inferred)%a"(Value.print~witnesses:false)vletto_stringv=Format.asprintf"%a"printvletjoint1t2=matcht1,t2with|No_assume,No_assume->No_assume|No_assume,(Assume_|Assume_inferred_)|(Assume_|Assume_inferred_),No_assume->No_assume|Assumet1,Assumet2->Assume(Value.joint1t2)|Assume_inferredt1,Assume_inferredt2->Assume_inferred(Value.joint1t2)|Assumet1,Assume_inferredt2|Assume_inferredt1,Assumet2->Assume_inferred(Value.joint1t2)letmeett1t2=matcht1,t2with|No_assume,No_assume->No_assume|No_assume,(Assume_ast)|(Assume_ast),No_assume->t|No_assume,(Assume_inferred_ast)|(Assume_inferred_ast),No_assume->t|Assumet1,Assumet2->Assume(Value.meett1t2)|Assume_inferredt1,Assume_inferredt2->Assume_inferred(Value.meett1t2)|Assumet1,Assume_inferredt2->Assume(Value.meett1t2)|Assume_inferredt1,Assumet2->Assume(Value.meett1t2)letnone=No_assumeletcreate~strict~never_returns_normally~never_raises~inferred=letv=Value.of_annotation~strict~never_returns_normally~never_raisesinmatchinferredwithfalse->Assumev|true->Assume_inferredvletget_valuet=matchtwithNo_assume->None|Assumev|Assume_inferredv->Somevletis_nonet=matchtwithNo_assume->true|Assume_|Assume_inferred_->falseletis_inferredt=matchtwithAssume_inferred_->true|Assume_|No_assume->falseend