Hi,

I've found a few numbers-related problems in the types database.
The finite?, exact? and inexact? procedures were marked as being pure
predicates accepting any type of input. They were also rewritten to C
functions that always return a boolean value, but all three raise a
type error in the interpreter when called with non-number values.
Of course, that results in an annoying inconsistency between compiled
code and interpreted code (where the latter gives an error while the
former does not).

The patch adds a few more tests (and moves the assert-fail definition
to the top so that they can be added at the most logical place)

Unfortunately, this gets rid of the warning messages when you pass
a number that's already known to be exact or inexact to exact?/inexact?,
but I think that's not too big a loss.

Some notes/questions:

- Maybe the C functions C_inexactp and such should be the ones that raise
  the exception, rather than the Scheme code?  I don't know where else
  they are used or what's most consistent/clean.
- The rewrites in c-platform.scm seem kind of redundant with the rewrites
   done by the scrutinizer and possibly wrong for these cases too, so
   another potential hiding place for many bugs.
  Now that we have the scrutinizer I think they can probably be removed
  altogether without loss of performance in compiled code.  This should
  also result in faster compilation times since the rewriting code seems
  rather complicated too (and it's hard to understand, so getting rid of
  it is probably a good idea maintenance-wise too).
  I'm just not sure whether all functionality is truly duplicated in
  types.db.  Of course if we remove it, this should wait until after
  4.8.0 is released.
