Skip to content
New issue

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

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

Already on GitHub? # to your account

Introspectable location/errors #1432

Open
thufschmitt opened this issue Jul 5, 2023 · 2 comments
Open

Introspectable location/errors #1432

thufschmitt opened this issue Jul 5, 2023 · 2 comments
Labels
P2 major: an upcoming release type: feature request

Comments

@thufschmitt
Copy link
Contributor

Is your feature request related to a problem? Please describe.

An alternative to the inputs_spec pattern used in https://github.com/nickel-lang/nickel-nix/ (and the one already used for importing files) is to have a Nickel function that generates a symbolic representation of the input (something like { type = "nix-input", attibute-path = "nixpkgs.hello" }) and have Nix interpret that in a special way (“free-effects style”).
Although this wouldn't give the best possible interface from the Nickel side (import_nix "nixpkgs.hello" is kinda meh), it could already be better than what we have.

One issue, however, would be the error reporting. If the user mistypes import_nix "nixpkgs.hallo", then this will throw an error, but somewhere within the Nix interop library and with no link to the place of the import_nix call.

Describe the solution you'd like

A workaround for the above could be to have a Nickel builtin able to serialize the current location, so that Nickel would send something like { type = "nix-input", attribute-path = "nixpkgs.hallo", loc = "project.ncl:13:24" } to Nix, and Nix's error message could point to that location.
Maybe Nickel could even serialize the stacktrace part of the error message if the thing is missing so that we could have something like

{ 
  type = "nix-input",
  attribute-path = "nixpkgs.hallo", 
  error-if-missing = m%"
    error: missing field `hallo`
   ┌─ project.ncl:13:24
   │
13 │ nixpkgs.hallo
   │ ^^^^^^^^^^^^^ this requires the field `hallo` to exist
   │
   ┌─ project.ncl:13:38
   │
13 │ let nixpkgs = { hello = 1 }
   │               ------------- field `hallo` is missing here
  "%
}

and have Nix just throw that error message if the field is missing.

@thufschmitt
Copy link
Contributor Author

(obviously, this would break referential transparency so it would have to be used with care)

@yannham
Copy link
Member

yannham commented Jul 7, 2023

workaround for the above could be to have a Nickel builtin able to serialize the current location

From your message, I infer that what you want is to serialize the location of a function's call (and especially its argument)? Otherwise users would have to pass or annotate each callsite of import_nix. GHC has a similar mechanism that can indeed capture the call stack, for error reporting when defining exception or something. Rust also track calls for e.g. reporting panic, and you can use the #[track_caller] annotation on a function to record call sites and show them upon failure. So that's not unreasonable.

I wonder how much you can extract from the call stack currently. It's not trivial to work with it, especially because of indirect calls introduced by contracts.

Also, those kind of things are not only needed for Nickel-nix: @vkleen needed to track the location of an argument in a custom way as well for json-schema-to-nickel converter (we could get away by abusing contract.apply, but that wouldn't apply to your use case, as you don't control the call site of import_nixpkgs).

Custom contracts are all about error reporting, so it makes sense that errors (and their subpart such as location and call-stack) are first class values, but currently they aren't really. You can attach a message and notes to labels, but you can't manipulate positions, you can't create labels at will, and you can't read anything back from a label. It's probably valuable to have a deeper and more general reflection on what "first class errors" would really mean, in theory and in practice. We might come up with different and less ad-hoc ideas.

In the meantime, and related to my comment #1431 (comment), we could try to work something out quickly - basically a primop %call_label% that would provide you with a label or position corresponding to the caller of the current function - and put it under nix-experimental, while we work out something better.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
P2 major: an upcoming release type: feature request
Projects
None yet
Development

No branches or pull requests

2 participants