diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 0623e49532..5ae4d6de8e 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -201,6 +201,11 @@ Expr evalExpr2(EvalState & state, Expr e) cons == "List")) return e; + /* The `Closed' constructor is just a way to prevent substitutions + into expressions not containing free variables. */ + if (atMatch(m, e) >> "Closed" >> e1) + return evalExpr(state, e1); + /* Any encountered variables must be undeclared or primops. */ if (atMatch(m, e) >> "Var" >> name) { PrimOp0 primOp = (PrimOp0) lookupPrimOp(state.primOps0, name); diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 0d14623ccc..2736daf323 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -177,9 +177,13 @@ Expr substitute(const ATermMap & subs, Expr e) ATMatcher m; ATerm name; + /* As an optimisation, don't substitute in subterms known to be + closed. */ + if (atMatch(m, e) >> "Closed") return e; + if (atMatch(m, e) >> "Var" >> name) { Expr sub = subs.get(name); - return sub ? sub : e; + return sub ? ATmake("Closed()", sub) : e; } /* In case of a function, filter out all variables bound by this @@ -199,7 +203,7 @@ Expr substitute(const ATermMap & subs, Expr e) substitute(subs2, body)); } - if (atMatch(m, e) >> "Function" >> name >> body) { + if (atMatch(m, e) >> "Function1" >> name >> body) { ATermMap subs2(subs); subs2.remove(name); return ATmake("Function1(, )", name,