- I noticed that with -O4, the following code passes cleanly:

    (define-syntax assert-fail
      (syntax-rules ()
        ((_ exp) (assert (handle-exceptions ex #t exp #f)))))
    (assert (exact? 1))
    (assert (not (exact? 1)))
    (assert-fail (exact? 1))

  Could someone explain how this is possible?  -debug o didn't
  really help, nor did ripping the rewrites from c-platform.scm

Cheers,
Peter
-- 
http://sjamaan.ath.cx
--
"The process of preparing programs for a digital computer
 is especially attractive, not only because it can be economically
 and scientifically rewarding, but also because it can be an aesthetic
 experience much like composing poetry or music."
                                                        -- Donald Knuth
>From 277b36970385aedeb40555d46ef0f5513e7448a7 Mon Sep 17 00:00:00 2001
From: Peter Bex <peter....@xs4all.nl>
Date: Sat, 21 Apr 2012 00:13:49 +0200
Subject: [PATCH] Two types.db fixes:

- finite?, exact? and inexact? raise an error on non-numbers.  They are not 
pure predicates and shouldn't be rewritten to "pure" C functions.
- The "base" (aka "radix") argument for string->number and number->string can 
only be a fixnum.
---
 tests/library-tests.scm   |   17 +++++++++++++----
 tests/scrutiny-2.expected |   16 ----------------
 types.db                  |   16 ++++++++++------
 3 files changed, 23 insertions(+), 26 deletions(-)

diff --git a/tests/library-tests.scm b/tests/library-tests.scm
index 1268bd4..fab5f00 100644
--- a/tests/library-tests.scm
+++ b/tests/library-tests.scm
@@ -2,6 +2,10 @@
 
 (use srfi-1 extras)
 
+(define-syntax assert-fail
+  (syntax-rules ()
+    ((_ exp)
+     (assert (handle-exceptions ex #t exp #f)))))
 
 ;; numbers
 
@@ -20,6 +24,7 @@
 (assert (= 1.0 (round 0.6)))
 (assert (rational? 1))
 (assert (finite? 1))
+(assert-fail (finite? 'foo))
 (assert (rational? 1.0))
 (assert (finite? 1.0))
 (assert (not (rational? +inf.0)))
@@ -40,10 +45,14 @@
 (assert (not (integer? "foo")))
 ; XXX number missing
 
-(define-syntax assert-fail
-  (syntax-rules ()
-    ((_ exp)
-     (assert (handle-exceptions ex #t exp #f)))))
+(assert (exact? 1))
+(assert (not (exact? 1.0)))
+(assert (not (exact? 1.1)))
+(assert-fail (exact? 'foo))
+(assert (not (inexact? 1)))
+(assert (inexact? 1.0))
+(assert (inexact? 1.1))
+(assert-fail (inexact? 'foo))
 
 (assert-fail (/ 1 1 0))
 (assert-fail (/ 1 1 0.0))
diff --git a/tests/scrutiny-2.expected b/tests/scrutiny-2.expected
index 4bea4df..1985dac 100644
--- a/tests/scrutiny-2.expected
+++ b/tests/scrutiny-2.expected
@@ -60,14 +60,6 @@ Note: at toplevel:
   `float' and will always return false
 
 Note: at toplevel:
-  (scrutiny-tests-2.scm:24) in procedure call to `exact?', the predicate is 
called with an argument of type
-  `fixnum' and will always return true
-
-Note: at toplevel:
-  (scrutiny-tests-2.scm:24) in procedure call to `exact?', the predicate is 
called with an argument of type
-  `float' and will always return false
-
-Note: at toplevel:
   (scrutiny-tests-2.scm:25) in procedure call to `flonum?', the predicate is 
called with an argument of type
   `float' and will always return true
 
@@ -76,14 +68,6 @@ Note: at toplevel:
   `fixnum' and will always return false
 
 Note: at toplevel:
-  (scrutiny-tests-2.scm:26) in procedure call to `inexact?', the predicate is 
called with an argument of type
-  `float' and will always return true
-
-Note: at toplevel:
-  (scrutiny-tests-2.scm:26) in procedure call to `inexact?', the predicate is 
called with an argument of type
-  `fixnum' and will always return false
-
-Note: at toplevel:
   (scrutiny-tests-2.scm:27) in procedure call to `number?', the predicate is 
called with an argument of type
   `fixnum' and will always return true
 
diff --git a/types.db b/types.db
index 7aed56f..61a3dd1 100644
--- a/types.db
+++ b/types.db
@@ -218,10 +218,14 @@
          ((fixnum) (let ((#(tmp) #(1))) '#t))
          ((float) (##core#inline "C_u_i_fpintegerp" #(1))))
 
-(exact? (#(procedure #:pure #:predicate fixnum) exact? (*) boolean))
 (real? (#(procedure #:pure #:predicate number) real? (*) boolean))
 (complex? (#(procedure #:pure #:predicate number) complex? (*) boolean))
-(inexact? (#(procedure #:pure #:predicate float) inexact? (*) boolean))
+(exact? (#(procedure #:clean #:enforce) exact? (number) boolean)
+        ((fixnum) (let ((#(tmp) #(1))) '#t))
+        ((float) (let ((#(tmp) #(1))) '#f)))
+(inexact? (#(procedure #:clean #:enforce) inexact? (number) boolean)
+          ((fixnum) (let ((#(tmp) #(1))) '#f))
+          ((float) (let ((#(tmp) #(1))) '#t)))
 
 ;;XXX predicate?
 (rational? (#(procedure #:pure) rational? (*) boolean)
@@ -474,10 +478,10 @@
                               #(2)))
       ((float float) (##core#inline_allocate ("C_a_i_flonum_atan2" 4) #(1) 
#(2))))
 
-(number->string (#(procedure #:clean #:enforce) number->string (number 
#!optional number) string)
+(number->string (#(procedure #:clean #:enforce) number->string (number 
#!optional fixnum) string)
                ((fixnum) (##sys#fixnum->string #(1))))
 
-(string->number (#(procedure #:clean #:enforce) string->number (string 
#!optional number) 
+(string->number (#(procedure #:clean #:enforce) string->number (string 
#!optional fixnum) 
                 (or number boolean)))
 
 (char? (#(procedure #:pure #:predicate char) char? (*) boolean))
@@ -802,9 +806,9 @@
 (file-exists? (#(procedure #:clean #:enforce) file-exists? (string) (or 
boolean string)))
 (directory-exists? (#(procedure #:clean #:enforce) directory-exists? (string) 
(or boolean string)))
 
-(finite? (#(procedure #:pure) finite? (*) boolean)
+(finite? (#(procedure #:clean #:enforce) finite? (number) boolean)
         ((fixnum) (let ((#(tmp) #(1))) '#t))
-        ((*) (##core#inline "C_i_finitep" #(1))))
+        (((or float number)) (##core#inline "C_i_finitep" #(1))))
 
 (fixnum-bits fixnum)
 (fixnum-precision fixnum)
-- 
1.7.9.1

_______________________________________________
Chicken-hackers mailing list
Chicken-hackers@nongnu.org
https://lists.nongnu.org/mailman/listinfo/chicken-hackers

Reply via email to