Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: emit new Error(ID, {cause: CAML_EXN}) for exceptions #1036

Merged
merged 12 commits into from
Jan 30, 2024

Conversation

anmonteiro
Copy link
Member

@anmonteiro anmonteiro commented Jan 23, 2024

Summary

Converts Melange-generated error throwing code to always emit a JS Error instance.

fixes #975

Details

Before:

      throw {
            MEL_EXN_ID: "Assert_failure",
            _1: [
              "jscomp/test/fun_pattern_match.ml",
              41,
              9
            ],
            Error: new Error()
          };

After

      throw new Error("Assert_failure", {
                cause: {
                  MEL_EXN_ID: "Assert_failure",
                  _1: [
                    "jscomp/test/fun_pattern_match.ml",
                    41,
                    9
                  ]
                }
              });
  • Melange now throws an instance of JavaScript's new Error() and adds the extension payload for cause in the Error cause option.
  • Exception catching runtime was adapted to read .cause in the error being caught by try .. catch(error) { .. } code

@anmonteiro anmonteiro marked this pull request as ready for review January 28, 2024 07:41
Copy link
Member

@jchavarri jchavarri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Some questions for the parts i don't understand.

jscomp/core/js_dump.ml Show resolved Hide resolved
jscomp/core/lam_convert.cppo.ml Outdated Show resolved Hide resolved
jscomp/core/lam_convert.cppo.ml Outdated Show resolved Hide resolved
jscomp/runtime/caml_js_exceptions.ml Outdated Show resolved Hide resolved
jscomp/runtime/caml_js_exceptions.ml Outdated Show resolved Hide resolved
@EduardoRFS
Copy link
Collaborator

EduardoRFS commented Jan 29, 2024

For both interop and performance reasons, wouldn't it be better to have a MelangeError class? Such that melange errors can be detected with instanceof.

Also is cause supported in older versions or it will be discarded? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause

Anyway, the MelangeError class could support both new MelangeError(message, cause) and it could also be used to ensure .cause is defined.

@anmonteiro
Copy link
Member Author

It might be interesting to play with a MelangeError instance too. I'll hold off on that for this PR, but I've opened an issue to track it: #1042.

@jchavarri
Copy link
Member

jchavarri commented Jan 30, 2024

For both interop and performance reasons, wouldn't it be better to have a MelangeError class?

@EduardoRFS Sorry, I don't understand what would be the upsides of this. In terms of performance, bundling size at least would get worse with MelangeError class.

Such that melange errors can be detected with instanceof.

In terms of detection, isn't the cause field enough to discern if a given error comes from Melange or not? Or is the proposal to remove cause and have it replaced with the new class? (That's not what @anmonteiro is doing in #1043, afaict).

@EduardoRFS
Copy link
Collaborator

EduardoRFS commented Jan 30, 2024

@jchavarri I was not talking about bundle size, but even that should shrink, as the MelangeError instance is smaller.

About detection, I was not talking about detecting it in Melange itself, but instead, detecting it outside of Melange.

throw new Error("Assert_failure", {
  cause: {
    MEL_EXN_ID: "Assert_failure",
    _1: [
      "jscomp/test/fun_pattern_match.ml",
      41,
      9
    ]
  }
});

throw new MelangeError("Assert_failure", [
  "jscomp/test/fun_pattern_match.ml",
  41,
  9
]);

@jchavarri
Copy link
Member

Thanks for clarifying. The part that I was missing is that the object with cause property would go away.

@EduardoRFS
Copy link
Collaborator

@jchavarri the object may still be there, it can still be accessed on the instance, is just that it is defined only inside of the constructor.

@anmonteiro
Copy link
Member Author

@EduardoRFS Sorry, I don't understand what would be the upsides of this. In terms of performance, bundling size at least would get worse with MelangeError class.

some of the upsides:

  • users outside melange can detect whether Melange threw an error with e instanceof Caml_js_exceptions.MelangeError
  • It also gives us a bit more browser coverage. Check caniuse for cause.

Improvements in bundling size might be a bit negligible IMO (check #1043 (comment)) and not the main motivator for this.

@anmonteiro anmonteiro merged commit a2204c4 into main Jan 30, 2024
4 checks passed
@anmonteiro anmonteiro deleted the anmonteiro/raise-js-error branch January 30, 2024 21:12
aspeddro added a commit to aspeddro/rescript-compiler that referenced this pull request Feb 5, 2024
cknitt pushed a commit to rescript-lang/rescript-compiler that referenced this pull request May 30, 2024
* throw as instance of JS `new Error()`

Adapted from melange-re/melange#1036

Thanks @anmonteiro

* uncomment test

* update output

* update build

* [skip ci]: update CHANGELOG.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pass Error messages through to throw new Error
3 participants