123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250moduleB=Kernel.BasicmoduleC=Common.ConstraintsmoduleF=Common.FilesmoduleL=Common.LogmoduleM=Api.MetamoduleP=Api.Pp.DefaultmoduleS=Kernel.SignaturemoduleT=Kernel.TermmoduleU=Common.UniversesmoduleV=Elaboration.Vartypet={env:Api.Env.t;(** The current environement used for type checking *)in_path:F.path;(** path of the original file that should be typed checked *)meta_out:M.cfg;(** Meta configuration to translate back universes of Universo to the original theory universes *)constraints:(B.name,U.pred)Hashtbl.t;(** additional user constraints *)out_file:F.coutF.t;(** File were constraints are written *)}(* This is a reference because we have to use it in the Reduction Engine *)(** [globel_env] is a reference to the current type checking environment. *)letglobal_env:toptionref=refNoneletget=function|None->failwith"Environment not initialized"|Someenv->envletof_global_envenv={C.file=env.out_file;C.meta=env.meta_out}moduleMakeRE(Conv:Kernel.Reduction.ConvChecker):Kernel.Reduction.S=structmodulerecR:Kernel.Reduction.S=Kernel.Reduction.Make(Conv)(Kernel.Matching.Make(R))moduleRule=Kernel.RuleincludeR(** Name for rules that reduce variables. Names are irrelevant for Universo. *)letdummy_name=Rule.Gamma(false,B.mk_name(B.mk_mident"dummy")(B.mk_ident"dummy"))(* FIXME: this rules are not exported hence redundant rules might be added when the current module is impoted somewhere else *)(** [add_rule vl vr] add to the current signature the rule that maps [vl] to [vr]. *)letrecadd_rulevlvr=letpat=Rule.Pattern(B.dloc,vl,[])inletrhs=T.mk_ConstB.dlocvrinletrule=Rule.{ctx=[];pat;rhs;name=dummy_name}inletsg=Api.Env.get_signature(get!global_env).envinS.add_rulessg[Rule.to_rule_infosrule]anduniv_conversionlr=letsg=Api.Env.get_signature(get!global_env).envinifT.term_eqlrthentrueelseif(* If two universes should be equal, then we add the constraint [l =?= r] AND a rule that
makes [l] convertible to [r]. Order matters and is handled by the module U. *)V.is_uvarl&&V.is_uvarrthenC.mk_cstr(of_global_env(get!global_env))add_rule(U.EqVar(V.name_of_uvarl,V.name_of_uvarr))elseifV.is_uvarl&&U.is_enumrthen(letr=U.extract_univrinignore(C.mk_cstr(of_global_env(get!global_env))add_rule(U.Pred(U.Cumul(Var(V.name_of_uvarl),r))));C.mk_cstr(of_global_env(get!global_env))add_rule(U.Pred(U.Cumul(r,Var(V.name_of_uvarl)))))elseifV.is_uvarr&&U.is_enumlthen(letl=U.extract_univlinignore(C.mk_cstr(of_global_env(get!global_env))add_rule(U.Pred(U.Cumul(Var(V.name_of_uvarr),l))));C.mk_cstr(of_global_env(get!global_env))add_rule(U.Pred(U.Cumul(l,Var(V.name_of_uvarr))))(* The witness of a universe constraint is always I. It's type should should be convertible to true. Knowing Dedukti behavior, the expected type is the left one (true) and the right one is the predicate to satisfy *))elseifT.term_eq(U.true_())lthenifU.is_subtyperthenlets=U.extract_subtyperinare_convertiblesg(U.true_())selseifU.is_forallrthenlets=U.extract_forallrinare_convertiblesg(U.true_())selseC.mk_cstr(of_global_env(get!global_env))add_rule(U.Pred(U.extract_predr))(* Encoding of cumulativity uses the rule cast _ _ A A t --> t. Hence, sometimes [lift ss a =?= a]. This case is not capture by the cases above. This quite ugly to be so dependent of that rule, but I have found no nice solution to resolve that one. *)elseifU.is_cast'l&¬(U.is_cast'r)thenlet_,_,a,b,t=U.extract_cast'linare_convertiblesgab&&are_convertiblesgtrelseif(not(U.is_cast'l))&&U.is_cast'rthenlet_,_,a,b,t=U.extract_cast'rinare_convertiblesgab&&are_convertiblesgltelse(* TODO: One should handle one more case with Cumul. Currentl Cumul is assumed being linear but it is hackish because it assumes a theory file where the order of rules matter. In particular, having Cumul linear forces to have the non linear rule for Subtype first. Otherwise, the system is not confluent. However, having Cumul non linear requires to add more cases here. Non linearity should be also handled in matching_test function. *)falseandare_convertible_lstsg:(T.term*T.term)list->bool=function|[]->true|(l,r)::lst->ifT.term_eqlrthenare_convertible_lstsglstelse(*Format.printf "l:%a@." Pp.print_term l;
Format.printf "r:%a@." Pp.print_term r; *)letl',r'=(whnfsgl,whnfsgr)in(* Format.printf "l':%a@." Pp.print_term l';
Format.printf "r':%a@." Pp.print_term r'; *)ifuniv_conversionl'r'thenare_convertible_lstsglstelseare_convertible_lstsg(R.conversion_stepsg(l',r')lst)andare_convertiblesgt1t2=tryare_convertible_lstsg[(t1,t2)]withKernel.Reduction.Not_convertible->falseandconstraint_convertibility_cstrrsgt1t2=ifT.term_eqt1t2thentrueelsematchrwith|Rule.Gamma(_,rn)->(* We need to avoid non linear rule of the theory otherwise we may produce inconsistent constraints: lift s s' a should not always reduce to a.*)ifB.string_of_ident(B.idrn)="id_cast"thenfalseelseare_convertiblesgt1t2|_->are_convertiblesgt1t2endmodulerecRE:Kernel.Reduction.S=MakeRE(RE)moduleTyping=Kernel.Typing.Make(RE)(** [check_user_constraints table name t] checks whether the user has added constraints on the onstant [name] and if so, add this constraint. In [t], every universo variable (md.var) are replaced by the sort associated to the constant [name]. *)letcheck_user_constraints:(B.name,U.pred)Hashtbl.t->B.name->T.term->unit=funconstraintsnamety->letget_uvarty=matchtywith|T.App(_,(T.Const(_,name)ast),_)whenV.is_uvart->name|_->assertfalseinifHashtbl.memconstraintsnamethenletpred=Hashtbl.findconstraintsnameinletuvar=get_uvartyinletreplace_univ:U.univ->U.univ=function|Var_->Varuvar|_ast->tinletreplace:U.pred->U.pred=function|Axiom(s,s')->Axiom(replace_univs,replace_univs')|Cumul(s,s')->Cumul(replace_univs,replace_univs')|Rule(s,s',s'')->Rule(replace_univs,replace_univs',replace_univs'')inignore(C.mk_cstr(of_global_env(get!global_env))(fun_->assertfalse)(U.Pred(replacepred)))(* TODO: universo_env and env should be only one *)(** [mk_entry env e] type checks the entry e in the same way then dkcheck does. However, the convertibility tests is hacked so that we can add constraints dynamically while type checking the term. This is really close to what is done with typical ambiguity in Coq. *)letmk_entry:t->Api.Env.t->Parsers.Entry.entry->unit=fununiverso_envenve->letmoduleE=Parsers.EntryinletmoduleRule=Kernel.Ruleinglobal_env:=Someuniverso_env;letsg=Api.Env.get_signatureuniverso_env.envinlet_add_rulesrs=letris=List.mapRule.to_rule_infosrsinS.add_rulessgrisinmatchewith|Decl(lc,id,sc,st,ty)->(L.log_check"[CHECKING] %a"P.print_identid;check_user_constraintsuniverso_env.constraints(B.mk_name(F.md_ofuniverso_env.in_path`Output)id)ty;Format.fprintf(F.fmt_of_fileuniverso_env.out_file)"@.(; %a ;)@."P.print_identid;matchTyping.inferencesgtywith|Kind|Type_->S.add_declarationsglcidscstty|s->raise(Kernel.Typing.Typing_error(Kernel.Typing.SortExpected(ty,[],s))))|Def(lc,id,sc,opaque,mty,te)->(L.log_check"[CHECKING] %a"P.print_identid;Format.fprintf(F.fmt_of_fileuniverso_env.out_file)"@.(; %a ;)@."P.print_identid;letopenRuleinletty=matchmtywith|None->Typing.inferencesgte|Somety->Typing.checkingsgtety;tyinmatchtywith|Kind->raise(Api.Env.Env_error(env,lc,Kernel.Typing.Typing_errorKernel.Typing.KindIsNotTypable))|_->ifopaquethenS.add_declarationsglcidscS.Statictyelselet_=S.add_declarationsglcidsc(S.DefinableT.Free)tyinletcst=B.mk_name(F.md_of(get!global_env).in_path`Output)idinletrule={name=Deltacst;ctx=[];pat=Pattern(lc,cst,[]);rhs=te;}in_add_rules[rule])|Rules(_,rs)->letopenRuleinlet_=List.map(fun(r:partially_typed_rule)->Format.fprintf(F.fmt_of_fileuniverso_env.out_file)"@.(; %a ;)@."Rule.pp_rule_namer.name;Typing.check_rulesgr)rsin_add_rulesrs|Require_->()(* FIXME: How should we handle a Require command? *)|_->assertfalse(* other commands are not supported by this is only by lazyness. *)