unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#28557: 26.0.60; Bugs using (:documentation FORM) in closures
@ 2017-09-22 17:30 Gemini Lasswell
  2020-05-03  1:32 ` Stefan Kangas
  2021-12-21  3:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 8+ messages in thread
From: Gemini Lasswell @ 2017-09-22 17:30 UTC (permalink / raw)
  To: 28557; +Cc: Stefan Monnier

[-- Attachment #1: Type: text/plain, Size: 466 bytes --]

Since Emacs 25, docstrings can be constructed using
(:documentation FORM) in closures, when lexical-binding is on. This
isn't documented except in NEWS. Bug #24773 is about Edebug specs
which have not been updated to recognize :documentation. I'd like to
fix it, so I started trying to figure out which macros accept
:documentation forms so I would know which Edebug specs to update, and
that effort turned into a collection of tests for the feature, see
attached:


[-- Attachment #2: cconv-tests.el --]
[-- Type: text/plain, Size: 7872 bytes --]

;;; cconv-tests.el --- Tests for cconv.el functionality  -*- lexical-binding: t; -*-

;; Copyright (C) 2017 Free Software Foundation, Inc.

;; Author: Gemini Lasswell

;; This file is part of GNU Emacs.

;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;;; Code:

(require 'ert)
(require 'cl-lib)

(ert-deftest cconv-tests-lambda-:documentation ()
  "Docstring for lambda can be specified with :documentation."
  (let ((fun (lambda ()
               (:documentation (concat "lambda" " documentation"))
               'lambda-result)))
    (should (string= (documentation fun) "lambda documentation"))
    (should (eq (funcall fun) 'lambda-result))))

(ert-deftest cconv-tests-pcase-lambda-:documentation ()
  "Docstring for pcase-lambda can be specified with :documentation."
  (let ((fun (pcase-lambda (`(,a ,b))
               (:documentation (concat "pcase-lambda" " documentation"))
               (list b a))))
    (should (string= (documentation fun) "pcase-lambda documentation"))
    (should (equal '(2 1) (funcall fun '(1 2))))))

