1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-09 03:56:01 +01:00

restore proper handling of no formals vs. 0 formals

e.g. (foo@{}: 1) { a = 3; } should error, but wasn't with the previous
commit
This commit is contained in:
Taeer Bar-Yam 2025-10-27 22:58:37 +01:00
parent 4a80c92a4d
commit e43888890f
9 changed files with 16 additions and 18 deletions

View file

@ -771,7 +771,7 @@ TEST_F(PrimOpTest, derivation)
ASSERT_EQ(v.type(), nFunction); ASSERT_EQ(v.type(), nFunction);
ASSERT_TRUE(v.isLambda()); ASSERT_TRUE(v.isLambda());
ASSERT_NE(v.lambda().fun, nullptr); ASSERT_NE(v.lambda().fun, nullptr);
ASSERT_TRUE(v.lambda().fun->hasFormals()); ASSERT_TRUE(v.lambda().fun->hasFormals);
} }
TEST_F(PrimOpTest, currentTime) TEST_F(PrimOpTest, currentTime)

View file

@ -1496,13 +1496,13 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
ExprLambda & lambda(*vCur.lambda().fun); ExprLambda & lambda(*vCur.lambda().fun);
auto size = (!lambda.arg ? 0 : 1) + lambda.nFormals; auto size = (!lambda.arg ? 0 : 1) + (lambda.hasFormals ? lambda.getFormals().size() : 0);
Env & env2(mem.allocEnv(size)); Env & env2(mem.allocEnv(size));
env2.up = vCur.lambda().env; env2.up = vCur.lambda().env;
Displacement displ = 0; Displacement displ = 0;
if (!lambda.hasFormals()) if (!lambda.hasFormals)
env2.values[displ++] = args[0]; env2.values[displ++] = args[0];
else { else {
try { try {
@ -1747,7 +1747,7 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res
} }
} }
if (!fun.isLambda() || !fun.lambda().fun->hasFormals()) { if (!fun.isLambda() || !fun.lambda().fun->hasFormals) {
res = fun; res = fun;
return; return;
} }

View file

