Is there a way to output json or some serialized machine-friendly output from the compiler/dune?

Hello,

I’m really tired of having to squint and copy/paste errors in my editor to be able to understand them. I think at this point I’m ready to write a parser/decoder in python or something to clean out errors (since it’d take me too much time to do it in the compiler). Is there a way to make dune output some serialized format so that I can parse that easily? Or am I stuck parsing text?

No there’s no structured format for warning and error messages emitted by the ocaml compiler so far. If you search the issue tracker on the ocaml compiler repo you’ll find some discussions related to this topic and you can eventually chime in if you have a use case.

I actually agree with you but just to get a sense of how others feel, can you explain why the error messages are difficult to read specifically?

I just spent the afternoon writing some python parser to display this last error I’m getting properly:

File "src/lib/pickles/composition_types/branch_data.ml", line 104, characters 13-64:
104 |       + pack (Pickles_types.Vector.to_list proofs_verified_mask)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type f Pickles_base.Proofs_verified.boolean list
       but an expression was expected of type Impl.Boolean.var list
       Type
         f Pickles_base.Proofs_verified.boolean =
           f Snarky_backendless.Boolean.t
       is not compatible with type
         Impl.Boolean.var = Impl.Field.t Snarky_backendless.Boolean.t 
       Type f is not compatible with type Impl.Field.t = field_var 
