]> git.eshelyaron.com Git - emacs.git/commitdiff
Make "parentless" structs inherit from their builtin type
authorStefan Monnier <monnier@iro.umontreal.ca>
Thu, 7 Mar 2024 21:58:15 +0000 (16:58 -0500)
committerEshel Yaron <me@eshelyaron.com>
Mon, 11 Mar 2024 09:16:50 +0000 (10:16 +0100)
* lisp/emacs-lisp/cl-preloaded.el (cl--struct-register-child):
Register child only in struct parents.
(cl-struct-define): Put the "type" as parent of parentless :type structs.
Copy slots only from struct parent classes.
(cl-structure-object): Set (manually) its parent to `record`
and remove assertion that it has no parents.

(cherry picked from commit 7c127fc965fbe781141a6bccbe0b620dc7862b1d)

lisp/emacs-lisp/cl-preloaded.el

index 882b4b5939b81476a215f814ab5e9708741bc83a..1b330e7f761bbe403e6f8ed4216e2a0a4cacbbbe 100644 (file)
 (defun cl--struct-register-child (parent tag)
   ;; Can't use (cl-typep parent 'cl-structure-class) at this stage
   ;; because `cl-structure-class' is defined later.
-  (while (recordp parent)
+  (while (cl--struct-class-p parent)
     (add-to-list (cl--struct-class-children-sym parent) tag)
     ;; Only register ourselves as a child of the leftmost parent since structs
     ;; can only have one parent.
     (with-suppressed-warnings ((obsolete cl-old-struct-compat-mode))
       (message "cl-old-struct-compat-mode is obsolete!")
       (cl-old-struct-compat-mode 1)))
-  (if (eq type 'record)
-      ;; Defstruct using record objects.
-      (setq type nil))
+  (when (eq type 'record)
+    ;; Defstruct using record objects.
+    (setq type nil)
+    ;; `cl-structure-class' and `cl-structure-object' are allowed to be
+    ;; defined without specifying the parent, because their parent
+    ;; doesn't exist yet when they're defined.
+    (cl-assert (or parent (memq name '(cl-structure-class
+                                       cl-structure-object)))))
   (cl-assert (or type (not named)))
   (if (boundp children-sym)
       (add-to-list children-sym tag)
   (and (null type) (eq (caar slots) 'cl-tag-slot)
        ;; Hide the tag slot from "standard" (i.e. non-`type'd) structs.
        (setq slots (cdr slots)))
-  (let* ((parent-class (when parent (cl--struct-get-class parent)))
+  (let* ((parent-class (if parent (cl--struct-get-class parent)
+                         (cl--find-class (if (eq type 'list) 'cons
+                                           (or type 'record)))))
          (n (length slots))
          (index-table (make-hash-table :test 'eq :size n))
          (vslots (let ((v (make-vector n nil))
                  name docstring
                  (unless (symbolp parent-class) (list parent-class))
                  type named vslots index-table children-sym tag print)))
-    (unless (symbolp parent-class)
+    (cl-assert (or (not (symbolp parent-class))
+                   (memq name '(cl-structure-class cl-structure-object))))
+    (when (cl--struct-class-p parent-class)
       (let ((pslots (cl--struct-class-slots parent-class)))
         (or (>= n (length pslots))
             (let ((ok t))
@@ -417,6 +426,13 @@ For this build of Emacs it's %dbit."
 (cl--define-built-in-type subr-primitive (subr)
   "Type of functions hand written in C.")
 
+(unless (cl--class-parents (cl--find-class 'cl-structure-object))
+  ;; When `cl-structure-object' is created, built-in classes didn't exist
+  ;; yet, so we couldn't put `record' as the parent.
+  ;; Fix it now to close the recursion.
+  (setf (cl--class-parents (cl--find-class 'cl-structure-object))
+      (list (cl--find-class 'record))))
+
 (defconst cl--direct-supertypes-of-type
   ;; Please run `sycdoc-update-type-hierarchy' in
   ;; `admin/syncdoc-type-hierarchy.el' each time this is modified to
@@ -447,9 +463,6 @@ supertypes from the most specific to least specific.")
 (defconst cl--all-builtin-types
   (delete-dups (copy-sequence (apply #'append cl--typeof-types))))
 
-(eval-and-compile
-  (cl-assert (null (cl--class-parents (cl--find-class 'cl-structure-object)))))
-
 ;; Make sure functions defined with cl-defsubst can be inlined even in
 ;; packages which do not require CL.  We don't put an autoload cookie
 ;; directly on that function, since those cookies only go to cl-loaddefs.