diff --git a/guix/utils.scm b/guix/utils.scm index ed13bae307..3d92bac9cc 100644 --- a/guix/utils.scm +++ b/guix/utils.scm @@ -479,20 +479,18 @@ (define (make-syntactic-constructor name ctor fields defaults) (lambda (s) (syntax-case s expected ((_ (field value) (... ...)) - (let ((fields (map syntax->datum #'(field (... ...)))) - (inits (map (match-lambda - ((f v) - (list (syntax->datum f) v))) - #'((field value) (... ...)))) - (dflt (map (match-lambda - ((f v) - (list (syntax->datum f) v))) - #'defaults))) + (let ((fields (map syntax->datum #'(field (... ...)))) + (dflt (map (match-lambda + ((f v) + (list (syntax->datum f) v))) + #'defaults))) - (define (field-value f) - (match (assoc f inits) - ((_ v) v) - (#f (car (assoc-ref dflt f))))) + (define (field-value f) + (or (and=> (find (lambda (x) + (eq? f (car (syntax->datum x)))) + #'((field value) (... ...))) + car) + (car (assoc-ref dflt (syntax->datum f))))) (let-syntax ((error* (syntax-rules () @@ -503,7 +501,8 @@ (define (field-value f) s))))) (let ((fields (append fields (map car dflt)))) (cond ((lset= eq? fields 'expected) - #`(ctor #,@(map field-value 'expected))) + #`(letrec* ((field value) (... ...)) + (ctor #,@(map field-value 'expected)))) ((pair? (lset-difference eq? fields 'expected)) (error* "extraneous field initializers ~a" (lset-difference eq? fields 'expected))) diff --git a/tests/utils.scm b/tests/utils.scm index 83a78b7a78..4a24e23df9 100644 --- a/tests/utils.scm +++ b/tests/utils.scm @@ -112,6 +112,22 @@ (define-record-type* foo make-foo (match (foo (bar 1)) (($ 1 42) #t))))) +(test-assert "define-record-type* with letrec* behavior" + ;; Make sure field initializers can refer to each other as if they were in + ;; a `letrec*'. + (begin + (define-record-type* bar make-bar + foo? + (x bar-x) + (y bar-y (default (+ 40 2))) + (z bar-z)) + (and (match (bar (x 1) (y (+ x 1)) (z (* y 2))) + (($ 1 2 4) #t)) + (match (bar (x 7) (z (* x 3))) + (($ 7 42 21))) + (match (bar (z 21) (x (/ z 3))) + (($ 7 42 21)))))) + (test-end)