add contract-pos/neg-doubling and use it in various places

This commit is contained in:
Robby Findler 2018-04-28 19:48:02 -05:00
parent 96b69d0366
commit ff588f93eb
12 changed files with 652 additions and 168 deletions

View File

@ -2374,6 +2374,43 @@ of the @tech{blame object} and the missing party should be used instead.
@history[#:added "6.4.0.4"]
}
@defform[(contract-pos/neg-doubling e1 e2)]{
Some contract combinators need to build projections for
subcontracts with both regular and @racket[blame-swap]ed
versions of the blame that they are given in order to check
both access and mutations (e.g., @racket[vector/c] and
@racket[vectorof]). In the case that such combinators are
nested deeply inside each other, there is a potential for an
exponential explosion of nested projections being built.
To avoid that explosion, wrap each of the calls to the
blame-accepting portion of the combinator in
@racket[contract-pos/neg-doubling]. It returns three values.
The first is a boolean, indicating how to interpret the
other two results. If the boolean is @racket[#t], then the
other two results are the values of @racket[e1] and
@racket[e2] and we are not too deep in the nesting. If the
boolean is @racket[#f], then we have passed a threshold and
it is not safe to evaluate @racket[e1] and @racket[e2] yet,
as we are in danger of running into the exponential
slowdown. In that case, the last two results are thunks
that, when invoked, compute the values of @racket[e1] and
@racket[e2].
As an example, @racket[vectorof] uses
@racket[contract-pos/neg-doubling] wrapping its two calls to
the blame-accepting part of the projection for its
subcontract. When it receives a @racket[#f] as that first
boolean, it does not invoke the thunks right away, but waits
until the interposition procedure that it attaches to the
chaperoned vector is called. Then it invokes them (and caches
the result). This delays the construction of the projections
until they are actually needed, avoiding the exponential blowup.
@history[#:added "6.90.0.27"]
}
@subsection{Blame Objects}
This section describes @deftech{blame objects} and operations on them.

View File

@ -75,6 +75,27 @@
'box/c12
'(set-box! (contract (box/c integer?) (box 1) 'pos 'neg) 1.5))
(test/pos-blame
'box/c13
'(let ()
(define N 18)
(define c
(for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(box/c c)))
(define val
(for/fold ([val 5])
([i (in-range N)])
(box val)))
(define cval (contract c val 'pos 'neg))
(for/fold ([val cval])
([i (in-range N)])
(unbox val))))
;; contract-stronger? tests
(contract-eval '(require (only-in racket/contract/combinator contract-stronger?)))

View File

@ -1593,6 +1593,31 @@
(inherit-field f)
(define/public (m) f))])
(send (new d%) m)))
(test/pos-blame
'inherit-field-lots-of-wrappers
'(let ()
(define N 40)
(define c
(for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(class/c (inherit-field [fld c]))))
(define val
(for/fold ([val 5])
([i (in-range N)])
(class object% (field [fld val]) (super-new))))
(define cval (contract c val 'pos 'neg))
(for/fold ([val cval])
([i (in-range N)])
(send (new (class val
(super-new)
(inherit-field fld)
(define/public (m) fld)))
m))))
(test/spec-passed
'class/c-higher-order-override-1
@ -2087,6 +2112,49 @@
'somethingelse1 'somethingelse2)
'pos 'neg)
[x 2]))
(test/pos-blame
'class/c-deep.1
'(let ()
(define N 40)
(define c
(for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(class/c (field [fld c]))))
(define v
(for/fold ([v 1])
([i (in-range N)])
(class object%
(field [fld v])
(super-new))))
(let loop ([v (contract c v 'pos 'neg)])
(loop (get-field fld (new v))))))
(test/neg-blame
'class/c-deep.2
'(let ()
(define N 40)
(define c
(for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(class/c (field [fld c]))))
(define v
(for/fold ([v 1])
([i (in-range N)])
(class object%
(field [fld v])
(super-new))))
(let loop ([v (contract c v 'pos 'neg)]
[i N])
(cond
[(= i 1) (set-field! fld (new v) 'not-a-proc)]
[else (loop (get-field fld (new v)) (- i 1))]))))
(test/spec-passed/result
'class-field-accessor1

View File

@ -235,6 +235,21 @@
c-h))
#t)
(test/pos-blame
'hash/c18
'(let ()
(define N 40)
(define c
(for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(hash/c c integer?)))
(define h
(for/fold ([h 0])
([i (in-range N)])
(hash h i)))
(immutable? h)
(void (contract c h 'pos 'neg))))
(test/pos-blame
'hash/dc1

View File

@ -283,6 +283,51 @@
(send x3 p)))
(test/pos-blame
'object/c-lots-of-wrapping.1
'(let ()
(define N 40)
(define c
(for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(object/c (field [fld c]))))
(define o
(for/fold ([v 'not-a-proc])
([i (in-range N)])
(new
(class object%
(field [fld v])
(super-new)))))
(let loop ([o (contract c o 'pos 'neg)])
(loop (get-field fld o)))))
(test/neg-blame
'object/c-lots-of-wrapping.2
'(let ()
(define N 40)
(define c
(for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(object/c (field [fld c]))))
(define o
(for/fold ([v add1])
([i (in-range N)])
(new
(class object%
(field [fld v])
(super-new)))))
(let loop ([o (contract c o 'pos 'neg)]
[i N])
(cond
[(= i 1) (set-field! fld o 'not-a-proc)]
[else (loop (get-field fld o) (- i 1))]))))
(test/spec-passed
'object/c-just-check-existence
'(contract (object/c m)

View File

@ -86,6 +86,42 @@
'(contract (vectorof integer? #:flat? #t)
(vector-immutable 11)
'pos 'neg))
(test/pos-blame
'vectorof13
'(let ()
(define N 40)
(define cv
(contract (for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(vectorof c))
(for/fold ([v 'not-a-procedure])
([i (in-range N)])
(vector v))
'pos 'neg))
(let loop ([cv cv])
(loop (vector-ref cv 0)))))
(test/neg-blame
'vectorof14
'(let ()
(define N 40)
(define cv
(contract (for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(vectorof c))
(for/fold ([v add1])
([i (in-range N)])
(vector v))
'pos 'neg))
(let loop ([cv cv]
[i N])
(cond
[(= i 1)
(vector-set! cv 0 'not-a-procedure)]
[else
(loop (vector-ref cv 0)
(- i 1))]))))
(test/spec-passed
'vector/c1
@ -126,6 +162,57 @@
(λ (vec i v) v))])
(vector-set! (contract (vector/c integer?) v 'pos 'neg)
0 #f)))
(test/pos-blame
'vector/c7
'(let ()
(define N 40)
(define cv
(contract (for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(vector/c c))
(for/fold ([v 'not-a-procedure])
([i (in-range N)])
(vector v))
'pos 'neg))
(let loop ([cv cv])
(loop (vector-ref cv 0)))))
(test/pos-blame
'vector/c8
'(let ()
(define N 40)
(define cv
(contract (for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(vector/c c))
(for/fold ([v 'not-a-procedure])
([i (in-range N)])
(vector-immutable v))
'pos 'neg))
(let loop ([cv cv])
(loop (vector-ref cv 0)))))
(test/neg-blame
'vector/c9
'(let ()
(define N 40)
(define cv
(contract (for/fold ([c (-> integer? integer?)])
([i (in-range N)])
(vector/c c))
(for/fold ([v add1])
([i (in-range N)])
(vector v))
'pos 'neg))
(let loop ([cv cv]
[i N])
(cond
[(= i 1)
(vector-set! cv 0 'not-a-procedure)]
[else
(loop (vector-ref cv 0)
(- i 1))]))))
(test/pos-blame
'vector/c7

View File

@ -105,7 +105,9 @@
[-make-flat-contract make-flat-contract]
[-build-chaperone-contract-property build-chaperone-contract-property]
[-build-flat-contract-property build-flat-contract-property])
skip-projection-wrapper?)
skip-projection-wrapper?
contract-pos/neg-doubling)
(define skip-projection-wrapper? (make-parameter #f))

View File

@ -137,29 +137,45 @@
(define r-vfp (get/build-late-neg-projection elem-r-ctc))
(λ (blame)
(define box-blame (add-box-context blame))
(define pos-elem-r-proj (r-vfp box-blame))
(define neg-elem-w-proj (w-vfp (blame-swap box-blame)))
(λ (val neg-party)
(define blame+neg-party (cons blame neg-party))
(cond
[(check-box/c-np ctc val blame)
=>
(λ (f) (f neg-party))]
[else
(if (and (immutable? val) (not (chaperone? val)))
(box-immutable (pos-elem-r-proj (unbox val) neg-party))
(chaperone/impersonate-box
val
(λ (b v)
(with-contract-continuation-mark
blame+neg-party
(pos-elem-r-proj v neg-party)))
(λ (b v)
(with-contract-continuation-mark
blame+neg-party
(neg-elem-w-proj v neg-party)))
impersonator-prop:contracted ctc
impersonator-prop:blame (blame-add-missing-party blame neg-party)))])))))
(define-values (filled? maybe-pos-elem-r-proj maybe-neg-elem-w-proj)
(contract-pos/neg-doubling (r-vfp box-blame)
(w-vfp (blame-swap box-blame))))
(define (make-val-np/proc pos-elem-r-proj neg-elem-w-proj)
(λ (val neg-party)
(define blame+neg-party (cons blame neg-party))
(cond
[(check-box/c-np ctc val blame)
=>
(λ (f) (f neg-party))]
[else
(if (and (immutable? val) (not (chaperone? val)))
(box-immutable (pos-elem-r-proj (unbox val) neg-party))
(chaperone/impersonate-box
val
(λ (b v)
(with-contract-continuation-mark
blame+neg-party
(pos-elem-r-proj v neg-party)))
(λ (b v)
(with-contract-continuation-mark
blame+neg-party
(neg-elem-w-proj v neg-party)))
impersonator-prop:contracted ctc
impersonator-prop:blame (blame-add-missing-party blame neg-party)))])))
(cond
[filled?
(make-val-np/proc maybe-pos-elem-r-proj maybe-neg-elem-w-proj)]
[else
(define tc (make-thread-cell #f))
(λ (val neg-party)
(cond
[(thread-cell-ref tc)
=>
(λ (f) (f val neg-party))]
[else
(define proc (make-val-np/proc (maybe-pos-elem-r-proj) (maybe-neg-elem-w-proj)))
(thread-cell-set! tc proc)
(proc val neg-party)]))]))))
(define-struct (chaperone-box/c base-box/c) ()
#:property prop:custom-write custom-write-property-proc

View File

@ -84,7 +84,9 @@
n->th
false/c-contract
true/c-contract)
true/c-contract
contract-pos/neg-doubling)
(define (contract-custom-write-property-proc stct port mode)
(define (write-prefix)
@ -877,3 +879,20 @@
[(2) "nd"]
[(3) "rd"]
[else "th"])))
(define-syntax-rule
(contract-pos/neg-doubling e1 e2)
(contract-pos/neg-doubling/proc (λ () e1) (λ () e2)))
(define doubling-cm-key (gensym 'racket/contract-doubling-mark))
(define (contract-pos/neg-doubling/proc t1 t2)
(define depth
(or (continuation-mark-set-first (current-continuation-marks)
doubling-cm-key)
0))
(cond
[(> depth 5)
(values #f t1 t2)]
[else
(with-continuation-mark doubling-cm-key (+ depth 1)
(values #t (t1) (t2)))]))

View File

@ -81,9 +81,6 @@
;; ... --> boolean
;; returns #t when it called raise-blame-error, #f otherwise
(define (check-hash/c dom-ctc immutable flat? val blame neg-party)
;(define dom-ctc (base-hash/c-dom ctc))
;(define immutable (base-hash/c-immutable ctc))
;(define flat? (flat-hash/c? ctc))
(cond
[(hash? val)
(cond
@ -215,18 +212,46 @@
(define dom-proc (get/build-late-neg-projection dom-ctc))
(define rng-proc (get/build-late-neg-projection (base-hash/c-rng ctc)))
(λ (blame)
(define pos-dom-proj (dom-proc (blame-add-key-context blame #f)))
(define neg-dom-proj (dom-proc (blame-add-key-context blame #t)))
(define pos-rng-proj (rng-proc (blame-add-value-context blame #f)))
(define neg-rng-proj (rng-proc (blame-add-value-context blame #t)))
(λ (val neg-party)
(cond
[(check-hash/c dom-ctc immutable flat? val blame neg-party)
val]
[else
(handle-the-hash val neg-party
pos-dom-proj neg-dom-proj (λ (v) pos-rng-proj) (λ (v) neg-rng-proj)
chaperone-or-impersonate-hash ctc blame)])))))
(define-values (dom-filled? maybe-pos-dom-proj maybe-neg-dom-proj)
(contract-pos/neg-doubling (dom-proc (blame-add-key-context blame #f))
(dom-proc (blame-add-key-context blame #t))))
(define-values (rng-filled? maybe-pos-rng-proj maybe-neg-rng-proj)
(contract-pos/neg-doubling (rng-proc (blame-add-value-context blame #f))
(rng-proc (blame-add-value-context blame #t))))
(cond
[(and dom-filled? rng-filled?)
(λ (val neg-party)
(cond
[(check-hash/c dom-ctc immutable flat? val blame neg-party)
val]
[else
(handle-the-hash val neg-party
maybe-pos-dom-proj maybe-neg-dom-proj
(λ (v) maybe-pos-rng-proj) (λ (v) maybe-neg-rng-proj)
chaperone-or-impersonate-hash ctc blame)]))]
[else
(define tc (make-thread-cell #f))
(λ (val neg-party)
(define-values (pos-dom-proj neg-dom-proj pos-rng-proj neg-rng-proj)
(cond
[(thread-cell-ref tc)
=>
(λ (v) (values (vector-ref v 1) (vector-ref v 2) (vector-ref v 3) (vector-ref v 4)))]
[else
(define pos-dom-proj (maybe-pos-dom-proj))
(define neg-dom-proj (maybe-neg-dom-proj))
(define pos-rng-proj (maybe-pos-rng-proj))
(define neg-rng-proj (maybe-neg-rng-proj))
(thread-cell-set! tc (vector pos-dom-proj neg-dom-proj pos-rng-proj neg-rng-proj))
(values pos-dom-proj neg-dom-proj pos-rng-proj neg-rng-proj)]))
(cond
[(check-hash/c dom-ctc immutable flat? val blame neg-party)
val]
[else
(handle-the-hash val neg-party
pos-dom-proj neg-dom-proj
(λ (v) pos-rng-proj) (λ (v) neg-rng-proj)
chaperone-or-impersonate-hash ctc blame)]))]))))
(define (blame-add-key-context blame swap?) (blame-add-context blame "the keys of" #:swap? swap?))
(define (blame-add-value-context blame swap?) (blame-add-context blame "the values of" #:swap? swap?))

View File

@ -147,7 +147,7 @@
(define (blame-add-element-of-context blame #:swap? [swap? #f])
(blame-add-context blame "an element of" #:swap? swap?))
(define (vectorof-late-neg-ho-projection chaperone-or-impersonate-vector)
(λ (ctc)
(define elem-ctc (base-vectorof-elem ctc))
@ -158,20 +158,54 @@
(define pos-blame (blame-add-element-of-context blame))
(define neg-blame (blame-add-element-of-context blame #:swap? #t))
(define vfp (get/build-late-neg-projection elem-ctc))
(define elem-pos-proj (vfp pos-blame))
(define elem-neg-proj (vfp neg-blame))
(define checked-ref (λ (neg-party)
(define blame+neg-party (cons pos-blame neg-party))
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
(elem-pos-proj val neg-party)))))
(define checked-set (λ (neg-party)
(define blame+neg-party (cons neg-blame neg-party))
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
(elem-neg-proj val neg-party)))))
(define-values (filled? elem-pos-proj elem-neg-proj)
(contract-pos/neg-doubling (vfp pos-blame) (vfp neg-blame)))
(define-values (checked-ref checked-set)
(cond
[filled?
(define checked-ref (λ (neg-party)
(define blame+neg-party (cons pos-blame neg-party))
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
(elem-pos-proj val neg-party)))))
(define checked-set (λ (neg-party)
(define blame+neg-party (cons neg-blame neg-party))
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
(elem-neg-proj val neg-party)))))
(values checked-ref checked-set)]
[else
(define ref-tc (make-thread-cell #f))
(define set-tc (make-thread-cell #f))
(define checked-ref (λ (neg-party)
(define blame+neg-party (cons pos-blame neg-party))
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
(define real-elem-pos-proj
(cond
[(thread-cell-ref ref-tc) => values]
[else
(define real-elem-pos-proj (elem-pos-proj))
(thread-cell-set! ref-tc real-elem-pos-proj)
real-elem-pos-proj]))
(real-elem-pos-proj val neg-party)))))
(define checked-set (λ (neg-party)
(define blame+neg-party (cons neg-blame neg-party))
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
(define real-elem-neg-proj
(cond
[(thread-cell-ref set-tc) => values]
[else
(define real-elem-neg-proj (elem-neg-proj))
(thread-cell-set! set-tc real-elem-neg-proj)
real-elem-neg-proj]))
(real-elem-neg-proj val neg-party)))))
(values checked-ref checked-set)]))
(cond
[(flat-contract? elem-ctc)
(define p? (flat-contract-predicate elem-ctc))
@ -181,35 +215,39 @@
(check val raise-blame #f)
;; avoid traversing large vectors
;; unless `eager` is specified
(if (and (or (equal? eager #t)
(and eager (<= (vector-length val) eager)))
(immutable? val)
(not (chaperone? val)))
(begin (for ([e (in-vector val)])
(unless (p? e)
(elem-pos-proj e neg-party)))
val)
(chaperone-or-impersonate-vector
val
(checked-ref neg-party)
(checked-set neg-party)
impersonator-prop:contracted ctc
impersonator-prop:blame (blame-add-missing-party blame neg-party))))]
(cond
[(and (or (equal? eager #t)
(and eager (<= (vector-length val) eager)))
(immutable? val)
(not (chaperone? val)))
(for ([e (in-vector val)])
(unless (p? e)
(elem-pos-proj e neg-party)))
val]
[else
(chaperone-or-impersonate-vector
val
(checked-ref neg-party)
(checked-set neg-party)
impersonator-prop:contracted ctc
impersonator-prop:blame (blame-add-missing-party blame neg-party))]))]
[else
(λ (val neg-party)
(λ (val neg-party)
(define (raise-blame val . args)
(apply raise-blame-error blame #:missing-party neg-party val args))
(check val raise-blame #f)
(if (and (immutable? val) (not (chaperone? val)))
(vector->immutable-vector
(for/vector #:length (vector-length val) ([e (in-vector val)])
(elem-pos-proj e neg-party)))
(chaperone-or-impersonate-vector
val
(checked-ref neg-party)
(checked-set neg-party)
impersonator-prop:contracted ctc
impersonator-prop:blame (blame-add-missing-party blame neg-party))))]))))
(cond
[(and (immutable? val) (not (chaperone? val)))
(vector->immutable-vector
(for/vector #:length (vector-length val) ([e (in-vector val)])
(elem-pos-proj e neg-party)))]
[else
(chaperone-or-impersonate-vector
val
(checked-ref neg-party)
(checked-set neg-party)
impersonator-prop:contracted ctc
impersonator-prop:blame (blame-add-missing-party blame neg-party))]))]))))
(define-values (prop:neg-blame-party prop:neg-blame-party? prop:neg-blame-party-get)
(make-impersonator-property 'prop:neg-blame-party))
@ -250,7 +288,10 @@
'racket/contract:contract
(vector this-one (list #'vecof) null))))]))
(define/subexpression-pos-prop (vectorof c #:immutable [immutable 'dont-care] #:flat? [flat? #f] #:eager [eager #t])
(define/subexpression-pos-prop (vectorof c
#:immutable [immutable 'dont-care]
#:flat? [flat? #f]
#:eager [eager #t])
(define ctc
(if flat?
(coerce-flat-contract 'vectorof c)
@ -398,37 +439,71 @@
(let ([elem-ctcs (base-vector/c-elems ctc)]
[immutable (base-vector/c-immutable ctc)])
(λ (blame)
(let ([elem-pos-projs (for/vector #:length (length elem-ctcs)
([c (in-list elem-ctcs)]
[i (in-naturals)])
((get/build-late-neg-projection c)
(blame-add-context blame (format "the ~a element of" (n->th i)))))]
[elem-neg-projs (for/vector #:length (length elem-ctcs)
([c (in-list elem-ctcs)]
[i (in-naturals)])
((get/build-late-neg-projection c)
(blame-add-context blame (format "the ~a element of" (n->th i))
#:swap? #t)))])
(λ (val neg-party)
(check-vector/c ctc val blame neg-party)
(define blame+neg-party (cons blame neg-party))
(if (and (immutable? val) (not (chaperone? val)))
(apply vector-immutable
(for/list ([e (in-vector val)]
[i (in-naturals)])
((vector-ref elem-pos-projs i) e neg-party)))
(vector-wrapper
val
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
((vector-ref elem-pos-projs i) val neg-party)))
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
((vector-ref elem-neg-projs i) val neg-party)))
impersonator-prop:contracted ctc
impersonator-prop:blame blame))))))))
(define-values (filled? maybe-elem-pos-projs maybe-elem-neg-projs)
(contract-pos/neg-doubling
(for/vector #:length (length elem-ctcs)
([c (in-list elem-ctcs)]
[i (in-naturals)])
((get/build-late-neg-projection c)
(blame-add-context blame (format "the ~a element of" (n->th i)))))
(for/vector #:length (length elem-ctcs)
([c (in-list elem-ctcs)]
[i (in-naturals)])
((get/build-late-neg-projection c)
(blame-add-context blame (format "the ~a element of" (n->th i))
#:swap? #t)))))
(cond
[filled?
(λ (val neg-party)
(check-vector/c ctc val blame neg-party)
(define blame+neg-party (cons blame neg-party))
(if (and (immutable? val) (not (chaperone? val)))
(apply vector-immutable
(for/list ([e (in-vector val)]
[i (in-naturals)])
((vector-ref maybe-elem-pos-projs i) e neg-party)))
(vector-wrapper
val
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
((vector-ref maybe-elem-pos-projs i) val neg-party)))
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
((vector-ref maybe-elem-neg-projs i) val neg-party)))
impersonator-prop:contracted ctc
impersonator-prop:blame blame)))]
[else
(define pos-tc (make-thread-cell #f))
(define neg-tc (make-thread-cell #f))
(define (get-projs tc get-ele-projs)
(cond
[(thread-cell-ref tc) => values]
[else
(define projs (get-ele-projs))
(thread-cell-set! tc projs)
projs]))
(λ (val neg-party)
(check-vector/c ctc val blame neg-party)
(define blame+neg-party (cons blame neg-party))
(if (and (immutable? val) (not (chaperone? val)))
(apply vector-immutable
(for/list ([e (in-vector val)]
[i (in-naturals)])
((vector-ref (get-projs pos-tc maybe-elem-pos-projs) i) e neg-party)))
(vector-wrapper
val
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
((vector-ref (get-projs pos-tc maybe-elem-pos-projs) i) val neg-party)))
(λ (vec i val)
(with-contract-continuation-mark
blame+neg-party
((vector-ref (get-projs neg-tc maybe-elem-neg-projs) i) val neg-party)))
impersonator-prop:contracted ctc
impersonator-prop:blame blame)))])))))
(define-struct (chaperone-vector/c base-vector/c) ()
#:property prop:custom-write custom-write-property-proc

View File

@ -177,27 +177,50 @@
[c (in-list (class/c-method-contracts ctc))])
(and c
((contract-late-neg-projection c) (blame-add-method-context blame name)))))
(define external-field-projections
(for/list ([f (in-list (class/c-fields ctc))]
[c (in-list (class/c-field-contracts ctc))])
(define pos-blame (blame-add-field-context blame f #:swap? #f))
(define neg-blame (blame-add-field-context blame f #:swap? #t))
(and c
(let ([p-pos ((contract-late-neg-projection c)
pos-blame)]
[p-neg ((contract-late-neg-projection c)
neg-blame)])
(cons (lambda (x pos-party)
(define blame+pos-party (cons pos-blame pos-party))
(with-contract-continuation-mark
blame+pos-party
(cond
[c
(define-values (filled? maybe-p-pos maybe-p-neg)
(contract-pos/neg-doubling ((contract-late-neg-projection c) pos-blame)
((contract-late-neg-projection c) neg-blame)))
(cond
[filled?
(cons (lambda (x pos-party)
(define blame+pos-party (cons pos-blame pos-party))
(with-contract-continuation-mark
blame+pos-party
(maybe-p-pos x pos-party)))
(lambda (x neg-party)
(define blame+neg-party (cons neg-blame neg-party))
(with-contract-continuation-mark
blame+neg-party
(maybe-p-neg x neg-party))))]
[else
(define tc-pos (make-thread-cell #f))
(define tc-neg (make-thread-cell #f))
(cons (lambda (x pos-party)
(define blame+pos-party (cons pos-blame pos-party))
(with-contract-continuation-mark
blame+pos-party
(define p-pos (or (thread-cell-ref tc-pos)
(let ([p-pos (maybe-p-pos)])
(thread-cell-set! tc-pos p-pos)
p-pos)))
(p-pos x pos-party)))
(lambda (x neg-party)
(define blame+neg-party (cons neg-blame neg-party))
(with-contract-continuation-mark
blame+neg-party
(p-neg x neg-party))))))))
(lambda (x neg-party)
(define blame+neg-party (cons neg-blame neg-party))
(with-contract-continuation-mark
blame+neg-party
(define p-neg (or (thread-cell-ref tc-neg)
(let ([p-neg (maybe-p-neg)])
(thread-cell-set! tc-neg p-neg)
p-neg)))
(p-neg x neg-party))))])]
[else #f])))
;; zip the inits and contracts together for ordered selection
(define inits+contracts
@ -439,20 +462,52 @@
(define internal-field-projections
(for/list ([f (in-list (internal-class/c-inherit-fields internal-ctc))]
[c (in-list (internal-class/c-inherit-field-contracts internal-ctc))])
(and c
(let* ([blame-acceptor (contract-late-neg-projection c)]
[p-pos (blame-acceptor blame)]
[p-neg (blame-acceptor bswap)])
(cons (lambda (x pos-party)
(define blame+pos-party (cons blame pos-party))
(with-contract-continuation-mark
blame+pos-party
(cond
[c
(define blame-acceptor (contract-late-neg-projection c))
(define-values (filled? maybe-p-pos maybe-p-neg)
(contract-pos/neg-doubling (blame-acceptor blame)
(blame-acceptor bswap)))
(cond
[filled?
(cons (lambda (x pos-party)
(define blame+pos-party (cons blame pos-party))
(with-contract-continuation-mark
blame+pos-party
(maybe-p-pos x pos-party)))
(lambda (x neg-party)
(define blame+neg-party (cons blame neg-party))
(with-contract-continuation-mark
blame+neg-party
(maybe-p-neg x neg-party))))]
[else
(define tc-pos (make-thread-cell #f))
(define tc-neg (make-thread-cell #f))
(cons (lambda (x pos-party)
(define blame+pos-party (cons blame pos-party))
(with-contract-continuation-mark
blame+pos-party
(define p-pos
(cond
[(thread-cell-ref tc-pos) => values]
[else
(define p-pos (maybe-p-pos))
(thread-cell-set! tc-pos p-pos)
p-pos]))
(p-pos x pos-party)))
(lambda (x neg-party)
(define blame+neg-party (cons blame neg-party))
(with-contract-continuation-mark
blame+neg-party
(p-neg x neg-party))))))))
(lambda (x neg-party)
(define blame+neg-party (cons blame neg-party))
(with-contract-continuation-mark
blame+neg-party
(define p-neg
(cond
[(thread-cell-ref tc-neg) => values]
[else
(define p-neg (maybe-p-neg))
(thread-cell-set! tc-neg p-neg)
p-neg]))
(p-neg x neg-party))))])]
[else #f])))
(define override-projections
(for/list ([m (in-list (internal-class/c-overrides internal-ctc))]
@ -1602,16 +1657,24 @@
((contract-late-neg-projection c) blame*)]
[else #f])))
(define pos/neg-field-projs
(for/list ([f (in-list fields)]
[c (in-list field-contracts)])
(cond
[(just-check-existence? c) #f]
[else
(define prj (contract-late-neg-projection c))
(vector
(prj (blame-add-field-context blame f #:swap? #f))
(prj (blame-add-field-context blame f #:swap? #t)))])))
(define-values (filled? maybe-pos-field-projs maybe-neg-field-projs)
(contract-pos/neg-doubling
(for/list ([f (in-list fields)]
[c (in-list field-contracts)])
(cond
[(just-check-existence? c) #f]
[else
(define prj (contract-late-neg-projection c))
(prj (blame-add-field-context blame f #:swap? #f))]))
(for/list ([f (in-list fields)]
[c (in-list field-contracts)])
(cond
[(just-check-existence? c) #f]
[else
(define prj (contract-late-neg-projection c))
(prj (blame-add-field-context blame f #:swap? #t))]))))
(define tc (and (not filled?) (make-thread-cell #f)))
(λ (cls neg-party)
(let* ([name (class-name cls)]
@ -1712,25 +1775,36 @@
(when method-proj
(define i (hash-ref method-ht m))
(vector-set! meths i (make-method (method-proj (vector-ref meths i) neg-party) m))))))
;; Handle external field contracts
(unless (null? fields)
(for ([f (in-list fields)]
[c (in-list field-contracts)]
[pos/neg-field-proj (in-list pos/neg-field-projs)])
(unless (just-check-existence? c)
(define fi (hash-ref field-ht f))
(define p-pos (vector-ref pos/neg-field-proj 0))
(define p-neg (vector-ref pos/neg-field-proj 1))
(hash-set! field-ht f (field-info-extend-external fi
(lambda args
(with-contract-continuation-mark
(cons blame neg-party)
(apply p-pos args)))
(lambda args
(with-contract-continuation-mark
(cons blame neg-party)
(apply p-neg args)))
neg-party)))))
(define (install-new-fields pos-field-projs neg-field-projs)
(for ([f (in-list fields)]
[c (in-list field-contracts)]
[p-pos (in-list pos-field-projs)]
[p-neg (in-list neg-field-projs)])
(unless (just-check-existence? c)
(define fi (hash-ref field-ht f))
(hash-set! field-ht f (field-info-extend-external
fi
(lambda args
(with-contract-continuation-mark
(cons blame neg-party)
(apply p-pos args)))
(lambda args
(with-contract-continuation-mark
(cons blame neg-party)
(apply p-neg args)))
neg-party)))))
(cond
[filled? (install-new-fields maybe-pos-field-projs maybe-neg-field-projs)]
[(thread-cell-ref tc)
=>
(λ (pr) (install-new-fields (car pr) (cdr pr)))]
[else
(define pos-field-projs (maybe-pos-field-projs))
(define neg-field-projs (maybe-neg-field-projs))
(thread-cell-set! tc (cons pos-field-projs neg-field-projs))
(install-new-fields pos-field-projs neg-field-projs)]))
(copy-seals cls c))))