-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Suppose I'm using StructuredReporter and I want to catch a fatal error, change the message code, and re-raise it. I would naively expect the following to work:
Reporter.try_with (fun () -> fatal Original_message)
~fatal:(fun d -> fatal_diagnostic { d with message = New_message })However, this doesn't work, because the original call to fatal has already invoked get_text on Original_message and stored the result in d.explanation, and that's what gets displayed to the user. This is unintuitive to me and was hard to track down.
I feel like in general if an interface includes the definition of a type as a record, then it should be valid to define new elements of that type as records. If there are invariants that should be maintained relating the fields, or if some fields are memoized computations from other fields, then the fact that the type is a record shouldn't be exposed in the interface. Of course a change like that would be breaking. A partial solution would be to supply a function like with_message that changes the message and also recomputes the explanation:
let with_message { severity; message = _; backtrace; explanation; extra_remarks } message =
let explanation = locate_opt explanation.loc (Code.default_text message) in
{ severity; message; backtrace; explanation; extra_remarks }With a warning in the documentation that this should be used instead of manually setting the message field.