1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

cl-preloaded.el: Fix the type lattice

We generally want types to form not just a DAG but a lattice.
If objects can be both `keyword` and `symbol-with-pos`, this
means there should be a more precise type describing this intersection.
If we ever find the need for such a refinement, we could add
such a `keyword-with-pos` type, but here I took the simpler
route of treating `keyword` not as a proper built-in type but
as a second-class type like `natnum`.

While fixing this problem, also fix the problem we had where
`functionp` was not quite adequate to characterize objects of type
`function`, by introducing a new predicate `cl-functionp` for that.

* lisp/emacs-lisp/cl-preloaded.el (cl-functionp): New function.
(function): Use it.
(keyword): Don't declare it as a built-in type.
(user-ptrp): Remove redundant declaration.

* lisp/emacs-lisp/cl-generic.el (cl--generic--unreachable-types):
Delete constant.
(cl-generic-generalizers): Remove corresponding test.

* lisp/emacs-lisp/cl-macs.el (cl-deftype-satisfies): Add entry for
`keyword` type.

* lisp/emacs-lisp/comp.el (comp-known-predicates): Fix type for
negative result of `characterp`.  Remove duplicate `numberp` entry.
Fix types for `keywordp` now that `keyword` is not a built-in type any more.

* test/src/data-tests.el (data-tests--cl-type-of): Add a few cases.
Remove workaround for `function`.
This commit is contained in:
Stefan Monnier 2024-03-26 13:14:15 -04:00
parent 351d98535d
commit 004f2493a5
6 changed files with 37 additions and 36 deletions

View file

@ -1700,9 +1700,11 @@ This function is like 'type-of' except that it sometimes returns
a more precise type. For example, for nil and t it returns 'null' a more precise type. For example, for nil and t it returns 'null'
and 'boolean' respectively, instead of just 'symbol'. and 'boolean' respectively, instead of just 'symbol'.
** New function `primitive-function-p`. ** New functions `primitive-function-p` and `cl-functionp`.
This is like `subr-primitive-p` except that it returns t only if the `primitive-function-p` is like `subr-primitive-p` except that it returns
argument is a function rather than a special-form. t only if the argument is a function rather than a special-form,
and `cl-functionp` is like `functionp` except it return nil
for lists and symbols.
** Built-in types have now corresponding classes. ** Built-in types have now corresponding classes.
At the Lisp level, this means that things like (cl-find-class 'integer) At the Lisp level, this means that things like (cl-find-class 'integer)

View file

