aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2017-03-24 09:21:52 -0400
committerLars Brinkhoff2017-03-30 18:31:27 +0200
commit390612eb7ab8ccf0792fda7c48b7056c5cda9b06 (patch)
tree71766520a963d9c970cd72e8a2022302661a9f94
parent43cb754a3109ac9afaeab1f08e35673b078a7a09 (diff)
downloademacs-scratch/record.tar.gz
emacs-scratch/record.zip
Backward compatibility with pre-existing struct instances.scratch/record
* lisp/emacs-lisp/cl-lib.el (cl--old-struct-type-of): New function. (cl-old-struct-compat-mode): New minor mode. * lisp/emacs-lisp/cl-macs.el (cl-defstruct): Pass `record' to cl-struct-define to signal use of record objects. * lisp/emacs-lisp/cl-preloaded.el (cl--struct-get-class, cl-struct-define): Enable legacy defstruct compatibility. * test/lisp/emacs-lisp/cl-lib-tests.el (cl-lib-old-struct, old-struct): New tests. * doc/lispref/elisp.texi, doc/lispref/records.texi: Document `old-struct-compat'.
Diffstat (limited to '')
-rw-r--r--doc/lispref/elisp.texi1
-rw-r--r--doc/lispref/records.texi17
-rw-r--r--lisp/emacs-lisp/cl-lib.el36
-rw-r--r--lisp/emacs-lisp/cl-macs.el4
-rw-r--r--lisp/emacs-lisp/cl-preloaded.el6
-rw-r--r--test/lisp/emacs-lisp/cl-lib-tests.el23
6 files changed, 84 insertions, 3 deletions
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi
index 0f7efb6f187..3a348aae98e 100644
--- a/doc/lispref/elisp.texi
+++ b/doc/lispref/elisp.texi
@@ -423,6 +423,7 @@ Sequences, Arrays, and Vectors
423Records 423Records
424 424
425* Record Functions:: Functions for records. 425* Record Functions:: Functions for records.
426* Backward Compatibility:: Compatibility for cl-defstruct.
426 427
427Hash Tables 428Hash Tables
428 429
diff --git a/doc/lispref/records.texi b/doc/lispref/records.texi
index 822fd2bf36e..9a5d900cfc9 100644
--- a/doc/lispref/records.texi
+++ b/doc/lispref/records.texi
@@ -26,7 +26,8 @@ evaluating it is the same record. This does not evaluate or even
26examine the slots. @xref{Self-Evaluating Forms}. 26examine the slots. @xref{Self-Evaluating Forms}.
27 27
28@menu 28@menu
29* Record Functions:: Functions for records. 29* Record Functions:: Functions for records.
30* Backward Compatibility:: Compatibility for cl-defstruct.
30@end menu 31@end menu
31 32
32@node Record Functions 33@node Record Functions
@@ -98,3 +99,17 @@ the copied record, are also visible in the original record.
98@end group 99@end group
99@end example 100@end example
100@end defun 101@end defun
102
103@node Backward Compatibility
104@section Backward Compatibility
105
106 Code compiled with older versions of @code{cl-defstruct} that
107doesn't use records may run into problems when used in a new Emacs.
108To alleviate this, Emacs detects when an old @code{cl-defstruct} is
109used, and enables a mode in which @code{type-of} handles old struct
110objects as if they were records.
111
112@defun cl-old-struct-compat-mode arg
113If @var{arg} is positive, enable backward compatibility with old-style
114structs.
115@end defun
diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el
index 8c4455a3dad..1f8615fad3e 100644
--- a/lisp/emacs-lisp/cl-lib.el
+++ b/lisp/emacs-lisp/cl-lib.el
@@ -639,6 +639,42 @@ If ALIST is non-nil, the new pairs are prepended to it."
639 (require 'cl-macs) 639 (require 'cl-macs)
640 (require 'cl-seq)) 640 (require 'cl-seq))
641 641
642(defun cl--old-struct-type-of (orig-fun object)
643 (or (and (vectorp object)
644 (let ((tag (aref object 0)))
645 (when (and (symbolp tag)
646 (string-prefix-p "cl-struct-" (symbol-name tag)))
647 (unless (eq (symbol-function tag)
648 :quick-object-witness-check)
649 ;; Old-style old-style struct:
650 ;; Convert to new-style old-style struct!
651 (let* ((type (intern (substring (symbol-name tag)
652 (length "cl-struct-"))))
653 (class (cl--struct-get-class type)))
654 ;; If the `cl-defstruct' was recompiled after the code
655 ;; which constructed `object', `cl--struct-get-class' may
656 ;; not have called `cl-struct-define' and setup the tag
657 ;; symbol for us.
658 (unless (eq (symbol-function tag)
659 :quick-object-witness-check)
660 (set tag class)
661 (fset tag :quick-object-witness-check))))
662 (cl--class-name (symbol-value tag)))))
663 (funcall orig-fun object)))
664
665;;;###autoload
666(define-minor-mode cl-old-struct-compat-mode
667 "Enable backward compatibility with old-style structs.
668This can be needed when using code byte-compiled using the old
669macro-expansion of `cl-defstruct' that used vectors objects instead
670of record objects."
671 :global t
672 (cond
673 (cl-old-struct-compat-mode
674 (advice-add 'type-of :around #'cl--old-struct-type-of))
675 (t
676 (advice-remove 'type-of #'cl--old-struct-type-of))))
677
642;; Local variables: 678;; Local variables:
643;; byte-compile-dynamic: t 679;; byte-compile-dynamic: t
644;; End: 680;; End:
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index c282938a9bf..25c9f999920 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2847,8 +2847,8 @@ non-nil value, that slot cannot be set via `setf'.
2847 ;; struct as a parent. 2847 ;; struct as a parent.
2848 (eval-and-compile 2848 (eval-and-compile
2849 (cl-struct-define ',name ,docstring ',include-name 2849 (cl-struct-define ',name ,docstring ',include-name
2850 ',type ,(eq named t) ',descs ',tag-symbol ',tag 2850 ',(or type 'record) ,(eq named t) ',descs
2851 ',print-auto)) 2851 ',tag-symbol ',tag ',print-auto))
2852 ',name))) 2852 ',name)))
2853 2853
2854;;; Add cl-struct support to pcase 2854;;; Add cl-struct support to pcase
diff --git a/lisp/emacs-lisp/cl-preloaded.el b/lisp/emacs-lisp/cl-preloaded.el
index 7432dd4978d..ab6354de7cd 100644
--- a/lisp/emacs-lisp/cl-preloaded.el
+++ b/lisp/emacs-lisp/cl-preloaded.el
@@ -110,6 +110,12 @@
110;;;###autoload 110;;;###autoload
111(defun cl-struct-define (name docstring parent type named slots children-sym 111(defun cl-struct-define (name docstring parent type named slots children-sym
112 tag print) 112 tag print)
113 (unless type
114 ;; Legacy defstruct, using tagged vectors. Enable backward compatibility.
115 (cl-old-struct-compat-mode 1))
116 (if (eq type 'record)
117 ;; Defstruct using record objects.
118 (setq type nil))
113 (cl-assert (or type (not named))) 119 (cl-assert (or type (not named)))
114 (if (boundp children-sym) 120 (if (boundp children-sym)
115 (add-to-list children-sym tag) 121 (add-to-list children-sym tag)
diff --git a/test/lisp/emacs-lisp/cl-lib-tests.el b/test/lisp/emacs-lisp/cl-lib-tests.el
index 26b19e93e42..98c4bd92de6 100644
--- a/test/lisp/emacs-lisp/cl-lib-tests.el
+++ b/test/lisp/emacs-lisp/cl-lib-tests.el
@@ -500,4 +500,27 @@
500 (should (eq (type-of x) 'foo)) 500 (should (eq (type-of x) 'foo))
501 (should (eql (foo-x x) 42)))) 501 (should (eql (foo-x x) 42))))
502 502
503(ert-deftest old-struct ()
504 (cl-defstruct foo x)
505 (let ((x [cl-struct-foo])
506 (saved cl-old-struct-compat-mode))
507 (cl-old-struct-compat-mode -1)
508 (should (eq (type-of x) 'vector))
509
510 (cl-old-struct-compat-mode 1)
511 (setq cl-struct-foo (cl--struct-get-class 'foo))
512 (setf (symbol-function 'cl-struct-foo) :quick-object-witness-check)
513 (should (eq (type-of x) 'foo))
514 (should (eq (type-of [foo]) 'vector))
515
516 (cl-old-struct-compat-mode (if saved 1 -1))))
517
518(ert-deftest cl-lib-old-struct ()
519 (let ((saved cl-old-struct-compat-mode))
520 (cl-old-struct-compat-mode -1)
521 (cl-struct-define 'foo "" 'cl-structure-object nil nil nil
522 'cl-struct-foo-tags 'cl-struct-foo t)
523 (should cl-old-struct-compat-mode)
524 (cl-old-struct-compat-mode (if saved 1 -1))))
525
503;;; cl-lib.el ends here 526;;; cl-lib.el ends here