aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2015-05-21 23:46:10 -0400
committerStefan Monnier2015-05-21 23:46:10 -0400
commitea92591983a05bd85d52a6a07dd3b7149feb46d2 (patch)
treeb22c6fde14f284e276e587198740d621aaced913
parentf590fc2760f8b8180a4caf77cea81840e37fe29e (diff)
downloademacs-ea92591983a05bd85d52a6a07dd3b7149feb46d2.tar.gz
emacs-ea92591983a05bd85d52a6a07dd3b7149feb46d2.zip
Change defgeneric so it doesn't completely redefine the function
* lisp/emacs-lisp/cl-generic.el (cl-generic-define): Don't throw away previously defined methods. (cl-generic-define-method): Let-bind purify-flag instead of using `fset'. (cl--generic-prefill-dispatchers): Only define during compilation. (cl-method-qualifiers): Remove redundant alias. (help-fns-short-filename): Silence byte-compiler. * test/automated/cl-generic-tests.el: Adjust to new defgeneric semantics.
-rw-r--r--lib-src/emacsclient.c8
-rw-r--r--lisp/ChangeLog.163
-rw-r--r--lisp/emacs-lisp/cl-generic.el43
-rw-r--r--test/automated/cl-generic-tests.el40
4 files changed, 66 insertions, 28 deletions
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index 806275f5b1d..357ebc736ab 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -107,13 +107,13 @@ char *w32_getenv (char *);
107/* Name used to invoke this program. */ 107/* Name used to invoke this program. */
108const char *progname; 108const char *progname;
109 109
110/* The second argument to main. */ 110/* The second argument to main. */
111char **main_argv; 111char **main_argv;
112 112
113/* Nonzero means don't wait for a response from Emacs. --no-wait. */ 113/* Nonzero means don't wait for a response from Emacs. --no-wait. */
114int nowait = 0; 114int nowait = 0;
115 115
116/* Nonzero means don't print messages for successful operations. --quiet. */ 116/* Nonzero means don't print messages for successful operations. --quiet. */
117int quiet = 0; 117int quiet = 0;
118 118
119/* Nonzero means args are expressions to be evaluated. --eval. */ 119/* Nonzero means args are expressions to be evaluated. --eval. */
@@ -131,7 +131,7 @@ const char *alt_display = NULL;
131/* The parent window ID, if we are opening a frame via XEmbed. */ 131/* The parent window ID, if we are opening a frame via XEmbed. */
132char *parent_id = NULL; 132char *parent_id = NULL;
133 133
134/* Nonzero means open a new Emacs frame on the current terminal. */ 134/* Nonzero means open a new Emacs frame on the current terminal. */
135int tty = 0; 135int tty = 0;
136 136
137/* If non-NULL, the name of an editor to fallback to if the server 137/* If non-NULL, the name of an editor to fallback to if the server
@@ -148,7 +148,7 @@ const char *server_file = NULL;
148int emacs_pid = 0; 148int emacs_pid = 0;
149 149
150/* If non-NULL, a string that should form a frame parameter alist to 150/* If non-NULL, a string that should form a frame parameter alist to
151 be used for the new frame */ 151 be used for the new frame. */
152const char *frame_parameters = NULL; 152const char *frame_parameters = NULL;
153 153
154static _Noreturn void print_help_and_exit (void); 154static _Noreturn void print_help_and_exit (void);
diff --git a/lisp/ChangeLog.16 b/lisp/ChangeLog.16
index 457c1511af8..bc5267aadba 100644
--- a/lisp/ChangeLog.16
+++ b/lisp/ChangeLog.16
@@ -5030,8 +5030,7 @@
5030 * mouse.el (mouse-yank-primarY): Look for frame-type w32, not 5030 * mouse.el (mouse-yank-primarY): Look for frame-type w32, not
5031 system-type windows-nt. 5031 system-type windows-nt.
5032 5032
5033 * server.el (server-create-window-system-frame): Look for window 5033 * server.el (server-create-window-system-frame): Look for window type.
5034 type.
5035 (server-proces-filter): Only force a window system when windows-nt 5034 (server-proces-filter): Only force a window system when windows-nt
5036 _and_ w32. Explain why. 5035 _and_ w32. Explain why.
5037 5036
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 13585bcaf18..b3c127f48f7 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -237,14 +237,19 @@ BODY, if present, is used as the body of a default method.
237 (`(,spec-args . ,_) (cl--generic-split-args args)) 237 (`(,spec-args . ,_) (cl--generic-split-args args))
238 (mandatory (mapcar #'car spec-args)) 238 (mandatory (mapcar #'car spec-args))
239 (apo (assq :argument-precedence-order options))) 239 (apo (assq :argument-precedence-order options)))
240 (setf (cl--generic-dispatches generic) nil) 240 (unless (fboundp name)
241 ;; If the generic function was fmakunbound, throw away previous methods.
242 (setf (cl--generic-dispatches generic) nil)
243 (setf (cl--generic-method-table generic) nil))
241 (when apo 244 (when apo
242 (dolist (arg (cdr apo)) 245 (dolist (arg (cdr apo))
243 (let ((pos (memq arg mandatory))) 246 (let ((pos (memq arg mandatory)))
244 (unless pos (error "%S is not a mandatory argument" arg)) 247 (unless pos (error "%S is not a mandatory argument" arg))
245 (push (list (- (length mandatory) (length pos))) 248 (let* ((argno (- (length mandatory) (length pos)))
246 (cl--generic-dispatches generic))))) 249 (dispatches (cl--generic-dispatches generic))
247 (setf (cl--generic-method-table generic) nil) 250 (dispatch (or (assq argno dispatches) (list argno))))
251 (setf (cl--generic-dispatches generic)
252 (cons dispatch (delq dispatch dispatches)))))))
248 (setf (cl--generic-options generic) options) 253 (setf (cl--generic-options generic) options)
249 (cl--generic-make-function generic))) 254 (cl--generic-make-function generic)))
250 255
@@ -438,16 +443,14 @@ which case this method will be invoked when the argument is `eql' to VAL.
438 ;; the generic function. 443 ;; the generic function.
439 current-load-list) 444 current-load-list)
440 ;; For aliases, cl--generic-name gives us the actual name. 445 ;; For aliases, cl--generic-name gives us the actual name.
441 (funcall 446 (let ((purify-flag
442 (if purify-flag 447 ;; BEWARE! Don't purify this function definition, since that leads
443 ;; BEWARE! Don't purify this function definition, since that leads 448 ;; to memory corruption if the hash-tables it holds are modified
444 ;; to memory corruption if the hash-tables it holds are modified 449 ;; (the GC doesn't trace those pointers).
445 ;; (the GC doesn't trace those pointers). 450 nil))
446 #'fset 451 ;; But do use `defalias', so that it interacts properly with nadvice,
447 ;; But do use `defalias' in the normal case, so that it interacts 452 ;; e.g. for tracing/debug-on-entry.
448 ;; properly with nadvice, e.g. for tracing/debug-on-entry. 453 (defalias (cl--generic-name generic) gfun)))))
449 #'defalias)
450 (cl--generic-name generic) gfun))))
451 454
452(defmacro cl--generic-with-memoization (place &rest code) 455(defmacro cl--generic-with-memoization (place &rest code)
453 (declare (indent 1) (debug t)) 456 (declare (indent 1) (debug t))
@@ -705,6 +708,11 @@ methods.")
705 (if (eq specializer t) (list cl--generic-t-generalizer) 708 (if (eq specializer t) (list cl--generic-t-generalizer)
706 (error "Unknown specializer %S" specializer))) 709 (error "Unknown specializer %S" specializer)))
707 710
711(eval-when-compile
712 ;; This macro is brittle and only really important in order to be
713 ;; able to preload cl-generic without also preloading the byte-compiler,
714 ;; So we use `eval-when-compile' so as not keep it available longer than
715 ;; strictly needed.
708(defmacro cl--generic-prefill-dispatchers (arg-or-context specializer) 716(defmacro cl--generic-prefill-dispatchers (arg-or-context specializer)
709 (unless (integerp arg-or-context) 717 (unless (integerp arg-or-context)
710 (setq arg-or-context `(&context . ,arg-or-context))) 718 (setq arg-or-context `(&context . ,arg-or-context)))
@@ -722,7 +730,7 @@ methods.")
722 ,@(cl-generic-generalizers ',specializer) 730 ,@(cl-generic-generalizers ',specializer)
723 ,cl--generic-t-generalizer))) 731 ,cl--generic-t-generalizer)))
724 ;; (message "Prefilling for %S with \n%S" dispatch ',fun) 732 ;; (message "Prefilling for %S with \n%S" dispatch ',fun)
725 (puthash dispatch ',fun cl--generic-dispatchers)))) 733 (puthash dispatch ',fun cl--generic-dispatchers)))))
726 734
727(cl-defmethod cl-generic-combine-methods (generic methods) 735(cl-defmethod cl-generic-combine-methods (generic methods)
728 "Standard support for :after, :before, :around, and `:extra NAME' qualifiers." 736 "Standard support for :after, :before, :around, and `:extra NAME' qualifiers."
@@ -796,8 +804,6 @@ Can only be used from within the lexical body of a primary or around method."
796 specializers qualifiers 804 specializers qualifiers
797 (cl--generic-method-table (cl--generic generic))))) 805 (cl--generic-method-table (cl--generic generic)))))
798 806
799(defalias 'cl-method-qualifiers 'cl--generic-method-qualifiers)
800
801;;; Add support for describe-function 807;;; Add support for describe-function
802 808
803(defun cl--generic-search-method (met-name) 809(defun cl--generic-search-method (met-name)
@@ -850,6 +856,9 @@ Can only be used from within the lexical body of a primary or around method."
850 856
851(add-hook 'help-fns-describe-function-functions #'cl--generic-describe) 857(add-hook 'help-fns-describe-function-functions #'cl--generic-describe)
852(defun cl--generic-describe (function) 858(defun cl--generic-describe (function)
859 ;; Supposedly this is called from help-fns, so help-fns should be loaded at
860 ;; this point.
861 (declare-function help-fns-short-filename "help-fns" (filename))
853 (let ((generic (if (symbolp function) (cl--generic function)))) 862 (let ((generic (if (symbolp function) (cl--generic function))))
854 (when generic 863 (when generic
855 (require 'help-mode) ;Needed for `help-function-def' button! 864 (require 'help-mode) ;Needed for `help-function-def' button!
diff --git a/test/automated/cl-generic-tests.el b/test/automated/cl-generic-tests.el
index a6035d1cba2..2703b44dee5 100644
--- a/test/automated/cl-generic-tests.el
+++ b/test/automated/cl-generic-tests.el
@@ -26,15 +26,18 @@
26(eval-when-compile (require 'ert)) ;Don't indirectly require cl-lib at run-time. 26(eval-when-compile (require 'ert)) ;Don't indirectly require cl-lib at run-time.
27(require 'cl-generic) 27(require 'cl-generic)
28 28
29(fmakunbound 'cl--generic-1)
29(cl-defgeneric cl--generic-1 (x y)) 30(cl-defgeneric cl--generic-1 (x y))
30(cl-defgeneric (setf cl--generic-1) (v y z) "My generic doc.") 31(cl-defgeneric (setf cl--generic-1) (v y z) "My generic doc.")
31 32
32(ert-deftest cl-generic-test-00 () 33(ert-deftest cl-generic-test-00 ()
34 (fmakunbound 'cl--generic-1)
33 (cl-defgeneric cl--generic-1 (x y)) 35 (cl-defgeneric cl--generic-1 (x y))
34 (cl-defmethod cl--generic-1 ((x t) y) (cons x y)) 36 (cl-defmethod cl--generic-1 ((x t) y) (cons x y))
35 (should (equal (cl--generic-1 'a 'b) '(a . b)))) 37 (should (equal (cl--generic-1 'a 'b) '(a . b))))
36 38
37(ert-deftest cl-generic-test-01-eql () 39(ert-deftest cl-generic-test-01-eql ()
40 (fmakunbound 'cl--generic-1)
38 (cl-defgeneric cl--generic-1 (x y)) 41 (cl-defgeneric cl--generic-1 (x y))
39 (cl-defmethod cl--generic-1 ((x t) y) (cons x y)) 42 (cl-defmethod cl--generic-1 ((x t) y) (cons x y))
40 (cl-defmethod cl--generic-1 ((_x (eql 4)) _y) 43 (cl-defmethod cl--generic-1 ((_x (eql 4)) _y)
@@ -54,6 +57,7 @@
54(cl-defstruct (cl-generic-struct-child2 (:include cl-generic-struct-parent)) e) 57(cl-defstruct (cl-generic-struct-child2 (:include cl-generic-struct-parent)) e)
55 58
56(ert-deftest cl-generic-test-02-struct () 59(ert-deftest cl-generic-test-02-struct ()
60 (fmakunbound 'cl--generic-1)
57 (cl-defgeneric cl--generic-1 (x y) "My doc.") 61 (cl-defgeneric cl--generic-1 (x y) "My doc.")
58 (cl-defmethod cl--generic-1 ((x t) y) "Doc 1." (cons x y)) 62 (cl-defmethod cl--generic-1 ((x t) y) "Doc 1." (cons x y))
59 (cl-defmethod cl--generic-1 ((_x cl-generic-struct-parent) y) 63 (cl-defmethod cl--generic-1 ((_x cl-generic-struct-parent) y)
@@ -91,6 +95,7 @@
91 (should (equal x '(3 2 1))))) 95 (should (equal x '(3 2 1)))))
92 96
93(ert-deftest cl-generic-test-04-overlapping-tagcodes () 97(ert-deftest cl-generic-test-04-overlapping-tagcodes ()
98 (fmakunbound 'cl--generic-1)
94 (cl-defgeneric cl--generic-1 (x y) "My doc.") 99 (cl-defgeneric cl--generic-1 (x y) "My doc.")
95 (cl-defmethod cl--generic-1 ((y t) z) (list y z)) 100 (cl-defmethod cl--generic-1 ((y t) z) (list y z))
96 (cl-defmethod cl--generic-1 ((_y (eql 4)) _z) 101 (cl-defmethod cl--generic-1 ((_y (eql 4)) _z)
@@ -104,6 +109,7 @@
104 (should (equal (cl--generic-1 4 'b) '("four" "integer" "number" 4 b)))) 109 (should (equal (cl--generic-1 4 'b) '("four" "integer" "number" 4 b))))
105 110
106(ert-deftest cl-generic-test-05-alias () 111(ert-deftest cl-generic-test-05-alias ()
112 (fmakunbound 'cl--generic-1)
107 (cl-defgeneric cl--generic-1 (x y) "My doc.") 113 (cl-defgeneric cl--generic-1 (x y) "My doc.")
108 (defalias 'cl--generic-2 #'cl--generic-1) 114 (defalias 'cl--generic-2 #'cl--generic-1)
109 (cl-defmethod cl--generic-1 ((y t) z) (list y z)) 115 (cl-defmethod cl--generic-1 ((y t) z) (list y z))
@@ -112,6 +118,7 @@
112 (should (equal (cl--generic-1 4 'b) '("four" 4 b)))) 118 (should (equal (cl--generic-1 4 'b) '("four" 4 b))))
113 119
114(ert-deftest cl-generic-test-06-multiple-dispatch () 120(ert-deftest cl-generic-test-06-multiple-dispatch ()
121 (fmakunbound 'cl--generic-1)
115 (cl-defgeneric cl--generic-1 (x y) "My doc.") 122 (cl-defgeneric cl--generic-1 (x y) "My doc.")
116 (cl-defmethod cl--generic-1 (x y) (list x y)) 123 (cl-defmethod cl--generic-1 (x y) (list x y))
117 (cl-defmethod cl--generic-1 (_x (_y integer)) 124 (cl-defmethod cl--generic-1 (_x (_y integer))
@@ -123,6 +130,7 @@
123 (should (equal (cl--generic-1 1 2) '("x&y-int" "x-int" "y-int" 1 2)))) 130 (should (equal (cl--generic-1 1 2) '("x&y-int" "x-int" "y-int" 1 2))))
124 131
125(ert-deftest cl-generic-test-07-apo () 132(ert-deftest cl-generic-test-07-apo ()
133 (fmakunbound 'cl--generic-1)
126 (cl-defgeneric cl--generic-1 (x y) 134 (cl-defgeneric cl--generic-1 (x y)
127 (:documentation "My doc.") (:argument-precedence-order y x)) 135 (:documentation "My doc.") (:argument-precedence-order y x))
128 (cl-defmethod cl--generic-1 (x y) (list x y)) 136 (cl-defmethod cl--generic-1 (x y) (list x y))
@@ -136,6 +144,7 @@
136 144
137(ert-deftest cl-generic-test-08-after/before () 145(ert-deftest cl-generic-test-08-after/before ()
138 (let ((log ())) 146 (let ((log ()))
147 (fmakunbound 'cl--generic-1)
139 (cl-defgeneric cl--generic-1 (x y)) 148 (cl-defgeneric cl--generic-1 (x y))
140 (cl-defmethod cl--generic-1 ((_x t) y) (cons y log)) 149 (cl-defmethod cl--generic-1 ((_x t) y) (cons y log))
141 (cl-defmethod cl--generic-1 ((_x (eql 4)) _y) 150 (cl-defmethod cl--generic-1 ((_x (eql 4)) _y)
@@ -150,6 +159,7 @@
150(defun cl--generic-test-advice (&rest args) (cons "advice" (apply args))) 159(defun cl--generic-test-advice (&rest args) (cons "advice" (apply args)))
151 160
152(ert-deftest cl-generic-test-09-advice () 161(ert-deftest cl-generic-test-09-advice ()
162 (fmakunbound 'cl--generic-1)
153 (cl-defgeneric cl--generic-1 (x y) "My doc.") 163 (cl-defgeneric cl--generic-1 (x y) "My doc.")
154 (cl-defmethod cl--generic-1 (x y) (list x y)) 164 (cl-defmethod cl--generic-1 (x y) (list x y))
155 (advice-add 'cl--generic-1 :around #'cl--generic-test-advice) 165 (advice-add 'cl--generic-1 :around #'cl--generic-test-advice)
@@ -161,6 +171,7 @@
161 (should (equal (cl--generic-1 4 5) '("integer" 4 5)))) 171 (should (equal (cl--generic-1 4 5) '("integer" 4 5))))
162 172
163(ert-deftest cl-generic-test-10-weird () 173(ert-deftest cl-generic-test-10-weird ()
174 (fmakunbound 'cl--generic-1)
164 (cl-defgeneric cl--generic-1 (x &rest r) "My doc.") 175 (cl-defgeneric cl--generic-1 (x &rest r) "My doc.")
165 (cl-defmethod cl--generic-1 (x &rest r) (cons x r)) 176 (cl-defmethod cl--generic-1 (x &rest r) (cons x r))
166 ;; This kind of definition is not valid according to CLHS, but it does show 177 ;; This kind of definition is not valid according to CLHS, but it does show
@@ -172,6 +183,7 @@
172 (should (equal (cl--generic-1 1 2) '("integer" 2 1)))) 183 (should (equal (cl--generic-1 1 2) '("integer" 2 1))))
173 184
174(ert-deftest cl-generic-test-11-next-method-p () 185(ert-deftest cl-generic-test-11-next-method-p ()
186 (fmakunbound 'cl--generic-1)
175 (cl-defgeneric cl--generic-1 (x y)) 187 (cl-defgeneric cl--generic-1 (x y))
176 (cl-defmethod cl--generic-1 ((x t) y) 188 (cl-defmethod cl--generic-1 ((x t) y)
177 (list x y (cl-next-method-p))) 189 (list x y (cl-next-method-p)))
@@ -179,15 +191,33 @@
179 (cl-list* "quatre" (cl-next-method-p) (cl-call-next-method))) 191 (cl-list* "quatre" (cl-next-method-p) (cl-call-next-method)))
180 (should (equal (cl--generic-1 4 5) '("quatre" t 4 5 nil)))) 192 (should (equal (cl--generic-1 4 5) '("quatre" t 4 5 nil))))
181 193
182(ert-deftest sm-generic-test-12-context () 194(ert-deftest cl-generic-test-12-context ()
195 (fmakunbound 'cl--generic-1)
183 (cl-defgeneric cl--generic-1 ()) 196 (cl-defgeneric cl--generic-1 ())
184 (cl-defmethod cl--generic-1 (&context (overwrite-mode (eql t))) 'is-t) 197 (cl-defmethod cl--generic-1 (&context (overwrite-mode (eql t)))
185 (cl-defmethod cl--generic-1 (&context (overwrite-mode (eql nil))) 'is-nil) 198 (list 'is-t (cl-call-next-method)))
186 (cl-defmethod cl--generic-1 () 'other) 199 (cl-defmethod cl--generic-1 (&context (overwrite-mode (eql nil)))
200 (list 'is-nil (cl-call-next-method)))
201 (cl-defmethod cl--generic-1 () 'any)
187 (should (equal (list (let ((overwrite-mode t)) (cl--generic-1)) 202 (should (equal (list (let ((overwrite-mode t)) (cl--generic-1))
188 (let ((overwrite-mode nil)) (cl--generic-1)) 203 (let ((overwrite-mode nil)) (cl--generic-1))
189 (let ((overwrite-mode 1)) (cl--generic-1))) 204 (let ((overwrite-mode 1)) (cl--generic-1)))
190 '(is-t is-nil other)))) 205 '((is-t any) (is-nil any) any))))
206
207(ert-deftest cl-generic-test-13-head ()
208 (fmakunbound 'cl--generic-1)
209 (cl-defgeneric cl--generic-1 (x y))
210 (cl-defmethod cl--generic-1 ((x t) y) (cons x y))
211 (cl-defmethod cl--generic-1 ((_x (head 4)) _y)
212 (cons "quatre" (cl-call-next-method)))
213 (cl-defmethod cl--generic-1 ((_x (head 5)) _y)
214 (cons "cinq" (cl-call-next-method)))
215 (cl-defmethod cl--generic-1 ((_x (head 6)) y)
216 (cons "six" (cl-call-next-method 'a y)))
217 (should (equal (cl--generic-1 'a nil) '(a)))
218 (should (equal (cl--generic-1 '(4) nil) '("quatre" (4))))
219 (should (equal (cl--generic-1 '(5) nil) '("cinq" (5))))
220 (should (equal (cl--generic-1 '(6) nil) '("six" a))))
191 221
192(provide 'cl-generic-tests) 222(provide 'cl-generic-tests)
193;;; cl-generic-tests.el ends here 223;;; cl-generic-tests.el ends here