~ chicken-core (chicken-5) 898c3a8cff0958dff859a4400ffbc4f192dddf04
commit 898c3a8cff0958dff859a4400ffbc4f192dddf04 Merge: 5e76f95e 610b76c9 Author: felix <felix@call-with-current-continuation.org> AuthorDate: Sat Jul 23 12:55:14 2011 +0200 Commit: felix <felix@call-with-current-continuation.org> CommitDate: Sat Jul 23 12:55:14 2011 +0200 resolved conflicts; no -verbose in debugbuild; simplify type after validation diff --cc defaults.make index 3ed7ae45,76f8f581..ee811fd0 --- a/defaults.make +++ b/defaults.make @@@ -275,8 -272,7 +272,8 @@@ CSI ?= csi$(EXE CHICKEN_OPTIONS = -optimize-level 2 -include-path . -include-path $(SRCDIR) -inline -ignore-repository -feature chicken-bootstrap ifdef DEBUGBUILD - CHICKEN_OPTIONS += -feature debugbuild -scrutinize -types $(SRCDIR)types.db -verbose + CHICKEN_OPTIONS += -feature debugbuild -scrutinize -types $(SRCDIR)types.db +CHICKEN_OPTIONS += -feature debugbuild else CHICKEN_OPTIONS += -no-warnings endif diff --cc rules.make index 5eed53fc,fc719023..3e7fd117 --- a/rules.make +++ b/rules.make @@@ -35,11 -35,10 +35,11 @@@ VPATH=$(SRCDIR SETUP_API_OBJECTS_1 = setup-api setup-download -LIBCHICKEN_OBJECTS_1 = \ +LIBCHICKEN_SCHEME_OBJECTS_1 = \ library eval data-structures ports files extras lolevel utils tcp srfi-1 srfi-4 srfi-13 \ srfi-14 srfi-18 srfi-69 $(POSIXFILE) irregex scheduler \ - profiler stub expand modules chicken-syntax chicken-ffi-syntax - profiler stub expand modules chicken-syntax chicken-ffi-syntax runtime build-version ++ profiler stub expand modules chicken-syntax chicken-ffi-syntax build-version +LIBCHICKEN_OBJECTS_1 = $(LIBCHICKEN_SCHEME_OBJECTS_1) runtime LIBCHICKEN_SHARED_OBJECTS = $(LIBCHICKEN_OBJECTS_1:=$(O)) LIBCHICKEN_STATIC_OBJECTS = $(LIBCHICKEN_OBJECTS_1:=-static$(O)) diff --cc scrutinizer.scm index b1f9d974,99f6840c..700deaf8 --- a/scrutinizer.scm +++ b/scrutinizer.scm @@@ -1076,352 -637,12 +1076,353 @@@ (for-each (lambda (e) (let* ((name (car e)) - (old (##sys#get name '##core#type)) - (new (cadr e))) - (when (and old (not (equal? old new))) - (##sys#notice + (old (variable-mark name '##compiler#type)) + (new (cadr e)) + (specs (and (pair? (cddr e)) (cddr e)))) + (when (pair? new) + (case (car new) + ((procedure!) + (mark-variable name '##compiler#enforce #t) + (set-car! new 'procedure)) + ((procedure!? procedure?!) + (mark-variable name '##compiler#enforce #t) + (mark-variable name '##compiler#predicate (cadr new)) + (set! new (cons 'procedure (cddr new)))) + ((procedure?) + (mark-variable name '##compiler#predicate (cadr new)) + (set! new (cons 'procedure (cddr new)))))) + (cond-expand + (debugbuild + (let-values (((t _) (validate-type new name))) + (unless t + (warning "invalid type specification" name new)))) + (else)) + (when (and old (not (compatible-types? old new))) + (warning (sprintf "type-definition `~a' for toplevel binding `~a' conflicts with previously loaded type `~a'" - name new old))) - (##sys#put! name '##core#type new))) + name new old))) + (mark-variable name '##compiler#type new) + (when specs + ;;XXX validate types in specs + (mark-variable name '##compiler#specializations specs)))) (read-file dbfile)))) + +(define (emit-type-file filename db) + (with-output-to-file filename + (lambda () + (print "; GENERATED BY CHICKEN " (chicken-version) " FROM " + source-filename "\n") + (##sys#hash-table-for-each + (lambda (sym plist) + (when (variable-visible? sym) + (when (variable-mark sym '##compiler#declared-type) + (let ((specs (or (variable-mark sym '##compiler#specializations) '())) + (type (variable-mark sym '##compiler#type)) + (pred (variable-mark sym '##compiler#predicate)) + (enforce (variable-mark sym '##compiler#enforce))) + (pp (cons* + sym + (if (and (pair? type) (eq? 'procedure (car type))) + `(,(cond ((and enforce pred) 'procedure!?) + (pred 'procedure?) + (enforce 'procedure!) + (else 'procedure)) + ,@(if pred (list pred) '()) + ,@(cdr type)) + type) + specs)))))) + db) + (print "; END OF FILE")))) + +(define (match-specialization typelist atypes exact) + ;; - does not accept complex procedure types in typelist! + ;; - "exact" means: "or"-type in atypes is not allowed + (define (match st t) + (cond ((eq? st t)) + ((pair? st) + (case (car st) + ((not) (matchnot (cadr st) t)) + ((or) (any (cut match <> t) (cdr st))) + ((and) (every (cut match <> t) (cdr st))) + ((procedure) (bomb "match-specialization: invalid complex procedure type" st)) + (else (equal? st t)))) + ((eq? st '*)) + ;; "list" different from "number": a pair is not necessarily a list: + ((eq? st 'list) (eq? t 'list)) + ((eq? st 'number) (match '(or fixnum float) t)) + ((pair? t) + (case (car t) + ((or) ((if exact every any) (cut match st <>) (cdr t))) + ((and) (every (cut match st <>) (cdr t))) + ((procedure) (match st 'procedure)) + ;; (not ...) should not occur + (else (equal? st t)))) + (else (equal? st t)))) + (define (matchnot st t) + (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 '(or null pair) t))) + ((eq? 'number st) (not (match '(or fixnum float) t))) + ((pair? t) + (case (car t) + ((or) (every (cut matchnot st <>) (cdr t))) + ((and) (any (cut matchnot st <>) (cdr t))) ;XXX test for "exact" here, too? + (else (not (match st t))))) + (else (not (match st t))))) + (let loop ((tl typelist) (atypes atypes)) + (cond ((null? tl) (null? atypes)) + ((null? atypes) #f) + ((eq? (car tl) '#!rest) + (every (cute match (cadr tl) <>) atypes)) + ((match (car tl) (car atypes)) (loop (cdr tl) (cdr atypes))) + (else #f)))) + +(define (specialize-node! node template) + (let ((args (cdr (node-subexpressions node))) + (env '())) + (define (subst x) + (cond ((and (vector? x) + (= 1 (vector-length x)) ) + (let ((y (vector-ref x 0))) + (cond ((integer? y) + (if (negative? y) + (list-tail args (sub1 (- y))) + (list-ref args (sub1 y)))) + ((symbol? y) + (cond ((assq y env) => cdr) + (else + (let ((var (gensym y))) + (set! env (alist-cons y var env)) + var))))))) + ((and (vector? x) + (= 2 (vector-length x)) + (integer? (vector-ref x 0)) + (eq? '... (vector-ref x 1))) + (list-tail args (sub1 (vector-ref x 0)))) + ((not (pair? x)) x) + ((eq? 'quote (car x)) x) ; to handle numeric constants + (else (cons (subst (car x)) (subst (cdr x)))))) + (let ((spec (subst template))) + (copy-node! (build-node-graph spec) node)))) + +(define (validate-type type name) + ;; - returns converted type or #f + ;; - also converts "(... -> ...)" types + ;; - drops "#!key ..." args by converting to #!rest + ;; - handles "(T1 -> T2 : T3)" (predicate) ++ ;; - simplifies result + (let ((ptype #f)) ; (T . PT) | #f + (define (upto lst p) + (let loop ((lst lst)) + (cond ((eq? lst p) '()) + (else (cons (car lst) (loop (cdr lst))))))) + (define (validate-llist llist) + (cond ((null? llist) '()) + ((symbol? llist) '(#!rest *)) + ((not (pair? llist)) #f) + ((eq? '#!optional (car llist)) + (let ((l1 (validate-llist (cdr llist)))) + (and l1 (cons '#!optional l1)))) + ((eq? '#!rest (car llist)) + (cond ((null? (cdr llist)) '(#!rest *)) + ((not (pair? (cdr llist))) #f) + (else + (let ((l1 (validate (cadr llist)))) + (and l1 `(#!rest ,l1)))))) + ((eq? '#!key (car llist)) '(#!rest *)) + (else + (let* ((l1 (validate (car llist))) + (l2 (validate-llist (cdr llist)))) + (and l1 l2 (cons l1 l2)))))) + (define (validate t #!optional (rec #t)) + (cond ((memq t '(* string symbol char number boolean list pair + procedure vector null eof undefined port blob + pointer locative fixnum float pointer-vector + deprecated noreturn values)) + t) + ((not (pair? t)) #f) + ((eq? 'or (car t)) + (and (list? t) + (let ((ts (map validate (cdr t)))) + (and (every identity ts) + `(or ,@ts))))) + ((eq? 'struct (car t)) + (and (= 2 (length t)) + (symbol? (cadr t)) + t)) + ((eq? 'procedure (car t)) + (and (pair? (cdr t)) + (let* ((name (if (symbol? (cadr t)) + (cadr t) + name)) + (t2 (if (symbol? (cadr t)) (cddr t) (cdr t)))) + (and (pair? t2) + (list? (car t2)) + (let ((ts (validate-llist (car t2)))) + (and ts + (every identity ts) + (let* ((rt2 (cdr t2)) + (rt (if (eq? '* rt2) + rt2 + (and (list? rt2) + (let ((rts (map validate rt2))) + (and (every identity rts) + rts)))))) + (and rt + `(procedure + ,@(if (and name (not rec)) (list name) '()) + ,ts + ,@rt))))))))) + ((and (pair? (cdr t)) (memq '-> (cdr t))) => + (lambda (p) + (let ((cp (memq ': (cdr t)))) + (cond ((not cp) + (validate + `(procedure ,(upto t p) ,@(cdr p)) + rec)) + ((and (= 5 (length t)) + (eq? p (cdr t)) + (eq? cp (cdddr t))) + (set! t (validate `(procedure (,(first t)) ,(third t)) rec)) + ;; we do it this way to distinguish the "outermost" predicate + ;; procedure type + (set! ptype (cons t (validate (cadr cp)))) + t) + (else #f))))) + (else #f))) - (let ((type (validate type #f))) ++ (let ((type (simplify-type (validate type #f)))) + (values type (and ptype (eq? (car ptype) type) (cdr ptype)))))) + +(define (initial-argument-types dest vars argc) + (if (and dest + strict-variable-types + (variable-mark dest '##compiler#declared-type)) + (let ((ptype (variable-mark dest '##compiler#type))) + (if (procedure-type? ptype) + (nth-value 0 (procedure-argument-types ptype argc #t)) + (make-list argc '*))) + (make-list argc '*))) + + +;;; generate type-checks for formal variables + +#;(define (generate-type-checks! node loc vars inits) + ;; assumes type is validated + (define (test t v) + (case t + ((null) `(##core#inline "C_eqp" ,v '())) + ((eof) `(##core#inline "C_eofp" ,v)) + ((string) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_stringp" ,v) + '#f)) + ((float) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_flonump" ,v) + '#f)) + ((char) `(##core#inline "C_charp" ,v)) + ((fixnum) `(##core#inline "C_fixnump" ,v)) + ((number) `(##core#inline "C_i_numberp" ,v)) + ((list) `(##core#inline "C_i_listp" ,v)) + ((symbol) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_symbolp" ,v) + '#f)) + ((pair) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_pairp" ,v) + '#f)) + ((boolean) `(##core#inline "C_booleanp" ,v)) + ((procedure) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_closurep" ,v) + '#f)) + ((vector) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_vectorp" ,v) + '#f)) + ((pointer) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_pointerp" ,v) + '#f)) + ((blob) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_byteblockp" ,v) + '#f)) + ((pointer-vector) `(##core#inline "C_i_structurep" ,v 'pointer-vector)) + ((port) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_portp" ,v) + '#f)) + ((locative) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_locativep" ,v) + '#f)) + (else + (case (car t) + ((procedure) `(if (##core#inline "C_blockp" ,v) + (##core#inline "C_closurep" ,v) + '#f)) + ((or) + (cond ((null? (cdr t)) '(##core#undefined)) + ((null? (cddr t)) (test (cadr t) v)) + (else + `(if ,(test (cadr t) v) + '#t + ,(test `(or ,@(cddr t)) v))))) + ((and) + (cond ((null? (cdr t)) '(##core#undefined)) + ((null? (cddr t)) (test (cadr t) v)) + (else + `(if ,(test (cadr t) v) + ,(test `(and ,@(cddr t)) v) + '#f)))) + ((not) + `(not ,(test (cadr t) v))) + (else (bomb "invalid type" t v)))))) + (let ((body (first (node-subexpressions node)))) + (let loop ((vars (reverse vars)) (inits (reverse inits)) (b body)) + (cond ((null? inits) + (if (eq? b body) + body + (copy-node! + (make-node + (node-class node) ; lambda + (node-parameters node) + (list b)) + node))) + ((eq? '* (car inits)) + (loop (cdr vars) (cdr inits) b)) + (else + (loop + (cdr vars) (cdr inits) + (make-node + 'let (list (gensym)) + (list + (build-node-graph + (let ((t (car inits)) + (v (car vars))) + `(if ,(test t v) + (##core#undefined) + (##core#app + ##sys#error ',loc + ',(sprintf "expected argument `~a' to be of type `~s'" + v t) + ,v)))) + b)))))))) + + +;;; hardcoded result types for certain primitives + +(define-syntax define-special-case + (syntax-rules () + ((_ name handler) + (##sys#put! 'name '##compiler#special-result-type handler)))) + +(define-special-case ##sys#make-structure + (lambda (node rtypes) + (or (let ((subs (node-subexpressions node))) + (and (>= (length subs) 2) + (let ((arg1 (second subs))) + (and (eq? 'quote (node-class arg1)) + (let ((val (first (node-parameters arg1)))) + (and (symbol? val) + ;;XXX a bit of a hack - we should remove the distinct + ;; "pointer-vector" type. + (if (eq? 'pointer-vector val) + '(pointer-vector) + `((struct ,val))))))))) + rtypes))) diff --cc tcp.scm index ff74f133,18530924..1e094208 --- a/tcp.scm +++ b/tcp.scm @@@ -642,19 -642,17 +642,19 @@@ EO (##sys#string-append "cannot compute remote address - " strerror) p) ) ) ) ) (define (tcp-port-numbers p) - (##sys#check-port p 'tcp-port-numbers) + (##sys#check-port* p 'tcp-port-numbers) (let ((fd (##sys#tcp-port->fileno p))) - (values - (or (##net#getsockport fd) - (##sys#signal-hook - #:network-error 'tcp-port-numbers - (##sys#string-append "cannot compute local port - " strerror) p) ) - (or (##net#getpeerport fd) - (##sys#signal-hook - #:network-error 'tcp-port-numbers - (##sys#string-append "cannot compute remote port - " strerror) p) ) ) ) ) + (let ((sp (##net#getsockport fd)) + (pp (##net#getpeerport fd))) + (when (eq? -1 sp) + (##sys#signal-hook + #:network-error 'tcp-port-numbers + (##sys#string-append "cannot compute local port - " strerror) p)) + (when (eq? -1 pp) + (##sys#signal-hook + #:network-error 'tcp-port-numbers + (##sys#string-append "cannot compute remote port - " strerror) p) ) + (values sp pp)))) (define (tcp-listener-port tcpl) (##sys#check-structure tcpl 'tcp-listener 'tcp-listener-port) diff --cc tests/scrutiny.expected index 9325c771,cd3a5bc4..1e469592 --- a/tests/scrutiny.expected +++ b/tests/scrutiny.expected @@@ -43,55 -43,6 +43,42 @@@ Warning: at toplevel expected in `let' binding of `g8' a single result, but were given 2 results Warning: at toplevel: - g89: in procedure call to `g89', expected a value of type `(procedure () *)', but were given a value of type `fixnum' + in procedure call to `g89', expected a value of type `(procedure () *)', but was given a value of type `fixnum' + +Warning: in toplevel procedure `foo2': + scrutiny-tests.scm:57: in procedure call to `string-append', expected argument #1 of type `string', but was given an argument of type `number' + +Warning: at toplevel: + scrutiny-tests.scm:65: in procedure call to `foo3', expected argument #1 of type `string', but was given an argument of type `fixnum' + +Warning: in toplevel procedure `foo4': + scrutiny-tests.scm:70: in procedure call to `+', expected argument #1 of type `number', but was given an argument of type `string' + +Warning: in toplevel procedure `foo5': + scrutiny-tests.scm:76: in procedure call to `+', expected argument #1 of type `number', but was given an argument of type `string' + +Warning: in toplevel procedure `foo6': + scrutiny-tests.scm:82: in procedure call to `+', expected argument #1 of type `number', but was given an argument of type `string' + - Warning: at toplevel: - scrutiny-tests.scm:89: in procedure call to `+', expected argument #1 of type `number', but was given an argument of type `string' - +Warning: in toplevel procedure `foo9': + scrutiny-tests.scm:97: in procedure call to `+', expected argument #1 of type `number', but was given an argument of type `string' + +Note: in toplevel procedure `foo10': + expression returns a result of type `string', but is declared to return `pair', which is not a subtype + +Warning: in toplevel procedure `foo10': + scrutiny-tests.scm:101: in procedure call to `string-append', expected argument #1 of type `string', but was given an argument of type `pair' + +Warning: in toplevel procedure `foo10': + expression returns 2 values but is declared to have a single result + +Note: in toplevel procedure `foo10': + expression returns a result of type `fixnum', but is declared to return `*', which is not a subtype + +Warning: in toplevel procedure `foo10': + expression returns zero values but is declared to have a single result of type `*' + +Warning: in toplevel procedure `foo10': + scrutiny-tests.scm:104: in procedure call to `*', expected argument #1 of type `number', but was given an argument of type `string' Warning: redefinition of standard binding: car - - Warning: (in k161) constant-folding expression results in error: "bad argument type": (+ (quote a) (quote b)) - - Warning: (in k171) constant-folding expression results in error: "bad argument type - not a string": (string-append (quote 99) (quote "abc")) - - Warning: (in k171) constant-folding expression results in error: "bad argument type - not a string": (string-append (quote 99) (quote "abc")) - - Warning: (in k171) constant-folding expression results in error: "bad argument type - not a string": (string-append (quote 99) (quote "abc")) - - Warning: (in k171) constant-folding expression results in error: "bad argument type - not a string": (string-append (quote 99) (quote "abc")) diff --cc types.db index 58a0bbe0,1603fda7..decdf091 --- a/types.db +++ b/types.db @@@ -780,35 -377,27 +780,36 @@@ (minimum-flonum float) (most-negative-fixnum fixnum) (most-positive-fixnum fixnum) -(on-exit (procedure on-exit ((procedure () . *)) undefined)) -(open-input-string (procedure open-input-string (string #!rest) port)) +(on-exit (procedure! on-exit ((procedure () . *)) undefined)) +(open-input-string (procedure! open-input-string (string #!rest) port)) (open-output-string (procedure open-output-string (#!rest) port)) (parentheses-synonyms (procedure parentheses-synonyms (#!optional *) *)) -(port-name (procedure port-name (#!optional port) *)) -(port-position (procedure port-position (#!optional port) fixnum)) -(port? (procedure port? (*) boolean)) + +(port-name (procedure! port-name (#!optional port) *) + ((port) (##sys#slot #(1) '3))) + +(port-position (procedure! port-position (#!optional port) fixnum)) + +(port? (procedure? port port? (*) boolean)) + (print (procedure print (#!rest *) undefined)) -(print-call-chain (procedure print-call-chain (#!optional port fixnum * string) undefined)) -(print-error-message (procedure print-error-message (* #!optional port string) undefined)) +(print-call-chain (procedure! print-call-chain (#!optional port fixnum * string) undefined)) +(print-error-message (procedure! print-error-message (* #!optional port string) undefined)) (print* (procedure print* (#!rest) undefined)) -(procedure-information (procedure procedure-information (procedure) *)) -(program-name (procedure program-name (#!optional string) string)) -(promise? (procedure promise? (*) boolean)) -(put! (procedure put! (symbol symbol *) undefined)) +(procedure-information (procedure! procedure-information (procedure) *)) +(program-name (procedure! program-name (#!optional string) string)) +(promise? (procedure? (struct promise) promise? (*) boolean)) + +(put! (procedure! put! (symbol symbol *) undefined) + ((symbol symbol *) + (##core#inline_allocate ("C_a_i_putprop" 8) #(1) #(2) #(3)))) + + (quit (procedure quit (#!optional *) noreturn)) -(register-feature! (procedure register-feature! (#!rest symbol) undefined)) -(remprop! (procedure remprop! (symbol symbol) undefined)) -(rename-file (procedure rename-file (string string) string)) -(repl (procedure repl (#!optional (procedure (*) *)) undefined)) -(repl-prompt (procedure repl-prompt (#!optional procedure) procedure)) +(register-feature! (procedure! register-feature! (#!rest symbol) undefined)) +(remprop! (procedure! remprop! (symbol symbol) undefined)) +(rename-file (procedure! rename-file (string string) string)) +(repl (procedure! repl (#!optional (procedure (*) *)) undefined)) +(repl-prompt (procedure! repl-prompt (#!optional procedure) procedure)) (repository-path (procedure repository-path (#!optional *) *)) (require (procedure require (#!rest *) undefined)) (reset (procedure reset () undefined))Trap