123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405(************************************************************************)(* * The Rocq Prover / The Rocq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)openUtilopenNamesopenTac2expropenTac2print(** Union find *)moduleUF:sigtypeelttype'atvalequal:elt->elt->boolvalcreate:unit->'atvalfresh:'at->eltvalfind:elt->'at->(elt*'aoption)valunion:elt->elt->'at->unitvalset:elt->'a->'at->unitmoduleMap:CSig.MapSwithtypekey=eltend=structtypeelt=intletequal=Int.equalmoduleMap=Int.Maptype'anode=|Canonofint*'aoption|Equivofelttype'at={mutableuf_data:'anodearray;mutableuf_size:int;}letresizep=ifInt.equal(Array.lengthp.uf_data)p.uf_sizethenbeginletnsize=2*p.uf_size+1inletv=Array.makensize(Equiv0)inArray.blitp.uf_data0v0(Array.lengthp.uf_data);p.uf_data<-v;endletcreate()={uf_data=[||];uf_size=0}letfreshp=resizep;letn=p.uf_sizeinp.uf_data.(n)<-(Canon(1,None));p.uf_size<-n+1;nletreclookupnp=letnode=Array.getp.uf_dataninmatchnodewith|Canon(size,v)->n,size,v|Equivy->let((z,_,_)asres)=lookupypinifnot(Int.equalzy)thenArray.setp.uf_datan(Equivz);resletfindnp=let(x,_,v)=lookupnpin(x,v)letunionxyp=let((x,size1,_)asxcan)=lookupxpinlet((y,size2,_)asycan)=lookupypinletxcan,ycan=ifsize1<size2thenxcan,ycanelseycan,xcaninletx,_,xnode=xcaninlety,_,ynode=ycaninassert(Option.is_emptyxnode);assert(Option.is_emptyynode);p.uf_data.(x)<-Equivy;p.uf_data.(y)<-Canon(size1+size2,None)letsetxvp=let(x,s,v')=lookupxpinassert(Option.is_emptyv');p.uf_data.(x)<-Canon(s,Somev)endmoduleTVar=structtypet=UF.eltletequal=UF.equalmoduleMap=UF.Mapendtypemix_var=|GVarofUF.elt|LVarofinttypemix_type_scheme=int*mix_varglb_typexpr(* Changing the APIs enough to get which variables are used in random genargs seems very hard
so instead we use mutation to detect them *)typeused={mutableused:bool}typet={env_var:(mix_type_scheme*used)Id.Map.t;(** Type schemes of bound variables *)env_cst:UF.eltglb_typexprUF.t;(** Unification state *)env_als:UF.eltId.Map.tref;(** Map user-facing type variables to unification variables *)env_opn:bool;(** Accept unbound type variables *)env_rec:(KerName.t*int)Id.Map.t;(** Recursive type definitions *)env_strict:bool;(** True iff in strict mode *)}letempty_env?(strict=true)()={env_var=Id.Map.empty;env_cst=UF.create();env_als=refId.Map.empty;env_opn=true;env_rec=Id.Map.empty;env_strict=strict;}letenv_strictenv=env.env_strictletset_recselfenv={envwithenv_rec=self}letreject_unbound_tvarenv={envwithenv_opn=false}letfind_rec_varidenv=Id.Map.find_optidenv.env_recletmem_varidenv=Id.Map.memidenv.env_varletfind_varidenv=lett,used=Id.Map.findidenv.env_varinused.used<-true;tletis_used_varidenv=let_,{used}=Id.Map.findidenv.env_varinusedletbound_varsenv=Id.Map.domainenv.env_varletget_variable0memvar=matchvarwith|RelIdqid->letopenLibnamesinletopenLocusinletid=qualid_basenameqidinifqualid_is_identqid&&memidthenArgVarCAst.(make?loc:qid.CAst.locid)elseletkn=tryTac2env.locate_ltacqidwithNot_found->CErrors.user_err?loc:qid.CAst.locPp.(str"Unbound value "++pr_qualidqid)inArgArgkn|AbsKnkn->ArgArgknletget_variableenvvar=letmemid=Id.Map.memidenv.env_varinget_variable0memvarletenv_nameenv=(* Generate names according to a provided environment *)letmknum=letbase=nummod26inletrem=num/26inletname=String.make1(Char.chr(97+base))inletsuff=ifInt.equalrem0then""elsestring_of_intreminletname=name^suffinnameinletfoldideltacc=UF.Map.addelt(Id.to_stringid)accinletvars=Id.Map.foldfoldenv.env_als.contentsUF.Map.emptyinletvars=refvarsinletrecfreshn=letname=mkninifUF.Map.exists(fun_name'->String.equalnamename')!varsthenfresh(succn)elsenameinfunn->ifUF.Map.memn!varsthenUF.Map.findn!varselseletans=fresh0inlet()=vars:=UF.Map.addnans!varsinansletfresh_idenv=UF.freshenv.env_cstletget_alias{CAst.loc;v=id}env=tryId.Map.findidenv.env_als.contentswithNot_found->ifenv.env_opnthenletn=fresh_idenvinlet()=env.env_als:=Id.Map.addidnenv.env_als.contentsinnelseCErrors.user_err?locPp.(str"Unbound type parameter "++Id.printid)letpush_nameidtenv=matchidwith|Anonymous->env|Nameid->{envwithenv_var=Id.Map.addid(t,{used=false})env.env_var}letpush_idsidsenv=letmerge_fun_freshorig=matchfresh,origwith|None,None->assertfalse|Somex,_->Some(x,{used=false})|None,Somex->Somexin{envwithenv_var=Id.Map.mergemerge_funidsenv.env_var}letrecsubst_typesubst(t:'aglb_typexpr)=matchtwith|GTypVarid->substid|GTypArrow(t1,t2)->GTypArrow(subst_typesubstt1,subst_typesubstt2)|GTypRef(qid,args)->GTypRef(qid,List.map(funt->subst_typesubstt)args)(** First-order unification algorithm *)letis_unfoldablekn=matchsnd(Tac2env.interp_typekn)with|GTydDef(Some_)->true|GTydDefNone|GTydAlg_|GTydRec_|GTydOpn->falseletunfoldenvknargs=let(nparams,def)=Tac2env.interp_typekninletdef=matchdefwith|GTydDef(Somet)->t|_->assertfalseinletargs=Array.of_listargsinletsubstn=args.(n)insubst_typesubstdef(** View function, allows to ensure head normal forms *)letreckindenvt=matchtwith|GTypVarid->let(id,v)=UF.findidenv.env_cstinbeginmatchvwith|None->GTypVarid|Somet->kindenvtend|GTypRef(Otherkn,tl)->ifis_unfoldableknthenkindenv(unfoldenvkntl)elset|GTypArrow_|GTypRef(Tuple_,_)->t(** Normalize unification variables without unfolding type aliases *)letrecnfenvt=matchtwith|GTypVarid->let(id,v)=UF.findidenv.env_cstinbeginmatchvwith|None->GTypVarid|Somet->nfenvtend|GTypRef(kn,tl)->lettl=List.map(funt->nfenvt)tlinGTypRef(kn,tl)|GTypArrow(t,u)->lett=nfenvtinletu=nfenvuinGTypArrow(t,u)letpr_glbtypeenvt=lett=nfenvtinletname=env_nameenvinpr_glbtypenametletnormalizeenv(count,vars)(t:TVar.tglb_typexpr)=letget_varid=tryUF.Map.findid!varswithNot_found->let()=assertenv.env_opninletn=GTypVar!countinlet()=incrcountinlet()=vars:=UF.Map.addidn!varsinninletrecsubstid=matchUF.findidenv.env_cstwith|id,None->get_varid|_,Somet->subst_typesubsttinsubst_typesubsttexceptionOccurletrecoccur_checkenvidt=matchkindenvtwith|GTypVarid'->ifTVar.equalidid'thenraiseOccur|GTypArrow(t1,t2)->let()=occur_checkenvidt1inoccur_checkenvidt2|GTypRef(kn,tl)->List.iter(funt->occur_checkenvidt)tlexceptionCannotUnifyofTVar.tglb_typexpr*TVar.tglb_typexprletunify_varenvidt=matchkindenvtwith|GTypVarid'->ifnot(TVar.equalidid')thenUF.unionidid'env.env_cst|GTypArrow_|GTypRef_->trylet()=occur_checkenvidtinUF.setidtenv.env_cstwithOccur->raise(CannotUnify(GTypVarid,t))leteq_or_tupleeqt1t2=matcht1,t2with|Tuplen1,Tuplen2->Int.equaln1n2|Othero1,Othero2->eqo1o2|_->falseletrecunify0envt1t2=matchkindenvt1,kindenvt2with|GTypVarid,_->unify_varenvidt2|_,GTypVarid->unify_varenvidt1|GTypArrow(t1,u1),GTypArrow(t2,u2)->let()=unify0envt1t2inunify0envu1u2|GTypRef(kn1,tl1),GTypRef(kn2,tl2)->ifeq_or_tupleKerName.equalkn1kn2thenList.iter2(funt1t2->unify0envt1t2)tl1tl2elseraise(CannotUnify(t1,t2))|_->raise(CannotUnify(t1,t2))letunify?locenvt1t2=tryunify0envt1t2withCannotUnify(u1,u2)->CErrors.user_err?locPp.(str"This expression has type"++spc()++pr_glbtypeenvt1++spc()++str"but an expression was expected of type"++spc()++pr_glbtypeenvt2)letunify_arrow?locenvftargs=letft0=ftinletreciterftargsis_fun=matchkindenvft,argswith|t,[]->t|GTypArrow(t1,ft),(loc,t2)::args->let()=unify?locenvt2t1initerftargstrue|GTypVarid,(_,t)::args->letft=GTypVar(fresh_idenv)inlet()=unify?locenv(GTypVarid)(GTypArrow(t,ft))initerftargstrue|GTypRef_,_::_->ifis_funthenCErrors.user_err?locPp.(str"This function has type"++spc()++pr_glbtypeenvft0++spc()++str"and is applied to too many arguments")elseCErrors.user_err?locPp.(str"This expression has type"++spc()++pr_glbtypeenvft0++spc()++str"and is not a function")initerftargsfalseletrecfv_typeftaccu=matchtwith|GTypVarid->fidaccu|GTypArrow(t1,t2)->fv_typeft1(fv_typeft2accu)|GTypRef(kn,tl)->List.fold_left(funaccut->fv_typeftaccu)accutlletfv_envenv=letrecfidaccu=matchUF.findidenv.env_cstwith|id,None->UF.Map.addid()accu|_,Somet->fv_typeftaccuinletfold_varid((_,t),_)accu=letfmixidaccu=matchidwith|LVar_->accu|GVarid->fidaccuinfv_typefmixtaccuinletfv_var=Id.Map.foldfold_varenv.env_varUF.Map.emptyinletfold_als_idaccu=fidaccuinId.Map.foldfold_als!(env.env_als)fv_varletabstract_varenv(t:TVar.tglb_typexpr):mix_type_scheme=letfv=fv_envenvinletcount=ref0inletvars=refUF.Map.emptyinletrecsubstid=let(id,t)=UF.findidenv.env_cstinmatchtwith|None->ifUF.Map.memidfvthenGTypVar(GVarid)elsebegintryUF.Map.findid!varswithNot_found->letn=!countinletvar=GTypVar(LVarn)inlet()=incrcountinlet()=vars:=UF.Map.addidvar!varsinvarend|Somet->subst_typesubsttinlett=subst_typesubsttin(!count,t)letmonomorphic(t:TVar.tglb_typexpr):mix_type_scheme=letsubstid=GTypVar(GVarid)in(0,subst_typesubstt)letpolymorphic((n,t):type_scheme):mix_type_scheme=letsubstid=GTypVar(LVarid)in(n,subst_typesubstt)