@@ -272,35 +272,17 @@ let apply_hooks env sigma proj pat =
272272 try CString.Map. get name ! all_hooks env sigma proj pat
273273 with e when CErrors. noncritical e -> anomaly Pp. (str " CS hook " ++ str name ++ str " exploded" )) ! active_hooks
274274
275- (* [check_conv_record env sigma (t1,stack1) (t2,stack2)] tries to decompose
276- the problem (t1 stack1) = (t2 stack2) into a problem
277-
278- stack1 = params1@[c1]@extra_args1
279- stack2 = us2@extra_args2
280- t1 params1 c1 = proji params (c xs)
281- t2 us2 = head us
282- extra_args1 = extra_args2
283-
284- by finding a record R and an object c := [xs:bs](Build_R params v1..vn)
285- with vi = (head us), for which we know that the i-th projection proji
286- satisfies
287-
288- proji params (c xs) = head us
289-
290- Rem: such objects, usable for conversion, are defined in the objdef
291- table; practically, it amounts to "canonically" equip t2 into a
292- object c in structure R (since, if c1 were not an evar, the
293- projection would have been reduced) *)
294-
295- let check_conv_record ?metas env sigma (t1 ,sk1 ) (t2 ,sk2 ) =
275+ let decompose_proj ?metas env sigma (t1 , sk1 ) =
296276 (* I only recognize ConstRef projections since these are the only ones for which
297277 I know how to obtain the number of parameters. *)
298278 let (proji, u), arg =
299279 match Termops. global_app_of_constr sigma t1 with
300280 | (Names.GlobRef. ConstRef proji , u ), arg -> (proji, u), arg
301- | _ -> raise Not_found in
281+ | _ -> raise Not_found
282+ | exception _ -> raise Not_found in
302283 (* Given a ConstRef projection, I obtain the structure it is a projection from. *)
303- let structure = Structures.Structure. find_from_projection proji in
284+ let structure = try Structures.Structure. find_from_projection proji
285+ with _ -> raise Not_found in
304286 (* Knowing the structure and hence its number of arguments, I can cut sk1 into pieces. *)
305287 let params1, c1, extra_args1 =
306288 match arg with
@@ -323,6 +305,29 @@ let check_conv_record ?metas env sigma (t1,sk1) (t2,sk2) =
323305 match Reductionops.Stack. strip_n_app structure.nparams sk1 with
324306 | Some (params1 , c1 , extra_args1 ) -> (Reductionops.Stack. list_of_app_stack params1), c1, extra_args1
325307 | _ -> raise Not_found in
308+ ((proji, u), (params1, c1, extra_args1))
309+
310+ (* [check_conv_record env sigma (t1,stack1) (t2,stack2)] tries to decompose
311+ the problem (t1 stack1) = (t2 stack2) into a problem
312+
313+ stack1 = params1@[c1]@extra_args1
314+ stack2 = us2@extra_args2
315+ t1 params1 c1 = proji params (c xs)
316+ t2 us2 = head us
317+ extra_args1 = extra_args2
318+
319+ by finding a record R and an object c := [xs:bs](Build_R params v1..vn)
320+ with vi = (head us), for which we know that the i-th projection proji
321+ satisfies
322+
323+ proji params (c xs) = head us
324+
325+ Rem: such objects, usable for conversion, are defined in the objdef
326+ table; practically, it amounts to "canonically" equip t2 into a
327+ object c in structure R (since, if c1 were not an evar, the
328+ projection would have been reduced) *)
329+
330+ let check_conv_record env sigma ((proji , u ), (params1 , c1 , extra_args1 )) (t2 ,sk2 ) =
326331 let h2, sk2' = decompose_app sigma (shrink_eta sigma t2) in
327332 let sk2 = Stack. append_app sk2' sk2 in
328333 let k = Reductionops.Stack. args_size sk2 - Reductionops.Stack. args_size extra_args1 in
@@ -642,6 +647,32 @@ let infer_conv_noticing_evars ~pb ~ts env sigma t1 t2 =
642647 if ! has_evar then None
643648 else Some (UnifFailure (sigma, UnifUnivInconsistency e))
644649
650+ module Cs_keys_cache = struct
651+ type t = (Names.GlobRef .t Queue .t * state Names.GlobRef.Map .t ) * (Names.GlobRef .t Queue .t * state Names.GlobRef.Map .t )
652+
653+ let empty () : t = ((Queue. create () , Names.GlobRef.Map. empty), (Queue. create () , Names.GlobRef.Map. empty))
654+
655+ let flip (c1 , c2 ) = (c2, c1)
656+
657+ let add_left sigma appr (((c1 , m1 ), c2 ) as c ) =
658+ match fst @@ EConstr. destRef sigma (fst appr) with
659+ | k when not (Names.GlobRef.Map. mem k m1) ->
660+ let () = Queue. push k c1 in
661+ ((c1, Names.GlobRef.Map. add k appr m1), c2)
662+ | _ | exception DestKO -> c
663+
664+ let add sigma l2r appr c =
665+ if l2r then add_left sigma appr c else flip (add_left sigma appr (flip c))
666+
667+ let fold_left f acc ((c , m ), _ ) = Queue. fold (fun acc k -> f acc (Names.GlobRef.Map. find k m)) acc c
668+ let fold l2r f acc c = fold_left f acc (if l2r then c else flip c)
669+
670+ let clear_left ((c , _ ), _ ) = Queue. clear c
671+
672+ let clear l2r c =
673+ if l2r then clear_left c else clear_left (flip c)
674+ end
675+
645676let rec evar_conv_x flags env evd pbty term1 term2 =
646677 let term1 = whd_head_evar evd term1 in
647678 let term2 = whd_head_evar evd term2 in
@@ -662,7 +693,7 @@ let rec evar_conv_x flags env evd pbty term1 term2 =
662693 let term2 = apprec_nohdbeta flags env evd term2 in
663694 let default () =
664695 match
665- evar_eqappr_x flags env evd pbty
696+ evar_eqappr_x flags env evd pbty ( Cs_keys_cache. empty () ) None
666697 (whd_nored_state env evd (term1,Stack. empty))
667698 (whd_nored_state env evd (term2,Stack. empty))
668699 with
@@ -699,6 +730,8 @@ let rec evar_conv_x flags env evd pbty term1 term2 =
699730 end
700731
701732and evar_eqappr_x ?(rhs_is_already_stuck = false ) flags env evd pbty
733+ keys (* canonical structure keys cache *)
734+ lastUnfolded (* tells which side was last unfolded, if any *)
702735 (term1 , sk1 as appr1 ) (term2 , sk2 as appr2 ) =
703736 let quick_fail i = (* not costly, loses info *)
704737 UnifFailure (i, NotSameHead )
@@ -736,8 +769,8 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
736769 flags.open_ts env' evd (c'1 , Stack. empty) in
737770 let out2 = whd_nored_state env' evd
738771 (lift 1 (Stack. zip evd (term', sk')), Stack. append_app [|EConstr. mkRel 1 |] Stack. empty) in
739- if onleft then evar_eqappr_x flags env' evd CONV out1 out2
740- else evar_eqappr_x flags env' evd CONV out2 out1
772+ if onleft then evar_eqappr_x flags env' evd CONV keys None out1 out2
773+ else evar_eqappr_x flags env' evd CONV ( Cs_keys_cache. flip keys) None out2 out1
741774 in
742775 let rigids env evd sk term sk' term' =
743776 let nargs = Stack. args_size sk in
@@ -777,7 +810,7 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
777810 3. reduce the redex into M and recursively solve E[?n[inst]] =? E'[M] *)
778811 let switch f a b = if l2r then f a b else f b a in
779812 let delta i =
780- switch (evar_eqappr_x flags env i pbty) apprF
813+ switch (evar_eqappr_x flags env i pbty keys None ) apprF
781814 (whd_betaiota_deltazeta_for_iota_state flags.open_ts env i vskM)
782815 in
783816 let default i = ise_try i [miller l2r ev apprF apprM;
@@ -800,7 +833,7 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
800833 whd_betaiota_deltazeta_for_iota_state flags.open_ts env evd (termM',skM)
801834 in
802835 let delta' i =
803- switch (evar_eqappr_x flags env i pbty) apprF apprM'
836+ switch (evar_eqappr_x flags env i pbty keys None ) apprF apprM'
804837 in
805838 fun i -> ise_try i [miller l2r ev apprF apprM';
806839 consume l2r apprF apprM'; delta']
@@ -867,7 +900,7 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
867900 (position_problem true pbty,destEvar i' ev1',term2)
868901 else
869902 (* HH: Why not to drop sk1 and sk2 since they unified *)
870- evar_eqappr_x flags env evd pbty
903+ evar_eqappr_x flags env evd pbty keys None
871904 (ev1', sk1) (term2, sk2)
872905 | Some (r ,[] ), Success i' ->
873906 (* We have sk1'[] = sk2[] for some sk1' s.t. sk1[]=sk1'[r[]] *)
@@ -877,7 +910,7 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
877910 solve_simple_eqn (conv_fun evar_conv_x) flags env i'
878911 (position_problem false pbty,destEvar i' ev2',Stack. zip i' (term1,r))
879912 else
880- evar_eqappr_x flags env evd pbty
913+ evar_eqappr_x flags env evd pbty keys None
881914 (ev2', sk1) (term2, sk2)
882915 | Some ([] ,r ), Success i' ->
883916 (* Symmetrically *)
@@ -889,7 +922,7 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
889922 (position_problem true pbty,destEvar i' ev1',Stack. zip i' (term2,r))
890923 else
891924 (* HH: Why not to drop sk1 and sk2 since they unified *)
892- evar_eqappr_x flags env evd pbty
925+ evar_eqappr_x flags env evd pbty keys None
893926 (ev1', sk1) (term2, sk2)
894927 | None , (UnifFailure _ as x ) ->
895928 (* sk1 and sk2 have no common outer part *)
@@ -923,6 +956,42 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
923956 in
924957 let app_empty = match sk1, sk2 with [] , [] -> true | _ -> false in
925958 (* Evar must be undefined since we have flushed evars *)
959+ let keys = Cs_keys_cache. add evd true appr1 keys in
960+ let keys = Cs_keys_cache. add evd false appr2 keys in
961+ let get_cs env sigma l2r keys nokey appr1 appr2 =
962+ let appr1, appr2 = if l2r then appr1, appr2 else appr2, appr1 in
963+ try
964+ let (_, (_, c1, _)) as p1 = decompose_proj env sigma appr1 in
965+ let kill, reduce =
966+ (* TOTHINK: Should I keep c1 simplified? *)
967+ let c1 = whd_all env sigma c1 in
968+ (* [proj (ctor ...)]: don't use CS *)
969+ match kind sigma c1 with
970+ | App (h ,_ ) when isConstruct sigma h -> true , true
971+ | Construct _ -> true , true
972+ | _ -> not (has_undefined_evars_or_metas sigma c1), false in
973+ let x =
974+ if nokey then
975+ (try Some (check_conv_record env sigma p1 appr2)
976+ with Not_found -> None )
977+ else
978+ let x = Cs_keys_cache. fold (not l2r) (fun r appr ->
979+ match r with
980+ | None ->
981+ (try Some (check_conv_record env sigma p1 appr)
982+ with | Not_found -> None )
983+ | _ -> r) None keys in
984+ (* If t is not a reference, it was not added to the keys cache, so we take care of it now. *)
985+ match x with
986+ | None when not (EConstr. isRef sigma (fst appr2)) ->
987+ (try Some (check_conv_record env sigma p1 appr2)
988+ with Not_found -> None )
989+ | _ -> x in
990+ if kill then Inr (reduce && (match x with | None -> false | _ -> true )) else
991+ (* The projection constant will not change, so there is no point in keeping the keys anymore. *)
992+ let () = Cs_keys_cache. clear (not l2r) keys in
993+ match x with | Some x -> Inl x | _ -> Inr false
994+ with _ -> Inr false in
926995 let () = debug_unification (fun () -> Pp. (v 0 (pr_state env evd appr1 ++ cut () ++ pr_state env evd appr2 ++ cut () ))) in
927996 match (flex_kind_of_term flags env evd term1 sk1,
928997 flex_kind_of_term flags env evd term2 sk2) with
@@ -991,7 +1060,7 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
9911060 and f2 i =
9921061 let out1 = whd_betaiota_deltazeta_for_iota_state flags.open_ts env i vsk1'
9931062 and out2 = whd_betaiota_deltazeta_for_iota_state flags.open_ts env i vsk2'
994- in evar_eqappr_x flags env i pbty out1 out2
1063+ in evar_eqappr_x flags env i pbty keys None out1 out2
9951064 in
9961065 ise_try evd [f1; f2]
9971066
@@ -1003,7 +1072,7 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
10031072 and f2 i =
10041073 let out1 = whd_betaiota_deltazeta_for_iota_state flags.open_ts env i vsk1'
10051074 and out2 = whd_betaiota_deltazeta_for_iota_state flags.open_ts env i vsk2'
1006- in evar_eqappr_x flags env i pbty out1 out2
1075+ in evar_eqappr_x flags env i pbty keys None out1 out2
10071076 in
10081077 ise_try evd [f1; f2]
10091078
@@ -1015,7 +1084,7 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
10151084 in
10161085 (match res with
10171086 | Some (f1 ,args1 ) ->
1018- evar_eqappr_x flags env evd pbty (f1,Stack. append_app args1 sk1)
1087+ evar_eqappr_x flags env evd pbty keys None (f1,Stack. append_app args1 sk1)
10191088 appr2
10201089 | None -> UnifFailure (evd,NotSameHead ))
10211090
@@ -1026,10 +1095,12 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
10261095 in
10271096 (match res with
10281097 | Some (f2 ,args2 ) ->
1029- evar_eqappr_x flags env evd pbty appr1 (f2,Stack. append_app args2 sk2)
1098+ evar_eqappr_x flags env evd pbty keys None appr1 (f2,Stack. append_app args2 sk2)
10301099 | None -> UnifFailure (evd,NotSameHead ))
10311100
10321101 | _ , _ ->
1102+ (* We remember if the LHS is a reducible projection to decide if we unfold left first. *)
1103+ let no_cs1 = ref false in
10331104 let f1 i =
10341105 (* Gather the universe constraints that would make term1 and term2 equal.
10351106 If these only involve unifications of flexible universes to other universes,
@@ -1050,8 +1121,13 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
10501121 (try
10511122 if not flags.with_cs then raise Not_found
10521123 else conv_record flags env
1053- (try check_conv_record env i appr1 appr2
1054- with Not_found -> check_conv_record env i appr2 appr1)
1124+ (match get_cs env i true keys (lastUnfolded = Some true ) appr1 appr2 with
1125+ | Inl x -> x
1126+ | Inr b ->
1127+ let () = no_cs1 := b in
1128+ (match get_cs env i false keys (lastUnfolded = Some false ) appr1 appr2 with
1129+ | Inl x -> x
1130+ | Inr _ -> raise Not_found ))
10551131 with Not_found -> UnifFailure (i,NoCanonicalStructure ))
10561132 and f3 i =
10571133 (* heuristic: unfold second argument first, exception made
@@ -1079,16 +1155,21 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
10791155 let rhs_is_already_stuck =
10801156 rhs_is_already_stuck || rhs_is_stuck_and_unnamed () in
10811157
1082- if (EConstr. isLambda i term1 || rhs_is_already_stuck)
1083- && (not (Stack. not_purely_applicative sk1')) then
1084- evar_eqappr_x ~rhs_is_already_stuck flags env i pbty
1085- (whd_betaiota_deltazeta_for_iota_state
1086- flags.open_ts env i vsk1')
1087- appr2
1088- else
1089- evar_eqappr_x flags env i pbty appr1
1090- (whd_betaiota_deltazeta_for_iota_state
1091- flags.open_ts env i vsk2')
1158+ let b = EConstr. isLambda i term1 || rhs_is_already_stuck
1159+ && (not (Stack. not_purely_applicative sk1')) in
1160+ ise_try i [
1161+ (fun i ->
1162+ if b || ! no_cs1 then
1163+ evar_eqappr_x flags env i pbty keys (Some false )
1164+ (whd_betaiota_deltazeta_for_iota_state
1165+ flags.open_ts env i vsk1')
1166+ appr2
1167+ else quick_fail i);
1168+ fun i ->
1169+ if b then quick_fail i else
1170+ evar_eqappr_x flags env i pbty keys (Some true ) appr1
1171+ (whd_betaiota_deltazeta_for_iota_state
1172+ flags.open_ts env i vsk2')]
10921173 in
10931174 ise_try evd [f1; f2; f3]
10941175 end
@@ -1112,10 +1193,13 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
11121193 let f3 i =
11131194 (try
11141195 if not flags.with_cs then raise Not_found
1115- else conv_record flags env (check_conv_record env i appr1 appr2)
1196+ else conv_record flags env (
1197+ match get_cs env i true keys false appr1 appr2 with
1198+ | Inl x -> x
1199+ | Inr _ -> raise Not_found )
11161200 with Not_found -> UnifFailure (i,NoCanonicalStructure ))
11171201 and f4 i =
1118- evar_eqappr_x flags env i pbty
1202+ evar_eqappr_x flags env i pbty keys ( Some false )
11191203 (whd_betaiota_deltazeta_for_iota_state
11201204 flags.open_ts env i vsk1')
11211205 appr2
@@ -1126,10 +1210,13 @@ and evar_eqappr_x ?(rhs_is_already_stuck = false) flags env evd pbty
11261210 let f3 i =
11271211 (try
11281212 if not flags.with_cs then raise Not_found
1129- else conv_record flags env (check_conv_record env i appr2 appr1)
1213+ else conv_record flags env (
1214+ match get_cs env i false keys false appr1 appr2 with
1215+ | Inl x -> x
1216+ | Inr _ -> raise Not_found )
11301217 with Not_found -> UnifFailure (i,NoCanonicalStructure ))
11311218 and f4 i =
1132- evar_eqappr_x flags env i pbty appr1
1219+ evar_eqappr_x flags env i pbty keys ( Some true ) appr1
11331220 (whd_betaiota_deltazeta_for_iota_state
11341221 flags.open_ts env i vsk2')
11351222 in
0 commit comments