File "src/lib/pickles/composition_types/spec.ml", line 1:
Error: The implementation src/lib/pickles/composition_types/spec.pp.ml
       does not match the interface src/lib/pickles/composition_types/.composition_types.objs/byte/composition_types__Spec.cmi:
        Values do not match:
          val typ :
            assert_16_bits:('a -> unit) ->
            (module Snarky_backendless.Snark_intf.Run with type field = 'b and type field_var = 'a and type run_state = 'c) ->
            ('d, 'e, 'b, 'a,
             (unit, 'c) Snarky_backendless__.Checked_runner.Simple.t)
            Snarky_backendless__.Types.Typ.t ->
            ('f, 'g,
             < bool1 : bool;
               bool2 : 'a Snarky_backendless.Snark_intf.Boolean0.t;
               branch_data1 : Composition_types__.Branch_data.t;
               branch_data2 : ('b, 'a)
                              Composition_types__.Branch_data.Checked.t;
               bulletproof_challenge1 : Limb_vector.Challenge.Constant.t Sc.t
                                        Composition_types__.Bulletproof_challenge.t;
               bulletproof_challenge2 : 'a Limb_vector.Challenge.t Sc.t
                                        Composition_types__.Bulletproof_challenge.t;
               challenge1 : Limb_vector.Challenge.Constant.t;
               challenge2 : 'a Limb_vector.Challenge.t;
               digest1 : (Limb_vector.Constant.Hex64.t,
                          Composition_types__Digest.Limbs.n)
                         Pickles_types.Vector.vec;
               digest2 : 'a; field1 : 'e; field2 : 'd; .. >)
            T.t -> ('g, 'f, 'b, 'a, 'c) Snarky_backendless.Typ.t
        is not included in
          val typ :
            assert_16_bits:('field_var -> unit) ->
            (module Snarky_backendless.Snark_intf.Run with type field = 'f and type field_var = 'field_var and type run_state = 'state) ->
            ('b, 'c, 'f, 'field_var,
             (unit, 'state)
             Snarky_backendless.Checked_runner.Simple.Types.Checked.t)
            Snarky_backendless.Types.Typ.t ->
            ('d, 'e,
             < bool1 : bool;
               bool2 : 'field_var Snarky_backendless.Snark_intf.Boolean0.t;
               branch_data1 : Composition_types__.Branch_data.t;
               branch_data2 : ('f, 'field_var)
                              Composition_types__.Branch_data.Checked.t;
               bulletproof_challenge1 : Limb_vector.Challenge.Constant.t
                                        Kimchi_backend_common.Scalar_challenge.t
                                        Composition_types__.Bulletproof_challenge.t;
               bulletproof_challenge2 : 'f Limb_vector.Challenge.t
                                        Kimchi_backend_common.Scalar_challenge.t
                                        Composition_types__.Bulletproof_challenge.t;
               challenge1 : Limb_vector.Challenge.Constant.t;
               challenge2 : 'f Limb_vector.Challenge.t;
               digest1 : (Limb_vector.Constant.Hex64.t,
                          Composition_types__.Digest.Limbs.n)
                         Pickles_types.Vector.vec;
               digest2 : 'field_var; field1 : 'c; field2 : 'b; .. >)
            T.t -> ('e, 'd, 'f, 'field_var, 'state) Snarky_backendless.Typ.t
        The type
          assert_16_bits:('a -> unit) ->
          (module Snarky_backendless.Snark_intf.Run with type field = 'b and type field_var = 'a and type run_state = 'c) ->
          ('d, 'e, 'b, 'a,
           (unit, 'c) Snarky_backendless__.Checked_runner.Simple.t)
          Snarky_backendless__.Types.Typ.t ->
          ('f, 'g,
           < bool1 : bool;
             bool2 : 'a Snarky_backendless.Snark_intf.Boolean0.t;
             branch_data1 : Composition_types__.Branch_data.t;
             branch_data2 : ('b, 'a)
                            Composition_types__.Branch_data.Checked.t;
             bulletproof_challenge1 : Limb_vector.Challenge.Constant.t Sc.t
                                      Composition_types__.Bulletproof_challenge.t;
             bulletproof_challenge2 : 'a Limb_vector.Challenge.t Sc.t
                                      Composition_types__.Bulletproof_challenge.t;
             challenge1 : Limb_vector.Challenge.Constant.t;
             challenge2 : 'a Limb_vector.Challenge.t;
             digest1 : (Limb_vector.Constant.Hex64.t,
                        Composition_types__Digest.Limbs.n)
                       Pickles_types.Vector.vec;
             digest2 : 'a; field1 : 'e; field2 : 'd; .. >)
          T.t -> ('g, 'f, 'b, 'a, 'c) Snarky_backendless.Typ.t
        is not compatible with the type
          assert_16_bits:('a -> unit) ->
          (module Snarky_backendless.Snark_intf.Run with type field = 'b and type field_var = 'a and type run_state = 'c) ->
          ('d, 'e, 'b, 'a,
           (unit, 'c)
           Snarky_backendless.Checked_runner.Simple.Types.Checked.t)
          Snarky_backendless.Types.Typ.t ->
          ('f, 'g,
           < bool1 : bool;
             bool2 : 'a Snarky_backendless.Snark_intf.Boolean0.t;
             branch_data1 : Composition_types__.Branch_data.t;
             branch_data2 : ('b, 'a)
                            Composition_types__.Branch_data.Checked.t;
             bulletproof_challenge1 : Limb_vector.Challenge.Constant.t
                                      Kimchi_backend_common.Scalar_challenge.t
                                      Composition_types__.Bulletproof_challenge.t;
             bulletproof_challenge2 : 'b Limb_vector.Challenge.t
                                      Kimchi_backend_common.Scalar_challenge.t
                                      Composition_types__.Bulletproof_challenge.t;
             challenge1 : Limb_vector.Challenge.Constant.t;
             challenge2 : 'b Limb_vector.Challenge.t;
             digest1 : (Limb_vector.Constant.Hex64.t,
                        Composition_types__.Digest.Limbs.n)
                       Pickles_types.Vector.vec;
             digest2 : 'a; field1 : 'e; field2 : 'd; .. >)
          T.t -> ('g, 'f, 'b, 'a, 'c) Snarky_backendless.Typ.t
        Type
          'a Limb_vector.Challenge.t Sc.t
          Composition_types__.Bulletproof_challenge.t =
            'a Limb_vector.Challenge.t Sc.t
            Mina_wire_types.Pickles_bulletproof_challenge.V1.t
        is not compatible with type
          'b Limb_vector.Challenge.t Kimchi_backend_common.Scalar_challenge.t
          Composition_types__.Bulletproof_challenge.t =
            'b Limb_vector.Challenge.t
            Kimchi_backend_common.Scalar_challenge.t
            Mina_wire_types.Pickles_bulletproof_challenge.V1.t 
        Type
          'a Limb_vector.Challenge.t Sc.t =
            'a Limb_vector.Challenge.t Kimchi_types.scalar_challenge
        is not compatible with type
          'b Limb_vector.Challenge.t Kimchi_backend_common.Scalar_challenge.t
            = 'b Limb_vector.Challenge.t Kimchi_types.scalar_challenge 
        Type 'a Limb_vector.Challenge.t = 'a is not compatible with type
          'b Limb_vector.Challenge.t = 'b 
        Types for method bulletproof_challenge2 are incompatible
        File "src/lib/pickles/composition_types/spec.mli", lines 81-118, characters 0-62:
          Expected declaration
        File "src/lib/pickles/composition_types/spec.ml", line 455, characters 4-7:
          Actual declaration

the problem is that the backtrace doesn’t seem to follow any convention. Sometimes it uses different words, or different linebreaks, it’s a nightmare to parse in Python (or with my eyes)

1 Like

if this is useful for someone, that better-ocaml/README.md at main · mimoo/better-ocaml · GitHub script can parse one error atm x) (the above one), which looks like this:

5 Likes

the name of your project reminded me of GitHub - reasonml-old/BetterErrors: Make OCaml/Reason errors prettier

I couldn’t figure out if the code still lives in reasonml nowadays.

2 Likes

That’s a cool idea. I would definitely encourage you to file an issue in the OCaml repo to see what the uptake is on this core idea, i.e. inverting the ordering of the type mismatch errors. Since in practice everyone tells you to read these error messages from the bottom up anyway.

oh wow! I’m not the first one irritated enough by the errors to start that :smiley: this hasn’t been updated in 7 years so I’m guessing this wouldn’t work today, although I would also bet the errors haven’t changed much since x)

usually when I do this I’m told to post here instead :smiley: (at least for these kind of more discussion-oriented topics)

there has been a few improvements on the format of errors, but I think it’s relatively stable indeed.

This particular better-error repo is old. If I remember correctly it was the first POC. The idea has been transfered to reasonml/bucklescript/rescript tho. For rescript this is part of the compiler I suppose, it’s called super-error. For reasonml I don’t know where it landed. That might be reason-native/src/refmterr at master · reasonml/reason-native · GitHub.

I would not bet on that but I am biased. There were many improvements on the format of errors since 4.02.3; and Bucklescript gave up on following upstream improvements (or bug fixes) relatively soon.

For open discussion, I maintain my stance; but for well-defined and actionable idea, the bug tracker is a good place. By the way, thank you for giving an explicit example, it helps a lot to understand your griefs
about error messages if the average message that you have to deal with looks like this.

That sounds like a good option to have; and pretty easy to implement once I will be done with the work on the more structured output for the compiler messages. However, in this specific case, the full context is also useful since the final error depends on the type equations (and inequations) introduced at the module level.

In fact, I like this example because it is a good illustration of having a message unreadable because important pieces of information are scattered across too many submessages.

5 Likes