From 5db4b0699ce880e8a4a2e836dd536834718da7a3 Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Thu, 11 Sep 2025 01:53:41 +0300 Subject: [PATCH] libexpr: Make constant Values global constants, move out of EvalState These constant Values have no business being in the EvalState in the first place. The ultimate goal is to get rid of the ugly `getBuiltins` and its relience (in `createBaseEnv`) on these global constants is getting in the way. Same idea as in https://git.lix.systems/lix-project/lix/commit/f017f9ddd336e32a5ed1ee835f1c6c7e73a052ae. Co-authored-by: eldritch horrors --- src/libexpr/eval.cc | 8 ++------ src/libexpr/include/nix/expr/eval.hh | 26 ------------------------ src/libexpr/include/nix/expr/value.hh | 28 ++++++++++++++++++++++++++ src/libexpr/meson.build | 1 + src/libexpr/primops.cc | 12 +++++------ src/libexpr/value.cc | 29 +++++++++++++++++++++++++++ src/nix/nix-env/nix-env.cc | 2 +- 7 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 src/libexpr/value.cc diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index b586c3409..3a53ecf79 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -284,10 +284,6 @@ EvalState::EvalState( static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes"); - vEmptyList.mkList(buildList(0)); - vNull.mkNull(); - vTrue.mkBool(true); - vFalse.mkBool(false); vStringRegular.mkStringNoCopy("regular"); vStringDirectory.mkStringNoCopy("directory"); vStringSymlink.mkStringNoCopy("symlink"); @@ -894,7 +890,7 @@ ListBuilder::ListBuilder(EvalState & state, size_t size) Value * EvalState::getBool(bool b) { - return b ? &vTrue : &vFalse; + return b ? &Value::vTrue : &Value::vFalse; } unsigned long nrThunks = 0; @@ -1300,7 +1296,7 @@ void ExprList::eval(EvalState & state, Env & env, Value & v) Value * ExprList::maybeThunk(EvalState & state, Env & env) { if (elems.empty()) { - return &state.vEmptyList; + return &Value::vEmptyList; } return Expr::maybeThunk(state, env); } diff --git a/src/libexpr/include/nix/expr/eval.hh b/src/libexpr/include/nix/expr/eval.hh index 0b91645ea..430e334b8 100644 --- a/src/libexpr/include/nix/expr/eval.hh +++ b/src/libexpr/include/nix/expr/eval.hh @@ -313,32 +313,6 @@ public: */ RepairFlag repair; - /** - * Empty list constant. - */ - Value vEmptyList; - - /** - * `null` constant. - * - * This is _not_ a singleton. Pointer equality is _not_ sufficient. - */ - Value vNull; - - /** - * `true` constant. - * - * This is _not_ a singleton. Pointer equality is _not_ sufficient. - */ - Value vTrue; - - /** - * `true` constant. - * - * This is _not_ a singleton. Pointer equality is _not_ sufficient. - */ - Value vFalse; - /** `"regular"` */ Value vStringRegular; /** `"directory"` */ diff --git a/src/libexpr/include/nix/expr/value.hh b/src/libexpr/include/nix/expr/value.hh index 0b10b78b5..c74588a31 100644 --- a/src/libexpr/include/nix/expr/value.hh +++ b/src/libexpr/include/nix/expr/value.hh @@ -833,6 +833,34 @@ struct Value : public ValueStorage { friend std::string showType(const Value & v); + /** + * Empty list constant. + * + * This is _not_ a singleton. Pointer equality is _not_ sufficient. + */ + static Value vEmptyList; + + /** + * `null` constant. + * + * This is _not_ a singleton. Pointer equality is _not_ sufficient. + */ + static Value vNull; + + /** + * `true` constant. + * + * This is _not_ a singleton. Pointer equality is _not_ sufficient. + */ + static Value vTrue; + + /** + * `true` constant. + * + * This is _not_ a singleton. Pointer equality is _not_ sufficient. + */ + static Value vFalse; + private: template bool isa() const noexcept diff --git a/src/libexpr/meson.build b/src/libexpr/meson.build index 00fb82e3c..40d3f390b 100644 --- a/src/libexpr/meson.build +++ b/src/libexpr/meson.build @@ -163,6 +163,7 @@ sources = files( 'search-path.cc', 'value-to-json.cc', 'value-to-xml.cc', + 'value.cc', 'value/context.cc', ) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 2a3eec672..f099e060e 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1075,11 +1075,11 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value ** args, Val try { state.forceValue(*args[0], pos); attrs.insert(state.s.value, args[0]); - attrs.insert(state.symbols.create("success"), &state.vTrue); + attrs.insert(state.symbols.create("success"), &Value::vTrue); } catch (AssertionError & e) { // `value = false;` is unfortunate but removing it is a breaking change. - attrs.insert(state.s.value, &state.vFalse); - attrs.insert(state.symbols.create("success"), &state.vFalse); + attrs.insert(state.s.value, &Value::vFalse); + attrs.insert(state.symbols.create("success"), &Value::vFalse); } // restore the debugRepl pointer if we saved it earlier. @@ -4613,7 +4613,7 @@ void prim_match(EvalState & state, const PosIdx pos, Value ** args, Value & v) auto list = state.buildList(match.size() - 1); for (const auto & [i, v2] : enumerate(list)) if (!match[i + 1].matched) - v2 = &state.vNull; + v2 = &Value::vNull; else v2 = mkString(state, match[i + 1]); v.mkList(list); @@ -4705,7 +4705,7 @@ void prim_split(EvalState & state, const PosIdx pos, Value ** args, Value & v) auto list2 = state.buildList(slen); for (const auto & [si, v2] : enumerate(list2)) { if (!match[si + 1].matched) - v2 = &state.vNull; + v2 = &Value::vNull; else v2 = mkString(state, match[si + 1]); } @@ -5059,7 +5059,7 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings) addConstant( "null", - &vNull, + &Value::vNull, { .type = nNull, .doc = R"( diff --git a/src/libexpr/value.cc b/src/libexpr/value.cc new file mode 100644 index 000000000..07d036b0d --- /dev/null +++ b/src/libexpr/value.cc @@ -0,0 +1,29 @@ +#include "nix/expr/value.hh" + +namespace nix { + +Value Value::vEmptyList = []() { + Value res; + res.setStorage(List{.size = 0, .elems = nullptr}); + return res; +}(); + +Value Value::vNull = []() { + Value res; + res.mkNull(); + return res; +}(); + +Value Value::vTrue = []() { + Value res; + res.mkBool(true); + return res; +}(); + +Value Value::vFalse = []() { + Value res; + res.mkBool(false); + return res; +}(); + +} // namespace nix diff --git a/src/nix/nix-env/nix-env.cc b/src/nix/nix-env/nix-env.cc index f165c069c..01c8ccf4b 100644 --- a/src/nix/nix-env/nix-env.cc +++ b/src/nix/nix-env/nix-env.cc @@ -158,7 +158,7 @@ static void loadSourceExpr(EvalState & state, const SourcePath & path, Value & v directory). */ else if (st.type == SourceAccessor::tDirectory) { auto attrs = state.buildBindings(maxAttrs); - attrs.insert(state.symbols.create("_combineChannels"), &state.vEmptyList); + attrs.insert(state.symbols.create("_combineChannels"), &Value::vEmptyList); StringSet seen; getAllExprs(state, path, seen, attrs); v.mkAttrs(attrs);