@@ -258,6 +258,8 @@ module type CONFIG = sig
258258 val use_real : bool
259259 val branch_coverage : out_channel option
260260 val track_throw : bool
261+ val needs_cleanup : bool
262+ val unreach_exceptions : bool
261263end
262264
263265module IdGraph = Graph. Make (Id )
@@ -727,6 +729,126 @@ module Make (C : CONFIG) = struct
727729 end
728730 | AP_nil _ -> ([ijump l (V_call (Bnot , [V_call (List_is_empty , [cval])])) case_label], [] , [] , ctx)
729731
732+ let rec compile_match_no_jump ctx (AP_aux (apat_aux , env , l )) cval =
733+ let ctx = { ctx with local_env = env } in
734+ let ctyp = cval_ctyp cval in
735+ match apat_aux with
736+ | AP_global (pid , typ ) ->
737+ let global_ctyp = ctyp_of_typ ctx typ in
738+ ([
739+ (None , [icopy l (CL_id (name pid, global_ctyp)) cval], [] )
740+ ], ctx)
741+ | AP_id (pid , _ ) when is_ct_enum ctyp -> begin
742+ match Env. lookup_id pid ctx.tc_env with
743+ | Unbound _ -> ([
744+ (None , [idecl l ctyp (name pid); icopy l (CL_id (name pid, ctyp)) cval], [] )
745+ ], ctx)
746+ | _ -> ([
747+ (Some (V_call (Neq , [V_id (name pid, ctyp); cval])), [] , [] )
748+ ], ctx)
749+ end
750+ | AP_id (pid , typ ) ->
751+ let id_ctyp = ctyp_of_typ ctx typ in
752+ let ctx = { ctx with locals = Bindings. add pid (Immutable , id_ctyp) ctx.locals } in
753+ ([
754+ None , [idecl l id_ctyp (name pid); icopy l (CL_id (name pid, id_ctyp)) cval], [iclear id_ctyp (name pid)]
755+ ], ctx)
756+ | AP_as (apat , id , typ ) ->
757+ let id_ctyp = ctyp_of_typ ctx typ in
758+ let steps, ctx = compile_match_no_jump ctx apat cval in
759+ let ctx = { ctx with locals = Bindings. add id (Immutable , id_ctyp) ctx.locals } in
760+ (
761+ steps @ [(
762+ None , [idecl l id_ctyp (name id); icopy l (CL_id (name id, id_ctyp)) cval], [iclear id_ctyp (name id)]
763+ )], ctx
764+ )
765+ | AP_struct (afpats , _ ) -> begin
766+ let fold (steps , ctx ) (field , apat ) =
767+ let steps', ctx = compile_match_no_jump ctx apat (V_field (cval, field)) in
768+ (steps @ steps', ctx)
769+ in
770+ List. fold_left fold ([] , ctx) afpats
771+ end
772+ | AP_tuple apats -> begin
773+ let get_tup n = V_tuple_member (cval, List. length apats, n) in
774+ let fold (steps , n , ctx ) apat ctyp =
775+ let steps', ctx = compile_match_no_jump ctx apat (get_tup n) in
776+ (steps @ steps', n + 1 , ctx)
777+ in
778+ match ctyp with
779+ | CT_tup ctyps ->
780+ let steps, _, ctx = List. fold_left2 fold ([] , 0 , ctx) apats ctyps in
781+ (steps, ctx)
782+ | _ -> Reporting. unreachable l __POS__ (" AP_tuple with ctyp " ^ string_of_ctyp ctyp)
783+ end
784+ | AP_app (ctor , apat , variant_typ ) -> begin
785+ match ctyp with
786+ | CT_variant (var_id , ctors ) ->
787+ let pat_ctyp = apat_ctyp ctx apat in
788+ (* These should really be the same, something has gone wrong if they are not. *)
789+ if not (ctyp_equal (cval_ctyp cval) (ctyp_of_typ ctx variant_typ)) then
790+ raise
791+ (Reporting. err_general l
792+ (Printf. sprintf " When compiling constructor pattern, %s should have the same type as %s"
793+ (string_of_ctyp (cval_ctyp cval))
794+ (string_of_ctyp (ctyp_of_typ ctx variant_typ))
795+ )
796+ );
797+ let unifiers, ctor_ctyp =
798+ let generic_ctors = Bindings. find var_id ctx.variants |> snd |> Bindings. bindings in
799+ let unifiers =
800+ ctyp_unify l (CT_variant (var_id, generic_ctors)) (cval_ctyp cval) |> KBindings. bindings |> List. map snd
801+ in
802+ match List. find_opt (fun (id , ctyp ) -> Id. compare id ctor = 0 && is_polymorphic ctyp) generic_ctors with
803+ | Some (_ , poly_ctor_ctyp ) ->
804+ let instantiated_parts = KBindings. map ctyp_suprema (ctyp_unify l poly_ctor_ctyp pat_ctyp) in
805+ (unifiers, subst_poly instantiated_parts poly_ctor_ctyp)
806+ | None -> begin
807+ match List. find_opt (fun (id , _ ) -> Id. compare id ctor = 0 ) ctors with
808+ | Some (_ , ctor_ctyp ) -> (unifiers, ctor_ctyp)
809+ | None ->
810+ Reporting. unreachable l __POS__
811+ (" Expected constructor " ^ string_of_id ctor ^ " for " ^ full_string_of_ctyp ctyp)
812+ end
813+ in
814+ let steps, ctx =
815+ compile_match_no_jump ctx apat (V_ctor_unwrap (cval, (ctor, unifiers), ctor_ctyp))
816+ in
817+ (
818+ (
819+ Some (V_ctor_kind (cval, (ctor, unifiers), pat_ctyp)), [] , []
820+ ) :: steps, ctx
821+ )
822+ | ctyp ->
823+ raise
824+ (Reporting. err_general l
825+ (Printf. sprintf " Variant constructor %s : %s matching against non-variant type %s : %s"
826+ (string_of_id ctor) (string_of_typ variant_typ) (string_of_cval cval) (string_of_ctyp ctyp)
827+ )
828+ )
829+ end
830+ | AP_wild _ -> ([] , ctx)
831+ | AP_cons (hd_apat , tl_apat ) -> begin
832+ match ctyp with
833+ | CT_list ctyp ->
834+ let hd, ctx = compile_match_no_jump ctx hd_apat (V_call (List_hd , [cval])) in
835+ let tl, ctx = compile_match_no_jump ctx tl_apat (V_call (List_tl , [cval])) in
836+ ((Some (V_call (List_is_empty , [cval])), [] , [] ) :: hd @ tl, ctx)
837+ | _ -> raise (Reporting. err_general l " Tried to pattern match cons on non list type" )
838+ end
839+ | AP_nil _ -> ([
840+ (Some (V_call (Bnot , [V_call (List_is_empty , [cval])])), [] , [] )
841+ ], ctx)
842+
843+ let compile_match_if_else ctx a cval l tcase =
844+ let steps, ctx = compile_match_no_jump ctx a cval in
845+ let rec fold steps = match steps with
846+ | [] -> tcase
847+ | (Some cond , ds , cl ) :: steps -> [iif l (V_call (Bnot , [cond])) (ds @ fold steps @ cl) [] CT_unit ]
848+ | (None, ds , cl ) :: steps -> ds @ fold steps @ cl
849+ in
850+ (fold steps, ctx)
851+
730852 let unit_cval = V_lit (VL_unit , CT_unit )
731853
732854 let rec compile_alexp ctx alexp =
@@ -768,9 +890,8 @@ module Make (C : CONFIG) = struct
768890 let branch_id, on_reached = coverage_branch_reached ctx l in
769891 let case_return_id = ngensym () in
770892 let finish_match_label = label " finish_match_" in
771- let compile_case (apat , guard , body ) =
772- let case_label = label " case_" in
773- if is_dead_aexp body then [ilabel case_label]
893+ let compile_case_else (apat , guard , body ) next =
894+ if is_dead_aexp body then next
774895 else (
775896 let trivial_guard =
776897 match guard with
@@ -779,36 +900,41 @@ module Make (C : CONFIG) = struct
779900 true
780901 | _ -> false
781902 in
782- let pre_destructure, destructure, destructure_cleanup, ctx = compile_match ctx apat cval case_label in
783903 let guard_setup, guard_call, guard_cleanup = compile_aexp ctx guard in
784904 let body_setup, body_call, body_cleanup = compile_aexp ctx body in
785- let gs = ngensym () in
905+ let matched = ngensym () in
906+ let tcase =
907+ if not trivial_guard then
908+ guard_setup @ [guard_call (CL_id (matched, CT_bool ))] @ guard_cleanup @
909+ [
910+ iif l (V_id (matched, CT_bool ))
911+ (body_setup @ [body_call (CL_id (case_return_id, ctyp))] @ body_cleanup)
912+ []
913+ CT_unit
914+ ]
915+ else
916+ [icopy l (CL_id (matched, CT_bool )) (V_lit (VL_bool true , CT_bool ))] @ body_setup @ [body_call (CL_id (case_return_id, ctyp))] @ body_cleanup
917+ in
918+ let check, ctx = compile_match_if_else ctx apat cval l tcase in
786919 let case_instrs =
787- pre_destructure @ destructure
788- @ ( if not trivial_guard then
789- guard_setup
790- @ [idecl l CT_bool gs; guard_call (CL_id (gs, CT_bool ))]
791- @ guard_cleanup
792- @ [
793- iif l (V_call (Bnot , [V_id (gs, CT_bool )])) (destructure_cleanup @ [igoto case_label]) [] CT_unit ;
794- ]
795- else []
796- )
797- @ (if num_cases > 1 then coverage_branch_target_taken ctx branch_id body else [] )
798- @ body_setup
799- @ [body_call (CL_id (case_return_id, ctyp))]
800- @ body_cleanup @ destructure_cleanup
801- @ [igoto finish_match_label]
920+ [
921+ idecl l CT_bool matched;
922+ icopy l (CL_id (matched, CT_bool )) (V_lit (VL_bool false , CT_bool ))
923+ ] @ check @ [
924+ iif l (V_call (Bnot , [V_id (matched, CT_bool )]))
925+ next
926+ []
927+ CT_unit
928+ ]
802929 in
803- [iblock case_instrs; ilabel case_label]
930+ case_instrs
804931 )
805932 in
806933 ( aval_setup
807934 @ [icomment (" Case with num_cases: " ^ string_of_int num_cases)]
808935 @ (if num_cases > 1 then on_reached else [] )
809936 @ [idecl l ctyp case_return_id]
810- @ List. concat (List. map compile_case cases)
811- @ [imatch_failure l]
937+ @ (List. fold_right compile_case_else cases [imatch_failure l])
812938 @ [ilabel finish_match_label],
813939 (fun clexp -> icopy l clexp (V_id (case_return_id, ctyp))),
814940 [iclear ctyp case_return_id] @ aval_cleanup
@@ -1031,8 +1157,10 @@ module Make (C : CONFIG) = struct
10311157 (return_setup @ creturn, (fun clexp -> icomment " unreachable after return" ), [] )
10321158 | AE_throw (aval , typ ) ->
10331159 (* Cleanup info will be handled by fix_exceptions *)
1034- let throw_setup, cval, _ = compile_aval l ctx aval in
1035- (throw_setup @ [ithrow l cval], (fun clexp -> icomment " unreachable after throw" ), [] )
1160+ if C. unreach_exceptions then ([imatch_failure l], (fun clexp -> icomment " unreachable after throw" ), [] )
1161+ else
1162+ let throw_setup, cval, _ = compile_aval l ctx aval in
1163+ (throw_setup @ [ithrow l cval], (fun clexp -> icomment " unreachable after throw" ), [] )
10361164 | AE_exit (aval , typ ) ->
10371165 let exit_setup, cval, _ = compile_aval l ctx aval in
10381166 (exit_setup @ [iexit l], (fun clexp -> icomment " unreachable after exit" ), [] )
@@ -1086,21 +1214,24 @@ module Make (C : CONFIG) = struct
10861214 @ [
10871215 iblock
10881216 ([
1089- ijump l
1090- (V_call ((if is_inc then Igt else Ilt ), [V_id (loop_var, CT_fint 64 ); V_id (to_gs, CT_fint 64 )]))
1091- loop_end_label;
1217+ iif l
1218+ (V_call (Bnot , [V_call ((if is_inc then Igt else Ilt ), [V_id (loop_var, CT_fint 64 ); V_id (to_gs, CT_fint 64 )])]))
1219+ (
1220+ body_setup
1221+ @ [body_call (CL_id (body_gs, CT_unit ))]
1222+ @ body_cleanup
1223+ @ [
1224+ icopy l
1225+ (CL_id (loop_var, CT_fint 64 ))
1226+ (V_call
1227+ ((if is_inc then Iadd else Isub ), [V_id (loop_var, CT_fint 64 ); V_id (step_gs, CT_fint 64 )])
1228+ );
1229+ ]
1230+ @ continue ()
1231+ )
1232+ []
1233+ CT_unit
10921234 ]
1093- @ body_setup
1094- @ [body_call (CL_id (body_gs, CT_unit ))]
1095- @ body_cleanup
1096- @ [
1097- icopy l
1098- (CL_id (loop_var, CT_fint 64 ))
1099- (V_call
1100- ((if is_inc then Iadd else Isub ), [V_id (loop_var, CT_fint 64 ); V_id (step_gs, CT_fint 64 )])
1101- );
1102- ]
1103- @ continue ()
11041235 );
11051236 ]
11061237 in
@@ -1461,9 +1592,9 @@ module Make (C : CONFIG) = struct
14611592 @ [call (CL_id (return, ret_ctyp))]
14621593 @ cleanup @ destructure_cleanup @ arg_cleanup
14631594 in
1464- let instrs = fix_early_return (exp_loc exp) (CL_id (return, ret_ctyp)) instrs in
1595+ let instrs = if C. needs_cleanup then fix_early_return (exp_loc exp) (CL_id (return, ret_ctyp)) instrs else instrs @ [iend def_annot.loc] in
14651596 let instrs = unique_names instrs in
1466- let instrs = fix_exception ~return: (Some ret_ctyp) ctx instrs in
1597+ let instrs = if C. unreach_exceptions then instrs else fix_exception ~return: (Some ret_ctyp) ctx instrs in
14671598 let instrs = coverage_function_entry ctx id (exp_loc exp) @ instrs in
14681599
14691600 if Option. is_some debug_attr then (
0 commit comments