libexpr/builtins: Document unsafeDiscardStringContext

Co-authored-by: eldritch horrors <pennae@lix.systems>

Change-Id: I4ebbbc9d32152f296a2553f2fd324dacf8af02d8
This commit is contained in:
Tom Hubrecht
2025-11-23 08:58:17 +01:00
parent fd273186c6
commit 3cf5ad0164
4 changed files with 36 additions and 8 deletions
@@ -0,0 +1,33 @@
---
name: unsafeDiscardStringContext
args: [s]
---
Returns a copy of the string `s` with all string context associated with `s` removed.
Since string context is used for dependency tracking the returned string will also have
*no dependencies* on store objects, even when the original string `s` had such dependencies.
This function is mainly useful when discarding dependencies is explicitly required, e.g.
to produce a string listing all inputs of a derivation without propagating these inputs
as dependencies into all *users* of the listing. For example, the derivation `dep` in the
following example will pull `hello` into its closure despite never using it while `nodep`
will not:
```nix
dep = runCommand "dep" {
inherit hello;
} "echo hello is at $hello >$out";
nodep = runCommand "nodep" {
hello = builtins.unsafeDiscardStringContext hello;
} "echo hello is at $hello >$out";
```
This behavior also makes this function unsafe: if `s` contains the path of a
store object that is not present in the store then any use of `s` in a
derivation tree will attempt to realize that path in the store, but no use
of `unsafeDiscardStringContext s` will. This can lead to derivation outputs that
refer to paths that were never created.
Lix cannot determine whether such reference are safe or not and must pass
this obligation to the user.
+1
View File
@@ -18,6 +18,7 @@ void prim_appendContext(EvalState & state, Value ** args, Value & v);
void prim_getContext(EvalState & state, Value * * args, Value & v);
void prim_hasContext(EvalState & state, Value * * args, Value & v);
void prim_unsafeDiscardOutputDependency(EvalState & state, Value * * args, Value & v);
void prim_unsafeDiscardStringContext(EvalState & state, Value ** args, Value & v);
namespace flake {
+1
View File
@@ -151,6 +151,7 @@ builtin_definitions = files(
'builtins/tryEval.md',
'builtins/typeOf.md',
'builtins/unsafeDiscardOutputDependency.md',
'builtins/unsafeDiscardStringContext.md',
'builtins/unsafeGetAttrPos.md',
'builtins/warn.md',
'builtins/zipAttrsWith.md',
+1 -8
View File
@@ -7,20 +7,13 @@
namespace nix {
static void prim_unsafeDiscardStringContext(EvalState & state, Value * * args, Value & v)
void prim_unsafeDiscardStringContext(EvalState & state, Value ** args, Value & v)
{
NixStringContext context;
auto s = state.coerceToString(noPos, *args[0], context, "while evaluating the argument passed to builtins.unsafeDiscardStringContext");
v.mkString(*s);
}
static RegisterPrimOp primop_unsafeDiscardStringContext({
.name = "__unsafeDiscardStringContext",
.arity = 1,
.fun = prim_unsafeDiscardStringContext
});
void prim_hasContext(EvalState & state, Value * * args, Value & v)
{
NixStringContext context;