Subject: bug#73748: 31.0.50; Problems with company-dabbrev in GNU ELPA package company

From: Stephen Berman <[email-masked]>
Date: Fri, 11 Oct 2024 13:42:54 +0200

0. Install the GNU ELPA packages company and gnu-elpa.
1. emacs -Q
2. M-x package-initialize and M-x toggle-debug-on-error
3. C-x b a M-x company-mode (switch to buffer "a" in fundamental-mode
   and enable company-mode there)
4. Type three arbitrary letters, e.g. dkf
5. On typing the third letter, the following prompt appears in the echo
   area: "Install package all? (yes or no) ".  Type "no".
==> This raises the error "Abort!" and pops up a *Backtrace* buffer,
whose content is attached.

Looking at the backtrace here is what I think happens (though I couldn't
actually get Edebug to stop execution before the prompt in step 5):
company-dabbrev--fetch call company-dabbrev--search, in which the sexp
`(eq other-buffer-modes 'all)' is evaluated as t ('all being the default
value of company-dabbrev-other-buffers), and this causes
gnu-elpa--perform-autoload (in gnu-elpa-utils.el) to be invoked, which
invokes the install package prompt in step 5 because the symbol `all' is
in gnu-elpa-features.el (from the GNU ELPA package "all").

It would not be unreasonable to lay the blame for this problem on the
"all" package with its namespace-unclean autoloaded command `all'
(naming it something like `all-show' would have avoided the problem).
However, the pcase code in company-dabbrev--fetch actually triggers the
problem, and `M-x eval-buffer' on company-dabbrev.el points to why: that
invocation issues the warning "pcase pattern `all shadowed by previous
pcase pattern".

The attached patch (I don't have a local clone of the company package
repo, so it's just a plain diff) avoids both this warning and the
problematic interaction with gnu-elpa--perform-autoload.  This patch
uses 'all instead of `all, since they are the same for symbols in pcase
patterns, and replaces `t by _, in accordance with (info "(elisp) pcase
Macro").  In addition, the patch fixes a typo in the defcustom
`company-dabbrev-other-buffers' that prevents choosing "Function to
return similar major-modes" from the value menu.

In GNU Emacs 31.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version
 3.24.43, cairo version 1.18.2) of 2024-10-05 built on strobelfssd
Repository revision: 4c7a6dc1a0ce8fe7bb603c907efb52d2ecf30858
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12101013
System Description: Linux From Scratch r12.2-17-systemd

Configured using:
 'configure -C 'CFLAGS=-Og -g3' PKG_CONFIG_PATH=/opt/qt6/lib/pkgconfig'

Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
LCMS2 LIBSYSTEMD LIBXML2 MODULES NATIVE_COMP NOTIFY INOTIFY PDUMPER PNG
RSVG SECCOMP SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER
WEBP X11 XDBE XIM XINPUT2 XPM GTK3 ZLIB
*** /home/steve/.emacs.d/elpa/company-1.0.2/company-dabbrev.el_orig	2024-09-23 15:23:02.270065887 +0200
--- /home/steve/.emacs.d/elpa/company-1.0.2/company-dabbrev.el	2024-10-11 11:17:54.607254997 +0200
***************
*** 41,47 ****
    :type '(choice (const :tag "Off" nil)
                   (const :tag "Same major mode" t)
                   (const :tag "All" all)
!                  (function :tag "Function to return similar major-modes" group)))

  (defcustom company-dabbrev-ignore-buffers "\\`[ *]"
    "Regexp matching the names of buffers to ignore.
--- 41,47 ----
    :type '(choice (const :tag "Off" nil)
                   (const :tag "Same major mode" t)
                   (const :tag "All" all)
!                  (function :tag "Function to return similar major-modes")))

  (defcustom company-dabbrev-ignore-buffers "\\`[ *]"
    "Regexp matching the names of buffers to ignore.
***************
*** 198,206 ****
    (company-dabbrev--search (company-dabbrev--make-regexp)
                             company-dabbrev-time-limit
                             (pcase company-dabbrev-other-buffers
!                              (`t (list major-mode))
!                              ((pred functionp) (funcall company-dabbrev-other-buffers (current-buffer)))
!                              (`all `all))))

  ;;;###autoload
  (defun company-dabbrev (command &optional arg &rest _ignored)
--- 198,208 ----
    (company-dabbrev--search (company-dabbrev--make-regexp)
                             company-dabbrev-time-limit
                             (pcase company-dabbrev-other-buffers
!                              ('all 'all)
!                              ((pred functionp)
!                               (funcall company-dabbrev-other-buffers
!                                        (current-buffer)))
!                              (_ (list major-mode)))))

  ;;;###autoload
  (defun company-dabbrev (command &optional arg &rest _ignored)