@ -490,6 +490,7 @@ struct ExprLambda : Expr
Symbol arg; Symbol arg;
bool ellipsis; bool ellipsis;
bool hasFormals;
uint16_t nFormals; uint16_t nFormals;
Formal * formalsStart; Formal * formalsStart;
@ -501,6 +502,7 @@ struct ExprLambda : Expr
: pos(pos) : pos(pos)
, arg(arg) , arg(arg)
, ellipsis(formals.ellipsis) , ellipsis(formals.ellipsis)
, hasFormals(true)
, nFormals(formals.formals.size()) , nFormals(formals.formals.size())
, formalsStart(alloc.allocate_object<Formal>(nFormals)) , formalsStart(alloc.allocate_object<Formal>(nFormals))
, body(body) , body(body)
@ -511,7 +513,7 @@ struct ExprLambda : Expr
ExprLambda(std::pmr::polymorphic_allocator<char> & alloc, PosIdx pos, Symbol arg, Expr * body) ExprLambda(std::pmr::polymorphic_allocator<char> & alloc, PosIdx pos, Symbol arg, Expr * body)
: pos(pos) : pos(pos)
, arg(arg) , arg(arg)
, nFormals(0) , hasFormals(false)
, formalsStart(nullptr) , formalsStart(nullptr)
, body(body) {}; , body(body) {};
@ -529,11 +531,6 @@ struct ExprLambda : Expr
void setName(Symbol name) override; void setName(Symbol name) override;
std::string showNamePos(const EvalState & state) const; std::string showNamePos(const EvalState & state) const;
inline bool hasFormals() const
{
return nFormals > 0;
}
std::vector<Formal> getFormalsLexicographic(const SymbolTable & symbols) const std::vector<Formal> getFormalsLexicographic(const SymbolTable & symbols) const
{ {
std::vector<Formal> result(getFormals().begin(), getFormals().end()); std::vector<Formal> result(getFormals().begin(), getFormals().end());
@ -551,6 +548,7 @@ struct ExprLambda : Expr
std::span<Formal> getFormals() const std::span<Formal> getFormals() const
{ {
assert(hasFormals);
return {formalsStart, nFormals}; return {formalsStart, nFormals};
} }

View file

@ -154,7 +154,7 @@ void ExprList::show(const SymbolTable & symbols, std::ostream & str) const
void ExprLambda::show(const SymbolTable & symbols, std::ostream & str) const void ExprLambda::show(const SymbolTable & symbols, std::ostream & str) const
{ {
str << "("; str << "(";
if (hasFormals()) { if (hasFormals) {
str << "{ "; str << "{ ";
bool first = true; bool first = true;
// the natural Symbol ordering is by creation time, which can lead to the // the natural Symbol ordering is by creation time, which can lead to the
@ -451,14 +451,14 @@ void ExprLambda::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv>
if (es.debugRepl) if (es.debugRepl)
es.exprEnvs.insert(std::make_pair(this, env)); es.exprEnvs.insert(std::make_pair(this, env));
auto newEnv = std::make_shared<StaticEnv>(nullptr, env, nFormals + (!arg ? 0 : 1)); auto newEnv = std::make_shared<StaticEnv>(nullptr, env, (hasFormals ? getFormals().size() : 0) + (!arg ? 0 : 1));
Displacement displ = 0; Displacement displ = 0;
if (arg) if (arg)
newEnv->vars.emplace_back(arg, displ++); newEnv->vars.emplace_back(arg, displ++);
if (hasFormals()) { if (hasFormals) {
for (auto & i : getFormals()) for (auto & i : getFormals())
newEnv->vars.emplace_back(i.name, displ++); newEnv->vars.emplace_back(i.name, displ++);

View file

@ -3363,7 +3363,7 @@ static void prim_functionArgs(EvalState & state, const PosIdx pos, Value ** args
if (!args[0]->isLambda()) if (!args[0]->isLambda())
state.error<TypeError>("'functionArgs' requires a function").atPos(pos).debugThrow(); state.error<TypeError>("'functionArgs' requires a function").atPos(pos).debugThrow();
if (!args[0]->lambda().fun->hasFormals()) { if (!args[0]->lambda().fun->hasFormals) {
v.mkAttrs(&Bindings::emptyBindings); v.mkAttrs(&Bindings::emptyBindings);
return; return;
} }

View file

@ -145,7 +145,7 @@ static void printValueAsXML(
posToXML(state, xmlAttrs, state.positions[v.lambda().fun->pos]); posToXML(state, xmlAttrs, state.positions[v.lambda().fun->pos]);
XMLOpenElement _(doc, "function", xmlAttrs); XMLOpenElement _(doc, "function", xmlAttrs);
if (v.lambda().fun->hasFormals()) { if (v.lambda().fun->hasFormals) {
XMLAttrs attrs; XMLAttrs attrs;
if (v.lambda().fun->arg) if (v.lambda().fun->arg)
attrs["name"] = state.symbols[v.lambda().fun->arg]; attrs["name"] = state.symbols[v.lambda().fun->arg];

View file

@ -281,7 +281,7 @@ static Flake readFlake(
if (auto outputs = vInfo.attrs()->get(sOutputs)) { if (auto outputs = vInfo.attrs()->get(sOutputs)) {
expectType(state, nFunction, *outputs->value, outputs->pos); expectType(state, nFunction, *outputs->value, outputs->pos);
if (outputs->value->isLambda() && outputs->value->lambda().fun->hasFormals()) { if (outputs->value->isLambda() && outputs->value->lambda().fun->hasFormals) {
for (auto & formal : outputs->value->lambda().fun->getFormals()) { for (auto & formal : outputs->value->lambda().fun->getFormals()) {
if (formal.name != state.s.self) if (formal.name != state.s.self)
flake.inputs.emplace( flake.inputs.emplace(

View file

@ -468,7 +468,7 @@ struct CmdFlakeCheck : FlakeCommand
if (!v.isLambda()) { if (!v.isLambda()) {
throw Error("overlay is not a function, but %s instead", showType(v)); throw Error("overlay is not a function, but %s instead", showType(v));
} }
if (v.lambda().fun->hasFormals() || !argHasName(v.lambda().fun->arg, "final")) if (v.lambda().fun->hasFormals || !argHasName(v.lambda().fun->arg, "final"))
throw Error("overlay does not take an argument named 'final'"); throw Error("overlay does not take an argument named 'final'");
// FIXME: if we have a 'nixpkgs' input, use it to // FIXME: if we have a 'nixpkgs' input, use it to
// evaluate the overlay. // evaluate the overlay.

View file

@ -415,7 +415,7 @@ static void main_nix_build(int argc, char ** argv)
return false; return false;
} }
bool add = false; bool add = false;
if (v.type() == nFunction && v.lambda().fun->hasFormals()) { if (v.type() == nFunction && v.lambda().fun->hasFormals) {
for (auto & i : v.lambda().fun->getFormals()) { for (auto & i : v.lambda().fun->getFormals()) {
if (state->symbols[i.name] == "inNixShell") { if (state->symbols[i.name] == "inNixShell") {
add = true; add = true;