More compact (format nil "~a" ...)
[sbcl.git] / src / pcl / combin.lisp
blobb149a2aee8379eda3e7147136752b0f6cbec3511
1 ;;;; This software is part of the SBCL system. See the README file for
2 ;;;; more information.
4 ;;;; This software is derived from software originally released by Xerox
5 ;;;; Corporation. Copyright and release statements follow. Later modifications
6 ;;;; to the software are in the public domain and are provided with
7 ;;;; absolutely no warranty. See the COPYING and CREDITS files for more
8 ;;;; information.
10 ;;;; copyright information from original PCL sources:
11 ;;;;
12 ;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
13 ;;;; All rights reserved.
14 ;;;;
15 ;;;; Use and copying of this software and preparation of derivative works based
16 ;;;; upon this software are permitted. Any distribution of this software or
17 ;;;; derivative works must comply with all applicable United States export
18 ;;;; control laws.
19 ;;;;
20 ;;;; This software is made available AS IS, and Xerox Corporation makes no
21 ;;;; warranty about the software, its performance or its conformity to any
22 ;;;; specification.
24 (in-package "SB-PCL")
26 (defun get-method-function (method &optional method-alist wrappers)
27 (let ((fn (cadr (assoc method method-alist))))
28 (if fn
29 (values fn nil nil nil)
30 (multiple-value-bind (mf fmf)
31 (if (listp method)
32 (early-method-function method)
33 (values nil (safe-method-fast-function method)))
34 (let* ((pv-table (and fmf (method-plist-value method :pv-table))))
35 (if (and fmf (or (null pv-table) wrappers))
36 (let* ((pv-wrappers (when pv-table
37 (pv-wrappers-from-all-wrappers
38 pv-table wrappers)))
39 (pv (when (and pv-table pv-wrappers)
40 (pv-table-lookup pv-table pv-wrappers))))
41 (values mf t fmf pv))
42 (values
43 (or mf (if (listp method)
44 (bug "early method with no method-function")
45 (method-function method)))
46 t nil nil)))))))
48 (defun make-effective-method-function (generic-function form &optional
49 method-alist wrappers)
50 (funcall (make-effective-method-function1 generic-function form
51 (not (null method-alist))
52 (not (null wrappers)))
53 method-alist wrappers))
55 (defun make-effective-method-function1 (generic-function form
56 method-alist-p wrappers-p)
57 (if (and (listp form)
58 (eq (car form) 'call-method)
59 (not (gf-requires-emf-keyword-checks generic-function)))
60 (make-effective-method-function-simple generic-function form)
61 ;; We have some sort of `real' effective method. Go off and get a
62 ;; compiled function for it. Most of the real hair here is done by
63 ;; the GET-FUN mechanism.
64 (make-effective-method-function-internal generic-function form
65 method-alist-p wrappers-p)))
67 (defun make-effective-method-fun-type (generic-function
68 form
69 method-alist-p
70 wrappers-p)
71 (if (and (listp form)
72 (eq (car form) 'call-method))
73 (let* ((cm-args (cdr form))
74 (method (car cm-args)))
75 (when method
76 (if (if (listp method)
77 (eq (car method) :early-method)
78 (method-p method))
79 (if method-alist-p
81 (multiple-value-bind (mf fmf)
82 (if (listp method)
83 (early-method-function method)
84 (values nil (safe-method-fast-function method)))
85 (declare (ignore mf))
86 (let* ((pv-table (and fmf (method-plist-value method :pv-table))))
87 (if (and fmf (or (null pv-table) wrappers-p))
88 'fast-method-call
89 'method-call))))
90 (if (and (consp method) (eq (car method) 'make-method))
91 (make-effective-method-fun-type
92 generic-function (cadr method) method-alist-p wrappers-p)
93 (type-of method)))))
94 'fast-method-call))
96 (defun make-effective-method-function-simple
97 (generic-function form &optional no-fmf-p)
98 ;; The effective method is just a call to CALL-METHOD. This opens up
99 ;; the possibility of just using the method function of the method as
100 ;; the effective method function.
102 ;; But we have to be careful. If that method function will ask for
103 ;; the next methods we have to provide them. We do not look to see
104 ;; if there are next methods, we look at whether the method function
105 ;; asks about them. If it does, we must tell it whether there are
106 ;; or aren't to prevent the leaky next methods bug.
107 (let* ((cm-args (cdr form))
108 (fmf-p (and (null no-fmf-p)
109 (or (not (eq **boot-state** 'complete))
110 (gf-fast-method-function-p generic-function))
111 (null (cddr cm-args))))
112 (method (car cm-args))
113 (cm-args1 (cdr cm-args)))
114 (lambda (method-alist wrappers)
115 (make-effective-method-function-simple1 generic-function
116 method
117 cm-args1
118 fmf-p
119 method-alist
120 wrappers))))
122 ;;; methods-tracing TODO:
124 ;;; 2. tracing method calls for non-fast-method-function calls
125 ;;; - [DONE] the calls themselves
126 ;;; - calls to the METHOD-FUNCTION of methods with fast functions
127 ;;; (e.g. from something implementing CALL-NEXT-METHOD; handle this with
128 ;;; some more smarts in %METHOD-FUNCTION objects?)
129 ;;; - calls to the METHOD-FUNCTION of methods without fast functions
130 ;;; (TRACE :METHODS T /could/ modify the METHOD-FUNCTION slot)
131 ;;; 4. tracing particular methods
132 ;;; - need an interface.
133 ;;; * (trace (method foo :around (t)))? [ how to trace the method and not
134 ;;; the generic function as a whole?]
135 ;;; * (trace :methods '((:around (t))) foo)? [probably not, interacts
136 ;;; poorly with TRACE arg handling]
137 ;;; 5. supporting non-munged arguments as an option
139 (defun method-trace-name (gf method)
140 ;; KLUDGE: we abuse NIL as second argument to mean that this is a
141 ;; combined method (i.e. something resulting from MAKE-METHOD in a
142 ;; method combination, rather than CALL-METHOD on a method object).
143 (if method
144 `(method ,(generic-function-name gf)
145 ,@(method-qualifiers method)
146 ,(unparse-specializers gf (method-specializers method)))
147 `(combined-method ,(generic-function-name gf))))
149 (defun maybe-trace-method (gf method fun fmf-p)
150 (let ((m-name (when (plusp (hash-table-count sb-debug::*traced-funs*))
151 ;; KLUDGE: testing if *TRACE-FUNS* has anything anything to
152 ;; avoid calling METHOD-TRACE-NAME during PCL bootstrapping
153 ;; when the generic-function type is not yet defined.)
154 (method-trace-name gf method))))
155 (when m-name
156 (sb-debug::retrace-local-funs m-name))
157 (let ((info (when m-name
158 (or (gethash m-name sb-debug::*traced-funs*)
159 (let ((gf-info (gethash (or (generic-function-name gf) gf)
160 sb-debug::*traced-funs*)))
161 (when (and gf-info (sb-debug::trace-info-methods gf-info))
162 (let ((copy (copy-structure gf-info)))
163 (setf (sb-debug::trace-info-what copy) m-name)
164 copy)))))))
165 (if info
166 (lambda (&rest args)
167 (apply #'sb-debug::trace-method-call info fun fmf-p args))
168 fun))))
170 (defun make-emf-from-method
171 (gf method cm-args fmf-p &optional method-alist wrappers)
172 ;; Avoid style-warning about compiler-macro being unavailable.
173 (declare (notinline make-instance))
174 (multiple-value-bind (mf real-mf-p fmf pv)
175 (get-method-function method method-alist wrappers)
176 (if fmf
177 (let* ((next-methods (car cm-args))
178 (next (make-effective-method-function-simple1
179 gf (car next-methods)
180 (list* (cdr next-methods) (cdr cm-args))
181 fmf-p method-alist wrappers))
182 (arg-info (method-plist-value method :arg-info))
183 (default (cons nil nil))
184 (value (method-plist-value method :constant-value default))
185 (fun (maybe-trace-method gf method fmf t)))
186 (if (eq value default)
187 (make-fast-method-call
188 :function fun :pv pv :next-method-call next :arg-info arg-info)
189 (make-constant-fast-method-call
190 :function fun :pv pv :next-method-call next
191 :arg-info arg-info :value value)))
192 (if real-mf-p
193 (flet ((frob-cm-arg (arg)
194 (if (if (listp arg)
195 (eq (car arg) :early-method)
196 (method-p arg))
198 (if (and (consp arg) (eq (car arg) 'make-method))
199 (let ((emf (make-effective-method-function
200 gf (cadr arg) method-alist wrappers)))
201 (etypecase emf
202 (method-call
203 (make-instance 'standard-method
204 :specializers nil ; XXX
205 :qualifiers nil ; XXX
206 :function (method-call-function emf)))
207 (fast-method-call
208 (let* ((fmf (fast-method-call-function emf))
209 (fun (method-function-from-fast-method-call emf))
210 (mf (%make-method-function fmf)))
211 (setf (%funcallable-instance-fun mf) fun)
212 (make-instance 'standard-method
213 :specializers nil ; XXX
214 :qualifiers nil
215 :function mf)))))
216 arg))))
217 (let* ((default (cons nil nil))
218 (value
219 (method-plist-value method :constant-value default))
220 ;; FIXME: this is wrong. Very wrong. It assumes
221 ;; that the only place that can have make-method
222 ;; calls is in the list structure of the second
223 ;; argument to CALL-METHOD, but AMOP says that
224 ;; CALL-METHOD can be more complicated if
225 ;; COMPUTE-EFFECTIVE-METHOD (and presumably
226 ;; MAKE-METHOD-LAMBDA) is adjusted to match.
228 ;; On the other hand, it's a start, because
229 ;; without this calls to MAKE-METHOD in method
230 ;; combination where one of the methods is of a
231 ;; user-defined class don't work at all. -- CSR,
232 ;; 2006-08-05
233 (args (cons (mapcar #'frob-cm-arg (car cm-args))
234 (cdr cm-args)))
235 (fun (maybe-trace-method gf method mf nil)))
236 (if (eq value default)
237 (make-method-call :function fun :call-method-args args)
238 (make-constant-method-call
239 :function fun :value value :call-method-args args))))
240 mf))))
242 (defun make-effective-method-function-simple1
243 (gf method cm-args fmf-p &optional method-alist wrappers)
244 (when method
245 (if (if (listp method)
246 (eq (car method) :early-method)
247 (method-p method))
248 (make-emf-from-method gf method cm-args fmf-p method-alist wrappers)
249 (if (and (consp method) (eq (car method) 'make-method))
250 (make-effective-method-function gf
251 (cadr method)
252 method-alist wrappers)
253 method))))
255 (defvar *global-effective-method-gensyms* ())
256 (defvar *rebound-effective-method-gensyms*)
258 (defun get-effective-method-gensym ()
259 (or (pop *rebound-effective-method-gensyms*)
260 (let ((new (pcl-symbolicate "EFFECTIVE-METHOD-GENSYM-"
261 (length *global-effective-method-gensyms*))))
262 (setq *global-effective-method-gensyms*
263 (append *global-effective-method-gensyms* (list new)))
264 new)))
266 (let ((*rebound-effective-method-gensyms* ()))
267 (dotimes-fixnum (i 10) (get-effective-method-gensym)))
269 (defun expand-effective-method-function (gf effective-method &optional env)
270 (declare (ignore env))
271 (declare (muffle-conditions code-deletion-note))
272 (multiple-value-bind (nreq applyp)
273 (get-generic-fun-info gf)
274 (let ((ll (make-fast-method-call-lambda-list nreq applyp))
275 (mc-args-p
276 (when (eq **boot-state** 'complete)
277 ;; Otherwise the METHOD-COMBINATION slot is not bound.
278 (let ((combin (generic-function-method-combination gf)))
279 (and (long-method-combination-p combin)
280 (long-method-combination-args-lambda-list combin)))))
281 (name `(emf ,(generic-function-name gf))))
282 (cond
283 (mc-args-p
284 (let* ((required (make-dfun-required-args nreq))
285 (gf-args (if applyp
286 `(list* ,@required
287 (sb-c::%listify-rest-args
288 .dfun-more-context.
289 (the (and unsigned-byte fixnum)
290 .dfun-more-count.)))
291 `(list ,@required))))
292 `(named-lambda ,name ,ll
293 (declare (ignore .pv. .next-method-call.))
294 (let ((.gf-args. ,gf-args))
295 (declare (ignorable .gf-args.))
296 ,effective-method))))
298 `(named-lambda ,name ,ll
299 (declare (ignore .pv. .next-method-call.))
300 (declare (ignorable ,@(make-dfun-required-args nreq)
301 ,@(when applyp '(.dfun-more-context. .dfun-more-count.))))
302 ,effective-method))))))
304 (defun expand-emf-call-method (gf form metatypes applyp env)
305 (declare (ignore gf metatypes applyp env))
306 `(call-method ,(cdr form)))
308 (defmacro call-method (&rest args)
309 (declare (ignore args))
310 ;; the PROGN is here to defend against premature macroexpansion by
311 ;; RESTART-CASE.
312 `(progn (error "~S outside of a effective method form" 'call-method)))
314 (defun make-effective-method-list-fun-type
315 (generic-function form method-alist-p wrappers-p)
316 (if (every (lambda (form)
317 (eq 'fast-method-call
318 (make-effective-method-fun-type
319 generic-function form method-alist-p wrappers-p)))
320 (cdr form))
321 'fast-method-call
324 (defun memf-test-converter (form generic-function method-alist-p wrappers-p)
325 (case (and (consp form) (car form))
326 (call-method
327 (case (make-effective-method-fun-type
328 generic-function form method-alist-p wrappers-p)
329 (fast-method-call '.fast-call-method.)
330 (t '.call-method.)))
331 (call-method-list
332 (case (make-effective-method-list-fun-type
333 generic-function form method-alist-p wrappers-p)
334 (fast-method-call '.fast-call-method-list.)
335 (t '.call-method-list.)))
336 (t (default-test-converter form))))
338 ;;; CMUCL comment (2003-10-15):
340 ;;; This function is called via the GET-FUNCTION mechanism on forms
341 ;;; of an emf lambda. First value returned replaces FORM in the emf
342 ;;; lambda. Second value is a list of variable names that become
343 ;;; closure variables.
344 (defun memf-code-converter
345 (form generic-function metatypes applyp method-alist-p wrappers-p)
346 (case (and (consp form) (car form))
347 (call-method
348 (let ((gensym (get-effective-method-gensym)))
349 (values (make-emf-call
350 (length metatypes) applyp gensym
351 (make-effective-method-fun-type
352 generic-function form method-alist-p wrappers-p))
353 (list gensym))))
354 (call-method-list
355 (let ((gensym (get-effective-method-gensym))
356 (type (make-effective-method-list-fun-type
357 generic-function form method-alist-p wrappers-p)))
358 (values `(dolist (emf ,gensym nil)
359 ,(make-emf-call (length metatypes) applyp 'emf type))
360 (list gensym))))
362 (default-code-converter form))))
364 (defun memf-constant-converter (form generic-function)
365 (case (and (consp form) (car form))
366 (call-method
367 (list (cons '.meth.
368 (make-effective-method-function-simple
369 generic-function form))))
370 (call-method-list
371 (list (cons '.meth-list.
372 (mapcar (lambda (form)
373 (make-effective-method-function-simple
374 generic-function form))
375 (cdr form)))))
377 (default-constant-converter form))))
379 (defun make-effective-method-function-internal
380 (generic-function effective-method method-alist-p wrappers-p)
381 (multiple-value-bind (nreq applyp metatypes nkeys arg-info)
382 (get-generic-fun-info generic-function)
383 (declare (ignore nkeys arg-info))
384 (let* ((*rebound-effective-method-gensyms*
385 *global-effective-method-gensyms*)
386 (name (if (early-gf-p generic-function)
387 (!early-gf-name generic-function)
388 (generic-function-name generic-function)))
389 (arg-info (cons nreq applyp))
390 (effective-method-lambda (expand-effective-method-function
391 generic-function effective-method)))
392 (multiple-value-bind (cfunction constants)
393 (get-fun effective-method-lambda
394 (lambda (form)
395 (memf-test-converter form generic-function
396 method-alist-p wrappers-p))
397 (lambda (form)
398 (memf-code-converter form generic-function
399 metatypes applyp
400 method-alist-p wrappers-p))
401 (lambda (form)
402 (memf-constant-converter form generic-function)))
403 (lambda (method-alist wrappers)
404 (flet ((compute-constant (constant)
405 (if (consp constant)
406 (case (car constant)
407 (.meth.
408 (funcall (cdr constant) method-alist wrappers))
409 (.meth-list.
410 (mapcar (lambda (fn)
411 (funcall fn method-alist wrappers))
412 (cdr constant)))
413 (t constant))
414 (case constant
415 (t constant)))))
416 (let ((fun (apply cfunction
417 (mapcar #'compute-constant constants))))
418 (set-fun-name fun `(combined-method ,name))
419 (make-fast-method-call :function (maybe-trace-method generic-function nil fun t)
420 :arg-info arg-info))))))))
422 (defmacro call-method-list (&rest calls)
423 `(progn ,@calls))
425 (defun make-call-methods (methods)
426 `(call-method-list
427 ,@(mapcar (lambda (method) `(call-method ,method ())) methods)))
429 (defun gf-requires-emf-keyword-checks (generic-function)
430 (member '&key (gf-lambda-list generic-function)))
432 (defconstant-eqx +standard-method-combination-qualifiers+
433 '(:around :before :after) #'equal)
435 (defun standard-method-combination-qualifier-p (qualifier)
436 (member qualifier +standard-method-combination-qualifiers+))
438 (defun standard-compute-effective-method
439 (generic-function combin applicable-methods)
440 (collect ((before) (primary) (after) (around))
441 (flet ((invalid (method)
442 (return-from standard-compute-effective-method
443 `(invalid-qualifiers ',generic-function ',combin ',method))))
444 (dolist (m applicable-methods)
445 (let ((qualifiers (if (listp m)
446 (early-method-qualifiers m)
447 (safe-method-qualifiers m))))
448 (cond
449 ((null qualifiers) (primary m))
450 ((cdr qualifiers) (invalid m))
451 ((eq (car qualifiers) :around) (around m))
452 ((eq (car qualifiers) :before) (before m))
453 ((eq (car qualifiers) :after) (after m))
454 (t (invalid m))))))
455 (cond ((null applicable-methods)
456 ;; APPLICABLE-METHODS is normally non-null in effective
457 ;; method computation, but COMPUTE-APPLICABLE-METHODS can
458 ;; in principle be called by MetaObject Protocol programmers.
459 `(method-combination-error
460 "No applicable method found for ~S"
461 ',generic-function))
462 ((null (primary))
463 ;; PCL checks for no primary method before method
464 ;; combination, but a MetaObject Protocol programmer could
465 ;; call COMPUTE-EFFECTIVE-METHOD themselves and end up
466 ;; here.
467 `(method-combination-error
468 "No primary method found for ~S among applicable methods: ~S"
469 ',generic-function (list ,@(mapcar (lambda (m) `(quote ,m)) applicable-methods))))
470 ((and (null (before)) (null (after)) (null (around)))
471 ;; By returning a single call-method `form' here we enable
472 ;; an important implementation-specific optimization; that
473 ;; is, we can use the fast method function directly as the
474 ;; effective method function.
476 ;; However, the requirement by ANSI (CLHS 7.6.5) on generic
477 ;; function argument checking inhibits this, as we don't
478 ;; perform this checking in fast-method-functions given
479 ;; that they are not solely used for effective method
480 ;; functions, but also in combination, when they should not
481 ;; perform argument checks. We still return the bare
482 ;; CALL-METHOD, but the caller is responsible for ensuring
483 ;; that keyword applicability is checked if this is a fast
484 ;; method function used in an effective method. (See
485 ;; WRAP-WITH-APPLICABLE-KEYWORD-CHECK below).
486 `(call-method ,(first (primary)) ,(rest (primary))))
488 (let ((main-effective-method
489 (if (or (before) (after))
490 `(multiple-value-prog1
491 (progn
492 ,(make-call-methods (before))
493 (call-method ,(first (primary))
494 ,(rest (primary))))
495 ,(make-call-methods (reverse (after))))
496 `(call-method ,(first (primary)) ,(rest (primary))))))
497 (if (around)
498 `(call-method ,(first (around))
499 (,@(rest (around))
500 (make-method ,main-effective-method)))
501 main-effective-method))))))
503 (defun short-method-combination-qualifiers (type-name)
504 (list type-name :around))
506 (defun short-method-combination-qualifier-p (type-name qualifier)
507 (or (eq qualifier type-name) (eq qualifier :around)))
509 (defun short-compute-effective-method
510 (generic-function combin applicable-methods)
511 (let ((type-name (method-combination-type-name combin))
512 (operator (short-combination-operator combin))
513 (ioa (short-combination-identity-with-one-argument combin))
514 (order (car (method-combination-options combin)))
515 (around ())
516 (primary ()))
517 (flet ((invalid (method)
518 (return-from short-compute-effective-method
519 `(invalid-qualifiers ',generic-function ',combin ',method))))
520 (dolist (m applicable-methods)
521 (let ((qualifiers (method-qualifiers m)))
522 (cond ((null qualifiers) (invalid m))
523 ((cdr qualifiers) (invalid m))
524 ((eq (car qualifiers) :around)
525 (push m around))
526 ((eq (car qualifiers) type-name)
527 (push m primary))
528 (t (invalid m))))))
529 (setq around (nreverse around))
530 (ecase order
531 (:most-specific-last) ; nothing to be done, already in correct order
532 (:most-specific-first
533 (setq primary (nreverse primary))))
534 (let ((main-method
535 (if (and (null (cdr primary))
536 (not (null ioa)))
537 `(call-method ,(car primary) ())
538 `(,operator ,@(mapcar (lambda (m) `(call-method ,m ()))
539 primary)))))
540 (cond ((null applicable-methods)
541 ;; APPLICABLE-METHODS is normally non-null in effective
542 ;; method computation, but COMPUTE-APPLICABLE-METHODS can
543 ;; in principle be called by MetaObject Protocol programmers.
544 `(method-combination-error
545 "No applicable method found for ~S"
546 ',generic-function))
547 ((null primary)
548 ;; PCL checks for no primary method before method
549 ;; combination, but a MetaObject Protocol programmer could
550 ;; call COMPUTE-EFFECTIVE-METHOD themselves and end up
551 ;; here.
552 `(method-combination-error
553 "No primary method found for ~S among applicable methods: ~S"
554 ',generic-function (list ,@(mapcar (lambda (m) `(quote ,m)) applicable-methods))))
555 ((null around) main-method)
557 `(call-method ,(car around)
558 (,@(cdr around) (make-method ,main-method))))))))
560 ;;; helper code for checking keywords in generic function calls.
561 (defun compute-applicable-keywords (gf methods)
562 (let ((any-keyp nil))
563 (flet ((analyze (lambda-list)
564 (multiple-value-bind (llks nreq nopt keys)
565 (analyze-lambda-list lambda-list)
566 (declare (ignore nreq))
567 (when (ll-kwds-keyp llks)
568 (setq any-keyp t))
569 (values nopt (ll-kwds-allowp llks) keys))))
570 (multiple-value-bind (nopt allowp keys)
571 (analyze (gf-lambda-list gf))
572 (dolist (method methods)
573 (let ((ll (if (consp method)
574 (early-method-lambda-list method)
575 (method-lambda-list method))))
576 (multiple-value-bind (n allowp method-keys)
577 (analyze ll)
578 (declare (ignore n))
579 (when allowp
580 (return-from compute-applicable-keywords (values t nopt)))
581 (setq keys (union method-keys keys)))))
582 (aver any-keyp)
583 (values (if allowp t keys) nopt)))))
585 (defun check-applicable-keywords (start valid-keys more-context more-count)
586 (let ((allow-other-keys-seen nil)
587 (allow-other-keys nil)
588 (i start))
589 (declare (type index i more-count)
590 (optimize speed))
591 (flet ((current-value ()
592 (sb-c::%more-arg more-context i)))
593 (declare (inline current-value))
594 (collect ((invalid))
595 (loop
596 (when (>= i more-count)
597 (when (and (invalid) (not allow-other-keys))
598 (%program-error "~@<invalid keyword argument~P: ~
599 ~{~S~^, ~} (valid keys are ~{~S~^, ~}).~@:>"
600 (length (invalid)) (invalid) valid-keys))
601 (return))
602 (let ((key (current-value)))
603 (incf i)
604 (cond
605 ((not (symbolp key))
606 (%program-error "~@<keyword argument not a symbol: ~S.~@:>"
607 key))
608 ((= i more-count)
609 (sb-c::%odd-key-args-error))
610 ((eq key :allow-other-keys)
611 ;; only the leftmost :ALLOW-OTHER-KEYS has any effect
612 (unless allow-other-keys-seen
613 (setq allow-other-keys-seen t
614 allow-other-keys (current-value))))
615 ((eq t valid-keys))
616 ((not (memq key valid-keys)) (invalid key))))
617 (incf i))))))
619 (defun wrap-with-applicable-keyword-check (effective valid-keys keyargs-start)
620 `(let ((.valid-keys. ',valid-keys)
621 (.keyargs-start. ',keyargs-start))
622 (check-applicable-keywords
623 .keyargs-start. .valid-keys. .dfun-more-context. .dfun-more-count.)
624 ,effective))
626 ;;;; the STANDARD method combination type. This is coded by hand
627 ;;;; (rather than with DEFINE-METHOD-COMBINATION) for bootstrapping
628 ;;;; and efficiency reasons. Note that the definition of the
629 ;;;; FIND-METHOD-COMBINATION-METHOD appears in the file
630 ;;;; defcombin.lisp. This is because EQL methods can't appear in the
631 ;;;; bootstrap.
632 ;;;;
633 ;;;; The DEFCLASS for the METHOD-COMBINATION and
634 ;;;; STANDARD-METHOD-COMBINATION classes has to appear here for this
635 ;;;; reason. This code must conform to the code in the file
636 ;;;; defcombin.lisp, look there for more details.
638 (defun compute-effective-method (generic-function combin applicable-methods)
639 (standard-compute-effective-method generic-function
640 combin
641 applicable-methods))
643 ;;; not INVALID-METHOD-ERROR as that would violate CLHS 11.1.2.1.1
644 (define-condition invalid-method-program-error (program-error simple-condition)
646 (defun invalid-method-error (method format-control &rest format-arguments)
647 (let ((sb-debug:*stack-top-hint* (find-caller-frame)))
648 (error 'invalid-method-program-error
649 :format-control "~@<invalid method error for ~2I~_~S ~I~_method: ~2I~_~?~:>"
650 :format-arguments (list method format-control format-arguments))))
652 ;;; not METHOD-COMBINATION-ERROR as that would violate CLHS 11.1.2.1.1
653 (define-condition method-combination-program-error (program-error simple-condition)
655 (defun method-combination-error (format-control &rest format-arguments)
656 (let ((sb-debug:*stack-top-hint* (find-caller-frame)))
657 (error 'method-combination-program-error
658 :format-control "~@<method combination error in CLOS dispatch: ~2I~_~?~:>"
659 :format-arguments (list format-control format-arguments))))