about summary refs log tree commit diff
path: root/tvix/eval/src
diff options
context:
space:
mode:
authorRyan Lahfa <tvl@lahfa.xyz>2023-12-25T23·39+0100
committerclbot <clbot@tvl.fyi>2023-12-29T22·00+0000
commit3e63d7be42c57f9724dcf5ff2ff3121ceb428f00 (patch)
tree128db7366ba199d20f1437fb5752a2dcd39bbd7d /tvix/eval/src
parent343ee0de57c4d44e6f4ac725eca7e7c4c34eab0d (diff)
feat(tvix/eval): context-aware casting to strings r/7282
By default, we don't want contextful strings and we almost always want contextless strings.

To this end, we make taking a contextful string a very explicit operation under `to_contextful_str`
and we implement manually the `to_str` cast which requires a `if !s.has_context()` guard that
the macro cannot cover.

Change-Id: I7aae8e57a7d73e547e62b1edb0b1cc7e8c0c69b6
Reviewed-on: https://cl.tvl.fyi/c/depot/+/10425
Autosubmit: raitobezarius <tvl@lahfa.xyz>
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval/src')
-rw-r--r--tvix/eval/src/value/mod.rs25
1 files changed, 23 insertions, 2 deletions
diff --git a/tvix/eval/src/value/mod.rs b/tvix/eval/src/value/mod.rs
index 2eb382d0db..16eb2a66b3 100644
--- a/tvix/eval/src/value/mod.rs
+++ b/tvix/eval/src/value/mod.rs
@@ -662,7 +662,27 @@ impl Value {
     gen_cast!(as_bool, bool, "bool", Value::Bool(b), *b);
     gen_cast!(as_int, i64, "int", Value::Integer(x), *x);
     gen_cast!(as_float, f64, "float", Value::Float(x), *x);
-    gen_cast!(to_str, NixString, "string", Value::String(s), s.clone());
+
+    /// Cast the current value into a **context-less** string.
+    /// If you wanted to cast it into a potentially contextful string,
+    /// you have to explicitly use `to_contextful_str`.
+    /// Contextful strings are special, they should not be obtained
+    /// everytime you want a string.
+    pub fn to_str(&self) -> Result<NixString, ErrorKind> {
+        match self {
+            Value::String(s) if !s.has_context() => Ok(s.clone()),
+            Value::Thunk(thunk) => Self::to_str(&thunk.value()),
+            other => Err(type_error("contextless strings", other)),
+        }
+    }
+
+    gen_cast!(
+        to_contextful_str,
+        NixString,
+        "contextful string",
+        Value::String(s),
+        s.clone()
+    );
     gen_cast!(to_path, Box<PathBuf>, "path", Value::Path(p), p.clone());
     gen_cast!(to_attrs, Box<NixAttrs>, "set", Value::Attrs(a), a.clone());
     gen_cast!(to_list, NixList, "list", Value::List(l), l.clone());
@@ -790,7 +810,8 @@ impl Value {
             Value::Bool(b) => format!("the boolean value '{}'", b),
             Value::Integer(i) => format!("the integer '{}'", i),
             Value::Float(f) => format!("the float '{}'", f),
-            Value::String(s) => format!("the string '{}'", s),
+            Value::String(s) if s.has_context() => format!("the contextful string '{}'", s),
+            Value::String(s) => format!("the contextless string '{}'", s),
             Value::Path(p) => format!("the path '{}'", p.to_string_lossy()),
             Value::Attrs(attrs) => format!("a {}-item attribute set", attrs.len()),
             Value::List(list) => format!("a {}-item list", list.len()),