diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index 3bbe0ad88620..e0e2b095c6a8 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -34,6 +34,13 @@ ValueList * EvalState::allocList() return new (allocBytes(sizeof(ValueList))) ValueList(); } +template +[[gnu::always_inline]] +ValueList * EvalState::allocListFromInitializerList(std::initializer_list values) +{ + return new (allocBytes(sizeof(ValueList))) ValueList(values); +} + [[gnu::always_inline]] Value * EvalState::allocValue() diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 3ac12d85df45..a4dd1f132abe 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -20,6 +20,7 @@ #include "fetch-to-store.hh" #include "tarball.hh" #include "parser-tab.hh" +#include "value.hh" #include #include @@ -1294,6 +1295,10 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) void ExprList::eval(EvalState & state, Env & env, Value & v) { + // TODO(@connorbaker): Tried to switch to using transient here, but started getting this error: + // Value::type: invalid internal type: -183796896 + // That's an indication the value is being used after it's been freed. Not sure why that's happening. + // NOTE: Running with GC_DONT_GC=1 doesn't seem to trigger the error, so it's likely a GC issue. auto list = state.allocList(); for (auto & i : elems) *list = list->push_back(i->maybeThunk(state, env)); @@ -1896,15 +1901,14 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v) { auto v1 = state.allocValue(); e1->eval(state, env, *v1); + state.forceList(*v1, pos, "in the left operand of the list concatenation operator"); auto v2 = state.allocValue(); e2->eval(state, env, *v2); - // TODO(@connorbaker): This kills me -- why do we need to create the list on the heap? Shouldn't I be able to pass - // a ValueList by value to concatLists without worrying about it being garbage collected *while the function is running*? - // If this doesn't work, then should I allocList in the test cases? + state.forceList(*v2, pos, "in the right operand of the list concatenation operator"); + auto list = state.allocList(); - *list = list->push_back(v1); - *list = list->push_back(v2); - state.concatLists(v, *list, pos, "while evaluating one of the elements to concatenate"); + *list = v1->list() + v2->list(); + v.mkList(list); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index a1887f93d508..5941ac41fe58 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -699,6 +699,8 @@ public: * Allocation primitives. */ inline ValueList * allocList(); + template + inline ValueList * allocListFromInitializerList(std::initializer_list values); inline Value * allocValue(); inline Env & allocEnv(size_t size); diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index ede3f9fda389..4c14a628204f 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -17,6 +17,7 @@ #include #include #include +#include // declare a memory policy for using a tracing garbage collector using gc_policy = immer::memory_policy, @@ -33,7 +34,8 @@ class BindingsBuilder; // alias the vector type so we are not concerned about memory policies // in the places where we actually use it -typedef immer::flex_vector ValueList; +typedef immer::flex_vector ValueList; +typedef immer::flex_vector_transient ValueListTransient; typedef enum { tUninitialized = 0, diff --git a/tests/functional/lang/eval-fail-list.err.exp b/tests/functional/lang/eval-fail-list.err.exp index d492f8bd2e43..3ad791dc4d5a 100644 --- a/tests/functional/lang/eval-fail-list.err.exp +++ b/tests/functional/lang/eval-fail-list.err.exp @@ -1,5 +1,5 @@ error: - … while evaluating one of the elements to concatenate + … in the left operand of the list concatenation operator at /pwd/lang/eval-fail-list.nix:1:2: 1| 8++1 | ^