(defun cconv-tests-defun ()
  (:documentation (concat "defun" " documentation"))
  'defun-result)
(ert-deftest cconv-tests-defun-:documentation ()
  "Docstring for defun can be specified with :documentation."
  (should (string= (documentation 'cconv-tests-defun)
                   "defun documentation"))
  (should (eq (cconv-tests-defun) 'defun-result)))

(cl-defun cconv-tests-cl-defun ()
  (:documentation (concat "cl-defun" " documentation"))
  'cl-defun-result)
(ert-deftest cconv-tests-cl-defun-:documentation ()
  "Docstring for cl-defun can be specified with :documentation."
  (should (string= (documentation 'cconv-tests-cl-defun)
                   "cl-defun documentation"))
  (should (eq (cconv-tests-cl-defun) 'cl-defun-result)))

(defmacro cconv-tests-defmacro ()
  (:documentation (concat "defmacro" " documentation"))
  '(quote defmacro-result))
(ert-deftest cconv-tests-defmacro-:documentation ()
  "Docstring for defmacro can be specified with :documentation."
  (should (string= (documentation 'cconv-tests-defmacro)
                   "defmacro documentation"))
  (should (eq (cconv-tests-defmacro) 'defmacro-result)))

(cl-defmacro cconv-tests-cl-defmacro ()
  (:documentation (concat "cl-defmacro" " documentation"))
  '(quote cl-defmacro-result))
(ert-deftest cconv-tests-cl-defmacro-:documentation ()
  "Docstring for cl-defmacro can be specified with :documentation."
  (should (string= (documentation 'cconv-tests-cl-defmacro)
                   "cl-defmacro documentation"))
  (should (eq (cconv-tests-cl-defmacro) 'cl-defmacro-result)))

(cl-iter-defun cconv-tests-cl-iter-defun ()
  (:documentation (concat "cl-iter-defun" " documentation"))
  (iter-yield 'cl-iter-defun-result))
(ert-deftest cconv-tests-cl-iter-defun-:documentation ()
  "Docstring for cl-iter-defun can be specified with :documentation."
  (should (string= (documentation 'cconv-tests-cl-iter-defun)
                   "cl-iter-defun documentation"))
  (should (eq (iter-next (cconv-tests-cl-iter-defun))
              'cl-iter-defun-result)))

(iter-defun cconv-tests-iter-defun ()
  (:documentation (concat "iter-defun" " documentation"))
  (iter-yield 'iter-defun-result))
(ert-deftest cconv-tests-iter-defun-:documentation ()
  "Docstring for iter-defun can be specified with :documentation."
  (should (string= (documentation 'cconv-tests-iter-defun)
                   "iter-defun documentation"))
  (should (eq (iter-next (cconv-tests-iter-defun)) 'iter-defun-result)))

(ert-deftest cconv-tests-iter-lambda-:documentation ()
  "Docstring for iter-lambda can be specified with :documentation."
  (let ((iter-fun
         (iter-lambda ()
           (:documentation (concat "iter-lambda" " documentation"))
           (iter-yield 'iter-lambda-result))))
    (should (string= (documentation iter-fun) "iter-lambda documentation"))
    (should (eq (iter-next (funcall iter-fun)) 'iter-lambda-result))))

(ert-deftest cconv-tests-cl-function-:documentation ()
  "Docstring for cl-function can be specified with :documentation."
  (let ((fun (cl-function (lambda (&key arg)
                            (:documentation (concat "cl-function"
                                                    " documentation"))
                            (list arg 'cl-function-result)))))
    (should (string= (documentation fun) "cl-function documentation"))
    (should (equal (funcall fun :arg t) '(t cl-function-result)))))

(ert-deftest cconv-tests-function-:documentation ()
  "Docstring for lambda inside function can be specified with :documentation."
  (let ((fun #'(lambda (arg)
                 (:documentation (concat "function" " documentation"))
                 (list arg 'function-result))))
    (should (string= (documentation fun) "function documentation"))
    (should (equal (funcall fun t) '(t function-result)))))

(fmakunbound 'cconv-tests-cl-defgeneric)
(setplist 'cconv-tests-cl-defgeneric nil)
(cl-defgeneric cconv-tests-cl-defgeneric (n)
  (:documentation (concat "cl-defgeneric" " documentation")))
(cl-defmethod cconv-tests-cl-defgeneric ((n integer))
  (:documentation (concat "cl-defmethod" " documentation"))
  (+ 1 n))
(ert-deftest cconv-tests-cl-defgeneric-:documentation ()
  "Docstring for cl-defgeneric can be specified with :documentation."
  (let ((descr (describe-function 'cconv-tests-cl-defgeneric)))
    (set-text-properties 0 (length descr) nil descr)
    (should (string-match-p "cl-defgeneric documentation" descr))
    (should (string-match-p "cl-defmethod documentation" descr)))
  (should (= 11 (cconv-tests-cl-defgeneric 10))))

(fmakunbound 'cconv-tests-cl-defgeneric-literal)
(setplist 'cconv-tests-cl-defgeneric-literal nil)
(cl-defgeneric cconv-tests-cl-defgeneric-literal (n)
  (:documentation "cl-defgeneric-literal documentation"))
(cl-defmethod cconv-tests-cl-defgeneric-literal ((n integer))
  (:documentation "cl-defmethod-literal documentation")
  (+ 1 n))
(ert-deftest cconv-tests-cl-defgeneric-literal-:documentation ()
  "Docstring for cl-defgeneric can be specified with :documentation."
  (let ((descr (describe-function 'cconv-tests-cl-defgeneric-literal)))
    (set-text-properties 0 (length descr) nil descr)
    (should (string-match-p "cl-defgeneric-literal documentation" descr))
    (should (string-match-p "cl-defmethod-literal documentation" descr)))
  (should (= 11 (cconv-tests-cl-defgeneric-literal 10))))

(defsubst cconv-tests-defsubst ()
  (:documentation (concat "defsubst" " documentation"))
  'defsubst-result)
(ert-deftest cconv-tests-defsubst-:documentation ()
  "Docstring for defsubst can be specified with :documentation."
  (should (string= (documentation 'cconv-tests-defsubst)
                   "defsubst documentation"))
  (should (eq (cconv-tests-defsubst) 'defsubst-result)))

(cl-defsubst cconv-tests-cl-defsubst ()
  (:documentation (concat "cl-defsubst" " documentation"))
  'cl-defsubst-result)
(ert-deftest cconv-tests-cl-defsubst-:documentation ()
  "Docstring for cl-defsubst can be specified with :documentation."
  (should (string= (documentation 'cconv-tests-cl-defsubst)
                   "cl-defsubst documentation"))
  (should (eq (cconv-tests-cl-defsubst) 'cl-defsubst-result)))

(provide 'cconv-tests)
;;; cconv-tests.el ends here

[-- Attachment #3: Type: text/plain, Size: 1069 bytes --]


While doing this I found these bugs:

1. A lambda wrapped by cl-function with a :documentation form will
not get a docstring and the :documentation form will be left in the
body of the closure.

2. In code run interactively, a :documentation form in cl-defmacro or
defmacro will work correctly. However if you byte-compile that code,
the byte-compiler stops with the following error message:
    Symbol’s function definition is void: internal-make-closure

3. A :documentation form in cl-defgeneric only works if its argument
is a string literal. In cl-defmethod, it works whether the argument is
a string literal or an expression.

4. A :documentation form works in cl-iter-defun and iter-defun, but
not in iter-lambda.

Stefan, here's a list of macros in which it appears to me that
(:documentation FORM) is supposed to work. Is this correct? Am I
missing any?

lambda
pcase-lambda
defun
defmacro
cl-defun
cl-defmacro
iter-defun
cl-iter-defun
iter-lambda
function
cl-function
cl-defgeneric
cl-defmethod
defsubst
cl-defsubst


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-12-21  3:05 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-09-22 17:30 bug#28557: 26.0.60; Bugs using (:documentation FORM) in closures Gemini Lasswell
2020-05-03  1:32 ` Stefan Kangas
2020-05-03 14:52   ` Eli Zaretskii
2020-05-03 19:22     ` Stefan Kangas
2020-05-04 13:47       ` Eli Zaretskii
2020-08-04 17:06         ` Stefan Kangas
2020-08-13  1:07           ` Gemini Lasswell
2021-12-21  3:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).