~ chicken-core (chicken-5) a9d3a22e16c0ab5b888cf72301dedc8c20f1c201


commit a9d3a22e16c0ab5b888cf72301dedc8c20f1c201
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Thu Apr 7 03:23:02 2011 -0400
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Thu Apr 7 03:23:02 2011 -0400

    predicate-specialization match fixes and tests

diff --git a/csc.scm b/csc.scm
index fd91fa98..f64d5bcf 100644
--- a/csc.scm
+++ b/csc.scm
@@ -353,7 +353,6 @@ Usage: #{csc} FILENAME | OPTION ...
                                     file
     -S  -scrutinize                perform local flow analysis
     -types FILENAME                load additional type database
-    -strict-types                  assume variable do not change their type
 
   Optimization options:
 
@@ -386,6 +385,7 @@ Usage: #{csc} FILENAME | OPTION ...
     -no-procedure-checks-for-toplevel-bindings
                                    disable procedure call checks for toplevel
                                     bindings
+    -strict-types                  assume variable do not change their type
 
   Configuration options:
 
diff --git a/distribution/manifest b/distribution/manifest
index 9636cce3..25b80b51 100644
--- a/distribution/manifest
+++ b/distribution/manifest
@@ -136,6 +136,7 @@ tests/test-finalizers.scm
 tests/test-finalizers-2.scm
 tests/module-tests-compiled.scm
 tests/scrutiny-tests.scm
+tests/scrutiny-tests-2.scm
 tests/scrutiny.expected
 tests/syntax-rule-stress-test.scm
 tests/syntax-tests.scm
diff --git a/manual/Using the compiler b/manual/Using the compiler
index ea782275..bed7bd1b 100644
--- a/manual/Using the compiler	
+++ b/manual/Using the compiler	
@@ -187,6 +187,8 @@ the source text should be read from standard input.
 
 ; -static-extension NAME : similar to {{-require-extension NAME}}, but links extension statically (also applies for an explicit {{(require-extension NAME)}}).
 
+; -strict-types : Assume that the type of variables does not change during their lifetime. This gives more type-information during specialization, but violating this assumption will result in unsafe and incorrectly behaving code.
+
 ; -types FILENAME : load additional type database from {{FILENAME}}. Type-definitions in {{FILENAME}} will override previous type-definitions.
 
 ; -compile-syntax : Makes macros also available at run-time. By default macros are not available at run-time.
