@@ -646,13 +646,111 @@ let rec cut n l =
646646
647647let try_ids = Hashtbl. create 8
648648
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
656754
657755let lambda_none = Lconst (Const_pointer (0 , Pt_shape_none ))
658756
@@ -765,11 +863,15 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda =
765863 (Lprim
766864 (Pccall (set_transformed_jsx d ~transformed_jsx ), argl, e.exp_loc))
767865 | _ -> 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} -> (
769868 let inlined, funct =
770869 Translattribute. get_and_remove_inlined_attribute funct
771870 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
773875 let uncurried_partial_application =
774876 (* In case of partial application foo(args, ...) when some args are missing,
775877 get the arity *)
0 commit comments