GNU bug report logs - #69120
Spurious "function is not known to be defined" if defined in `use-package` body

Previous Next

Package: emacs;

Reported by: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>

Date: Wed, 14 Feb 2024 11:17:02 UTC

Severity: normal

To reply to this bug, email your comments to 69120 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Wed, 14 Feb 2024 11:17:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Konstantin Kharlamov <Hi-Angel <at> yandex.ru>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Wed, 14 Feb 2024 11:17:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
To: bug-gnu-emacs <at> gnu.org
Subject: Spurious "function is not known to be defined" if defined in
 `use-package` body
Date: Wed, 14 Feb 2024 14:16:09 +0300
I have many functions that are only useful inside a specific mode. So I
group them with `use-package`, by defining them inside `:init` or
`:config` section, depending on the use.

It turns out, byte-compiler does not consider such functions to be
defined and prints a warning about it.

# Steps to reproduce (in terms of terminal commands)

    λ cat test.el
    ;;; -*- lexical-binding: t -*-
    (use-package prog-mode
      :init
      (defun hello()
        (print "hello"))
      (hello))
    λ emacs -batch -f batch-byte-compile test.el

    In end of data:
    test.el:6:4: Warning: the function ‘hello’ is not known to be defined.

## Expected

File gets compiled with no warnings

## Actual

There's a warning

    test.el:6:4: Warning: the function ‘hello’ is not known to be defined.

# Additional information

Emacs version: commit d4d5830f8a0 built two weeks ago from master.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Wed, 14 Feb 2024 15:24:02 GMT) Full text and rfc822 format available.

Message #8 received at 69120 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
Cc: 69120 <at> debbugs.gnu.org
Subject: Re: bug#69120: Spurious "function is not known to be defined" if
 defined in `use-package` body
Date: Wed, 14 Feb 2024 17:23:02 +0200
> From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
> Date: Wed, 14 Feb 2024 14:16:09 +0300
> 
> I have many functions that are only useful inside a specific mode. So I
> group them with `use-package`, by defining them inside `:init` or
> `:config` section, depending on the use.
> 
> It turns out, byte-compiler does not consider such functions to be
> defined and prints a warning about it.
> 
> # Steps to reproduce (in terms of terminal commands)
> 
>     λ cat test.el
>     ;;; -*- lexical-binding: t -*-
>     (use-package prog-mode
>       :init
>       (defun hello()
>         (print "hello"))
>       (hello))
>     λ emacs -batch -f batch-byte-compile test.el
> 
>     In end of data:
>     test.el:6:4: Warning: the function ‘hello’ is not known to be defined.
> 
> ## Expected
> 
> File gets compiled with no warnings
> 
> ## Actual
> 
> There's a warning
> 
>     test.el:6:4: Warning: the function ‘hello’ is not known to be defined.

What do you get if you macro-expand your code?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Wed, 14 Feb 2024 15:30:02 GMT) Full text and rfc822 format available.

Message #11 received at 69120 <at> debbugs.gnu.org (full text, mbox):

From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 69120 <at> debbugs.gnu.org
Subject: Re: bug#69120: Spurious "function is not known to be defined" if
 defined in `use-package` body
Date: Wed, 14 Feb 2024 18:28:15 +0300
On Wed, 2024-02-14 at 17:23 +0200, Eli Zaretskii wrote:
> > From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
> > Date: Wed, 14 Feb 2024 14:16:09 +0300
> > 
> > I have many functions that are only useful inside a specific mode.
> > So I
> > group them with `use-package`, by defining them inside `:init` or
> > `:config` section, depending on the use.
> > 
> > It turns out, byte-compiler does not consider such functions to be
> > defined and prints a warning about it.
> > 
> > # Steps to reproduce (in terms of terminal commands)
> > 
> >     λ cat test.el
> >     ;;; -*- lexical-binding: t -*-
> >     (use-package prog-mode
> >       :init
> >       (defun hello()
> >         (print "hello"))
> >       (hello))
> >     λ emacs -batch -f batch-byte-compile test.el
> > 
> >     In end of data:
> >     test.el:6:4: Warning: the function ‘hello’ is not known to be
> > defined.
> > 
> > ## Expected
> > 
> > File gets compiled with no warnings
> > 
> > ## Actual
> > 
> > There's a warning
> > 
> >     test.el:6:4: Warning: the function ‘hello’ is not known to be
> > defined.
> 
> What do you get if you macro-expand your code?

