about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval.cc5
-rw-r--r--src/libexpr/nixexpr.cc8
2 files changed, 11 insertions, 2 deletions
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(<term>)", 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(<term>, <term>)", name,