@@ -646,13 +646,111 @@ let rec cut n l =
646
646
647
647
let try_ids = Hashtbl. create 8
648
648
649
- let stdlib_option_call_extra exp =
650
- let rec aux = function
651
- | [] -> None
652
- | (Texp_stdlib_option_call info , _ , _ ) :: _ -> Some info
653
- | _ :: rest -> aux rest
654
- in
655
- aux exp.exp_extra
649
+ (* Recompute metadata needed for inlining Stdlib.Option helpers at translation
650
+ time; the typed tree only marks such applications with a boolean flag. *)
651
+ type stdlib_option_call_kind =
652
+ | Stdlib_option_forEach
653
+ | Stdlib_option_map of {result_cannot_contain_undefined : bool }
654
+ | Stdlib_option_flatMap
655
+
656
+ type stdlib_option_callback =
657
+ | Stdlib_option_inline_lambda of {param : Ident .t ; body : expression }
658
+ | Stdlib_option_inline_ident of expression
659
+
660
+ type stdlib_option_call = {
661
+ callback : stdlib_option_callback ;
662
+ call_kind : stdlib_option_call_kind ;
663
+ payload_not_nested : bool ;
664
+ }
665
+
666
+ type stdlib_option_fun_kind =
667
+ | Stdlib_option_fun_forEach
668
+ | Stdlib_option_fun_map
669
+ | Stdlib_option_fun_flatMap
670
+
671
+ let stdlib_option_fun_of_path env path =
672
+ let canonical = Env. normalize_path_prefix None env path in
673
+ match Path. flatten canonical with
674
+ | `Contains_apply -> None
675
+ | `Ok (head , rest ) ->
676
+ let segments = Ident. name head :: rest in
677
+ let matches fname =
678
+ match segments with
679
+ | [" Stdlib" ; " Option" ; name] -> String. equal name fname
680
+ | [" Stdlib_Option" ; name] -> String. equal name fname
681
+ | _ -> false
682
+ in
683
+ if matches " forEach" then Some Stdlib_option_fun_forEach
684
+ else if matches " map" then Some Stdlib_option_fun_map
685
+ else if matches " flatMap" then Some Stdlib_option_fun_flatMap
686
+ else None
687
+
688
+ let inline_lambda_callback (expr : expression ) : stdlib_option_callback option =
689
+ match expr.exp_desc with
690
+ | Texp_function {arg_label = Nolabel ; case; partial = Total ; async = false ; _}
691
+ when Option. is_none case.c_guard -> (
692
+ match case.c_lhs.pat_desc with
693
+ | Tpat_var (param , _ ) ->
694
+ Some (Stdlib_option_inline_lambda {param; body = case.c_rhs})
695
+ | _ -> None )
696
+ | _ -> None
697
+
698
+ let inline_ident_callback (expr : expression ) : stdlib_option_callback option =
699
+ match expr.exp_desc with
700
+ | Texp_ident _ -> Some (Stdlib_option_inline_ident expr)
701
+ | _ -> None
702
+
703
+ let callback_return_type env (expr : expression ) =
704
+ match (Ctype. expand_head env expr.exp_type).desc with
705
+ | Tarrow (_ , ret_ty , _ , _ ) -> Some ret_ty
706
+ | _ -> None
707
+
708
+ let detect_stdlib_option_call env (funct : expression )
709
+ (args : (Noloc.arg_label * expression option) list ) :
710
+ stdlib_option_call option =
711
+ match funct.exp_desc with
712
+ | Texp_ident (path , _ , _ ) -> (
713
+ match stdlib_option_fun_of_path env path with
714
+ | None -> None
715
+ | Some fun_kind -> (
716
+ match args with
717
+ | [(Nolabel , Some opt_expr); (Nolabel , Some callback_expr)] -> (
718
+ let callback_info =
719
+ match inline_lambda_callback callback_expr with
720
+ | Some info -> Some info
721
+ | None -> inline_ident_callback callback_expr
722
+ in
723
+ match callback_info with
724
+ | None -> None
725
+ | Some callback ->
726
+ let payload_not_nested =
727
+ match (Ctype. expand_head env opt_expr.exp_type).desc with
728
+ | Tconstr (path, [payload_ty], _)
729
+ when Path. same path Predef. path_option ->
730
+ Typeopt. type_cannot_contain_undefined payload_ty env
731
+ | _ -> false
732
+ in
733
+ let call_kind =
734
+ match fun_kind with
735
+ | Stdlib_option_fun_forEach -> Stdlib_option_forEach
736
+ | Stdlib_option_fun_map ->
737
+ let result_cannot_contain_undefined =
738
+ match callback with
739
+ | Stdlib_option_inline_lambda {body; _} ->
740
+ Typeopt. type_cannot_contain_undefined body.exp_type
741
+ body.exp_env
742
+ | Stdlib_option_inline_ident cb -> (
743
+ match callback_return_type cb.exp_env cb with
744
+ | Some ret_ty ->
745
+ Typeopt. type_cannot_contain_undefined ret_ty cb.exp_env
746
+ | None -> false )
747
+ in
748
+ Stdlib_option_map {result_cannot_contain_undefined}
749
+ | Stdlib_option_fun_flatMap -> Stdlib_option_flatMap
750
+ in
751
+ Some {callback; call_kind; payload_not_nested})
752
+ | _ -> None ))
753
+ | _ -> None
656
754
657
755
let lambda_none = Lconst (Const_pointer (0 , Pt_shape_none ))
658
756
@@ -765,11 +863,15 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda =
765
863
(Lprim
766
864
(Pccall (set_transformed_jsx d ~transformed_jsx ), argl, e.exp_loc))
767
865
| _ -> wrap (Lprim (prim, argl, e.exp_loc))))
768
- | Texp_apply {funct; args = oargs ; partial; transformed_jsx} -> (
866
+ | Texp_apply
867
+ {funct; args = oargs; partial; transformed_jsx; stdlib_option_call} -> (
769
868
let inlined, funct =
770
869
Translattribute. get_and_remove_inlined_attribute funct
771
870
in
772
- let option_call_info = stdlib_option_call_extra e in
871
+ let option_call_info =
872
+ if stdlib_option_call then detect_stdlib_option_call e.exp_env funct oargs
873
+ else None
874
+ in
773
875
let uncurried_partial_application =
774
876
(* In case of partial application foo(args, ...) when some args are missing,
775
877
get the arity *)
0 commit comments