X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=tests%2Fcompiler.impure.lisp;h=f94e582ec1f0cf82e8fafa4444d052953419f8f6;hb=5ce77b3465434e396aa2d7670138a7e7741f3dae;hp=72013e8fdae6cf76eb0eb9683d82f3772cb3dda9;hpb=fb91e1987cc40f3f698f2972d0de50426ec3086f;p=sbcl.git diff --git a/tests/compiler.impure.lisp b/tests/compiler.impure.lisp index 72013e8..f94e582 100644 --- a/tests/compiler.impure.lisp +++ b/tests/compiler.impure.lisp @@ -15,9 +15,8 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(cl:in-package :cl-user) - (load "assertoid.lisp") +(use-package "ASSERTOID") ;;; Old CMU CL code assumed that the names of "keyword" arguments are ;;; necessarily self-evaluating symbols, but ANSI Common Lisp allows @@ -289,16 +288,22 @@ ;;; bug 194, fixed in part by APD "more strict type checking" patch ;;; (sbcl-devel 2002-08-07) (progn - #+nil ; FIXME: still broken in 0.7.7.19 (after patch) (multiple-value-bind (result error) (ignore-errors (multiple-value-prog1 (progn (the real '(1 2 3))))) (assert (null result)) (assert (typep error 'type-error))) - #+nil ; FIXME: still broken in 0.7.7.19 (after patch) (multiple-value-bind (result error) (ignore-errors (the real '(1 2 3))) (assert (null result)) (assert (typep error 'type-error)))) + +(defun bug194d () + (null (ignore-errors + (let ((arg1 1) + (arg2 (identity (the real #(1 2 3))))) + (if (< arg1 arg2) arg1 arg2))))) +(assert (eq (bug194d) t)) + ;;; BUG 48a. and b. (symbol-macrolet handling), fixed by Eric Marsden ;;; and Raymond Toy for CMUCL, fix ported for sbcl-0.7.6.18. @@ -313,13 +318,10 @@ *standard-input*))) (assert failure-p) (assert (raises-error? (funcall function) program-error))) -#|| -BUG 48c, not yet fixed: (multiple-value-bind (function warnings-p failure-p) (compile nil '(lambda () (symbol-macrolet ((s nil)) (declare (special s)) s))) (assert failure-p) (assert (raises-error? (funcall function) program-error))) -||# ;;; bug 120a: Turned out to be constraining code looking like (if foo ;;; ) where was optimized by the compiler to be the exact @@ -336,6 +338,586 @@ BUG 48c, not yet fixed: (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)) + +;;; 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 4 :b) '(4 :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)) + +;;; 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)) + +;;; 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))) + +;;; 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)))) + +;;; 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)))) + +;;; 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))) + +(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)) + +;;;; MUFFLE-CONDITIONS test (corresponds to the test in the manual) +(defvar *compiler-note-count* 0) +#-alpha ; 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))))) + +(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))) ;;;; tests not in the problem domain, but of the consistency of the ;;;; compiler machinery itself