Fix (setf (map-elt map key) (my-func))

* lisp/emacs-lisp/map.el (map-elt): Ensure that the value isn't
referenced more than once (bug#50290).
This commit is contained in:
Lars Ingebrigtsen 2021-09-01 10:32:49 +02:00
parent 4a1505904e
commit fffcc7ab25
2 changed files with 19 additions and 8 deletions

View file

@ -119,14 +119,16 @@ or array."
((key key) (default default) (testfn testfn))
(funcall do `(map-elt ,mgetter ,key ,default)
(lambda (v)
`(condition-case nil
;; Silence warnings about the hidden 4th arg.
(with-no-warnings (map-put! ,mgetter ,key ,v ,testfn))
(map-not-inplace
,(funcall msetter
`(map-insert ,mgetter ,key ,v))
;; Always return the value.
,v))))))))
(macroexp-let2 nil v v
`(condition-case nil
;; Silence warnings about the hidden 4th arg.
(with-no-warnings
(map-put! ,mgetter ,key ,v ,testfn))
(map-not-inplace
,(funcall msetter
`(map-insert ,mgetter ,key ,v))
;; Always return the value.
,v)))))))))
;; `testfn' is deprecated.
(advertised-calling-convention (map key &optional default) "27.1"))
;; Can't use `cl-defmethod' with `advertised-calling-convention'.

View file

@ -521,5 +521,14 @@ Evaluate BODY for each created map."
'value2))
(should (equal (map-elt ht 'key) 'value2))))
(ert-deftest test-setf-map-with-function ()
(let ((num 0)
(map nil))
(setf (map-elt map 'foo)
(funcall (lambda ()
(cl-incf num))))
;; Check that the function is only called once.
(should (= num 1))))
(provide 'map-tests)
;;; map-tests.el ends here