formatter functions should be lazy in arg count checking
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
New
|
Undecided
|
Unassigned |
Bug Description
Given:
* (defstruct foo a)
* (defmethod print-object ((self foo) stream) (when (eql (foo-a self) 42) (throw 'dog 'bone)))
Other implementations are able to process :
* (catch 'dog (format t "Hi there ~S ~S~%" (make-foo :a 42)))
But the compiler turns that format into a lambda which never executes its body because it insists on receiving 2 args.
(macroexpand-1 '(formatter "Hi there ~S ~S~%"))
#'(LAMBDA
(STREAM
&OPTIONAL
(ERROR 'SB-FORMAT:
"Hi there ~S ~S~%" :OFFSET 10))
(ERROR 'SB-FORMAT:
"Hi there ~S ~S~%" :OFFSET 13))
&REST SB-FORMAT::ARGS)
(DECLARE (IGNORABLE STREAM))
(BLOCK NIL
(WRITE-STRING "Hi there " STREAM)
(PRIN1 #:FORMAT-ARG669 STREAM)
(WRITE-STRING " " STREAM)
(PRIN1 #:FORMAT-ARG670 STREAM)
(TERPRI STREAM))
SB-
Probably we should have the lambda accept a dx &rest arg and use guarded expressions of the form
(output-something (if (> (length args) K) (NTH ...) (error ...)))
which should compile not too much worse if either &rest is converted to &more or is really stack-allocated.
actually, since you have to return args anyway, there's no additional overhead imposed by
(output-something (if args (pop args) (error ...))