aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakater2021-07-12 14:15:54 +0000
committerStefan Monnier2021-07-16 15:40:08 -0400
commit109c27341e35fae778b95e0eb5d4d72927bf4ea8 (patch)
tree02033cc7f712d8f10935aa108455d7b4b6188e77
parent24a8cc5e707affad345e085b6fe8c778559533f6 (diff)
downloademacs-109c27341e35fae778b95e0eb5d4d72927bf4ea8.tar.gz
emacs-109c27341e35fae778b95e0eb5d4d72927bf4ea8.zip
EIEIO: Prevent excessive evaluation of :initform
* lisp/emacs-lisp/eieio.el (initialize-instance): Do not evaluate initform of a slot when initarg for the slot is provided, according to the following secitons of CLHS: - Object Creation and Initialization - Initialization Arguments - Defaulting of Initialization Arguments - Rules for Initialization Arguments * test/lisp/emacs-lisp/eieio-etests/eieio-tests.el: Add corresponding tests Fix a typo
-rw-r--r--lisp/emacs-lisp/eieio.el35
-rw-r--r--test/lisp/emacs-lisp/eieio-tests/eieio-tests.el16
2 files changed, 36 insertions, 15 deletions
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el
index 1c8c372aaef..b31ea42a99b 100644
--- a/lisp/emacs-lisp/eieio.el
+++ b/lisp/emacs-lisp/eieio.el
@@ -53,6 +53,7 @@
53 (message eieio-version)) 53 (message eieio-version))
54 54
55(require 'eieio-core) 55(require 'eieio-core)
56(eval-when-compile (require 'subr-x))
56 57
57 58
58;;; Defining a new class 59;;; Defining a new class
@@ -740,31 +741,37 @@ Called from the constructor routine."
740 "Construct the new object THIS based on SLOTS.") 741 "Construct the new object THIS based on SLOTS.")
741 742
742(cl-defmethod initialize-instance ((this eieio-default-superclass) 743(cl-defmethod initialize-instance ((this eieio-default-superclass)
743 &optional slots) 744 &optional args)
744 "Construct the new object THIS based on SLOTS. 745 "Construct the new object THIS based on SLOTS.
745SLOTS is a tagged list where odd numbered elements are tags, and 746ARGS is a property list where odd numbered elements are tags, and
746even numbered elements are the values to store in the tagged slot. 747even numbered elements are the values to store in the tagged slot.
747If you overload the `initialize-instance', there you will need to 748If you overload the `initialize-instance', there you will need to
748call `shared-initialize' yourself, or you can call `call-next-method' 749call `shared-initialize' yourself, or you can call `call-next-method'
749to have this constructor called automatically. If these steps are 750to have this constructor called automatically. If these steps are
750not taken, then new objects of your class will not have their values 751not taken, then new objects of your class will not have their values
751dynamically set from SLOTS." 752dynamically set from ARGS."
752 ;; First, see if any of our defaults are `lambda', and
753 ;; re-evaluate them and apply the value to our slots.
754 (let* ((this-class (eieio--object-class this)) 753 (let* ((this-class (eieio--object-class this))
754 (initargs args)
755 (slots (eieio--class-slots this-class))) 755 (slots (eieio--class-slots this-class)))
756 (dotimes (i (length slots)) 756 (dotimes (i (length slots))
757 ;; For each slot, see if we need to evaluate it. 757 ;; For each slot, see if we need to evaluate its initform.
758 (let* ((slot (aref slots i)) 758 (let* ((slot (aref slots i))
759 (slot-name (eieio-slot-descriptor-name slot))
759 (initform (cl--slot-descriptor-initform slot))) 760 (initform (cl--slot-descriptor-initform slot)))
760 ;; Those slots whose initform is constant already have the right 761 (unless (or (when-let ((initarg
761 ;; value set in the default-object. 762 (car (rassq slot-name
762 (unless (macroexp-const-p initform) 763 (eieio--class-initarg-tuples
763 ;; FIXME: We should be able to just do (aset this (+ i <cst>) dflt)! 764 this-class)))))
764 (eieio-oset this (cl--slot-descriptor-name slot) 765 (plist-get initargs initarg))
765 (eval initform t)))))) 766 ;; Those slots whose initform is constant already have
766 ;; Shared initialize will parse our slots for us. 767 ;; the right value set in the default-object.
767 (shared-initialize this slots)) 768 (macroexp-const-p initform))
769 ;; FIXME: Use `aset' instead of `eieio-oset', relying on that
770 ;; vector returned by `eieio--class-slots'
771 ;; should be congruent with the object itself.
772 (eieio-oset this slot-name (eval initform t))))))
773 ;; Shared initialize will parse our args for us.
774 (shared-initialize this args))
768 775
769(cl-defgeneric slot-missing (object slot-name _operation &optional _new-value) 776(cl-defgeneric slot-missing (object slot-name _operation &optional _new-value)
770 "Method invoked when an attempt to access a slot in OBJECT fails. 777 "Method invoked when an attempt to access a slot in OBJECT fails.
diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el
index 11ffc115f7e..3ec42343443 100644
--- a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el
+++ b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el
@@ -574,7 +574,21 @@ METHOD is the method that was attempting to be called."
574 (setf (get-slot-3 eitest-t1) 'setf-emu) 574 (setf (get-slot-3 eitest-t1) 'setf-emu)
575 (should (eq (get-slot-3 eitest-t1) 'setf-emu)) 575 (should (eq (get-slot-3 eitest-t1) 'setf-emu))
576 ;; Roll back 576 ;; Roll back
577 (setf (get-slot-3 eitest-t1) 'emu)) 577 (setf (get-slot-3 eitest-t1) 'emu)
578 (defvar eieio-tests-initform-was-evaluated)
579 (defclass eieio-tests-initform-not-evaluated-when-initarg-is-present ()
580 ((slot-with-initarg-and-initform
581 :initarg :slot-with-initarg-and-initform
582 :initform (setf eieio-tests-initform-was-evaluated t))))
583 (setq eieio-tests-initform-was-evaluated nil)
584 (make-instance
585 'eieio-tests-initform-not-evaluated-when-initarg-is-present)
586 (should eieio-tests-initform-was-evaluated)
587 (setq eieio-tests-initform-was-evaluated nil)
588 (make-instance
589 'eieio-tests-initform-not-evaluated-when-initarg-is-present
590 :slot-with-initarg-and-initform t)
591 (should-not eieio-tests-initform-was-evaluated))
578 592
579(defvar eitest-t2 nil) 593(defvar eitest-t2 nil)
580(ert-deftest eieio-test-26-default-inheritance () 594(ert-deftest eieio-test-26-default-inheritance ()