Wrapping the above code to a `(macroexpand …)` gives a:

   "hello"
   nil




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Wed, 14 Feb 2024 16:09:02 GMT) Full text and rfc822 format available.

Message #14 received at 69120 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
Cc: 69120 <at> debbugs.gnu.org
Subject: Re: bug#69120: Spurious "function is not known to be defined" if
 defined in `use-package` body
Date: Wed, 14 Feb 2024 18:07:45 +0200
> From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
> Cc: 69120 <at> debbugs.gnu.org
> Date: Wed, 14 Feb 2024 18:28:15 +0300
> 
> > >     test.el:6:4: Warning: the function ‘hello’ is not known to be
> > > defined.
> > 
> > What do you get if you macro-expand your code?
> 
> Wrapping the above code to a `(macroexpand …)` gives a:
> 
>    "hello"
>    nil

You need to quote the form you pass to macroexpand, to get the
expansion, I think.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Wed, 14 Feb 2024 16:12:02 GMT) Full text and rfc822 format available.

Message #17 received at 69120 <at> debbugs.gnu.org (full text, mbox):

From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 69120 <at> debbugs.gnu.org
Subject: Re: bug#69120: Spurious "function is not known to be defined" if
 defined in `use-package` body
Date: Wed, 14 Feb 2024 19:10:54 +0300
On Wed, 2024-02-14 at 18:07 +0200, Eli Zaretskii wrote:
> > From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
> > Cc: 69120 <at> debbugs.gnu.org
> > Date: Wed, 14 Feb 2024 18:28:15 +0300
> >
> > > >     test.el:6:4: Warning: the function ‘hello’ is not known to
> > > > be
> > > > defined.
> > >
> > > What do you get if you macro-expand your code?
> >
> > Wrapping the above code to a `(macroexpand …)` gives a:
> >
> >    "hello"
> >    nil
>
> You need to quote the form you pass to macroexpand, to get the
> expansion, I think.

Oh indeed you're right!

It gives me the following:

