Unportable ways to add non-trivial type constraints.
Vasily Postnicov <[email protected]> Mon, 3 Feb 2025 12:37:39 +0000
| Newsgroups | gmane.lisp.steel-bank.general |
|---|---|
| Message-ID | <CADnZ6B=qEAAX6TreYDNUhQ=aATo-pP_UAsREMPTBNUNtVToSJg@mail.gmail.com> |
Hi! Suppose I want to write a specialized eql comparison function which has
a type a -> a -> BOOLEAN (i.e. types of its arguments must be equal).
There is no portable way to specify such a type in Common Lisp. But, in
src/compiler/fun-info.lisp I found this:
;; If true, the function can add flow-sensitive type information
;; about the state of the world after its execution. The COMBINATION
;; node is passed as an argument, along with the current set of
;; active constraints for the block. The function returns a
;; sequence of constraints; a constraint is a triplet of a
;; constraint kind (a symbol, see (defstruct (constraint ...)) in
;; constraint.lisp) and arguments, either LVARs, LAMBDA-VARs, or
;; CTYPEs. If any of these arguments is NIL, the constraint is
;; skipped. This simplifies integration with OK-LVAR-LAMBDA-VAR,
;; which maps LVARs to LAMBDA-VARs. An optional fourth value in
;; each constraint flips the meaning of the constraint if it is
;; non-NIL.
(constraint-propagate nil :type (or function null))
So I thought this is what I need and tried the following:
(defpackage foo
(:use #:cl)
(:export #:foo #:bar #:baz))
(in-package :foo)
(sb-c:defknown (foo) (t t) boolean
(sb-c:movable sb-c:flushable sb-c:foldable))
(defun foo (x y)
(eql x y))
(sb-c:defoptimizer (foo sb-c::constraint-propagate) ((x y) node gen)
(let ((type-x (sb-c::lvar-type x))
(type-y (sb-c::lvar-type y))
(var-x (sb-c::ok-lvar-lambda-var x gen))
(var-y (sb-c::ok-lvar-lambda-var y gen)))
(when (and var-x var-y)
(print
(list
(list 'typep var-x type-y)
(list 'typep var-y type-x))))))
(declaim (ftype (function (integer string) (values boolean &optional)) bar))
(defun bar (x y)
(foo x y))
When compiling bar I have this printed:
((TYPEP
#<SB-C::LAMBDA-VAR
:%SOURCE-NAME X
:TYPE #<SB-KERNEL:NUMERIC-TYPE INTEGER>
:WHERE-FROM :DECLARED {1111651493}>
#<SB-KERNEL:UNION-TYPE STRING> T)
(TYPEP
#<SB-C::LAMBDA-VAR
:%SOURCE-NAME Y
:TYPE #<SB-KERNEL:UNION-TYPE STRING>
:WHERE-FROM :DECLARED {1111651553}>
#<SB-KERNEL:NUMERIC-TYPE INTEGER> T))
but no compile-time or run-time when I use bar:
CL-USER> (foo:baz 543 "dsd")
NIL
Can you please give me a hint how type information about arguments can be
added to a function? My goal is to learn how I can write a bit type-safer
code and non-portability does not bother me.
Also, if there are any publications about how SBCL handles types, please
tell me.
_______________________________________________
Sbcl-help mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sbcl-help