guix_mirror_bot pushed a commit to branch master
in repository guix.

commit 96bd7262777f7f67cdd83c28171425f6bbcf3d50
Author: David Elsing <[email protected]>
AuthorDate: Tue Feb 3 21:33:21 2026 +0100

    gexp: Add 'delayed-object'.
    
    * guix/gexp.scm (<delayed-object>): New record type.
    (delayed-object): New macro.
    (delayed-object-compiler): New gexp compiler.
    * tests/gexp.scm ("delayed-object"): New test.
    * doc/guix.texi (G-Expressions): Document it.
    
    Signed-off-by: Ludovic Courtès <[email protected]>
---
 doc/guix.texi  | 10 ++++++++++
 guix/gexp.scm  | 20 ++++++++++++++++++++
 tests/gexp.scm | 15 +++++++++++++++
 3 files changed, 45 insertions(+)

diff --git a/doc/guix.texi b/doc/guix.texi
index ce67ea9c82..a3b17578a8 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -148,6 +148,7 @@ Copyright @copyright{} 2025 Edouard Klein@*
 Copyright @copyright{} 2025 Rodion Goritskov@*
 Copyright @copyright{} 2025 dan@*
 Copyright @copyright{} 2025 Noé Lopez@*
+Copyright @copyright{} 2026 David Elsing@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -12982,6 +12983,15 @@ The example above returns an object that corresponds 
to the i686 build
 of Coreutils, regardless of the current value of @code{%current-system}.
 @end defmac
 
+@defmac delayed object exp
+This macro delays the evaluation of @var{exp} until the returned object
+is lowered to a derivation or store item.
+
+Its intended use case is to prevent the use of a non-delayed top-level
+variable of another module, e.g. when using a gexp in the @code{source}
+field of a @var{package}.
+@end defmac
+
 @anchor{gexp-input}
 @deffn {Procedure} gexp-input @var{obj} [@var{output}] [#:native? #f]
 Return a @dfn{gexp input} record for the given @var{output} of file-like
diff --git a/guix/gexp.scm b/guix/gexp.scm
index 030092843a..5305678b34 100644
--- a/guix/gexp.scm
+++ b/guix/gexp.scm
@@ -6,6 +6,7 @@
 ;;; Copyright © 2020 Maxim Cournoyer <[email protected]>
 ;;; Copyright © 2021, 2022 Maxime Devos <[email protected]>
 ;;; Copyright © 2025 Tomas Volf <[email protected]>
+;;; Copyright © 2026 David Elsing <[email protected]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -96,6 +97,10 @@
             with-parameters
             parameterized?
 
+            delayed-object
+            delayed-object?
+            delayed-object-promise
+
             load-path-expression
             gexp-modules
 
@@ -778,6 +783,21 @@ x86_64-linux when COREUTILS is lowered."
                            (obj                   ;store item
                             obj)))))))))
 
+;; Object which evaluates its promise when it is lowered.
+(define-record-type <delayed-object>
+  (%delayed-object promise)
+  delayed-object?
+  (promise delayed-object-promise))
+
+(define-syntax-rule (delayed-object body ...)
+  "Delays the evaluation of BODY to lowering time of the return object."
+  (%delayed-object (delay (begin body ...))))
+
+(define-gexp-compiler (delayed-object-compiler (object <delayed-object>)
+                                               system target)
+  (with-monad %store-monad
+    (return (force (delayed-object-promise object)))))
+
 
 ;;;
 ;;; Inputs & outputs.
diff --git a/tests/gexp.scm b/tests/gexp.scm
index 3622324a15..bba8c141f6 100644
--- a/tests/gexp.scm
+++ b/tests/gexp.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014-2025 Ludovic Courtès <[email protected]>
 ;;; Copyright © 2021-2022 Maxime Devos <[email protected]>
+;;; Copyright © 2026 David Elsing <[email protected]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -518,6 +519,20 @@
     (return (and (eq? drv0 result0)
                  (eq? drv1 result1)))))
 
+(test-assertm "delayed-object"
+  (let ((evaluated #f))
+    (mlet* %store-monad ((drv (package->derivation coreutils))
+                         (obj -> (delayed-object
+                                  (begin
+                                    (set! evaluated #t)
+                                    coreutils)))
+                         (first-evaluated -> evaluated)
+                         (result (lower-object obj)))
+      (return (and (string=? (derivation-file-name drv)
+                             (derivation-file-name result))
+                   (not first-evaluated)
+                   evaluated)))))
+
 (test-assert "with-parameters + file-append"
   (let* ((system (match (%current-system)
                    ("aarch64-linux" "x86_64-linux")

Reply via email to