adjusted the contract error messages so that the words expected/promised

are switched in and out based on the sense of the blame (similar to a recent
change that made given/produced swap in and out)
This commit is contained in:
Robby Findler 2012-05-15 17:49:47 -05:00
parent dfa0305bb3
commit 3fceae2715
16 changed files with 168 additions and 117 deletions

View File

@ -113,7 +113,7 @@ v4 todo:
[res-checker (λ (res-x ...) (values (p-app-x res-x) ...))]) [res-checker (λ (res-x ...) (values (p-app-x res-x) ...))])
(λ (val) (λ (val)
(unless (procedure? val) (unless (procedure? val)
(raise-blame-error orig-blame val "expected a procedure, ~a ~v" (given/produced orig-blame) val)) (raise-blame-error orig-blame val '(expected: "a procedure," given: "~v") val))
(wrapper (wrapper
val val
(make-keyword-procedure (make-keyword-procedure
@ -389,12 +389,12 @@ v4 todo:
(if (and (null? req-kwd) (null? opt-kwd)) (if (and (null? req-kwd) (null? opt-kwd))
(λ (kwds kwd-args . args) (λ (kwds kwd-args . args)
(raise-blame-error (blame-swap blame) val (raise-blame-error (blame-swap blame) val
"expected no keywords")) '(expected: "no keywords")))
(λ (kwds kwd-args . args) (λ (kwds kwd-args . args)
(define args-len (length args)) (define args-len (length args))
(unless (valid-number-of-args? args) (unless (valid-number-of-args? args)
(raise-blame-error (blame-swap blame) val (raise-blame-error (blame-swap blame) val
"received ~a argument~a, expected ~a" '("received ~a argument~a," expected: "~a")
args-len (if (= args-len 1) "" "s") arity-string)) args-len (if (= args-len 1) "" "s") arity-string))
;; these two for loops are doing O(n^2) work that could be linear ;; these two for loops are doing O(n^2) work that could be linear
@ -402,7 +402,7 @@ v4 todo:
(for ([req-kwd (in-list req-kwd)]) (for ([req-kwd (in-list req-kwd)])
(unless (memq req-kwd kwds) (unless (memq req-kwd kwds)
(raise-blame-error (blame-swap blame) val (raise-blame-error (blame-swap blame) val
"expected keyword argument ~a" '(expected "keyword argument ~a")
req-kwd))) req-kwd)))
(for ([k (in-list kwds)]) (for ([k (in-list kwds)])
(unless (memq k all-kwds) (unless (memq k all-kwds)
@ -416,7 +416,7 @@ v4 todo:
(unless (valid-number-of-args? args) (unless (valid-number-of-args? args)
(define args-len (length args)) (define args-len (length args))
(raise-blame-error (blame-swap blame) val (raise-blame-error (blame-swap blame) val
"received ~a argument~a, expected ~a" '("received ~a argument~a," expected: "~a")
args-len (if (= args-len 1) "" "s") arity-string)) args-len (if (= args-len 1) "" "s") arity-string))
(apply basic-lambda args)) (apply basic-lambda args))
(λ args (λ args
@ -1873,7 +1873,7 @@ v4 todo:
(raise-blame-error (raise-blame-error
blame blame
val val
"expected a ~a that accepts ~a~a~a argument~a~a~a, ~a: ~e" '(expected" a ~a that accepts ~a~a~a argument~a~a~a," given: "~e")
(if mtd? "method" "procedure") (if mtd? "method" "procedure")
(if (zero? dom-length) "no" dom-length) (if (zero? dom-length) "no" dom-length)
(if (null? optionals) "" " mandatory") (if (null? optionals) "" " mandatory")
@ -1882,7 +1882,6 @@ v4 todo:
(if (zero? optionals) "" (if (zero? optionals) ""
(format " and up to ~a optional argument~a" optionals (if (= 1 optionals) "" "s"))) (format " and up to ~a optional argument~a" optionals (if (= 1 optionals) "" "s")))
(keyword-error-text mandatory-kwds optional-keywords) (keyword-error-text mandatory-kwds optional-keywords)
(given/produced blame)
val))] val))]
[else [else
passes?])) passes?]))
@ -1949,14 +1948,13 @@ v4 todo:
(raise-blame-error (raise-blame-error
blame blame
val val
"expected a ~a that accepts ~a argument~a and arbitrarily more~a, ~a: ~e" '(expected "a ~a that accepts ~a argument~a and arbitrarily more~a," given: "~e")
(if mtd? "method" "procedure") (if mtd? "method" "procedure")
(cond (cond
[(zero? dom-length) "no"] [(zero? dom-length) "no"]
[else dom-length]) [else dom-length])
(if (= 1 dom-length) "" "s") (if (= 1 dom-length) "" "s")
(keyword-error-text mandatory-kwds optional-kwds) (keyword-error-text mandatory-kwds optional-kwds)
(given/produced blame)
val))] val))]
[else [else
passes?])) passes?]))

View File

@ -32,7 +32,7 @@
(raise-blame-error (raise-blame-error
blame blame
val val
"expected ~a" '(expected: "~a")
pred-name)) pred-name))
;; ;;
@ -93,9 +93,8 @@
(raise-blame-error (raise-blame-error
blame blame
val val
"expected: ~s, ~a: ~e" '(expected: "~s," given: "~e")
(contract-name ctc) (contract-name ctc)
(given/produced blame)
val))) val)))
#:lifts #:lifts
(interleave-lifts (interleave-lifts

View File

@ -15,11 +15,11 @@
blame-add-context blame-add-context
blame-add-unknown-context blame-add-unknown-context
blame-context blame-context
given/produced
raise-blame-error raise-blame-error
current-blame-format current-blame-format
(struct-out exn:fail:contract:blame)) (struct-out exn:fail:contract:blame)
blame-fmt->-string)
(define (blame=? a b equal?/recur) (define (blame=? a b equal?/recur)
(and (equal?/recur (blame-source a) (blame-source b)) (and (equal?/recur (blame-source a) (blame-source b))
@ -86,12 +86,61 @@
(define-struct (exn:fail:contract:blame exn:fail:contract) [object] (define-struct (exn:fail:contract:blame exn:fail:contract) [object]
#:transparent) #:transparent)
(define (raise-blame-error b x fmt . args) (define (raise-blame-error blame x fmt . args)
(raise (raise
(make-exn:fail:contract:blame (make-exn:fail:contract:blame
((current-blame-format) b x (apply format fmt args)) ((current-blame-format)
blame x
(apply format (blame-fmt->-string blame fmt) args))
(current-continuation-marks) (current-continuation-marks)
b))) blame)))
(define (blame-fmt->-string blame fmt)
(cond
[(string? fmt) fmt]
[else
(let loop ([strs fmt]
[so-far '()]
[last-ended-in-whitespace? #t])
(cond
[(null? strs)
(apply string-append (reverse so-far))]
[else
(define fst (car strs))
(define nxt
(cond
[(eq? 'given: fst) (if (blame-original? blame)
"produced:"
"given:")]
[(eq? 'given fst) (if (blame-original? blame)
"produced"
"given")]
[(eq? 'expected: fst) (if (blame-original? blame)
"promised:"
"expected:")]
[(eq? 'expected fst) (if (blame-original? blame)
"promised"
"expected")]
[else fst]))
(define new-so-far
(if (or last-ended-in-whitespace?
(regexp-match #rx"^ " nxt))
(cons nxt so-far)
(list* nxt " " so-far)))
(loop (cdr strs)
new-so-far
(regexp-match #rx" $" nxt))]))]))
(define (given/produced blame)
(if (blame-original? blame)
"produced"
"given"))
(define (expected/promised blame)
(if (blame-original? blame)
"expected"
"promised"))
(define (default-blame-format blme x custom-message) (define (default-blame-format blme x custom-message)
(define source-message (source-location->string (blame-source blme))) (define source-message (source-location->string (blame-source blme)))
@ -113,7 +162,7 @@
(format " at: ~a" source-message))) (format " at: ~a" source-message)))
(define self-or-not (if (blame-original? blme) (define self-or-not (if (blame-original? blme)
"self-contract violation" "broke it's contract"
"contract violation")) "contract violation"))
(define start-of-message (define start-of-message
@ -202,8 +251,3 @@
(define current-blame-format (define current-blame-format
(make-parameter default-blame-format)) (make-parameter default-blame-format))
(define (given/produced blame)
(if (blame-original? blame)
"produced"
"given"))

View File

@ -18,14 +18,14 @@
(define elem-ctc (base-box/c-content ctc)) (define elem-ctc (base-box/c-content ctc))
(define immutable (base-box/c-immutable ctc)) (define immutable (base-box/c-immutable ctc))
(unless (box? val) (unless (box? val)
(raise-blame-error blame val "expected a box, ~a: ~a" (given/produced blame) val)) (raise-blame-error blame val '(expected "a box," given: "~e") val))
(case immutable (case immutable
[(#t) [(#t)
(unless (immutable? val) (unless (immutable? val)
(raise-blame-error blame val "expected an immutable box, ~a: ~a" (given/produced blame) val))] (raise-blame-error blame val '(expected "an immutable box," given: "~e") val))]
[(#f) [(#f)
(when (immutable? val) (when (immutable? val)
(raise-blame-error blame val "expected a mutable box, ~a: ~a" (given/produced blame) val))] (raise-blame-error blame val '(expected "a mutable box," given: "~e") val))]
[(dont-care) (void)])) [(dont-care) (void)]))
(define (box/c-first-order ctc) (define (box/c-first-order ctc)

View File

@ -253,7 +253,7 @@ it around flattened out.
(raise-blame-error (raise-blame-error
blame blame
val val
"expected: ~s, ~a ~e" 'name (given/produced blame) val)) '(expected: "~s," given: "~e") 'name val))
(cond (cond
[(already-there? contract/info val lazy-depth-to-look) [(already-there? contract/info val lazy-depth-to-look)
val] val]
@ -459,9 +459,8 @@ it around flattened out.
(raise-blame-error (raise-blame-error
blame blame
val val
"expected: ~s, ~a ~e" '(expected: "~s," given: "~e")
(contract-name ctc) (contract-name ctc)
(given/produced blame)
val)])) val)]))
#:lifts lifts #:lifts lifts
#:superlifts superlifts #:superlifts superlifts
@ -536,7 +535,8 @@ it around flattened out.
(raise-blame-error (raise-blame-error
(contract/info-blame contract/info) (contract/info-blame contract/info)
stct stct
"failed `and' clause, ~a ~e" (given/produced (contract/info-blame contract/info)) stct))) '("failed `and' clause," given: "~e")
stct)))
(define-values (evaluate-attr-prop evaluate-attr-prop-predicate evaluate-attr-prop-accessor) (define-values (evaluate-attr-prop evaluate-attr-prop-predicate evaluate-attr-prop-accessor)
(make-struct-type-property 'evaluate-attr-prop)) (make-struct-type-property 'evaluate-attr-prop))

View File

@ -82,23 +82,22 @@
(define immutable (base-hash/c-immutable ctc)) (define immutable (base-hash/c-immutable ctc))
(define flat? (flat-hash/c? ctc)) (define flat? (flat-hash/c? ctc))
(unless (hash? val) (unless (hash? val)
(raise-blame-error blame val "expected a hash, ~a: ~e" (given/produced blame) val)) (raise-blame-error blame val '(expected "a hash," given: "~e") val))
(when (and (not flat?) (when (and (not flat?)
(not (flat-contract? dom-ctc)) (not (flat-contract? dom-ctc))
(not (hash-equal? val))) (not (hash-equal? val)))
(raise-blame-error blame val (raise-blame-error blame val
"expected equal?-based hash table due to higher-order domain contract, ~a: ~e" '(expected "equal?-based hash table due to higher-order domain contract," given: "~e")
(given/produced blame)
val)) val))
(case immutable (case immutable
[(#t) [(#t)
(unless (immutable? val) (unless (immutable? val)
(raise-blame-error blame val (raise-blame-error blame val
"expected an immutable hash, ~a: ~e" (given/produced blame) val))] '(expected "an immutable hash," given: "~e") val))]
[(#f) [(#f)
(when (immutable? val) (when (immutable? val)
(raise-blame-error blame val (raise-blame-error blame val
"expected an mutable hash, ~a: ~e" (given/produced blame) val))] '(expected "a mutable hash," given: "~e") val))]
[(dont-care) (void)])) [(dont-care) (void)]))
(define (hash/c-first-order ctc) (define (hash/c-first-order ctc)

View File

@ -220,16 +220,14 @@
(if candidate-proc (if candidate-proc
(candidate-proc val) (candidate-proc val)
(raise-blame-error blame val (raise-blame-error blame val
"none of the branches of the or/c matched, ~a: ~e" '("none of the branches of the or/c matched," given: "~e")
(given/produced blame)
val))] val))]
[((car checks) val) [((car checks) val)
(if candidate-proc (if candidate-proc
(raise-blame-error blame val (raise-blame-error blame val
"two of the clauses in the or/c might both match: ~s and ~s, ~a: ~e" '("two of the clauses in the or/c might both match: ~s and ~s," given: "~e")
(contract-name candidate-contract) (contract-name candidate-contract)
(contract-name (car contracts)) (contract-name (car contracts))
(given/produced blame)
val) val)
(loop (cdr checks) (loop (cdr checks)
(cdr procs) (cdr procs)
@ -364,9 +362,8 @@
(raise-blame-error (raise-blame-error
blame blame
val val
"expected: ~s, ~a: ~e, which isn't ~s" '(expected: "~s," given: "~e, which isn't ~s")
(contract-name ctc) (contract-name ctc)
(given/produced blame)
val val
(contract-name (car ctcs))))]))))) (contract-name (car ctcs))))])))))
@ -645,9 +642,8 @@
(λ (val) (λ (val)
(unless (predicate? val) (unless (predicate? val)
(raise-blame-error blame val (raise-blame-error blame val
"expected: ~s, ~a: ~e" '(expected: "~s," given "~e")
'type-name 'type-name
(given/produced blame)
val)) val))
(check-all p-app val)))) (check-all p-app val))))
(cond (cond
@ -692,8 +688,8 @@
[cdr-p (cdr-proj (blame-add-context blame "the cdr of"))]) [cdr-p (cdr-proj (blame-add-context blame "the cdr of"))])
(λ (v) (λ (v)
(unless (pair? v) (unless (pair? v)
(raise-blame-error blame v "expected <cons?>, ~a: ~e" (raise-blame-error blame v
(given/produced blame) '(expected "<pair?>," given: "~e")
v)) v))
(combine v (car-p (car v)) (cdr-p (cdr v)))))) (combine v (car-p (car v)) (cdr-p (cdr v))))))
(cond (cond
@ -747,17 +743,18 @@
(lambda (blame) (lambda (blame)
(lambda (x) (lambda (x)
(unless (list? x) (unless (list? x)
(raise-blame-error blame x "expected a list, ~a: ~e" (given/produced blame) x)) (raise-blame-error blame x '(expected "a list," given: "~e") x))
(let* ([args (generic-list/c-args c)] (let* ([args (generic-list/c-args c)]
[expected (length args)] [expected (length args)]
[actual (length x)]) [actual (length x)])
(unless (= actual expected) (unless (= actual expected)
(raise-blame-error (raise-blame-error
blame x blame x
"expected a list of ~a elements, but ~a ~a elements in: ~e" '(expected "a list of ~a elements, but" given "~a element~a in: ~e")
expected expected
(given/produced blame) actual
actual x)) (if (= actual 1) "" "s")
x))
(for ([arg/c (in-list args)] [v (in-list x)] [i (in-naturals 1)]) (for ([arg/c (in-list args)] [v (in-list x)] [i (in-naturals 1)])
(((contract-projection arg/c) (((contract-projection arg/c)
(add-list-context blame i)) (add-list-context blame i))
@ -773,15 +770,16 @@
(arg/c (add-list-context blame i)))) (arg/c (add-list-context blame i))))
(λ (x) (λ (x)
(unless (list? x) (unless (list? x)
(raise-blame-error blame x "expected a list, ~a: ~e" (given/produced blame) x)) (raise-blame-error blame x '(expected "a list," given: "~e") x))
(define actual (length x)) (define actual (length x))
(unless (= actual expected) (unless (= actual expected)
(raise-blame-error (raise-blame-error
blame x blame x
"expected a list of ~a elements, but ~a ~a elements in: ~e" '(expected "a list of ~a elements, but" given "~a element~a in: ~e")
expected expected
(given/produced blame) actual
actual x)) (if (= actual 1) "" "s")
x))
(for/list ([item (in-list x)] (for/list ([item (in-list x)]
[proj (in-list projs)]) [proj (in-list projs)])
(proj item))))) (proj item)))))
@ -833,8 +831,7 @@
(raise-blame-error (raise-blame-error
blame blame
val val
"expected <promise>, ~a: ~e" '(expected "<promise>," given: "~e")
(given/produced blame)
val)) val))
(delay (p-app (force val)))))) (delay (p-app (force val))))))
#:first-order promise?)))) #:first-order promise?))))
@ -861,7 +858,7 @@
partial-neg-contract partial-neg-contract
partial-pos-contract)] partial-pos-contract)]
[else [else
(raise-blame-error blame val "expected a parameter")]))))) (raise-blame-error blame val '(expected "a parameter"))])))))
#:name #:name
(λ (ctc) (build-compound-type-name 'parameter/c (parameter/c-ctc ctc))) (λ (ctc) (build-compound-type-name 'parameter/c (parameter/c-ctc ctc)))
@ -911,7 +908,7 @@
(raise-blame-error (raise-blame-error
blame blame
val val
"~s accepts no values, given: ~e" '("~s accepts no values," given: "~e")
(none/c-name ctc) (none/c-name ctc)
val)))) val))))

