sbcl.sbcl/tests/compiler-2.pure.lisp
2026-09-01 18:01:23 +03:00

5266 lines
157 KiB
Common Lisp

;;;; various compiler tests without side effects
;;;; This software is part of the SBCL system. See the README file for
;;;; more information.
;;;;
;;;; While most of SBCL is derived from the CMU CL system, the test
;;;; files (like this one) were written from scratch after the fork
;;;; from CMU CL.
;;;;
;;;; This software is in the public domain and is provided with
;;;; absolutely no warranty. See the COPYING and CREDITS files for
;;;; more information.
;;;; This file of tests was added because the tests in 'compiler.pure.lisp'
;;;; are a total hodgepodge- there is often no hugely compelling reason for
;;;; their being tests of the compiler per se, such as whether
;;;; INPUT-ERROR-IN-COMPILED-FILE is a subclass of SERIOUS-CONDITION;
;;;; in addition to which it is near impossible to wade through the
;;;; ton of nameless, slow, and noisy tests.
;;;; This file strives to do better on all fronts:
;;;; the tests should be fast, named, and not noisy.
(enable-test-parallelism)
(defun compiles-with-warning (lambda)
(assert (nth-value 2 (checked-compile lambda :allow-warnings t))))
(with-test (:name :duplicate-labels)
(dolist (operator '(labels flet macrolet))
(multiple-value-bind (fun warn err)
(let ((*error-output* (make-broadcast-stream)))
(compile nil `(lambda (x)
(declare (ignorable x))
(,operator ((f (z) z 2)
(f (z) z 3))
(f x)))))
;; I'm not asserting on the result of calling FUN
;; because I don't really care what it is.
(declare (ignore fun))
(assert (and warn err)))))
(with-test (:name (position :derive-type))
(checked-compile '(lambda (x)
(ash 1 (position (the (member a b c) x) #(a b c )))))
(checked-compile '(lambda (x)
(ash 1 (position x #(a b c ))))
:allow-style-warnings t)
;; The sequence must contain a mixture of symbols and non-symbols
;; to call %FIND-POSITION. If only symbols, it makes no calls.
(let ((calls (ctu:ir1-funargs '(lambda (x)
(position x '(1 2 3 a b c 4 5 6 d e f g "x") :from-end t)))))
;; Assert that the default :TEST of #'EQL was strength-reduced to #'EQ
(assert (equal calls '((sb-kernel:%find-position identity eq)))))
(checked-compile-and-assert ()
'(lambda (x)
(position x '(a b c d e d c b a) :from-end t))
(('a) 8)
(('b) 7)))
(with-test (:name (ldb :recognize-local-macros))
;; Should not call %LDB
(assert (equal
(ctu:ir1-named-calls
'(lambda (x)
(declare (optimize speed))
(macrolet ((b () '(byte 2 2)))
(ldb (b) (the fixnum x)))))
'(sb-c::check-ds-list)))) ; why does this remain in the IR?
(with-test (:name (dpb :eval-order :lp-1458190))
(sb-int:collect ((calls))
(flet ((f (new old)
(dpb (progn (calls 'eval-new) new)
(progn (calls 'eval-byte) (byte 10 10))
(progn (calls 'eval-old) old))))
(f 20 0)
(assert (equal (calls)
'(eval-new eval-byte eval-old))))))
;; Best practice treats TRULY-THE as a special operator, not a macro,
;; in a context such as (DPB X (TRULY-THE SB-KERNEL:BYTE-SPECIFIER ...) Y).
;; DPB used to expand its second argument using MACROEXPAND and lose
;; the nuance of TRULY-THE. Strictly speaking, byte-specifier is not a
;; type specifier that users are supposed to know about, so portable code
;; should not care, but this might affect internal code.
(with-test (:name (dpb :inner-macro))
(flet ((source-xform (sexpr)
(funcall (sb-int:info :function :source-transform (car sexpr))
sexpr (sb-kernel:make-null-lexenv))))
(assert (equal-mod-gensyms
(source-xform
'(dpb (new) (truly-the sb-kernel:byte-specifier bspec) (old)))
'(let ((new (new))
(byte (truly-the sb-kernel:byte-specifier bspec)))
(sb-kernel:%dpb new (byte-size byte) (byte-position byte)
(old)))))))
(with-test (:name :inline-satisfies-predicate)
;; If we remove the indirections in these functions,
;; this test should visibly break so that we can write a new test
;; that asserts that inlining F works in (THE (SATISFIES F) obj).
(assert (equal (sb-ext:typexpand 'sb-impl::function-name)
'(satisfies sb-int:legal-fun-name-p)))
(let ((f `(lambda (x) (the sb-impl::function-name x))))
(assert (equal (ctu:ir1-named-calls f) '(sb-int:valid-function-name-p))))
(let ((f `(lambda (x)
(declare (notinline sb-int:legal-fun-name-p))
(the sb-impl::function-name x))))
(assert (equal (ctu:ir1-named-calls f) '(sb-int:legal-fun-name-p)))))
(with-test (:name (make-array :untestable-type :no-warning))
(checked-compile `(lambda () (make-array '(2 2)
:element-type `(satisfies foofa)))))
(with-test (:name (make-array nil :no-warning))
(checked-compile '(lambda () (make-array '(2 2) :element-type nil))))
(with-test (:name (nth-value :huge-n :works))
(flet ((return-a-ton-of-values ()
(values-list (loop for i below (min 5000 (1- multiple-values-limit)) collect i))))
(assert (= (nth-value 1 (return-a-ton-of-values)) 1))
(let ((n (min 4000 (- multiple-values-limit 2))))
(assert (= (nth-value n (return-a-ton-of-values)) n)))))
(with-test (:name :internal-name-p :skipped-on :sb-xref-for-internals)
(assert (sb-c::internal-name-p 'sb-int:neq)))
(with-test (:name (:coerce-callable-to-fun :note))
(flet ((try (form what)
(multiple-value-bind (fun failure-p warnings style-warnings notes)
(checked-compile `(lambda (x)
(declare (optimize speed))
(funcall ,form)))
(declare (ignore fun failure-p warnings style-warnings))
(assert (search (format nil "~A is not known to be" what)
(princ-to-string (first notes)))))))
(try '(eval `(work-with ,x)) "callable expression")
(try 'x "X")
;; For this I'd accept either Z or X in the message.
(try '(progn (let ((z x)) (identity z))) "X")))
(with-test (:name (princ-to-string :unflushable))
;; Ordinary we'll flush it
(assert (not (ctu:ir1-named-calls '(lambda (x) (princ-to-string x) x))))
;; But in high safety it should be called for effect
(let ((f `(lambda (x)
(declare (optimize safety)) (princ-to-string x) x)))
(assert (equal (ctu:ir1-named-calls f) '(princ-to-string)))))
(with-test (:name :space-bounds-no-consing
:serial t
:skipped-on :interpreter)
;; Asking for the size of a heap space should not cost anything!
(ctu:assert-no-consing (sb-vm:%space-bounds :static))
(ctu:assert-no-consing (sb-vm:space-bytes :static)))
(with-test (:name (sb-vm:map-allocated-objects :no-consing)
:serial t
:fails-on (or :cheneygc (not :sb-thread))
:skipped-on :interpreter)
(let ((n 0))
(sb-int:dx-flet ((f (obj type size)
(declare (ignore obj type size))
(incf n)))
(ctu:assert-no-consing
(sb-vm:map-allocated-objects #'f :dynamic)
5))))
(with-test (:name :pack-varints-as-bignum
:skipped-on :interpreter) ; too slow
(dotimes (i 500) ; do some random testing this many times
(let* ((random-numbers (loop repeat (+ (random 20) 3)
collect (1+ (random 4000))))
(test-list (sort (delete-duplicates random-numbers) #'<))
(packed-int (sb-c:pack-code-fixup-locs test-list nil nil))
(result (make-array 1 :element-type '(unsigned-byte 32))))
(sb-sys:with-pinned-objects (packed-int result)
;; Now exercise the C unpacker.
;; This hack of allocating 4 longs is terrible, but whatever.
(let ((unpacker (make-alien word 4))
(prev-loc 0))
(alien-funcall (extern-alien "varint_unpacker_init"
(function void (* word) word))
unpacker
(sb-kernel:get-lisp-obj-address packed-int))
(sb-int:collect ((unpacked))
(loop
(let ((status
(alien-funcall
(extern-alien "varint_unpack"
(function int (* word) system-area-pointer))
unpacker (sb-sys:vector-sap result))))
(let ((val (aref result 0)))
;; status of 0 is EOF, val = 0 means a decoded value was 0,
;; which can't happen, so it's effectively EOF.
(when (or (eql status 0) (eql val 0)) (return))
(let ((loc (+ prev-loc val)))
(unpacked loc)
(setq prev-loc loc)))))
(assert (equal (unpacked) test-list))))))))
(with-test (:name (symbol-value symbol-global-value :quoted-constant))
(let ((f (checked-compile '(lambda () (symbol-value 'char-code-limit)))))
(assert (not (ctu:find-code-constants f :type 'symbol))))
(let ((f (checked-compile '(lambda () (symbol-global-value 'char-code-limit)))))
(assert (not (ctu:find-code-constants f :type 'symbol)))))
(with-test (:name (:set symbol-value :of defglobal))
(let ((s 'sb-c::*recognized-declarations*))
(assert (eq (sb-int:info :variable :kind s) :global)) ; verify precondition
(let ((f (checked-compile `(lambda () (setf (symbol-value ',s) nil)))))
;; Should not have a call to SET-SYMBOL-GLOBAL-VALUE>
(assert (not (ctu:find-code-constants f :type 'sb-kernel:fdefn))))))
(with-test (:name (:no style-warning :for inline :cl-fun))
(checked-compile '(lambda (x)
(declare (optimize (speed 3)) (inline length)
(muffle-conditions compiler-note))
(length x))))
(with-test (:name :deleted-return-use)
(checked-compile-and-assert ()
`(lambda ()
(block nil
(return 345)
(let ((a (catch 'x)))
(flet ((%f (a &optional b)
a))
(%f 0 (%f 123))))))
(() 345)))
(with-test (:name :shift-right-transform-nil-type)
(checked-compile-and-assert (:optimize nil)
`(lambda (b c)
(declare (type (integer -10 -6) c)
(optimize (debug 2)))
(catch 'c
(flet ((f1 (a &optional (b (shiftf b 0)) c d)
(declare (ignore a b c d))
(throw 'c 780)))
(flet ((f2 (a b)
(f1 a b 0)))
(ash
(f1 (if t
c
(f1 (f2 1 0) 0))
b)
(+ c))))))
((-3 -7) 780)))
(with-test (:name :move-lvar-result-through-unused-cast)
(checked-compile-and-assert (:optimize nil)
`(lambda ()
(declare (optimize (debug 0)))
(labels ((f (a b)
a b)
(x ()
(apply #'f (list 2 3))))
(declare (notinline f))
(the integer (x)))
132)
(() 132)))
(with-test (:name (:type-conflict funcall :external-lambda))
(compiles-with-warning `(lambda ()
(let ((x (lambda (x) (declare (fixnum x)) x)))
(funcall x 'a)))))
(with-test (:name (:type-conflict :callable :external-lambda))
(compiles-with-warning `(lambda ()
(let ((x (lambda (x) (declare (fixnum x)) x)))
(find-if x "abca")))))
(with-test (:name (:type-conflict map :result-type))
(compiles-with-warning `(lambda (str)
(map 'string (lambda (x) (declare (ignore x)) nil)
str))))
(with-test (:name (:type-conflict :by-name))
(compiles-with-warning `(lambda (str)
(map 'string 'evenp str))))
(with-test (:name (:type-conflict :callable :reporting))
(multiple-value-bind (fun failure-p warnings)
(checked-compile '(lambda (x) (map-into (make-string 10) #'evenp x))
:allow-warnings 'warning)
(declare (ignore fun))
(assert failure-p)
(assert (= (length warnings) 1))
(search "Derived type of EVENP is"
(princ-to-string (first warnings)))))
(with-test (:name (:type-conflict string :union-type))
(compiles-with-warning `(lambda (x)
(find-if #'evenp (the string x)))))
(with-test (:name (:type-conflict map-into :let))
(compiles-with-warning `(lambda (z)
(let ((x "abc"))
(map-into z #'evenp x)))))
(with-test (:name (:type-conflict map-into :result))
(compiles-with-warning `(lambda (z)
(map-into (make-string 10) #'evenp z))))
(with-test (:name (:type-conflict complement))
(compiles-with-warning
`(lambda (z)
(find z "l" :test (complement #'=)))))
(with-test (:name :type-across-hairy-lambda-transforms)
(assert (subtypep (sb-kernel:%simple-fun-type
(checked-compile `(lambda (x) (find 1 (the vector x)))))
'(function * (values (or (integer 1 1) null) &optional)))))
(with-test (:name :lea-type-derivation)
(checked-compile-and-assert ()
`(lambda (b)
(declare ((integer -3755795408964870057 -3391381516052960895)
b))
(ldb (byte 22 10) (* b 9)))
((-3391381516052980893) 2826685)))
(with-test (:name (:unused &optional :and &key))
(checked-compile-and-assert (:allow-style-warnings t)
`(lambda (&optional x &key)
(declare (ignore x))
10)
(() 10)))
(with-test (:name (:unknown values :coercion))
(checked-compile-and-assert ()
`(lambda (a)
(declare (notinline values typep))
(the integer (values a 2305843009213693946 a -207)))
((123) (values 123 2305843009213693946 123 -207))))
(with-test (:name :deleted-block-during-generate-type-checks)
(checked-compile-and-assert (:allow-warnings t)
`(lambda (a b)
(declare (notinline min ash conjugate oddp >=))
(if (and (or t (>= a)) (oddp 0))
(prog2 0
0
(labels ((f (a b c &key)
(declare (ignore a b c))
6965670824543402))
(f a 0 b)))
(conjugate
(dotimes (i 0 0)
(catch 'c
(ash
(the integer
(ignore-errors
(ignore-errors (throw 'c 1))))
(min a)))))))
((1 2) 0)))
(with-test (:name :block-delete-twice)
(checked-compile-and-assert ()
`(lambda ()
(declare (notinline >=))
(block nil
(lambda (x &key (key (if (>= 0 1)
(return (catch 'ct5 0)))))
(declare (ignore key))
x)))
(() 123 :test (lambda (values expected)
(equal (multiple-value-list
(funcall (first values) (first expected)))
expected)))))
(with-test (:name :dead-lvars-and-stack-analysis)
(checked-compile-and-assert ()
`(lambda (b)
(catch 'ct2
(block b5
(return-from b5
(multiple-value-prog1 19
(if (or b t)
(return-from b5 333)))))))
((11) 333)))
(with-test (:name :mv-call-more-values)
(checked-compile-and-assert ()
`(lambda (z)
(multiple-value-call (lambda (&optional x y &rest args)
(declare (ignore args))
(+ y x))
2 (truncate z 30)))
((2345) 80)))
(with-test (:name :unused-casts-at-ir2-convert)
(checked-compile-and-assert ()
`(lambda ()
(unwind-protect 123
(the integer
(labels ((%f (x &key)
(declare (ignore x))
(svref #(46 32) 0)))
(unwind-protect (%f (%f 0)))))))
(() 123)))
(with-test (:name :cmov-constants-different-primitive-type)
(checked-compile-and-assert ()
`(lambda (b)
(case b
((2030) 4611686018427387908)
((572) b)
(t 0)))
((572) 572)
((123) 0)
((2030) 4611686018427387908)))
(with-test (:name :mv-bind-skipping-vars-on-reoptimize)
(checked-compile-and-assert ()
`(lambda ()
(let (lv1)
(apply (lambda (&rest args)
(declare (ignore args)))
0
(list 3 lv1))
(setf lv1 10)))
(() 10)))
(with-test (:name :transform-on-a-nil-arg)
(checked-compile-and-assert ()
`(lambda ()
(block nil
(logtest
(multiple-value-prog1
(unwind-protect (return 32))
(catch 'tag (return 33)))
1)
34))
(() 32)))
(with-test (:name :nesteted-dx-deleted-uses)
(checked-compile-and-assert ()
`(lambda (a)
(block b2
(let* ((v1 (make-array nil :initial-element
(let ((a a))
(return-from b2 a)))))
(declare (dynamic-extent v1))
(aref v1))))
((342) 342)))
(with-test (:name :deleted-during-locall-analyze-fun-1)
(checked-compile-and-assert (:allow-warnings t)
`(lambda ()
(flet ((a ()))
(a 1)
(a 2)))
(() (condition 'program-error))))
(with-test (:name :delete-return-without-flush-dest)
(assert (eql
(catch 'c
(funcall (checked-compile
'(lambda ()
(labels ((%f () 40))
(multiple-value-prog1 *
(throw 'c (%f))
(%f)
30))))))
40)))
(with-test (:name :let-conversion-inside-deleted-lambda.1)
(checked-compile-and-assert ()
`(lambda ()
(block nil
(catch 'c)
(flet ((f (x &key)
(when x
(progv '(*) '(0)
(return)))))
(f (return 123))
(f 0))))
(() 123)))
(with-test (:name :let-conversion-inside-deleted-lambda.2)
(checked-compile-and-assert ()
`(lambda ()
(block nil
(block nil
(lambda () (return)))
(labels ((l () (l))
(%f (a &key)
(l)
(return a)))
(%f (return 321))
(%f 1))))
(() 321)))
(with-test (:name :assignment-conversion-inside-deleted-lambda)
(checked-compile-and-assert
(:allow-style-warnings t)
`(lambda (b)
(tagbody
(labels ((%f13 (&optional (f13-1 0) &key &allow-other-keys)
(declare (ignore f13-1))
b))
(if nil
(%f13 (go tag8))
(%f13)))
tag8))
((1) nil)))
(with-test (:name :nil-type-derived-before-assignment-conversion)
(checked-compile-and-assert ()
`(lambda (a)
(declare (ignore a))
(tagbody
(labels ((f (a)
(declare (ignore a))
(go tag1)))
(apply #'f 1 (list))
(apply #'f (catch 'ct (go tag1)) (list)))
tag1))
((1) nil)))
(with-test (:name :assignment-convert-untail-outside-calls)
(checked-compile-and-assert ()
`(lambda ()
(flet ((%f17 (&optional f17-1)
(declare (ignore f17-1))
(block block608
(block block606
(flet ((h0 ()
(return-from block606)))
(declare (dynamic-extent #'h0))
(return-from block608
(progn
(print #'h0 (make-broadcast-stream))
nil)))))))
(when nil (%f17))
(if t
(%f17)
(when nil
(%f17)))))
(() nil)))
(with-test (:name :assignment-convert-lambda-with-deleted-bind-block)
(checked-compile-and-assert ()
`(lambda ()
(flet ((%f5 ()
(flet ((%f2 (&optional (f2-2 (return-from %f5 1)))
0))
(let ((g624 1))
(cond ((eql g624 '1)
(%f2))
((eql g624 '2)
(%f2)))))))
0))
(() 0)))
(with-test (:name :unconvert-tail-calls)
(checked-compile-and-assert ()
`(lambda ()
(block nil
(labels ((f (&optional (a (return))
(b (if t (return)))
c
&rest args)
(declare (ignore a b c args))
(return 0)))
(let (x)
(equal 10 (f 0 3))
(f 123 0 0)
(f 0)
x))))
(() 0)))
(with-test (:name :deleting-exits-with-multiple-users)
(checked-compile-and-assert ()
`(lambda (a b)
(block nil
(multiple-value-prog1 b
(tagbody (return (multiple-value-prog1 3
(if a (go z)))) z))))
((nil :good) 3)
((t :good) :good)))
(with-test (:name :merge-tail-sets-deleted-functional)
(checked-compile-and-assert ()
`(lambda (a)
(block nil
(tagbody
(go g549)
g549
(return-from nil
(block b3
(let ((x (progn (lambda (&optional (x a)) x)
(unwind-protect 10)
(return-from b3 a))))
(unwind-protect x)))))))
((321) 321)))
(with-test (:name :float-remainders-rounding-errors)
(loop for fun in '(ceiling truncate floor
fceiling ftruncate ffloor
round fround)
do
(assert (member (second
(third (sb-kernel:%simple-fun-type
(checked-compile
`(lambda (x)
(nth-value 1 (,fun (the double-float x) 1/2)))))))
'(double-float real)))))
(with-test (:name :complex-float-contagion)
(checked-compile-and-assert ()
`(lambda (p1)
(declare (type (or double-float integer) p1))
(complex p1 2.0))
((1d0) #c(1d0 2d0))))
(with-test (:name :equal-transform-member-types)
(let* ((s1 "abc")
(s2 (copy-seq s1)))
(checked-compile-and-assert ()
`(lambda (p1 p2)
(declare (type (member ,s1) p1)
(type (member ,s2 #*10) p2))
(equal p1 p2))
((s1 s2) t))))
(with-test (:name :equalp-transform-numeric-types)
(checked-compile-and-assert ()
`(lambda (p1 p2)
(declare (type (or fixnum list) p1)
(type double-float p2))
(equalp p1 p2))
((1 1d0) t)))
(with-test (:name :equalp-transform-zero-array)
(checked-compile-and-assert ()
`(lambda (a b)
(declare (simple-string a)
(simple-bit-vector b))
(equalp a b))
(("" #*) t)))
(with-test (:name :equalp-transform-zero-string)
(checked-compile-and-assert
()
`(lambda (a)
(equalp "" a))
((#*) t)
((#()) t)))
(with-test (:name :fill-transform-returning-array-data)
(let ((vector (make-array 10 :fill-pointer 2)))
(checked-compile-and-assert ()
`(lambda (v)
(declare (type (vector t) v))
(fill v nil))
((vector) vector))))
(with-test (:name :missing-error-context)
(flet ((run ()
(let ((string
(with-output-to-string (*error-output*)
(compile nil '(sb-int:named-lambda bob () (otherfun) 3)))))
(assert (search "in: SB-INT:NAMED-LAMBDA BOB" string)))))
(run)
;; Unrepeatability is confusing:
;; The first compiler invocation used to leave *last-format-string*
;; with a toplevel value, so the second would not print enough context
;; because the format control and args were the same.
(run)))
(with-test (:name :cast-deletion-notes)
(checked-compile-and-assert
(:allow-notes nil)
`(lambda (m)
(setf m (list 1 2 3))
(the simple-vector
(coerce m 'vector)))
((nil) #(1 2 3) :test #'equalp)))
(with-test (:name :cast-deletion-notes.2)
(multiple-value-bind (fun fail warn style notes)
(checked-compile
`(lambda (m)
(setf m (list 1 2 3))
(the simple-vector
(if (vectorp m)
m
#(1)))))
(declare (ignore fail warn style))
(assert (equalp (funcall fun nil)
#(1)))
(assert (= (length notes) 1))
(assert (typep (car notes) 'code-deletion-note))))
(with-test (:name :array-call-type-deriver)
(checked-compile-and-assert
()
`(lambda (vector)
(funcall (the (function (t t)) #'aref)
vector
0))
(((vector 333)) 333)))
(with-test (:name :function-designator-cast-removal)
(let ((fun (checked-compile
`(lambda (vectors x)
(declare (list vectors x))
(map 'list #'svref vectors x)))))
(assert (notany (lambda (c)
(typecase c
(sb-kernel:fdefn
(eq (sb-c::fdefn-name c) 'svref))
(function
(eq c #'svref))))
(ctu:find-code-constants fun)))
(assert (equal (funcall fun '(#(44)) '(0)) '(44)))))
(with-test (:name :zombie-casts)
(checked-compile-and-assert
()
`(lambda ()
(flet ((f (a b)
(declare (ignore a))
b))
(multiple-value-call #'f
(values (the integer (unwind-protect (f 10 20)))
322))))
(() 322)))
(with-test (:name :zombie-casts.2)
(let ((sb-c::*max-optimize-iterations* 1))
(checked-compile-and-assert
()
`(lambda (a b)
(declare (type fixnum a b))
(elt '(167992664 119771479)
(max 0
(catch 'ct2
(if (typep b '(integer -52))
a
0)))))
((1 2) 119771479))))
(with-test (:name :find-dfo-on-deleted-lambda)
(assert (= (funcall
(funcall (checked-compile
`(lambda ()
(declare (notinline <))
(block nil
(lambda (&key (key
(unwind-protect
(if (< 0)
34
(return (catch 'c))))))
key))))))
34)))
(with-test (:name :ir1-ir2-dead-code-consistency)
(checked-compile-and-assert
()
`(lambda ()
(loop for x below 2
count (zerop (min x x x x x x x x x x))))
(() 1)))
(with-test (:name :ir1-ir2-dead-code-consistency)
(checked-compile-and-assert
()
`(lambda ()
(loop for x below 2
count (zerop (min x x x x x x x x x x))))
(() 1)))
(with-test (:name (setf svref :constant-modification))
(assert
(= (length (nth-value 2
(checked-compile
`(lambda (x)
(setf (svref #(a b c) 1) x))
:allow-warnings 'sb-int:constant-modified)))
1)))
(with-test (:name (debug :constant-modification))
(assert
(= (length (nth-value 2
(checked-compile
`(lambda (x)
(declare (optimize (debug 2)))
(let ((m "abc"))
(delete x m)))
:allow-warnings 'sb-int:constant-modified)))
1)))
(with-test (:name (debug :constant-modification.2))
(assert
(= (length (nth-value 2
(checked-compile
`(lambda (x)
(declare (optimize (debug 2)))
(let ((m (if x
"abc"
"fgh")))
(delete x m)))
:allow-warnings 'sb-int:constant-modified)))
1)))
(with-test (:name (debug :unused-tn-long-arglist))
(checked-compile-and-assert
()
`(lambda (n x)
(declare (sb-vm:word n))
(log (float n))
(nth-value 33 (funcall x . #.(loop for i to 35 collect i))))
((10 (lambda (&rest args) (values-list args))) 33)))
(with-test (:name (debug :unused-tn-very-long-arglist))
(checked-compile-and-assert
()
`(lambda (n x)
(declare (sb-vm:word n))
(log (float n))
(nth-value 33 (funcall x . #.(loop for i to (min 350 (- multiple-values-limit 2))
collect i))))
((10 (lambda (&rest args) (values-list args))) 33)))
(with-test (:name (dynamic-extent :recursive-local-functions))
(checked-compile
`(lambda ()
(let ((s (labels ((%f () (%f)))
(%f))))
(declare (dynamic-extent s))
(car s)))))
(with-test (:name (:ctypep :hairy-types))
(checked-compile
`(lambda ()
(the (cons (satisfies error)) '("a"))))
(assert
(nth-value 3
(checked-compile
`(lambda () (the (array abc) #()))
:allow-style-warnings t))))
(with-test (:name (catch :evaluate-tag-before-%catch))
(checked-compile-and-assert
(:allow-style-warnings t)
`(lambda (z)
(catch (multiple-value-call #'+
(if z 1 (values 1 2)))
:done))
((t) :done)
((nil) :done)))
(with-test (:name :nested-catch-progv-compile)
(checked-compile
`(lambda (a b)
(catch 'ct
(flet ((f (x &key) x (throw 'ct b)))
(dotimes (i 1)
(if (< (progv '() (f a) 1) a)
a
(catch 'ct (f a)))))))))
(with-test (:name (tagbody :tag-dynamic-extent))
(checked-compile-and-assert
(:optimize '(:safety 3 :debug 2))
`(lambda (b)
(declare (optimize (safety 3) (debug 2)))
(tagbody
(labels ((f (x &key) x (go tag6)))
(tagbody
(catch 'ct2 (f b))
2)
(dotimes (i 1) (f 1))
-1)
tag6))
((1) nil)))
(with-test (:name :fewer-cast-conversions)
(multiple-value-bind (fun failed)
(checked-compile
`(lambda ()
(let* ((v (cons 0 (catch 'ct (the integer nil)))))
(declare (dynamic-extent v))
(flet ((%f (x) x))
(%f (cdr v)))))
:allow-warnings t)
(assert failed)
(handler-bind ((error (lambda (c) c (throw 'ct 33))))
(assert (= (funcall fun) 33)))))
(with-test (:name :constant-folding-with-callable-args)
(checked-compile '(lambda () (count #'%f '(a)))
:allow-style-warnings t))
(with-test (:name :flushable-with-callable-args)
(assert (not (ctu:ir1-named-calls
'(lambda (y) (let ((x (count y '(1 2 3))))
(declare (ignore x))))))))
(with-test (:name (remove :count))
(checked-compile-and-assert
()
`(lambda (x)
(remove x "aaa" :count 2))
((#\a) "a"))
(checked-compile-and-assert
()
`(lambda (x)
(remove-if (lambda (y) (eql y x)) "aaa" :count 2))
((#\a) "a")))
(with-test (:name (:constant-fold :allow-other-keys))
(checked-compile-and-assert
()
`(lambda (x)
(reduce #'+ '(1 2 3) :allow-other-keys t :bad x))
((1) 6)))
(with-test (:name (:constant-fold :allow-other-keys.2))
(checked-compile-and-assert
()
`(lambda (x)
(reduce #'+ '(1 2 3) :allow-other-keys x))
((1) 6)))
(with-test (:name (:constant-fold :repeat-keys))
(checked-compile-and-assert
()
`(lambda (x)
(member nil '(1 2 3) :key #'evenp :key x))
((1) '(1 2 3) :test #'equal)))
(with-test (:name :function-and-instance-primitive-type)
(checked-compile-and-assert
()
`(lambda (f)
(declare (function f))
(the standard-object f)
(funcall f #'list t))
((#'documentation) (documentation #'list t))))
(with-test (:name :mv-call-safety-0)
(checked-compile-and-assert
()
`(lambda (a)
(flet ((%f1 (x y) (+ x y)))
(apply #'%f1 a (list 0))))
((3) 3)))
(with-test (:name :cast-type-check-external)
(checked-compile-and-assert
()
`(lambda (x)
(declare (notinline +))
(gcd
(loop for lv2 below 1
count (logbitp 0
(if x
(return x)
1)))
0))
((334) 334)))
(with-test (:name :flush-combination-non-fun-type)
(checked-compile-and-assert
()
`(lambda ()
(rassoc-if-not #'values '((1 . a)) :allow-other-keys t)
1)
(() 1)))
(with-test (:name :symeval-nil)
(checked-compile-and-assert
()
`(lambda ()
(symbol-value nil))
(() nil)))
(with-test (:name (:environment-analyze :deleted-lambda))
(checked-compile-and-assert
()
`(lambda (log)
(loop for str in nil
for i from 0
do
(ignore-errors (format log ""))))
((t) nil)))
(with-test (:name (:ensure-lvar-fun-form :lvar-uses))
(checked-compile-and-assert
()
`(lambda (op) (funcall (case op (equal '=) (t '=)) 1 2))
(('equal) nil)
((t) nil)))
(with-test (:name :substitute-let-funargs-during-find-initial-dfo)
(checked-compile
`(lambda ()
(labels ((%r (f)
(loop)
(%r f)))
(%r (lambda ()))))))
(with-test (:name :split-ir2-blocks-cmov)
(checked-compile-and-assert
()
`(lambda ()
(let ((v (list 0)))
(if (block nil
(eq v (cdr v)))
1
2)))
(() 2)))
(with-test (:name :=-rational-complex-rational-fold)
(let ((fun (checked-compile '(lambda (x)
(declare ((complex integer) x))
(= x 10))))
(fun2 (checked-compile '(lambda (x)
(declare ((complex rational) x))
(= x 10d0)))))
(assert (equal (sb-kernel:%simple-fun-type fun)
'(function ((complex rational)) (values null &optional))))
(assert (not (funcall fun #C(10 10))))
(assert (equal (sb-kernel:%simple-fun-type fun2)
'(function ((complex rational)) (values null &optional))))
(assert (not (funcall fun2 #C(10 10))))))
(with-test (:name (:numeric float rational :contagion))
(flet ((check (operator type argument)
(let ((fun (checked-compile
`(lambda (x)
(declare (type ,type x))
,(ecase argument
(1 `(,operator x 1/2))
(2 `(,operator 1/2 x)))))))
(assert (null (ctu:find-code-constants fun :type 'ratio))))))
(dolist (operator '(+ * / - = < > <= >=))
(dolist (type '(single-float double-float))
(check operator type 1)
(check operator type 2)
(when (member operator '(+ * / - =))
(check operator `(complex ,type) 1)
(check operator `(complex ,type) 2))))))
(with-test (:name (:numeric float float :contagion))
(flet ((check (operator type argument)
(let ((fun (checked-compile
`(lambda (x)
(declare (type ,type x))
,(ecase argument
(1 `(,operator x 1.0f0))
(2 `(,operator 1.0f0 x)))))))
(assert (null (ctu:find-code-constants fun :type 'single-float))))))
(dolist (operator '(+ * / - = < > <= >=))
(check operator 'double-float 1)
(check operator 'double-float 2)
(when (member operator '(+ * / - =))
(check operator '(complex double-float) 1)
(check operator '(complex double-float) 2)))))
(with-test (:name :find-type-deriver)
(checked-compile-and-assert
()
`(lambda (x)
(find 1 x :key #'values))
(('(1)) 1)))
(with-test (:name :tail-call-ltn-annotation)
(checked-compile-and-assert
()
`(lambda (x)
(labels ((ff1 ()
(multiple-value-call #'print
(if x
(values t t)
nil))
(ff1)))
(identity (ff1))))))
(with-test (:name (:substitute-lvar-uses :deleted-code-and-dx-lvars))
(assert (nth-value 1
(checked-compile
`(lambda ()
(let ((v (values
(the integer
(flet ((%f5 (x) x))
(%f5)))
(unwind-protect 1))))
(declare (dynamic-extent v))
v))
:allow-warnings t))))
(with-test (:name (restart-case :declaration-processing))
(checked-compile-and-assert
()
`(lambda ()
(restart-case (list)
(my-restart (x) "foo" "bar" x)))
(() ()))
(checked-compile-and-assert
()
`(lambda ()
(restart-case (list)
(my-restart () (declare))))
(() ())))
(with-test (:name (handler-case :declaration-processing))
(checked-compile-and-assert
()
`(lambda ()
(handler-case (list 1 2) (error (e) "foo" "bar" e)))
(() '(1 2)))
(assert (nth-value 1
(checked-compile
`(lambda ()
(handler-case (declare)))
:allow-failure t))))
(with-test (:name (:unconvert-tail-calls :deleted-call))
(assert (nth-value 1
(checked-compile
'(lambda ()
(labels ((%f (&optional (x (* 2 nil (%f)))) x))
(%f)
(%f 1)))
:allow-warnings t))))
(with-test (:name (:equal-transform :nil-types))
(assert (nth-value 1
(checked-compile
'(lambda ()
(loop for y below 3
count (or
(not (or (>= y y) (equal y -787357528)))
(the integer (or (>= y y) (equal y -787357528))))))
:allow-warnings t))))
(with-test (:name (:delete-recursive-optional))
(checked-compile '(lambda (x)
(lambda ()
(labels ((f (&optional a) (values x a #'f))))))))
(with-test (:name (:combination-args-flow-cleanly-p :unused-result))
(checked-compile-and-assert
()
`(lambda ()
(let ((v (flet ((%f (x)
(list x)
(list 1)))
(%f 2))))
(declare (dynamic-extent v))
(car v)))
(() 1)))
(with-test (:name (:delete-ref :maintain-lambda-calls-or-closes))
(checked-compile `(lambda (c y)
(labels ((f1 ()
(if y
(f3 2)))
(l () (loop))
(f2 ()
(l)
(f3 3))
(f3 (x)
(f3 x))
(f4 ()
(f1)
(f2)))
(f4)
c))))
(with-test (:name (the :nil-type))
(checked-compile
`(lambda ()
(flet ((f () (the nil 0)))
(oddp (f))))))
(with-test (:name :concatenate-transform-hairy-type)
(checked-compile
'(lambda (x)
(concatenate '(and string (satisfies eval)) x))))
(with-test (:name :make-array-transform-deletion-notes)
(checked-compile
`(lambda (vector)
(let* ((length (length vector))
(new (make-array length :adjustable t
:fill-pointer length)))
new))
:allow-notes nil))
(with-test (:name :ltn-analyze-cast-unlink)
(assert (nth-value 1 (checked-compile
`(lambda (n)
(* 2 n)
(let ((p (make-array n :element-type 'double-float)))
(dotimes (i n)
(setf (aref p i)
(ignore-errors i)))))
:allow-warnings t))))
(with-test (:name :call-type-validation)
(checked-compile
`(lambda ()
(funcall (the (or cons function) *debugger-hook*)))))
(with-test (:name :setf-schar-hairy-types)
(checked-compile-and-assert
()
`(lambda (s v)
(setf (schar (the (satisfies eval) s) 0) v)
s)
(((copy-seq "abc") #\m) "mbc" :test #'equal)))
(with-test (:name :replace-zero-elements)
(checked-compile-and-assert
()
'(lambda (x)
(declare ((simple-vector 2) x))
(replace x x :start1 2))
(((vector 1 2)) #(1 2) :test #'equalp))
(checked-compile-and-assert
()
'(lambda (x)
(replace x x :start1 2))
(((vector 1 2)) #(1 2) :test #'equalp)))
(with-test (:name :error-in-xep)
(checked-compile-and-assert
(:optimize :safe)
'(lambda (x)
(declare (type (satisfies error) x))
x)
(("") (condition 'error))))
(with-test (:name :lifetime-analyze-tn-overflow-unused-tns)
(checked-compile-and-assert
()
`(lambda (x)
(multiple-value-bind (a b c)
(funcall x 1 2 3 ,@(make-list 58))
(declare (ignore b))
(values a c)))
((#'values) (values 1 3))))
(with-test (:name :constraints-not-enough-args)
(checked-compile-and-assert
()
`(lambda (list)
(delete-if #'> (the list list)))
(((list 1)) nil)))
(with-test (:name :%coerce-callable-for-call-removal-order-mv-call)
(checked-compile-and-assert
()
`(lambda (fun args)
(loop
(let ((result (apply fun args)))
(when result
(return result))
(setf args result))))
(('list '(1)) '(1) :test #'equal)))
(with-test (:name :constraint-loop)
(checked-compile-and-assert
()
`(lambda (a b)
(check-type a list)
(when a
(mapcar #'identity a)
(loop for c from 0 do (loop for d in b do
(loop for e in a)))))))
(with-test (:name :primitive-type-fun-designator)
(checked-compile-and-assert
()
`(lambda (fun)
(map 'vector fun '(1 2 3)))
(('1+) #(2 3 4) :test #'equalp)))
(with-test (:name :mv-call-lambda-type-derivation)
(assert
(equal (sb-kernel:%simple-fun-type
(checked-compile
'(lambda (x)
(multiple-value-call
(lambda () 133)
(funcall x)))))
'(function (t) (values (integer 133 133) &optional)))))
(with-test (:name :mv-call-lambda-type-derivation.closure)
(assert
(equal (sb-kernel:%simple-fun-type
(checked-compile
'(lambda (x)
(multiple-value-call
(lambda () (print x) 133)
(funcall x)))))
'(function (t) (values (integer 133 133) &optional)))))
(with-test (:name :constant-folding-and-hairy-types)
(checked-compile-and-assert
()
'(lambda ()
(> 0 (the (satisfies eval) (- 1))))
(() t)))
(with-test (:name :type-approximate-interval-and-hairy-types)
(checked-compile-and-assert
()
'(lambda (x)
(declare (fixnum x))
(<= (the (satisfies eval) 65) x))
((66) t)))
(with-test (:name :remove-equivalent-blocks-constraints)
(checked-compile-and-assert
()
`(lambda (c)
(declare (integer c))
(= (case c
((-10) (abs c))
(t c))
-1))
((-1) t)))
(with-test (:name :typep-singleton-intersect-types)
(checked-compile-and-assert
()
`(lambda ()
(keywordp t))
(() nil)))
(with-test (:name :constants-and-cmp)
(checked-compile-and-assert
()
'(lambda (l)
(declare (fixnum l))
(let ((v 0))
(labels ((change ()
(setf v 10)
#'change))
(> v l))))
((1) nil))
(checked-compile-and-assert
()
'(lambda (l)
(declare (fixnum l))
(let ((v 0))
(labels ((change ()
(setf v 10)
#'change))
(> l v))))
((1) t)))
(with-test (:name :inlining-and-substituted-block-lvars)
(checked-compile-and-assert
()
`(lambda ()
(let ((z (block nil
(labels ((f (x)
(return x)))
(declare (inline f))
(funcall (the function #'f) t)
(funcall (the function #'f) t)))))
(and z
1)))
(() 1)))
(with-test (:name :inlining-reanlyzing-optionals)
(checked-compile-and-assert
()
`(lambda ()
(labels ((w (x)
x
#'s)
(fun2 (f x)
(funcall f x))
(s (&optional x)
(fun2 #'w x)))
(declare (inline w))
(s)))))
(with-test (:name :vector-fill/t-fast-safe)
(let ((sb-c::*policy-min* sb-c::*policy-min*))
(sb-ext:restrict-compiler-policy 'safety 1)
(checked-compile-and-assert
()
'(lambda ()
(make-array 2 :initial-element 10))
(() #(10 10) :test #'equalp))))
(with-test (:name :deleted-tail-sets)
(checked-compile-and-assert
()
'(lambda ()
(labels ((f (&optional (a (catch t 6))
(b (error ""))
(c (unwind-protect 1)))
(+ a b c)))
(unwind-protect (f 4))))
(() (condition 'error))))
;;; The SLEEP source transform barfed on float positive infinity
;;; values.
(with-test (:name (compile sleep float :infinity :lp-1754081))
(checked-compile '(lambda () (sleep single-float-positive-infinity)))
(checked-compile '(lambda () (sleep double-float-positive-infinity))))
;;; And it didn't work at all after the fix for aforementioned
(with-test (:name :sleep-float-transform
:skipped-on (and :win32 (not :sb-thread)))
(let* ((xform (car (sb-c::fun-info-transforms (sb-int:info :function :info 'sleep))))
(type (car (sb-kernel:fun-type-required (sb-c::transform-type xform)))))
(assert (sb-kernel:constant-type-p type))
;; CONSTANT-TYPE isn't actually testable through CTYPEP.
;; So pull out the actual type as the compiler would do.
(assert (sb-kernel:ctypep 1.5 (sb-kernel:constant-type-type type)))))
(with-test (:name :atanh-type-derivation)
(checked-compile-and-assert
()
'(lambda (x)
(atanh (coerce x '(double-float * (0.0d0)))))))
(with-test (:name :ir1-optimize-combination-unknown-keys)
(checked-compile-and-assert
()
'(lambda (p x y)
(let ((f (when p #'string-equal)))
(when f
(funcall f "a" "b" x y))))
((t :start1 0) nil)))
(with-test (:name :member-transform)
(let ((list '(2 1 3)))
(checked-compile-and-assert
()
'(lambda (list &key key)
(member 1 list :key key))
((list) (cdr list)))))
(with-test (:name :note-no-stack-allocation-casts)
(checked-compile-and-assert
()
`(lambda ()
(let ((*s* (the integer (catch 'ct1 0))))
(declare (dynamic-extent *s*)
(special *s*))))))
(with-test (:name :dxify-downward-funargs-variable-name)
(checked-compile-and-assert
()
'(lambda () ((lambda (map) (funcall map)) #'list))))
(with-test (:name :dxify-downward-funargs-malformed)
(checked-compile
'(lambda () (sb-debug:map-backtrace))
:allow-style-warnings t))
(with-test (:name :dxify-downward-funargs-casts)
(checked-compile-and-assert
()
'(lambda (f x)
(flet ((f (y) (funcall f y)))
(funcall (the (satisfies eval) #'every) #'f x)))
((#'evenp '(2 2 4)) t)))
(with-test (:name :array-call-type-deriver-non-fun-type)
(checked-compile-and-assert
()
'(lambda (x) (funcall (the compiled-function #'aref) x))
((#0A123) 123)))
(with-test (:name :nth-&rest-overflow)
(checked-compile-and-assert
()
'(lambda (&rest s) (nth 536870908 s))
(() nil)))
(with-test (:name :array-in-bounds-p-transform-hairy-types)
(checked-compile-and-assert
()
'(lambda ()
(let ((a (the (satisfies eval) (make-array 4 :fill-pointer 0))))
(and (array-in-bounds-p a 0)
(array-in-bounds-p a 1))))
(() t)))
(with-test (:name :array-type-dimensions-or-give-up-hairy-types)
(checked-compile-and-assert
()
'(lambda (a i)
(declare ((or (array * (1)) (satisfies eval)) a))
(array-row-major-index a i))
((#(a b) 1) 1)))
(with-test (:name :array-type-dimensions-0-rank)
(checked-compile-and-assert
()
'(lambda (p1)
(declare ((or (array bit 1) (array * 0)) p1))
(array-total-size p1))
((#0a3) 1)))
(with-test (:name :type-derivation-hairy-types)
(checked-compile-and-assert
()
`(lambda (n s)
(declare (fixnum n))
(ash (the (satisfies eval) n)
(the (integer * 0) s)))
((1234 -4) 77))
(checked-compile-and-assert
()
`(lambda (p)
(declare (type (member #c(0.5d0 4.0d0) #c(0 -1)) p))
(/ (the (satisfies eval) p)))
((#c(0 -1)) #C(0 1))))
(with-test (:name :assert-lvar-type-intersection)
(checked-compile-and-assert
()
`(lambda (x y)
(write-sequence nil (the standard-object x) y nil))))
(with-test (:name :or-bignum-single-float-no-notes
:skipped-on (not (or :arm64 ppc :x86 :x86-64)))
(checked-compile
'(lambda (x) (declare (optimize speed)) (typep x '(or bignum single-float)))
:allow-notes nil))
(with-test (:name :vertices-best-color/general-default-value)
(checked-compile-and-assert
()
`(lambda (a)
(declare ((simple-array (complex double-float)) a))
(* (aref a 0)
(let ((z (aref a 0)))
(complex (realpart z) (imagpart z)))))))
(with-test (:name :copy-list-inlined)
(let ((f (checked-compile
`(lambda (x) (declare (optimize speed)) (copy-list x)))))
;; Should not have a call to COPY-LIST (or anything)
(assert (not (ctu:find-code-constants f :type 'sb-kernel:fdefn)))))
(with-test (:name :move-from-fixnum+-1)
(checked-compile-and-assert
(:allow-notes nil)
`(lambda (x)
(declare (fixnum x))
(1- x))
((0) -1)
((most-positive-fixnum) (1- most-positive-fixnum))
((most-negative-fixnum) (1- most-negative-fixnum)))
(checked-compile-and-assert
(:allow-notes nil)
`(lambda (x)
(declare (fixnum x))
(1+ x))
((0) 1)
((most-positive-fixnum) (1+ most-positive-fixnum))
((most-negative-fixnum) (1+ most-negative-fixnum)))
(checked-compile-and-assert
(:allow-notes nil)
`(lambda (a x)
(declare (fixnum x))
(if a
10
(1+ x)))
((nil 0) 1)
((t 0) 10)
((nil most-positive-fixnum) (1+ most-positive-fixnum))
((nil most-negative-fixnum) (1+ most-negative-fixnum))))
(with-test (:name :coalesce-more-ltn-numbers-constants)
(checked-compile-and-assert
()
`(lambda (x)
(list 1 1 ,@(make-list 100 :initial-element 'x)))
((1) (make-list 102 :initial-element 1) :test #'equal)))
(with-test (:name (:lambda-var-ref-lvar :multiple-refs))
(checked-compile-and-assert
()
`(lambda (vector index)
(labels ((update (index)
(let ((old (svref vector index)))
(if (eq old 10)
(update index)
old)))
(wrap (index)
(update index)))
(wrap index)))
((#(1 2 3) 1) 2)))
(with-test (:name :string-type-unparsing)
(checked-compile-and-assert
()
`(lambda (s)
(declare (type (string 1) s))
(the (or simple-array (member 1/2 "ba" 0 #\3)) s))
((#1="a") #1#)))
(with-test (:name :primitive-type-function)
(checked-compile-and-assert
()
`(lambda (x)
(funcall (the (and atom (not null)) x))
)
((#'list) nil)
(('list) nil)))
(with-test (:name :copyprop-sc-mismatch-between-moves
:serial t
:skipped-on :interpreter)
(let ((f (checked-compile
'(lambda (f x)
(let ((x (the double-float x)))
(values (funcall f x) (> x 1d0)))))))
(ctu:assert-no-consing (funcall f #'identity 1d0))))
(with-test (:name (:infer-iteration-var-type :step-is-range))
(let ((f (checked-compile
'(lambda (s)
(declare ((integer 1 2) s))
(let ((r 16))
(loop for i from 16 below 32 by s
do (setf r i))
r)))))
(assert (equal (sb-impl::%simple-fun-type f)
'(function ((integer 1 2)) (values (integer 16 31) &optional))))))
(with-test (:name (:infer-iteration-var-type :multiple-sets))
(let ((f (checked-compile
'(lambda (x)
(declare (optimize speed)
(type (integer 3 10) x))
(let ((y x))
(tagbody
:start
(when (plusp y)
(decf y)
(when (plusp y)
(decf y)
(go :start))))
y))
:allow-notes nil)))
(assert (equal (sb-impl::%simple-fun-type f)
'(function ((integer 3 10)) (values (integer 0 0) &optional))))))
(with-test (:name (:infer-iteration-var-type :incompatible-sets))
(checked-compile-and-assert ()
'(lambda (input-total missing-amount)
(declare (fixnum input-total) (fixnum missing-amount))
(loop with tot = 0
repeat 1
do (let ((difference input-total))
(setq difference (max difference 0))
(setq tot (+ tot difference)))
finally (when (plusp missing-amount)
(decf tot missing-amount))
(return (if (plusp tot) :good :bad))))
((0 0) :bad)
((1 0) :good)
((0 1) :bad)
((1 1) :bad)))
(with-test (:name :delay-transform-until-constraint-loop)
(checked-compile-and-assert
()
`(lambda (str)
(declare (string str))
(when (plusp (length str))
(make-array (1- (length str))
:element-type (array-element-type str)
:displaced-to str)))
(("abc") "ab" :test #'equal)))
(with-test (:name :lambda-var-ref-lvar-loop)
(checked-compile-and-assert
()
`(lambda ()
(labels ((z (a)
(when (>= 0 (the integer a))
(values #'z a))))))
(() nil)))
(with-test (:name :vector-length-fill-pointer-type-derivation)
(checked-compile-and-assert
()
`(lambda (s)
(= (length (the (string 1) s)) 1))
(((make-array 1 :element-type 'character :fill-pointer 0)) nil)))
(with-test (:name :function-designator-loop)
(checked-compile-and-assert
()
`(lambda (p1 p3 p4)
(declare (type (or (eql #.#'oddp)
(satisfies eval)) p1))
(find-if-not p1 nil p3 p4))
((#'oddp :from-end t) nil)))
(with-test (:name :lvar-constants-nested-funs)
(checked-compile-and-assert
()
`(lambda (x)
(labels ((f (x &optional result)
(if x
(f x result)
(nreverse result))))
(f x)))
((nil) nil)))
(with-test (:name :nested-indirect-var-fp-coalescence)
(checked-compile-and-assert
()
`(lambda ()
(let ((x 1)
(j 2))
(labels ((m ()
(incf x 32)
(incf j 44)
(let ((z 1))
(labels ((m ()
(incf x 32)
(incf z)))
(declare (notinline m))
(m)
(incf j z)))))
(declare (notinline m))
(m)
(values x j))))
(() (values 65 48))))
(with-test (:name :non-returning-functions-conflict)
(checked-compile-and-assert
()
`(lambda (x) (map nil #'error x))
((nil) nil)))
(with-test (:name :array-typep-other-pointer-widetag)
(checked-compile-and-assert
()
`(lambda (x)
(typep x '(and base-string (not simple-array))))
((10) nil)
(((make-array 10 :element-type 'base-char :adjustable t)) t)))
(with-test (:name :constraint-after-checkgen)
(let ((v #(10 20)))
(checked-compile-and-assert
()
`(lambda (p1 p2 p3 p4)
(declare (type (satisfies eval) p2)
(type (member :from-end 2) p3))
(position p1
(the (member ,v 3) p2)
(the (member 1 :from-end) p3) nil
:test-not p4))
((20 v :from-end #'/=) 1))))
(with-test (:name :cast-multiple-uses-no-dest)
(checked-compile-and-assert
(:allow-style-warnings t)
`(lambda (x)
(the integer
(when x
(if (> x 0) 1 2)))
(the integer x))
((23) 23))
(checked-compile-and-assert
(:allow-style-warnings t)
`(lambda (a b)
(declare (optimize (debug 1)))
(logand
(when b
(if (> (the integer a) 0) 10 20))
0)
(the integer b))
((24 23) 23)))
(with-test (:name :maybe-delete-exit-after-let-conversion)
(checked-compile-and-assert
()
`(lambda (m)
(flet ((out ()
(flet ((in (a)
(dotimes (i 3 a)
(if m
(return-from out)
(return-from out)))
(labels ((f (&optional (a m))
a
m)))))
(in (in 10)))))
(out)
33))
((t) 33))
(checked-compile-and-assert
()
`(lambda ()
(unwind-protect
(flet ((f (a b &optional c)
(values a b c)))
(f 1 2 (f 0 0)))))
(() (values 1 2 0))))
(with-test (:name :make-array-hairy-cons)
(checked-compile-and-assert
()
`(lambda (type)
(make-array 4 :element-type type :initial-element 0))
(('(or (cons (satisfies eval)) atom)) #(0 0 0 0) :test #'equalp)))
(with-test (:name :substitute-single-use-lvar-exit-cleanups)
(checked-compile-and-assert
()
`(lambda (z)
(block nil
(let ((b (1+ (funcall z))))
(catch 'c (return b)))))
(((constantly 33)) 34)))
(with-test (:name :substitute-single-use-lvar-unknown-exits)
(checked-compile-and-assert
()
`(lambda (f)
(block nil
(let ((x (evenp (funcall f)))
(y (catch 'c
(return (catch 'c (block nil 11))))))
(declare (ignore y))
x)))
(((constantly 33)) 11)))
(with-test (:name :substitute-single-use-lvar-unknown-exits.2)
(checked-compile-and-assert
()
`(lambda (b)
(block nil
(if (catch 'c 0)
(return
(let ((x (the real b)))
(let ((* (list 1)))
(declare (dynamic-extent *))
(catch 'ct5
(if t (return 34))))
x))
(catch 'c 0))))
((1) 34)))
(with-test (:name :substitute-single-use-lvar-unknown-exits.3)
(checked-compile-and-assert
()
`(lambda (b)
(let ((a b))
(block nil
(let ((* (list 1)))
(declare (dynamic-extent *))
(if b
(let ((j a))
(let ((* (list 1)))
(declare (dynamic-extent *))
(if b (return 44))
(setf a nil))
(let ((z j)) z))
(eval 2))))))
((33) 44)))
(with-test (:name :substitute-single-use-lvar-unknown-exits.4)
(checked-compile-and-assert
()
`(lambda (a)
(block nil
(flet ((f ()
(let ((p (1+ a)))
(let ((* (list 1)))
(declare (dynamic-extent *))
(if a
(return 45)))
p)))
(let ((* (lambda ()
(return (eval a)))))
(f)))))
((33) 45)))
(with-test (:name :substitute-single-use-lvar-unknown-exits.5)
(checked-compile-and-assert
()
`(lambda (b c)
(block nil
(flet ((f ()
(return (catch 'c (block b b)))))
(return
(block b5
(let ((o c))
(setf c
(catch 'c
(flet ((g ()
(return)))
(f))))
(let ((x o)) x)))))))
((10 20) 10)))
(with-test (:name :substitute-single-use-lvar-unknown-exits.6)
(checked-compile-and-assert
()
`(lambda ()
(block b
(return-from b
(let ((lv3 (random 10))
*)
(boole boole-1 lv3
(the integer
(catch 'ct4
(let ((x (list '*)))
(declare (dynamic-extent x))
(return-from b (eval x))))))))))
(() 1)))
(with-test (:name :lambda-let-inline)
(let ((fun (checked-compile
`(lambda ()
(let ((x (lambda () 1)))
(funcall x))))))
(assert (null (ctu:find-anonymous-callees fun)))
(assert (= (funcall fun) 1))))
(with-test (:name :external-cast-deletion)
(checked-compile-and-assert
()
`(lambda (a c)
(declare (notinline elt logior))
(logior
(if c
(the integer (elt '(10 20) a))
(let ((v1 (loop repeat 3 count t)))
(declare (dynamic-extent v1))
v1))))
((0 t) 10)
((1 nil) 3)))
(with-test (:name :fixnump-instance-ref-immediately-used)
(checked-compile-and-assert
()
`(lambda (a b c)
(let (z)
(and
(typep
(let ((y (let ((s (cons a b)))
(declare (dynamic-extent s))
(cdr s))))
(unwind-protect
(let ((s (list c)))
(declare (dynamic-extent s))
(setf z (car s))))
y)
'fixnum)
z)))
((1 2 'a) 'a)))
(with-test (:name :fixnump-instance-ref-immediately-used.2)
(checked-compile-and-assert
()
`(lambda (a b c)
(let* ((l (cons a b))
(cdr (cdr l)))
(setf (cdr l) c)
(typep cdr 'fixnum)))
((1 2 'a) t)))
(with-test (:name :round-numeric-bound)
(checked-compile-and-assert
()
`(lambda (a c f)
(declare (type (integer -1111868182375 1874303539234) a))
(- (rem (funcall f) (max 23 (* 45092832376540563 a -4469591966)))
(signum c)))
((1874303539234 2 (constantly 123)) 7)))
(with-test (:name :ir2-optimize-jumps-to-nowhere)
(checked-compile-and-assert
()
`(lambda (a)
(declare (type fixnum a))
(if (< a 0 a)
(block a (shiftf a 1))
0))
((0) 0)))
(with-test (:name :double-float-bits-stub)
(checked-compile-and-assert
()
`(lambda (x)
(float-sign 5.0d0 (the double-float x)))
((3d0) 3d0)))
(with-test (:name :typep-word)
(checked-compile-and-assert
()
`(lambda (x)
(typep x 'sb-vm:word))
((1) t)
(((1- (expt 2 sb-vm:n-word-bits))) t)
(((expt 2 sb-vm:n-word-bits)) nil)
((-1) nil)
(('a) nil)
((()) nil)
(((1- most-negative-fixnum)) nil)))
(with-test (:name :fixnum-mod-p-word-descriptor)
(checked-compile-and-assert
()
`(lambda (a)
(declare (type sb-vm:signed-word a))
(typep a '(integer 0 ,(1- most-positive-fixnum))))
(((1- most-positive-fixnum)) t)
((0) t)
((1) t)
((most-positive-fixnum) nil)
(((1+ most-positive-fixnum)) nil)
((most-negative-fixnum) nil)
(((1+ most-negative-fixnum)) nil)
(((1- (expt 2 (1- sb-vm:n-word-bits)))) nil)
((-1) nil)))
(with-test (:name :check-bound-zero-safety-notes)
(checked-compile-and-assert
(:allow-notes nil
:optimize '(:speed 3 :safety 0))
`(lambda (a x y z)
(declare (fixnum x y z)
((simple-array t (*)) a)
(optimize (speed 3) (safety 0)))
(aref a (+ x (- y z))))
((#(1 2 3) 1 0 0) 2)))
(with-test (:name :convert-mv-bind-to-let-multiple-uses)
(checked-compile-and-assert
()
`(lambda (f)
(let* ((a (eval 1))
(b (eval 2)))
(multiple-value-bind (x y) (if f
(values a 1)
(values b 2))
(values x y))))
((t) (values 1 1))
((nil) (values 2 2))))
(with-test (:name :substitute-single-use-lvar-multiple-uses)
(checked-compile-and-assert
()
`(lambda (f)
(let* ((a (eval 1))
(b (eval 2))
(m (if f
(values a)
(values b))))
m))
((t) 1)
((nil) 2)))
(with-test (:name :tn-ref-type-multiple-moves)
(checked-compile-and-assert
()
`(lambda (a c)
(declare (type (integer 546181490258163 937632934000433) c))
(let ((v8 c))
(multiple-value-bind (v9 v6)
(if (/= a v8)
(values 0 10983313414045189807)
(values 0 c))
(declare (ignore v9))
(loop repeat 2
do (eval v6))
v6)))
((0 571816791704489) 10983313414045189807)))
(with-test (:name :substitute-single-use-lvar-cast-chains)
(checked-compile-and-assert
()
`(lambda (f a b)
(labels ((fun (z)
(let ((m z))
;; delays type derivation of FUN as FIXNUM until constraint propagation
;; making sure SUBSTITUTE-SINGLE-USE-LVAR runs first.
(if (typep m 'fixnum)
m
0))))
(declare (inline fun))
(let* ((a (fun a))
(b (fun b)))
(let ((m
(if f
(the fixnum (the integer a))
(the fixnum (the integer b)))))
m))))
((t 1 2) 1)
((nil 1 2) 2)))
(with-test (:name :m-v-bind-multi-use-unused-values.1)
(multiple-value-bind (calls f)
(ctu:ir1-named-calls
'(lambda (z m)
(multiple-value-bind (a b)
(if z
10
(values (sxhash m) m))
(declare (ignore a))
b)))
(assert (eql (funcall f t 33) nil))
(assert (eql (funcall f nil 33) 33))
(assert (not calls))))
(with-test (:name :m-v-bind-multi-use-unused-values.2)
(multiple-value-bind (calls f)
(ctu:ir1-named-calls
'(lambda (z m)
(multiple-value-bind (a b c)
(if z
(values 10)
(values (sxhash m) m))
(declare (ignore a))
(list b c))))
(assert (equal (funcall f t 33) '(nil nil)))
(assert (equal (funcall f nil 33) '(33 nil)))
(assert (not calls))))
(with-test (:name :m-v-bind-multi-use-unused-values.3)
(multiple-value-bind (calls f)
(ctu:ir1-named-calls
'(lambda (z m)
(multiple-value-bind (a b)
(if z
10
(values m (sxhash m)))
(declare (ignore b))
a)))
(assert (eql (funcall f t 33) 10))
(assert (eql (funcall f nil 33) 33))
(assert (not calls))))
(with-test (:name :m-v-bind-multi-use-unused-values.4
:skipped-on :sbcl)
(multiple-value-bind (calls f)
(ctu:ir1-named-calls
'(lambda (z m)
(nth-value 1
(if z
(funcall (the function z))
(values (sxhash m) m)))))
(assert (eql (funcall f (lambda () (values 1 22)) 33) 22))
(assert (eql (funcall f nil 34) 34))
(assert (not calls))))
(with-test (:name :m-v-bind-multi-use-unused-values.5
:skipped-on :sbcl)
(multiple-value-bind (calls f)
(ctu:ir1-named-calls
'(lambda (z m)
(nth-value 1
(if z
(funcall (the function z))
(sxhash m)))))
(assert (eql (funcall f (lambda () (values 1 22)) 33) 22))
(assert (eql (funcall f nil 34) nil))
(assert (not calls))))
(with-test (:name :m-v-bind-multi-use-variable-type-change)
(checked-compile-and-assert
()
'(lambda (p)
(when (position #\a (the (or (simple-string 1) (simple-string 2)) p))
nil))
(("a") nil)
(("ab") nil)))
(with-test (:name :array-element-type-cons.1)
(checked-compile-and-assert
(:allow-notes nil)
'(lambda (vector)
(declare ((or (simple-array (unsigned-byte 32) (2))
(simple-array (unsigned-byte 32) (4))) vector))
(make-array 10 :element-type (array-element-type vector)))
(((make-array 2 :element-type '(unsigned-byte 32)))
'(unsigned-byte 32) :test (lambda (x y)
(equal (array-element-type (car x)) (car y))))))
(with-test (:name :array-element-type-cons.2)
(checked-compile-and-assert
(:allow-notes nil)
'(lambda (vector)
(declare ((and (simple-array (unsigned-byte 32) (2))
(satisfies eval)) vector))
(make-array 10 :element-type (array-element-type vector)))
(((make-array 2 :element-type '(unsigned-byte 32)))
'(unsigned-byte 32) :test (lambda (x y)
(equal (array-element-type (car x)) (car y))))))
(with-test (:name :about-to-modify-symbol-value-relax-fun-type)
(let* ((compiled-lambda (compile nil '(lambda (&rest x) x 'hi)))
(sb-c::*compiler-error-bailout*
(lambda (&optional c) (error c))))
(declare (notinline set))
(set 'sb-c::*compiler-error-bailout* compiled-lambda)))
(with-test (:name :self-evaluating-p-not)
(let ((s (gensym)))
(set s 9)
(unintern s)
(import s 'keyword)
(assert (not (sb-int:self-evaluating-p s)))))
(with-test (:name :lea-modfx-constant-folding)
(checked-compile-and-assert
()
'(lambda (c)
(if (if c
c
(if 444
nil
99))
11
(logand 3
(logxor
(* 5
(if c
0
(ash most-positive-fixnum -2)))
3))))
((t) 11)
((nil) 0)))
(with-test (:name :setup-environment-tn-conflicts)
(checked-compile-and-assert
()
'(lambda (z)
(let ((c 0))
(flet ((bar ()
(let ((m (eval :bad)))
(eval m)
(and m c))))
(declare (notinline bar))
(cond (z
(setf c 10)
(bar))
(44)))))
((t) 10)
((nil) 44)))
(with-test (:name :setup-environment-tn-conflicts.2)
(checked-compile-and-assert
()
'(lambda (z)
(let ((c 0)
(b 0)
(a 0)
(d 0))
(labels ((bar ()
(let ((m (eval :bad)))
(eval m)
(if m
(values a b c d))))
(jam ()
(multiple-value-list (bar))))
(declare (notinline bar
jam))
(cond (z
(setf a 10
c 10
b 10
d 10)
(jam))
(44)))))
((t) '(10 10 10 10) :test #'equal)
((nil) 44)))
(with-test (:name :setup-environment-tn-conflicts.3)
(checked-compile-and-assert
()
'(lambda (b)
(flet ((%f7 ()
(flet ((%f10 ()
(setf b b)))
(declare (dynamic-extent #'%f10))
(funcall (eval #'%f10)))))
(declare (notinline %f7))
(%f7)))
((10) 10)))
(with-test (:name :dead-sets)
(checked-compile-and-assert
()
`(lambda ()
(logtest
((lambda (v &rest args)
(declare (ignore args))
(setf v
((lambda (&rest args) (declare (ignore args)) (error "")) v)))
1)
1))
(() (condition 'simple-error))))
(with-test (:name :inlining-multiple-refs)
(checked-compile
`(lambda (x)
(labels ((%s (y &rest r)
(some
(lambda (r) (apply #'%s (1+ y) r))
(apply #'eql x r))))
(%s 1)))))
(with-test (:name :update-lvar-dependencies-delete-lvar)
(checked-compile-and-assert
()
'(lambda (x y)
(let ((x x))
(block nil
(flet ((proc (thing)
(when thing
(return (eval thing)))))
(declare (inline proc))
(if x
(proc y)
(proc y)))))
t)
((1 2) t)))
(with-test (:name :car-type-on-or-null
:fails-on :sbcl)
(assert
(equal (sb-kernel:%simple-fun-type
(checked-compile
'(lambda (x)
(declare (type (or null (cons fixnum)) x))
(if x
(car x)
0))))
'(function ((or null (cons fixnum t))) (values fixnum &optional)))))
(with-test (:name :nlx-entry-zero-values)
(checked-compile-and-assert
()
'(lambda (x)
(multiple-value-call (lambda (&optional x) x)
(block nil
(funcall (eval (lambda ()
(return (if x
(values)
10))))))))
((t) nil)
((nil) 10)))
(with-test (:name :find-test-to-eq-with-key)
(checked-compile-and-assert
()
'(lambda (x)
(position (1- (expt x 64)) '((#xFFFFFFFFFFFFFFFF)) :key #'car))
((2) 0)
((1) nil)))
(with-test (:name :maybe-infer-iteration-var-type-on-union)
(checked-compile-and-assert
(:allow-notes nil :optimize '(:speed 3 :compilation-speed 1 :space 1))
`(lambda (a)
(loop repeat (if a 2 0) count 1))
((t) 2)
((nil) 0)))
(with-test (:name :maybe-infer-iteration-var-type-on-union.2)
(checked-compile-and-assert
()
`(lambda (a)
(let ((v4 (the (or (single-float (1.0) (3.0)) (single-float 4.0 5.0)) a)))
(incf v4 1.0)))
((4.0) 5.0)))
(with-test (:name :derive-array-rank-negation)
(checked-compile-and-assert
()
`(lambda (a)
(declare ((not (simple-array * (* *))) a))
(eql (array-rank a) 2))
(((make-array '(2 2) :adjustable t)) t))
(checked-compile-and-assert
()
`(lambda (a)
(declare ((not (simple-array fixnum (* *))) a))
(eql (array-rank a) 2))
(((make-array '(2 2))) t))
(checked-compile-and-assert
()
`(lambda (a)
(declare ((not (and (array * (* *)) (not simple-array))) a))
(eql (array-rank a) 2))
(((make-array '(2 2))) t)))
(with-test (:name :derive-array-rank-negation.2)
(assert
(type-specifiers-equal
(sb-kernel:%simple-fun-type
(checked-compile
'(lambda (x)
(declare ((and simple-array
(not (simple-array * (* *))))
x))
(eql (array-rank x) 2))))
'(function ((and simple-array (not (simple-array * (* *)))))
(values null &optional)))))
(with-test (:name :known-fun-no-fdefn)
(assert (equal (ctu:find-code-constants (checked-compile '(lambda () #'+))
:type 'function)
(list #'+))))
(with-test (:name :double-float-p-weakening)
(checked-compile-and-assert
(:optimize '(:speed 3 :safety 1))
'(lambda (x)
(declare (double-float x))
x)
((0.0) (condition 'type-error))
((1d0) 1d0)))
(declaim (inline inline-fun-arg-mismatch))
(defun inline-fun-arg-mismatch (x)
(declare (optimize (debug 0)))
x)
(with-test (:name :inline-fun-arg-mismatch)
(checked-compile-and-assert
(:allow-warnings '(or sb-int:local-argument-mismatch
#+interpreter simple-warning)) ;; why?
'(lambda ()
(multiple-value-call #'inline-fun-arg-mismatch 1 2))
(() (condition 'program-error))))
(with-test (:name :principal-lvar-ref-use-loop)
(checked-compile-and-assert ()
'(lambda (vector)
(labels ((f (count)
(when (< (aref vector 0) count)
(f count))))))
((1) nil)))
(with-test (:name (:mv-call :more-arg)
:fails-on :mips)
(checked-compile-and-assert
()
'(lambda (&rest rest)
(multiple-value-bind (a b c) (values-list rest)
(declare (ignore c))
(list a b)))
((1 3) '(1 3) :test #'equal)))
(with-test (:name (:mv-call :more-arg-unused)
:fails-on :mips)
(checked-compile-and-assert
()
'(lambda (&rest rest)
(multiple-value-bind (a b) (values-list rest)
(list a b)))
(() '(nil nil) :test #'equal)
((1) '(1 nil) :test #'equal)
((1 3) '(1 3) :test #'equal)))
(with-test (:name :truncate-deriver-on-number-type)
(checked-compile-and-assert
()
'(lambda (i)
(truncate
(labels ((f (&optional (o i))
(declare (ignore o))
(complex 0 0)))
(declare (dynamic-extent (function f)))
(the integer
(multiple-value-call #'f (values))))
3))
((0) (values 0 0))))
(with-test (:name :signum-type-deriver)
(checked-compile-and-assert
()
'(lambda (n)
(typep (signum n) 'complex))
((#C(1 2)) t)
((1d0) nil)
((10) nil)))
(with-test (:name :array-header-p-derivation)
(checked-compile-and-assert
()
'(lambda (q)
(and (typep q '(not simple-array))
(sb-kernel:array-header-p q)))
((10) nil)
(((make-array 10 :adjustable t)) t)))
(with-test (:name :phase-type-derivation)
(checked-compile-and-assert
()
'(lambda (x)
(= (phase (the (integer -1 0) x))
(coerce pi 'single-float)))
((-1) t)
((0) nil)))
(with-test (:name :maybe-negate-check-fun-type)
(checked-compile-and-assert
()
'(lambda (m)
(declare ((or (function (number)) (eql #.#'symbolp)) m))
(the (member 3/4 4/5 1/2 #.#'symbolp) m))
((#'symbolp) #'symbolp)))
(with-test (:name :equal-to-eql)
(let ((f (checked-compile
`(lambda (x y)
(equal (the hash-table x) y)))))
(assert (not (ctu:find-code-constants f :type 'sb-kernel:fdefn))))
(let ((f (checked-compile
`(lambda (x y)
(equalp (the function x) y)))))
(assert (not (ctu:find-code-constants f :type 'sb-kernel:fdefn)))))
(with-test (:name :multiway-branch-duplicate-case)
(let ((f (checked-compile '(lambda (b)
(case b
((1 2) :good)
((3 2) :bad)))
:allow-style-warnings t)))
(assert (eq (funcall f 2) :good))))
(with-test (:name :modular-arith-type-derivers
:fails-on :ppc64)
(let ((f (checked-compile
`(lambda (x)
(declare ((and fixnum
unsigned-byte) x)
(optimize speed))
(rem x 10)))))
(assert (not (ctu:find-code-constants f :type 'bignum)))))
(with-test (:name :deduplicated-fdefns)
(flet ((scan-range (c start end)
(let (dup-fdefns names)
(loop for i from start below end
do (let ((obj (sb-kernel:code-header-ref c i)))
(when (sb-kernel:fdefn-p obj)
(let ((name (sb-kernel:fdefn-name obj)))
(when (member name names)
(push obj dup-fdefns))
(push name names)))))
(assert (not dup-fdefns)))))
(dolist (c (sb-vm:list-allocated-objects :all :type sb-vm:code-header-widetag))
(sb-int:binding* (((start count) (ctu:code-header-fdefn-range c))
(end (+ start count)))
;; Within each subset of FDEFNs there should be no duplicates
;; by name. But there could be an fdefn that is in the union of the two sets.
(scan-range c start end)
(scan-range c end (sb-kernel:code-header-words c))))))
(with-test (:name :map-all-lvar-dests)
(checked-compile-and-assert
()
`(lambda (&key (pred (constantly 44)))
(declare (type function pred))
(funcall pred))
(() 44)))
(with-test (:name (:lvar-fun-name :constant-leaf-not-constant-lvar-p))
(assert (nth-value 1
(checked-compile
`(lambda ()
(funcall
(the (function (t) t)
,(checked-compile '(lambda ())))))
:allow-warnings t
:allow-style-warnings t))))
(with-test (:name (:%logbitp :signed-and-unsigned))
(checked-compile-and-assert
()
`(lambda (p2)
(declare (type (integer ,(expt -2 (1- sb-vm:n-word-bits))
,(1- (expt 2 sb-vm:n-word-bits))) p2))
(logbitp 26 p2))
((3) nil)
(((ash 1 26)) t)))
(with-test (:name :vop-return-constant-boxing)
(checked-compile
`(lambda (x)
(declare (optimize speed))
(setf (aref (the (simple-array double-float (*)) x) 0)
10d0))
:allow-notes nil)
(checked-compile
`(lambda (x)
(declare (optimize speed))
(setf (aref (the (simple-array sb-vm:word (*)) x) 0)
(1- (expt 2 sb-vm:n-word-bits))))
:allow-notes nil)
(checked-compile
`(lambda (x y)
(declare (optimize speed))
(setf (svref y 0)
(setf (aref (the (simple-array double-float (*)) x) 0)
10d0)))
:allow-notes nil)
(checked-compile
`(lambda (f a)
(declare (optimize speed))
(funcall (the function f)
1 2 3 4 5 6 7 8 9 10
(setf (aref (the (simple-array double-float (*)) a) 0)
10d0)))
:allow-notes nil))
(with-test (:name :make-constant-tn-force-boxed)
(checked-compile-and-assert
()
`(lambda (c)
(declare (type character c))
(list 1 1 1 1 1 1 1 1 1 1 1 (the (eql #\() c)))
((#\() '(1 1 1 1 1 1 1 1 1 1 1 #\() :test #'equal)))
(with-test (:name :jump-over-move-coercion
:serial t
:skipped-on :interpreter)
(let ((f (checked-compile
'(lambda (number)
(declare ((or fixnum double-float single-float) number))
(cond ((typep number 'double-float)
number)
((typep number 'single-float)
(coerce number 'double-float))
((typep number 'fixnum)
(coerce number 'double-float)))))))
(ctu:assert-no-consing (funcall f 1d0)))
(let ((f (checked-compile
'(lambda (v number)
(declare ((or fixnum double-float single-float) number))
(setf (svref v 0)
(cond ((typep number 'double-float)
number)
((typep number 'single-float)
(coerce number 'double-float))
((typep number 'fixnum)
(coerce number 'double-float))))))))
(let ((v (vector 0)))
(ctu:assert-no-consing (funcall f v 1d0)))))
(with-test (:name :jump-over-move-coercion-match-type)
(checked-compile-and-assert
()
`(lambda (a b)
(declare (type (or sb-vm:word sb-vm:signed-word) a))
(declare (type (and fixnum unsigned-byte) b))
(lognand (max 0 a) b))
(((expt 2 (1- sb-vm:n-word-bits)) #xFFFFFF) -1)
(((1- (expt 2 (1- sb-vm:n-word-bits))) #xFFFFFF) -16777216)))
#+#.(cl:if (cl:gethash 'sb-c:jump-table sb-c::*backend-template-names*)
'(:and)
'(:or))
(with-test (:name :typecase-to-case-preserves-type)
(let ((f (checked-compile
'(lambda (x)
;; This illustrates another possible improvement-
;; there are not actually 6 different slot indices
;; that we might load. Some of them are the same
(typecase x
(sb-pretty:pprint-dispatch-table (sb-pretty::pp-dispatch-entries x))
(sb-impl::comma (sb-impl::comma-expr x))
(sb-vm:primitive-object (sb-vm:primitive-object-slots x))
(sb-kernel:defstruct-description (sb-kernel::dd-name x))
(sb-kernel:lexenv (sb-c::lexenv-vars x))
(broadcast-stream (broadcast-stream-streams x))
(t :none))))))
;; There should be no #<layout> referenced directly from the code header
;; (which implies that no type-check occurs when accessing a structure instance).
;; There is of course a vector of layouts in there to compare against.
(assert (not (ctu:find-code-constants f :type 'sb-kernel:layout)))
;; The function had better work.
(assert (eq (funcall f 'wat) :none))
(assert (equal (funcall f (make-broadcast-stream *error-output*))
(list *error-output*)))))
(with-test (:name :=-interval-derivation-and-complex)
(checked-compile-and-assert
()
`(lambda (p1)
(declare ((complex (integer -1 -1)) p1))
(= -1 p1))
((#C(-1 -1)) nil)))
(with-test (:name :cmov-move-hoisting)
(checked-compile-and-assert
()
`(lambda (p)
(declare ((or (eql 0.0)
sb-vm:word) p))
(if (> p 51250)
p
1))
((0.0) 1)
((#1=(1- (expt 2 sb-vm:n-word-bits))) #1#))
(checked-compile-and-assert
()
`(lambda (p)
(declare (type (member 4801112936349103672 -9474680540642044437) p))
(max 0 p -1.0))
((4801112936349103672) 4801112936349103672)
((-9474680540642044437) 0)))
(with-test (:name :logior-derive-type-widening-tail-set-types)
(checked-compile-and-assert
()
`(lambda (a b c)
(labels ((q (x y)
(let ((* (lambda () x y)))
(the integer a)))
(p ()
(logior (apply #'q (list a b))
(if b
(return-from p (q b c))
1))))
(if c
0.0
(p))))
((44 nil nil) 45)
((3 2 1) 0.0)
((30 2 nil) 30)))
(with-test (:name :if-eq-optimization-consistency)
(let ((sb-c::*check-consistency* t))
(checked-compile-and-assert
()
`(lambda ()
(eval (and (if (eval 0) (eval 0) (eval 0)) t)))
(() t))))
(with-test (:name :make-array-half-finished-transform)
(checked-compile-and-assert
(:allow-warnings t)
`(lambda ()
(make-array 6 :fill-pointer 33))
(() (condition '(not program-error)))))
(with-test (:name :nested-if+let)
(checked-compile-and-assert
()
`(lambda ()
(let (x)
(when x
(setq x 1))
(let ((y (if x
t
nil)))
(if y
y
(let ((x x))
x)))))
(() nil)))
(with-test (:name :let-var-immediately-used-p-deleted-lambda)
(checked-compile-and-assert
()
`(lambda (c)
(if (and nil
(or
(zerop (count (unwind-protect 1) '(1)))
c))
1
0))
((2) 0)))
(with-test (:name :dce-local-functions)
(checked-compile-and-assert
()
`(lambda ()
(block out
(labels ((mmm (z vars)
(when vars
(mmm z vars))))
(mmm 1 (progn
(dotimes (a 1) (return-from out 10))
(dotimes (b 3) (catch 'b))))
(dotimes (c 3) (catch 'c)))))
(() 10)))
(with-test (:name :dce-more-often)
(checked-compile-and-assert
()
`(lambda (a)
(+ 1
(if t
0
(progn
(tagbody
p
(tagbody
(let ((a (lambda () (go o))))
(declare (special a)))
o)
(when (< a 1)
(go p)))
2))))
((1) 1)
(:return-type (values (integer 1 1) &optional))))
(with-test (:name :dce-more-often.2)
(checked-compile-and-assert
()
`(lambda (b)
(declare (fixnum b))
(- (case 0
(1
(dotimes (i 1 b) (ignore-errors)))
(t 0))))
((3) 0)
(:return-type (values (integer 0 0) &optional))))
(with-test (:name :ir1-optimize-constant-fold-before-giving-up)
(checked-compile-and-assert
()
`(lambda (a)
(+ 2 (- (let ((sum 0))
(declare (type fixnum sum))
(block nil
(tagbody
next
(cond ((>= sum '0)
(go end))
(a
(ceiling 1 (unwind-protect 2))
(incf sum)))
(go next)
end))
sum))))
((1) 2)))
(with-test (:name :position-case-otherwise)
(checked-compile-and-assert
()
`(lambda (x)
(position x '(a otherwise b t nil)))
(('a) 0)
(('otherwise) 1)
((nil) 4)
((t) 3)))
(with-test (:name :unreachable-component-propagate-let-args)
(checked-compile-and-assert
()
`(lambda ()
(let ((p 0))
(flet ((f (&key)
(flet ((g (&optional
(z
(return-from f (+ (dotimes (i 0 0)) p))))
p))))))
p))
(() 0)))
(with-test (:name :dce-through-optional-dispatch)
(checked-compile-and-assert
()
`(lambda (x)
(flet ((z (&optional a)
(declare (ignore a))
123))
(let ((z #'z))
(when x
(unless x
(setf z 10)))
(funcall z))))
((nil) 123)
((t) 123)))
(with-test (:name :values-list+cons)
(assert
(equal (sb-kernel:%simple-fun-type
(checked-compile
`(lambda ()
(values-list (cons 1 nil)))))
'(function () (values (integer 1 1) &optional))))
(assert
(equal (sb-kernel:%simple-fun-type
(checked-compile
`(lambda (x) (values-list (list* x 1 x nil)))))
'(function (t) (values t (integer 1 1) t &optional)))))
(with-test (:name :xeps-and-inlining)
(checked-compile-and-assert
()
`(lambda (args)
(flet ((fun () args))
(declare (inline fun))
(multiple-value-call #'fun (values-list args))
#'fun))))
(with-test (:name :split-let-ctran-kind)
(checked-compile-and-assert
()
`(lambda (a b)
(let ((a-n (null a))
(b-n (null b)))
(cond (b-n 1)
(a-n a)
(t a))))
((nil nil) 1)
((nil t) nil)))
(with-test (:name :dead-component-unused-closure)
(checked-compile-and-assert
()
`(lambda ()
(labels ((%f1 ())
(%f2 (&key)
(flet ((%f3 ()
(unwind-protect 1)
(return-from %f2 (%f1)))))))
(%f1)))
(() nil)))
(with-test (:name :references-to-inline-funs-copied)
(checked-compile-and-assert
()
`(lambda ()
(and (inline-fun-arg-mismatch t)
#'inline-fun-arg-mismatch))
(() #'inline-fun-arg-mismatch)))
(with-test (:name :eliminate-dead-code-before-initial-dfo)
(checked-compile-and-assert
()
`(lambda ()
(block nil
(flet ((f (&key (k1 (catch 'c)))
(max 0
(let ((v9 10))
(return))))))))
(() nil)))
(with-test (:name :%coerce-callable-to-fun-movement)
(checked-compile-and-assert
()
`(lambda (y x)
(let ((x (sb-kernel:%coerce-callable-to-fun x)))
(when y
(funcall x))))
((nil (make-symbol "UNDEF")) (condition 'undefined-function))))
(with-test (:name :jump-table-use-labels)
(checked-compile-and-assert
()
`(lambda (x m)
(case x
((a b c)
(if m
(error ""))
x)
((d e f)
(eval 10)
x)))
(('a nil) 'a)
(('d 30) 'd)))
(with-test (:name :dfo-deleted-lambda-home)
(assert
(nth-value 5 (checked-compile
`(lambda (c)
(flet ((f (&optional (o c))
(lambda (&key)
(+ (restart-bind nil (go missing-tag))
(progv nil nil o)))))))
:allow-failure t))))
(with-test (:name :split-let-unused-vars)
(checked-compile-and-assert
()
`(lambda (x y)
(let ((a
(if x y))
(b)
(c
(if y
x)))
(declare (ignore b))
(if c (if a a c))))
((t t) t)
((t nil) nil)
((nil t) nil)
((nil nil) nil)))
(with-test (:name :sequence-lvar-dimensions-on-arrays)
(checked-compile-and-assert
()
`(lambda (x a)
(count a (make-string x :initial-element a)))
((10 #\a) 10)))
(with-test (:name :length-transform-on-arrays)
(checked-compile-and-assert
()
`(lambda () (length (make-sequence '(string *) 10 :initial-element #\a)))
(() 10)))
(with-test (:name :constant-fold-unknown-types)
(checked-compile-and-assert
(:allow-style-warnings t)
`(lambda ()
(oddp (the (or a b) -1)))))
(with-test (:name :dead-code-no-constant-fold-errors)
(assert
(typep (nth-value 4
(checked-compile
`(lambda (z)
(when (and (eq z 0)
(not (eq z 0)))
(/ 10 0)))))
'(cons sb-ext:code-deletion-note null))))
(with-test (:name :unused-assignment)
(flet ((try (expr &aux (warned 0))
(handler-bind ((style-warning
(lambda (c)
(if (search "assigned but never read" (princ-to-string c))
(incf warned)
(error "That's unexpected")))))
(multiple-value-bind (fun warn error)
(let ((*error-output* (make-broadcast-stream))) (compile nil expr))
(declare (ignore fun))
(assert (and warn (not error) (eql warned 1)))))))
(try '(lambda (x) (let* ((a (+ x 5)) (b a)) (setq b 3) (eval ''z))))
;; Even if the initializer is necessary to call, it's still warning-worthy.
(try '(lambda (x) (let* ((a (+ x 5))
(b (opaque-identity a)))
(setq b 3)
(eval ''z))))
(try '(lambda (x) (let* ((a (+ x 5)) (b a))
(setq b (opaque-identity 3))
(eval ''z)))))
;; This one uses the value of B
(checked-compile '(lambda (x) (let* ((a (+ x 5)) (b a))
(setq b (opaque-identity 3))))))
(with-test (:name :unconvert-tail-calls-terminate-block)
(checked-compile-and-assert
()
`(lambda (x y)
(flet ((f ()
(labels ((a ()
(error "~a" x))
(b ()
(a)))
(if nil
(b)
(if y
(a)
(b))))))
(block nil
(return (f)))))
((t t) (condition 'error))))
(with-test (:name :unconvert-tail-calls-terminate-block.2)
(checked-compile-and-assert
()
`(lambda (x)
(flet ((f ()
(labels ((a ()
(error "foo ~a" x))
(b ()
(let (*)
(a))))
(if nil
(b)
(if nil
(a)
(if x
(a)
(b)))))))
(f)
10))
((t t) (condition 'error))))
(with-test (:name :fixnum-checking-boxing
:skipped-on (not :x86-64))
(checked-compile
`(lambda (x y)
(declare (optimize speed)
(fixnum x y))
(the fixnum (+ x y)))
:allow-notes nil))
(with-test (:name :ltn-analyze-mv-bind)
(checked-compile-and-assert
()
`(lambda ()
(multiple-value-call #'list
10 (apply #'values '(44 33d0))))
(() '(10 44 33d0) :test #'equal)))
(with-test (:name :lp719585)
;; Iteration variables are always "used"
(checked-compile '(lambda () (do (var) (t))))
(checked-compile '(lambda () (do* (var) (t))))
(checked-compile '(lambda () (do-all-symbols (var))))
(checked-compile '(lambda () (do-external-symbols (var))))
(checked-compile '(lambda () (do-symbols (var))))
(checked-compile '(lambda () (dolist (var '(1 2 3))))))
(with-test (:name :key-default-type)
(let ((name (gensym)))
(proclaim `(ftype (function (double-float &key (:y double-float))) ,name))
(checked-compile-and-assert
(:optimize :default)
`(sb-int:named-lambda ,name (x &key (y x))
(values x y))
((1d0 :y nil) (condition 'error)))))
(with-test (:name :deleting-unreachable-floats)
(let ((name (gensym)))
(proclaim `(inline ,name))
(eval `(defun ,name (&key (k (eval 0f0)))
k))
(checked-compile-and-assert
(:allow-notes nil)
`(lambda ()
(,name :k 0f0))
(() 0f0))))
(with-test (:name :no-*-as-type)
(multiple-value-bind (fun errorp warnings)
(checked-compile '(lambda (x) (the * x))
:allow-failure t :allow-warnings t)
(declare (ignore fun))
(assert errorp)
(assert (= (length warnings) 1)))
;; (values t) parses into *wild-type* and has to be allowed
;; even though * which parses into *wild-type* isn't.
(checked-compile '(lambda () (the (values t) t))))
(with-test (:name :hairy-data-vector-set-t-upgrade)
(checked-compile
'(lambda (x) (sb-kernel:hairy-data-vector-set
(the (simple-array symbol) x) 1 'hey))))
(with-test (:name :ir2-convert-reffer-no-lvar)
(checked-compile-and-assert
(:allow-style-warnings t)
`(lambda (a)
(/ (unwind-protect (if a
(values nil (cdr a))
(values 1 0))
a)
1))
((nil) 1)))
(with-test (:name :%eql-integer-fold)
(checked-compile-and-assert
()
`(lambda (d)
(declare (type fixnum d))
(or (find d '(-98 27749116333474161060))
t))
((-98) -98)
((95) t)))
(with-test (:name :svref-with-addend+if-eq-immediate)
(checked-compile-and-assert
()
`(lambda (a d)
(eql (svref a d) -276932090860495638))
((#(1 0) 0) nil)
((#(-276932090860495638) 0) t)))
(with-test (:name :zeroize-stack-tns)
(checked-compile-and-assert
()
`(lambda (a b d e)
(declare (type fixnum a))
(dpb
(ash
(truncate 562949953421316 (max 97 d))
(min 81 (expt (boole boole-and e b) 2)))
(byte 7 5)
(dotimes (i 2 a)
(count i #(61) :test '>=))))
((1 2 3 4) 1985)))
(with-test (:name :logtest-derive-type-nil)
(checked-compile-and-assert
(:allow-warnings t)
`(lambda (c)
(block nil
(evenp (the integer (ignore-errors (return c))))))
((1) 1)))
(with-test (:name :cast-filter-lvar)
(checked-compile-and-assert
(:allow-warnings t)
`(lambda ()
(block nil
(equal
(the integer (tagbody
(let ((* (lambda () (go tag))))
(return))
tag))
(the integer (block nil
(return))))))
(() nil)))
;;; EXPLICIT-CHECK + ETYPECASE should not produce a error message
;;; which reveals whether type-checking on entry to a standard function
;;; was performed this way or that way.
(with-test (:name :etypecase-error-simplify)
(let ((x (nth-value 1 (ignore-errors (logcount (opaque-identity #\a)))))
(y (nth-value 1 (ignore-errors (oddp (opaque-identity #\a))))))
(assert (string= (princ-to-string x) (princ-to-string y)))))
(with-test (:name :set-exclusive-or-inlined)
(checked-compile-and-assert
()
`(lambda (set1 set2)
(declare (inline set-exclusive-or))
(set-exclusive-or set1 set2))))
(declaim (inline inline-deletion-note))
(defun inline-deletion-note (x y)
(if y
10
x))
(with-test (:name :inline-deletion-note)
(checked-compile-and-assert
(:allow-notes nil)
`(lambda (x)
(inline-deletion-note x t))
((t) 10)))
(with-test (:name :inline-type-mismatch)
(checked-compile-and-assert
(:allow-notes nil)
`(lambda (x y)
(car (inline-deletion-note x y)))
(('(a) nil) 'a))
(checked-compile-and-assert
()
`(lambda (x y)
(1+ (position x (the list y))))
((1 '(1)) 1)))
(with-test (:name :lvar-annotation-inline-type-mismatch)
(checked-compile-and-assert
()
`(lambda (x y)
(sb-kernel:the* (float :use-annotations t) (inline-deletion-note x y)))
((1.0 nil) 1.0)))
(with-test (:name :cast-type-preservation)
(assert
(equal (caddr
(sb-kernel:%simple-fun-type
(checked-compile
`(lambda (b)
(declare ((integer 1 1000) b))
(declare (optimize (space 0)))
(gcd 2 b)))))
'(values (integer 1 2) &optional))))
(with-test (:name :lvar-substituting-non-deletable-casts)
(checked-compile-and-assert
()
`(lambda (b)
(the integer
(let (*)
(rem 2
(let ((m
(flet ((f ()
(truncate (the (integer -10 0) b) -4)))
(f))))
(if (> m 1)
1
m)))))
10)
((-10) 10)))
(with-test (:name :convert-mv-bind-to-let-no-casts)
(checked-compile-and-assert
()
`(lambda (a)
(declare (type (integer 7693489 168349189459797431) a))
(max
(floor a
(min -14
(loop for lv3 below 3
sum (mod 77196223293181
(max 75 (mod a (min -57 lv3)))))))))
((8000000) -571429)))
(with-test (:name :values-length-mismatch)
(checked-compile-and-assert
(:allow-style-warnings t :optimize :default)
`(lambda (a)
(declare (values t &optional))
(when a
(values 1 2)))
((nil) nil)
((t) (condition 'type-error))))
(with-test (:name :substitute-single-use-lvar-type-cast-movement)
(checked-compile-and-assert
()
`(lambda (a)
(block nil
(let ((x (multiple-value-prog1 a)))
(when (< a 0)
(return :good))
(if (minusp x)
1
(+ x 1)))))
((-1) :good)
((0) 1)))
(with-test (:name :fold-ash-mod-0)
(checked-compile-and-assert
()
`(lambda ()
(loop for i below 3 sum
(ldb (byte 6 6)
(ash i (mask-field (byte 5 8) i)))))
(() 0)))
(with-test (:name :substitute-single-use-lvar-type-multiple-uses)
(checked-compile-and-assert
()
`(lambda (c)
(let ((z
(ceiling
(truncate 655
(min -7
(if c
-1000
3)))
3)))
z))
((t) 0)
((nil) -31)))
(with-test (:name :division-by-multiplication-type-derivation)
(assert
(type-specifiers-equal
(caddr
(sb-kernel:%simple-fun-type
(checked-compile
`(lambda (c)
(declare (optimize speed))
(ceiling
(truncate 65527
(min -78
(if c
-913097464
5)))
39)))))
'(values (or (integer -21 -21) (integer 0 0)) (integer #+(or arm64 x86-64) -21
#-(or arm64 x86-64) -38 0)
&optional)))
(assert
(type-specifiers-equal
(caddr
(sb-kernel:%simple-fun-type
(checked-compile
`(lambda (c)
(declare (optimize speed))
(ceiling
(truncate 65527
(min 78
(if c
913097464
5)))
39)))))
'(values (or (integer 22 22) (integer 337 337)) (integer -38 -1) &optional))))
(with-test (:name :boundp-ir2-optimizer)
(checked-compile-and-assert
()
`(lambda (v)
(flet ((f (s)
(when (boundp s)
(symbol-value s))))
(f v)
(f v)
v))
((t) t)))
(with-test (:name :nfp-in-unwinding)
(catch 'z
(checked-compile-and-assert
()
`(lambda (x y f)
(declare (double-float x y))
(block nil
(let ((z (+ x y)))
(unwind-protect (funcall f)
(return (+ z 1d0))))))
((4d0 1d0 (lambda () (throw 'z 1))) 6d0))))
(with-test (:name :ir1-optimize-if-same-target-type-derivation)
(checked-compile-and-assert
()
`(lambda (b c)
(declare (notinline equal))
(multiple-value-bind (v7 v2)
(if (equal 0 0)
(values c 0)
(values b 0))
(declare (ignore v2))
(tagbody (progn v7))
b))
((1 2) 1)))
(with-test (:name :delete-let-source-paths)
(checked-compile-and-assert
()
`(lambda (a)
(declare (type (member -3 -54972 3) a))
(values (floor -98740440 a)))
((-3) 32913480)
((3) -32913480)
((-54972) 1796)))
(with-test (:name :unused-debug-tns)
(checked-compile-and-assert
()
`(lambda (d)
(flet ((f (x)
(unwind-protect d
(eval x))))
(dotimes (i 3)
(f (1+ most-positive-fixnum)))))
((3) nil)))
(with-test (:name :exit-becomes-single-value)
(checked-compile-and-assert
()
`(lambda (x z)
(max
(block nil
(flet ((x () (return (floor 1020 z))))
(funcall x #'x))
nil)
10))
(((lambda (x) (funcall x)) 4) 255)))
(with-test (:name :principal-lvar-single-valuify-exit)
(checked-compile-and-assert
()
`(lambda ()
((lambda (a)
(flet ((a ()
(let ((v3 a))
(block nil (truncate (flet ((b ()
(return (block b3 (values 1 v3)))))
(declare (inline b))
(b)))))))
(declare (inline a))
(values (a))))
t))
(() 1)))
(with-test (:name :%coerce-callable-for-call-with-casts
:skipped-on (not :call-symbol))
(multiple-value-bind (calls f)
(ctu:ir1-named-calls
`(lambda (x y)
(apply x 1 2 y)))
(assert (equal (funcall f #'list '(3)) '(1 2 3)))
(assert (equal calls '(x)))))
(with-test (:name :local-fun-type-check-eliminatetion)
(let ((fun (checked-compile '(lambda ()
(flet ((f (x)
(declare (fixnum x))
(1+ x)))
(declare (inline f))
(funcall
(the (function (&optional fixnum)) #'f)
10))))))
(assert (= (sb-kernel:code-n-entries (sb-kernel:fun-code-header fun))
1))))
(with-test (:name :%cleanup-point-transform)
(checked-compile-and-assert
()
`(lambda (a b c)
(declare ((integer -14 49702337) a)
((integer -5376440588342 5921272101558) b)
((integer 3395101368955 8345185767296289) c))
(if (and (< c b) (> a b))
(progv nil
(list 288230376151711735 c)
(restart-bind nil a))
c))
((49702337 5921272101558 8345185767296289) 8345185767296289)))
;;; Test from git rev e47ffa8855d4139f88f5982fe4b82a05c3498ed3.
;;; I have absolutely zero understanding of what this was doing,
;;; but the are bunch of "undefined variable" warnings, so it can't
;;; go at toplevel in a .cload test.
(with-test (:name :bug-226)
(with-scratch-file (lisp "lisp")
(with-open-file (f lisp :direction :output)
(write '(defun bug226 ()
(declare (optimize (speed 0) (safety 3) (debug 3)))
(flet ((safe-format (stream string &rest r)
(unless (ignore-errors (progn
(apply #'format stream string r)
t))
(format stream "~&foo ~S" string))))
(cond
((eq my-result :ERROR)
(cond
((ignore-errors (typep condition result))
(safe-format t "~&bar ~S" result))
(t
(safe-format t "~&baz ~S (~A) ~S" condition condition result)))))))
:stream f :readably t))
(with-scratch-file (fasl "fasl")
(compile-file lisp :output-file fasl))))
;;; I think these tests had to be present in a COMPILE-FILE (as opposed to COMPILE)
;;; to prove that the bug was fixed.
;;; Anway it's no longer going to be allowed to have deliberately bad code in '.cload'
;;; files, because any condition of type warnings or error is considered failure
;;; of the compile step.
(with-test (:name :lp-1276282)
(with-scratch-file (lisp "lisp")
(with-open-file (f lisp :direction :output)
;; from git rev feb31fb6cfc8f89e2d75b5f2cc2ee569ac975033
(format f "(lambda () (the string (+ 1 x)))~%")
;; from git rev fbea35e879891723259dfa55589b498228390bb9
(format f
"(lambda ()
(macrolet ((x (&rest args)
(declare (ignore args))
'a))
(let (a)
(declare (type vector a))
(x #.#'list))))~%"))
(with-scratch-file (fasl "fasl")
(compile-file lisp :output-file fasl))))
(with-test (:name :substitute-single-use-lvar-mv-cast)
(checked-compile-and-assert
()
`(lambda ()
(let ((r (random 10))
(x (list 1)))
(declare (special x)
(dynamic-extent x))
(throw 'c (the (integer 0 10) r))))))
(with-test (:name :list-ir2-convert)
(checked-compile '(lambda ()
(declare (notinline list +))
(list (loop for i below 2 count t)))))
(with-test (:name :bignump-integer-<)
(checked-compile-and-assert
()
`(lambda (a)
(declare (type integer a))
(if (and (typep a 'bignum) (< a 0))
t
nil))
((-1) nil)
(((- (expt 2 300))) t)))
(with-test (:name :cmov-branch)
(checked-compile-and-assert
()
`(lambda (x y)
(assert
(let ((res nil))
(when x (setf res (not res)))
(when y (setf res (not res)))
(not res))))
((1 2) nil)
((nil nil) nil)))
(with-test (:name :constant-type-proclamation)
(ctu:file-compile
`((defconstant +foo+ 4)
(defun bar () +foo+)
(declaim (type integer +foo+)))
:load t)
(assert (eq (funcall 'bar) 4)))
(with-test (:name :if-split-let-blocks)
(checked-compile-and-assert
()
`(lambda (a e)
(labels ((f1 (b)
(map nil
(lambda (n)
(return-from f1 n))
b)
nil)
(f (n)
(let ((x (eval e))
(y (f1 n)))
(if y
y
x))))
(f a)))
((() 1) 1)
(('(2) 1) 2)))
(with-test (:name :duplicate-more-local-tn-overflow)
(let ((vars (loop repeat 200 collect (gensym)))
(args (loop repeat 201 for i from (random 30000)
collect i)))
(assert
(equal
(apply
(compile
()
`(lambda (a ,@vars)
(list a a ,@vars)))
args)
(cons (car args) args)))))
(with-test (:name :aref-single-value-type)
(checked-compile-and-assert
()
`(lambda (x)
(aref (the (values (and (not simple-array) vector)) x) 0))
(((make-array 10 :adjustable t :initial-element 3)) 3)))
(with-test (:name :restoring-tns-after-cleanups)
(checked-compile-and-assert
()
`(lambda ()
(declare (notinline values))
(unwind-protect 1
(let ((a (list 'list)))
(declare (dynamic-extent a))
(unwind-protect 1 (eval a)))
(eval 1)
(eval 2)))
(() 1)))
(defun noflush-symbol-function ()
(declare (optimize safety))
(if (functionp (symbol-function '#:notathing)) 1))
(defun flush-symbol-function ()
(if (functionp (symbol-function '#:notathing)) 1))
(with-test (:name :flush-symbol-function :skipped-on :interpreter)
(assert (ctu:find-code-constants #'noflush-symbol-function))
(assert (not (ctu:find-code-constants #'flush-symbol-function))))
(with-test (:name :symbolp-other-pointer)
(checked-compile-and-assert
()
`(lambda (x)
(declare ((or symbol bit-vector) x))
(the symbol x))
((t) t)))
(with-test (:name :non-nil-symbolp-other-pointer)
(checked-compile-and-assert
()
`(lambda (x)
(declare ((or bignum symbol) x))
(sb-kernel:non-null-symbol-p x))
((t) t)
(((1+ most-positive-fixnum)) nil)
((nil) nil)))
(with-test (:name :list-constant-coalesce)
(checked-compile-and-assert
()
`(lambda ()
(list -13303942049971317088
-6714119381493
-13303942049971317088))
(() '(-13303942049971317088 -6714119381493 -13303942049971317088) :test #'equal)))
(with-test (:name :list-constant-coalesce.2)
(checked-compile-and-assert
()
`(lambda ()
(list -3819610816126750017 -7639221632253500034))
(() '(-3819610816126750017 -7639221632253500034) :test #'equal))
(checked-compile-and-assert
()
`(lambda ()
(list -7639221632253500034 -3819610816126750017))
(() '(-7639221632253500034 -3819610816126750017) :test #'equal)))
(with-test (:name :constraint-loop)
(checked-compile-and-assert
()
`(lambda (b)
(let ((v (elt '(2444 2740 3237 8155 3296 7304 7612 2949) b)))
(progv '(*) (list (ceiling v 40))
*)))
((3) 204)))
(with-test (:name :unused-local-fun-results)
(let ((f `(lambda (x)
(flet ((x ()
(expt x x)))
(x)
(x)
10))))
(assert (not (ctu:ir1-named-calls f)))))
(with-test (:name :ir2opt-tns-without-sc)
(checked-compile-and-assert
()
`(lambda (a)
(boole boole-set (the rational a) a))
((1) -1)))
(with-test (:name set-slot-old-p-optionals)
(checked-compile-and-assert
()
`(lambda (x &key)
(let ((list (list 1)))
(setf (car list) x)
list))
((2) '(2) :test #'equal)))
(with-test (:name :tn-ref-type-ir2opt)
(checked-compile-and-assert
()
`(lambda (p)
(the unsigned-byte
(the (or (array * (1)) real) p)))
((5) 5)))
(with-test (:name :qword-to-dword-cut)
(checked-compile-and-assert
(:allow-warnings t)
`(lambda (a b)
(declare (fixnum b))
(logxor
(lognor (setq a -336272099380508247)
(shiftf b (logorc1 1073741832 a)))
(the (integer -504635362412860905 -99686857090873309) (lognand b 11))))))
(with-test (:name :not-folded-vops)
(assert
(type-specifiers-equal
(caddr
(sb-kernel:%simple-fun-type
(checked-compile
`(lambda ()
(floor
(dpb 42
(byte 15 7)
(block b
(loop for lv below 1 count
(floor
(flet ((%f (f1)
(- (floor f1 f1) (return-from b -9))))
(multiple-value-call #'%f (values (block b3 lv))))
42))))
42)))))
'(values (integer -99734 -99734) (integer 19 19) &optional))))
(with-test (:name :bit-ir2opt)
(checked-compile-and-assert
()
`(lambda (a c)
(declare (fixnum c))
(setf a -14)
(logior
(shiftf a (bit #*01 (max 0 c)))
(max 0 c)))
((1 1) -13)))
(with-test (:name :find-initial-dfo-ignore-let-converted-funs)
(checked-compile-and-assert
()
`(lambda (c)
(tagbody
(flet ((%f7 (f7-3
&optional (f7-4 (go tag5))
(f7-5 ((lambda (&rest args) (go tag5))))
(f7-6 0))
0))
((lambda (v10) (%f7 (go tag5) -63522127 v10)) c))
tag5))
((9) nil)))
(with-test (:name :find-initial-dfo-ignore-assignment-converted-funs)
(checked-compile-and-assert
()
`(lambda ()
(values
(catch 'c 0)
(labels ((%f (&optional (x 0) (y 0)) y))
(case 0
((1) (%f 0))
((2) (%f))))))
(() (values 0 nil))))
(with-test (:name :find-initial-dfo-ignore-assignment-converted-funs.2)
(checked-compile-and-assert
(:allow-style-warnings t)
`(lambda (a)
(let ((v (make-array 1 :initial-element (catch 'ct 42))))
(labels ((f (&optional (x 4) &key (k a)) x))
(if nil (f) (f a)))))
((9) 9)))
(with-test (:name :if-eq-optimizer-nil)
(checked-compile-and-assert
()
`(lambda (x)
(let (b)
(unless (eq x b)
(error ""))
x))
((nil) nil)))
(with-test (:name :assignment-convert-check-same-lvar)
(checked-compile-and-assert
(:allow-style-warnings t)
`(lambda (c)
(flet ((%f9 (f9-1 f9-2 &optional (key1 0))
f9-2))
(multiple-value-prog1 (%f9 701021570480035 c)
(if t
0
(progn
(%f9 1048572 2385880201)
(if t
(%f9 777238289903386671 -15131644893)
0))))))
((10) 10)))
(with-test (:name :range<)
(checked-compile-and-assert
()
`(lambda (l h v)
(declare (fixnum l h))
(if (< l v)
(if (> h v)
:bad
:good)
:bad))
((-1 -1 0) :good)))
(with-test (:name :range<.2)
(checked-compile-and-assert
()
`(lambda (a h)
(declare (fixnum h))
(and (>= a 0)
(not (> h a))))
((1 0) t)
((-1 0) nil)))
(with-test (:name :range<.3)
(checked-compile-and-assert
()
`(lambda (b c)
(and (or (not b) (< 0 c)) (<= c 0)))
((nil -1) t)
((t -1) nil)
((nil 1) nil)))
(with-test (:name :range<.4)
(checked-compile-and-assert
()
`(lambda (f m)
(declare (fixnum f))
(<= (truncate 10 f) m 0))
((-1 0) t)
((1 0) nil)
((-1 10) nil)))
(with-test (:name :range<-equal-bounds)
(checked-compile-and-assert
()
`(lambda (l x h)
(sb-kernel:range< l x h))
((0 0 0) nil)
((0 0.5 0) nil)
((0 -0.5 0) nil)
((0 1/2 0) nil)
((0 -1/2 0) nil))
(checked-compile-and-assert
()
`(lambda (l x h)
(sb-kernel:range<<= l x h))
((0 0 0) nil)
((0 0.5 0) nil)
((0 -0.5 0) nil)
((0 1/2 0) nil)
((0 -1/2 0) nil))
(checked-compile-and-assert
()
`(lambda (l x h)
(sb-kernel:range<=< l x h))
((0 0 0) nil)
((0 0.5 0) nil)
((0 -0.5 0) nil)
((0 1/2 0) nil)
((0 -1/2 0) nil))
(checked-compile-and-assert
()
`(lambda (l x h)
(sb-kernel:range<= l x h))
((0 0 0) t)
((0 0.5 0) nil)
((0 -0.5 0) nil)
((0 1/2 0) nil)
((0 -1/2 0) nil)))
(with-test (:name :move-from-word/fixnum-ir2opt)
(checked-compile-and-assert
()
`(lambda (c)
(declare (type (integer -10 10) c))
(let ((v5 (logior 2305843195621877482 c)))
(values v5
(abs (shiftf v5 (+ v5 1))))))
((-10) (values -2 2))))
(with-test (:name :values-list-type-check
:skipped-on (not (or :x86-64 :arm64)))
(assert (find-if (lambda (line)
(search "BOGUS-ARG-TO-VALUES-LIST-ERROR" line :test #'equal))
(ctu:disassembly-lines
(checked-compile
`(lambda (l)
(let (*)
(values-list l)))))))
(assert (not (find-if (lambda (line)
(search "BOGUS-ARG-TO-VALUES-LIST-ERROR" line :test #'equal))
(ctu:disassembly-lines
(checked-compile
`(lambda (l)
(declare (optimize (safety 0)))
(let (*)
(values-list l)))))))))
(with-test (:name :explicit-value-cell-top-level)
(ctu:file-compile
`((defvar *x*)
(let ((v 0))
(loop repeat 1
do
(setf *x* (lambda () (incf v)))))
(assert (eql (funcall *x*) 1))
(assert (eql (funcall *x*) 2)))
:load t))
(with-test (:name :load-store-two-words-reused-load-tn)
(checked-compile-and-assert
()
`(lambda (x)
(funcall x 1 2 3 4 'a t t))
(('list) '(1 2 3 4 a t t) :test #'equal)))
(with-test (:name :closures-unreachable-components)
(checked-compile-and-assert
()
`(lambda (f)
(catch 'c
(block nil
(labels ((f11 () f)
(b (&key)
(catch 'd
(lambda () #'f11))
(return #'f11)))))))))
(with-test (:name :flushable-nil-funs)
(checked-compile-and-assert
()
`(lambda (a b)
(eq (the (or) (car a))
(the (or) (car b))))))
(with-test (:name :cmov-modifying-input)
(checked-compile-and-assert
()
`(lambda (a b d)
(declare (double-float d))
(values (if (not (> d 10d0))
b
a)
a))
((1 2 1d0) (values 2 1))))
(with-test (:name :ir1-optimize-return-type-widening)
(checked-compile-and-assert
()
`(lambda (a b)
(flet ((f ()
(ceiling a b)))
(values (the integer (f)))))
((1 2) 1)))
(with-test (:name :reuse-coercion)
(multiple-value-bind (fun fail warn style notes)
(checked-compile `(lambda (x d)
(declare (double-float d)
(fixnum x)
(optimize speed))
(cond ((= x 1)
(+ d 1))
((= x 2)
(+ d 2))
((= x 3)
(+ d 3)))))
(declare (ignore fail warn style))
(assert (= (length notes) 1))
(assert (= (funcall fun 1 0d0) 1d0))
(assert (= (funcall fun 2 0d0) 2d0))
(assert (= (funcall fun 3 0d0) 3d0))
(assert (null (funcall fun 4 0d0)))))
(with-test (:name :reorder-keywordp)
(checked-compile-and-assert
()
`(lambda (a)
(cond ((stringp a)
1)
((keywordp a)
2)
((symbolp a)
3)))
(("a") 1)
((:a) 2)
(('m) 3)
((1) nil)))
(with-test (:name :reorder-same-block)
(checked-compile-and-assert
()
`(lambda (a)
(typecase a
(double-float 1)
(fixnum 2)
(bignum 3)
(t 2)))
((1d0) 1)
((1) 2)
(((1+ most-positive-fixnum)) 3)
((t) 2)))
(with-test (:name :unlink-node-in-delete-block)
(checked-compile-and-assert
()
`(lambda (b)
(tagbody
((lambda (v)
(declare (ignore v))
((lambda (a b &rest c)
a b c
(go 7))
(catch 'c 0)
(case b ((-424 -278) b) (t 0))))
((lambda () (go 7))))
7))))
(with-test (:name :multiple-call-unboxed-calls)
(checked-compile-and-assert
()
`(lambda (m j)
(declare (double-float m))
(let (*)
(if j
(funcall j)
(truncate m))))
((1d0 nil) (values 1 0d0))
((4d38 nil) (values 399999999999999990995239293824136118272 0d0)))
(checked-compile-and-assert
()
`(lambda (m j)
(declare (ratio m))
(let (*)
(if j
(funcall j)
(coerce m 'double-float))))
((1/2 nil) 0.5d0))
(checked-compile-and-assert
()
`(lambda (m j)
(declare (double-float m))
(let (*)
(if j
(funcall j)
(scale-float m 2))))
((1d0 nil) 4d0)
((2d0 nil) 8d0)))
(with-test (:name :structure-typep*-deleted-branch)
(checked-compile-and-assert
()
`(lambda (x)
(cond
((typep x 'random-state)
1)
((typep x 'hash-table)
2)
(t x)))
((*random-state*) 1)
(((make-hash-table)) 2)
((423444) 423444)))
(with-test (:name :deleted-call-type)
(checked-compile-and-assert
()
`(lambda (x)
(labels ((foo (x)
x))
(foo 1)
(when x
(unless x
(foo 3)))
(foo 2)))
(:return-type (values (integer 1 2) &optional))))
(with-test (:name :optional-type-propagation)
(checked-compile-and-assert
()
`(lambda ()
(labels ((foo (&optional x)
x))
(foo 1)
(foo 2)))
(:return-type (values (integer 1 2) &optional)))
(checked-compile-and-assert
()
`(lambda ()
(labels ((foo (&key x)
x))
(foo :x 1)
(foo :x 2)))
(:return-type (values (integer 1 2) &optional))))
(with-test (:name :local-function-declaration)
(checked-compile-and-assert
(:optimize :safe)
`(lambda (n)
(declare ((function * fixnum) n))
(typep (funcall n) 'fixnum))
((#'list) (condition 'type-error))))
(declaim (inline member-type-derivation))
(defun member-type-derivation (x)
(member x '(a b c d)))
(with-test (:name :member-type-derivation)
(checked-compile-and-assert
()
`(lambda (n)
(when (member-type-derivation n)
t))
(('a) t)
(('b) t)
(('c) t)
(('d) t)
(('e) nil)))
(with-test (:name :equal-not-null-transform)
(checked-compile-and-assert
()
`(lambda (x y)
(declare (atom x) (list y))
(equalp x y))
((nil nil) t)
((nil '(1)) nil)
((1 nil) nil))
(checked-compile-and-assert
()
`(lambda (x y)
(declare (atom x) (list y))
(equal y x))
((nil nil) t)
((nil '(1)) nil)
((1 nil) nil)))
(with-test (:name :optimize-return-deleted-lambda)
(checked-compile-and-assert
()
`(lambda (x)
(labels ((f1 ()
(case x (:star (f1))))
(f2 (d n)
(case x (:open (f1))))
(f3 (d n)
(case x
(:backquote (f4 d 0))
(:nest
(f3 d n))
(t (f2 d n))))
(f4 (d n)
(case x
(:nest (f3 d n))
(t (f2 d n))))
(f5 (d)
(case x
(:backquote (f4 d 0))
(:nest (f5 d)))))))
((1) nil)))
(with-test (:name :propagate-to-refs-hairy)
(checked-compile-and-assert
()
`(lambda (y)
(declare (fixnum y))
(let ((d (max 1 (the (satisfies eval) y))))
(the fixnum (* d 8))))
((2) 16)))
(with-test (:name :complicated-cons-function-unions)
(checked-compile-and-assert
()
`(lambda (w)
(car (member w '#.(list #'< #'= #'eql #'equalp))))
((#'=) #'=)))
(with-test (:name :tail-calls-terminated-blocks)
(prog* ((f (checked-compile `(lambda (f)
(declare (optimize (debug 1)))
(labels ((f1 (f)
(funcall f)
(f1 f)))
(f1 (f1 f))))))
(x 0))
(assert (funcall f (lambda () (when (= (incf x) 2) (return t)))))))
(with-test (:name :the*-exits)
(checked-compile-and-assert
()
`(lambda (x)
(if x
10
(block nil
(hash-table-test (return)))))
((t) 10)
((nil) nil)))
(with-test (:name :inlining-deleted-go-tag)
(checked-compile-and-assert
()
`(lambda (a)
(tagbody
(labels ((f () (go t)))
(declare (inline f))
(funcall a #'f)
(multiple-value-call #'f (values)))
t)
2)
((#'list) 2)))
(with-test (:name :inling-non-convertible-locals)
(checked-compile-and-assert
()
`(lambda (x)
(labels ((f (&key m)
(values m x)))
(declare (inline f))
(eval (f))
(f x 30)))
((:m) (values 30 :m))
((:allow-other-keys) (values nil :allow-other-keys))))
(with-test (:name :undeleted-exits)
(checked-compile-and-assert
()
`(lambda ()
(tagbody
(flet ((f (a) a (go 5)))
(print (list #'f (loop for i in (f 1)
do (print i)))))
5))
(() nil)))
(with-test (:name :unused-initial-values)
(checked-compile-and-assert
(:allow-notes nil :optimize '(:debug 2 :speed 3 :safety 1))
`(lambda (v)
(declare ((simple-array double-float (*)) v))
(loop for e across v count (> e 0)))
(((make-array 9 :element-type 'double-float :initial-element 1d0)) 9)))
(with-test (:name :consecutive-cast)
(checked-compile-and-assert
()
`(lambda (f)
(the fixnum (the integer (funcall f))))
((#'+) 0))
(checked-compile-and-assert
()
`(lambda (a)
(abs (catch 'c (the (satisfies eval) a))))
((-1) 1))
(checked-compile-and-assert
()
`(lambda (f x)
(the fixnum
(if f
(funcall f)
(the real x))))
((#'* 0) 1)
((nil 2) 2))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (x)
(the vector (the array x)))
((1) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (x)
(let ((m (the array x)))
(values (the vector m)
m)))
((1) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (c d m)
(declare (type fixnum c d m))
(the (unsigned-byte 62)
(values
(let ((v (logxor c -7322529 d 9223372036854775805)))
(if (> v 0)
(the unsigned-byte m)
(logior 80827861226 v))))))
((-3462512952 -77 0) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (x m)
(the fixnum
(if x
(let ((j (the integer m)))
j)
m)))
((nil 'a) (condition 'type-error))
((t 1d0) (condition 'type-error))
((nil 1) 1)
((t 2) 2))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (f x)
(the (values fixnum &optional) (the (values integer &rest t) (funcall f x))))
((#'identity .0) (condition 'type-error))
((#'identity 1) 1)
((#'identity (expt 2 1000)) (condition 'type-error))))
(with-test (:name :pop-values-unused)
(checked-compile-and-assert
()
`(lambda (j l r)
(declare ((function (fixnum &rest t)) j))
(apply j l r))
((#'+ 1 '(2)) 3)))
(with-test (:name :disabling-arg-count-checking)
(checked-compile-and-assert
(:optimize :safe)
`(lambda (x d)
(let ((f (lambda (x y)
(< x y))))
(funcall d f)
(sort x f)))
((nil #'funcall) (condition 'program-error))
((nil #'list) nil))
(checked-compile-and-assert
(:optimize :default)
`(lambda (x d f)
(multiple-value-bind (f key)
(if f
(values f #'car)
(values (lambda (x y)
(< x y))
#'cdr))
(funcall d f)
(sort x f :key key)))
((nil #'funcall nil) (condition 'program-error))
((nil #'list nil) nil)))
(with-test (:name :dont-rebind)
(let ((* :dont-rebind))
(checked-compile-and-assert
()
`(lambda ()
(let* ((x *)
(* x))
x))
(() :dont-rebind))))
(with-test (:name :multiple-uses-type-derivation)
(assert-type
(lambda (x a b)
(funcall (ecase x
(0 #'+)
(1 (lambda (x y) (- x y)))
(2 'logand))
a b))
number)
(assert-type
(lambda (x a b)
(let ((f (ecase x
(0 '+)
(2 'logand))))
(when a
(funcall f a b))))
(or null number)))
(with-test (:name :multiple-uses-to-fdefn)
(checked-compile-and-assert
(:optimize :safe)
`(lambda (x a b)
(let ((fun (ecase x
(0 'a)
(1 'b))))
(when a
(funcall fun a b))))
((0 nil 2) nil)
((0 1 2) (condition 'undefined-function))))
(with-test (:name :undefined-system-fun
:fails-on (and :ppc64 :big-endian))
(checked-compile-and-assert
(:optimize :safe :allow-warnings t)
`(lambda ()
#'nil)
(() (condition 'undefined-function)))
(checked-compile-and-assert
(:optimize :safe :allow-warnings t)
`(lambda ()
#'(setf *standard-output*))
(() (condition 'undefined-function)))
(checked-compile-and-assert
(:optimize :safe :allow-warnings t)
`(lambda ()
(nil))
(() (condition 'undefined-function))))
(with-test (:name :multiple-uses-type-mismatch-from-transforms)
(assert (nth-value 3
(checked-compile
`(lambda (m)
(sb-kernel:the* (fixnum :use-annotations t) (or m (make-array 10))))
:allow-style-warnings t)))
(checked-compile
`(lambda (m s)
(declare (optimize speed))
(sb-kernel:the* (fixnum :use-annotations t) (or m (position 10 (the list s))))))
(assert (nth-value 3
(checked-compile
`(lambda (m)
(the fixnum (or m (make-array 10))))
:allow-style-warnings t)))
(checked-compile
`(lambda (m s)
(declare (optimize speed))
(the fixnum (or m (position 10 (the list s)))))))
(with-test (:name :if-bypass)
(assert-type
(lambda (x)
(declare ((or null vector) x)
(optimize speed))
(if (> (length x) 10)
x
(error "m")))
vector)
(checked-compile-and-assert
()
`(lambda (a)
(evenp (if a 1 0)))
((t) nil)
((nil) t)))
(declaim (inline inline-losing-type))
(defun inline-losing-type (array)
(block nil
(cond ((typep array '(simple-array * (*)))
(return array))
(t (error "x")))))
(with-test (:name :inline-losing-type)
(checked-compile-and-assert
()
`(lambda (array)
(declare (type (or null array) array))
(aref (inline-losing-type array) 0))
((#(1)) 1)))
(with-test (:name :lvar-fun-type-specials)
(checked-compile `(lambda (y) (find t y :test *))))
(with-test (:name :notinline-with-source-transforms)
(checked-compile `(lambda (x y z)
(declare (notinline make-array))
(make-array x y z))))
(with-test (:name :setq-derive-type)
(assert-type
(lambda (x)
(declare (optimize speed))
(values (sb-kernel:%with-array-data-macro (the string x) 0 10)))
simple-string)
(assert-type
(lambda (n m)
(let ((f most-positive-single-float))
(tagbody
:next
(unless (> f n)
(go :end))
(funcall m f)
(setq f (/ f 2.0))
(go :next)
:end)
f))
single-float)
(assert-type
(lambda (l)
(let ((r 0))
(dolist (x l)
(setq r (logior r (truly-the (signed-byte 32) l))))
r))
(signed-byte 32)))
(with-test (:name :if-redundant)
(checked-compile-and-assert
()
`(lambda ()
(let* ((x nil)
(y x))
(setq x t)
(if y x)))
(() nil)))
(with-test (:name :important-result-of-a-constant)
(checked-compile `(lambda ()
(let (x)
(mapcar #'cdr (sort x #'< :key (constantly nil)))))))
(with-test (:name :values-list-stack-push)
(checked-compile-and-assert
()
`(lambda (a b)
(let ((list (if a
'(2 3)
'(1))))
(apply #'list b list)))
((t 1) '(1 2 3) :test #'equal)
((nil 1) '(1 1) :test #'equal)))
(declaim (ftype (function (integer t)) setf-on-ftype))
(with-test (:name :setf-on-ftype)
(checked-compile-and-assert
(:optimize :safe)
`(sb-int:named-lambda setf-on-ftype (x j)
(setf x j)
x)
((nil 1) (condition 'type-error))
((1 nil) nil))
(assert-type
(sb-int:named-lambda setf-on-ftype (x j)
(when j
(incf x))
x)
integer))
(with-test (:name :late-inline-return-from)
(checked-compile `(lambda (r)
((lambda ()
(block nil
(flet ((f ()
(or (funcall r)
(return))))
(declare (inline f))
(when (f)
(f)))))))
:allow-notes 'code-deletion-note))
;;; This trivial function failed to compile due to rev 88d078fe
(with-test (:name :make-list-reduce)
(checked-compile
`(lambda (&key k)
(make-list (reduce #'max (mapcar #'length k))))))
(with-test (:name :cdr-union-types)
(assert-type
(lambda (x)
(cdr (assoc x '((a . 1) (b . 2)))))
(or (eql 1) (eql 2) null))
(assert-type
(lambda (x)
(declare ((member a b) x)
(optimize speed))
(car (assoc x '((a . 1) (b . 3)))))
(member a b)))
(with-test (:name :pop-type)
(assert-type
(lambda (n)
(let ((x '(1 2 3)))
(when n
(setf x (cdr x)))
(car x)))
(or null (integer 1 3)))
(assert-type
(lambda ()
(let ((x '(1 2 3)))
(values (pop x) (pop x))))
(values (integer 1 3) (or null (integer 1 3)) &optional))
(assert-type
(lambda ()
(declare (optimize speed (debug 1)))
(destructuring-bind (a b) '(1 2)
(values a b)))
(values (integer 1 2) (or null (integer 1 2)) &optional))
(assert-type
(lambda (n)
(loop for x in '(a b c)
when (eql n x)
return x))
(member a b c nil))
(assert-type
(lambda (n)
(let ((x '(1 2 (10))))
(dolist (x x)
(when (eql x n)
(return x)))))
(or (integer 1 2) (cons (integer 10 10) null) null))
(assert-type
(lambda (n)
(declare (optimize (debug 2)))
(let ((x '(1 2 3)))
(dolist (x x)
(when (eql x n)
(return x)))))
(or (integer 1 3) null))
(assert-type
(lambda (x)
(do ((cdr '(1 2 3) (cdr cdr)))
((null cdr))
(declare (list cdr))
(let ((car (car cdr)))
(when (eq car x)
(return car)))))
(or (integer 1 3) null))
(assert-type
(lambda (j)
(declare (optimize (debug 2)))
(let ((x nil))
(labels ((f ()
(pop x)))
(when j
(f)
(f)))
x))
null)
(assert-type
(lambda (j)
(block nil
(map nil (lambda (x) (when j (return x))) '(1 2 3))
0))
(integer 0 3))
(assert-type
(lambda (j)
(block nil
(map nil (lambda (x) (when j (return (+ x 1)))) nil)
0))
(eql 0)))
(with-test (:name :test-headers-lowtag-only)
(checked-compile-and-assert
()
`(lambda (a)
(declare ((or hash-table string) a))
(typep a '(or simple-vector string)))
(("") t)
(((make-hash-table)) nil)))
(with-test (:name :&rest-escaping)
(let ((wrapper (lambda (x)
(let ((list (list -1 -2)))
(declare (dynamic-extent list))
(opaque-identity list)
(funcall x)))))
(checked-compile-and-assert
()
`(lambda (control &rest arguments)
(lambda ()
(with-standard-io-syntax
(apply #'format nil control arguments))))
(("~a~a~a" 1 2 3) "123" :test (lambda (f a)
(assert (equal (funcall wrapper (car f)) (car a)))
t)))))
(with-test (:name :&rest-escaping.recursive-reference)
(checked-compile-and-assert
()
`(lambda (control &rest arguments)
(labels ((f ()
(opaque-identity #'g)
(apply #'format nil control arguments))
(g ()
(opaque-identity #'f #'f)))
(declare (dynamic-extent #'g #'f))
(opaque-identity #'g)
(opaque-identity #'f)
(f)))
(("~a~a~a" 1 2 3) "123")))
(with-test (:name :car-eq-if-listp)
(let ((f (compile nil '(lambda (x) (typep x '(cons (eql t)))))))
(assert (eq (funcall f '(t)) t))
(assert (eq (funcall f '(1)) nil))))
(with-test (:name :apply-list-if)
(let ((f (compile nil '(lambda (p) (apply #'list (if p '(a b) '(c d)))))))
(assert (equal (funcall f t) '(a b)))
(assert (equal (funcall f nil) '(c d)))))
(with-test (:name :values-list-if)
(let ((f (compile nil '(lambda (p) (values-list (if p '(a) ()))))))
(multiple-value-call (lambda (x) (assert (eql x 'a))) (funcall f t))
(multiple-value-call (lambda () t) (funcall f nil))))
(with-test (:name :no-notes-list-vs-or-null)
(checked-compile `(lambda (l)
(declare (list l)
(optimize speed))
(coerce l 'vector))
:allow-notes nil))
(with-test (:name :flushable-combination-args-p-lost-annotation)
(checked-compile-and-assert
()
`(lambda (b)
(declare (vector b))
(let ((j))
(find 1 b :key (lambda (x)
(setf j x)))
j))
((#(2)) 2)))
(with-test (:name :constant-fold-variables)
(assert-type
(lambda ()
(declare (optimize (debug 2)))
(let ((x #(a b)))
(aref x 0)))
(eql a)))
(with-test (:name :funcall-externally-checkable-type)
(checked-compile-and-assert
(:optimize :safe)
`(lambda (n m)
(funcall (the (function ((signed-byte 33)) t)
(if m
(lambda (x) x)
(lambda (x) (1+ x))))
n))
(('a t) (condition 'type-error))
(((expt 2 33) nil) (condition 'type-error))
((1 t) 1)
((2 nil) 3))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (n f)
(funcall (the (function ((signed-byte 33)) t)
f)
n))
(('a #'-) (condition 'type-error))
((1 #'-) -1))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (n)
(funcall (the (function ((signed-byte 33)) t)
#'opaque-identity)
n))
(("a") (condition 'type-error))
((2) 2))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (n j)
(funcall (the (function ((signed-byte 33)) (values symbol &optional))
(lambda (x) (when (evenp x)
j)))
n))
((2 'a) 'a)
((2 1) (condition 'type-error))))
(with-test (:name :cast-move-exit)
(checked-compile-and-assert
(:optimize :safe)
`(lambda (m f)
(+ m (catch t (funcall f) 0)))
((1 #'list) 1)
((1 (lambda () (throw t 1))) 2)
((1 (lambda () (throw t t))) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (f)
(the number (catch t (funcall f) 2)))
((#'list) 2)
(((lambda () (throw t 3))) 3)
(((lambda () (throw t t))) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (f)
(the number (values (catch t (funcall f) 2))))
((#'list) 2)
(((lambda () (throw t 3))) 3)
(((lambda () (throw t t))) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (f)
(values (the number (catch t (funcall f) 2))))
((#'list) 2)
(((lambda () (throw t 3))) 3)
(((lambda () (throw t t))) (condition 'type-error))))
(with-test (:name :apply-type-derivation)
(assert-type
(lambda (r)
(apply #'concatenate 'vector r))
simple-vector)
(assert-type
(lambda (a r)
(declare ((array double-float) a))
(apply #'aref a r))
double-float)
(assert-type
(lambda (r)
(apply #'make-array 1 :element-type t r))
(vector t)))
(with-test (:name :foldable-read-only)
(assert-type
(lambda ()
(let ((l (list 1)))
(values (car l)
(car l))))
(values (eql 1) (eql 1) &optional)))
(with-test (:name :>-integer-fixnum)
(checked-compile-and-assert
(:optimize :safe)
`(lambda (v1 m)
(declare (single-float v1)
(integer m))
(if (> (+ v1 4) 0.9)
(>
-7
(+
(if (> v1 7)
#c(4.0 3.0)
2)
m))
(* -0.2 v1)))
((8.0 8) (condition 'type-error))
((-8.0 8) 1.6)))
(with-test (:name :unused-tns-erased-types)
(checked-compile-and-assert
(:optimize :safe :allow-warnings t)
'(lambda (x)
(declare ((integer 10 20) x))
(let ((q (truncate (/ x 0))))
(when (minusp x)
q)))
((10) (condition 'division-by-zero))))
(with-test (:name :constant-fold-call-multiple-uses-casts)
(checked-compile-and-assert
(:optimize :safe
:allow-warnings t)
`(lambda (v)
(if v
(truncate
(if v
#c(1 2)
2)
(if v
9
2))))
((t) (condition 'type-error))
((nil) nil)))
(with-test (:name :cast-externally-checkable-p-vop-ref)
(checked-compile-and-assert
(:optimize :safe)
`(lambda (v3)
(let ((v (the integer v3)))
(values (logand 1 v)
v)))
((t) (condition 'type-error))
((3) (values 1 3)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (p n)
(declare ((or float (rational 6357799611333445141)) n))
(let ((v (if p
9
(the integer n))))
(values (logand v 9) v)))
((t 1.0) (values 9 9))
((nil 1.0) (condition 'type-error))))
(with-test (:name :un/signed-byte-64-p-move-to-word)
(checked-compile-and-assert
()
`(lambda (x n m)
(declare (integer x n))
(prog ()
sb64
(when (typep x '(signed-byte 64))
(return (logand x 2)))
ub64
(when (typep x '(unsigned-byte 64))
(return (logand x 1)))
(when m
(setf x n
m nil)
(go ub64))))
(((expt 2 64) -1 t) nil)
(((expt 2 64) 3 t) 1)))
(with-test (:name :test-header-lowtag-null)
(checked-compile-and-assert
(:optimize :safe)
`(lambda (x)
(declare ((or bignum null) x))
(logand x 3))
(((+ (expt 2 64) 2)) 2)
((nil) (condition 'type-error))))
(with-test (:name :unwind-protect-mv-bind)
(checked-compile-and-assert
()
`(lambda (m)
(let (n)
(values
(nth-value 1
(unwind-protect
1
(setf n m)))
n)))
((2) (values nil 2)))
(checked-compile-and-assert
()
`(lambda (m)
(nth-value 1
(block nil
(values (unwind-protect t
(return m))))))
((2) nil)))
(with-test (:name :nth-value-the)
(checked-compile-and-assert
(:optimize :safe)
`(lambda (f)
(nth-value 1 (the fixnum (funcall f))))
(((lambda () 1)) nil)
(((lambda () (values 1 2))) 2)
(((lambda () (values t 2))) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (f)
(values (the (values fixnum fixnum) (funcall f))))
(((lambda () 1)) (condition 'type-error))
(((lambda () (values 1 2))) 1)
(((lambda () (values 2 t))) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (f)
(values (the (values fixnum &optional fixnum) (funcall f))))
(((lambda () 1)) 1)
(((lambda () (values 1 2))) 1)
(((lambda () (values 2 t))) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (f)
(values (the real (the (not single-float) (funcall f)))))
(((lambda () 1)) 1)
(((lambda () (values 1 2))) 1)
(((lambda () nil)) (condition 'type-error))
(((lambda () 1.0)) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe)
`(lambda (f)
(the (values number number) (funcall f)))
(((lambda () 1)) (condition 'type-error))
(((lambda () (values 1 2))) (values 1 2))
(((lambda () (values nil 2))) (condition 'type-error))
(((lambda () (values 1 nil))) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe
:allow-style-warnings t)
`(lambda (f)
(the (values real boolean) (if f (values 1 1))))
((t) (condition 'type-error))
((nil) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe :allow-style-warnings t)
`(lambda (f)
(the (values &optional real)
(the (values &optional complex)
(funcall f))))
(((lambda () (values))) (values))
(((lambda () 1)) (condition 'type-error))
(((lambda () #c(1 2))) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe :allow-warnings t)
`(lambda ()
(the (values &optional real) nil))
(() (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe :allow-warnings t)
`(lambda ()
(the (values real (not real)) (floor 1 1)))
(() (condition 'type-error)))
(checked-compile-and-assert
(:optimize :safe :allow-warnings t)
`(lambda ()
(the (values fixnum &optional)
(block nil (floor 2))))
(() (condition 'type-error))))
(with-test (:name :unwrap-predicates-block)
(checked-compile-and-assert
()
`(lambda (v)
(if (block nil (> v 7))
t))
((8) t)
((0) nil)))
(with-test (:name :deleted-node-in-derive-type)
(checked-compile
`(lambda (a)
(declare ((simple-array nil (9)) a))
(setf (aref a 0) 1)
a)))
(with-test (:name :xep-type-derivation)
(assert-type
(lambda (n)
(funcall (if n
(lambda (a) (+ a 2))
(lambda (a) (+ a 1)))
1))
(integer 2 3)))
(with-test (:name :compile-name-correct)
(let ((gensym (gensym)))
(assert (eq (sb-kernel:%fun-name
(symbol-function
(checked-compile
`(lambda (a)
(declare ((simple-array nil (9)) a))
(setf (aref a 0) 1)
a)
:name gensym)))
gensym))))
(declaim (ftype function self-call))
(with-test (:name :compile-self-call-policy.1)
(let ((fun (symbol-function
(checked-compile
`(lambda (a)
(declare (optimize (sb-c::recognize-self-calls 0)))
(if (zerop a)
2
(self-call (1- a))))
:name 'self-call))))
(assert (member 'self-call (ctu:find-named-callees fun)))))
(with-test (:name :compile-self-call-policy.2)
(let ((fun (symbol-function
(checked-compile
`(lambda (a)
(declare (optimize sb-c::recognize-self-calls))
(if (zerop a)
2
(self-call (1- a))))
:name 'self-call))))
(assert (not (member 'self-call (ctu:find-named-callees fun))))))
(with-test (:name :mv-bind-unused-p-multiple-args)
(checked-compile-and-assert
()
`(lambda (x y)
(multiple-value-call #'values t -1 (floor x y)))
((5 3) (values t -1 1 2)))
(checked-compile-and-assert
()
`(lambda (x y)
(multiple-value-call (lambda (a b c d)
(values a b c d)) -1 t (floor x y)))
((3 5) (values -1 t 0 3)))
(checked-compile-and-assert
()
`(lambda (x y)
(multiple-value-call (lambda (a b c d)
(declare (ignore a b))
(values c d)) -1 t (floor x y)))
((3 5) (values 0 3)))
(assert (equal (ctu:ir1-named-calls `(lambda (x y)
(multiple-value-call (lambda (a b c d)
(declare (ignore d))
(values a b c)) -1 t (floor x y))))
'(sb-kernel::floor1))))
(with-test (:name :reusing-inlined-function)
(checked-compile-and-assert
(:optimize '(:safety 1 :debug 3 :space 0))
`(lambda (b)
(values (elt '(1 2) b)
(elt '(3 4) b)))
((0) (values 1 3))
((1) (values 2 4))))
(with-test (:name :annotations-traveling-type-conflicts)
(checked-compile
`(lambda (x)
(let ((g (sb-kernel:the* (symbol :use-annotations t) x)))
(unless (typep g 'symbol)
g)))))
#+sb-devel ;; no sb-c::ir1-attributep
(with-test (:name :unfoldable-functions)
(let (no-folders)
(do-all-symbols (symbol)
(unless (or (equal (package-name (symbol-package symbol))
"SB-BIGNUM")
(eq symbol 'sb-kernel:complex-vector-p))
(loop for name in (list symbol `(setf ,symbol))
do
(let ((info (sb-int:info :function :info name)))
(when (and info
(sb-c::ir1-attributep (sb-c::fun-info-attributes info) sb-c::foldable)
(not (sb-c::fun-info-folder info))
(sb-c::fun-info-templates info))
(unless (fboundp name)
(push name no-folders)))))))
(assert (not no-folders))))
(declaim (ftype (function (&key (:a float)) t) ftype-test-unused-key)
(ftype (function (t &key (:a float)) t) ftype-test-unused-key2)
(ftype (function (&optional float) t) ftype-test-unused-opt)
(ftype (function (&optional float float) t) ftype-test-unused-opt2)
(ftype (function (t &optional float float) t) ftype-test-unused-opt3))
(defun ftype-test-unused-key (&key a)
(declare (ignore a)))
(defun ftype-test-unused-key2 (x &key a)
(declare (ignore x a)))
(defun ftype-test-unused-opt (&optional a)
(declare (ignore a)))
(defun ftype-test-unused-opt2 (&optional a b)
(declare (ignore a b)))
(defun ftype-test-unused-opt3 (x &optional a b)
(declare (ignore x a b)))
(with-test (:name :ftype-unused-optional)
(checked-compile-and-assert
(:optimize :default)
`(lambda () (ftype-test-unused-opt))
(() nil))
(checked-compile-and-assert
(:optimize :default)
`(lambda () (ftype-test-unused-key))
(() nil))
(checked-compile-and-assert
(:optimize :default)
`(lambda () (ftype-test-unused-opt2))
(() nil))
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-opt2 a))
((0.0) nil))
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-opt3 a))
((0.0) nil))
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-opt3 1 a))
((0.0) nil))
(checked-compile-and-assert
(:optimize :default)
`(lambda () (ftype-test-unused-key2 1))
(() nil))
#-interpreter
(progn
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-opt a))
((1) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-key :a a))
((1) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-key2 1 :a a))
((1) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-opt2 a))
((1) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-opt2 a))
((1) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-opt2 0.0 a))
((1) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-opt3 1 a))
((1) (condition 'type-error)))
(checked-compile-and-assert
(:optimize :default)
`(lambda (a) (ftype-test-unused-opt3 1 0.0 a))
((1) (condition 'type-error)))))