From fb0528c5dada2d3af6152b37a46e505e6bb2ac94 Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Thu, 27 Aug 2020 11:58:28 -0400 Subject: fix(tvix): Pass all args when auto-calling a function with an ellipsis The command line options --arg and --argstr that are used by a bunch of CLI commands to pass arguments to top-level functions in files go through the same code-path as auto-calling top-level functions with their default arguments - this, however, was only passing the arguments that were *explicitly* mentioned in the formals of the function - in the case of an as-pattern with an ellipsis (eg args @ { ... }) extra passed arguments would get omitted. This fixes that to instead pass *all* specified auto args in the case that our function has an ellipsis. Submitted upstream at https://github.com/NixOS/nix/pull/3965 Fixes: #46 Change-Id: I32b7ee0e5bacf75b2bc43a3f0796f533f4bd5959 Reviewed-on: https://cl.tvl.fyi/c/depot/+/1863 Reviewed-by: tazjin Tested-by: BuildkiteCI --- third_party/nix/src/libexpr/eval.cc | 29 ++++++++++++++++++++--------- third_party/nix/src/nix-build/nix-build.cc | 1 + 2 files changed, 21 insertions(+), 9 deletions(-) (limited to 'third_party/nix/src') diff --git a/third_party/nix/src/libexpr/eval.cc b/third_party/nix/src/libexpr/eval.cc index 569e04e3a712..b735495f2132 100644 --- a/third_party/nix/src/libexpr/eval.cc +++ b/third_party/nix/src/libexpr/eval.cc @@ -1117,15 +1117,26 @@ void EvalState::autoCallFunction(Bindings* args, Value& fun, Value& res) { Value* actualArgs = allocValue(); mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size()); - for (auto& i : fun.lambda.fun->formals->formals) { - Bindings::iterator j = args->find(i.name); - if (j != args->end()) { - actualArgs->attrs->push_back(j->second); - } else if (i.def == nullptr) { - throwTypeError( - "cannot auto-call a function that has an argument without a default " - "value ('%1%')", - i.name); + if (fun.lambda.fun->formals->ellipsis) { + // If the formals have an ellipsis (eg the function accepts extra args) pass + // all available automatic arguments (which includes arguments specified on + // the command line via --arg/--argstr) + for (auto& [_, v] : *args) { + actualArgs->attrs->push_back(v); + } + } else { + // Otherwise, only pass the arguments that the function accepts + for (auto& i : fun.lambda.fun->formals->formals) { + Bindings::iterator j = args->find(i.name); + if (j != args->end()) { + actualArgs->attrs->push_back(j->second); + } else if (i.def == nullptr) { + throwTypeError( + "cannot auto-call a function that has an argument without a " + "default " + "value ('%1%')", + i.name); + } } } diff --git a/third_party/nix/src/nix-build/nix-build.cc b/third_party/nix/src/nix-build/nix-build.cc index 67cd8252f07e..30ab2a8136d2 100644 --- a/third_party/nix/src/nix-build/nix-build.cc +++ b/third_party/nix/src/nix-build/nix-build.cc @@ -270,6 +270,7 @@ static void _main(int argc, char** argv) { if (packages) { std::ostringstream joined; + // TODO(grfn): Generate a syntax tree here, not a string joined << "with import { }; (pkgs.runCommandCC or " "pkgs.runCommand) \"shell\" { buildInputs = [ "; for (const auto& i : left) { -- cgit 1.4.1