(progn (defvar use-package--warning196 #'(lambda (keyword err) (let ((msg (format "%s/%s: %s" 'prog-mode keyword (error-message-string err)))) (display-warning 'use-package msg :error)))) (condition-case-unless-debug err (progn (condition-case-unless-debug err (progn (defun hello nil (print "hello")) (hello)) (error (funcall use-package--warning196 :init err))) (if (not (require 'prog-mode nil t)) (display-warning 'use-package (format "Cannot load %s" 'prog-mode) :error))) (error (funcall use-package--warning196 :catch err))))




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Wed, 14 Feb 2024 16:39:01 GMT) Full text and rfc822 format available.

Message #20 received at 69120 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
Cc: 69120 <at> debbugs.gnu.org
Subject: Re: bug#69120: Spurious "function is not known to be defined" if
 defined in `use-package` body
Date: Wed, 14 Feb 2024 18:38:01 +0200
> From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
> Cc: 69120 <at> debbugs.gnu.org
> Date: Wed, 14 Feb 2024 19:10:54 +0300
> 
> On Wed, 2024-02-14 at 18:07 +0200, Eli Zaretskii wrote:
> > > From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
> > > Cc: 69120 <at> debbugs.gnu.org
> > > Date: Wed, 14 Feb 2024 18:28:15 +0300
> > >
> > > > >     test.el:6:4: Warning: the function ‘hello’ is not known to
> > > > > be
> > > > > defined.
> > > >
> > > > What do you get if you macro-expand your code?
> > >
> > > Wrapping the above code to a `(macroexpand …)` gives a:
> > >
> > >    "hello"
> > >    nil
> >
> > You need to quote the form you pass to macroexpand, to get the
> > expansion, I think.
> 
> Oh indeed you're right!
> 
> It gives me the following:
> 
> (progn (defvar use-package--warning196 #'(lambda (keyword err) (let ((msg (format "%s/%s: %s" 'prog-mode keyword (error-message-string err)))) (display-warning 'use-package msg :error)))) (condition-case-unless-debug err (progn (condition-case-unless-debug err (progn (defun hello nil (print "hello")) (hello)) (error (funcall use-package--warning196 :init err))) (if (not (require 'prog-mode nil t)) (display-warning 'use-package (format "Cannot load %s" 'prog-mode) :error))) (error (funcall use-package--warning196 :catch err))))

And that doesn't explain the warning?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Wed, 14 Feb 2024 17:00:03 GMT) Full text and rfc822 format available.

Message #23 received at 69120 <at> debbugs.gnu.org (full text, mbox):

From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 69120 <at> debbugs.gnu.org
Subject: Re: bug#69120: Spurious "function is not known to be defined" if
 defined in `use-package` body
Date: Wed, 14 Feb 2024 19:58:36 +0300
On Wed, 2024-02-14 at 18:38 +0200, Eli Zaretskii wrote:
> > From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
> > Cc: 69120 <at> debbugs.gnu.org
> > Date: Wed, 14 Feb 2024 19:10:54 +0300
> >
> > On Wed, 2024-02-14 at 18:07 +0200, Eli Zaretskii wrote:
> > > > From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
> > > > Cc: 69120 <at> debbugs.gnu.org
> > > > Date: Wed, 14 Feb 2024 18:28:15 +0300
> > > >
> > > > > >     test.el:6:4: Warning: the function ‘hello’ is not known
> > > > > > to
> > > > > > be
> > > > > > defined.
> > > > >
> > > > > What do you get if you macro-expand your code?
> > > >
> > > > Wrapping the above code to a `(macroexpand …)` gives a:
> > > >
> > > >    "hello"
> > > >    nil
> > >
> > > You need to quote the form you pass to macroexpand, to get the
> > > expansion, I think.
> >
> > Oh indeed you're right!
> >
> > It gives me the following:
> >
> > (progn (defvar use-package--warning196 #'(lambda (keyword err) (let
> > ((msg (format "%s/%s: %s" 'prog-mode keyword (error-message-string
> > err)))) (display-warning 'use-package msg :error)))) (condition-
> > case-unless-debug err (progn (condition-case-unless-debug err
> > (progn (defun hello nil (print "hello")) (hello)) (error (funcall
> > use-package--warning196 :init err))) (if (not (require 'prog-mode
> > nil t)) (display-warning 'use-package (format "Cannot load %s"
> > 'prog-mode) :error))) (error (funcall use-package--warning196
> > :catch err))))
>
> And that doesn't explain the warning?

Mhm… Well, that does reduce the testcase to this code:

    ;;; -*- lexical-binding: t -*-
    (progn
      (defun hello()
        (print "hello"))
      (hello))

So the function is defined in the same visibility scope as where it's used, right
before its use, but byte-compiler apparently doesn't see that.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Thu, 15 Feb 2024 03:59:02 GMT) Full text and rfc822 format available.

Message #26 received at 69120 <at> debbugs.gnu.org (full text, mbox):

From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 69120 <at> debbugs.gnu.org
Subject: Re: bug#69120: Spurious "function is not known to be defined" if
 defined in `use-package` body
Date: Thu, 15 Feb 2024 06:57:41 +0300
On Wed, 2024-02-14 at 19:58 +0300, Konstantin Kharlamov wrote:
> Mhm… Well, that does reduce the testcase to this code:
> 
>     ;;; -*- lexical-binding: t -*-
>     (progn
>       (defun hello()
>         (print "hello"))
>       (hello))
> 
> So the function is defined in the same visibility scope as where it's
> used, right
> before its use, but byte-compiler apparently doesn't see that.

Turns out this false-positive is even more common than I thought.

As upstream Emacs deprecated `defadvice`, I'm porting `lsp-mode` plugin
to an `advice-add`. They use it as a debugging facility, and there's an
"advicing" call inside a `(defun …)`, and the function is defined
inside the same `(defun …)` as well. And it also triggers the same
warning. In terms of minimal testcase:

   ;;; -*- lexical-binding: t -*-
   (defun foo ()
     (defun hello()
       (print "hello"))
     (hello))
   




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Thu, 15 Feb 2024 04:02:02 GMT) Full text and rfc822 format available.

Message #29 received at 69120 <at> debbugs.gnu.org (full text, mbox):

From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 69120 <at> debbugs.gnu.org
Subject: Re: bug#69120: Spurious "function is not known to be defined" if
 defined in `use-package` body
Date: Thu, 15 Feb 2024 07:00:40 +0300
On Thu, 2024-02-15 at 06:57 +0300, Konstantin Kharlamov wrote:
> On Wed, 2024-02-14 at 19:58 +0300, Konstantin Kharlamov wrote:
> > Mhm… Well, that does reduce the testcase to this code:
> > 
> >     ;;; -*- lexical-binding: t -*-
> >     (progn
> >       (defun hello()
> >         (print "hello"))
> >       (hello))
> > 
> > So the function is defined in the same visibility scope as where
> > it's
> > used, right
> > before its use, but byte-compiler apparently doesn't see that.
> 
> Turns out this false-positive is even more common than I thought.
> 
> As upstream Emacs deprecated `defadvice`, I'm porting `lsp-mode`
> plugin
> to an `advice-add`. They use it as a debugging facility, and there's
> an
> "advicing" call inside a `(defun …)`, and the function is defined
> inside the same `(defun …)` as well. And it also triggers the same
> warning. In terms of minimal testcase:
> 
>    ;;; -*- lexical-binding: t -*-
>    (defun foo ()
>      (defun hello()
>        (print "hello"))
>      (hello))

An interesting fact: inserting a `(declare-function hello nil)` after a
`defun` suppresses the warning. So I guess `defun` should work somehow
similarly to `declare-function`.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Thu, 15 Feb 2024 06:52:02 GMT) Full text and rfc822 format available.

Message #32 received at 69120 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 69120 <at> debbugs.gnu.org
Subject: Re: bug#69120: Spurious "function is not known to be defined" if
 defined in `use-package` body
Date: Thu, 15 Feb 2024 08:51:28 +0200
> From: Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
> Cc: 69120 <at> debbugs.gnu.org
> Date: Thu, 15 Feb 2024 07:00:40 +0300
> 
> On Thu, 2024-02-15 at 06:57 +0300, Konstantin Kharlamov wrote:
> > On Wed, 2024-02-14 at 19:58 +0300, Konstantin Kharlamov wrote:
> > > Mhm… Well, that does reduce the testcase to this code:
> > > 
> > >     ;;; -*- lexical-binding: t -*-
> > >     (progn
> > >       (defun hello()
> > >         (print "hello"))
> > >       (hello))
> > > 
> > > So the function is defined in the same visibility scope as where
> > > it's
> > > used, right
> > > before its use, but byte-compiler apparently doesn't see that.
> > 
> > Turns out this false-positive is even more common than I thought.
> > 
> > As upstream Emacs deprecated `defadvice`, I'm porting `lsp-mode`
> > plugin
> > to an `advice-add`. They use it as a debugging facility, and there's
> > an
> > "advicing" call inside a `(defun …)`, and the function is defined
> > inside the same `(defun …)` as well. And it also triggers the same
> > warning. In terms of minimal testcase:
> > 
> >    ;;; -*- lexical-binding: t -*-
> >    (defun foo ()
> >      (defun hello()
> >        (print "hello"))
> >      (hello))
> 
> An interesting fact: inserting a `(declare-function hello nil)` after a
> `defun` suppresses the warning. So I guess `defun` should work somehow
> similarly to `declare-function`.

Perhaps Stefan (CC'ed) will have some comments or advice.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#69120; Package emacs. (Thu, 15 Feb 2024 15:22:02 GMT) Full text and rfc822 format available.

Message #35 received at 69120 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 69120 <at> debbugs.gnu.org, Konstantin Kharlamov <Hi-Angel <at> yandex.ru>
Subject: Re: bug#69120: Spurious "function is not known to be defined" if
 defined in `use-package` body
Date: Thu, 15 Feb 2024 10:21:03 -0500
>> >    ;;; -*- lexical-binding: t -*-
>> >    (defun foo ()
>> >      (defun hello()
>> >        (print "hello"))
>> >      (hello))
>> 
>> An interesting fact: inserting a `(declare-function hello nil)` after a
>> `defun` suppresses the warning. So I guess `defun` should work somehow
>> similarly to `declare-function`.
>
> Perhaps Stefan (CC'ed) will have some comments or advice.

Both `defun` and `declare-function` work in unsatisfactory ways in this
respect.

Any `declare-function` anywhere in the file will silence all warnings
about this function in the whole file, which is too lax.

`defun` in contrast only silences the warnings if it's at the top-level,
which is too restrictive.

We should make them both work a bit more like `defvar`.


        Stefan





This bug report was last modified 1 year and 125 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.