~ chicken-core (chicken-5) 1b0b27387a2e4888179bc1e0fb46f68f18cf0d06


commit 1b0b27387a2e4888179bc1e0fb46f68f18cf0d06
Author:     megane <meganeka@gmail.com>
AuthorDate: Tue Aug 20 20:03:54 2019 +0300
Commit:     Peter Bex <peter@more-magic.net>
CommitDate: Sun Sep 15 11:07:09 2019 +0200

    * scrutinizer.scm: Don't insert duplicate entries in blist
    
      The important change is changing
        (eq? fl (cdaar bl))
      to
        (or fl-found? (eq? fl (ble-tag ble)))
    
      Example showing the behaviour:
      (lambda (x y)
        (if y (+ x 1))
        (set! x 'a)
        (set! x 'a) ; <- these add more and more identical entries to blist
        (set! x 'a)
        (set! x 'a))
    
      Also rename f -> fl-found?. It took half an hour to figure out
      what was happening here at all, hopefully this helps the next soul.
    
      Also added accessors for the blist entries.
    
    Signed-off-by: Peter Bex <peter@more-magic.net>

diff --git a/scrutinizer.scm b/scrutinizer.scm
index aaed8498..2b3d08f8 100644
--- a/scrutinizer.scm
+++ b/scrutinizer.scm
@@ -624,22 +624,39 @@
 				  loc
 				  "variable `~a' of type `~a' was modified to a value of type `~a'"
 				  var ot rt)))))
-		      ;; don't use "add-to-blist" since the current operation does not affect aliases
 		      (let ((t (if (or strict (not (db-get db var 'captured)))
 				   rt 
 				   '*))
 			    (fl (car flow)))
-			(let loop ((bl blist) (f #f))
+			;; For each outer flow F, change the var's
+			;; type to (or t <old-type@F>). Add a new
+			;; entry for current flow if it's missing.
+			;;
+			;; Motivating example:
+			;;
+			;;   (let* ((x 1)
+			;;          (y x))      ; y x : fixnum @ flow f_1
+			;;     (if foo
+			;;         (set! y 'a)) ; y : symbol   @ flow f_2
+			;;     y)               ; (1)          @ flow f_1
+			;;
+			;; At point (1) the type of y can be inferred
+			;; to be (or fixnum symbol). The type of x
+			;; should stay unchanged, however.
+			(let loop ((bl blist) (fl-found? #f))
 			  (cond ((null? bl)
-				 (unless f
+				 (unless fl-found?
+				   (dd "set! ~a in ~a (new) --> ~a" var fl t)
 				   (set! blist (alist-cons (cons var fl) t blist))))
-				((eq? (caaar bl) var)
-				 (let ((t (simplify-type `(or ,t ,(cdar bl)))))
-				   (dd "assignment modifies blist entry ~s -> ~a"
-				       (caar bl) t)
-				   (set-cdr! (car bl) t)
-				   (loop (cdr bl) (eq? fl (cdaar bl)))))
-				(else (loop (cdr bl) f))))))
+				((eq? var (ble-id (car bl)))
+				 (let* ((ble (car bl))
+					(old-type (ble-type ble))
+					(t2 (simplify-type `(or ,t ,old-type))))
+				   (dd "set! ~a in ~a, or old ~a with ~a --> ~a"
+				       var tag old-type t t2)
+				   (ble-type-set! ble t2)
+				   (loop (cdr bl) (or fl-found? (eq? fl (ble-tag ble))))))
+				(else (loop (cdr bl) fl-found?))))))
 
 		    (when (always-immediate var rt loc)
 		      (set! assigned-immediates (add1 assigned-immediates))
@@ -839,6 +856,16 @@
 		 (cute set-car! (cddr t) <>))))))))
 
 
+;;; blist (binding list) helpers
+;;
+;; - Entries (ble) in blist have type ((symbol . fixnum) . type)
+
+(define ble-id caar)		; variable name : symbol
+(define ble-tag cdar)		; block tag     : fixnum
+(define ble-type cdr)		; variable type : valid type sexp
+(define ble-type-set! set-cdr!)
+
+
 ;;; Type-matching
 ;
 ; - "all" means: all elements in `or'-types in second argument must match
Trap