Hi hackers,

Here are some list-related scrutiny improvements. I started with pair
walking for the scrutinizer's special cases to fix #759 (patch #2),
which made adding special cases for drop & tail easy (#3). The other
special cases (#4, #5) are basically just improving result type accuracy
for make-list, make-vector and reverse, where possible.

The list-copy types.db fix (#1) speaks for itself, I think. Let me know
if anything looks off.

Cheers,

Evan
>From fd3de2653850806947de6461d3c1db332278e1fc Mon Sep 17 00:00:00 2001
From: Evan Hanson <ev...@foldling.org>
Date: Sat, 16 Aug 2014 16:16:29 +1200
Subject: [PATCH 1/5] Fix list-copy types.db entry to allow any argument type

list-copy accepts any argument type (returning non-pair arguments
unchanged), so its type should be a -> a. This also means it can be
marked pure, and improves the scrutinizer's accuracy on list-copy calls
since the argument type can be preserved as the result type.
---
 tests/typematch-tests.scm |    3 +++
 types.db                  |    2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/tests/typematch-tests.scm b/tests/typematch-tests.scm
index bbd5a3c..6cbcc9a 100644
--- a/tests/typematch-tests.scm
+++ b/tests/typematch-tests.scm
@@ -263,6 +263,9 @@
 (mx fixnum (##sys#vector-ref '#(1 2 3.4) 0))
 (mx (vector fixnum float) (vector 1 2.3))
 (mx (list fixnum float) (list 1 2.3))
+(mx (list fixnum float) (list-copy (list 1 2.3)))
+(mx (pair fixnum float) (list-copy (cons 1 2.3)))
+(mx fixnum (list-copy 1))
 
 (: f1 (forall (a) ((list-of a) -> a)))
 (define (f1 x) (car x))
diff --git a/types.db b/types.db
index 2621686..e5c0771 100644
--- a/types.db
+++ b/types.db
@@ -1924,7 +1924,7 @@
 (last (#(procedure #:clean #:enforce) last (pair) *))
 (last-pair (#(procedure #:clean #:enforce) last-pair (pair) *))
 (length+ (#(procedure #:clean #:enforce) length+ (list) *))
-(list-copy (forall (a) (#(procedure #:clean #:enforce) list-copy ((list-of a)) 
(list-of a))))
+(list-copy (forall (a) (#(procedure #:pure) list-copy (a) a)))
 (list-index (forall (a) (#(procedure #:enforce) list-index ((procedure (a 
#!rest) *) (list-of a) #!rest list) *)))
 (list-tabulate (forall (a) (#(procedure #:enforce) list-tabulate (fixnum 
(procedure (fixnum) a)) (list-of a))))
 (list= (#(procedure #:clean #:enforce) list= (#!optional (procedure (list 
list) *) #!rest list) boolean)
-- 
1.7.10.4

>From 2f96ca6af2cfdb29b10dd00f656fa2a2f22f0e37 Mon Sep 17 00:00:00 2001
From: Evan Hanson <ev...@foldling.org>
Date: Sat, 16 Aug 2014 16:42:07 +1200
Subject: [PATCH 2/5] Walk nested pair types in special-cased scrutiny for
 list-ref/list-tail

Also, remove the unused ##sys#list-ref alias and its special case.

Fixes #759.
---
 library.scm               |    1 -
 scrutinizer.scm           |   86 +++++++++++++++++++++++++++------------------
 tests/typematch-tests.scm |   16 +++++++--
 3 files changed, 65 insertions(+), 38 deletions(-)

diff --git a/library.scm b/library.scm
index 74980fb..fb85c86 100644
--- a/library.scm
+++ b/library.scm
@@ -4763,7 +4763,6 @@ EOF
 (define ##sys#list? list?)
 (define ##sys#null? null?)
 (define ##sys#map-n map)
-(define ##sys#list-ref list-ref)
 
 
 ;;; Promises:
diff --git a/scrutinizer.scm b/scrutinizer.scm
index c437933..c756067 100644
--- a/scrutinizer.scm
+++ b/scrutinizer.scm
@@ -2232,42 +2232,60 @@
   (define-special-case vector-ref vector-ref-result-type)
   (define-special-case ##sys#vector-ref vector-ref-result-type))
 
+
+;;; List-related special cases
+;
+; Preserve known element types for list-ref, list-tail.
+
 (let ()
-  (define (list-ref-result-type node args rtypes)
-    (or (and-let* ((subs (node-subexpressions node))
-                   ((= (length subs) 3))
-                   (arg1 (walked-result (second args)))
-                   ((pair? arg1))
-                   ((eq? 'list (car arg1)))
-                   (index (third subs))
-                   ((eq? 'quote (node-class index)))
-                   (val (first (node-parameters index)))
-                   ((fixnum? val))
-                   ((>= val 0))  ;XXX could warn on failure (but needs 
location)
-                   ((< val (length (cdr arg1)))))
-          (list (list-ref (cdr arg1) val)))
-       rtypes))
-  (define-special-case list-ref list-ref-result-type)
-  (define-special-case ##sys#list-ref list-ref-result-type))
 
-(define-special-case list-tail
-  (lambda (node args rtypes)
-    (or (and-let* ((subs (node-subexpressions node))
-                   ((= (length subs) 3))
-                   (arg1 (walked-result (second args)))
-                   ((pair? arg1))
-                   ((eq? 'list (car arg1)))
-                   (index (third subs))
-                   ((eq? 'quote (node-class index)))
-                   (val (first (node-parameters index)))
-                   ((fixnum? val))
-                   ((>= val 0))
-                   ((<= val (length (cdr arg1)))))   ;XXX could warn on 
failure (but needs location)
-          (let ((rest (list-tail (cdr arg1) val)))
-            (list (if (null? rest)
-                      'null
-                      `(list ,@rest)))))
-       rtypes)))
+  (define (list-or-null a)
+    (if (null? a) 'null `(list ,@a)))
+
+  ;; Split a list or pair type form at index i, calling k with the two
+  ;; sections of the type or returning #f if it doesn't match that far.
+  (define (split-list-type l i k)
+    (cond ((not (pair? l))
+          (and (fx= i 0) (eq? l 'null) (k l l)))
+         ((eq? (first l) 'list)
+          (and (fx< i (length l))
+               (receive (left right) (split-at (cdr l) i)
+                 (k (list-or-null left)
+                    (list-or-null right)))))
+         ((eq? (first l) 'pair)
+          (let lp ((a '()) (l l) (i i))
+            (cond ((fx= i 0)
+                   (k (list-or-null (reverse a)) l))
+                  ((and (pair? l)
+                        (eq? (first l) 'pair))
+                   (lp (cons (second l) a)
+                        (third l)
+                        (sub1 i)))
+                  (else #f))))
+         (else #f)))
+
+  (define (list+index-call-result-type-special-case k)
+    (lambda (node args rtypes)
+      (or (and-let* ((subs (node-subexpressions node))
+                    ((= (length subs) 3))
+                    (arg1 (walked-result (second args)))
+                    (index (third subs))
+                    ((eq? 'quote (node-class index)))
+                    (val (first (node-parameters index)))
+                    ((fixnum? val))
+                    ((>= val 0)))
+           (split-list-type arg1 val k))
+         rtypes)))
+
+  (define-special-case list-ref
+    (list+index-call-result-type-special-case
+     (lambda (_ result-type)
+       (and (pair? result-type)
+           (list (cadr result-type))))))
+
+  (define-special-case list-tail
+    (list+index-call-result-type-special-case
+     (lambda (_ result-type) (list result-type)))))
 
 (define-special-case list
   (lambda (node args rtypes)
diff --git a/tests/typematch-tests.scm b/tests/typematch-tests.scm
index 6cbcc9a..85ada83 100644
--- a/tests/typematch-tests.scm
+++ b/tests/typematch-tests.scm
@@ -49,9 +49,11 @@
 (define-syntax mx
   (syntax-rules ()
     ((_ t x) 
-     (compiler-typecase 
-      x
-      (t 'ok)))))
+     (begin
+       (print 'x " = " 't)
+       (compiler-typecase
+       x
+       (t 'ok))))))
 
 (define-syntax mn
   (er-macro-transformer
@@ -266,6 +268,14 @@
 (mx (list fixnum float) (list-copy (list 1 2.3)))
 (mx (pair fixnum float) (list-copy (cons 1 2.3)))
 (mx fixnum (list-copy 1))
+(mx fixnum (list-ref (list 1 2.3) 0))
+(mx fixnum (list-ref (cons 1 2.3) 0))
+(mx float (list-ref (list 1 2.3) 1))
+(mx (list fixnum float) (list-tail (list 1 2.3) 0))
+(mx (pair fixnum float) (list-tail (cons 1 2.3) 0))
+(mx (list float) (list-tail (list 1 2.3) 1))
+(mx float (list-tail (cons 1 2.3) 1))
+(mx null  (list-tail (list 1 2.3) 2))
 
 (: f1 (forall (a) ((list-of a) -> a)))
 (define (f1 x) (car x))
-- 
1.7.10.4

>From 39844c1859d7fc5f22430f5dd136e393701757a3 Mon Sep 17 00:00:00 2001
From: Evan Hanson <ev...@foldling.org>
Date: Sun, 17 Aug 2014 13:10:43 +1200
Subject: [PATCH 3/5] Add scrutiny special cases for split-at, drop & take

This preserves the element types of pair and list arguments in the
result types for these procedures where possible, similarly to the
preexisting special cases for list-ref and list-tail.
---
 scrutinizer.scm           |   16 +++++++++++++++-
 tests/typematch-tests.scm |   12 +++++++++++-
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/scrutinizer.scm b/scrutinizer.scm
index c756067..6de343f 100644
--- a/scrutinizer.scm
+++ b/scrutinizer.scm
@@ -2235,7 +2235,9 @@
 
 ;;; List-related special cases
 ;
-; Preserve known element types for list-ref, list-tail.
+; Preserve known element types for:
+;
+;   list-ref, list-tail, drop, take, split-at
 
 (let ()
 
@@ -2285,6 +2287,18 @@
 
   (define-special-case list-tail
     (list+index-call-result-type-special-case
+     (lambda (_ result-type) (list result-type))))
+
+  (define-special-case split-at
+    (list+index-call-result-type-special-case
+     (lambda result-types (list result-types))))
+
+  (define-special-case take
+    (list+index-call-result-type-special-case
+     (lambda (result-type _) (list result-type))))
+
+  (define-special-case drop
+    (list+index-call-result-type-special-case
      (lambda (_ result-type) (list result-type)))))
 
 (define-special-case list
diff --git a/tests/typematch-tests.scm b/tests/typematch-tests.scm
index 85ada83..4051595 100644
--- a/tests/typematch-tests.scm
+++ b/tests/typematch-tests.scm
@@ -1,7 +1,7 @@
 ;;;; typematch-tests.scm
 
 
-(use lolevel data-structures)
+(use srfi-1 lolevel data-structures)
 
 
 (define-syntax check
@@ -276,6 +276,16 @@
 (mx (list float) (list-tail (list 1 2.3) 1))
 (mx float (list-tail (cons 1 2.3) 1))
 (mx null  (list-tail (list 1 2.3) 2))
+(mx (list fixnum float) (drop (list 1 2.3) 0))
+(mx (pair fixnum float) (drop (cons 1 2.3) 0))
+(mx (list float) (drop (list 1 2.3) 1))
+(mx float (drop (cons 1 2.3) 1))
+(mx null (drop (list 1 2.3) 2))
+(mx null (take (list 1 2.3) 0))
+(mx null (take (cons 1 2.3) 0))
+(mx (list fixnum) (take (list 1 2.3) 1))
+(mx (list fixnum) (take (cons 1 2.3) 1))
+(mx (list fixnum float) (take (list 1 2.3) 2))
 
 (: f1 (forall (a) ((list-of a) -> a)))
 (define (f1 x) (car x))
-- 
1.7.10.4

>From b62a8ce2b2a9c405c06acce60866ad3684f61bd0 Mon Sep 17 00:00:00 2001
From: Evan Hanson <ev...@foldling.org>
Date: Sun, 17 Aug 2014 18:36:21 +1200
Subject: [PATCH 4/5] Add scrutiny special cases for make-list/make-vector
 with known sizes

---
 scrutinizer.scm           |   32 +++++++++++++++++++++++++++++++-
 tests/typematch-tests.scm |    4 ++++
 types.db                  |    2 ++
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/scrutinizer.scm b/scrutinizer.scm
index 6de343f..d1690b6 100644
--- a/scrutinizer.scm
+++ b/scrutinizer.scm
@@ -110,6 +110,7 @@
 (define-constant +fragment-max-length+ 6)
 (define-constant +fragment-max-depth+ 4)
 (define-constant +maximal-union-type-length+ 20)
+(define-constant +maximal-complex-object-constructor-result-type-length+ 256)
 
 
 (define specialization-statistics '())
@@ -2322,6 +2323,34 @@
     `((vector ,@(map walked-result (cdr args))))))
 
 
+;;; Special cases for make-list/make-vector with a known size
+;
+; e.g. (make-list 3 #\a) => (list char char char)
+
+(let ()
+
+  (define (complex-object-constructor-result-type-special-case type)
+    (lambda (node args rtypes)
+      (or (and-let* ((subs (node-subexpressions node))
+                    (fill (case (length subs)
+                            ((2) '*)
+                            ((3) (walked-result (third args)))
+                            (else #f)))
+                    (sub2 (second subs))
+                    ((eq? 'quote (node-class sub2)))
+                    (size (first (node-parameters sub2)))
+                    ((fixnum? size))
+                    ((<= 0 size 
+maximal-complex-object-constructor-result-type-length+)))
+           `((,type ,@(make-list size fill))))
+         rtypes)))
+
+  (define-special-case make-list
+    (complex-object-constructor-result-type-special-case 'list))
+
+  (define-special-case make-vector
+    (complex-object-constructor-result-type-special-case 'vector)))
+
+
 ;;; perform check over all typevar instantiations
 
 (define (over-all-instantiations tlist typeenv exact process)
@@ -2365,7 +2394,8 @@
 
     (ddd " over-all-instantiations: ~s exact=~a" tlist exact)
     ;; process all tlist elements
-    (let loop ((ts tlist) (ok #f))
+    (let loop ((ts (delete-duplicates tlist equal?))
+              (ok #f))
       (cond ((null? ts)
             (cond ((or ok (null? tlist))
                    (for-each 
diff --git a/tests/typematch-tests.scm b/tests/typematch-tests.scm
index 4051595..4374337 100644
--- a/tests/typematch-tests.scm
+++ b/tests/typematch-tests.scm
@@ -286,6 +286,10 @@
 (mx (list fixnum) (take (list 1 2.3) 1))
 (mx (list fixnum) (take (cons 1 2.3) 1))
 (mx (list fixnum float) (take (list 1 2.3) 2))
+(mx (list * *) (make-list 2))
+(mx (list string string) (make-list 2 "a"))
+(mx (vector * *) (make-vector 2))
+(mx (vector string string) (make-vector 2 "a"))
 
 (: f1 (forall (a) ((list-of a) -> a)))
 (define (f1 x) (car x))
diff --git a/types.db b/types.db
index e5c0771..76e2a85 100644
--- a/types.db
+++ b/types.db
@@ -561,6 +561,7 @@
 
 (vector? (#(procedure #:pure #:predicate vector) vector? (*) boolean))
 
+;; special-cased (see scrutinizer.scm)
 (make-vector (forall (a) (#(procedure #:clean #:enforce) make-vector (fixnum 
#!optional a) 
                          (vector-of a))))
 
@@ -1993,6 +1994,7 @@
  ((procedure) (let ((#(tmp) #(1))) '#t))
  ((procedure list) (let ((#(tmp1) #(1)) (#(tmp2) #(2))) '#t)))
 
+;; special-cased (see scrutinizer.scm)
 (make-list (forall (a) (#(procedure #:clean #:enforce) make-list (fixnum 
#!optional a) (list-of a))))
 
 (map!
-- 
1.7.10.4

>From 39b3649176042897f91942eec5eb67d9690f4c6c Mon Sep 17 00:00:00 2001
From: Evan Hanson <ev...@foldling.org>
Date: Sat, 6 Sep 2014 09:10:18 +1200
Subject: [PATCH 5/5] Add scrutiny special case for reverse and specialization
 for null argument

This preserves the element types of list- and null-type arguments to
reverse in its result type (rather than the less specialized list-of).
---
 scrutinizer.scm           |    9 +++++++++
 tests/typematch-tests.scm |    4 ++++
 types.db                  |    4 +++-
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/scrutinizer.scm b/scrutinizer.scm
index d1690b6..1261f8c 100644
--- a/scrutinizer.scm
+++ b/scrutinizer.scm
@@ -2322,6 +2322,15 @@
   (lambda (node args rtypes)
     `((vector ,@(map walked-result (cdr args))))))
 
+(define-special-case reverse
+  (lambda (node args rtypes)
+    (or (and-let* ((subs (node-subexpressions node))
+                  ((= (length subs) 2))
+                  (arg1 (walked-result (second args)))
+                  ((pair? arg1))
+                  ((eq? (car arg1) 'list)))
+         `((list ,@(reverse (cdr arg1)))))
+       rtypes)))
 
 ;;; Special cases for make-list/make-vector with a known size
 ;
diff --git a/tests/typematch-tests.scm b/tests/typematch-tests.scm
index 4374337..930362f 100644
--- a/tests/typematch-tests.scm
+++ b/tests/typematch-tests.scm
@@ -290,6 +290,10 @@
 (mx (list string string) (make-list 2 "a"))
 (mx (vector * *) (make-vector 2))
 (mx (vector string string) (make-vector 2 "a"))
+(mx null (reverse '()))
+(mx list (reverse (the list (list 1 "2"))))
+(mx (list string fixnum) (reverse (list 1 "2")))
+(mx (list fixnum string) (reverse (cons "1" (cons 2 '()))))
 
 (: f1 (forall (a) ((list-of a) -> a)))
 (define (f1 x) (car x))
diff --git a/types.db b/types.db
index 76e2a85..b554ace 100644
--- a/types.db
+++ b/types.db
@@ -170,7 +170,9 @@
 (append (#(procedure #:clean) append (#!rest *) *)) ; sic
 (##sys#append (#(procedure #:clean) ##sys#append (#!rest *) *))
 
-(reverse (forall (a) (#(procedure #:clean #:enforce) reverse ((list-of a)) 
(list-of a))))
+;; special cased (see scrutinizer.scm)
+(reverse (forall (a) (#(procedure #:clean #:enforce) reverse ((list-of a)) 
(list-of a)))
+         ((null) (null) (let ((#(tmp) #(1))) '())))
 
 (memq (forall (a b) (#(procedure #:clean) memq (a (list-of b)) (or false 
(list-of b))))
       ((* list) (##core#inline "C_u_i_memq" #(1) #(2))))
-- 
1.7.10.4

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

Reply via email to