From a4bfd559f1671f3bf9f0a8961d90bbd978cd3f08 Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Mon, 19 May 2025 19:53:20 +0000 Subject: [PATCH] libexpr: Use `attrs.alreadySorted()` in primop_functionArgs Formals are already sorted as it's an invariant of `Formals`. --- src/libexpr/include/nix/expr/nixexpr.hh | 3 +++ src/libexpr/primops.cc | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/libexpr/include/nix/expr/nixexpr.hh b/src/libexpr/include/nix/expr/nixexpr.hh index a5ce0fd89..6ede91948 100644 --- a/src/libexpr/include/nix/expr/nixexpr.hh +++ b/src/libexpr/include/nix/expr/nixexpr.hh @@ -306,6 +306,9 @@ struct Formal struct Formals { typedef std::vector Formals_; + /** + * @pre Sorted according to predicate (std::tie(a.name, a.pos) < std::tie(b.name, b.pos)). + */ Formals_ formals; bool ellipsis; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index d13314ffb..c38eed267 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -3148,10 +3148,16 @@ static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * arg return; } - auto attrs = state.buildBindings(args[0]->payload.lambda.fun->formals->formals.size()); - for (auto & i : args[0]->payload.lambda.fun->formals->formals) + const auto &formals = args[0]->payload.lambda.fun->formals->formals; + auto attrs = state.buildBindings(formals.size()); + for (auto & i : formals) attrs.insert(i.name, state.getBool(i.def), i.pos); - v.mkAttrs(attrs); + /* Optimization: avoid sorting bindings. `formals` must already be sorted according to + (std::tie(a.name, a.pos) < std::tie(b.name, b.pos)) predicate, so the following assertion + always holds: + assert(std::is_sorted(attrs.alreadySorted()->begin(), attrs.alreadySorted()->end())); + .*/ + v.mkAttrs(attrs.alreadySorted()); } static RegisterPrimOp primop_functionArgs({