Re: Unportable ways to add non-trivial type constraints.
Stas Boukarev <[email protected]> Mon, 3 Feb 2025 15:43:44 +0300
| Newsgroups | gmane.lisp.steel-bank.general |
|---|---|
| Message-ID | <CAF63=12oeo84Wqeq7529S1CmtBd=T12OL9k-4crTHjofcggVxQ@mail.gmail.com> |
Constraint propagation is changing all the time, it's going to be not just non-portable but non-portable between different versions. And possibly in subtle ways where you can't catch it. So, don't do this. On Mon, Feb 3, 2025 at 3:40 PM Vasily Postnicov <[email protected]> wrote: > > 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 _______________________________________________ Sbcl-help mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sbcl-help