doomemacs / doomemacs/core

`###autodef`s in an `;;;###if`-gated autoload file are emitted as live autoloads when the cookie is false

Open Beginner friendly
#8,891 0 comments 0 reactions 0 assignees View on GitHub
AI core:cli
Dominant language
Emacs Lisp
Stars
22.7k
Forks
3.1k
Avg merge
10h 46m
Merged PRs (30d)
4

Description

### Describe your issue

`doom-loaddefs--scan-file` (`lisp/cli/loaddefs.el`) skips the `;;;###autoload` cookies of a file whose `;;;###if` cookie is nil, but hands `doom-loaddefs--scan-autodefs` only the module-level `enabled?` flag, not the cookie verdict:

```elisp
(unless skip?
(quiet! (autoload-generate-file-autoloads file target-buffer)))
(when module?
(doom-loaddefs--scan-autodefs file target-buffer module enabled?))
```

So every `;;;###autodef` in an `###if`-gated file of an active module is written as a live `autoload` into that file instead of the disabled-feature stub. Calling it loads the whole gated file, which redefines whatever else that file `defun`s. The pre-rewrite core passed `(and (doom-module-p ...) (doom-file-cookie-p file "if" t))` (see 3a0f1aa3e).

**Symptom.** `:checkers spell` without `+flyspell`. `+flyspell.el` is gated by `;;;###if (modulep! +flyspell)` and autodefs `set-flyspell-predicate!`. The generated profile init still contains:

```elisp
(autoload 'set-flyspell-predicate! "~/.emacs.d/sources/doom+/modules/checkers/spell/autoload/+flyspell.el" ...)
```

`:lang markdown` calls `set-flyspell-predicate!` as soon as `markdown-mode` loads (an org src block fontified as markdown is enough). That loads `+flyspell.el`, whose `defun`s overwrite all four spell-fu aliases: `+spell/add-word`, `+spell/remove-word`, `+spell/next-error`, `+spell/previous-error`. `+spell/add-word` then fails because its interactive spec needs ispell's dictionary parameters, which spell-fu never initialises:

```
Debugger entered--Lisp error: (error "No data for dictionary \"nil\" in ‘ispell-local-dictionary-alist’ or ‘ispell-dictionary-alist’")
error("No data for dictionary \"%s\" in `ispell-local-dictionary-alist' or `ispell-dictionary-alist'" nil)
ispell-get-decoded-string(1)
flyspell-get-casechars()
flyspell-get-word()
(car (flyspell-get-word))
(progn (require 'flyspell) (car (flyspell-get-word)))
(list (progn (require 'flyspell) (car (flyspell-get-word))) (cond ((equal current-prefix-arg '(16)) 'session) ((equal current-prefix-arg '(4)) 'buffer)))
call-interactively(+spell/add-word)
```

**Proposed fix.** For module files `(not skip?)` is exactly `(and enabled? cookie-ok)`:

```diff
(when module?
- (doom-loaddefs--scan-autodefs file target-buffer module enabled?))
+ (doom-loaddefs--scan-autodefs file target-buffer module (not skip?)))
```

**Workaround** (verified in a fresh daemon: after `(require 'markdown-mode)`, `+spell/add-word` is still `spell-fu-word-add` and `+flyspell.el` is not in `load-history`):

```elisp
(defun set-flyspell-predicate! (&rest _) nil)
```

### Steps to reproduce

1. Enable `:checkers spell` (no `+flyspell`) and `:lang markdown`; `doom sync`.
2. Grep `.local/etc/@/init..el` for `set-flyspell-predicate!`: it is an `autoload` into `+flyspell.el`, not a stub.
3. In Emacs, `(symbol-function '+spell/add-word)` → `spell-fu-word-add`.
4. `(require 'markdown-mode)`.
5. `(symbol-function '+spell/add-word)` → the flyspell `defun`.
6. On a misspelt word in a `text-mode` buffer with `spell-fu-mode`, `M-x +spell/add-word` → backtrace above.

### System information

`doom info`: https://gist.github.com/dustinfarris/66cb6953a4f0841959498fa67c707387

### Disclosures

- [x] This issue was written with/by AI.

Drafted end to end by Claude Fable 5.1 in Claude Code, working in my Emacs session; the diagnosis, init excerpt, backtrace and workaround verification were all produced on my machine. I reviewed it before posting.

Contributor guide

Open the contributing guide

Research direction

Start in lisp/cli/loaddefs.el with doom-loaddefs--scan-file and doom-loaddefs--scan-autodefs, then reproduce with :checkers spell without +flyspell and :lang markdown followed by doom sync. Done means the generated init file emits a disabled-feature stub rather than a live autoload for +flyspell.el, and loading markdown does not redefine the spell-fu commands.

Written by the indexing model from the issue text.

Assessment

Tech stack
emacs-lisp
Domain
build-system
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.