123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155openUtilsLib.UtilsopenLambdamoduleLog=(valLogs.src_log(Logs.Src.create"ACGtkLib.typeInference"~doc:"logs ACGtkLib typeInference events"):Logs.LOG)moduleValue=structtypet=inttypevalue=Lambda.stypeletunfoldstype_=matchstypewith|Lambda.Atom_->None|Lambda.LFun(a,b)->Some(1,[a;b])|Lambda.Fun(a,b)->Some(1,[a;b])|_->failwith"Bug: No type inference on these types"endmoduleUF=VarUnionFind.UF(Value)moduleType=structexceptionNot_typabletypetyping_env={l_level:int;nl_level:int;lvar_typing:intIntMap.t;nlvar_typing:intIntMap.t;const_typing:(int*int)IntMap.t;(* maps the occurrence position, which is unique,
to a pair consisting of the type variable and the
constant identifier *)cst_nbr:int;type_equations:UF.t;}letempty_env={l_level=0;nl_level=0;lvar_typing=IntMap.empty;nlvar_typing=IntMap.empty;const_typing=IntMap.empty;cst_nbr=0;type_equations=UF.empty;}lettype_equation_log_eq=Log.debug(funm->m"type equation:");UF.log_contentLogs.Debugeqletrecinference_auxleveltty_varenv=letprefix=String.make(level*3)' 'inLog.debug(funm->m"%sType inference of %s (currently %d)."prefix(Lambda.raw_to_stringt)ty_var);Log.debug(funm->m"%sEquations are:"prefix);type_equation_logprefixenv.type_equations;letty,new_env=matchtwith|Lambda.Vari->(tryletty_in_env=IntMap.find(env.nl_level-i-1)env.nlvar_typinginLog.debug(funm->m"%sAdding an equation (variable found in the environment) %d<-->%d"prefixty_varty_in_env);letnew_eq=UF.unionty_varty_in_envenv.type_equationsinty_var,{envwithtype_equations=new_eq}with|Not_found->letnew_var,new_eq=UF.generate_new_varenv.type_equationsinLog.debug(funm->m"%sAdding a new variable %d and an equation"prefixnew_var);new_var,{envwithnlvar_typing=IntMap.addinew_varenv.nlvar_typing;type_equations=new_eq})|Lambda.LVari->(tryletty_in_env=IntMap.find(env.l_level-i-1)env.lvar_typinginLog.debug(funm->m"%sAdding an equation (Lvariable found in the environment) %d<-->%d"prefixty_varty_in_env);letnew_eq=UF.unionty_varty_in_envenv.type_equationsinty_var,{envwithtype_equations=new_eq}with|Not_found->letnew_var,new_eq=UF.generate_new_varenv.type_equationsinLog.debug(funm->m"%sAdding a new Lvariable %d and an equation"prefixnew_var);new_var,{envwithlvar_typing=IntMap.addinew_varenv.lvar_typing;type_equations=new_eq})|Lambda.Consti->(* Each occurence of a constants is considered as a new free
variables *)letnew_var,new_eq=UF.generate_new_varenv.type_equationsinletnew_eq=UF.unionty_varnew_varnew_eqinnew_var,{envwithtype_equations=new_eq;const_typing=IntMap.add(env.cst_nbr+1)(new_var,i)env.const_typing;cst_nbr=env.cst_nbr+1}|Lambda.DConst_->failwith"Bug: there should not remain any defined constant when computing the principal type"|Lambda.Abs(_x,t)->Log.debug(funm->m"%sType inference of an abstraction:"prefix);letalpha,new_eq=UF.generate_new_varenv.type_equationsinLog.debug(funm->m"%sAdded a variable at %d. Equations are:"prefixalpha);let()=type_equation_logprefixnew_eqinletbeta,new_eq=UF.generate_new_varnew_eqinLog.debug(funm->m"%sAdded a variable at %d. Equations are:"prefixbeta);let()=type_equation_logprefixnew_eqinletnew_const,new_eq=UF.generate_new_constrnew_eq(1,[alpha;beta])inLog.debug(funm->m"%sAdded new const at %d. Equations are:"prefixnew_const);let()=type_equation_logprefixnew_eqinLog.debug(funm->m"%sPreparing a Union %d %d."prefixty_varnew_const);letnew_eq=UF.unionty_varnew_constnew_eqinLog.debug(funm->m"%sAdded a varibale at %d. Equations are:"prefixbeta);type_equation_logprefixnew_eq;let_,new_env=inference_aux(level+1)tbeta{envwithnl_level=env.nl_level+1;nlvar_typing=IntMap.addenv.nl_levelalphaenv.nlvar_typing;type_equations=new_eq}inlet_is_cyclic,new_eq=UF.cyclicty_varnew_env.type_equationsinty_var,{envwithtype_equations=new_eq;const_typing=new_env.const_typing;cst_nbr=new_env.cst_nbr}|Lambda.LAbs(_x,t)->Log.debug(funm->m"%sType inference of a linear abstraction:"prefix);letalpha,new_eq=UF.generate_new_varenv.type_equationsinletbeta,new_eq=UF.generate_new_varnew_eqinletnew_const,new_eq=UF.generate_new_constrnew_eq(1,[alpha;beta])inletnew_eq=UF.unionty_varnew_constnew_eqinlet_,new_env=inference_aux(level+1)tbeta{envwithl_level=env.l_level+1;lvar_typing=IntMap.addenv.l_levelalphaenv.lvar_typing;type_equations=new_eq}inlet_is_cyclic,new_eq=UF.cyclicty_varnew_env.type_equationsinty_var,{envwithtype_equations=new_eq;const_typing=new_env.const_typing;cst_nbr=new_env.cst_nbr}(* ty_var,{new_env with type_equations=new_eq;lvar_typing=env.lvar_typing} *)(* ty_var,{new_env with type_equations=new_eq} *)|Lambda.App(t,u)->letu_type,new_eq=UF.generate_new_varenv.type_equationsinlett_type,new_eq=UF.generate_new_constrnew_eq(1,[u_type;ty_var])inLog.debug(funm->m"%sType inference of the parameter in an application:"prefix);let_u_type,new_env=inference_aux(level+1)uu_type{envwithtype_equations=new_eq}inLog.debug(funm->m"%sType inference of the functor in an application:"prefix);let_t_type,new_env=inference_aux(level+1)tt_typenew_envinty_var,new_env|_->failwith"Bug: No principal typing algorithm for these types"inletis_cyclic,new_eq=UF.cyclictynew_env.type_equationsinifis_cyclicthenraiseNot_typableelsety,{new_envwithtype_equations=new_eq}letrecbuild_typeitype_eq=let(i,v),type_eq=UF.finditype_eqinmatchvwith|UF.Link_tojwhenj=i->Lambda.Atom(-i)|UF.Link_to_->failwith"Bug: when UF.find returns a Link_to, it should be a Link_to itself"|UF.Value_->failwith"Bug: when performing type inference for principal typing, no type constant should appear"|UF.Constr(_c,[alpha;beta])->letalpha'=build_typealphatype_eqinletbeta'=build_typebetatype_eqinLambda.Fun(alpha',beta')|UF.Constr_->failwith"Bug: when performing type inference for principal typing, the only allowd type construction is the arrow"letinferencet=tryletvars=UF.emptyinletty,vars=UF.generate_new_varvarsinletty,env=inference_aux0tty{empty_envwithtype_equations=vars}inbuild_typetyenv.type_equations,IntMap.map(fun(ty,i)->Lambda.Consti,build_typetyenv.type_equations)env.const_typingwith|UF.Union_Failure->raiseNot_typableend