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

Add builtins.warn #10592

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

Add builtins.warn #10592

wants to merge 4 commits into from

Conversation

roberth
Copy link
Member

@roberth roberth commented Apr 22, 2024

Motivation

A variation of trace, but

  • with the correct log level
  • no ANSI codes in expressions
  • can be debugged without stopping for actual trace calls (ie intentional "info level" or trace logging).
  • logs warnings without trace: in front of it
  • follows the Nix color scheme.

Context

I'd planned to add this a long time ago but forgot to eventually follow up on it.
This Nixpkgs PR reminded me to complete it, and I would like to avoid an unnecessary deprecation.
It proposes to rename the environment variable, which would make the current lib.warn not an (anachronistic) polyfill of the Nix feature anymore. That'd be unfortunate.

Priorities and Process

Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

@roberth roberth added feature Feature request or proposal error-messages Confusing messages and better diagnostics language The Nix expression language; parser, interpreter, primops, evaluation, etc labels Apr 22, 2024
@roberth roberth requested a review from edolstra as a code owner April 22, 2024 23:32
@github-actions github-actions bot added the with-tests Issues related to testing. PRs with tests have some priority label Apr 22, 2024
@lorenzleutgeb

This comment was marked as outdated.

Comment on lines 1049 to 1052
if (args[0]->type() == nString)
printMsg(lvlWarn, ANSI_WARNING "warning:" ANSI_NORMAL " %1%", args[0]->string_view());
else
printMsg(lvlWarn, ANSI_WARNING "warning:" ANSI_NORMAL " %1%", ValuePrinter(state, *args[0]));
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need to redo the error formatting here, vs reused something from the loggers?

Copy link
Member Author

Choose a reason for hiding this comment

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

It now uses logWarning, which also sets us up to print an actual position, after #10597.

}

if (evalSettings.builtinsAbortOnWarn) {
state.error<Abort>("aborting to reveal stack trace of warning, as abort-on-warn is set").debugThrow();
Copy link
Member

Choose a reason for hiding this comment

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

Optional: we could also just throw our BaseError with this as extra context.

Copy link
Member Author

Choose a reason for hiding this comment

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

I prefer to treat them separately, because they don't have the same message, and I don't think it should be just a single message.

Copy link
Member

Choose a reason for hiding this comment

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

Totally fine! Though just to be clear, I was thinking the this message would become an addTrace call --- I too don't think it should be a single message.

}

if (evalSettings.builtinsAbortOnWarn) {
state.error<Abort>("aborting to reveal stack trace of warning, as abort-on-warn is set").debugThrow();
Copy link
Member

Choose a reason for hiding this comment

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

Totally fine! Though just to be clear, I was thinking the this message would become an addTrace call --- I too don't think it should be a single message.

Comment on lines 1063 to 1062
if ((evalSettings.builtinsTraceDebugger || evalSettings.builtinsDebuggerOnWarn) && state.debugRepl && !state.debugTraces.empty()) {
const DebugTrace & last = state.debugTraces.front();
state.runDebugRepl(nullptr, last.env, last.expr);
}
Copy link
Member

Choose a reason for hiding this comment

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

A few of the call sites runDebugRepl look similar --- not just builtin.trace's even. Should we abstract over this a bit?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think yes, by allowing any primop to be marked as a breakpoint.
Until we have that, let's just keep it simple.

Copy link
Member

Choose a reason for hiding this comment

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

Just to be clear, I mean not a new generalized feature, but something very mechanical:

if (state.debugRepl && !state.debugTraces.empty()) {
    const DebugTrace & last = state.debugTraces.front();
    state.runDebugRepl(<some-expression>, last.env, last.expr);
}

seems to be part of this EvalErrorBuilder<T>::debugThrow, primop_break, primop_trace, and now prim_warn. So I am wondering if a new function (maybe in header, taking an auto && lambda, to get the laziness right) is warranted.

@roberth roberth requested a review from Ericson2314 May 2, 2024 08:25
src/libexpr/primops.cc Outdated Show resolved Hide resolved
msg.atPos(state.positions[pos]);
auto info = msg.info();
info.level = lvlWarn;
logWarning(info);
Copy link
Member

Choose a reason for hiding this comment

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

If I understand correctly, users will not be able to easily distinguish output produced by builtins.warn from output produced by other calls of logWarning. However, other callsites will not go ahead and trigger the "abort on warn" behaviour. It's a safe bet that you'll have some users set NIX_ABORT_ON_WARN, then hit one of the other codepaths, and be confused why Nix did not abort.

I don't think that it's a solution to have Nix abort on all these kinds of warnings. There are rather benign warnings too, like:

warning: Git tree '...' is dirty
warning: unknown flake output 'homeModules'

The only proposal I have is to use some other logging prefix, like eval-warning: instead of warning: to make the distinction more clear.

Constructing ErrorInfo is a little awkward for now, but this does
produce a richer log entry.
... so that we may perhaps later extend the interface.
Note that Nixpkgs' lib.warn already requires a string coercible
argument, so this is reasonable. Also note that string coercible
values aren't all strings, but in practice, for warn, they are.
@roberth
Copy link
Member Author

roberth commented May 6, 2024

Trivial rebase for CI 🤞

}

if (evalSettings.builtinsAbortOnWarn) {
state.error<Abort>("aborting to reveal stack trace of warning, as abort-on-warn is set").debugThrow();
Copy link
Member

@edolstra edolstra May 6, 2024

Choose a reason for hiding this comment

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

This shouldn't throw Abort, since that's a subclass of EvalError, which causes the error to be stored in the eval cache. So it should be an exception type that is not a subclass of EvalError.

@edolstra
Copy link
Member

edolstra commented May 6, 2024

Can you add a release note for this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
error-messages Confusing messages and better diagnostics feature Feature request or proposal language The Nix expression language; parser, interpreter, primops, evaluation, etc with-tests Issues related to testing. PRs with tests have some priority
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants