Fix arity checking for ->*.

Some functions were passing when they shouldn't have, only to fail when
the function is called.

Technically not backwards compatible, but should only affect functions
that were never called.
This commit is contained in:
Vincent St-Amour 2016-03-18 12:34:26 -05:00
parent b94e77a062
commit 894873c2ff
2 changed files with 47 additions and 28 deletions

View File

@ -716,4 +716,20 @@
(test/spec-passed (test/spec-passed
'->*-opt-optional5 '->*-opt-optional5
'((contract (->* () integer? #:post #t) (lambda x 1) 'pos 'neg)))) '((contract (->* () integer? #:post #t) (lambda x 1) 'pos 'neg)))
(test/pos-blame
'->*-opt-vs-mand1
'(contract (->* (integer?) (symbol? boolean?) number?)
(lambda (x y [z #t])
x)
'pos
'neg))
(test/pos-blame
'->*-opt-vs-mand2
'(contract (->* () (symbol? boolean?) symbol?)
(lambda (y [z #t])
y)
'pos
'neg))
)

View File

@ -29,32 +29,35 @@
(define exra-required-args (if (ellipsis-rest-arg-ctc? ->stct-rest) (define exra-required-args (if (ellipsis-rest-arg-ctc? ->stct-rest)
(length (*list-ctc-suffix ->stct-rest)) (length (*list-ctc-suffix ->stct-rest))
0)) 0))
(define expected-number-of-non-keyword-args (+ (length ->stct-doms) exra-required-args))
(define matching-arity? ;; the function must be ok for *all* the arities the contract says are ok
(and (for/or ([a (in-list arity)]) (for/and ([base-number-of-non-keyword-args (in-range ->stct-min-arity (add1 (length ->stct-doms)))])
(or (equal? expected-number-of-non-keyword-args a) (define expected-number-of-non-keyword-args (+ base-number-of-non-keyword-args exra-required-args))
(and (arity-at-least? a) (define matching-arity?
(>= expected-number-of-non-keyword-args (arity-at-least-value a))))) (and (for/or ([a (in-list arity)])
(if ->stct-rest (or (and (equal? expected-number-of-non-keyword-args a))
(let ([lst (car (reverse arity))]) (and (arity-at-least? a)
(and (arity-at-least? lst) (>= expected-number-of-non-keyword-args (arity-at-least-value a)))))
(<= (arity-at-least-value lst) (+ exra-required-args ->stct-min-arity)))) (if ->stct-rest
#t))) (let ([lst (car (reverse arity))])
(unless matching-arity? (and (arity-at-least? lst)
(k (<= (arity-at-least-value lst) (+ exra-required-args ->stct-min-arity))))
(λ (neg-party) #t)))
(raise-blame-error blame #:missing-party neg-party val (unless matching-arity?
'(expected: (k
"a procedure that accepts ~a non-keyword argument~a~a" (λ (neg-party)
given: "~e" (raise-blame-error blame #:missing-party neg-party val
"\n ~a") '(expected:
expected-number-of-non-keyword-args "a procedure that accepts ~a non-keyword argument~a~a"
(if (= expected-number-of-non-keyword-args 1) "" "s") given: "~e"
(if ->stct-rest "\n ~a")
" and arbitrarily many more" expected-number-of-non-keyword-args
"") (if (= expected-number-of-non-keyword-args 1) "" "s")
val (if ->stct-rest
(arity-as-string val))))) " and arbitrarily many more"
"")
val
(arity-as-string val))))))
(define (should-have-supplied kwd) (define (should-have-supplied kwd)
(k (k