@ -1332,11 +1332,6 @@ These match if the argument is `eql' to VAL."
;;; Dispatch on "normal types". ;;; Dispatch on "normal types".
(defconst cl--generic--unreachable-types
;; FIXME: Try to make that list empty?
'(keyword)
"Built-in classes on which we cannot dispatch for technical reasons.")
(defun cl--generic-type-specializers (tag &rest _) (defun cl--generic-type-specializers (tag &rest _)
(and (symbolp tag) (and (symbolp tag)
(let ((class (cl--find-class tag))) (let ((class (cl--find-class tag)))
@ -1350,14 +1345,12 @@ These match if the argument is `eql' to VAL."
(cl-defmethod cl-generic-generalizers :extra "typeof" (type) (cl-defmethod cl-generic-generalizers :extra "typeof" (type)
"Support for dispatch on types. "Support for dispatch on types.
This currently works for built-in types and types built on top of records." This currently works for built-in types and types built on top of records."
;; FIXME: Add support for other types accepted by `cl-typep' such ;; FIXME: Add support for other "types" accepted by `cl-typep' such
;; as `character', `face', `function', ... ;; as `character', `face', `keyword', ...?
(or (or
(and (symbolp type) (and (symbolp type)
(not (eq type t)) ;; Handled by the `t-generalizer'. (not (eq type t)) ;; Handled by the `t-generalizer'.
(let ((class (cl--find-class type))) (let ((class (cl--find-class type)))
(when (memq type cl--generic--unreachable-types)
(error "Dispatch on %S is currently not supported" type))
(memq (type-of class) (memq (type-of class)
'(built-in-class cl-structure-class eieio--class))) '(built-in-class cl-structure-class eieio--class)))
(list cl--generic-typeof-generalizer)) (list cl--generic-typeof-generalizer))

View file

@ -3467,6 +3467,7 @@ Of course, we really can't know that for sure, so it's just a heuristic."
'((base-char . characterp) ;Could be subtype of `fixnum'. '((base-char . characterp) ;Could be subtype of `fixnum'.
(character . natnump) ;Could be subtype of `fixnum'. (character . natnump) ;Could be subtype of `fixnum'.
(command . commandp) ;Subtype of closure & subr. (command . commandp) ;Subtype of closure & subr.
(keyword . keywordp) ;Would need `keyword-with-pos`.
(natnum . natnump) ;Subtype of fixnum & bignum. (natnum . natnump) ;Subtype of fixnum & bignum.
(real . numberp) ;Not clear where it would fit. (real . numberp) ;Not clear where it would fit.
)) ))

View file

@ -349,6 +349,14 @@ The `slots' (and hence `index-table') are currently unused."
;; so the DAG of OClosure types is "orthogonal" to the distinction ;; so the DAG of OClosure types is "orthogonal" to the distinction
;; between interpreted and compiled functions. ;; between interpreted and compiled functions.
(defun cl-functionp (object)
"Return non-nil if OBJECT is a member of type `function'.
This is like `functionp' except that it returns nil for all lists and symbols,
regardless if `funcall' would accept to call them."
(memq (cl-type-of object)
'(primitive-function subr-native-elisp module-function
interpreted-function byte-code-function)))
(cl--define-built-in-type t nil "Abstract supertype of everything.") (cl--define-built-in-type t nil "Abstract supertype of everything.")
(cl--define-built-in-type atom t "Abstract supertype of anything but cons cells." (cl--define-built-in-type atom t "Abstract supertype of anything but cons cells."
:predicate atom) :predicate atom)
@ -356,11 +364,9 @@ The `slots' (and hence `index-table') are currently unused."
(cl--define-built-in-type tree-sitter-compiled-query atom) (cl--define-built-in-type tree-sitter-compiled-query atom)
(cl--define-built-in-type tree-sitter-node atom) (cl--define-built-in-type tree-sitter-node atom)
(cl--define-built-in-type tree-sitter-parser atom) (cl--define-built-in-type tree-sitter-parser atom)
(declare-function user-ptrp "data.c")
(when (fboundp 'user-ptrp) (when (fboundp 'user-ptrp)
(cl--define-built-in-type user-ptr atom nil (cl--define-built-in-type user-ptr atom nil
;; FIXME: Shouldn't it be called ;; FIXME: Shouldn't it be called `user-ptr-p'?
;; `user-ptr-p'?
:predicate user-ptrp)) :predicate user-ptrp))
(cl--define-built-in-type font-object atom) (cl--define-built-in-type font-object atom)
(cl--define-built-in-type font-entity atom) (cl--define-built-in-type font-entity atom)
@ -410,8 +416,6 @@ The `slots' (and hence `index-table') are currently unused."
The size depends on the Emacs version and compilation options. The size depends on the Emacs version and compilation options.
For this build of Emacs it's %dbit." For this build of Emacs it's %dbit."
(1+ (logb (1+ most-positive-fixnum))))) (1+ (logb (1+ most-positive-fixnum)))))
(cl--define-built-in-type keyword (symbol)
"Type of those symbols whose first char is `:'.")
(cl--define-built-in-type boolean (symbol) (cl--define-built-in-type boolean (symbol)
"Type of the canonical boolean values, i.e. either nil or t.") "Type of the canonical boolean values, i.e. either nil or t.")
(cl--define-built-in-type symbol-with-pos (symbol) (cl--define-built-in-type symbol-with-pos (symbol)
@ -431,7 +435,8 @@ For this build of Emacs it's %dbit."
;; Example of slots we could document. ;; Example of slots we could document.
(car car) (cdr cdr)) (car car) (cdr cdr))
(cl--define-built-in-type function (atom) (cl--define-built-in-type function (atom)
"Abstract supertype of function values.") "Abstract supertype of function values."
:predicate cl-functionp)
(cl--define-built-in-type compiled-function (function) (cl--define-built-in-type compiled-function (function)
"Abstract type of functions that have been compiled.") "Abstract type of functions that have been compiled.")
(cl--define-built-in-type byte-code-function (compiled-function) (cl--define-built-in-type byte-code-function (compiled-function)

View file

@ -193,13 +193,14 @@ Useful to hook into pass checkers.")
;; cl-macs.el. We can't use `cl-deftype-satisfies' directly as the ;; cl-macs.el. We can't use `cl-deftype-satisfies' directly as the
;; relation type <-> predicate is not bijective (bug#45576). ;; relation type <-> predicate is not bijective (bug#45576).
(defconst comp-known-predicates (defconst comp-known-predicates
;; FIXME: Auto-generate (most of) it from `cl-deftype-satifies'?
'((arrayp array) '((arrayp array)
(atom atom) (atom atom)
(bool-vector-p bool-vector) (bool-vector-p bool-vector)
(booleanp boolean) (booleanp boolean)
(bufferp buffer) (bufferp buffer)
(char-table-p char-table) (char-table-p char-table)
(characterp fixnum) (characterp fixnum t)
(consp cons) (consp cons)
(floatp float) (floatp float)
(framep frame) (framep frame)
@ -207,14 +208,13 @@ Useful to hook into pass checkers.")
(hash-table-p hash-table) (hash-table-p hash-table)
(integer-or-marker-p integer-or-marker) (integer-or-marker-p integer-or-marker)
(integerp integer) (integerp integer)
(keywordp keyword) (keywordp symbol t)
(listp list) (listp list)
(markerp marker) (markerp marker)
(natnump (integer 0 *)) (natnump (integer 0 *))
(null null) (null null)
(number-or-marker-p number-or-marker) (number-or-marker-p number-or-marker)
(numberp number) (numberp number)
(numberp number)
(obarrayp obarray) (obarrayp obarray)
(overlayp overlay) (overlayp overlay)
(processp process) (processp process)

View file

@ -845,10 +845,12 @@ comparing the subr with a much slower Lisp implementation."
;; Note: This doesn't work for list/vector structs since those types ;; Note: This doesn't work for list/vector structs since those types
;; are too difficult/unreliable to detect (so `cl-type-of' only says ;; are too difficult/unreliable to detect (so `cl-type-of' only says
;; it's a `cons' or a `vector'). ;; it's a `cons' or a `vector').
(dolist (val (list -2 10 (expt 2 128) nil t 'car (dolist (val (list -2 10 (expt 2 128) nil t 'car :car
(symbol-function 'car) (symbol-function 'car)
(symbol-function 'progn) (symbol-function 'progn)
(position-symbol 'car 7))) (eval '(lambda (x) (+ x 1)) t)
(position-symbol 'car 7)
(position-symbol :car 7)))
(let* ((type (cl-type-of val)) (let* ((type (cl-type-of val))
(class (cl-find-class type)) (class (cl-find-class type))
(alltypes (cl--class-allparents class)) (alltypes (cl--class-allparents class))
@ -858,19 +860,17 @@ comparing the subr with a much slower Lisp implementation."
(dolist (parent alltypes) (dolist (parent alltypes)
(should (cl-typep val parent)) (should (cl-typep val parent))
(dolist (subtype (cl--class-children (cl-find-class parent))) (dolist (subtype (cl--class-children (cl-find-class parent)))
(unless (memq subtype alltypes) (when (and (not (memq subtype alltypes))
(unless (memq subtype (built-in-class-p (cl-find-class subtype))
;; FIXME: Some types don't have any associated (not (memq subtype
;; predicate, ;; FIXME: Some types don't have any associated
'( font-spec font-entity font-object ;; predicate,
finalizer condvar terminal '( font-spec font-entity font-object
native-comp-unit interpreted-function finalizer condvar terminal
tree-sitter-compiled-query native-comp-unit interpreted-function
tree-sitter-node tree-sitter-parser tree-sitter-compiled-query
;; `functionp' also matches things of type tree-sitter-node tree-sitter-parser))))
;; `symbol' and `cons'. (should-not (cl-typep val subtype))))))))
function))
(should-not (cl-typep val subtype)))))))))
;;; data-tests.el ends here ;;; data-tests.el ends here