adjust -> opter so that it avoids stacking up range checks

(using continuation marks, just like the un opt/c version of ->)
This commit is contained in:
Robby Findler 2013-04-29 16:34:35 -05:00
parent 6edfc0cc9d
commit 8706ac286e
5 changed files with 171 additions and 176 deletions

View File

@ -1768,64 +1768,6 @@ v4 todo:
(append acc x)))
;
;
;
;
; ; ;;; ;;;
; ;;; ;;;
; ;;;; ;;;;; ;;; ;;;
; ;;;; ;;;;;;; ;;; ;;;
; ;;; ;; ;;; ;;; ;;;
; ;;; ;;;;; ;;; ;;;
; ;;; ;;; ;;; ;;; ;;;
; ;;;; ;;; ;;; ;;; ;;;
; ;;; ;;;;;; ;;; ;;;
;
;
;
;
(define-syntax (apply-projections stx)
(syntax-case stx ()
[(_ ((x f) ...) e)
(with-syntax ([count (length (syntax->list #'(x ...)))])
#'(let ([fs (list f ...)]
[thunk (λ () e)])
(call-with-immediate-continuation-mark
multiple-contract-key
(λ (first-mark)
(if (and first-mark
(= (length first-mark) count)
(andmap procedure-closure-contents-eq? fs first-mark))
(thunk)
(let-values ([(x ...) (with-continuation-mark multiple-contract-key fs
(thunk))])
(values/drop (f x) ...)))))))]))
(define multiple-contract-key (gensym 'multiple-contract-key))
(define-syntax (apply-projection stx)
(syntax-case stx ()
[(_ ctc arg)
#'(apply-projection/proc ctc (λ () arg))]))
(define single-contract-key (gensym 'single-contract-key))
(define (apply-projection/proc ctc thnk)
(call-with-immediate-continuation-mark
single-contract-key
(λ (first-mark) ;; note this is #f if there is no mark (so if #f can be a contract, something must change)
(if (and first-mark (procedure-closure-contents-eq? first-mark ctc))
(thnk)
(ctc
(with-continuation-mark single-contract-key ctc
(thnk)))))))
;
;
;

View File

@ -9,7 +9,7 @@
(provide get-opter reg-opter! opter
interleave-lifts
make-opt/info
build-opt/info
opt/info-contract
opt/info-val
opt/info-blame
@ -22,6 +22,7 @@
opt/info-swap-blame
opt/info-add-blame-context
opt/info-change-val
opt/info-positive-blame
opt/unknown
opt-error-name
@ -148,13 +149,22 @@
;; struct for color-keeping across opters
(define-struct opt/info
(contract val blame-stx swap-blame? free-vars recf base-pred this that))
(contract val blame-original-id blame-stx swap-blame? free-vars recf base-pred this that))
(define (build-opt/info contract val blame-id free-vars this that)
(make-opt/info contract val blame-id blame-id #f free-vars #f #f this that))
(define (opt/info-blame oi)
(if (opt/info-swap-blame? oi)
#`(blame-swap #,(opt/info-blame-stx oi))
(opt/info-blame-stx oi)))
;; returns syntax that, when evaluated, computes
;; the name of the positive blame party
(define (opt/info-positive-blame oi)
(if (opt/info-swap-blame? oi)
#`(blame-positive #,(opt/info-blame-original-id oi))
#`(blame-negative #,(opt/info-blame-original-id oi))))
;; opt/info-swap-blame : opt/info -> opt/info
;; swaps pos and neg
(define (opt/info-swap-blame info)

View File

@ -229,7 +229,7 @@
(values #'e (syntax-e #'x)))]))
(parameterize ([opt-error-name error-name-sym])
(define info (make-opt/info #'ctc #'val #'blame #f '() #f #f #'this #'that))
(define info (build-opt/info #'ctc #'val #'blame '() #'this #'that))
(define an-optres (opt/i info exp #:call-opt/unknown? #f))
(if an-optres
(bind-superlifts
@ -258,7 +258,7 @@
(cond
[(top-level-unknown? #'e) #'(otherwise-id e val-e blame-e)]
[else
(define info (make-opt/info #'ctc #'val #'blame #f '() #f #f #'this #'that))
(define info (build-opt/info #'ctc #'val #'blame '() #'this #'that))
(define an-optres (opt/i info #'e))
#`(let ([val val-e]
[blame blame-e])
@ -302,9 +302,9 @@
(syntax-case stx ()
[(_ f1 f2 no-neg-blame? (id args ...) e)
(let ()
(define info (make-opt/info #'ctc #'val #'blame #f
(define info (build-opt/info #'ctc #'val #'blame
(syntax->list #'(args ...))
#f #f #'this #'that))
#'this #'that))
;; it seems like this syntax-local-value can fail when expand-once
;; is called, but otherwise I think it shouldn't fail
(define bx (syntax-local-value #'no-neg-blame? (λ () #f)))

View File

@ -557,27 +557,39 @@
((next-dom ...) next-doms)
(dom-len (length dom-vars))
(rng-len (length rng-vars))
((next-rng ...) next-rngs))
((next-rng ...) next-rngs)
[(dom-vars ...) (generate-temporaries dom-vars)]
[(cont-mark-value) (generate-temporaries '(cont-mark-value))])
(define (values/maybe-one stx)
(syntax-case stx ()
[(x) #'x]
[(x ...) #'(values x ...)]))
#`(let ([exact-proc (case-lambda
[(dom-arg ...)
(values
(case-lambda
[(rng-arg ...)
#,(values/maybe-one #'(next-rng ...))]
[args
(bad-number-of-results blame val rng-len args)])
next-dom ...)]
[args
(bad-number-of-arguments blame val args dom-len)])])
#`(let* ([cont-mark-value (cons #,(opt/info-positive-blame opt/info) '#,rngs)]
[exact-proc (case-lambda
[(dom-arg ...)
(let-values ([(rng-checker dom-vars ...)
(values (case-lambda
[(rng-arg ...)
#,(values/maybe-one #'(next-rng ...))]
[args
(bad-number-of-results blame val rng-len args)])
next-dom ...)])
(call-with-immediate-continuation-mark
opt->/c-cm-key
(λ (mark-value)
(if (equal? mark-value cont-mark-value)
(values dom-vars ...)
(values rng-checker
dom-vars ...)))))]
[args
(bad-number-of-arguments blame val args dom-len)])])
(if (and (procedure? val)
(equal? dom-len (procedure-arity val))
(let-values ([(a b) (procedure-keywords val)])
(null? b)))
(chaperone-procedure val exact-proc)
(chaperone-procedure val exact-proc
impersonator-prop:application-mark
(cons opt->/c-cm-key cont-mark-value))
(handle-non-exact-procedure val dom-len blame exact-proc))))
(append lifts-doms lifts-rngs)
(append superlifts-doms superlifts-rngs)
@ -709,6 +721,8 @@
#:name name)
(opt/unknown opt/i opt/info stx))))]))
(define opt->/c-cm-key (gensym 'opt->/c-cm-key))
(define (blame-add-nth-arg-context blame n)
(blame-add-context blame
(format "the ~a argument of" (n->th n))))

View File

@ -186,17 +186,32 @@
(define (test/pos-blame name expression) (test/spec-failed name expression 'pos))
(define (test/neg-blame name expression) (test/spec-failed name expression 'neg))
(define-syntax (ctest/rewrite stx)
(syntax-case stx ()
[(_ expected name expression)
#'(begin
(contract-eval `(,test expected name expression))
(let/ec k
(contract-eval `(,test expected
',(string->symbol (format "~a+opt/c" name))
,(rewrite 'expression k)))))]))
(define (test/well-formed stx)
(contract-eval
`(,test (void)
(let ([expand/ret-void (lambda (x) (expand x) (void))]) expand/ret-void)
,stx)))
(let ([expand/ret-void (lambda (x) (expand x) (void))]) expand/ret-void)
,stx)))
(define (test/no-error sexp)
(contract-eval
`(,test (void)
eval
'(begin ,sexp (void)))))
`(,test (void)
eval
'(begin ,sexp (void))))
(let/ec k
(contract-eval
`(,test (void)
eval
'(begin ,(rewrite sexp k) (void))))))
(define (test-flat-contract contract pass fail)
(contract-eval `(,test #t flat-contract? ,contract))
@ -13040,100 +13055,114 @@ so that propagation occurs.
[() c]
[(x) (set! c (+ c 1)) #t]))))
(ctest 1
'tail-arrow
(let ([c (counter)])
(letrec ([f
(contract (-> any/c c)
(λ (x) (if (zero? x) x (f (- x 1))))
'pos
'neg)])
(f 3))
(c)))
(ctest 1
'tail-unconstrained-domain-arrow
(let ([c (counter)])
(letrec ([f
(contract (unconstrained-domain-> c)
(λ (x) (if (zero? x) x (f (- x 1))))
'pos
'neg)])
(f 3))
(c)))
(ctest 2
'tail-multiple-value-arrow
(let ([c (counter)])
(letrec ([f
(contract (-> any/c (values c c))
(λ (x) (if (zero? x) (values x x) (f (- x 1))))
'pos
'neg)])
(f 3))
(c)))
(ctest 2
'tail-arrow-star
(let ([c (counter)])
(letrec ([f
(contract (->* (any/c) () (values c c))
(λ (x) (if (zero? x) (values x x) (f (- x 1))))
'pos
'neg)])
(f 3))
(c)))
(ctest 1
'case->-regular
(let ([c (counter)])
(letrec ([f
(contract (case-> (-> any/c c)
(-> any/c any/c c))
(case-lambda
[(x) (if (zero? x) x (f (- x 1)))]
[(x y) (f x)])
'pos
'neg)])
(f 4 1))
(c)))
(ctest 1
'case->-rest-args
(let ([c (counter)])
(letrec ([f
(contract (case-> (-> any/c #:rest any/c c)
(-> any/c any/c #:rest any/c c))
(case-lambda
[(x) (f x 1)]
[(x y . z) (if (zero? x) x (apply f (- x 1) y (list y y)))])
'pos
'neg)])
(f 4))
(c)))
(ctest '(1)
'mut-rec-with-any/c
(let ()
(define f
(contract (-> number? any/c)
(lambda (x)
(if (zero? x)
(continuation-mark-set->list (current-continuation-marks) 'tail-test)
(with-continuation-mark 'tail-test x
(g (- x 1)))))
'pos
'neg))
(define g
(contract (-> number? any/c)
(lambda (x)
(f x))
'pos
'neg))
(f 3)))
(ctest/rewrite 1
'tail-arrow
(let ([c (counter)])
(letrec ([f
(contract (-> any/c c)
(λ (x) (if (zero? x) x (f (- x 1))))
'pos
'neg)])
(f 3))
(c)))
(ctest/rewrite 1
'tail-unconstrained-domain-arrow
(let ([c (counter)])
(letrec ([f
(contract (unconstrained-domain-> c)
(λ (x) (if (zero? x) x (f (- x 1))))
'pos
'neg)])
(f 3))
(c)))
(ctest/rewrite 2
'tail-multiple-value-arrow
(let ([c (counter)])
(letrec ([f
(contract (-> any/c (values c c))
(λ (x) (if (zero? x) (values x x) (f (- x 1))))
'pos
'neg)])
(f 3))
(c)))
(ctest/rewrite 2
'tail-arrow-star
(let ([c (counter)])
(letrec ([f
(contract (->* (any/c) () (values c c))
(λ (x) (if (zero? x) (values x x) (f (- x 1))))
'pos
'neg)])
(f 3))
(c)))
(ctest/rewrite 1
'case->-regular
(let ([c (counter)])
(letrec ([f
(contract (case-> (-> any/c c)
(-> any/c any/c c))
(case-lambda
[(x) (if (zero? x) x (f (- x 1)))]
[(x y) (f x)])
'pos
'neg)])
(f 4 1))
(c)))
(ctest/rewrite 1
'case->-rest-args
(let ([c (counter)])
(letrec ([f
(contract (case-> (-> any/c #:rest any/c c)
(-> any/c any/c #:rest any/c c))
(case-lambda
[(x) (f x 1)]
[(x y . z) (if (zero? x) x (apply f (- x 1) y (list y y)))])
'pos
'neg)])
(f 4))
(c)))
(ctest/rewrite '(1)
'mut-rec-with-any/c
(let ()
(define f
(contract (-> number? any/c)
(lambda (x)
(if (zero? x)
(continuation-mark-set->list (current-continuation-marks) 'tail-test)
(with-continuation-mark 'tail-test x
(g (- x 1)))))
'something-that-is-not-pos
'neg))
(define g
(contract (-> number? any/c)
(lambda (x)
(f x))
'also-this-is-not-pos
'neg))
(f 3)))
(test/pos-blame
'different-blame=>cannot-drop-check
'((contract (-> integer? integer?)
(λ (x)
((contract (-> integer? integer?)
(λ (x) #f)
'pos
'neg)
x))
'abc
'def)
5))
(test/pos-blame 'free-vars-change-so-cannot-drop-the-check
'(let ()