module Window = struct
let t = H.div [||] []
let%component make ~(name : string) ~(window_config : Window_config.t) = t
end
this gets compile error:
open Core
module Window = struct
let t = H.div [||] []
let%component make ~(name : string) ~(window_config : Window_config.t) = t
end
error:
File "ml/widget/dom.ml", line 33, characters 2-76:
33 | let%component make ~(name : string) ~(window_config : Window_config.t) = t
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error (warning 6 [labels-omitted]): label f was omitted in the application of this function.
File "ml/widget/dom.ml", line 33, characters 2-76:
33 | let%component make ~(name : string) ~(window_config : Window_config.t) = t
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type string -> Js.js_string Js.t
but an expression was expected of type 'a option
Unlike other libraries that try to extend the standard library (e.g. containers) base and core are meant as complete replacement. And method signatures in Core can be imcompatible with the stdlib. let%component is probably generating code relying on some function of the stdlib String module but with open Core its in fact using the Core String module and it’s uncompatible libraries. (fair guess based on the compiler error, but I haven’t check the code).
how do I fix this
Not sure you will like my suggestions (but people more expert in the subject could have better ones):
Only use stdlib extentions, not replacements (so no core, or base)
Do not use ppx imcompatible with the expected usage of Core.
Try to isolate any none-JS ppx from the rest of your code, so you can open Core in most places without impacting the code generation.
Prefix all your usages of modules that would be in stdlib with Core. and deal with the weird compiler errors if you ever forget one.
Option 3. might be the less annoying to pick if you are already invested in core and don’t fancy option 1.
in vscode there is a command to show the preprocessed version of a file, ie after the ppx runs. It could help you understand what is happening.
Alternatively you can use dune directly. From the root of you project, do dune describe pp ./path/to/the/file.ml. I don’t know if it works when there’s a typing issue like you have.
If it doesn’t work, you can do something like _build/default/.ppx/SOMEHASH/ppx.exe path/to/your/file.ml.
When you are just experimenting you can get it from utop, by launching it with the -dsource flag
$ utop -dsource
# #require "lwt.unix";;
# let () = Lwt_main.run (let%lwt () = Lwt.return () in Lwt.return ());;
let () =
Lwt_main.run
(let __ppx_lwt_0 = Lwt.return () in
let module Reraise = struct external reraise : exn -> 'a = "%reraise" end
in
Lwt.backtrace_bind
(fun exn -> try Reraise.reraise exn with | exn -> exn) __ppx_lwt_0
(fun () -> Lwt.return ()));;
I buy this logic. So the most direct way is probably to rewrite the ppx? I.e. figure out what functions its using whose signature changed from stdlib to Core, and patch those ?
Thank you for sharing this debugging tip. This is very useful.
min failure case:
open Core
module H = React.Dom.Dsl.Html
module Window = struct
let t = H.div [||] []
let%component make () = t
end
error:
File "ml/widget/min.ml", line 6, characters 2-27:
6 | let%component make () = t
^^^^^^^^^^^^^^^^^^^^^^^^^
Error (warning 6 [labels-omitted]): label f was omitted in the application of this function.
File "ml/widget/min.ml", line 6, characters 2-27:
6 | let%component make () = t
^^^^^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type
string -> Js_of_ocaml.Js.js_string Js_of_ocaml.Js.t
but an expression was expected of type 'a option
expanded output:
[@@@ocaml.ppx.context
{
tool_name = "ppx_driver";
include_dirs = [];
load_path = [];
open_modules = [];
for_package = None;
debug = false;
use_threads = false;
use_vmthreads = false;
recursive_types = false;
principal = false;
transparent_modules = false;
unboxed_types = false;
unsafe_string = false;
cookies =
[("library-name", "widget");
("ppx_optcomp.env",
(env ~flambda2:(Defined false) ~flambda_backend:(Defined false)
~ocaml_version:(Defined (5, 0, 0)) ~os_type:(Defined "Unix")))]
}]
let () =
Ppx_module_timer_runtime.record_start Ppx_module_timer_runtime.__MODULE__
let () = Ppx_bench_lib.Benchmark_accumulator.Current_libname.set "widget"
let () =
Expect_test_collector.Current_file.set
~absolute_filename:"ml/widget/min.ml"
let () = Ppx_inline_test_lib.Runtime.set_lib_and_partition "widget" ""
open Core
module H = React.Dom.Dsl.Html
module Window =
struct
let t = H.div [||] []
let make =
let make_props : ?key:string -> unit -> < > Js_of_ocaml.Js.t =
fun ?key ->
fun () ->
let open Js_of_ocaml.Js.Unsafe in
obj
[|("key",
(inject
(Js_of_ocaml.Js.Optdef.option
(Option.map Js_of_ocaml.Js.string key))))|]
[@@merlin.hide ] in
let make () = (t : React.element) in
((let make (Props : < > Js_of_ocaml.Js.t) = make () in
fun ?key -> fun () -> React.create_element make (make_props ?key ()))
[@merlin.hide ])
end
let () = Ppx_inline_test_lib.Runtime.unset_lib "widget"
let () = Expect_test_collector.Current_file.unset ()
let () = Ppx_bench_lib.Benchmark_accumulator.Current_libname.unset ()
let () =
Ppx_module_timer_runtime.record_until Ppx_module_timer_runtime.__MODULE__
For what it’s worth…you could also do something like this if you didn’t want to change the ppx:
module Window = struct
module Option = struct
include Option
(* Use the stdlib [map] function in this custom [Option] module. *)
let map = Caml.Option.map
end
let%component make () = failwith ""
end
Yes came here to say this. Instead of forking or patching the lib, It would be nice to open a PR with the change directly.
And please, open the issue related to jsoo-react in the repo (I’m fine if you open the issue in two places) but it might happen that we won’t see this post.
it does matter, but I don’t know how to pick the right one. If I end up needing this I usually try a bunch of them until I find the one which is taking care of the annotation I have trouble with.
You figured it out already. But for people who wonders how to get there, you can simply replace your original code with the expanded version and the compiler will point you to the exact line that is creating the issue.