@@ -2568,6 +2568,181 @@ let t_congr (f1, f2) (args, ty) tc =
25682568 in
25692569 doit (List. rev args) ty tc
25702570
2571+ (* -------------------------------------------------------------------- *)
2572+ (* Read the equality (or iff) at the head of the goal and return:
2573+ - the two sides [f1, f2];
2574+ - [t_ensure_eq], a tactic that coerces an iff goal to an eq goal;
2575+ - [t_subgoal], the auto-discharge tactic for trivial side goals
2576+ (alpha-reflexivity and alpha-assumption).
2577+ It is the caller's responsibility to have checked that the goal is an
2578+ equality or an equivalence (e.g. via [EcFol.is_eq_or_iff]). *)
2579+ let congr_split_eq_or_iff tc =
2580+ let concl = FApi. tc1_goal tc in
2581+ assert (EcFol. is_eq_or_iff concl);
2582+
2583+ let ((f1, f2), iseq) =
2584+ if EcFol. is_eq concl
2585+ then (EcFol. destr_eq concl, true )
2586+ else (EcFol. destr_iff concl, false ) in
2587+
2588+ let t_ensure_eq =
2589+ if iseq then t_id
2590+ else
2591+ (fun tc ->
2592+ let hyps = FApi. tc1_hyps tc in
2593+ Apply. t_apply_bwd_r
2594+ (PT. pt_of_uglobal !! tc hyps LG. p_eq_iff) tc) in
2595+
2596+ let t_subgoal =
2597+ FApi. t_ors [t_reflex ~mode: `Alpha ; t_assumption `Alpha ; t_id] in
2598+
2599+ (f1, f2, t_ensure_eq, t_subgoal)
2600+
2601+ (* -------------------------------------------------------------------- *)
2602+ (* Discharge an equality goal whose two sides are [skel[xi := Li]] and
2603+ [skel[xi := Ri]] (up to beta), by:
2604+ 1. coercing iff to eq if needed;
2605+ 2. changing the goal to [(\xi. skel) Li... = (\xi. skel) Ri...];
2606+ 3. unfolding the congruence one step per hole with [t_congr];
2607+ 4. auto-closing trivial side goals.
2608+ The goal type is read from [f1.f_ty]; [holes], [lvec] and [rvec] must
2609+ have the same length, and each [Li/Ri] must have the type of [xi]. *)
2610+ let t_congr_from_skeleton ~holes ~skel ~lvec ~rvec tc =
2611+ let (f1, _f2, t_ensure_eq, t_subgoal) = congr_split_eq_or_iff tc in
2612+
2613+ if List. is_empty holes then
2614+ FApi. t_seq t_ensure_eq t_reflex tc
2615+ else
2616+ let ty = f1.f_ty in
2617+ let bds = List. map (fun (x , t ) -> (x, GTty t)) holes in
2618+ let lam = f_lambda bds skel in
2619+ let app_lhs = f_app lam lvec ty in
2620+ let app_rhs = f_app lam rvec ty in
2621+ let newgoal = f_eq app_lhs app_rhs in
2622+ let pairs = List. combine lvec rvec in
2623+ let tcgr = t_congr (lam, lam) (pairs, ty) in
2624+ FApi. t_seqs
2625+ [t_ensure_eq;
2626+ (fun tc -> FApi. tcenv_of_tcenv1 (t_change1 newgoal tc));
2627+ tcgr;
2628+ t_subgoal]
2629+ tc
2630+
2631+ (* -------------------------------------------------------------------- *)
2632+ (* [congr pat]: pattern matches both sides of an equality/iff goal; one
2633+ subgoal per pattern variable (skipping syntactically-equal sides).
2634+ - [pat] is the elaborated pattern formula (containing free [f_local]s
2635+ for each pattern variable);
2636+ - [pvars] is the list of pattern-variable identifiers;
2637+ - [ue] is the unification environment from pattern elaboration. *)
2638+ let t_congr_pattern ~pat ~pvars ~ue tc =
2639+ let (env, hyps, _concl) = FApi. tc1_eflat tc in
2640+ let (f1, f2, _, _) = congr_split_eq_or_iff tc in
2641+
2642+ let ev0 = MEV. of_idents pvars `Form in
2643+
2644+ let match_side label side =
2645+ let ue' = EcUnify.UniEnv. copy ue in
2646+ try
2647+ let (ue'', _, ev'') =
2648+ f_match fmsearch hyps (ue', ev0) pat side
2649+ in (ue'', ev'')
2650+ with MatchFailure ->
2651+ tc_error !! tc " pattern does not match %s of the goal" label
2652+ in
2653+
2654+ let (ueL, evL) = match_side " left-hand side" f1 in
2655+ let (ueR, evR) = match_side " right-hand side" f2 in
2656+
2657+ let substL = MEV. assubst ueL evL env in
2658+ let substR = MEV. assubst ueR evR env in
2659+
2660+ let holes_full =
2661+ List. map (fun x ->
2662+ let probe_ty = EcUnify.UniEnv. fresh ueL in
2663+ let probe = f_local x probe_ty in
2664+ let li = Fsubst. f_subst substL probe in
2665+ let ri = Fsubst. f_subst substR probe in
2666+ (x, li.f_ty, li, ri)
2667+ ) pvars
2668+ in
2669+
2670+ let kept, dropped =
2671+ List. partition
2672+ (fun (_ , _ , li , ri ) -> not (is_alpha_eq hyps li ri))
2673+ holes_full
2674+ in
2675+
2676+ let holes = List. map (fun (x , t , _ , _ ) -> (x, t)) kept in
2677+ let lvec = List. map (fun (_ , _ , l , _ ) -> l) kept in
2678+ let rvec = List. map (fun (_ , _ , _ , r ) -> r) kept in
2679+
2680+ let skel =
2681+ List. fold_left
2682+ (fun acc (x , _ , li , _ ) -> Fsubst. f_subst_local x li acc)
2683+ pat dropped
2684+ in
2685+
2686+ t_congr_from_skeleton ~holes ~skel ~lvec ~rvec tc
2687+
2688+ (* -------------------------------------------------------------------- *)
2689+ (* [congr *]: walk LHS/RHS in lock-step without reduction; emit one
2690+ subgoal per pair of differing positions. Binders are opaque. *)
2691+ let t_congr_star tc =
2692+ let (env, hyps, _concl) = FApi. tc1_eflat tc in
2693+ let (f1, f2, _, _) = congr_split_eq_or_iff tc in
2694+
2695+ let holes = ref [] in
2696+ let lvec = ref [] in
2697+ let rvec = ref [] in
2698+
2699+ let mk_hole (l : form ) (r : form ) : form =
2700+ let x = EcIdent. create " _x" in
2701+ holes := (x, l.f_ty) :: ! holes;
2702+ lvec := l :: ! lvec;
2703+ rvec := r :: ! rvec;
2704+ f_local x l.f_ty
2705+ in
2706+
2707+ let rec walk (l : form ) (r : form ) : form =
2708+ if is_alpha_eq hyps l r then
2709+ l
2710+ else
2711+ match l.f_node, r.f_node with
2712+ | Fapp (hL, aL), Fapp (hR, aR)
2713+ when is_alpha_eq hyps hL hR
2714+ && List. length aL = List. length aR
2715+ && EqTest. for_type env l.f_ty r.f_ty ->
2716+ let args' = List. map2 walk aL aR in
2717+ f_app hL args' l.f_ty
2718+
2719+ | Fif (cL , tL , eL ), Fif (cR , tR , eR ) ->
2720+ let c' = walk cL cR in
2721+ let t' = walk tL tR in
2722+ let e' = walk eL eR in
2723+ f_if c' t' e'
2724+
2725+ | Ftuple xs , Ftuple ys when List. length xs = List. length ys ->
2726+ let zs = List. map2 walk xs ys in
2727+ f_tuple zs
2728+
2729+ | Fproj (xL, iL), Fproj (xR, iR)
2730+ when iL = iR && EqTest. for_type env l.f_ty r.f_ty ->
2731+ f_proj (walk xL xR) iL l.f_ty
2732+
2733+ | _ , _ ->
2734+ if not (EqTest. for_type env l.f_ty r.f_ty) then
2735+ tc_error !! tc " congr*: cannot equate subterms of different types" ;
2736+ mk_hole l r
2737+ in
2738+
2739+ let skel = walk f1 f2 in
2740+ let holes = List. rev ! holes in
2741+ let lvec = List. rev ! lvec in
2742+ let rvec = List. rev ! rvec in
2743+
2744+ t_congr_from_skeleton ~holes ~skel ~lvec ~rvec tc
2745+
25712746(* -------------------------------------------------------------------- *)
25722747type smtmode = [`Sloppy | `Strict | `Report of EcLocation .t option ]
25732748
0 commit comments