(defun fdefn-fun (fdefn)
(declare (type fdefn fdefn)
- (values (or function null)))
+ (values (or function null)))
(fdefn-fun fdefn))
(defun (setf fdefn-fun) (fun fdefn)
(declare (type function fun)
- (type fdefn fdefn)
- (values function))
+ (type fdefn fdefn)
+ (values function))
(setf (fdefn-fun fdefn) fun))
(defun fdefn-makunbound (fdefn)
;;; CREATE is non-NIL, create a new (unbound) one.
(defun fdefinition-object (name create)
(declare (values (or fdefn null)))
- (unless (legal-fun-name-p name)
- (error 'simple-type-error
- :datum name
- :expected-type '(or symbol list)
- :format-control "invalid function name: ~S"
- :format-arguments (list name)))
+ (legal-fun-name-or-type-error name)
(let ((fdefn (info :function :definition name)))
(if (and (null fdefn) create)
- (setf (info :function :definition name) (make-fdefn name))
- fdefn)))
+ (setf (info :function :definition name) (make-fdefn name))
+ fdefn)))
+
+(defun maybe-clobber-ftype (name)
+ (unless (eq :declared (info :function :where-from name))
+ (clear-info :function :type name)))
;;; Return the fdefinition of NAME, including any encapsulations.
-;;; The compiler emits calls to this when someone tries to FUNCALL
+;;; The compiler emits calls to this when someone tries to FUNCALL
;;; something. SETFable.
#!-sb-fluid (declaim (inline %coerce-name-to-fun))
(defun %coerce-name-to-fun (name)
(let ((fdefn (fdefinition-object name nil)))
(or (and fdefn (fdefn-fun fdefn))
- (error 'undefined-function :name name))))
+ (error 'undefined-function :name name))))
(defun (setf %coerce-name-to-fun) (function name)
+ (maybe-clobber-ftype name)
(let ((fdefn (fdefinition-object name t)))
(setf (fdefn-fun fdefn) function)))
;;;; definition encapsulation
(defstruct (encapsulation-info (:constructor make-encapsulation-info
- (type definition))
- (:copier nil))
+ (type definition))
+ (:copier nil))
;; This is definition's encapsulation type. The encapsulated
- ;; definition is in the previous encapsulation-info element or
+ ;; definition is in the previous ENCAPSULATION-INFO element or
;; installed as the global definition of some function name.
type
;; the previous, encapsulated definition. This used to be installed
;; an encapsulation that no longer exists.
(let ((info (make-encapsulation-info type (fdefn-fun fdefn))))
(setf (fdefn-fun fdefn)
- (lambda (&rest arg-list)
- (declare (special arg-list))
- (let ((basic-definition (encapsulation-info-definition info)))
- (declare (special basic-definition))
- (eval body)))))))
+ (named-lambda encapsulation (&rest arg-list)
+ (declare (special arg-list))
+ (let ((basic-definition (encapsulation-info-definition info)))
+ (declare (special basic-definition))
+ (eval body)))))))
;;; This is like FIND-IF, except that we do it on a compiled closure's
;;; environment.
-(defun find-if-in-closure (test fun)
- (dotimes (index (1- (get-closure-length fun)))
- (let ((elt (%closure-index-ref fun index)))
- (when (funcall test elt)
- (return elt)))))
+(defun find-if-in-closure (test closure)
+ (declare (closure closure))
+ (do-closure-values (value closure)
+ (when (funcall test value)
+ (return value))))
;;; Find the encapsulation info that has been closed over.
(defun encapsulation-info (fun)
- (and (functionp fun)
- (= (widetag-of fun) sb!vm:closure-header-widetag)
- (find-if-in-closure #'encapsulation-info-p fun)))
+ (when (closurep fun)
+ (find-if-in-closure #'encapsulation-info-p fun)))
;;; When removing an encapsulation, we must remember that
;;; encapsulating definitions close over a reference to the
-;;; encapsulation-info that describes the encapsulating definition.
+;;; ENCAPSULATION-INFO that describes the encapsulating definition.
;;; When you find an info with the target type, the previous info in
;;; the chain has the ensulating definition of that type. We take the
;;; encapsulated definition from the info with the target type, and we
#!+sb-doc
"Removes NAME's most recent encapsulation of the specified TYPE."
(let* ((fdefn (fdefinition-object name nil))
- (encap-info (encapsulation-info (fdefn-fun fdefn))))
+ (encap-info (encapsulation-info (fdefn-fun fdefn))))
(declare (type (or encapsulation-info null) encap-info))
(cond ((not encap-info)
- ;; It disappeared on us, so don't worry about it.
- )
- ((eq (encapsulation-info-type encap-info) type)
- ;; It's the first one, so change the fdefn object.
- (setf (fdefn-fun fdefn)
- (encapsulation-info-definition encap-info)))
- (t
- ;; It must be an interior one, so find it.
- (loop
- (let ((next-info (encapsulation-info
- (encapsulation-info-definition encap-info))))
- (unless next-info
- ;; Not there, so don't worry about it.
- (return))
- (when (eq (encapsulation-info-type next-info) type)
- ;; This is it, so unlink us.
- (setf (encapsulation-info-definition encap-info)
- (encapsulation-info-definition next-info))
- (return))
- (setf encap-info next-info))))))
+ ;; It disappeared on us, so don't worry about it.
+ )
+ ((eq (encapsulation-info-type encap-info) type)
+ ;; It's the first one, so change the fdefn object.
+ (setf (fdefn-fun fdefn)
+ (encapsulation-info-definition encap-info)))
+ (t
+ ;; It must be an interior one, so find it.
+ (loop
+ (let ((next-info (encapsulation-info
+ (encapsulation-info-definition encap-info))))
+ (unless next-info
+ ;; Not there, so don't worry about it.
+ (return))
+ (when (eq (encapsulation-info-type next-info) type)
+ ;; This is it, so unlink us.
+ (setf (encapsulation-info-definition encap-info)
+ (encapsulation-info-definition next-info))
+ (return))
+ (setf encap-info next-info))))))
t)
;;; Does NAME have an encapsulation of the given TYPE?
(defun encapsulated-p (name type)
(let ((fdefn (fdefinition-object name nil)))
(do ((encap-info (encapsulation-info (fdefn-fun fdefn))
- (encapsulation-info
- (encapsulation-info-definition encap-info))))
- ((null encap-info) nil)
+ (encapsulation-info
+ (encapsulation-info-definition encap-info))))
+ ((null encap-info) nil)
(declare (type (or encapsulation-info null) encap-info))
(when (eq (encapsulation-info-type encap-info) type)
- (return t)))))
+ (return t)))))
\f
;;;; FDEFINITION
This is SETF'able."
(let ((fun (%coerce-name-to-fun name)))
(loop
- (let ((encap-info (encapsulation-info fun)))
- (if encap-info
- (setf fun (encapsulation-info-definition encap-info))
- (return fun))))))
+ (let ((encap-info (encapsulation-info fun)))
+ (if encap-info
+ (setf fun (encapsulation-info-definition encap-info))
+ (return fun))))))
(defvar *setf-fdefinition-hook* nil
#!+sb-doc
- "This holds functions that (SETF FDEFINITION) invokes before storing the
- new value. These functions take the function name and the new value.")
+ "A list of functions that (SETF FDEFINITION) invokes before storing the
+ new value. The functions take the function name and the new value.")
(defun %set-fdefinition (name new-value)
#!+sb-doc
"Set NAME's global function definition."
(declare (type function new-value) (optimize (safety 1)))
- (let ((fdefn (fdefinition-object name t)))
- ;; *SETF-FDEFINITION-HOOK* won't be bound when initially running
- ;; top level forms in the kernel core startup.
- (when (boundp '*setf-fdefinition-hook*)
- (dolist (f *setf-fdefinition-hook*)
- (funcall f name new-value)))
+ (with-single-package-locked-error (:symbol name "setting fdefinition of ~A")
+ (maybe-clobber-ftype name)
+
+ ;; Check for hash-table stuff. Woe onto him that mixes encapsulation
+ ;; with this.
+ (when (and (symbolp name) (fboundp name)
+ (boundp '*user-hash-table-tests*))
+ (let ((old (symbol-function name)))
+ (declare (special *user-hash-table-tests*))
+ (dolist (spec *user-hash-table-tests*)
+ (cond ((eq old (second spec))
+ ;; test-function
+ (setf (second spec) new-value))
+ ((eq old (third spec))
+ ;; hash-function
+ (setf (third spec) new-value))))))
- (let ((encap-info (encapsulation-info (fdefn-fun fdefn))))
- (cond (encap-info
- (loop
- (let ((more-info
- (encapsulation-info
- (encapsulation-info-definition encap-info))))
- (if more-info
- (setf encap-info more-info)
- (return
- (setf (encapsulation-info-definition encap-info)
- new-value))))))
- (t
- (setf (fdefn-fun fdefn) new-value))))))
+ ;; FIXME: This is a good hook to have, but we should probably
+ ;; reserve it for users.
+ (let ((fdefn (fdefinition-object name t)))
+ ;; *SETF-FDEFINITION-HOOK* won't be bound when initially running
+ ;; top level forms in the kernel core startup.
+ (when (boundp '*setf-fdefinition-hook*)
+ (dolist (f *setf-fdefinition-hook*)
+ (declare (type function f))
+ (funcall f name new-value)))
+
+ (let ((encap-info (encapsulation-info (fdefn-fun fdefn))))
+ (cond (encap-info
+ (loop
+ (let ((more-info
+ (encapsulation-info
+ (encapsulation-info-definition encap-info))))
+ (if more-info
+ (setf encap-info more-info)
+ (return
+ (setf (encapsulation-info-definition encap-info)
+ new-value))))))
+ (t
+ (setf (fdefn-fun fdefn) new-value)))))))
\f
;;;; FBOUNDP and FMAKUNBOUND
(defun fmakunbound (name)
#!+sb-doc
"Make NAME have no global function definition."
- (let ((fdefn (fdefinition-object name nil)))
- (when fdefn
- (fdefn-makunbound fdefn)))
- (sb!kernel:undefine-fun-name name)
- name)
+ (with-single-package-locked-error
+ (:symbol name "removing the function or macro definition of ~A")
+ (let ((fdefn (fdefinition-object name nil)))
+ (when fdefn
+ (fdefn-makunbound fdefn)))
+ (sb!kernel:undefine-fun-name name)
+ name))