123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143openProofviewletconstants=ref([]:EConstr.tlist)(* This is a pattern to collect terms from the Coq memory of valid terms
and proofs. This pattern extends all the way to the definition of function
c_U *)letcollect_constants()=if(!constants=[])thenletopenEConstrinletopenUnivGeninletfind_reference=Coqlib.find_reference[@ocaml.warning"-3"]inletgr_H=find_reference"Tuto3"["Tuto3";"Data"]"pack"inletgr_M=find_reference"Tuto3"["Tuto3";"Data"]"packer"inletgr_R=find_reference"Tuto3"["Coq";"Init";"Datatypes"]"pair"inletgr_P=find_reference"Tuto3"["Coq";"Init";"Datatypes"]"prod"inletgr_U=find_reference"Tuto3"["Tuto3";"Data"]"uncover"inconstants:=List.map(funx->of_constr(constr_of_monomorphic_global(Global.env())x))[gr_H;gr_M;gr_R;gr_P;gr_U];!constantselse!constantsletc_H()=matchcollect_constants()withit::_->it|_->failwith"could not obtain an internal representation of pack"letc_M()=matchcollect_constants()with_::it::_->it|_->failwith"could not obtain an internal representation of pack_marker"letc_R()=matchcollect_constants()with_::_::it::_->it|_->failwith"could not obtain an internal representation of pair"letc_P()=matchcollect_constants()with_::_::_::it::_->it|_->failwith"could not obtain an internal representation of prod"letc_U()=matchcollect_constants()with_::_::_::_::it::_->it|_->failwith"could not obtain an internal representation of prod"(* The following tactic is meant to pack an hypothesis when no other
data is already packed.
The main difficulty in defining this tactic is to understand how to
construct the input expected by apply_in. *)letpackagei=Goal.enterbeginfungl->Tactics.apply_intruefalsei[(* this means that the applied theorem is not to be cleared. *)None,(CAst.make(c_M(),(* we don't specialize the theorem with extra values. *)Tactypes.NoBindings))](* we don't destruct the result according to any intro_pattern *)Noneend(* This function is meant to observe a type of shape (f a)
and return the value a. *)(* Remark by Maxime: look for destApp combinator. *)letunpack_typesigmaterm=letreport()=CErrors.user_err(Pp.str"expecting a packed type")inmatchEConstr.kindsigmatermwith|Constr.App(_,[|ty|])->ty|_->report()(* This function is meant to observe a type of shape
A -> pack B -> C and return A, B, C
but it is not used in the current version of our tactic.
It is kept as an example. *)lettwo_lambda_patternsigmaterm=letreport()=CErrors.user_err(Pp.str"expecting two nested implications")in(* Note that pattern-matching is always done through the EConstr.kind function,
which only provides one-level deep patterns. *)matchEConstr.kindsigmatermwith(* Here we recognize the outer implication *)|Constr.Prod(_,ty1,l1)->(* Here we recognize the inner implication *)(matchEConstr.kindsigmal1with|Constr.Prod(n2,packed_ty2,deep_conclusion)->(* Here we recognized that the second type is an application *)ty1,unpack_typesigmapacked_ty2,deep_conclusion|_->report())|_->report()(* In the environment of the goal, we can get the type of an assumption
directly by a lookup. The other solution is to call a low-cost retyping
function like *)letget_type_of_hypenvid=matchEConstr.lookup_namedidenvwith|Context.Named.Declaration.LocalAssum(_,ty)->ty|_->CErrors.user_err(letopenPpinstr(Names.Id.to_stringid)++str" is not a plain hypothesis")letrepackageih_hyps_id=Goal.enterbeginfungl->letenv=Goal.envglinletsigma=Tacmach.projectglinletconcl=Tacmach.pf_conclglinlet(ty1:EConstr.t)=get_type_of_hypenviinlet(packed_ty2:EConstr.t)=get_type_of_hypenvh_hyps_idinletty2=unpack_typesigmapacked_ty2inletnew_packed_type=EConstr.mkApp(c_P(),[|ty1;ty2|])inletopenEConstrinletnew_packed_value=mkApp(c_R(),[|ty1;ty2;mkVari;mkApp(c_U(),[|ty2;mkVarh_hyps_id|])|])inRefine.refine~typecheck:truebeginfunsigma->letsigma,new_goal=Evarutil.new_evarenvsigma(mkArrowR(mkApp(c_H(),[|new_packed_type|]))(Vars.lift1concl))insigma,mkApp(new_goal,[|mkApp(c_M(),[|new_packed_type;new_packed_value|])|])endendletpack_tactici=leth_hyps_id=(Names.Id.of_string"packed_hyps")inProofview.Goal.enterbeginfungl->lethyps=Environ.named_context_val(Proofview.Goal.envgl)inifnot(Termops.mem_named_context_valihyps)then(CErrors.user_err(Pp.str("no hypothesis named"^(Names.Id.to_stringi))))elseifTermops.mem_named_context_valh_hyps_idhypsthentclTHEN(repackageih_hyps_id)(tclTHEN(Tactics.clear[h_hyps_id;i])(Tactics.introductionh_hyps_id))elsetclTHEN(packagei)(tclTHEN(Tactics.rename_hyp[i,h_hyps_id])(Tactics.move_hyph_hyps_idLogic.MoveLast))end