adjust implementation of recursive contract to cope with
the fact that blame object equality now works right and
adding context to a blame object doesn't produce an equal?
blame object
also it appears that blame-add-unknown-context is not actually
being called so lets just get rid of that functionality
(but preserve reasonable backwards compatibility in
case someone is actually calling that function or
supplying #f to blame-add-context)
And the interning of blame objects was not intended to be
in 0b3f4b627e
, so get rid of it here
closes racket/typed-racket#722
This commit is contained in:
parent
4b2a202640
commit
be7fe82ea8
|
@ -2526,13 +2526,13 @@ The @racket[swap?] argument has the effect of calling @racket[blame-swap]
|
||||||
while adding the layer of context, but without creating an extra
|
while adding the layer of context, but without creating an extra
|
||||||
@|blame-object|.
|
@|blame-object|.
|
||||||
|
|
||||||
The context information recorded in blame structs keeps track of
|
|
||||||
combinators that do not add information, and add the string @racket["..."]
|
Passing @racket[#f] as the context string argument is no longer relevant.
|
||||||
for them, so programmers at least see that there was some context
|
For backwards compatibility, @racket[blame-add-context] returns @racket[b]
|
||||||
they are missing in the error messages. Accordingly, since there are
|
when @racket[context] is @racket[#f].
|
||||||
combinators that should not add any context (e.g., @racket[recursive-contract]),
|
|
||||||
passing @racket[#f] as the context string argument avoids adding the
|
@history[#:changed "6.90.0.29" @elem{The @racket[context] argument being
|
||||||
@racket["..."] string.
|
@racket[#f] is no longer relevant.}]
|
||||||
}
|
}
|
||||||
|
|
||||||
@defproc[(blame-context [blame blame?]) (listof string?)]{
|
@defproc[(blame-context [blame blame?]) (listof string?)]{
|
||||||
|
|
|
@ -85,6 +85,15 @@
|
||||||
'(letrec ([ctc (or/c number? (cons/c number? (recursive-contract ctc #:flat #:extra-delay)))])
|
'(letrec ([ctc (or/c number? (cons/c number? (recursive-contract ctc #:flat #:extra-delay)))])
|
||||||
(contract ctc (cons 1 (cons 2 'not-a-number)) 'pos 'neg)))
|
(contract ctc (cons 1 (cons 2 'not-a-number)) 'pos 'neg)))
|
||||||
|
|
||||||
|
(test/spec-passed/result
|
||||||
|
'recursive-contract14
|
||||||
|
'(let ()
|
||||||
|
(define c (recursive-contract (or/c integer? (cons/c c integer?))))
|
||||||
|
(void (contract (-> c any/c) void 'p 'n))
|
||||||
|
((contract (-> c any/c) values 'p 'n) '(1 . 2)))
|
||||||
|
'(1 . 2))
|
||||||
|
|
||||||
|
|
||||||
(test/spec-passed/result
|
(test/spec-passed/result
|
||||||
'memoize-applied-blame
|
'memoize-applied-blame
|
||||||
'(let ()
|
'(let ()
|
||||||
|
|
|
@ -170,6 +170,7 @@
|
||||||
#`(#,maker '#,stx
|
#`(#,maker '#,stx
|
||||||
(λ () #,arg)
|
(λ () #,arg)
|
||||||
'#,(syntax-local-infer-name stx)
|
'#,(syntax-local-infer-name stx)
|
||||||
|
'recursive-contract-val->lnp-not-yet-initialized
|
||||||
#,(if list-contract? #'#t #'#f)
|
#,(if list-contract? #'#t #'#f)
|
||||||
#,@(if (equal? (syntax-e type) '#:flat)
|
#,@(if (equal? (syntax-e type) '#:flat)
|
||||||
(list (if extra-delay? #'#t #'#f))
|
(list (if extra-delay? #'#t #'#f))
|
||||||
|
@ -207,6 +208,7 @@
|
||||||
(unless (list-contract? forced-ctc)
|
(unless (list-contract? forced-ctc)
|
||||||
(raise-argument-error 'recursive-contract "list-contract?" forced-ctc)))
|
(raise-argument-error 'recursive-contract "list-contract?" forced-ctc)))
|
||||||
(set-recursive-contract-ctc! ctc forced-ctc)
|
(set-recursive-contract-ctc! ctc forced-ctc)
|
||||||
|
(set-recursive-contract-blame->val-np->val! ctc (make-blame->val-np->val ctc))
|
||||||
(when (and (pair? old-name) (pair? (cdr old-name)))
|
(when (and (pair? old-name) (pair? (cdr old-name)))
|
||||||
;; this guard will be #f when we are forcing this contract
|
;; this guard will be #f when we are forcing this contract
|
||||||
;; in a nested which (which can make the `cddr` below fail)
|
;; in a nested which (which can make the `cddr` below fail)
|
||||||
|
@ -217,33 +219,48 @@
|
||||||
forced-ctc]
|
forced-ctc]
|
||||||
[else current]))
|
[else current]))
|
||||||
|
|
||||||
(define (recursive-contract-late-neg-projection ctc)
|
(define (make-blame->val-np->val ctc)
|
||||||
(cond
|
(define list-check? (recursive-contract-list-contract? ctc))
|
||||||
[(recursive-contract-list-contract? ctc)
|
(define blame-accepting-func-cell (make-thread-cell #f))
|
||||||
(λ (blame)
|
(define (do-list-check val neg-party blame-known)
|
||||||
(define r-ctc (force-recursive-contract ctc))
|
(when list-check?
|
||||||
(define f (get/build-late-neg-projection r-ctc))
|
|
||||||
(define blame-known (blame-add-context blame #f))
|
|
||||||
(define f-blame-known (make-thread-cell #f))
|
|
||||||
(λ (val neg-party)
|
|
||||||
(unless (list? val)
|
(unless (list? val)
|
||||||
(raise-blame-error blame-known #:missing-party neg-party
|
(raise-blame-error blame-known #:missing-party neg-party
|
||||||
val
|
val
|
||||||
'(expected: "list?" given: "~e")
|
'(expected: "list?" given: "~e")
|
||||||
val))
|
val))))
|
||||||
(unless (thread-cell-ref f-blame-known)
|
|
||||||
(thread-cell-set! f-blame-known (f blame-known)))
|
|
||||||
((thread-cell-ref f-blame-known) val neg-party)))]
|
|
||||||
[else
|
|
||||||
(λ (blame)
|
(λ (blame)
|
||||||
|
(cond
|
||||||
|
[(thread-cell-ref blame-accepting-func-cell)
|
||||||
|
=>
|
||||||
|
(λ (blame-accepting-func) (blame-accepting-func blame))]
|
||||||
|
[else
|
||||||
(define r-ctc (force-recursive-contract ctc))
|
(define r-ctc (force-recursive-contract ctc))
|
||||||
(define f (get/build-late-neg-projection r-ctc))
|
(define f (get/build-late-neg-projection r-ctc))
|
||||||
(define blame-known (blame-add-context blame #f))
|
(define val-neg-party-acceptor (make-thread-cell #f))
|
||||||
(define f-blame-known (make-thread-cell #f))
|
|
||||||
(λ (val neg-party)
|
(λ (val neg-party)
|
||||||
(unless (thread-cell-ref f-blame-known)
|
(cond
|
||||||
(thread-cell-set! f-blame-known (f blame-known)))
|
[(thread-cell-ref val-neg-party-acceptor)
|
||||||
((thread-cell-ref f-blame-known) val neg-party)))]))
|
=>
|
||||||
|
(λ (f) (f val neg-party))]
|
||||||
|
[else
|
||||||
|
(thread-cell-set! blame-accepting-func-cell
|
||||||
|
(λ (blame)
|
||||||
|
(λ (val neg-party)
|
||||||
|
((thread-cell-ref val-neg-party-acceptor) val neg-party))))
|
||||||
|
(do-list-check val neg-party blame)
|
||||||
|
(define f-of-blame 'f-of-blame-not-yet-set)
|
||||||
|
(thread-cell-set! val-neg-party-acceptor
|
||||||
|
(λ (val neg-party)
|
||||||
|
(do-list-check val neg-party blame)
|
||||||
|
(f-of-blame val neg-party)))
|
||||||
|
(set! f-of-blame (f blame))
|
||||||
|
(f-of-blame val neg-party)]))])))
|
||||||
|
|
||||||
|
(define (recursive-contract-late-neg-projection ctc)
|
||||||
|
(λ (blame)
|
||||||
|
(force-recursive-contract ctc)
|
||||||
|
((recursive-contract-blame->val-np->val ctc) blame)))
|
||||||
|
|
||||||
(define (flat-recursive-contract-late-neg-projection ctc)
|
(define (flat-recursive-contract-late-neg-projection ctc)
|
||||||
(cond
|
(cond
|
||||||
|
@ -287,7 +304,11 @@
|
||||||
(force-recursive-contract ctc)
|
(force-recursive-contract ctc)
|
||||||
(contract-random-generate/choose (recursive-contract-ctc ctc) (- fuel 1))])))
|
(contract-random-generate/choose (recursive-contract-ctc ctc) (- fuel 1))])))
|
||||||
|
|
||||||
(struct recursive-contract ([name #:mutable] [thunk #:mutable] [ctc #:mutable] list-contract?)
|
(struct recursive-contract ([name #:mutable]
|
||||||
|
thunk
|
||||||
|
[ctc #:mutable]
|
||||||
|
[blame->val-np->val #:mutable]
|
||||||
|
list-contract?)
|
||||||
#:property prop:recursive-contract (λ (this)
|
#:property prop:recursive-contract (λ (this)
|
||||||
(force-recursive-contract this)
|
(force-recursive-contract this)
|
||||||
(recursive-contract-ctc this)))
|
(recursive-contract-ctc this)))
|
||||||
|
|
|
@ -39,32 +39,37 @@
|
||||||
(define (combine-them x y)
|
(define (combine-them x y)
|
||||||
(bitwise-xor x (* 3 y)))
|
(bitwise-xor x (* 3 y)))
|
||||||
|
|
||||||
(define (blame-hash b hash/recur)
|
(define (blame-hash/combine b hash/recur combine-them)
|
||||||
(combine-them (hash/recur (blame-no-swap? b))
|
(combine-them (hash/recur (blame-no-swap? b))
|
||||||
(combine-them (hash/recur (blame-context-frame b))
|
(combine-them (hash/recur (blame-context-frame b))
|
||||||
(hash/recur (blame-and-more b)))))
|
(hash/recur (blame-and-more b)))))
|
||||||
|
|
||||||
|
(define (blame-hash b hash/recur)
|
||||||
|
(blame-hash/combine b hash/recur (λ (x y) (bitwise-xor x (* 3 y)))))
|
||||||
|
(define (blame-secondary-hash b hash/recur)
|
||||||
|
(blame-hash/combine b hash/recur (λ (x y) (bitwise-xor (* 5 x) y))))
|
||||||
|
|
||||||
;; missing-party? field is #t when the missing party
|
;; missing-party? field is #t when the missing party
|
||||||
;; is still missing and it is #f when the missing party
|
;; is still missing and it is #f when the missing party
|
||||||
;; has been filled in (or if it was filled in from the start)
|
;; has been filled in (or if it was filled in from the start)
|
||||||
(define-struct all-the-info
|
(define-struct all-the-info
|
||||||
[positive
|
[positive
|
||||||
negative
|
negative
|
||||||
source value build-name top-known? important missing-party? context-limit extra-fields]
|
source value build-name important missing-party? context-limit extra-fields]
|
||||||
#:transparent)
|
#:transparent)
|
||||||
|
|
||||||
;; and-more : (or/c blame-no-swap? blame-swap? all-the-info?)
|
;; and-more : (or/c blame-no-swap? blame-swap? all-the-info?)
|
||||||
;; context : string?
|
;; context : string?
|
||||||
(define-struct blame (context-frame and-more)
|
(define-struct blame (context-frame and-more)
|
||||||
#:property prop:equal+hash
|
#:property prop:equal+hash
|
||||||
(list blame=? blame-hash blame-hash))
|
(list blame=? blame-hash blame-secondary-hash))
|
||||||
|
|
||||||
(define-struct (blame-no-swap blame) ()
|
(define-struct (blame-no-swap blame) ()
|
||||||
#:property prop:equal+hash
|
#:property prop:equal+hash
|
||||||
(list blame=? blame-hash blame-hash))
|
(list blame=? blame-hash blame-secondary-hash))
|
||||||
(define-struct (blame-yes-swap blame) ()
|
(define-struct (blame-yes-swap blame) ()
|
||||||
#:property prop:equal+hash
|
#:property prop:equal+hash
|
||||||
(list blame=? blame-hash blame-hash))
|
(list blame=? blame-hash blame-secondary-hash))
|
||||||
|
|
||||||
(define (blame->all-the-info b)
|
(define (blame->all-the-info b)
|
||||||
(let loop ([b b])
|
(let loop ([b b])
|
||||||
|
@ -73,7 +78,6 @@
|
||||||
[else b])))
|
[else b])))
|
||||||
(define (blame-source b) (all-the-info-source (blame->all-the-info b)))
|
(define (blame-source b) (all-the-info-source (blame->all-the-info b)))
|
||||||
(define (blame-value b) (all-the-info-value (blame->all-the-info b)))
|
(define (blame-value b) (all-the-info-value (blame->all-the-info b)))
|
||||||
(define (blame-top-known? b) (all-the-info-top-known? (blame->all-the-info b)))
|
|
||||||
(define (blame-important b) (all-the-info-important (blame->all-the-info b)))
|
(define (blame-important b) (all-the-info-important (blame->all-the-info b)))
|
||||||
(define (blame-missing-party? b) (all-the-info-missing-party? (blame->all-the-info b)))
|
(define (blame-missing-party? b) (all-the-info-missing-party? (blame->all-the-info b)))
|
||||||
(define (blame-contract b) ((all-the-info-build-name (blame->all-the-info b))))
|
(define (blame-contract b) ((all-the-info-build-name (blame->all-the-info b))))
|
||||||
|
@ -146,7 +150,6 @@
|
||||||
source
|
source
|
||||||
value
|
value
|
||||||
build/memo-name
|
build/memo-name
|
||||||
#t
|
|
||||||
#f
|
#f
|
||||||
(not negative)
|
(not negative)
|
||||||
context-limit
|
context-limit
|
||||||
|
@ -155,11 +158,10 @@
|
||||||
;; so be careful in other parts of the code to ignore
|
;; so be careful in other parts of the code to ignore
|
||||||
;; it, as appropriate.
|
;; it, as appropriate.
|
||||||
(if original?
|
(if original?
|
||||||
(blame-no-swap/intern #f all-the-info)
|
(blame-no-swap #f all-the-info)
|
||||||
(blame-yes-swap/intern #f all-the-info)))])
|
(blame-yes-swap #f all-the-info)))])
|
||||||
make-blame))
|
make-blame))
|
||||||
|
|
||||||
(define seen '())
|
|
||||||
(define (blame-add-context b s #:important [name #f] #:swap? [swap? #f])
|
(define (blame-add-context b s #:important [name #f] #:swap? [swap? #f])
|
||||||
(unless (blame? b)
|
(unless (blame? b)
|
||||||
(raise-argument-error 'blame-add-context
|
(raise-argument-error 'blame-add-context
|
||||||
|
@ -172,20 +174,15 @@
|
||||||
(format "~s" '(or/c string? #f))
|
(format "~s" '(or/c string? #f))
|
||||||
1
|
1
|
||||||
b s))
|
b s))
|
||||||
(do-blame-add-context b s name swap?))
|
(cond
|
||||||
|
[(string? s)
|
||||||
|
(do-blame-add-context b s name swap?)]
|
||||||
|
[else b]))
|
||||||
|
|
||||||
(define (blame-add-unknown-context b)
|
;; this has become a no op. it seems to never have been
|
||||||
(do-blame-add-context b #f #f #f))
|
;; documented. probably exported because of the Great
|
||||||
|
;; Extra Export ScrewUp that happened years back
|
||||||
(define (make-blame-yes/no-swap/intern blame-yes/no-swap)
|
(define (blame-add-unknown-context b) b)
|
||||||
(define ht (make-hash))
|
|
||||||
(define (blame-yes/no-swap/intern s b)
|
|
||||||
(define b-table (hash-ref! ht s make-hash))
|
|
||||||
(hash-ref! b-table b (λ () (blame-yes/no-swap s b))))
|
|
||||||
blame-yes/no-swap/intern)
|
|
||||||
|
|
||||||
(define blame-no-swap/intern (make-blame-yes/no-swap/intern blame-no-swap))
|
|
||||||
(define blame-yes-swap/intern (make-blame-yes/no-swap/intern blame-yes-swap))
|
|
||||||
|
|
||||||
(define (do-blame-add-context b s name swap?)
|
(define (do-blame-add-context b s name swap?)
|
||||||
(define context-limit (blame-context-limit b))
|
(define context-limit (blame-context-limit b))
|
||||||
|
@ -195,51 +192,44 @@
|
||||||
;; we are not updating the name
|
;; we are not updating the name
|
||||||
;; at the top of the messages either
|
;; at the top of the messages either
|
||||||
;(not name)
|
;(not name)
|
||||||
(blame-top-known? b))
|
)
|
||||||
(cond
|
(cond
|
||||||
[(and s (not (zero? context-limit)))
|
[(not (zero? context-limit))
|
||||||
;; if the limit is zero, we skip this case,
|
;; if the limit is zero, we skip this case,
|
||||||
;; which has the effect of always keeping only
|
;; which has the effect of always keeping only
|
||||||
;; the dummy context frame
|
;; the dummy context frame
|
||||||
(define-values (limited-b dropped-swap?) (drop-to-limit b context-limit))
|
(define-values (limited-b dropped-swap?) (drop-to-limit b context-limit))
|
||||||
(if (equal? dropped-swap? swap?)
|
(if (equal? dropped-swap? swap?)
|
||||||
(blame-no-swap/intern s limited-b)
|
(blame-no-swap s limited-b)
|
||||||
(blame-yes-swap/intern s limited-b))]
|
(blame-yes-swap s limited-b))]
|
||||||
[swap?
|
[swap?
|
||||||
(if (blame-yes-swap? b)
|
(if (blame-yes-swap? b)
|
||||||
(blame-no-swap/intern (blame-context-frame b) (blame-and-more b))
|
(blame-no-swap (blame-context-frame b) (blame-and-more b))
|
||||||
(blame-yes-swap/intern (blame-context-frame b) (blame-and-more b)))]
|
(blame-yes-swap (blame-context-frame b) (blame-and-more b)))]
|
||||||
[else b])]
|
[else b])]
|
||||||
[else
|
[else
|
||||||
(define blame-yes/no-swap (if swap? blame-yes-swap/intern blame-no-swap/intern))
|
(define blame-yes/no-swap (if swap? blame-yes-swap blame-no-swap))
|
||||||
(define inside-part
|
(define inside-part
|
||||||
(let/ec k
|
(cond
|
||||||
|
[name
|
||||||
(let loop ([inner-b b])
|
(let loop ([inner-b b])
|
||||||
(cond
|
(cond
|
||||||
[(blame-yes-swap? inner-b)
|
[(blame-yes-swap? inner-b)
|
||||||
(blame-yes-swap/intern (blame-context-frame inner-b) (loop (blame-and-more inner-b)))]
|
(blame-yes-swap (blame-context-frame inner-b) (loop (blame-and-more inner-b)))]
|
||||||
[(blame-no-swap? inner-b)
|
[(blame-no-swap? inner-b)
|
||||||
(blame-no-swap/intern (blame-context-frame inner-b) (loop (blame-and-more inner-b)))]
|
(blame-no-swap (blame-context-frame inner-b) (loop (blame-and-more inner-b)))]
|
||||||
[else
|
[else
|
||||||
(define top-known? (all-the-info-top-known? inner-b))
|
|
||||||
(cond
|
|
||||||
[(or (equal? top-known? (string? s))
|
|
||||||
name)
|
|
||||||
(define new-original? (if swap? (not (blame-original? b)) (blame-original? b)))
|
(define new-original? (if swap? (not (blame-original? b)) (blame-original? b)))
|
||||||
;; in this case, we need to make a new blame record
|
;; in this case, we need to make a new blame record
|
||||||
(struct-copy
|
(struct-copy
|
||||||
all-the-info inner-b
|
all-the-info inner-b
|
||||||
[important (if name
|
[important (if name
|
||||||
(important name new-original?)
|
(important name new-original?)
|
||||||
(all-the-info-important inner-b))]
|
(all-the-info-important inner-b))])]))]
|
||||||
[top-known? (string? s)])]
|
[else b]))
|
||||||
[else
|
|
||||||
;; we can skip all that pending work
|
|
||||||
;; of making a copy in this case
|
|
||||||
(k b)])]))))
|
|
||||||
(if swap?
|
(if swap?
|
||||||
(blame-yes-swap/intern s inside-part)
|
(blame-yes-swap s inside-part)
|
||||||
(blame-no-swap/intern s inside-part))]))
|
(blame-no-swap s inside-part))]))
|
||||||
|
|
||||||
(define (drop-to-limit b context-limit)
|
(define (drop-to-limit b context-limit)
|
||||||
(define short-enough?
|
(define short-enough?
|
||||||
|
@ -269,10 +259,10 @@
|
||||||
(set! swapped? swap?)
|
(set! swapped? swap?)
|
||||||
b]))]
|
b]))]
|
||||||
[(blame-no-swap? b)
|
[(blame-no-swap? b)
|
||||||
(blame-no-swap/intern (blame-context-frame b)
|
(blame-no-swap (blame-context-frame b)
|
||||||
(loop (blame-and-more b) (- n 1)))]
|
(loop (blame-and-more b) (- n 1)))]
|
||||||
[(blame-yes-swap? b)
|
[(blame-yes-swap? b)
|
||||||
(blame-yes-swap/intern (blame-context-frame b)
|
(blame-yes-swap (blame-context-frame b)
|
||||||
(loop (blame-and-more b) (- n 1)))])))
|
(loop (blame-and-more b) (- n 1)))])))
|
||||||
(values limited-b swapped?)]))
|
(values limited-b swapped?)]))
|
||||||
|
|
||||||
|
@ -281,9 +271,9 @@
|
||||||
(define (blame-swap b)
|
(define (blame-swap b)
|
||||||
(cond
|
(cond
|
||||||
[(blame-yes-swap? b)
|
[(blame-yes-swap? b)
|
||||||
(blame-no-swap/intern (blame-context-frame b) (blame-and-more b))]
|
(blame-no-swap (blame-context-frame b) (blame-and-more b))]
|
||||||
[(blame-no-swap? b)
|
[(blame-no-swap? b)
|
||||||
(blame-yes-swap/intern (blame-context-frame b) (blame-and-more b))]))
|
(blame-yes-swap (blame-context-frame b) (blame-and-more b))]))
|
||||||
|
|
||||||
(define (blame-replace-negative b new-neg)
|
(define (blame-replace-negative b new-neg)
|
||||||
(update-the-info
|
(update-the-info
|
||||||
|
@ -331,9 +321,9 @@
|
||||||
[swap? #f])
|
[swap? #f])
|
||||||
(cond
|
(cond
|
||||||
[(blame-yes-swap? b)
|
[(blame-yes-swap? b)
|
||||||
(blame-yes-swap/intern (blame-context-frame b) (loop (blame-and-more b) (not swap?)))]
|
(blame-yes-swap (blame-context-frame b) (loop (blame-and-more b) (not swap?)))]
|
||||||
[(blame-no-swap? b)
|
[(blame-no-swap? b)
|
||||||
(blame-no-swap/intern (blame-context-frame b) (loop (blame-and-more b) swap?))]
|
(blame-no-swap (blame-context-frame b) (loop (blame-and-more b) swap?))]
|
||||||
[else (f b swap?)])))
|
[else (f b swap?)])))
|
||||||
|
|
||||||
(define (ensure-blame-known who blame)
|
(define (ensure-blame-known who blame)
|
||||||
|
|
|
@ -364,12 +364,6 @@
|
||||||
'anonymous-flat-contract 'build-flat-contract-property #t #t)
|
'anonymous-flat-contract 'build-flat-contract-property #t #t)
|
||||||
'build-flat-contract-property))
|
'build-flat-contract-property))
|
||||||
|
|
||||||
(define (blame-context-projection-wrapper proj)
|
|
||||||
(λ (ctc)
|
|
||||||
(define c-proj (proj ctc))
|
|
||||||
(λ (blame)
|
|
||||||
(c-proj (blame-add-unknown-context blame)))))
|
|
||||||
|
|
||||||
(define build-chaperone-contract-property
|
(define build-chaperone-contract-property
|
||||||
(procedure-rename
|
(procedure-rename
|
||||||
(build-property (compose make-chaperone-contract-property make-contract-property)
|
(build-property (compose make-chaperone-contract-property make-contract-property)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user