From 823f756ff4b83e6b2bc936a0ff95f95e9ae4b3fd Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 20 Feb 2026 20:46:12 +0100 Subject: [PATCH 1/3] builtins.hashString: Devirtualize lazy paths Fixes https://github.com/DeterminateSystems/determinate/issues/160. --- src/libexpr/primops.cc | 5 +++-- tests/functional/fetchGit.sh | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index e1df04f2624..1a4b01805ad 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -4729,8 +4729,9 @@ static void prim_hashString(EvalState & state, const PosIdx pos, Value ** args, state.error("unknown hash algorithm '%1%'", algo).atPos(pos).debugThrow(); NixStringContext context; // discarded - auto s = - state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.hashString"); + auto s = state.devirtualize( + state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.hashString"), + context); v.mkString(hashString(*ha, s).to_string(HashFormat::Base16, false), state.mem); } diff --git a/tests/functional/fetchGit.sh b/tests/functional/fetchGit.sh index 1d8a8e75224..d43108e6d2a 100755 --- a/tests/functional/fetchGit.sh +++ b/tests/functional/fetchGit.sh @@ -363,3 +363,17 @@ rm "$TEST_ROOT"/flake/flake.lock nix eval "path:$TEST_ROOT/flake"#isModern nix eval --nix-219-compat "path:$TEST_ROOT/flake"#isModern [[ $(jq -r .nodes.eol.locked.narHash < "$TEST_ROOT"/flake/flake.lock) = "$newHash" ]] + + +# Test that builtins.hashString devirtualizes lazy paths (https://github.com/DeterminateSystems/determinate/issues/160). +hashStringRepo="$TEST_ROOT/hashString" +createGitRepo "$hashStringRepo" +echo hello > "$hashStringRepo"/hello +git -C "$hashStringRepo" add hello +git -C "$hashStringRepo" commit -m 'Initial' +hashStringRev=$(git -C "$hashStringRepo" rev-parse HEAD) + +hash1=$(nix eval --lazy-trees --raw --expr "builtins.hashString \"sha256\" (toString ((builtins.fetchGit { url = file://$hashStringRepo; rev = \"$hashStringRev\"; })))") +hash2=$(nix eval --lazy-trees --raw --expr "builtins.hashString \"sha256\" (toString ((builtins.fetchGit { url = file://$hashStringRepo; rev = \"$hashStringRev\"; })))") + +[[ "$hash1" = "$hash2" ]] From 90bec9c8fb9135664aa6ba450a14b653435516f7 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 20 Feb 2026 21:10:04 +0100 Subject: [PATCH 2/3] Re-enable lazy trees tests This was lost in 823b1195b309e8814a13009efef725f2ce2ed178. --- ci/gha/tests/default.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ci/gha/tests/default.nix b/ci/gha/tests/default.nix index c179174e6e2..4a30a96a475 100644 --- a/ci/gha/tests/default.nix +++ b/ci/gha/tests/default.nix @@ -82,6 +82,11 @@ rec { ''; repl-completion = pkgs.callPackage ../../../tests/repl-completion.nix { inherit (packages') nix; }; + lazyTrees = nixComponents.nix-functional-tests.override { + pname = "nix-lazy-trees-tests"; + lazyTrees = true; + }; + /** Checks for our packaging expressions. This shouldn't build anything significant; just check that things From 5d6ab843db7c9f9481938c91bc63aaacd5339656 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 20 Feb 2026 21:25:04 +0100 Subject: [PATCH 3/3] Fix `nix run` on an app with lazy trees enabled --- src/nix/app.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nix/app.cc b/src/nix/app.cc index 07c7c55cfdb..4a8ca815c0f 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -90,7 +90,7 @@ UnresolvedApp InstallableValue::toApp(EvalState & state) }, [&](const NixStringContextElem::Opaque & o) -> DerivedPath { return DerivedPath::Opaque{ - .path = o.path, + .path = state.devirtualize(o.path), }; }, [&](const NixStringContextElem::Path & p) -> DerivedPath { @@ -102,7 +102,7 @@ UnresolvedApp InstallableValue::toApp(EvalState & state) return UnresolvedApp{App{ .context = std::move(context2), - .program = program, + .program = state.devirtualize(program, context), }}; }