Skip to content

Commit eb84009

Browse files
committed
handle circulaties better when printing events
Previously, (is (not (% '(#1=(#1#))))) used to overflow that stack.
1 parent 05677f6 commit eb84009

3 files changed

Lines changed: 44 additions & 17 deletions

File tree

src/is.lisp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,10 +347,10 @@
347347
(is (endp (member (1+ 1) '(1 2 3))))
348348
.. debugger invoked on UNEXPECTED-RESULT-FAILURE:
349349
.. UNEXPECTED-FAILURE in check:
350-
.. (IS (ENDP #1=(MEMBER #2=(1+ 1) '(1 2 3))))
350+
.. (IS (ENDP #1=(MEMBER #2=(1+ 1) '(1 . #3=(2 3)))))
351351
.. where
352352
.. #2# = 2
353-
.. #1# = (2 3)
353+
.. #1# = #3#
354354
```
355355
356356
Note that the argument of [NOT][function] is not captured as it is

src/result.lisp

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,29 +40,45 @@
4040
(%write-result-captures result stream)
4141
(%write-result-ctx result stream))))
4242

43-
;;; Remove % and %% (see CAPTURE), so that they don't pollute the form
44-
;;; displayed in the events. KLUDGE: We should use a proper code
45-
;;; walker, but we simply assume that all % and %% are to be removed.
46-
;;; FIXME: Infinite loop on #1=(#1#) or #1=(% #1#).
43+
(declaim (ftype function capture-subform capture-explicitp))
44+
45+
;;; Remove % and %% (see CAPTURE) in explicit captures, so that they
46+
;;; don't pollute the form displayed in the events.
4747
(defun %frob-form-for-printing (result form)
4848
;; Memoize the results so that printing a result twice writes EQ
4949
;; objects and *PRINT-CIRCLE* thus works.
5050
(let ((data (print-form-memoization-data result)))
51-
(labels ((frob (form)
51+
(labels ((explicitly-captured-p (subform)
52+
(loop for capture in (captures result)
53+
thereis (and (capture-explicitp capture)
54+
(eq subform (capture-subform capture)))))
55+
(frob (form)
5256
(or (gethash form data)
5357
(cond
54-
;; Basically ATOM, but also include improper
55-
;; lists.
56-
((not (alexandria:proper-list-p form))
58+
((atom form)
5759
form)
58-
((and (member (first form) '(% %%))
59-
;; Catch circles in code.
60+
((and (member (car form) '(% %%))
61+
;; See if it's a proper list of length 2.
62+
(consp (cdr form))
6063
(null (cddr form))
61-
(= (length form) 2))
62-
(setf (gethash form data) (frob (second form))))
64+
(explicitly-captured-p (second form)))
65+
(let* ((subform (second form))
66+
(frobbed (frob subform)))
67+
(setf (gethash subform data) frobbed)
68+
(values frobbed t)))
6369
(t
64-
(setf (gethash form data)
65-
(mapcar #'frob form)))))))
70+
(let ((new (cons nil nil)))
71+
(setf (gethash form data) new)
72+
(multiple-value-bind (car car-frobbed?)
73+
(frob (car form))
74+
(multiple-value-bind (cdr cdr-frobbed?)
75+
(frob (cdr form))
76+
(cond ((or car-frobbed? cdr-frobbed?)
77+
(setf (car new) car
78+
(cdr new) cdr)
79+
(values new t))
80+
(t
81+
(setf (gethash form data) form)))))))))))
6682
(frob form))))
6783

6884
(defun %write-result-msg (result stream &key terse)

test/test-is.lisp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@
105105
(test-is/capture/evaluation-order)
106106
(test-is/capture/duplicate)
107107
(test-is/capture/nested-subs)
108-
(test-is/capture/improper-list-literal))
108+
(test-is/capture/improper-list-literal)
109+
(test-is/capture/cyclic))
109110

110111
(deftest test-is/capture/implicit-and-explicit ()
111112
(is-ctx-captures '(((null t) nil nil t))
@@ -211,6 +212,16 @@
211212
× (IS (EQUALP 1 '(1 . 2)))
212213
× FOO77 ×1
213214
"))
215+
216+
(deftest test-is/capture/cyclic ()
217+
(check-try-output ((named-lambda-test fff ()
218+
(is (not (% '(#1=(#1#)))))))
219+
"FFF
220+
× (IS (NOT #1='#2=(#3=(#3#))))
221+
where
222+
#1# = #2#
223+
× FFF ×1
224+
"))
214225

215226

216227
(deftest test-is/restarts ()

0 commit comments

Comments
 (0)