diff --git a/scrutinizer.scm b/scrutinizer.scm
index f918d174..51baf162 100755
--- a/scrutinizer.scm
+++ b/scrutinizer.scm
@@ -514,52 +514,53 @@
 		 (pname) i (car atypes) (car args)))))
 	  (let ((r (procedure-result-types ptype values-rest (cdr args))))
 	    (d  "  result-types: ~a" r)
-	    (when specialize
-	      ;;XXX we should check whether this is a standard- or extended binding
-	      (let ((pn (procedure-name ptype))
-		    (op #f))
-		(when pn
-		  (cond ((and (fx= 1 nargs) 
-			      (variable-mark pn '##compiler#predicate)) =>
-			      (lambda (pt)
-				(cond ((match-specialization (list pt) (cdr args))
-				       (report
-					loc
-					(sprintf 
-					    "~athe predicate is called with an argument of type `~a' and will always return true"
-					  (pname) pt))
+	    ;;XXX we should check whether this is a standard- or extended binding
+	    (let ((pn (procedure-name ptype))
+		  (op #f))
+	      (when pn
+		(cond ((and (fx= 1 nargs) 
+			    (variable-mark pn '##compiler#predicate)) =>
+			    (lambda (pt)
+			      (cond ((match-specialization (list pt) (cdr args))
+				     (report
+				      loc
+				      (sprintf 
+					  "~athe predicate is called with an argument of type `~a' and will always return true"
+					(pname) pt))
+				     (when specialize
 				       (specialize-node!
 					node
 					`(let ((#:tmp #(1))) '#t))
-				       (set! op (list pn pt)))
-				      ((match-specialization (list `(not ,pt)) (cdr args))
-				       (report
-					loc
-					(sprintf 
-					    "~athe predicate is called with an argument of type `~a' and will always return false"
-					  (pname) (cadr args)))
+				       (set! op (list pn pt))))
+				    ((match-specialization (list `(not ,pt)) (cdr args))
+				     (report
+				      loc
+				      (sprintf 
+					  "~athe predicate is called with an argument of type `~a' and will always return false"
+					(pname) (cadr args)))
+				     (when specialize
 				       (specialize-node!
 					node
 					`(let ((#:tmp #(1))) '#f))
-				       (set! op (list pt `(not ,pt)))))))
-			((variable-mark pn '##compiler#specializations) =>
-			 (lambda (specs)
-			   (for-each
-			    (lambda (spec)
-			      (when (match-specialization (car spec) (cdr args))
-				(set! op (cons pn (car spec)))
-				(specialize-node! node (cadr spec))))
-			    specs))))
-		  (when op
-		    (cond ((assoc op specialization-statistics) =>
-			   (lambda (a) (set-cdr! a (add1 (cdr a)))))
-			  (else
-			   (set! specialization-statistics
-			     (cons (cons op 1) 
-				   specialization-statistics))))))
-		(when (and (not op) (procedure-type? ptype))
-		  (set-car! (node-parameters node) #t)
-		  (set! safe-calls (add1 safe-calls)))))
+				       (set! op (list pt `(not ,pt))))))))
+		      ((and specialize (variable-mark pn '##compiler#specializations)) =>
+		       (lambda (specs)
+			 (for-each
+			  (lambda (spec)
+			    (when (match-specialization (car spec) (cdr args))
+			      (set! op (cons pn (car spec)))
+			      (specialize-node! node (cadr spec))))
+			  specs))))
+		(when op
+		  (cond ((assoc op specialization-statistics) =>
+			 (lambda (a) (set-cdr! a (add1 (cdr a)))))
+			(else
+			 (set! specialization-statistics
+			   (cons (cons op 1) 
+				 specialization-statistics))))))
+	      (when (and specialize (not op) (procedure-type? ptype))
+		(set-car! (node-parameters node) #t)
+		(set! safe-calls (add1 safe-calls))))
 	    r))))
     (define (procedure-type? t)
       (or (eq? 'procedure t)
@@ -862,8 +863,12 @@
 	     (else (equal? st t))))
 	  (else (equal? st t))))
   (define (matchnot st t)
-    (cond ((eq? 'list t) (matchnot st '(or null pair)))
+    (cond ((eq? st t) #f)
+	  ((eq? 'list t) (matchnot st '(or null pair)))
+	  ((eq? 'number t) (matchnot st '(or fixnum float)))
 	  ((eq? '* t) #f)
+	  ((eq? 'list st) (not (match t '(or null pair))))
+	  ((eq? 'number st) (not (match t '(or fixnum float))))
 	  ((pair? t)
 	   (case (car t)
 	     ((or) (every (cut matchnot st <>) (cdr t)))
diff --git a/support.scm b/support.scm
index e9d20e86..d3d8e2f3 100644
--- a/support.scm
+++ b/support.scm
@@ -1535,7 +1535,6 @@ Usage: chicken FILENAME OPTION ...
     -no-lambda-info              omit additional procedure-information
     -scrutinize                  perform local flow analysis for static checks
     -types FILENAME              load additional type database
-    -strict-types                assume variable do not change their type
     -emit-type-file FILENAME     write type-declaration information into file
 
   Optimization options:
@@ -1567,6 +1566,7 @@ Usage: chicken FILENAME OPTION ...
     -no-procedure-checks-for-toplevel-bindings
                                    disable procedure call checks for toplevel
                                     bindings
+    -strict-types                assume variable do not change their type
 
   Configuration options:
 
diff --git a/tests/runtests.sh b/tests/runtests.sh
index 42c7d8b4..7d971c7b 100644
--- a/tests/runtests.sh
+++ b/tests/runtests.sh
@@ -79,6 +79,9 @@ fi
 
 diff -bu scrutiny.out scrutiny.expected
 
+$compile scrutiny-tests-2.scm -scrutinize -analyze-only -ignore-repository -types ../types.db
+./a.out
+
 echo "======================================== specialization tests ..."
 rm -f foo.types foo.import.*
 $compile specialization-test-1.scm -emit-type-file foo.types -specialize \
diff --git a/tests/scrutiny-tests-2.scm b/tests/scrutiny-tests-2.scm
new file mode 100644
index 00000000..986c303b
--- /dev/null
+++ b/tests/scrutiny-tests-2.scm
@@ -0,0 +1,27 @@
+;;;; scrutiny-tests-2.scm
+
+
+(define-syntax predicate
+  (syntax-rules ()
+    ((_ pred (proto ...) (nonproto ...))
+     (begin
+       (assert (pred proto)) ...
+       (assert (not (pred nonproto))) ...))))
+
+
+;;;
+
+(let ((p '(1 . 2))
+      (l (list))
+      (n '())
+      (i 123)
+      (f 12.3)
+      (u (+ i f)))
+  (predicate pair? (p) (l n i f))
+  (predicate list? (l) (p n i f))
+  (predicate null? (n) (p l i f))
+  (predicate fixnum? (i) (f u))
+  (predicate exact? (i) (f u))
+  (predicate flonum? (f) (i u))
+  (predicate inexact? (f) (i u))
+  (predicate number? (i f u) (n)))
diff --git a/types.db b/types.db
index d73a3c04..c3f34c90 100644
--- a/types.db
+++ b/types.db
@@ -580,8 +580,8 @@
 (fixnum-bits fixnum)
 (fixnum-precision fixnum)
 
-(fixnum? (procedure fixnum? (*) boolean)
-	 ((fixnum) (let ((#:tmp #(1))) '#t)))
+(fixnum? (procedure fixnum? (*) boolean))
+(predicate fixnum? fixnum)
 
 (flonum-decimal-precision fixnum)
 (flonum-epsilon float)
@@ -593,8 +593,8 @@
 (flonum-print-precision (procedure! (#!optional fixnum) fixnum))
 (flonum-radix fixnum)
 
-(flonum? (procedure flonum? (*) boolean)
-	 ((float) (let ((#:tmp #(1))) '#t)))
+(flonum? (procedure flonum? (*) boolean))
+(predicate flonum? float)
 
 (flush-output (procedure! flush-output (#!optional port) undefined))
 (force-finalizers (procedure force-finalizers () undefined))
Trap