+\f
+;;; bug 120a: Turned out to be constraining code looking like (if foo
+;;; <X> <X>) where <X> was optimized by the compiler to be the exact
+;;; same block in both cases, but not turned into (PROGN FOO <X>).
+;;; Fixed by APD in sbcl-0.7.7.2, who provided this test:
+(declaim (inline dont-constrain-if-too-much))
+(defun dont-constrain-if-too-much (frame up-frame)
+ (declare (optimize (speed 3) (safety 1) (debug 1)))
+ (if (or (not frame) t)
+ frame
+ "bar"))
+(defun dont-constrain-if-too-much-aux (x y)
+ (declare (optimize (speed 3) (safety 1) (debug 1)))
+ (if x t (if y t (dont-constrain-if-too-much x y))))
+
+(assert (null (dont-constrain-if-too-much-aux nil nil)))
+
+;;; TYPE-ERROR confusion ca. sbcl-0.7.7.24, reported and fixed by
+;;; APD sbcl-devel 2002-09-14
+(defun exercise-0-7-7-24-bug (x)
+ (declare (integer x))
+ (let (y)
+ (setf y (the single-float (if (> x 0) x 3f0)))
+ (list y y)))
+(multiple-value-bind (v e) (ignore-errors (exercise-0-7-7-24-bug 4))
+ (assert (null v))
+ (assert (typep e 'type-error)))
+(assert (equal (exercise-0-7-7-24-bug -4) '(3f0 3f0)))
+
+;;; non-intersecting type declarations were DWIMing in a confusing
+;;; fashion until sbcl-0.7.7.28, when APD reported and fixed the
+;;; problem.
+(defun non-intersecting-the (x)
+ (let (y)
+ (setf y (the single-float (the integer x)))
+ (list y y)))
+
+(raises-error? (foo 3) type-error)
+(raises-error? (foo 3f0) type-error)
+
+;;; until 0.8.2 SBCL did not check THEs in arguments
+(defun the-in-arguments-aux (x)
+ x)
+(defun the-in-arguments-1 (x)
+ (list x (the-in-arguments-aux (the (single-float 0s0) x))))
+(defun the-in-arguments-2 (x)
+ (list x (the-in-arguments-aux (the single-float x))))
+
+(multiple-value-bind (result condition)
+ (ignore-errors (the-in-arguments-1 1))
+ (assert (null result))
+ (assert (typep condition 'type-error)))
+(multiple-value-bind (result condition)
+ (ignore-errors (the-in-arguments-2 1))
+ (assert (null result))
+ (assert (typep condition 'type-error)))
+
+;;; bug 153: a hole in a structure slot type checking
+(declaim (optimize safety))
+(defstruct foo153
+ (bla 0 :type fixnum))
+(defun bug153-1 ()
+ (let ((foo (make-foo153)))
+ (setf (foo153-bla foo) '(1 . 1))
+ (format t "Is ~a of type ~a a cons? => ~a~%"
+ (foo153-bla foo)
+ (type-of (foo153-bla foo))
+ (consp (foo153-bla foo)))))
+(defun bug153-2 (x)
+ (let ((foo (make-foo153)))
+ (setf (foo153-bla foo) x)
+ (format t "Is ~a of type ~a a cons? => ~a~%"
+ (foo153-bla foo)
+ (type-of (foo153-bla foo))
+ (consp (foo153-bla foo)))))
+
+(multiple-value-bind (result condition)
+ (ignore-errors (bug153-1))
+ (declare (ignore result))
+ (assert (typep condition 'type-error)))
+(multiple-value-bind (result condition)
+ (ignore-errors (bug153-2 '(1 . 1)))
+ (declare (ignore result))
+ (assert (typep condition 'type-error)))
+
+;;;; bug 110: the compiler flushed the argument type test and the default
+;;;; case in the cond.
+;
+;(locally (declare (optimize (safety 3) (speed 2)))
+; (defun bug110 (x)
+; (declare (optimize (safety 2) (speed 3)))
+; (declare (type (or string stream) x))
+; (cond ((typep x 'string) 'string)
+; ((typep x 'stream) 'stream)
+; (t
+; 'none))))
+;
+;(multiple-value-bind (result condition)
+; (ignore-errors (bug110 0))
+; (declare (ignore result))
+; (assert (typep condition 'type-error)))
+
+;;; bug 202: the compiler failed to compile a function, which derived
+;;; type contradicted declared.
+(declaim (ftype (function () null) bug202))
+(defun bug202 ()
+ t)
+
+;;; bugs 178, 199: compiler failed to compile a call of a function
+;;; with a hairy type
+(defun bug178 (x)
+ (funcall (the function (the standard-object x))))
+
+(defun bug199-aux (f)
+ (eq nil (funcall f)))
+
+(defun bug199 (f x)
+ (declare (type (and function (satisfies bug199-aux)) f))
+ (funcall f x))
+
+;;; check non-toplevel DEFMACRO
+(defvar *defmacro-test-status* nil)
+
+(defun defmacro-test ()
+ (fmakunbound 'defmacro-test-aux)
+ (let* ((src "defmacro-test.lisp")
+ (obj (compile-file-pathname src)))
+ (unwind-protect
+ (progn
+ (compile-file src)
+ (assert (equal *defmacro-test-status* '(function a)))
+ (setq *defmacro-test-status* nil)
+ (load obj)
+ (assert (equal *defmacro-test-status* nil))
+ (macroexpand '(defmacro-test-aux 'a))
+ (assert (equal *defmacro-test-status* '(macro 'a z-value)))
+ (eval '(defmacro-test-aux 'a))
+ (assert (equal *defmacro-test-status* '(expanded 'a z-value))))
+ (ignore-errors (delete-file obj)))))
+
+(defmacro-test)
+
+;;; bug 204: EVAL-WHEN inside a local environment
+(defvar *bug204-test-status*)
+
+(defun bug204-test ()
+ (let* ((src "bug204-test.lisp")
+ (obj (compile-file-pathname src)))
+ (unwind-protect
+ (progn
+ (setq *bug204-test-status* nil)
+ (compile-file src)
+ (assert (equal *bug204-test-status* '((:expanded :load-toplevel)
+ (:called :compile-toplevel)
+ (:expanded :compile-toplevel))))
+ (setq *bug204-test-status* nil)
+ (load obj)
+ (assert (equal *bug204-test-status* '((:called :load-toplevel)))))
+ (ignore-errors (delete-file obj)))))
+
+(bug204-test)
+
+;;; toplevel SYMBOL-MACROLET
+(defvar *symbol-macrolet-test-status*)
+
+(defun symbol-macrolet-test ()
+ (let* ((src "symbol-macrolet-test.lisp")
+ (obj (compile-file-pathname src)))
+ (unwind-protect
+ (progn
+ (setq *symbol-macrolet-test-status* nil)
+ (compile-file src)
+ (assert (equal *symbol-macrolet-test-status*
+ '(2 1)))
+ (setq *symbol-macrolet-test-status* nil)
+ (load obj)
+ (assert (equal *symbol-macrolet-test-status* '(2))))
+ (ignore-errors (delete-file obj)))))
+
+(symbol-macrolet-test)
+
+;;; On the x86, this code failed to compile until sbcl-0.7.8.37:
+(defun x86-assembler-failure (x)
+ (declare (optimize (speed 3) (safety 0)))
+ (eq (setf (car x) 'a) nil))
+
+;;; bug 211: :ALLOW-OTHER-KEYS
+(defun bug211d (&key (x :x x-p) ((:allow-other-keys y) :y y-p))
+ (list x x-p y y-p))
+
+(assert (equal (bug211d) '(:x nil :y nil)))
+(assert (equal (bug211d :x 1) '(1 t :y nil)))
+(assert (raises-error? (bug211d :y 2) program-error))
+(assert (equal (bug211d :y 2 :allow-other-keys t :allow-other-keys nil)
+ '(:x nil t t)))
+(assert (raises-error? (bug211d :y 2 :allow-other-keys nil) program-error))
+
+(let ((failure-p
+ (nth-value
+ 3
+ (compile 'bug211b
+ '(lambda ()
+ (flet ((test (&key (x :x x-p) ((:allow-other-keys y) :y y-p))
+ (list x x-p y y-p)))
+ (assert (equal (test) '(:x nil :y nil)))
+ (assert (equal (test :x 1) '(1 t :y nil)))
+ (assert (equal (test :y 2 :allow-other-keys 11 :allow-other-keys nil)
+ '(:x nil 11 t)))))))))
+ (assert (not failure-p))
+ (bug211b))
+
+(let ((failure-p
+ (nth-value
+ 3
+ (compile 'bug211c
+ '(lambda ()
+ (flet ((test (&key (x :x x-p))
+ (list x x-p)))
+ (assert (equal (test) '(:x nil)))
+ (assert (equal (test :x 1) '(1 t)))
+ (assert (equal (test :y 2 :allow-other-keys 11 :allow-other-keys nil)
+ '(:x nil)))))))))
+ (assert (not failure-p))
+ (bug211c))
+
+(dolist (form '((test :y 2)
+ (test :y 2 :allow-other-keys nil)
+ (test :y 2 :allow-other-keys nil :allow-other-keys t)))
+ (multiple-value-bind (result warnings-p failure-p)
+ (compile nil `(lambda ()
+ (flet ((test (&key (x :x x-p) ((:allow-other-keys y) :y y-p))
+ (list x x-p y y-p)))
+ ,form)))
+ (assert failure-p)
+ (assert (raises-error? (funcall result) program-error))))
+
+;;; bug 217: wrong type inference
+(defun bug217-1 (x s)
+ (let ((f (etypecase x
+ (character #'write-char)
+ (integer #'write-byte))))
+ (funcall f x s)
+ (etypecase x
+ (character (write-char x s))
+ (integer (write-byte x s)))))
+(bug217-1 #\1 *standard-output*)
+
+
+;;; bug 221: tried and died on CSUBTYPEP (not VALUES-SUBTYPEP) of the
+;;; function return types when inferring the type of the IF expression
+(declaim (ftype (function (fixnum) (values package boolean)) bug221f1))
+(declaim (ftype (function (t) (values package boolean)) bug221f2))
+(defun bug221 (b x)
+ (funcall (if b #'bug221f1 #'bug221f2) x))
+\f
+;;; bug 172: macro lambda lists were too permissive until 0.7.9.28
+;;; (fix provided by Matthew Danish) on sbcl-devel
+(assert (null (ignore-errors
+ (defmacro bug172 (&rest rest foo) `(list ,rest ,foo)))))
+
+;;; embedded THEs
+(defun check-embedded-thes (policy1 policy2 x y)
+ (handler-case
+ (funcall (compile nil
+ `(lambda (f)
+ (declare (optimize (speed 2) (safety ,policy1)))
+ (multiple-value-list
+ (the (values (integer 2 3) t &optional)
+ (locally (declare (optimize (safety ,policy2)))
+ (the (values t (single-float 2f0 3f0) &optional)
+ (funcall f)))))))
+ (lambda () (values x y)))
+ (type-error (error)
+ error)))
+
+(assert (equal (check-embedded-thes 0 0 :a :b) '(:a :b)))
+
+(assert (equal (check-embedded-thes 0 3 :a 2.5f0) '(:a 2.5f0)))
+(assert (typep (check-embedded-thes 0 3 2 3.5f0) 'type-error))
+
+(assert (equal (check-embedded-thes 0 1 :a 3.5f0) '(:a 3.5f0)))
+(assert (typep (check-embedded-thes 0 1 2 2.5d0) 'type-error))
+
+(assert (equal (check-embedded-thes 3 0 2 :a) '(2 :a)))
+(assert (typep (check-embedded-thes 3 0 4 2.5f0) 'type-error))
+
+(assert (equal (check-embedded-thes 1 0 3 :b) '(3 :b)))
+(assert (typep (check-embedded-thes 1 0 1.0 2.5f0) 'type-error))
+
+
+(assert (equal (check-embedded-thes 3 3 2 2.5f0) '(2 2.5f0)))
+(assert (typep (check-embedded-thes 3 3 0 2.5f0) 'type-error))
+(assert (typep (check-embedded-thes 3 3 2 3.5f0) 'type-error))
+\f
+;;; INLINE inside MACROLET
+(declaim (inline to-be-inlined))
+(macrolet ((def (x) `(defun ,x (y) (+ y 1))))
+ (def to-be-inlined))
+(defun call-inlined (z)
+ (to-be-inlined z))
+(assert (= (call-inlined 3) 4))
+(macrolet ((frob (x) `(+ ,x 3)))
+ (defun to-be-inlined (y)
+ (frob y)))
+(assert (= (call-inlined 3)
+ ;; we should have inlined the previous definition, so the
+ ;; new one won't show up yet.
+ 4))
+(defun call-inlined (z)
+ (to-be-inlined z))
+(assert (= (call-inlined 3) 6))
+(defun to-be-inlined (y)
+ (+ y 5))
+(assert (= (call-inlined 3) 6))
+\f
+;;; DEFINE-COMPILER-MACRO to work as expected, not via weird magical
+;;; IR1 pseudo-:COMPILE-TOPLEVEL handling
+(defvar *bug219-a-expanded-p* nil)
+(defun bug219-a (x)
+ (+ x 1))
+(define-compiler-macro bug219-a (&whole form y)
+ (setf *bug219-a-expanded-p* t)
+ (if (constantp y)
+ (+ (eval y) 2)
+ form))
+(defun bug219-a-aux ()
+ (bug219-a 2))
+(assert (= (bug219-a-aux)
+ (if *bug219-a-expanded-p* 4 3)))
+(defvar *bug219-a-temp* 3)
+(assert (= (bug219-a *bug219-a-temp*) 4))
+
+(defvar *bug219-b-expanded-p* nil)
+(defun bug219-b-aux1 (x)
+ (when x
+ (define-compiler-macro bug219-b (y)
+ (setf *bug219-b-expanded-p* t)
+ `(+ ,y 2))))
+(defun bug219-b-aux2 (z)
+ (bug219-b z))
+(assert (not *bug219-b-expanded-p*))
+(assert (raises-error? (bug219-b-aux2 1) undefined-function))
+(bug219-b-aux1 t)
+(defun bug219-b-aux2 (z)
+ (bug219-b z))
+(defun bug219-b (x)
+ x)
+(assert (= (bug219-b-aux2 1)
+ (if *bug219-b-expanded-p* 3 1)))
+
+;;; bug 224: failure in unreachable code deletion
+(defmacro do-optimizations (&body body)
+ `(dotimes (.speed. 4)
+ (dotimes (.space. 4)
+ (dotimes (.debug. 4)
+ (dotimes (.compilation-speed. 4)
+ (proclaim `(optimize (speed , .speed.) (space , .space.)
+ (debug , .debug.)
+ (compilation-speed , .compilation-speed.)))
+ ,@body)))))
+
+(do-optimizations
+ (compile nil
+ (read-from-string
+ "(lambda () (#:localy (declare (optimize (safety 3)))
+ (ignore-errors (progn (values-list (car (list '(1 . 2)))) t))))")))
+
+(do-optimizations
+ (compile nil '(lambda ()
+ (labels ((ext ()
+ (tagbody
+ (labels ((i1 () (list (i2) (i2)))
+ (i2 () (list (int) (i1)))
+ (int () (go :exit)))
+ (list (i1) (i1) (i1)))
+ :exit (return-from ext)
+ )))
+ (list (error "nih") (ext) (ext))))))
+
+(do-optimizations
+ (compile nil '(lambda (x) (let ((y (error ""))) (list x y)))))
+
+;;; bug 223: invalid moving of global function name referencing
+(defun bug223-int (n)
+ `(int ,n))
+
+(defun bug223-wrap ()
+ (let ((old #'bug223-int))
+ (setf (fdefinition 'bug223-int)
+ (lambda (n)
+ (assert (> n 0))
+ `(ext ,@(funcall old (1- n)))))))
+(compile 'bug223-wrap)
+
+(assert (equal (bug223-int 4) '(int 4)))
+(bug223-wrap)
+(assert (equal (bug223-int 4) '(ext int 3)))
+(bug223-wrap)
+(assert (equal (bug223-int 4) '(ext ext int 2)))
+\f
+;;; COERCE got its own DEFOPTIMIZER which has to reimplement most of
+;;; SPECIFIER-TYPE-NTH-ARG. For a while, an illegal type would throw
+;;; you into the debugger on compilation.
+(defun coerce-defopt1 (x)
+ ;; illegal, but should be compilable.
+ (coerce x '(values t)))
+(defun coerce-defopt2 (x)
+ ;; illegal, but should be compilable.
+ (coerce x '(values t &optional)))
+(assert (null (ignore-errors (coerce-defopt1 3))))
+(assert (null (ignore-errors (coerce-defopt2 3))))
+\f
+;;; Oops. In part of the (CATCH ..) implementation of DEBUG-RETURN,
+;;; it was possible to confuse the type deriver of the compiler
+;;; sufficiently that compiler invariants were broken (explained by
+;;; APD sbcl-devel 2003-01-11).
+
+;;; WHN's original report
+(defun debug-return-catch-break1 ()
+ (with-open-file (s "/tmp/foo"
+ :direction :output
+ :element-type (list
+ 'signed-byte
+ (1+
+ (integer-length most-positive-fixnum))))
+ (read-byte s)
+ (read-byte s)
+ (read-byte s)
+ (read-byte s)))
+
+;;; APD's simplified test case
+(defun debug-return-catch-break2 (x)
+ (declare (type (vector (unsigned-byte 8)) x))
+ (setq *y* (the (unsigned-byte 8) (aref x 4))))
+\f
+;;; FUNCTION-LAMBDA-EXPRESSION should return something that's COMPILE
+;;; can understand. Here's a simple test for that on a function
+;;; that's likely to return a hairier list than just a lambda:
+(macrolet ((def (fn) `(progn
+ (declaim (inline ,fn))
+ (defun ,fn (x) (1+ x)))))
+ (def bug228))
+(let ((x (function-lambda-expression #'bug228)))
+ (when x
+ (assert (= (funcall (compile nil x) 1) 2))))
+
+;;;
+(defun bug192b (i)
+ (dotimes (j i)
+ (declare (type (mod 4) i))
+ (unless (< i 5)
+ (print j))))
+(assert (raises-error? (bug192b 6) type-error))
+
+(defun bug192c (x y)
+ (locally (declare (type fixnum x y))
+ (+ x (* 2 y))))
+(assert (raises-error? (bug192c 1.1 2) type-error))
+
+(assert (raises-error? (progn (the real (list 1)) t) type-error))
+
+(defun bug236 (a f)
+ (declare (optimize (speed 2) (safety 0)))
+ (+ 1d0
+ (the double-float
+ (multiple-value-prog1
+ (svref a 0)
+ (unless f (return-from bug236 0))))))
+(assert (eql (bug236 #(4) nil) 0))
+
+;;; Bug reported by reported by rif on c.l.l 2003-03-05
+(defun test-type-of-special-1 (x)
+ (declare (special x)
+ (fixnum x)
+ (optimize (safety 3)))
+ (list x))
+(defun test-type-of-special-2 (x)
+ (declare (special x)
+ (fixnum x)
+ (optimize (safety 3)))
+ (list x (setq x (/ x 2)) x))
+(assert (raises-error? (test-type-of-special-1 3/2) type-error))
+(assert (raises-error? (test-type-of-special-2 3) type-error))
+(assert (equal (test-type-of-special-2 8) '(8 4 4)))
+
+;;; bug which existed in 0.8alpha.0.4 for several milliseconds before
+;;; APD fixed it in 0.8alpha.0.5
+(defun frob8alpha04 (x y)
+ (+ x y))
+(defun baz8alpha04 (this kids)
+ (flet ((n-i (&rest rest)
+ ;; Removing the #+NIL here makes the bug go away.
+ #+nil (format t "~&in N-I REST=~S~%" rest)
+ (apply #'frob8alpha04 this rest)))
+ (n-i kids)))
+;;; failed in 0.8alpha.0.4 with "The value 13 is not of type LIST."
+(assert (= (baz8alpha04 12 13) 25))
+
+;;; evaluation order in structure slot writers
+(defstruct sswo
+ a b)
+(let* ((i 0)
+ (s (make-sswo :a (incf i) :b (incf i)))
+ (l (list s :v)))
+ (assert (= (sswo-a s) 1))
+ (assert (= (sswo-b s) 2))
+ (setf (sswo-a (pop l)) (pop l))
+ (assert (eq l nil))
+ (assert (eq (sswo-a s) :v)))
+
+(defun bug249 (x)
+ (flet ((bar (y)
+ (declare (fixnum y))
+ (incf x)))
+ (list (bar x) (bar x) (bar x))))
+
+(assert (raises-error? (bug249 1.0) type-error))
+
+;;; bug reported by ohler on #lisp 2003-07-10
+(defun bug-ohler-2003-07-10 (a b)
+ (declare (optimize (speed 0) (safety 3) (space 0)
+ (debug 1) (compilation-speed 0)))
+ (adjoin a b))
+
+;;; bug reported by Doug McNaught on sbcl-devel 2003-09-14:
+;;; COMPILE-FILE did not bind *READTABLE*
+(let* ((source "bug-doug-mcnaught-20030914.lisp")
+ (fasl (compile-file-pathname source)))
+ (labels ((check ()
+ (assert (null (get-macro-character #\]))))
+ (full-check ()
+ (check)
+ (assert (typep *bug-doug-mcnaught-20030914*
+ '(simple-array (unsigned-byte 4) (*))))
+ (assert (equalp *bug-doug-mcnaught-20030914* #(1 2 3)))
+ (makunbound '*bug-doug-mcnaught-20030914*)))
+ (compile-file source)
+ (check)
+ (load fasl)
+ (full-check)
+ (load source)
+ (full-check)
+ (delete-file fasl)))
+\f
+(defun expt-derive-type-bug (a b)
+ (unless (< a b)
+ (truncate (expt a b))))
+(assert (equal (multiple-value-list (expt-derive-type-bug 1 1))
+ '(1 0)))
+
+;;; Problems with type checking in functions with EXPLICIT-CHECK
+;;; attribute (reported by Peter Graves)
+(loop for (fun . args) in '((= a) (/= a)
+ (< a) (<= a) (> a) (>= a))
+ do (assert (raises-error? (apply fun args) type-error)))
+
+(defclass broken-input-stream (sb-gray:fundamental-input-stream) ())
+(defmethod sb-gray:stream-read-char ((stream broken-input-stream))
+ (throw 'break :broken))
+(assert (eql (block return
+ (handler-case
+ (catch 'break
+ (funcall (eval ''peek-char)
+ 1 (make-instance 'broken-input-stream))
+ :test-broken)
+ (type-error (c)
+ (return-from return :good))))
+ :good))
+\f
+;;;; MUFFLE-CONDITIONS test (corresponds to the test in the manual)
+(defvar *compiler-note-count* 0)
+#-(or alpha x86-64) ; FIXME: make a better test!
+(handler-bind ((sb-ext:compiler-note (lambda (c)
+ (declare (ignore c))
+ (incf *compiler-note-count*))))
+ (let ((fun
+ (compile nil
+ '(lambda (x)
+ (declare (optimize speed) (fixnum x))
+ (declare (sb-ext:muffle-conditions sb-ext:compiler-note))
+ (values (* x 5) ; no compiler note from this
+ (locally
+ (declare (sb-ext:unmuffle-conditions sb-ext:compiler-note))
+ ;; this one gives a compiler note
+ (* x -5)))))))
+ (assert (= *compiler-note-count* 1))
+ (assert (equal (multiple-value-list (funcall fun 1)) '(5 -5)))))
+\f
+(handler-case
+ (eval '(flet ((%f (&key) nil)) (%f nil nil)))
+ (error (c) :good)
+ (:no-error (val) (error "no error: ~S" val)))
+(handler-case
+ (eval '(labels ((%f (&key x) x)) (%f nil nil)))
+ (error (c) :good)
+ (:no-error (val) (error "no error: ~S" val)))
+
+;;; PROGV must not bind constants, or violate declared types -- ditto for SET.
+(assert (raises-error? (set pi 3)))
+(assert (raises-error? (progv '(pi s) '(3 pi) (symbol-value x))))
+(declaim (cons *special-cons*))
+(assert (raises-error? (set '*special-cons* "nope") type-error))
+(assert (raises-error? (progv '(*special-cons*) '("no hope") (car *special-cons*)) type-error))
+
+;;; No bogus warnings for calls to functions with complex lambda-lists.
+(defun complex-function-signature (&optional x &rest y &key z1 z2)
+ (cons x y))
+(with-test (:name :complex-call-doesnt-warn)
+ (handler-bind ((warning #'error))
+ (compile nil '(lambda (x) (complex-function-signature x :z1 1 :z2 2)))))
+
+(with-test (:name :non-required-args-update-info)
+ (let ((name (gensym "NON-REQUIRE-ARGS-TEST"))
+ (*evaluator-mode* :compile))
+ (eval `(defun ,name (x) x))
+ (assert (equal '(function (t) (values t &optional))
+ (sb-kernel:type-specifier (sb-int:info :function :type name))))
+ (eval `(defun ,name (x &optional y) (or x y)))
+ (assert (equal '(function (t &optional t) (values t &optional))
+ (sb-kernel:type-specifier (sb-int:info :function :type name))))))
+
+;;;; inline & maybe inline nested calls
+
+(defun quux-marker (x) x)
+(declaim (inline foo-inline))
+(defun foo-inline (x) (quux-marker x))
+(declaim (maybe-inline foo-maybe-inline))
+(defun foo-maybe-inline (x) (quux-marker x))
+;; Pretty horrible, but does the job
+(defun count-full-calls (name function)
+ (let ((code (with-output-to-string (s)
+ (disassemble function :stream s)))
+ (n 0))
+ (with-input-from-string (s code)
+ (loop for line = (read-line s nil nil)
+ while line
+ when (search name line)
+ do (incf n)))
+ n))
+
+(with-test (:name :nested-inline-calls)
+ (let ((fun (compile nil `(lambda (x)
+ (foo-inline (foo-inline (foo-inline x)))))))
+ (assert (= 0 (count-full-calls "FOO-INLINE" fun)))
+ (assert (= 3 (count-full-calls "QUUX-MARKER" fun)))))
+
+(with-test (:name :nested-maybe-inline-calls)
+ (let ((fun (compile nil `(lambda (x)
+ (declare (optimize (space 0)))
+ (foo-maybe-inline (foo-maybe-inline (foo-maybe-inline x)))))))
+ (assert (= 0 (count-full-calls "FOO-MAYBE-INLINE" fun)))
+ (assert (= 1 (count-full-calls "QUUX-MARKER" fun)))))
+
+(with-test (:name :inline-calls)
+ (let ((fun (compile nil `(lambda (x)
+ (list (foo-inline x)
+ (foo-inline x)
+ (foo-inline x))))))
+ (assert (= 0 (count-full-calls "FOO-INLINE" fun)))
+ (assert (= 3 (count-full-calls "QUUX-MARKER" fun)))))
+
+(with-test (:name :maybe-inline-calls)
+ (let ((fun (compile nil `(lambda (x)
+ (declare (optimize (space 0)))
+ (list (foo-maybe-inline x)
+ (foo-maybe-inline x)
+ (foo-maybe-inline x))))))
+ (assert (= 0 (count-full-calls "FOO-MAYBE-INLINE" fun)))
+ (assert (= 1 (count-full-calls "QUUX-MARKER" fun)))))
+
+(defun file-compile (toplevel-forms &key load)
+ (let* ((lisp "compile-impure-tmp.lisp")
+ (fasl (compile-file-pathname lisp)))
+ (unwind-protect
+ (progn
+ (with-open-file (f lisp :direction :output)
+ (dolist (form toplevel-forms)
+ (prin1 form f)))
+ (multiple-value-bind (fasl warn fail) (compile-file lisp)
+ (when load
+ (load fasl))
+ (values warn fail)))
+ (ignore-errors (delete-file lisp))
+ (ignore-errors (delete-file fasl)))))
+
+(with-test (:name :bug-405)
+ ;; These used to break with a TYPE-ERROR
+ ;; The value NIL is not of type SB-C::PHYSENV.
+ ;; in MERGE-LETS.
+ (file-compile
+ '((LET (outer-let-var)
+ (lambda ()
+ (print outer-let-var)
+ (MULTIPLE-VALUE-CALL 'some-function
+ (MULTIPLE-VALUE-CALL (LAMBDA (a) 'foo)
+ 1))))))
+ (file-compile
+ '((declaim (optimize (debug 3)))
+ (defstruct bug-405-foo bar)
+ (let ()
+ (flet ((i (x) (frob x (bug-405-foo-bar foo))))
+ (i :five))))))
+
+;;; bug 235a
+(declaim (ftype (function (cons) number) bug-235a-aux))
+(declaim (inline bug-235a-aux))
+(defun bug-235a-aux (c)
+ (the number (car c)))
+(with-test (:name :bug-235a)
+ (let ((fun (compile nil
+ `(lambda (x y)
+ (values (locally (declare (optimize (safety 0)))
+ (bug-235a-aux x))
+ (locally (declare (optimize (safety 3)))
+ (bug-235a-aux y)))))))
+ (assert
+ (eq :error
+ (handler-case
+ (funcall fun '(:one) '(:two))
+ (type-error (e)
+ (assert (eq :two (type-error-datum e)))
+ (assert (eq 'number (type-error-expected-type e)))
+ :error))))))
+
+(with-test (:name :compiled-debug-funs-leak)
+ (sb-ext:gc :full t)
+ (let ((usage-before (sb-kernel::dynamic-usage)))
+ (dotimes (x 10000)
+ (let ((f (compile nil '(lambda ()
+ (error "X")))))
+ (handler-case
+ (funcall f)
+ (error () nil))))
+ (sb-ext:gc :full t)
+ (let ((usage-after (sb-kernel::dynamic-usage)))
+ (when (< (+ usage-before 2000000) usage-after)
+ (error "Leak")))))
+
+;;; PROGV compilation and type checking when the declared type
+;;; includes a FUNCTION subtype.
+(declaim (type (or (function (t) (values boolean &optional)) string)
+ *hairy-progv-var*))
+(defvar *hairy-progv-var* #'null)
+(with-test (:name :hairy-progv-type-checking)
+ (assert (eq :error
+ (handler-case
+ (progv '(*hairy-progv-var*) (list (eval 42))
+ *hairy-progv-var*)
+ (type-error () :error))))
+ (assert (equal "GOOD!"
+ (progv '(*hairy-progv-var*) (list (eval "GOOD!"))
+ *hairy-progv-var*))))
+
+(with-test (:name :fill-complex-single-float)
+ (assert (every (lambda (x) (eql x #c(-1.0 -2.0)))
+ (funcall
+ (lambda ()
+ (make-array 2
+ :element-type '(complex single-float)
+ :initial-element #c(-1.0 -2.0)))))))
+
+(with-test (:name :make-array-symbol-as-initial-element)
+ (assert (every (lambda (x) (eq x 'a))
+ (funcall
+ (compile nil
+ `(lambda ()
+ (make-array 12 :initial-element 'a)))))))
+
+;;; This non-minimal test-case catches a nasty error when loading
+;;; inline constants.
+(deftype matrix ()
+ `(simple-array single-float (16)))
+(declaim (ftype (sb-int:sfunction (single-float single-float single-float single-float
+ single-float single-float single-float single-float
+ single-float single-float single-float single-float
+ single-float single-float single-float single-float)
+ matrix)
+ matrix)
+ (inline matrix))
+(defun matrix (m11 m12 m13 m14
+ m21 m22 m23 m24
+ m31 m32 m33 m34
+ m41 m42 m43 m44)
+ (make-array 16
+ :element-type 'single-float
+ :initial-contents (list m11 m21 m31 m41
+ m12 m22 m32 m42
+ m13 m23 m33 m43
+ m14 m24 m34 m44)))
+(declaim (ftype (sb-int:sfunction ((simple-array single-float (3)) single-float) matrix)
+ rotate-around))
+(defun rotate-around (a radians)
+ (let ((c (cos radians))
+ (s (sin radians))
+ ;; The 1.0 here was misloaded on x86-64.
+ (g (- 1.0 (cos radians))))
+ (let* ((x (aref a 0))
+ (y (aref a 1))
+ (z (aref a 2))
+ (gxx (* g x x)) (gxy (* g x y)) (gxz (* g x z))
+ (gyy (* g y y)) (gyz (* g y z)) (gzz (* g z z)))
+ (matrix
+ (+ gxx c) (- gxy (* s z)) (+ gxz (* s y)) 0.0
+ (+ gxy (* s z)) (+ gyy c) (- gyz (* s x)) 0.0
+ (- gxz (* s y)) (+ gyz (* s x)) (+ gzz c) 0.0
+ 0.0 0.0 0.0 1.0))))
+(with-test (:name :regression-1.0.29.54)
+ (assert (every #'=
+ '(-1.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 1.0)
+ (rotate-around
+ (make-array 3 :element-type 'single-float) (coerce pi 'single-float))))
+ ;; Same bug manifests in COMPLEX-ATANH as well.
+ (assert (= (atanh #C(-0.7d0 1.1d0)) #C(-0.28715567731069275d0 0.9394245539093365d0))))
+
+(with-test (:name :slot-value-on-structure)
+ (let ((f (compile nil `(lambda (x a b)
+ (declare (something-known-to-be-a-struct x))
+ (setf (slot-value x 'x) a
+ (slot-value x 'y) b)
+ (list (slot-value x 'x)
+ (slot-value x 'y))))))
+ (assert (equal '(#\x #\y)
+ (funcall f
+ (make-something-known-to-be-a-struct :x "X" :y "Y")
+ #\x #\y)))
+ (assert (not (ctu:find-named-callees f)))))
+
+(defclass some-slot-thing ()
+ ((slot :initarg :slot)))
+(with-test (:name :with-slots-the)
+ (let ((x (make-instance 'some-slot-thing :slot "foo")))
+ (with-slots (slot) (the some-slot-thing x)
+ (assert (equal "foo" slot)))))
+
+;;; Missing &REST type in proclamation causing a miscompile.
+(declaim (ftype
+ (function
+ (sequence unsigned-byte
+ &key (:initial-element t) (:initial-contents sequence))
+ (values sequence &optional))
+ bug-458354))
+(defun bug-458354
+ (sequence length
+ &rest keys
+ &key (initial-element nil iep) (initial-contents nil icp))
+ (declare (sb-ext:unmuffle-conditions style-warning))
+ (declare (ignorable keys initial-element iep initial-contents icp))
+ (apply #'sb-sequence:make-sequence-like sequence length keys))
+(with-test (:name :bug-458354)
+ (assert (equalp #((a b) (a b)) (bug-458354 #(1 2) 2 :initial-element '(a b)))))
+
+(with-test (:name :bug-542807)
+ (handler-bind ((style-warning #'error))
+ (eval '(defstruct bug-542807 slot)))
+ (let (conds)
+ (handler-bind ((style-warning (lambda (c)
+ (push c conds))))
+ (eval '(defstruct bug-542807 slot)))
+ (assert (= 1 (length conds)))
+ (assert (typep (car conds) 'sb-kernel::redefinition-with-defun))))