Subject: bug#11661: 24.1; (wrong-type-argument stringp t) in `display-completion-list'

From: "Drew Adams" <[email-masked]>
Date: Sat, 9 Jun 2012 10:50:57 -0700

This bug is at least as old as Emacs 20.  So it is clearly not too
important. ;-)
 
emacs -Q
 
M-x load-library minibuffer.el RET
M-x load-library simple.el RET
M-x debug-on-entry display-completion-list
 
Evaluate this in buffer *scratch*, then walk through the debugger:
(display-completion-list ())
 
First, you will notice that the recursive clause is called in this case,
which puts the lie to this comment in the code:
 
;; This *never* (ever) happens, so there's no point trying to be clever.
 
Continuing, the text "There are no possible completions of what you have
typed." is inserted into the temporary buffer, which is expected.  It is
also princ'd, I'm not sure where (or why).  Then the temporary buffer is
killed.  Perhaps it should not be killed in this recursive call of
`display-completion-list'?
 
Continuing, the code uses buffer standard-output, and it runs
`completion-setup-hook' (again), which calls
`completion-setup-function', which also tries (with-current-buffer
standard-output...).  But standard-output is `t' then, so we get:
 
Debugger entered--Lisp error: (wrong-type-argument stringp t)
* set-buffer(t)
* (save-current-buffer (set-buffer standard-output) (let ((base-size
completion-base-size) (base-position completion-base-position)
(insert-fun completion-list-insert-choice-function))
(completion-list-mode) (set (make-local-variable (quote
completion-base-size)) base-size) (set (make-local-variable (quote
completion-base-position)) base-position) (set (make-local-variable
(quote completion-list-insert-choice-function)) insert-fun)) (set
(make-local-variable (quote completion-reference-buffer)) mainbuf) (if
base-dir (setq default-directory base-dir)) (when completion-show-help
(goto-char (point-min)) (if (display-mouse-p) (insert
(substitute-command-keys "Click \\[mouse-choose-completion] on a
completion to select it.\n"))) (insert (substitute-command-keys "In this
buffer, type \\[choose-completion] to select the completion near
point.\n\n"))))
 
`display-completion-list' should do something sane for an empty
completions list in an arbitrary buffer.  Users should never see a
`wrong-type-arg' error.
 
Yes, it is the case that in the existing Emacs source code,
`display-completion-list' is ALWAYS called within
`with-output-to-temp-buffer', with this one exception in `message.el',
where the code does something similar anyway:
 
(with-temp-buffer
 (let ((standard-output (current-buffer)))
   (eval '(display-completion-list nil "")))
 (defalias 'message-display-completion-list
 'display-completion-list))
 
So the problem does not arise for the source code that Emacs provides.
In that context (a) the source comment is true and (b) the error is not
raised.
 
But there is nothing in the doc of `display-completion-list' that says
that it must be called with `standard-output' so bound etc.  It says
only: "It [`completion-setup-hook'] can find the completion buffer in
`standard-output'."  Which is true only if called within
`with-output-to-temp-buffer' or a similar context.

The doc in (elisp) suffers from the same problem.  There, at least, it mentions
`with-output-to-temp-buffer', but it does so only saying "a common way to use
it...".  In fact, that (or equivalent) is currently the ONLY way you can use it
without getting a wrong-type-arg error.
 
The function could try to support enforcement of using it only within
`with-output-to-temp-buffer' by raising an error unless
(bufferp standard-output) (with a better error message than
wrong-type-arg).  But at that point it is too late: it is the user
and not the developer who would see the error.
 
If the code is kept as it is or an error is raised like that, then
the doc should be improved to mention the proper calling context.

FWIW, in the similar Icicles function, I do this for the recursive case
of `display-completion-list', instead of using (with-temp-buffer ...):
 
(let ((standard-output  (current-buffer)))
  (icicle-display-completion-list completions))
 
And I also do not do (princ (buffer-string)) in that case.
 
This has the effect of inserting the text "There are no possible
completions..." - or the completion candidates if there are some -
into the current buffer.  I think it always DTRT (including within
`with-output-to-temp-buffer').
 
Perhaps that would make sense for `display-completion-list' too -
dunno.
 
In GNU Emacs 24.1.1 (i386-mingw-nt5.1.2600)
 of 2012-06-01 on MARVIN
Windowing system distributor `Microsoft Corp.', version 5.1.2600
Configured using:
 `configure --with-gcc (4.6) --no-opt --enable-checking --cflags
 -ID:/devel/emacs/libs/libXpm-3.5.8/include
 -ID:/devel/emacs/libs/libXpm-3.5.8/src
 -ID:/devel/emacs/libs/libpng-dev_1.4.3-1/include
 -ID:/devel/emacs/libs/zlib-dev_1.2.5-2/include
 -ID:/devel/emacs/libs/giflib-4.1.4-1/include
 -ID:/devel/emacs/libs/jpeg-6b-4/include
 -ID:/devel/emacs/libs/tiff-3.8.2-1/include
 -ID:/devel/emacs/libs/gnutls-3.0.9/include'