diff --git a/pkgs/racket-test-core/tests/racket/serialize.rktl b/pkgs/racket-test-core/tests/racket/serialize.rktl index cf342bf9f8..a5312cc3b8 100644 --- a/pkgs/racket-test-core/tests/racket/serialize.rktl +++ b/pkgs/racket-test-core/tests/racket/serialize.rktl @@ -535,6 +535,13 @@ (test s read (open-input-string (get-output-string o)))) (delete-file fn)) +;; ---------------------------------------- + +(define-serializable-struct immutable-a (b)) + +(let ([a (immutable-a (box #f))]) + (set-box! (immutable-a-b a) a) + (deserialize (serialize a))) ;; ---------------------------------------- diff --git a/racket/collects/racket/private/class-internal.rkt b/racket/collects/racket/private/class-internal.rkt index f90e7e461d..880c54ca8b 100644 --- a/racket/collects/racket/private/class-internal.rkt +++ b/racket/collects/racket/private/class-internal.rkt @@ -2459,9 +2459,7 @@ last few projections. (lambda (obj) ((class-serializer c) obj)) deserialize-id - (and (not inspector) - (not (interface-extension? i externalizable<%>)) - (eq? #t (class-serializer super))) + (not (interface-extension? i externalizable<%>)) (or (current-load-relative-directory) (current-directory))))) null)) diff --git a/racket/collects/racket/private/serialize.rkt b/racket/collects/racket/private/serialize.rkt index c5eac794f3..3571d566ce 100644 --- a/racket/collects/racket/private/serialize.rkt +++ b/racket/collects/racket/private/serialize.rkt @@ -154,7 +154,8 @@ (vector? o) (hash? o)) (not (immutable? o))) - (serializable-struct? o) + (and (serializable-struct? o) + (serialize-info-can-cycle? (serializable-info o))) (flvector? o) (fxvector? o) (let ([k (prefab-struct-key o)]) diff --git a/racket/collects/racket/serialize.rkt b/racket/collects/racket/serialize.rkt index 2015a23c6c..84018a6c3b 100644 --- a/racket/collects/racket/serialize.rkt +++ b/racket/collects/racket/serialize.rkt @@ -112,6 +112,11 @@ #'orig-stx (syntax-case #'id/sup () [(_ sup) #'sup])))) + (define can-handle-cycles? + ;; Yes, as long as we have mutators here and for the superclass + (and (andmap values setters) + (or (not super-info) + (andmap values (list-ref super-info 4))))) #`(begin ;; =============== struct with serialize property ================ (define-struct/derived orig-stx @@ -139,11 +144,7 @@ ;; The serializer id: -------------------- (quote-syntax #,deserialize-id) ;; Can handle cycles? -------------------- - ;; Yes, as long as we have mutators for the - ;; superclass. - #,(and (andmap values setters) - (or (not super-info) - (andmap values (list-ref super-info 4)))) + '#,can-handle-cycles? ;; Directory for last-ditch resolution -------------------- (or (current-load-relative-directory) (current-directory)))) @@ -174,16 +175,19 @@ (values s0 (lambda (s) - #,@(if super-info - (map (lambda (set get) - #`((or #,set void) s0 (#,get s))) - (list-ref super-info 4) - (list-ref super-info 3)) - null) - #,@(map (lambda (getter setter) - #`((or #,setter void) s0 (#,getter s))) - getters - setters) + #,(if can-handle-cycles? + #`(begin + #,@(if super-info + (map (lambda (set get) + #`(#,set s0 (#,get s))) + (list-ref super-info 4) + (list-ref super-info 3)) + null) + #,@(map (lambda (getter setter) + #`(#,setter s0 (#,getter s))) + getters + setters)) + #`(error "cannot mutate to complete a cycle")) (void)))))))) #,@(map (lambda (other-deserialize-id proc-expr cycle-proc-expr) #`(define #,other-deserialize-id