View File

@ -97,7 +97,7 @@
#:chaperone #t)) #:chaperone #t))
(define (opt-constant-contract-failure blame val compare should-be) (define (opt-constant-contract-failure blame val compare should-be)
(raise-blame-error blame val "expected a value ~a to ~e" compare should-be)) (raise-blame-error blame val '(expected "a value ~a to ~e") compare should-be))
(begin-for-syntax (begin-for-syntax
(define-struct define-opt/recursive-fn (transformer internal-fn neg-blame?-id) (define-struct define-opt/recursive-fn (transformer internal-fn neg-blame?-id)

View File

@ -183,10 +183,8 @@
(raise-blame-error (raise-blame-error
blame blame
val val
"expected a number between ~a and ~a, ~a: ~e" '(expected "a number between ~a and ~a," given: "~e")
lo hi lo hi val))
(given/produced blame)
val))
(define-for-syntax (single-comparison-opter opt/info stx check-arg comparison arg) (define-for-syntax (single-comparison-opter opt/info stx check-arg comparison arg)
(with-syntax ([comparison comparison]) (with-syntax ([comparison comparison])
@ -222,10 +220,8 @@
(raise-blame-error (raise-blame-error
blame blame
val val
"expected a number ~a ~a, ~a: ~e" '(expected "a number ~a ~a," given: "~e")
(object-name comparison) m (object-name comparison) m val))
(given/produced blame)
val))
(define/opter (=/c opt/i opt/info stx) (define/opter (=/c opt/i opt/info stx)
@ -308,9 +304,8 @@
(raise-blame-error (raise-blame-error
blame blame
val val
"expected: ~s, ~a: ~e" '(expected: "~s," given: "~e")
(contract-name ctc) (contract-name ctc)
(given/produced blame)
val)))) val))))
#:lifts #:lifts
(append (optres-lifts optres-hd) (optres-lifts optres-tl)) (append (optres-lifts optres-hd) (optres-lifts optres-tl))
@ -358,8 +353,8 @@
blame blame
val val
#,(if non-empty? #,(if non-empty?
"expected a non-empty list" #''(expected "a non-empty list")
"expected a list"))))) #''(expected "a list"))))))
#:lifts (optres-lifts optres-ele) #:lifts (optres-lifts optres-ele)
#:superlifts (optres-superlifts optres-ele) #:superlifts (optres-superlifts optres-ele)
#:partials (optres-partials optres-ele) #:partials (optres-partials optres-ele)
@ -589,13 +584,12 @@
(define (raise-flat-arrow-err blame val n) (define (raise-flat-arrow-err blame val n)
(raise-blame-error blame val (raise-blame-error blame val
"expected a procedure matching the contract ~s" '(expected "a procedure matching the contract ~s")
`(-> ,@(build-list n (λ (x) 'any/c)) any))) `(-> ,@(build-list n (λ (x) 'any/c)) any)))
(define (bad-number-of-arguments blame val args dom-len) (define (bad-number-of-arguments blame val args dom-len)
(define num-values (length args)) (define num-values (length args))
(raise-blame-error (blame-swap blame) val (raise-blame-error (blame-swap blame) val
"expected ~a argument~a, ~a ~a argument~a" '(expected "~a argument~a," given "~a argument~a")
dom-len (if (= dom-len 1) "" "s") dom-len (if (= dom-len 1) "" "s")
(given/produced blame)
num-values (if (= num-values 1) "" "s"))) num-values (if (= num-values 1) "" "s")))

View File

@ -46,7 +46,7 @@
(lambda (p) (lambda (p)
(unless (procedure? p) (unless (procedure? p)
(raise-blame-error blame p "expected a procedure; ~a: ~e" (given/produced blame) p)) (raise-blame-error blame p '(expected "a procedure;" given: "~e") p))
(make-keyword-procedure (make-keyword-procedure
(lambda (keys vals . args) (keyword-apply (wrap p) keys vals args)) (lambda (keys vals . args) (keyword-apply (wrap p) keys vals args))
(case-lambda (case-lambda
@ -80,7 +80,6 @@
(lambda (x) (lambda (x)
(if ((barrier-contract-pred c) x) (if ((barrier-contract-pred c) x)
((barrier-contract-get c) x) ((barrier-contract-get c) x)
(raise-blame-error blame x "expected a(n) ~a; ~a: ~e" (raise-blame-error blame x '(expected "a(n) ~a;" given: "~e")
(barrier-contract-name c) (barrier-contract-name c)
(given/produced blame)
x)))))))) x))))))))

View File

@ -262,9 +262,8 @@
(if (first-order x) (if (first-order x)
x x
(raise-blame-error b x (raise-blame-error b x
"expected: ~s, ~a: ~e" '(expected: "~s," given: "~e")
name name
(given/produced b)
x)))))) x))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -189,7 +189,7 @@
v] v]
[else [else
(unless (pred? v) (unless (pred? v)
(raise-blame-error blame v "expected a ~a" (raise-blame-error blame v '(expected: "~a")
(base-struct/dc-struct-name ctc))) (base-struct/dc-struct-name ctc)))
(let loop ([subcontracts (base-struct/dc-subcontracts ctc)] (let loop ([subcontracts (base-struct/dc-subcontracts ctc)]
[projs projs] [projs projs]
@ -955,7 +955,7 @@
(define (struct/dc-error blame obj what) (define (struct/dc-error blame obj what)
(raise-blame-error blame obj (raise-blame-error blame obj
"expected a struct of type ~a" '(expected "a struct of type ~a")
what)) what))
(define-syntax (struct/c stx) (define-syntax (struct/c stx)

View File

@ -14,8 +14,7 @@
(lambda (x) (lambda (x)
(unless (struct-type-property? x) (unless (struct-type-property? x)
(raise-blame-error blame x (raise-blame-error blame x
"expected struct-type-property, ~a: ~e" '(expected "struct-type-property," given: "~e")
(given/produced blame)
x)) x))
(let-values ([(nprop _pred _acc) (let-values ([(nprop _pred _acc)
(make-struct-type-property (make-struct-type-property

View File

@ -49,20 +49,20 @@
[flat? (flat-vectorof? c)]) [flat? (flat-vectorof? c)])
(λ (val fail first-order?) (λ (val fail first-order?)
(unless (vector? val) (unless (vector? val)
(fail val "expected a vector, got ~a" val)) (fail val '(expected "a vector," given: "~e") val))
(cond (cond
[(eq? immutable #t) [(eq? immutable #t)
(unless (immutable? val) (unless (immutable? val)
(fail val "expected an immutable vector, got ~a" val))] (fail val '(expected "an immutable vector," given: "~e") val))]
[(eq? immutable #f) [(eq? immutable #f)
(when (immutable? val) (when (immutable? val)
(fail val "expected an mutable vector, got ~a" val))] (fail val '(expected "an mutable vector," given: "~e" val)))]
[else (void)]) [else (void)])
(when first-order? (when first-order?
(for ([e (in-vector val)] (for ([e (in-vector val)]
[n (in-naturals)]) [n (in-naturals)])
(unless (contract-first-order-passes? elem-ctc e) (unless (contract-first-order-passes? elem-ctc e)
(fail val "expected: ~s for element ~v, got ~v" (contract-name elem-ctc) n e)))) (fail val '(expected: "~s for element ~s," given "~e") (contract-name elem-ctc) n e))))
#t))) #t)))
(define (vectorof-first-order ctc) (define (vectorof-first-order ctc)
@ -182,29 +182,24 @@
(define elem-ctcs (base-vector/c-elems ctc)) (define elem-ctcs (base-vector/c-elems ctc))
(define immutable (base-vector/c-immutable ctc)) (define immutable (base-vector/c-immutable ctc))
(unless (vector? val) (unless (vector? val)
(raise-blame-error blame val "expected a vector, ~a: ~e" (raise-blame-error blame val '(expected "a vector," given: "~e") val))
(given/produced blame)
val))
(cond (cond
[(eq? immutable #t) [(eq? immutable #t)
(unless (immutable? val) (unless (immutable? val)
(raise-blame-error blame val (raise-blame-error blame val
"expected an immutable vector, ~a: ~e" '(expected "an immutable vector," given: "~e")
(given/produced blame)
val))] val))]
[(eq? immutable #f) [(eq? immutable #f)
(when (immutable? val) (when (immutable? val)
(raise-blame-error blame val (raise-blame-error blame val
"expected an mutable vector, ~a: ~e" '(expected "a mutable vector," given: "~e")
(given/produced blame)
val))] val))]
[else (void)]) [else (void)])
(define elem-count (length elem-ctcs)) (define elem-count (length elem-ctcs))
(unless (= (vector-length val) elem-count) (unless (= (vector-length val) elem-count)
(raise-blame-error blame val "expected a vector of ~a element~a, ~a: ~e" (raise-blame-error blame val '(expected "a vector of ~a element~a," given: "~e")
elem-count elem-count
(if (= elem-count 1) "" "s") (if (= elem-count 1) "" "s")
(given/produced blame)
val))) val)))
(define (vector/c-first-order ctc) (define (vector/c-first-order ctc)

View File

@ -1273,7 +1273,7 @@ use in the contract system:
(raise-blame-error (raise-blame-error
blame blame
val val
"expected <integer>, given: ~e" '(expected "<integer>," given: "~e")
val)))) val))))
] ]
The new argument specifies who is to be blamed for The new argument specifies who is to be blamed for
@ -1304,7 +1304,7 @@ Compare that to the projection for our function contract:
(raise-blame-error (raise-blame-error
blame blame
val val
"expected a procedure of one argument, given: ~e" '(expected "a procedure of one argument," given: "~e")
val))))) val)))))
] ]
@ -1362,7 +1362,7 @@ when a contract violation is detected.
(raise-blame-error (raise-blame-error
blame blame
val val
"expected a procedure of one argument, given: ~e" '(expected "a procedure of one argument," given: "~e")
val)))))) val))))))
] ]
@ -1380,7 +1380,9 @@ the contract library primitives below.
(if (test x) (if (test x)
x x
(raise-blame-error (raise-blame-error
b x "expected <~a>, given: ~e" name x))))] b x
'(expected "<~a>," given: "~e")
name x))))]
[#:stronger stronger (-> contract? contract? boolean?)]) [#:stronger stronger (-> contract? contract? boolean?)])
contract?] contract?]
@defproc[(make-chaperone-contract @defproc[(make-chaperone-contract
@ -1392,7 +1394,9 @@ the contract library primitives below.
(if (test x) (if (test x)
x x
(raise-blame-error (raise-blame-error
b x "expected <~a>, given: ~e" name x))))] b x
'(expected "<~a>," given: "~e")
name x))))]
[#:stronger stronger (-> contract? contract? boolean?)]) [#:stronger stronger (-> contract? contract? boolean?)])
chaperone-contract?] chaperone-contract?]
@defproc[(make-flat-contract @defproc[(make-flat-contract
@ -1404,7 +1408,9 @@ the contract library primitives below.
(if (test x) (if (test x)
x x
(raise-blame-error (raise-blame-error
b x "expected <~a>, given: ~e" name x))))] b x
'(expected "<~a>," given: "~e")
name x))))]
[#:stronger stronger (-> contract? contract? boolean?)]) [#:stronger stronger (-> contract? contract? boolean?)])
flat-contract?] flat-contract?]
)]{ )]{
@ -1468,7 +1474,7 @@ was passed as the second argument to @racket[contract-stronger?].
(λ (x) (range (f (domain x)))) (λ (x) (range (f (domain x))))
(raise-blame-error (raise-blame-error
b f b f
"expected a function of one argument, got: ~e" '(expected "a function of one argument," 'given: "~e")
f))))))) f)))))))
(contract int->int/c "not fun" 'positive 'negative) (contract int->int/c "not fun" 'positive 'negative)
(define halve (define halve
@ -1630,17 +1636,32 @@ the other; both are provided for convenience and clarity.
position @racket[b] has. position @racket[b] has.
} }
@defproc[(raise-blame-error [b blame?] [x any/c] [fmt string?] [v any/c] ...) @defproc[(raise-blame-error [b blame?]
[x any/c]
[fmt (or/c string?
(listof (or/c string?
'given 'given:
'expected 'expected:)))]
[v any/c] ...)
none/c]{ none/c]{
Signals a contract violation. The first argument, @racket[b], records the Signals a contract violation. The first argument, @racket[b], records the
current blame information, including positive and negative parties, the name of current blame information, including positive and negative parties, the name of
the contract, the name of the value, and the source location of the contract the contract, the name of the value, and the source location of the contract
application. The second argument, @racket[x], is the value that failed to application. The second argument, @racket[x], is the value that failed to
satisfy the contract. The remaining arguments are a format string, satisfy the contract.
The remaining arguments are a format string,
@racket[fmt], and its arguments, @racket[v ...], specifying an error message @racket[fmt], and its arguments, @racket[v ...], specifying an error message
specific to the precise violation. specific to the precise violation.
If @racket[fmt] is a list, then the elements are concatenated together
(with spaces added, unless there are already spaces at the ends of the strings),
after first replacing symbols with either their string counterparts, or
replacing @racket['given] with @racket["produced"] and
@racket['expected] with @racket["promised"], depending on whether or not
the @racket[b] argument has been swapped or not (see @racket[blame-swap]).
} }
@defstruct[(exn:fail:contract:blame exn:fail:contract) ([object blame?])]{ @defstruct[(exn:fail:contract:blame exn:fail:contract) ([object blame?])]{

View File

@ -13,6 +13,7 @@
(namespace-require 'scheme/contract) (namespace-require 'scheme/contract)
(namespace-require 'scheme/set) (namespace-require 'scheme/set)
(namespace-require '(only racket/contract/private/arrow procedure-accepts-and-more?)) (namespace-require '(only racket/contract/private/arrow procedure-accepts-and-more?))
(namespace-require '(only racket/contract/private/blame blame-fmt->-string make-blame))
(namespace-require 'scheme/class) (namespace-require 'scheme/class)
(namespace-require 'scheme/promise) (namespace-require 'scheme/promise)
(namespace-require 'scheme/match)) (namespace-require 'scheme/match))
@ -143,7 +144,7 @@
(define (has-proper-blame? msg) (define (has-proper-blame? msg)
(define reg (define reg
(cond (cond
[(eq? blame 'pos) #rx"self-contract violation[\n:,].*blaming: pos"] [(eq? blame 'pos) #rx"broke it's contract[\n:,].*blaming: pos"]
[(eq? blame 'neg) #rx"blaming: neg"] [(eq? blame 'neg) #rx"blaming: neg"]
[(string? blame) (string-append "blaming: " (regexp-quote blame))] [(string? blame) (string-append "blaming: " (regexp-quote blame))]
[else #f])) [else #f]))
@ -12741,6 +12742,12 @@ so that propagation occurs.
0) 0)
1))) 1)))
(let* ([blame-pos (contract-eval '(make-blame #'here #f (λ () 'integer?) 'positive 'negative #t))]
[blame-neg (contract-eval `(blame-swap ,blame-pos))])
(ctest "something ~a" blame-fmt->-string ,blame-neg "something ~a")
(ctest "promised: ~s; produced: ~e" blame-fmt->-string ,blame-pos '(expected: "~s;" given: "~e"))
(ctest "expected: ~s; given: ~e" blame-fmt->-string ,blame-neg '(expected: "~s;" given: "~e")))
; ;
; ;
; ;
@ -13581,7 +13588,7 @@ so that propagation occurs.
(eval '(require 'pce1-bug))) (eval '(require 'pce1-bug)))
(λ (x) (λ (x)
(and (exn:fail:contract:blame? x) (and (exn:fail:contract:blame? x)
(regexp-match #rx"the-defined-variable1: self-contract violation" (exn-message x))))) (regexp-match #rx"the-defined-variable1: broke it's contract" (exn-message x)))))
(contract-error-test (contract-error-test
'contract-error-test9 'contract-error-test9