123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507(** Set domains. *)modulePretty=GoblintCil.PrettyopenPretty(* Exception raised when the set domain can not support the requested operation.
* This will be raised, when trying to iterate a set that has been set to Top *)exceptionUnsupportedofstringletunsupporteds=raise(Unsupporteds)(** A set domain must support all the standard library set operations.
They have been copied instead of included since our [empty] has a different signature. *)moduletypeS=sigincludeLattice.Stypeeltvalempty:unit->tvalis_empty:t->boolvalmem:elt->t->boolvaladd:elt->t->tvalsingleton:elt->tvalremove:elt->t->t(** See {!Set.S.remove}.
{b NB!} On set abstractions this is a {e strong} removal,
i.e. all subsumed elements are also removed.
@see <https://github.com/goblint/analyzer/pull/809#discussion_r936336198> *)valunion:t->t->tvalinter:t->t->tvaldiff:t->t->t(** See {!Set.S.diff}.
{b NB!} On set abstractions this is a {e strong} removal,
i.e. all subsumed elements are also removed.
@see <https://github.com/goblint/analyzer/pull/809#discussion_r936336198> *)valsubset:t->t->boolvaldisjoint:t->t->boolvaliter:(elt->unit)->t->unit(** See {!Set.S.iter}.
On set abstractions this iterates only over canonical elements,
not all subsumed elements. *)valmap:(elt->elt)->t->t(** See {!Set.S.map}.
On set abstractions this maps only canonical elements,
not all subsumed elements. *)valfold:(elt->'a->'a)->t->'a->'a(** See {!Set.S.fold}.
On set abstractions this folds only over canonical elements,
not all subsumed elements. *)valfor_all:(elt->bool)->t->bool(** See {!Set.S.for_all}.
On set abstractions this checks only canonical elements,
not all subsumed elements. *)valexists:(elt->bool)->t->bool(** See {!Set.S.exists}.
On set abstractions this checks only canonical elements,
not all subsumed elements. *)valfilter:(elt->bool)->t->t(** See {!Set.S.filter}.
On set abstractions this filters only canonical elements,
not all subsumed elements. *)valpartition:(elt->bool)->t->t*t(** See {!Set.S.partition}.
On set abstractions this partitions only canonical elements,
not all subsumed elements. *)valcardinal:t->int(** See {!Set.S.cardinal}.
On set abstractions this counts only canonical elements,
not all subsumed elements. *)valelements:t->eltlist(** See {!Set.S.elements}.
On set abstractions this lists only canonical elements,
not all subsumed elements. *)valto_seq:t->eltSeq.t(** See {!Set.S.to_seq}.
On set abstractions this lists only canonical elements,
not all subsumed elements. *)valof_list:eltlist->tvalmin_elt:t->elt(** See {!Set.S.min_elt}.
On set abstractions this chooses only a canonical element,
not any subsumed element. *)valmax_elt:t->elt(** See {!Set.S.max_elt}.
On set abstractions this chooses only a canonical element,
not any subsumed element. *)valchoose:t->elt(** See {!Set.S.choose}.
On set abstractions this chooses only a canonical element,
not any subsumed element. *)end(** Subsignature of {!S}, which is sufficient for {!Print}. *)moduletypeElements=sigtypettypeeltvalelements:t->eltlistvaliter:(elt->unit)->t->unitend(** Reusable output definitions for sets. *)modulePrint(E:Printable.S)(S:Elementswithtypeelt=E.t)=structletpretty()x=letelts=S.elementsxinletcontent=List.map(E.pretty())eltsinletrecseparatex=matchxwith|[]->[]|[x]->[x]|(x::xs)->x++(text","++break)::separatexsinletseparated=separatecontentinletcontent=List.fold_left(++)nilseparatedin(text"{"++align)++content++(unalign++text"}")(** Short summary for sets. *)letshowx:string=letall_elems:stringlist=List.mapE.show(S.elementsx)inPrintable.get_short_list"{""}"all_elemsletto_yojsonx=[%to_yojson:E.tlist](S.elementsx)letprintXmlfxs=BatPrintf.fprintff"<value>\n<set>\n";S.iter(E.printXmlf)xs;BatPrintf.fprintff"</set>\n</value>\n"end(** A functor for creating a simple set domain, there is no top element, and
* calling [top ()] will raise an exception *)moduleMake(Base:Printable.S):Swithtypeelt=Base.tandtypet=BatSet.Make(Base).t=(* TODO: remove, only needed in VarEq for some reason... *)structincludePrintable.StdincludeBatSet.Make(Base)letname()="Set ("^Base.name()^")"letempty_=emptyletleq=subsetletjoin=unionletwiden=joinletmeet=interletnarrow=meetletbot=emptyletis_bot=is_emptylettop()=unsupported"Make.top"letis_top_=falseincludePrint(Base)(structtypenonrect=ttypenonrecelt=eltletelements=elementsletiter=iterend)lethashx=fold(funxy->13*y+Base.hashx)x0letreliftx=mapBase.reliftxletpretty_diff()((x:t),(y:t)):Pretty.doc=ifleqxythendprintf"%s: These are fine!"(name())elseifis_botythendprintf"%s: %a instead of bot"(name())prettyxelsebeginletevil=choose(diffxy)inPretty.dprintf"%s: %a not leq %a\n @[because %a@]"(name())prettyxprettyyBase.prettyevilendletarbitrary()=QCheck.map~rev:elementsof_list@@QCheck.small_list(Base.arbitrary())end(** A functor for creating a path sensitive set domain, that joins the base
* analysis whenever the user elements coincide. Just as above there is no top
* element, and calling [top ()] will raise an exception *)(* TODO: unused *)moduleSensitiveConf(C:Printable.ProdConfiguration)(Base:Lattice.S)(User:Printable.S)=structmoduleElt=Printable.ProdConf(C)(Base)(User)includeMake(Elt)letname()="Sensitive "^name()letleqs1s2=(* I want to check that forall e in x, the same key is in y with it's base
* domain element being leq of this one *)letp(b1,u1)=exists(fun(b2,u2)->User.equalu1u2&&Base.leqb1b2)s2infor_allps1letpretty_diff()((x:t),(y:t)):Pretty.doc=Pretty.dprintf"%s: %a not leq %a"(name())prettyxprettyyletjoins1s2=(* Ok, so for each element (b2,u2) in s2, we check in s1 for elements that have
* equal user values (there should be at most 1) and we either join with it, or
* just add the element to our accumulator res and remove it from s1 *)letf(b2,u2)(s1,res)=let(s1_match,s1_rest)=partition(fun(b1,u1)->User.equalu1u2)s1inletel=trylet(b1,u1)=chooses1_matchin(Base.joinb1b2,u2)withNot_found->(b2,u2)in(s1_rest,addelres)inlet(s1',res)=foldfs2(s1,empty())inunions1'resletaddes=join(singletone)s(* The meet operation is slightly different from the above, I think this is
* the right thing, the intuition is from thinking of this as a MapBot *)letmeets1s2=letf(b2,u2)(s1,res)=let(s1_match,s1_rest)=partition(fun(b1,u1)->User.equalu1u2)s1inletres=trylet(b1,u1)=chooses1_matchinadd(Base.meetb1b2,u2)reswithNot_found->resin(s1_rest,res)insnd(foldfs2(s1,empty()))end[@@deprecated](** Auxiliary signature for naming the top element *)moduletypeToppedSetNames=sigvaltopname:stringendmoduleLiftTop(S:S)(N:ToppedSetNames):Swithtypeelt=S.eltandtypet=[`Top|`LiftedofS.t]=(* Expose t for HoareDomain.Set_LiftTop *)structincludePrintable.StdincludeLattice.LiftTop(S)typeelt=S.eltletempty()=`Lifted(S.empty())letis_emptyx=matchxwith|`Top->false|`Liftedx->S.is_emptyxletmemxs=matchswith|`Top->true|`Lifteds->S.memxsletaddxs=matchswith|`Top->`Top|`Lifteds->`Lifted(S.addxs)letsingletonx=`Lifted(S.singletonx)letremovexs=matchswith|`Top->`Top(* NB! NB! NB! *)|`Lifteds->`Lifted(S.removexs)letunionxy=matchx,ywith|`Top,_->`Top|_,`Top->`Top|`Liftedx,`Liftedy->`Lifted(S.unionxy)letinterxy=matchx,ywith|`Top,y->y|x,`Top->x|`Liftedx,`Liftedy->`Lifted(S.interxy)letdiffxy=matchx,ywith|x,`Top->empty()|`Top,y->`Top(* NB! NB! NB! *)|`Liftedx,`Liftedy->`Lifted(S.diffxy)letsubsetxy=matchx,ywith|_,`Top->true|`Top,_->false|`Liftedx,`Liftedy->S.subsetxyletdisjointxy=matchx,ywith|`Top,`Top->false|`Liftedx,`Top|`Top,`Liftedx->S.is_emptyx|`Liftedx,`Liftedy->S.disjointxyletschemanormalabnormalx=matchxwith|`Top->unsupportedabnormal|`Liftedt->normaltletschema_defaultvf=function|`Top->v|`Liftedx->fx(* HACK! Map is an exception in that it doesn't throw an exception! *)letmapfx=matchxwith|`Top->`Top|`Liftedt->`Lifted(S.mapft)letiterf=schema(S.iterf)"iter on `Top"(* let map f = schema (fun t -> `Lifted (S.map f t)) "map"*)letfoldfxe=schema(funt->S.foldfte)"fold on `Top"xletfor_allf=schema_defaultfalse(S.for_allf)letexistsf=schema_defaulttrue(S.existsf)letfilterf=schema(funt->`Lifted(S.filterft))"filter on `Top"letelements=schemaS.elements"elements on `Top"letto_seq=schemaS.to_seq"to_seq on `Top"letof_listxs=`Lifted(S.of_listxs)letcardinal=schemaS.cardinal"cardinal on `Top"letmin_elt=schemaS.min_elt"min_elt on `Top"letmax_elt=schemaS.max_elt"max_elt on `Top"letchoose=schemaS.choose"choose on `Top"letpartitionf=schema(funt->matchS.partitionftwith(a,b)->(`Lifteda,`Liftedb))"filter on `Top"(* The printable implementation *)(* Overrides `Top text *)letpretty()x=matchxwith|`Top->textN.topname|`Liftedt->S.pretty()tletshowx:string=matchxwith|`Top->N.topname|`Liftedt->S.showt(* Lattice implementation *)(* Lift separately because lattice order might be different from subset order, e.g. after Reverse *)letbot()=`Lifted(S.bot())letis_botx=matchxwith|`Top->false|`Liftedx->S.is_botxletleqxy=matchx,ywith|_,`Top->true|`Top,_->false|`Liftedx,`Liftedy->S.leqxyletjoinxy=matchx,ywith|`Top,_->`Top|_,`Top->`Top|`Liftedx,`Liftedy->`Lifted(S.joinxy)letwidenxy=(* assumes y to be bigger than x *)matchx,ywith|`Top,_|_,`Top->`Top|`Liftedx,`Liftedy->`Lifted(S.widenxy)letmeetxy=matchx,ywith|`Top,y->y|x,`Top->x|`Liftedx,`Liftedy->`Lifted(S.meetxy)letnarrowxy=matchx,ywith|`Top,y->y|x,`Top->x|`Liftedx,`Liftedy->`Lifted(S.narrowxy)letarbitrary()=QCheck.set_printshow(arbitrary())end(** Functor for creating artificially topped set domains. *)moduleToppedSet(Base:Printable.S)(N:ToppedSetNames):Swithtypeelt=Base.tandtypet=[`Top|`LiftedofMake(Base).t]=(* TODO: don't expose t *)structmoduleS=Make(Base)includeLiftTop(S)(N)end(* This one just removes the extra "{" notation and also by always returning
* false for the isSimple, the answer looks better, but this is essentially a
* hack. All the pretty printing needs some rethinking. *)moduleHeadlessSet(Base:Printable.S)=structincludeMake(Base)letname()="Headless "^name()letpretty()x=letelts=elementsxinletcontent=List.map(Base.pretty())eltsinletrecseparatex=matchxwith|[]->[]|[x]->[x]|(x::xs)->x++(text", ")++line::separatexsinletseparated=separatecontentinletcontent=List.fold_left(++)nilseparatedincontentletpretty_diff()((x:t),(y:t)):Pretty.doc=Pretty.dprintf"%s: %a not leq %a"(name())prettyxprettyyletprintXmlfxs=iter(Base.printXmlf)xsend(** Reverses lattice order of a set domain while keeping the set operations same. *)moduleReverse(Base:S)=structincludeBaseincludeLattice.Reverse(Base)endmoduletypeFiniteSetElem=sigincludePrintable.Svalelems:tlist(** List of all possible elements. *)endmoduleFiniteSet(E:FiniteSetElem)=structmoduleE=structincludeEletarbitrary()=QCheck.oneoflE.elemsendincludeMake(E)lettop()=of_listE.elemsletis_topx=equalx(top())end(** Set abstracted by a single (joined) element.
Element-wise {!S} operations only observe the single element. *)moduleJoined(E:Lattice.S):Swithtypeelt=E.t=structtypeelt=E.tincludeEletsingletone=eletof_listes=List.fold_leftE.join(E.bot())esletexistspe=peletfor_allpe=peletmemee'=E.leqee'letchoosee=eletelementse=[e]letto_seqe=Seq.returneletremoveee'=ifE.leqe'ethenE.bot()(* NB! strong removal *)elsee'letmapfe=feletfoldfea=fealetempty()=E.bot()letaddee'=E.joinee'letis_emptye=E.is_boteletunionee'=E.joinee'letdiffee'=removee'e(* NB! strong removal *)letiterfe=feletcardinale=ifis_emptyethen0else1letinteree'=E.meetee'letsubsetee'=E.leqee'letfilterpe=unsupported"Joined.filter"letpartitionpe=unsupported"Joined.partition"letmin_elte=unsupported"Joined.min_elt"letmax_elte=unsupported"Joined.max_elt"letdisjointee'=is_empty(interee')end