1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741(* This file is free software, part of Logtk. See file "license" for more details. *)(** {1 Simple Typed Terms}.
These terms are scoped, and possibly typed. Type inference should be
performed on them. *)moduleLoc=ParseLocationtypelocation=ParseLocation.tletsection=Util.Section.make"typedSTerm"typet={term:view;ty:toption;mutablehash:int;(* computed lazily *)loc:locationoption;}andterm=tandty=tandmatch_cstor={cstor_id:ID.t;cstor_ty:ty;cstor_args:tylist;}andmatch_branch=match_cstor*tVar.tlist*tandview=|VaroftVar.t(** variable *)|ConstofID.t(** constant *)|Appoft*tlist(** apply term *)|Iteoft*t*t|Matchoft*match_branchlist|Letof(tVar.t*t)list*t|BindofBinder.t*tVar.t*t(** bind variable in term *)|AppBuiltinofBuiltin.t*tlist|Multisetoftlist|Recordof(string*t)list*toption(** extensible record *)|Metaofmeta_var(** Unification variable *)andmeta_var=tVar.t*toptionref*[`Generalize|`BindDefault|`NoBind]letrecdereft=matcht.termwith|Meta(_,{contents=Somet'},_)->dereft'|_->tlet[@inline]must_dereft:bool=matcht.termwith|Meta(_,{contents=Some_},_)->true|_->falseletviewt=matcht.termwith|Meta(_,{contents=Somet'},_)->(dereft').term|v->vletloct=t.loclettyt=t.tyletty_exnt=matcht.tywith|None->assertfalse|Somex->xletrechead_exnt=matchviewtwith|Constid->id|App(f,_)->head_exnf|Var_|Bind(_,_,_)|Ite(_,_,_)|Let_|Match(_,_)|AppBuiltin(_,_)|Multiset_|Record(_,_)|Meta_->raiseNot_foundletheadt=trySome(head_exnt)withNot_found->Noneletis_tTypet=matchviewtwithAppBuiltin(Builtin.TType,_)->true|_->falseletto_int_=function|Var_->0|Const_->3|App_->4|Bind_->5|Multiset_->6|Record_->7|AppBuiltin_->8|Meta_->9|Ite_->10|Match_->11|Let_->12letrechasht=ift.hash<>-1thent.hashelse(leth=hash_rec_tinassert(h<>-1);t.hash<-h;h)andhash_rec_t=matchviewtwith|Vars->Hash.combine21(Var.hashs)|Consts->Hash.combine22(ID.hashs)|App(s,l)->Hash.combine33(hashs)(Hash.listhashl)|Multisetl->Hash.combine24(Hash.listhashl)|AppBuiltin(b,l)->Hash.combine35(Builtin.hashb)(Hash.listhashl)|Bind(s,v,t')->Hash.combine46(Binder.hashs)(Var.hashv)(hasht')|Record(l,rest)->Hash.combine37(Hash.opthashrest)(Hash.list(Hash.pairHash.stringhash)l)|Ite(a,b,c)->Hash.combine48(hasha)(hashb)(hashc)|Let(_,u)->Hash.combine29(hashu)|Match(u,_)->Hash.combine210(hashu)|Meta(id,_,_)->Var.hashidletreccomparet1t2=leth1=hasht1inleth2=hasht2inlet(<?>)=letopenCCOrdin(<?>)inifh1<>h2thenCCInt.compareh1h2(* compare by hash, first *)elsematchviewt1,viewt2with|Vars1,Vars2->Var.compares1s2|Consts1,Consts2->ID.compares1s2|App(s1,l1),App(s2,l2)->compares1s2<?>(CCOrd.listcompare,l1,l2)|Bind(s1,v1,t1),Bind(s2,v2,t2)->Binder.compares1s2<?>(Var.compare,v1,v2)<?>(compare,t1,t2)|AppBuiltin(b1,l1),AppBuiltin(b2,l2)->Builtin.compareb1b2<?>(CCOrd.listcompare,l1,l2)|Multisetl1,Multisetl2->letl1=List.sortcomparel1andl2=List.sortcomparel2inCCOrd.listcomparel1l2|Record(l1,rest1),Record(l2,rest2)->CCOrd.(CCOpt.comparecomparerest1rest2<?>(cmp_fields,l1,l2))|Meta(id1,_,_),Meta(id2,_,_)->Var.compareid1id2|Ite(a1,b1,c1),Ite(a2,b2,c2)->CCList.comparecompare[a1;b1;c1][a2;b2;c2]|Let(l1,t1),Let(l2,t2)->CCOrd.(comparet1t2<?>(list(pairVar.comparecompare),l1,l2))|Match(u1,l1),Match(u2,l2)->letcmp_branch(c1,vars1,rhs1)(c2,vars2,rhs2)=CCOrd.(ID.comparec1.cstor_idc2.cstor_id<?>(listcompare,c1.cstor_args,c2.cstor_args)<?>(listVar.compare,vars1,vars2)<?>(compare,rhs1,rhs2))inCCOrd.(compareu1u2<?>(listcmp_branch,l1,l2))|Var_,_|Const_,_|App_,_|Bind_,_|Ite_,_|Let_,_|Match_,_|Multiset_,_|AppBuiltin_,_|Meta_,_|Record_,_->to_int_t1.term-to_int_t2.termandcmp_fieldxy=CCOrd.pairString.comparecomparexyandcmp_fieldsxy=CCOrd.listcmp_fieldxyletrecunfold_binderbf=matchf.termwith|Bind(b',v,f')whenb=b'->letvars,bod=unfold_binderbf'inv::vars,bod|_->[],fletrecppoutt=matchviewtwith|Vars->Var.pp_fullcouts|Consts->beginmatchID.as_prefixswith|Somes->CCFormat.stringouts|None->ID.ppoutsend|App(_,[])->assertfalse|App(f,l)->letl=if!InnerTerm.show_type_arguments||is_tType(ty_exnt)thenlelseList.filter(funt->not(ty_exnt|>is_tType))linletas_infix=matchviewfwithConstid->ID.as_infixid|_->Noneinletas_prefix=matchviewfwithConstid->ID.as_prefixid|_->Noneinbeginmatchas_infix,as_prefix,lwith|_,_,[]->ppoutf|Somes,_,[a;b]->Format.fprintfout"@[<1>%a@ %s@ %a@]"pp_inneraspp_innerb|_,Somes,[a]->Format.fprintfout"@[<1>%s@ %a@]"spp_innera|_->Format.fprintfout"@[<2>%a@ %a@]"pp_innerf(Util.pp_list~sep:" "pp_inner)lend|Bind(s,_,_)->letvars,body=unfold_binderstinletpp_bound_varoutv=Format.fprintfout"@[%a%a@]"Var.pp_fullcvpp_var_tyvinFormat.fprintfout"@[<2>%a %a.@ %a@]"Binder.pps(Util.pp_list~sep:" "pp_bound_var)varspp_innerbody|Record(l,None)->Format.fprintfout"{%a}"pp_fieldsl|Record(l,Somer)->Format.fprintfout"{%a | %a}"pp_fieldslppr|AppBuiltin(Builtin.Box_opaque,[t])->Format.fprintfout"@<1>⟦@[%a@]@<1>⟧"pp_innert|AppBuiltin(b,[a])whenBuiltin.is_prefixb->Format.fprintfout"@[%a %a@]"Builtin.ppbpp_innera|AppBuiltin(Builtin.Arrow,ret::args)->Format.fprintfout"@[<hv>%a@]"(pp_infix_Builtin.Arrow)(args@[ret])|AppBuiltin(Builtin.Not,[f])->Format.fprintfout"@[¬@ %a@]"ppf|AppBuiltin(b,([t1;t2]|[_;t1;t2]))whenBuiltin.fixityb=Builtin.Infix_binary->Format.fprintfout"@[%a %a@ %a@]"pp_innert1Builtin.ppbpp_innert2|AppBuiltin(b,l)whenBuiltin.is_infixb&&List.lengthl>0->Format.fprintfout"@[<hv>%a@]"(pp_infix_b)l|AppBuiltin(b,[])->Builtin.ppoutb|AppBuiltin(b,l)->Format.fprintfout"@[<2>%a@ %a@]"Builtin.ppb(Util.pp_listpp_inner)l|Ite(a,b,c)->Format.fprintfout"@[<2>if %a@ then %a@ else %a@]"ppappbppc|Let(l,u)->letpp_bindingout(v,t)=Format.fprintfout"@[%a := %a@]"Var.pp_fullcvpptinFormat.fprintfout"@[<2>let %a@ in (%a)@]"(Util.pp_list~sep:" and "pp_binding)lppu|Match(u,l)->letpp_branchout(c,vars,rhs)=Format.fprintfout"@[<2>case@ @[%a%a%a@] ->@ %a@]"ID.ppc.cstor_id(Util.pp_list0~sep:" "pp_inner)c.cstor_args(Util.pp_list0~sep:" "Var.pp_fullc)varspprhsinFormat.fprintfout"@[<hv>@[<hv2>match %a with@ %a@]@ end@]"ppu(Util.pp_list~sep:" | "pp_branch)l|Multisetl->Format.fprintfout"[@[%a@]]"(Util.pp_list~sep:", "pp_inner)l|Meta(id,r,_)->assert(!r=None);(* we used {!view} *)Format.fprintfout"?%a"Var.ppidandpp_inneroutt=matchviewtwith|AppBuiltin(_,_::_)|Ite(_,_,_)|App_|Let(_,_)|Bind_->Format.fprintfout"(@[%a@])"ppt(* avoid ambiguities *)|_->ppouttandpp_fieldout(name,t)=Format.fprintfout"%s=%a"namepp_innertandpp_fieldsoutf=Util.pp_list~sep:", "pp_fieldoutfandpp_infix_boutl=matchlwith|[]->assertfalse|[t]whenb=Builtin.Arrow->ppoutt|[t]->pp_inneroutt|t::l'->Format.fprintfout"@[%a@]@ %a %a"pp_innertBuiltin.ppb(pp_infix_b)l'andpp_var_tyoutv=letty=Var.tyvinmatchviewtywith|AppBuiltin(Builtin.Term,[])->()|_->Format.fprintfout":%a"pp_innertyletpp_with_tyoutt=Format.fprintfout"(@[%a@,:%a@])"pptpp(ty_exnt)letequalt1t2=comparet1t2=0exceptionIllFormedTermofstringletill_formedm=raise(IllFormedTermm)letill_formedfm=CCFormat.ksprintfm~f:ill_formedlet()=Printexc.register_printer(function|IllFormedTermmsg->Some("ill formed term: "^msg)|_->None)letmake_?loc~tyview={term=view;loc;ty=Somety;hash=-1;}letvar?locv=make_?loc~ty:v.Var.ty(Varv)letvar_of_string?loc~tyn=var?loc(Var.of_string~tyn)letconst?loc~tys=make_?loc~ty(Consts)letconst_of_cstor?locc=const?locc.cstor_id~ty:c.cstor_tyletapp_builtin?loc~tyb(l:tlist)=letmk_bl=make_?loc~ty(AppBuiltin(b,l))inbeginmatchb,lwith|Builtin.Not,[f']->beginmatchviewf'with|AppBuiltin(Builtin.Eq,l)->mk_Builtin.Neql|AppBuiltin(Builtin.Neq,l)->mk_Builtin.Eql|AppBuiltin(Builtin.Not,[t])->t|AppBuiltin(Builtin.True,[])->mk_Builtin.False[]|AppBuiltin(Builtin.False,[])->mk_Builtin.True[]|_->mk_blend|Builtin.Arrow,ret1::args1->beginmatchviewret1with|AppBuiltin(Builtin.Arrow,ret2::args2)->mk_Builtin.Arrow(ret2::args1@args2)|_->mk_blend|_->mk_blendletite?locabc=letty=matchb.tywithNone->assertfalse|Somety->tyinmake_?loc~ty(Ite(a,b,c))letlet_?loclu=matchlwith|[]->u|_->letty=ty_exnuinmake_?loc~ty(Let(l,u))letmatch_?locul=letty=matchlwith|(_,_,{ty=Somety;_})::_->ty|_::_|[]->assertfalseinmake_?loc~ty(Match(u,l))letbuiltin?loc~tyb=make_?loc~ty(AppBuiltin(b,[]))letmeta?loc(v,r,k)=make_?loc~ty:v.Var.ty(Meta(v,r,k))letapp?loc~tysl=matchviews,lwith|_,[]->s|App(f,l'),_->make_?loc~ty(App(f,l'@l))|AppBuiltin(b,l'),_->make_?loc~ty(AppBuiltin(b,l'@l))|_->make_?loc~ty(App(s,l))letbind?loc~tysvl=make_?loc~ty(Bind(s,v,l))letbind_list?loc~tysvarst=List.fold_right(funvt->bind?loc~tysvt)varstletmultiset?loc~tyl=make_?loc~ty(Multisetl)letreccheck_no_dup_seenl=matchlwith|[]->()|(n,_)::l'->ifList.memnseenthenill_formedf"name %s occurs twice"n;check_no_dup_(n::seen)l'letrecord?loc~tyl~rest=letrest=CCOpt.map(var?loc)restincheck_no_dup_[]l;make_?loc~ty(Record(l,rest))letrecord_flatten?loc~tyl~rest=matchCCOpt.mapderefrestwith|None|Some{term=(Var_|Meta_);_}->letl=List.sortcmp_fieldlinmake_?loc~ty(Record(l,rest))|Some{term=Record(l',rest');_}->letl=List.sortcmp_field(l@l')incheck_no_dup_[]l;make_?loc~ty(Record(l,rest'))|Somet'->ill_formedf"ill-formed record row: @[%a@]"ppt'letat_loc?loct={twithloc;}letwith_ty~tyt={twithty=Somety;}letmap_tyt~f={twithhash=~-1;ty=matcht.tywith|None->None|Somex->Some(fx)}letof_string?loc~tys=const?loc~ty(ID.makes)lettType={ty=None;loc=None;term=AppBuiltin(Builtin.TType,[]);hash=-1;}letprop=builtin~ty:tTypeBuiltin.Propletfresh_var?loc~ty()=var?loc(Var.gensym~ty())letbox_opaquet:t=make_~ty:(ty_exnt)(AppBuiltin(Builtin.Box_opaque,[t]))(** {2 Utils} *)letis_var=function|{term=Var_;_}->true|_->falseletis_metat=matchviewtwithMeta_->true|_->falseletis_const=function{term=Const_;_}->true|_->falseletis_fun=function{term=Bind(Binder.Lambda,_,_);_}->true|_->falsemoduleSet=Iter.Set.Make(structtypet=termletcompare=compareend)moduleMap=Iter.Map.Make(structtypet=termletcompare=compareend)moduleTbl=Hashtbl.Make(structtypet=termletequal=equallethash=hashend)moduleSeq=structletsubtermstk=letrecitert=kt;CCOpt.iteritert.ty;match(dereft).termwith|Meta_|Var_|Const_->()|App(f,l)->iterf;List.iteriterl|Bind(_,v,t')->iter(Var.tyv);itert'|Record(l,rest)->CCOpt.iteriterrest;List.iter(fun(_,t)->itert)l|Ite(a,b,c)->itera;iterb;iterc|Let(l,u)->iteru;List.iter(fun(_,t)->itert)l|Match(u,l)->iteru;List.iter(fun(_,_,t)->itert)l|AppBuiltin(_,l)|Multisetl->List.iteriterlinitertletvarst=subtermst|>Iter.filter_map(funt->matchviewtwith|Varv->Somev|_->None)letsymbolst=subtermst|>Iter.filter_map(funt->matchviewtwith|Constid->Someid|_->None)letmetast=subtermst|>Iter.filter_map(funt->matchviewtwith|Meta(a,r,k)->assert(!r=None);Some(a,r,k)|_->None)letsubterms_with_boundtk=letrecitersett=k(t,set);CCOpt.iter(iterset)t.ty;matchviewtwith|Meta_|Var_|Const_->()|App(f,l)->itersetf;List.iter(iterset)l|Ite(a,b,c)->iterseta;itersetb;itersetc|Let(l,u)->letset'=List.fold_left(funbound'(v,u)->itersetu;Var.Set.addbound'v)setliniterset'u|Match(u,l)->itersetu;List.iter(fun(_,vars,t)->letset=List.fold_leftVar.Set.addsetvarsinitersett)l|Bind(_,v,t')->letset'=Var.Set.addsetviniterset(Var.tyv);iterset't'|Record(l,rest)->CCOpt.iter(iterset)rest;List.iter(fun(_,t)->itersett)l|AppBuiltin(_,l)|Multisetl->List.iter(iterset)liniterVar.Set.emptytletfree_varst=subterms_with_boundt|>Iter.filter_map(fun(t,set)->matchviewtwith|Varvwhennot(Var.Set.memsetv)->Somev|_->None)endletrecis_groundt=CCOpt.map_oris_ground~default:truet.ty&&matcht.termwith|Var_->false|Const_->true|App(f,l)->is_groundf&&List.for_allis_groundl|AppBuiltin(_,l)->List.for_allis_groundl|Ite(a,b,c)->is_grounda&&is_groundb&&is_groundc|Let(l,u)->is_groundu&&List.for_all(fun(_,t)->is_groundt)l|Match(u,l)->is_groundu&&List.for_all(fun(_,_,t)->is_groundt)l|Bind(_,v,t')->is_ground(Var.tyv)&&is_groundt'|Record(l,rest)->CCOpt.map_oris_ground~default:truerest&&List.for_all(fun(_,t')->is_groundt')l|Multisetl->List.for_allis_groundl|Meta_->falseletvar_occurs~vart=Seq.varst|>Iter.mem~eq:Var.equalvarletas_id_appt=matchviewtwith|Constid->Some(id,ty_exnt,[])|App({term=Constid;ty=Somety;_},l)->Some(id,ty,l)|_->Noneletvarst=Seq.varst|>Var.Set.of_iter|>Var.Set.to_listletfree_vars_sett=Seq.free_varst|>Var.Set.of_iterletfree_varst=Seq.free_varst|>Var.Set.of_iter|>Var.Set.to_listletfree_vars_ll=Iter.of_listl|>Iter.flat_mapSeq.free_vars|>Var.Set.of_iter|>Var.Set.to_listletclosedt=Seq.free_varst|>Iter.is_emptyletclose_all~tyst=letvars=free_varstinbind_list~tysvarstletclose_with_vars?(binder=Binder.Forall)varst=letvars=List.map(funv->matchviewvwith|Varv->v|_->invalid_arg"has to be a variable")varsinbind_listbindervarst~ty:propletunfold_fun=unfold_binderBinder.Lambda(* non recursive map *)letmap~f~bind:f_bindb_acct=matchviewtwith|Varv->var?loc:t.loc(Var.update_ty~f:(fb_acc)v)|Constid->const?loc:t.locid~ty:(fb_acc(ty_exnt))|App(hd,l)->lethd=fb_acchdinletl=List.map(fb_acc)linapp?loc:t.loc~ty:(fb_acc(ty_exnt))hdl|Bind(s,v,body)->letb_acc',v'=f_bindb_accvinletbody=fb_acc'bodyinbind?loc:t.loc~ty:(fb_acc(ty_exnt))sv'body|AppBuiltin(Builtin.TType,_)->t|AppBuiltin(b,l)->letl=List.map(fb_acc)linletty=fb_acc(ty_exnt)inapp_builtin?loc:t.loc~tybl|Record(l,rest)->letty=fb_acc(ty_exnt)inrecord_flatten?loc:t.loc~ty(List.map(CCPair.map_snd(fb_acc))l)~rest:(CCOpt.map(fb_acc)rest)|Ite(a,b,c)->leta=fb_accainletb=fb_accbinletc=fb_acccinite?loc:t.locabc|Let(l,u)->letb_acc',l=CCList.fold_map(funb_acc'(v,t)->lett=fb_acctinletb_acc',v=f_bindb_acc'vinb_acc',(v,t))b_acclinletu=fb_acc'uinlet_?loc:t.loclu|Match(u,l)->letu=fb_accuinletl=List.map(fun(c,vars,rhs)->letb_acc,vars=CCList.fold_mapf_bindb_accvarsinc,vars,fb_accrhs)linmatch_?loc:t.locul|Multisetl->letty=fb_acc(ty_exnt)inmultiset?loc:t.loc~ty(List.map(fb_acc)l)|Meta(v,r,k)->letv=Var.update_tyv~f:(fb_acc)inmeta?loc:t.loc(v,r,k)(** {2 Specific Views} *)moduleTy=structtypet=termtypebuiltin=Prop|TType|Term|Int|Rat|Realtypeview=|Ty_builtinofbuiltin|Ty_varoftVar.t|Ty_appofID.t*tlist|Ty_funoftlist*t|Ty_foralloftVar.t*t|Ty_multisetoft|Ty_recordof(string*t)list*tVar.toption|Ty_metaofmeta_varlett_view_=viewletrecview(t:t):view=matcht_view_twith|Varv->Ty_varv|App(f,l)->beginmatcht_view_fwith|Constid->Ty_app(id,l)|_->assertfalseend|Constid->Ty_app(id,[])|Bind(Binder.ForallTy,v,t)->Ty_forall(v,t)|Record(l,None)->Ty_record(l,None)|Record(l,Somer)->beginmatcht_view_rwith|Varr->Ty_record(l,Somer)|_->assertfalseend|Meta(_,{contents=Somety'},_)->viewty'|Meta(v,o,k)->Ty_meta(v,o,k)|AppBuiltin(Builtin.Prop,[])->Ty_builtinProp|AppBuiltin(Builtin.TType,[])->Ty_builtinTType|AppBuiltin(Builtin.TyInt,[])->Ty_builtinInt|AppBuiltin(Builtin.TyRat,[])->Ty_builtinRat|AppBuiltin(Builtin.TyReal,[])->Ty_builtinReal|AppBuiltin(Builtin.Term,[])->Ty_builtinTerm|AppBuiltin(Builtin.Arrow,ret::args)->Ty_fun(args,ret)|AppBuiltin(Builtin.Multiset,[t])->Ty_multisett|Let_|Ite_|Match_|Multiset_|AppBuiltin_|Bind_->assertfalseletequal=equalletcompare=comparelethash=hashlethash_fun=hashlettType=tTypeletvar=varletvar_of_string?locv=var_of_string?loc~ty:tTypevletmeta=metaletmk_fun_?locargsret=app_builtin?loc~ty:tTypeBuiltin.Arrow(ret::args)letfun_?locargsret=matchargs,viewretwith|[],_->ret|_,Ty_fun(args',ret')->mk_fun_?loc(args@args')ret'|_->mk_fun_?locargsretletapp?locidl=letty_id=fun_(List.map(fun_->tType)l)tTypeinapp?loc~ty:tType(const?loc~ty:ty_idid)lletconst?locid=const?loc~ty:tTypeidletforall?locvt=bind~ty:tType?locBinder.ForallTyvtletforall_l?loc=List.fold_right(forall?loc)letmultiset?loct=app_builtin?loc~ty:tTypeBuiltin.Multiset[t]letrecord?locl~rest=record?loc~ty:tTypel~restletrecord_flatten?locl~rest=record_flatten?loc~ty:tTypel~restletprop=builtin~ty:tTypeBuiltin.Propletint=builtin~ty:tTypeBuiltin.TyIntletrat=builtin~ty:tTypeBuiltin.TyRatletreal=builtin~ty:tTypeBuiltin.TyRealletterm=builtin~ty:tTypeBuiltin.Termlet(==>)argsret=fun_argsretletorderty:int=letrecauxty=matchviewtywith|Ty_forall(_,ty)->auxty|Ty_fun(l,ret)->List.fold_left(funoarg->maxo(1+auxarg))(auxret)l|Ty_app(_,l)->List.fold_left(funoarg->maxo(auxarg))0l|_->0inmax1(auxty)(* never less than 1 *)letclose_forallt=close_all~ty:tTypeBinder.ForallTytletunfoldt=letrecu_forallt=matchviewtwith|Ty_forall(v,t')->lettyvars,args,ret=u_forallt'inv::tyvars,args,ret|_->letargs,ret=u_argstin[],args,retandu_argst=matchviewtwith|Ty_fun(args,ret)->letargs',ret=u_argsretinargs@args',ret|_->[],tinu_foralltletrecarityt=matchviewtwith|Ty_forall(_,t')->leta,b=arityt'ina+1,b|Ty_fun(args,_)->0,List.lengthargs|_->0,0letmanglety=letadd_idbufid=lets=ID.nameid|>CCString.filter(function'#'->false|_->true)inBuffer.add_stringbufsinletrecauxbuft=matchviewtwith|Ty_builtinTType->Buffer.add_stringbuf"ty"|Ty_builtinInt->Buffer.add_stringbuf"int"|Ty_builtinRat->Buffer.add_stringbuf"rat"|Ty_builtinReal->Buffer.add_stringbuf"real"|Ty_builtinProp->Buffer.add_stringbuf"prop"|Ty_builtinTerm->Buffer.add_stringbuf"i"|Ty_varv->add_idbuf(Var.idv)|Ty_app(f,[])->add_idbuff|Ty_app(f,l)->add_idbuff;List.iter(funsub->Buffer.add_charbuf'_';auxbufsub)l|Ty_fun(args,ret)->List.iter(funsub->auxbufsub;Buffer.add_stringbuf"_to_")args;auxbufret;|Ty_forall(v,f)->Printf.bprintfbuf"pi_%a_%a"add_id(Var.idv)auxf|Ty_multiset_|Ty_record(_,_)|Ty_meta_->()inletbuf=Buffer.create32inauxbufty;Buffer.contentsbufletneeds_argsty=arityty<>(0,0)letrecis_quantifier_freet:bool=matchviewtwith|Ty_forall_->false|Ty_builtin_|Ty_var_|Ty_meta_->true|Ty_app(_,l)->List.for_allis_quantifier_freel|Ty_fun(l,ret)->List.for_allis_quantifier_freel&&is_quantifier_freeret|Ty_multisetu->is_quantifier_freeu|Ty_record(l,_)->List.for_all(fun(_,t)->is_quantifier_freet)lletrecis_prenexty=matchviewtywith|Ty_forall(_,bod)->is_prenexbod|_->is_quantifier_freetyletis_tType=is_tTypeletis_propt=matchviewtwithTy_builtinProp->true|_->falseletrecreturnst=matchviewtwith|Ty_fun(_,ret)->returnsret|Ty_forall(_,t')->returnst'|_->tletreturns_tTypet=is_tType(returnst)letreturns_propt=is_prop(returnst)letrecis_monot=matchviewtwith|Ty_builtin_->true|Ty_app(_,l)->List.for_allis_monol|Ty_fun(l,ret)->List.for_allis_monol&&is_monoret|Ty_multisett->is_monot|Ty_record(l,rest)->List.for_allCCFun.(composesndis_mono)l&&rest=None|Ty_meta_|Ty_var_|Ty_forall(_,_)->falseendletfun_l?locvarsbody=letty=Ty.fun_?loc(List.mapVar.tyvars)(ty_exnbody)inbind_list?loc~tyBinder.Lambdavarsbodyletsort_ty_vars_first:tVar.tlist->tVar.tlist=List.sort(funv1v2->beginmatchTy.is_tType(Var.tyv1),Ty.is_tType(Var.tyv2)with|true,false->-1|false,true->1|_->0end)moduleForm=structtypet=termtypeview=|True|False|Atomoft|Eqoft*t|Neqoft*t|Equivoft*t|Xoroft*t|Implyoft*t|Andoftlist|Oroftlist|Notoft|ForalloftVar.t*t|ExistsoftVar.t*tletis_prop_(t:term):bool=matcht.tywith|Somety->Ty.is_propty|None->falseletview(t:term)=matchviewtwith|AppBuiltin(Builtin.True,[])->True|AppBuiltin(Builtin.False,[])->False|AppBuiltin(Builtin.And,l)whenTy.is_prop(ty_exnt)->Andl|AppBuiltin(Builtin.Or,l)whenTy.is_prop(ty_exnt)->Orl|AppBuiltin(Builtin.Not,[f])->Notf|AppBuiltin(Builtin.Imply,[a;b])->Imply(a,b)|AppBuiltin(Builtin.Equiv,[a;b])->Equiv(a,b)|AppBuiltin(Builtin.Xor,[a;b])->Xor(a,b)|AppBuiltin(Builtin.(Eq|Neq)ashd,l)whenTy.is_prop(ty_exnt)->beginmatchlwith|([x]|[x;_])->ifnot(Ty.is_tType(ty_exnx))then(letargs=CCFormat.sprintf"@[%a@]"(CCList.pp(pp))lininvalid_arg("type argument missing for equality: "^args))else(Atomt)|[x;l;r]->ifhd=Builtin.EqthenEq(l,r)elseNeq(l,r)|_->invalid_arg"equality encoded wrongly"end|Bind(Binder.Forall,v,t)->Forall(v,t)|Bind(Binder.Exists,v,t)->Exists(v,t)|Bind((Binder.ForallTy|Binder.Lambda),_,_)->assertfalse|Ite_|Match_|Let_|Multiset_|Record_|Meta_|Var_|Const_|App_|AppBuiltin_->Atomt(** Smart constructors (perform simplifications) *)lettrue_=builtin~ty:Ty.propBuiltin.Trueletfalse_=builtin~ty:Ty.propBuiltin.Falseletatomt=tleteq?locab=assert(not(is_tType(ty_exna)));app_builtin?loc~ty:Ty.propBuiltin.Eq[ty_exna;a;b]letneq?locab=assert(not(is_tType(ty_exna)));app_builtin?loc~ty:Ty.propBuiltin.Neq[ty_exna;a;b]letequiv?locab=app_builtin?loc~ty:Ty.propBuiltin.Equiv[a;b]letxor?locab=app_builtin?loc~ty:Ty.propBuiltin.Xor[a;b]letite=iteletimply?locab=app_builtin?loc~ty:Ty.propBuiltin.Imply[a;b]leteq_or_equivtu=ifTy.is_prop(ty_exnt)thenequivtuelseeqtuletneq_or_xortu=ifTy.is_prop(ty_exnt)thenxortuelseneqtuletbox_opaque=box_opaqueletrecflatten_(k:[<`And|`Or])accl=matchlwith|[]->acc|t::l'->letacc=matchviewt,kwith|False,`Or|True,`And->acc|Andl,`And|Orl,`Or->List.rev_appendlacc|_->t::accinflatten_kaccl'letand_?locl=letflattened=flatten_`And[]linletparsing=CCOpt.is_somelocinmatchflattenedwith|[]whennotparsing->true_|[t]whennotparsing->t|_->app_builtin?loc~ty:Ty.propBuiltin.And(ifparsingthenlelseflattened)letor_?locl=letflattened=flatten_`Or[]linletparsing=CCOpt.is_somelocinmatchflattenedwith|[]whennotparsing->false_|[t]whennotparsing->t|_->app_builtin?loc~ty:Ty.propBuiltin.Or(ifparsingthenlelseflattened)letnot_?locf=assert(Ty.is_prop(ty_exnf));app_builtin?loc~ty:Ty.propBuiltin.Not[f]letforall?locvt=bind?loc~ty:Ty.propBinder.Forallvtletexists?locvt=bind?loc~ty:Ty.propBinder.Existsvtletforall_l?loc=List.fold_right(forall?loc)letexists_l?loc=List.fold_right(exists?loc)letunfold_binder=unfold_binderletunfold_forall=unfold_binderBinder.Forallletclose_forall?locf=(* quantification over types: outermost *)lettyvars,vars=List.partition(funv->Ty.returns_tType(Var.tyv))(free_varsf)inforall_l?loctyvars(forall_l?locvarsf)letis_var=function|Atomx->is_varx|_->falseendlet_l_counter=ref0let_lam_ids=Tbl.create16letis_monomorphict=Seq.subtermst|>Iter.for_all(funt->Ty.is_mono(ty_exnt))letis_subterm~stricta~of_:b=letsubs=Seq.subtermsbin(* drop the first element ([b]) if [strict] *)letsubs=ifstrictthenIter.drop1subselsesubsinIter.exists(equala)subs(** {2 IO} *)letto_string=CCFormat.to_stringpplet_pp_term=pp(** {2 Subst} *)moduleSubst=structtypet=(term,term)Var.Subst.tletempty=Var.Subst.emptyletis_empty=Var.Subst.is_emptyletmem=Var.Subst.memletremove=Var.Subst.removeletpp=Var.Subst.pp_pp_termletto_string=CCFormat.to_stringppletaddsubstvt=ifmemsubstvthen(Util.invalid_argf"@[<2>var `@[%a@]`@ already bound in {@[%a@]}@]"Var.pp_fullvppsubst);Var.Subst.addsubstvtletadd_l=List.fold_left(funsubst(v,t)->addsubstvt)letfind_exn=Var.Subst.find_exnletfind=Var.Subst.findletmergeab=Var.Subst.mergeabletreceval_~rename_binders~recursivesubstt=matchviewtwith|Varv->eval_var~rename_binders~recursive~tsubstv|_->mapsubstt~bind:(ifrename_bindersthenrename_var~rename_binderselseeval_binders~recursive~rename_binders~t)~f:(eval_~rename_binders~recursive)(* rename variable and evaluate its type. *)andrename_var~rename_binderssubstv=letv'=Var.copyv|>Var.update_ty~f:(eval_~rename_binders~recursive:truesubst)in(* (re-)bind [v] to [v'] *)letsubst=Var.Subst.addsubstv(varv')insubst,v'andeval_var~rename_binders~recursive~tsubstv=beginmatchVar.Subst.findsubstvwith|None->var?loc:t.loc(Var.update_tyv~f:(eval_~recursive~rename_binderssubst))|Somet'->ifrecursivethen(assert(t!=t');eval_~recursive~rename_binderssubstt')else(t')endandeval_binders~rename_binders~recursive~tsubstv=subst,matchview(eval_var~recursive~rename_binders~tsubstv)with|Varv'->v'|_->invalid_arg"binder must be evaluated to a variable"leteval?(rename_binders=true)substt=ifis_emptysubstthentelseeval_~rename_binders~recursive:truesubsttleteval_nonrecsubstt=ifis_emptysubstthentelseeval_~rename_binders:true~recursive:falsesubsttendletrecrenamesubstt=matchviewtwith|Varv->begintryletv'=Var.Subst.find_exnsubstvinvar(Var.update_tyv'~f:(renamesubst))withNot_found->var?loc:t.loc(Var.update_tyv~f:(renamesubst))end|_->mapsubstt~bind:bind_rename_var~f:rename(* rename variable and evaluate its type *)andbind_rename_varsubstv=letv'=Var.copyv|>Var.update_ty~f:(renamesubst)inletsubst=Var.Subst.addsubstvv'insubst,v'letrename_all_varst=renameSubst.emptytletrecrectify_aux?(pref="v_")~cnt~substt=lett_ty=ty_exntinmatchviewtwith|Const_->(t,subst)|Varv->let(t,subst,_)=handle_var~pref~cnt~substvt_tyin(t,subst)|App(hd,fs)->letts,subst=rec_aux_l~cnt~subst(hd::fs)inlethd=List.hdtsandargs=List.tltsinapp~ty:t_tyhdargs,subst|Bind(b,v_old,body)->letold=Subst.findsubstv_oldinlet(_,subst,v)=handle_var~rename:false~pref~cnt~substv_oldt_tyinlet(body,subst)=rectify_aux~cnt~substbodyinbind~ty:t_tybvbody,(ifCCOpt.is_noneoldthenSubst.removesubstv_oldelseSubst.addsubstv_old(CCOpt.get_exnold))|AppBuiltin(b,fs)->letfs,subst=rec_aux_l~cnt~substfsinapp_builtin~ty:t_tybfs,subst|_->t,substandrec_aux_l?(pref="v_")~cnt~substargs=ignore(pref);List.fold_right(funarg(tmp,subst)->letarg',subst'=rectify_aux~subst~cntarginarg'::tmp,subst')args([],subst)andhandle_var~pref?(rename=true)~cnt~substvt_ty=ignore(pref);ifrename&&Subst.memsubstvthen(Subst.find_exnsubstv,subst,v)else(letid=CCRef.get_then_incrcntinletv'=Var.make~ty:t_ty(ID.dummy_of_intid)inletres=varv'inletsubst=Subst.addsubstvresin(res,subst,v'))letrectify?(cnt=ref0)?(subst=Subst.empty)t=rectify_aux~cnt~substtletrectify_l?(cnt=ref0)?(subst=Subst.empty)ls=rec_aux_l~cnt~substls(* apply and reduce *)letapp_whnf?loc~tyfl=letrecauxsubstfl=matchviewf,lwith|Bind(Binder.Lambda,v,body),a::tail->letsubst=Subst.addsubstvainauxsubstbodytail|_->app?loc~ty(Subst.evalsubstf)linauxSubst.emptyfl(** {2 Table of Variables} *)moduleVar_tbl=CCHashtbl.Make(structtypet_=ttypet=t_Var.tletequal=Var.equallethash=Var.hashend)(** {2 Substitutions, Unification} *)moduleUStack=structtypet={mutablesize:int;mutablel:termoptionreflist;(* list of bindings to undo *)}letcreate()={size=0;l=[];}typesnapshot=intletsnapshot~st:t=t.sizeletrestore~st:ti=letrecunwindlsizei=ifsize>ithenmatchlwith|[]->assertfalse|r::l'->r:=None;unwindl'(size-1)ielselinifi<t.sizethen(letl=unwindt.lt.sizeiint.l<-l;t.size<-i)(* bind [r] to [x] *)letbind~strx=assert(!r=None);st.l<-r::st.l;st.size<-st.size+1;r:=SomexendexceptionUnifyFailureofstring*(term*term)list*locationoptionletpp_stackoutl=letpp_tyout=function|None->()|Somety->Format.fprintfout":%a"pptyinletpp_frameout(t1,t2)=Format.fprintfout"@[<2>unifying `@[%a@,%a@]`@ and `@[%a@,%a@]`@]"ppt1pp_ty(tyt1)ppt2pp_ty(tyt2)inFormat.fprintfout"@[<v>%a@]"(Util.pp_listpp_frame)llet()=Printexc.register_printer(function|UnifyFailure(msg,st,loc)->Some(CCFormat.sprintf"@[<2>@{<Red>unification error@}:@ %s@ %a@,%a@]"msgpp_stackstLoc.pp_optloc)|_->None)letfail_unif_?locstmsg=raise(UnifyFailure(msg,st,loc))letfail_uniff_?locstmsg=CCFormat.ksprintfmsg~f:(fail_unif_?locst)(* check that:
- v does not occur in t
- t is closed (if allow_open=false)
*)letoccur_check_~allow_open~substvt=assert(is_metav);letreccheckboundt=v==t||CCOpt.map_or(checkbound)~default:falset.ty||matchviewtwith|Meta_->equalvt|Varv'->beginmatchSubst.findsubstv'with|None->notallow_open&¬(Var.Set.memboundv')|Somet'->checkboundt'end|Ite(a,b,c)->checkbounda||checkboundb||checkboundc|Let(l,u)->List.exists(fun(_,t)->checkboundt)l||letbound=List.fold_left(funset(v,_)->Var.Set.addsetv)boundlincheckboundu|Match(u,l)->checkboundu||List.exists(fun(_,vars,rhs)->letbound=ifallow_openthenboundelseList.fold_leftVar.Set.addboundvarsincheckboundrhs)l|Const_->false|App(f,l)->checkboundf||List.exists(checkbound)l|Bind(_,v,t)->checkboundv.Var.ty||check(ifallow_openthenboundelseVar.Set.addboundv)t|AppBuiltin(_,l)|Multisetl->List.exists(checkbound)l|Record(l,rest)->CCOpt.map_or(checkbound)~default:falserest||List.exists(fun(_,t)->checkboundt)lincheckVar.Set.emptytletare_same_meta_r1r2=matchr1,r2with|Somer1,Somer2->beginmatchviewr1,viewr2with|Meta(v1,_,_),Meta(v2,_,_)->Var.equalv1v2|_->falseend|_->falseletrename_varssubstv1v2=letc=var(Var.copyv1)inletsubst=Subst.addsubstv1cinletsubst=Subst.addsubstv2cinsubstletrecrename_vars_lsubstl1l2=matchl1,l2with|[],[]->subst|[],_|_,[]->assertfalse|v1::tail1,v2::tail2->letsubst=rename_varssubstv1v2inrename_vars_lsubsttail1tail2(* normalize some terms; a more thorough version of {!deref}.
flatten applications and arrow that contain bound variables *)let[@inline][@unfold1]recnormalizesubst(t:term):term=matchviewtwith|App(f,l)whenmust_dereff->normalizesubst(app?loc:t.loc~ty:(ty_exnt)(dereff)l)|App({term=Varv;_},l)whenSubst.memsubstv->letf=Subst.find_exnsubstvinnormalizesubst(app?loc:t.loc~ty:(ty_exnt)(dereff)l)|AppBuiltin(Builtin.Arrow,ret::args)whenmust_derefret->letvars,args',ret'=Ty.unfold@@derefretinifvars=[]then(Ty.fun_?loc:t.loc(args@args')ret')elset|AppBuiltin(Builtin.Arrow,{term=Varv;_}::args)whenSubst.memsubstv->letret=Subst.find_exnsubstvinletvars,args',ret'=Ty.unfold@@derefretinifvars=[]then(Ty.fun_?loc:t.loc(args@args')ret'|>normalizesubst)elset|_->dereftletunify?(allow_open=false)?loc?(st=UStack.create())?(subst=Subst.empty)t1t2=letstack=ref[]inletfail_msg=fail_uniff_?loc!stackmsginletrecunif_recsubstt1t2=ift1==t2then()else(letold_stack=!stackinunify_tyssubstt1t2;lett1=normalizesubstt1inlett2=normalizesubstt2instack:=(t1,t2)::old_stack;unify_termssubstt1t2;stack:=old_stack;(* restore stack *))andunify_tyssubstt1t2=matcht1.ty,t2.tywith|Somety1,Somety2->unif_recsubstty1ty2|_->(* none means one of them is tType; unification of terms will work
that out anyway *)()andunify_termssubstt1t2=matchviewt1,viewt2with|Varv,_whenSubst.memsubstv->unif_recsubst(Subst.find_exnsubstv)t2|_,VarvwhenSubst.memsubstv->unif_recsubstt1(Subst.find_exnsubstv)|Meta(v1,r1,k1),Meta(v2,r2,_)->ifVar.equalv1v2then()else((* if some meta is [`BindDefault] and the other is [`Generalize],
the former remains unbound, to avoid scope escaping *)letr,t=ifk1=`BindDefaultthenr2,t1elser1,t2inUStack.bind~str(Subst.evalsubstt))|Meta(_,r,_),_->assert(!r=None);ifoccur_check_~allow_open~substt1t2thenfail_"occur check"elseUStack.bind~str(Subst.evalsubstt2)|_,Meta(_,r,_)->assert(!r=None);ifoccur_check_~allow_open~substt2t1thenfail_"occur check"elseUStack.bind~str(Subst.evalsubstt1)|Varv1,Varv2->ifnot(Var.equalv1v2)thenfail_"incompatible variables@ (subst {@[%a@]})"Subst.ppsubst|Constid1,Constid2whenID.equalid1id2->()|App(f1,l1),App(f2,l2)whenList.lengthl1=List.lengthl2->unif_recsubstf1f2;unif_lsubstl1l2|App(f1,l1),App(f2,l2)->letn1=List.lengthl1inletn2=List.lengthl2inassert(n1<>n2);(* if [t1 = f1 (hd1 @ tl1)] where [length tl1 = length l2], then
unify [f1 hd1] with [f2], and [tl1] with [l2] *)ifn1>n2then(lethd1,tl1=CCList.take_drop(n1-n2)l1inletf1'=appf1hd1~ty:Ty.(fun_(List.mapty_exntl1)(ty_exnt1))inunif_recsubstf1'f2;unif_lsubsttl1l2)else(lethd2,tl2=CCList.take_drop(n2-n1)l2inletf2'=appf2hd2~ty:Ty.(fun_(List.mapty_exntl2)(ty_exnt2))inunif_recsubstf1f2';unif_lsubstl1tl2)|Ite(a1,b1,c1),Ite(a2,b2,c2)->unif_recsubsta1a2;unif_recsubstb1b2;unif_recsubstc1c2;|Let(l,u),_->(* expand "let" on the fly *)letsubst=Subst.add_lsubstlinunif_recsubstut2|_,Let(l,u)->(* expand "let" on the fly *)letsubst=Subst.add_lsubstlinunif_recsubstt1u|Match(u1,l1),Match(u2,l2)whenList.lengthl1=List.lengthl2->unif_recsubstu1u2;List.iter2(fun(c1,vars1,rhs1)(c2,vars2,rhs2)->ifList.lengthvars1=List.lengthvars2&&List.lengthc1.cstor_args=List.lengthc2.cstor_argsthen(ifnot(ID.equalc1.cstor_idc2.cstor_id)thenfail_"constructors %a and %a are not compatible (subst {@[%a@]})"ID.ppc1.cstor_idID.ppc2.cstor_idSubst.ppsubst;unif_lsubstc1.cstor_argsc2.cstor_args;letsubst=rename_vars_lsubstvars1vars2inunif_recsubstrhs1rhs2)elsefail_"incompatible branches")l1l2|AppBuiltin(b1,l1),AppBuiltin(b2,l2)whenList.lengthl1=List.lengthl2->ifBuiltin.equalb1b2thenunif_lsubstl1l2elsefail_"%a and %a are not compatible (subst {@[%a@]})"Builtin.ppb1Builtin.ppb2Subst.ppsubst|Multisetl1,Multisetl2whenList.lengthl1=List.lengthl2->(* unification is n-ary, so we choose the first satisfying, if any *)unif_multisubstl1l2|Record(l1,r1),Record(l2,r2)->(* check if r1=r2=var. If true, then fields must be the same *)ifare_same_meta_r1r2then(letrest1,rest2=unif_record_fields`MustMatchsubstl1l2inassert(rest1=[]);assert(rest2=[]);())else(letrest1,rest2=unif_record_fields`Flexiblesubstl1l2inunif_record_rest~ty:(ty_exnt1)substr2rest1;unif_record_rest~ty:(ty_exnt2)substr1rest2)|Bind(b1,v1,t1),Bind(b2,v2,t2)whenBinder.equalb1b2->(* unify [t1] and [t2], but ensure that [v1] and [v2] are the same.
We use a fresh variable, because it is still forbidden to
unify a meta with [v1] or [v2] (not closed) *)letsubst=rename_varssubstv1v2inunif_recsubstt1t2|Var_,_|Const_,_|App_,_|Ite_,_|Match_,_|Bind_,_|Multiset_,_|Record_,_|AppBuiltin_,_->fail_"incompatible shape of terms (subst {@[%a@]})"Subst.ppsubstandunif_lsubstl1l2=List.iter2(unif_recsubst)l1l2andunif_multisubstl1l2=matchl1with|[]->assert(l2=[]);()(* success *)|t1::l1'->unif_multiset_withsubstt1l1'[]l2andunif_multiset_withsubstt1l1rest2l2=matchl2with|[]->()|t2::l2'->(* save current state, then try to unify t1 and t2 *)letsnapshot=UStack.snapshot~stinbegintryunif_recsubstt1t2;unif_multisubstl1(rest2@l2')withUnifyFailure_->(* backtrack *)UStack.restore~stsnapshot;unif_multiset_withsubstt1l1(t2::rest2)l2'end;andunif_record_fieldskindsubstl1l2=matchl1,l2,kindwith|[],[],_->[],[]|[],_,`Flexible|_,[],`Flexible->l1,l2|[],_,`MustMatch|_,[],`MustMatch->fail_"fields must match, but got %a and %a"pp_fieldsl1pp_fieldsl2|(n1,t1)::l1',(n2,t2)::l2',`Flexible->ifn1=n2then(unif_recsubstt1t2;unif_record_fieldskindsubstl1'l2')elseifn1<n2then(letrest1,rest2=unif_record_fieldskindsubstl1'l2in(n1,t1)::rest1,rest2)else(letrest1,rest2=unif_record_fieldskindsubstl1l2'inrest1,(n2,t2)::rest2)|(n1,t1)::l1',(n2,t2)::l2',`MustMatch->ifn1=n2then(unif_recsubstt1t2;unif_record_fieldskindsubstl1'l2')elsefail_"fields %a and %a do not match"pp_fieldsl1pp_fieldsl2andunif_record_rest~tysubstrrest=matchr,restwith|None,[]->()|None,_::_->fail_"row is absent, cannot match %a"pp_fieldsrest|Somet,_->beginmatchviewt,restwith|Meta(_,v,_),_->lett'=record~tyrest~rest:Noneinifoccur_check_~allow_open~substtt'thenfail_"occur-check of the row %a in @[%a@]"pptppt'elseUStack.bind~stvt'|Record([],None),[]->()(* if the meta was already bound, somehow *)|_->fail_"record row @[%a@] is not a unification variable"pptendinunif_recsubstt1t2letapply_unify?gen_fresh_meta?allow_open?loc?st?(subst=Subst.empty)tyl=Util.debugf~section5"@[<>apply `%a`@ to [@[%a@]]@]"(funk->kppty(Util.pp_listpp)l);letrecauxsubsttyl=matchTy.viewty,lwith|_,[]->Subst.evalsubstty|Ty.Ty_forall(v,ty'),a::l'->letty_a=ty_exnainunify?allow_open?loc?st~substty_atType;Util.debugf~section5"@[bind `%a` to `@[%a@]`@]"(funk->kVar.pp_fullcvppa);aux(Subst.addsubstva)ty'l'|Ty.Ty_fun(exp,ret),_->aux_lsubstexpretl|Ty.Ty_meta_,_->beginmatchgen_fresh_metawith|None->fail_uniff_?loc[]"cannot apply type `@[%a@]`@ to `@[%a@]`"ppty(Util.pp_listpp)l|Someg->(* unify meta with [tyof(l) -> fresh_var()] *)letret=g()|>Ty.metainunify?allow_open?loc?st~substty(Ty.fun_(List.mapty_exnl)ret);retend|Ty.Ty_varv,_whenSubst.memsubstv->(* Apply the substitution because it could replace the type variable by a function type *)auxsubst(Subst.evalsubstty)l|(Ty.Ty_var_|Ty.Ty_app_|Ty.Ty_builtin_|Ty.Ty_multiset_|Ty.Ty_record_),_->fail_uniff_?loc[]"cannot apply type `@[%a@]`@ to `@[%a@]`"ppty(Util.pp_listpp)landaux_lsubstexpretl=matchexp,lwith|[],[]->Subst.evalsubstret|_,[]->Subst.evalsubst(Ty.fun_expret)|[],_->auxsubstretl|exp_a::exp',a::l'->unify?allow_open?loc?st~substexp_a(ty_exna);aux_lsubstexp'retl'inauxsubsttylletapp_infer?st?substfl=letty=apply_unify?st?subst(ty_exnf)linapp~tyfllettry_alpha_renamingf1f2=letrecauxsubst=function|[]->subst|(f1,f2)::rest->matchviewf1,viewf2with|Varv,Varv'->beginmatchSubst.findsubstvwith|Somet->beginmatchviewtwith|Varv''whenVar.equalv'v''&&equal(Var.tyv')(Var.tyv'')->auxsubstrest|_->fail_unif_[f1,f2]"double binding"end|None->ifnot(Var.equalvv')thenaux(Subst.addsubstvf2)((Var.tyv,Var.tyv')::rest)elseauxsubstrestend|Constx,ConstywhenID.equalxy->auxsubst((ty_exnf1,ty_exnf2)::rest)|App(hd_x,xs),App(hd_y,ys)whenList.lengthxs=List.lengthys->(* head might be a lambda or a const, delegate solving it to
the same algorithm *)letargs=List.combine(hd_x::xs)(hd_y::ys)inauxsubst(args@rest)|AppBuiltin(hd_x,xs),AppBuiltin(hd_y,ys)whenBuiltin.equalhd_xhd_y&&List.lengthxs=List.lengthys->(* unify types, if they have any *)letrest=matchf1.ty,f2.tywith|None,None->rest|None,Some_|Some_,None->fail_unif_[f1,f2]"incompatible types"|Somety1,Somety2->(ty1,ty2)::restinauxsubst((List.combinexsys)@rest)|AppBuiltin(hd_x,_xs),AppBuiltin(hd_y,_ys)whenBuiltin.equalhd_xhd_y->fail_unif_[f1,f2]"arity mismatch"|Bind(b,v,body),Bind(b',v',body')whenBinder.equalbb'->assert(not@@Subst.memsubstv);letsubst=ifnot(Var.equalvv')thenSubst.addsubstv(varv')elsesubstinauxsubst((Var.tyv,Var.tyv')::(body,body')::rest)|_->fail_unif_[f1,f2]"mismatch or unknown constructors"intryletvars1=Seq.varsf1|>Var.Set.of_iterinletvars2=Seq.varsf2|>Var.Set.of_iterinifVar.Set.intersection_emptyvars1vars2then(letsubst=auxSubst.empty[f1,f2]inUtil.debugf~section5"Alpha renaming succeeded:@ of %a@ and %a@ with subst %a"(funk->kppf1ppf2Subst.ppsubst);Somesubst)elseNonewithUnifyFailure(msg,st,_)->Util.debugf~section1"Alpha renaming failed: %s@ %a"(funk->kmsgpp_stackst);None(*
Perform rewritings of this form
A | A -> A; A | ~ A -> T; A | T -> T; A | F -> A
A & A -> A; A & ~ A -> F; A & T -> A; A & F -> F
~T -> F ~F -> T
A <=> ~A -> F; A <=> A -> T A <=> F -> ~A A <=> T -> A
P <~> P -> ~(P<->P)
A => ~A -> F; A <-> A => T A <-> F => ~A A <-> T => A *)letsimplify_formulat=letmoduleF=Forminletsimplify_and_ortbl=letexists_doubleargs=letpos,neg=CCList.partition_map(funt->matchviewtwith|AppBuiltin(Builtin.Not,[s])->`Rights|_->`Leftt)args|>CCPair.map_sameSet.of_listinnot(Set.is_empty(Set.interposneg))inletnetural_el,absorbing_el=ifb=Builtin.AndthenF.true_,F.false_else(F.false_,F.true_)inletl'=CCList.sort_uniq~cmp:comparelinifexists_doublel||List.exists(equalabsorbing_el)lthenabsorbing_elelse(letl'=List.filter(funs->not(equalsnetural_el))l'inifList.lengthl=List.lengthl'thentelse(ifCCList.is_emptyl'thennetural_elelse(ifList.lengthl'=1thenList.hdl'elseapp_builtin~ty:(prop)bl')))inletsimpl_and_or_imppremiseconclusion=(* if premise is of the form a1 /\ ... /\ an
and the conclusion of the form b1 \/ ... \/ bm
and if the intersection of {a1, ..., an} and {b1, ..., bm}
is not empty then simplify the implication into T *)letpremise_terms=matchviewpremisewith|AppBuiltin(And,l)->l|_->[premise]inletconc_terms=matchviewconclusionwith|AppBuiltin(Or,l)->l|_->[conclusion]inletis_true=List.exists(func->List.exists(equalc)premise_terms)conc_termsinifis_truethenSomeF.true_elseNoneinletrecauxt=letty=ty_exntinmatchviewtwith|AppBuiltin(((And|Or)asb),args)whenTy.is_propty->simplify_and_ortb(List.mapauxargs)|AppBuiltin(Not,[s])->beginmatchviewswith|AppBuiltin(Not,[u])->auxu|AppBuiltin(True,[])->F.false_|AppBuiltin(False,[])->F.true_|_->app_builtin~tyNot[auxs]end|AppBuiltin((Eq|Equiv)asb,[x;y])whenTy.is_prop(ty_exnx)->assert(Ty.is_prop(ty_exny));letx=auxxandy=auxyinifequalxythenF.true_elseifequalxF.true_thenyelseifequalxF.false_thenF.not_yelseifequalyF.true_thenxelseifequalyF.false_thenF.not_xelseifequalx(F.not_y)||equaly(F.not_x)thenF.false_elseapp_builtin~tyb[x;y]|AppBuiltin((Neq|Xor),[x;y])whenTy.is_prop(ty_exnx)->aux(F.not_(F.eq_or_equivxy))|AppBuiltin(Imply,[x;y])->letx=auxxandy=auxyinbeginmatchsimpl_and_or_impxywith|Someres->res|None->ifequalxythenF.true_elseifequalxF.true_thenyelseifequalxF.false_thenF.true_elseifequalyF.true_thenF.true_elseifequalyF.false_thenF.not_xelseifequalx(F.not_y)thenyelseifequaly(F.not_x)thenyelseapp_builtin~tyImply[x;y]end|AppBuiltin((Neq|Xor),[x;y])whenTy.is_prop(ty_exnx)->aux(F.not_(F.eq_or_equivxy))|AppBuiltin(b,args)->app_builtin~tyb(List.mapauxargs)|App(hd,args)->app~ty(auxhd)(List.mapauxargs)|Bind(s,v,body)->bind~tysv(auxbody)|_->tinletres=auxtinres(** {2 Conversion} *)letreceraset=matchviewtwith|Varv->STerm.var(Var.to_stringv)|Consts->STerm.const(ID.to_strings)|App(f,l)->STerm.app(erasef)(List.maperasel)|Bind(b,v,t)->STerm.bindb[STerm.V(Var.to_stringv),Some(erase(Var.tyv))](eraset)|AppBuiltin(b,l)->STerm.app_builtinb(List.maperasel)|Ite(a,b,c)->STerm.ite(erasea)(eraseb)(erasec)|Match(u,l)->letu=eraseuinletl=List.map(fun(c,vars,rhs)->(* type arguments of [c] are ignored as being implicit *)letc=ID.to_stringc.cstor_idinletvars=List.map(funv->STerm.V(Var.to_stringv))varsinletrhs=eraserhsinSTerm.Match_case(c,vars,rhs))linSTerm.match_ul|Multisetl->STerm.list_(List.maperasel)|Let(l,u)->letl=List.map(fun(v,t)->STerm.V(Var.to_stringv),eraset)linletu=eraseuinSTerm.let_lu|Record(l,rest)->letrest=CCOpt.map(funt->matchviewtwith|Varv->STerm.V(Var.to_stringv)|_->failwith"cannot erase non-variable record raw")restinSTerm.record(List.map(fun(n,t)->n,eraset)l)~rest|Meta_->failwith"cannot erase meta"letrecdeptht=matchviewtwith|Var_|Meta_|Const_->0|App(f,l)->depth_l(f::l)|Bind(b,v,t)->1+deptht|AppBuiltin(b,l)->depth_ll|Ite(a,b,c)->depth_l[a;b;c]|Match(u,l)->1+depthu|_->failwith"not implemented"anddepth_ll=1+List.fold_left(funacct->maxacc(deptht))0lmoduleTPTP=structletppoutt=STerm.TPTP.ppout(eraset)letto_stringt=STerm.TPTP.to_string(eraset)endmoduleTPTP_THF=structletppoutt=STerm.TPTP_THF.ppout(eraset)letto_stringt=STerm.TPTP_THF.to_string(eraset)endmoduleZF=structletppoutt=STerm.ZF.ppout(eraset)letpp_inneroutt=STerm.ZF.pp_innerout(eraset)letto_stringt=STerm.ZF.to_string(eraset)endletpp_in=function|Output_format.O_zf->ZF.pp|Output_format.O_tptp->TPTP_THF.pp|Output_format.O_normal->pp|Output_format.O_none->CCFormat.silent