ocaml-multicore / eio

Effects-based direct-style IO for multicore OCaml
Other
548 stars 66 forks source link

eio 0.10 giving error #564

Closed bikallem closed 1 year ago

bikallem commented 1 year ago

I recently updated eio to v 0.10. While everything builds okay, doing dune test gives the following error.

+```mdx-error
+Line 27, characters 66-69:
+Error: This expression has type Eio_unix.Stdenv.base
+       but an expression was expected of type
+         < clock : Eio.Time.clock; secure_random : Eio.Flow.source; .. >
+       Eio_unix.Stdenv.base is abstract because no corresponding cmi file was found in path.
+```

dune test on v0.9 runs without any issues.

talex5 commented 1 year ago

Which MDX file is this from? Is this in Eio itself or a project using Eio? Does it still happen if you run dune test a second time?

bikallem commented 1 year ago

It is from a project using eio and mdx. Yes, it happens all the time no matter how many times I execute dune test. The version of mdx seems to not matter. I tried with (using mdx 0.2) in dune-project file and I get the same error (in v0.10). I am using mdx version 0.4 in dune-project.

talex5 commented 1 year ago

Lwt_eio is using MDX and testing against Eio 0.10 successfully: https://ocaml.ci.dev/github/ocaml-multicore/lwt_eio/commit/220dfd5c57b3d8a620f908daa58dad993719e005/variant/debian-11-5.0_opam-2.1

Perhaps your project is missing a dependency on eio_main or something like that?

bikallem commented 1 year ago

The test dependencies are specified in the mdx stanza https://github.com/bikallem/spring/blob/main/test/dune as I am using (using mdx 0.4). I re-added the # #require "eio_main" to .md files. It still fails but this time with different error as below.

+Exception: Stdlib.Effect.Unhandled(Eio__core__Cancel.Get_context)

Reverting the eio version back to 0.9 seems to work without any error.

It seems the tests that fails seems to be .mdx files that use either Eio_main.run of Eio_mock.Backend.run. For example https://github.com/bikallem/spring/blob/main/test/client.md

talex5 commented 1 year ago

You need to #require "eio.mock" if you want to use that library. The odd thing is why MDX isn't giving an error about that.

e.g. when running with MDX directly, I get:

$ ocaml-mdx test ./test.md; cat ./test.md.corrected
```ocaml
# #require "eio_main"
# Eio_mock.Backend.run @@ fun () ->
  Eio.Switch.run @@ fun sw -> ();;
Line 1, characters 1-21:
Error: Unbound module Eio_mock
```

But when run with dune, I get:

Exception: Stdlib.Effect.Unhandled(Eio__core__Cancel.Get_context)

I guess it's because the libraries in your dune file don't match the libraries in #requires, but I don't know why it fails in that way.

bikallem commented 1 year ago

Yeah, it seems I need to #require all the libraries as declared in dune mdx stanza. This is not the case with eio.0.9. Additionally, when I do #require spring, it gives me No such package spring. I will probably need to opam pin eio to get around the last issue. However, pinning the project under dev will be a tedious dev experience I think.

SGrondin commented 1 year ago

I ran into the same error and figured it out.

In my case, it happened because I wasn't careful with partial application:

let main settings env () = ...

let () =
  (* Using core_unix.command_unix to create a CLI tool *)
  let open Command in
  let open Command.Let_syntax in

  (* First I define simple CLI parameters *)
  let common =
    let%map_open something1 = ...
    and something2 = ...
    in
    { something1; something2 }
  in

  (* Now I start the app *)
  common
  >>| (fun common ->
        Eio_posix.run (fun env ->
          main common env ))
  |> basic ~summary:"TODO"
  |> Command_unix.run ~version
(* BOOM! Fails with Exception: Stdlib.Effect.Unhandled(Eio__core__Cancel.Get_context) *)

It's NOT OBVIOUS but there's a hidden eta-reduction happening here.

Compare it with the working code:

(* ...skipping identical code... *)

  (* Now I start the app *)
  common
  >>| (fun common () ->
        Eio_posix.run (fun env ->
          main common env () ))
  |> basic ~summary:"TODO"
  |> Command_unix.run ~version

By NOT removing the () on the lambda and the call to main, I ensure that main is called while the event loop is running.

I know you are not using the Command library, but I suspect that your problem is caused by a similar issue.

I wonder if we could trap the exception and replace it with a helpful error message?

talex5 commented 1 year ago

@bikallem: you might just need to depend on the "spring" package in your dune file. e.g. Eio does:

(mdx
  (package eio_main)
  (deps
    (package eio_main)))

This says that the tests are part of the "eio_main" package, and that they depend on it. You might want to upgrade your dune project version to see if the new syntax works better. If not, perhaps you could file an issue on dune with a simpler case demonstrating the problem. I don't think this has anything to do with Eio.

@SGrondin: that sounds like an unrelated issue. You could move the main loop to the top to avoid any confusion:

  (* Now I start the app *)
  Eio_posix.run @@ fun env ->
  common
  >>| (fun common -> main common env))
  |> basic ~summary:"TODO"
  |> Command_unix.run ~version
bikallem commented 1 year ago

I finally managed to make this work. For others facing the same issue, I managed to solve the issue by adding eio.unix to libraries section in mdx section.