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 <mail@tazj.in>
Tested-by: BuildkiteCI
This commit is contained in:
Griffin Smith 2020-08-27 11:58:28 -04:00 committed by glittershark
parent 3bada1d41e
commit fb0528c5da
2 changed files with 21 additions and 9 deletions

View file

@ -1117,15 +1117,26 @@ void EvalState::autoCallFunction(Bindings* args, Value& fun, Value& res) {
Value* actualArgs = allocValue(); Value* actualArgs = allocValue();
mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size()); mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size());
for (auto& i : fun.lambda.fun->formals->formals) { if (fun.lambda.fun->formals->ellipsis) {
Bindings::iterator j = args->find(i.name); // If the formals have an ellipsis (eg the function accepts extra args) pass
if (j != args->end()) { // all available automatic arguments (which includes arguments specified on
actualArgs->attrs->push_back(j->second); // the command line via --arg/--argstr)
} else if (i.def == nullptr) { for (auto& [_, v] : *args) {
throwTypeError( actualArgs->attrs->push_back(v);
"cannot auto-call a function that has an argument without a default " }
"value ('%1%')", } else {
i.name); // 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);
}
} }
} }

View file

@ -270,6 +270,7 @@ static void _main(int argc, char** argv) {
if (packages) { if (packages) {
std::ostringstream joined; std::ostringstream joined;
// TODO(grfn): Generate a syntax tree here, not a string
joined << "with import <nixpkgs> { }; (pkgs.runCommandCC or " joined << "with import <nixpkgs> { }; (pkgs.runCommandCC or "
"pkgs.runCommand) \"shell\" { buildInputs = [ "; "pkgs.runCommand) \"shell\" { buildInputs = [ ";
for (const auto& i : left) { for (const auto& i : left) {