mirror of
git://git.code.sf.net/p/sbcl/sbcl
synced 2026-09-10 07:26:40 -04:00
150 lines
5.3 KiB
Common Lisp
150 lines
5.3 KiB
Common Lisp
;;; Consider the following definitions in which we assign F2 and F3
|
||
;;; the function binding of F1.
|
||
;;; Even if we were to agree that tracing of F2 and F3 should happen
|
||
;;; (which I think is wrong in itself), then what about SB-DEBUG::*TRACED-FUNS* ?
|
||
;;; It doesn't know that F2 and F3 are traced, which seems like a metadata bug.
|
||
;;; So then when we UNTRACE F1, we don't know that we're supposed to UNTRACE
|
||
;;; F2 and F3, so they continue to print the tracing output.
|
||
;;; And aside from that, when F2 or F3 would get invoked, the tracing output
|
||
;;; would suggest that F1 was called by name, which doesn't make a ton of sense,
|
||
;;; because first of all tracing is supposed to print the name of what was
|
||
;;; actually called - which coincidentally is bound to the same function object
|
||
;;; as some other global name - and secondly we just explicitly UNTRACEd the very
|
||
;;; name that it said was called.
|
||
;;; A reasonable solution to these bugs is to remove the tracing encapsulation
|
||
;;; when assigning SYMBOL-FUNCTION or FDEFINITION. Granted there are other
|
||
;;; encapsulations (profiling, e.g.) but this entire area is unspecified.
|
||
|
||
(defparameter *count* 0)
|
||
(defun f1 () (incf *count*))
|
||
|
||
(test-util:with-test (:name (:print-object-function-name :untraced))
|
||
;; The SEARCH allows for SB-KERNEL:INTERPRETED-FUNCTION as well.
|
||
(assert (search "FUNCTION F1>" (prin1-to-string #'f1))))
|
||
|
||
(defvar *f1/base* #'f1)
|
||
(trace f1)
|
||
(defvar *f1/traced* #'f1)
|
||
(setf (symbol-function 'f2) #'f1)
|
||
(setf (fdefinition 'f3) #'f1)
|
||
(defun f4 ())
|
||
(trace f4)
|
||
(defun f5 ())
|
||
(trace f5)
|
||
(setf (symbol-function 'f4) #'f1)
|
||
(setf (fdefinition 'f5) #'f1)
|
||
|
||
(test-util:with-test (:name :symbol-function-vs-fdefinition)
|
||
(assert (not (eq *f1/base* *f1/traced*)))
|
||
(assert (eq (symbol-function 'f1) (fdefinition 'f1))))
|
||
|
||
(test-util:with-test (:name :strip-encap)
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(f1))))
|
||
(assert (search "F1 returned 1" s)))
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(f2))))
|
||
(assert (= (length s) 0)))
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(f3))))
|
||
(assert (= (length s) 0)))
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(f4))))
|
||
(assert (search "F4 returned 4" s)))
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(f5))))
|
||
(assert (search "F5 returned 5" s))))
|
||
|
||
(test-util:with-test (:name (:printed-function-name :traced))
|
||
(assert (search "FUNCTION F1 ENCAPSULATED>"
|
||
(prin1-to-string (symbol-function 'f1))))
|
||
(assert (search "FUNCTION F1 ENCAPSULATED>"
|
||
(prin1-to-string (fdefinition 'f1))))
|
||
(let ((sub (if (typep #'f2 'sb-kernel:interpreted-function)
|
||
"FUNCTION F1"
|
||
"FUNCTION F1 {")))
|
||
(dolist (name '(f2 f3))
|
||
(assert (search sub (prin1-to-string (symbol-function name)))
|
||
() "(SYMBOL-FUNCTION ~S) printed as ~S"
|
||
name (prin1-to-string (symbol-function name)))
|
||
(assert (search sub (prin1-to-string (fdefinition name)))
|
||
() "(FDEFINITION ~S) printed as ~S"
|
||
name (prin1-to-string (fdefinition name)))))
|
||
(dolist (name '(f4 f5))
|
||
(assert (search "FUNCTION F1 ENCAPSULATED {"
|
||
(prin1-to-string (symbol-function name)))
|
||
() "(SYMBOL-FUNCTION ~S) printed as ~S"
|
||
name (prin1-to-string (symbol-function name)))
|
||
(assert (search "FUNCTION F1 ENCAPSULATED {"
|
||
(prin1-to-string (fdefinition name)))
|
||
() "(FDEFINITION ~S) printed as ~S"
|
||
name (prin1-to-string (fdefinition name)))))
|
||
|
||
(defvar *foo*)
|
||
;; this should keep the tracing encapsulation
|
||
(defun f1 () (setq *foo* 'invoked))
|
||
(test-util:with-test (:name :no-strip-encap)
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(f1))))
|
||
(assert (search "F1 returned INVOKED" s))))
|
||
|
||
|
||
;;;; Same thing for generic functions
|
||
|
||
(defparameter *count* 0)
|
||
(defgeneric g1 ()
|
||
(:method ()
|
||
(incf *count*)))
|
||
(defvar *g1/base* #'g1)
|
||
(trace g1)
|
||
(defvar *g1/traced* #'g1)
|
||
(setf (symbol-function 'g2) #'g1)
|
||
(setf (fdefinition 'g3) #'g1)
|
||
(defun g4 ())
|
||
(trace g4)
|
||
(defun g5 ())
|
||
(trace g5)
|
||
(setf (symbol-function 'g4) #'g1)
|
||
(setf (fdefinition 'g5) #'g1)
|
||
|
||
(test-util:with-test (:name (:symbol-function-vs-fdefinition :generic-function))
|
||
(assert (eq *g1/base* *g1/traced*))
|
||
(assert (eq (symbol-function 'g1) (fdefinition 'g1))))
|
||
|
||
(test-util:with-test (:name (:strip-encap :generic-function))
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(g1))))
|
||
(assert (search "G1 returned 1" s)))
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(f2))))
|
||
(assert (= (length s) 0)))
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(f3))))
|
||
(assert (= (length s) 0)))
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(f4))))
|
||
(assert (search "F4 returned 4" s)))
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(f5))))
|
||
(assert (search "F5 returned 5" s))))
|
||
|
||
(defvar *foo*)
|
||
;; this should keep the tracing encapsulation
|
||
(defgeneric g1 ()
|
||
(:method ()
|
||
(setq *foo* 'invoked)))
|
||
(test-util:with-test (:name (:no-strip-encap :generic-function))
|
||
(let ((s (with-output-to-string (*trace-output*)
|
||
(g1))))
|
||
(assert (search "G1 returned INVOKED" s))))
|
||
|
||
|
||
(defun echo (x)
|
||
x)
|
||
|
||
(trace echo)
|
||
|
||
;;; Check that this does not fail when printing *PACKAGE*.
|
||
(let ((*print-readably* t))
|
||
(echo *package*))
|