From 4c1acd1bb6f75eaed601afb77750ab72cf8c5efa Mon Sep 17 00:00:00 2001 From: Robby Findler Date: Mon, 17 Dec 2007 23:48:30 +0000 Subject: [PATCH] added keywords to -> contract svn: r8041 original commit: 0e43e1da8ca10aad81945c47a7dc98faba28c459 --- .../scheme/private/contract-arr-checks.ss | 33 ++- .../private/contract-arr-obj-helpers.ss | 16 +- collects/scheme/private/contract-arrow.ss | 221 +++++++++++++----- collects/tests/mzscheme/contract-test.ss | 144 +++++++++++- 4 files changed, 335 insertions(+), 79 deletions(-) diff --git a/collects/scheme/private/contract-arr-checks.ss b/collects/scheme/private/contract-arr-checks.ss index 977cbb6..1c1a399 100644 --- a/collects/scheme/private/contract-arr-checks.ss +++ b/collects/scheme/private/contract-arr-checks.ss @@ -58,6 +58,10 @@ arity-count f))) +(define (get-mandatory-keywords f) + (let-values ([(mandatory optional) (procedure-keywords f)]) + mandatory)) + (define (no-mandatory-keywords? f) (let-values ([(mandatory optional) (procedure-keywords f)]) (null? mandatory))) @@ -89,19 +93,31 @@ orig-str "post-condition expression failure"))) -(define (check-procedure val dom-length src-info blame orig-str) +(define (check-procedure val dom-length mandatory-kwds src-info blame orig-str) (unless (and (procedure? val) - (and (procedure-arity-includes? val dom-length) - (no-mandatory-keywords? val))) + (procedure-arity-includes? val dom-length) + (equal? mandatory-kwds (get-mandatory-keywords val))) (raise-contract-error val src-info blame orig-str - "expected a procedure that accepts ~a arguments without any keywords, given: ~e" + "expected a procedure that accepts ~a arguments~a, given: ~e" dom-length + (keyword-error-text mandatory-kwds) val))) +(define (keyword-error-text mandatory-keywords) + (cond + [(null? mandatory-keywords) " without any keywords"] + [(null? (cdr mandatory-keywords)) + (format " and the keyword ~a" (car mandatory-keywords))] + [else + (format + " and the keywords ~a~a" + (car mandatory-keywords) + (apply string-append (map (λ (x) (format " ~a" x)) (cdr mandatory-keywords))))])) + (define ((check-procedure? arity) val) (and (procedure? val) (procedure-arity-includes? val arity) @@ -149,17 +165,18 @@ (procedure-arity val) val))) -(define (check-procedure/more val dom-length src-info blame orig-str) +(define (check-procedure/more val dom-length mandatory-kwds src-info blame orig-str) (unless (and (procedure? val) - (procedure-accepts-and-more? val dom-length)) + (procedure-accepts-and-more? val dom-length) + (equal? mandatory-kwds (get-mandatory-keywords val))) (raise-contract-error val src-info blame orig-str - "expected a procedure that accepts ~a arguments and any number of arguments larger than ~a, given: ~e" - dom-length + "expected a procedure that accepts ~a arguments and and arbitrarily more~a, given: ~e" dom-length + (keyword-error-text mandatory-kwds) val))) diff --git a/collects/scheme/private/contract-arr-obj-helpers.ss b/collects/scheme/private/contract-arr-obj-helpers.ss index affb0d9..4e76478 100644 --- a/collects/scheme/private/contract-arr-obj-helpers.ss +++ b/collects/scheme/private/contract-arr-obj-helpers.ss @@ -382,7 +382,7 @@ (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) (syntax - (check-procedure val dom-length src-info pos-blame orig-str)))) + (check-procedure val dom-length '() #|mandatory-keywords|# src-info pos-blame orig-str)))) (syntax (check-procedure? dom-length)) (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) @@ -428,7 +428,7 @@ (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) (syntax - (check-procedure val dom-length src-info pos-blame orig-str)))) + (check-procedure val dom-length '() #|mandatory-keywords|# src-info pos-blame orig-str)))) (syntax (check-procedure? dom-length)) (lambda (outer-args) @@ -472,7 +472,7 @@ (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) (syntax - (check-procedure val dom-length src-info pos-blame orig-str)))) + (check-procedure val dom-length '() #|mandatory keywords|# src-info pos-blame orig-str)))) (syntax (check-procedure? dom-length)) (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) @@ -548,7 +548,7 @@ (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) (syntax - (check-procedure/more val dom-length src-info pos-blame orig-str)))) + (check-procedure/more val dom-length '() #|mandatory keywords|# src-info pos-blame orig-str)))) (syntax (check-procedure/more? dom-length)) (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) @@ -610,7 +610,7 @@ (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) (syntax - (check-procedure/more val dom-length src-info pos-blame orig-str)))) + (check-procedure/more val dom-length '() #|mandatory keywords|# src-info pos-blame orig-str)))) (syntax (check-procedure/more? dom-length)) (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) @@ -663,7 +663,7 @@ (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) (syntax - (check-procedure val arity src-info pos-blame orig-str)))) + (check-procedure val arity '() #|mandatory keywords|# src-info pos-blame orig-str)))) (syntax (check-procedure? arity)) @@ -723,7 +723,7 @@ (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) (syntax - (check-procedure val dom-length src-info pos-blame orig-str)))) + (check-procedure val dom-length '() #|mandatory keywords|# src-info pos-blame orig-str)))) (syntax (check-procedure? dom-length)) (lambda (outer-args) @@ -797,7 +797,7 @@ (lambda (outer-args) (with-syntax ([(val pos-blame neg-blame src-info orig-str name-id) outer-args]) (syntax - (check-procedure/more val arity src-info pos-blame orig-str)))) + (check-procedure/more val arity '() #|mandatory keywords|# src-info pos-blame orig-str)))) (syntax (check-procedure/more? arity)) (lambda (outer-args) diff --git a/collects/scheme/private/contract-arrow.ss b/collects/scheme/private/contract-arrow.ss index c638cae..00ccfc5 100644 --- a/collects/scheme/private/contract-arrow.ss +++ b/collects/scheme/private/contract-arrow.ss @@ -2,11 +2,21 @@ #| -add mandatory keywords to ->, ->* ->d ->d* +keywords done: + +- added mandatory keywords to -> + +keywords todo: + +add mandatory keywords to ->* ->d ->d* Add both optional and mandatory keywords to opt-> and friends. (Update opt-> so that it doesn't use case-lambda anymore.) +- raise-syntax-errors + . multiple identical keywords syntax error, sort-keywords + . split-doms + |# (require "contract-guts.ss" @@ -16,8 +26,8 @@ Add both optional and mandatory keywords to opt-> and friends. (for-syntax "contract-opt-guts.ss") (for-syntax "contract-helpers.ss") (for-syntax "contract-arr-obj-helpers.ss") - (for-syntax (lib "stx.ss" "syntax")) - (for-syntax (lib "name.ss" "syntax"))) + (for-syntax syntax/stx) + (for-syntax syntax/name)) (provide -> ->d @@ -29,8 +39,7 @@ Add both optional and mandatory keywords to opt-> and friends. case-> opt-> opt->* - unconstrained-domain-> - check-procedure) + unconstrained-domain->) (define-syntax (unconstrained-domain-> stx) (syntax-case stx () @@ -57,20 +66,30 @@ Add both optional and mandatory keywords to opt-> and friends. "expected a procedure"))))) procedure?))))])) -;; FIXME: need to pass in the name of the contract combinator. -(define (build--> name doms doms-rest rngs rng-any? func) +(define (build--> name doms doms-rest rngs kwds quoted-kwds rng-any? func) (let ([doms/c (map (λ (dom) (coerce-contract name dom)) doms)] [rngs/c (map (λ (rng) (coerce-contract name rng)) rngs)] + [kwds/c (map (λ (kwd) (coerce-contract name kwd)) kwds)] [doms-rest/c (and doms-rest (coerce-contract name doms-rest))]) - (make--> rng-any? doms/c doms-rest/c rngs/c func))) - -(define-struct/prop -> (rng-any? doms dom-rest rngs func) + (make--> rng-any? doms/c doms-rest/c rngs/c kwds/c quoted-kwds func))) +;; rng-any? : boolean +;; doms : (listof contract) +;; dom-rest : (or/c false/c contract) +;; rngs : (listof contract) -- may be ignored by the wrapper function in the case of any +;; kwds : (listof contract) +;; quoted-keywords : (listof keyword) -- must be sorted by keyword< +;; func : the wrapper function maker. It accepts a procedure for +;; checking the first-order properties and the contracts +;; and it produces a wrapper-making function. +(define-struct/prop -> (rng-any? doms dom-rest rngs kwds quoted-kwds func) ((proj-prop (λ (ctc) (let* ([doms/c (map (λ (x) ((proj-get x) x)) (if (->-dom-rest ctc) (append (->-doms ctc) (list (->-dom-rest ctc))) (->-doms ctc)))] [rngs/c (map (λ (x) ((proj-get x) x)) (->-rngs ctc))] + [kwds/c (map (λ (x) ((proj-get x) x)) (->-kwds ctc))] + [mandatory-keywords (->-quoted-kwds ctc)] [func (->-func ctc)] [dom-length (length (->-doms ctc))] [check-proc @@ -81,10 +100,12 @@ Add both optional and mandatory keywords to opt-> and friends. (let ([partial-doms (map (λ (dom) (dom neg-blame pos-blame src-info orig-str)) doms/c)] [partial-ranges (map (λ (rng) (rng pos-blame neg-blame src-info orig-str)) - rngs/c)]) + rngs/c)] + [partial-kwds (map (λ (kwd) (kwd neg-blame pos-blame src-info orig-str)) + kwds/c)]) (apply func - (λ (val) (check-proc val dom-length src-info pos-blame orig-str)) - (append partial-doms partial-ranges))))))) + (λ (val) (check-proc val dom-length mandatory-keywords src-info pos-blame orig-str)) + (append partial-doms partial-ranges partial-kwds))))))) (name-prop (λ (ctc) (single-arrow-name-maker (->-doms ctc) (->-dom-rest ctc) @@ -134,68 +155,134 @@ Add both optional and mandatory keywords to opt-> and friends. [else (apply build-compound-type-name 'values rngs)])]) (apply build-compound-type-name '-> (append doms/c (list rng-name))))])) +(define-for-syntax (sort-keywords stx kwd/ctc-pairs) + (define (insert x lst) + (cond + [(null? lst) (list x)] + [else + (let ([fst-kwd (syntax-e (car (car lst)))]) + (printf "comparing ~s to ~s\n" (car x) fst-kwd) + (cond + [(equal? (syntax-e (car x)) fst-kwd) + (raise-syntax-error #f + "duplicate keyword" + stx + (car x))] + [(keywordlist kwd/ctc-pairs)]) + (cond + [(null? pairs) null] + [else (insert (car pairs) (loop (cdr pairs)))]))) + +(define-for-syntax (split-doms stx name raw-doms) + (let loop ([raw-doms raw-doms] + [doms '()] + [kwd-doms '()]) + (syntax-case raw-doms () + [() (list (reverse doms) + (sort-keywords stx kwd-doms))] + [(kwd arg . rest) + (and (keyword? (syntax-e #'kwd)) + (not (keyword? (syntax-e #'arg)))) + (loop #'rest + doms + (cons #'(kwd arg) kwd-doms))] + [(kwd arg . rest) + (and (keyword? (syntax-e #'kwd)) + (keyword? (syntax-e #'arg))) + (raise-syntax-error name + "expected a keyword followed by a contract" + stx + #'kwd)] + [(kwd) + (keyword? (syntax-e #'kwd)) + (raise-syntax-error name + "expected a keyword to be followed by a contract" + stx + #'kwd)] + [(x . rest) + (loop #'rest (cons #'x doms) kwd-doms)]))) + (define-for-syntax (->-helper stx) - (syntax-case* stx (-> any values) module-or-top-identifier=? - [(-> doms ... any) - (with-syntax ([(args ...) (generate-temporaries (syntax (doms ...)))] - [(dom-ctc ...) (generate-temporaries (syntax (doms ...)))] - [(ignored) (generate-temporaries (syntax (rng)))]) - (values (syntax (dom-ctc ...)) - (syntax (ignored)) - (syntax (doms ...)) - (syntax (any/c)) - (syntax ((args ...) (val (dom-ctc args) ...))) - #t))] - [(-> doms ... (values rngs ...)) - (with-syntax ([(args ...) (generate-temporaries (syntax (doms ...)))] - [(dom-ctc ...) (generate-temporaries (syntax (doms ...)))] - [(rng-x ...) (generate-temporaries (syntax (rngs ...)))] - [(rng-ctc ...) (generate-temporaries (syntax (rngs ...)))]) - (values (syntax (dom-ctc ...)) - (syntax (rng-ctc ...)) - (syntax (doms ...)) - (syntax (rngs ...)) - (syntax ((args ...) - (let-values ([(rng-x ...) (val (dom-ctc args) ...)]) - (values (rng-ctc rng-x) ...)))) - #f))] - [(_ doms ... rng) - (with-syntax ([(args ...) (generate-temporaries (syntax (doms ...)))] - [(dom-ctc ...) (generate-temporaries (syntax (doms ...)))] - [(rng-ctc) (generate-temporaries (syntax (rng)))]) - (values (syntax (dom-ctc ...)) - (syntax (rng-ctc)) - (syntax (doms ...)) - (syntax (rng)) - (syntax ((args ...) (rng-ctc (val (dom-ctc args) ...)))) - #f))])) + (syntax-case stx () + [(-> raw-doms ... last-one) + (with-syntax ([((doms ...) ((dom-kwd dom-kwd-ctc) ...)) (split-doms stx '-> #'(raw-doms ...))]) + (with-syntax ([(dom-kwd-arg ...) (generate-temporaries (syntax (dom-kwd ...)))] + [(dom-kwd-ctc-id ...) (generate-temporaries (syntax (dom-kwd ...)))]) + (with-syntax ([(keyword-call/ctc ...) (apply append (map syntax->list (syntax->list #'((dom-kwd (dom-kwd-ctc-id dom-kwd-arg)) ...))))] + [(keyword-formal-parameters ...) (apply append (map syntax->list (syntax->list #'((dom-kwd dom-kwd-arg) ...))))] + [(args ...) (generate-temporaries (syntax (doms ...)))] + [(dom-ctc ...) (generate-temporaries (syntax (doms ...)))]) + (syntax-case* #'last-one (-> any values) module-or-top-identifier=? + [any + (with-syntax ([(ignored) (generate-temporaries (syntax (rng)))]) + (values (syntax (dom-ctc ...)) + (syntax (ignored)) + (syntax (dom-kwd-ctc-id ...)) + (syntax (doms ...)) + (syntax (any/c)) + (syntax (dom-kwd-ctc ...)) + (syntax (dom-kwd ...)) + (syntax ((args ... keyword-formal-parameters ...) (val (dom-ctc args) ... keyword-call/ctc ...))) + #t))] + [(values rngs ...) + (with-syntax ([(rng-x ...) (generate-temporaries (syntax (rngs ...)))] + [(rng-ctc ...) (generate-temporaries (syntax (rngs ...)))]) + (values (syntax (dom-ctc ...)) + (syntax (rng-ctc ...)) + (syntax (dom-kwd-ctc-id ...)) + (syntax (doms ...)) + (syntax (rngs ...)) + (syntax (dom-kwd-ctc ...)) + (syntax (dom-kwd ...)) + (syntax ((args ... keyword-formal-parameters ...) + (let-values ([(rng-x ...) (val (dom-ctc args) ... keyword-call/ctc ...)]) + (values (rng-ctc rng-x) ...)))) + #f))] + [rng + (with-syntax ([(rng-ctc) (generate-temporaries (syntax (rng)))]) + (values (syntax (dom-ctc ...)) + (syntax (rng-ctc)) + (syntax (dom-kwd-ctc-id ...)) + (syntax (doms ...)) + (syntax (rng)) + (syntax (dom-kwd-ctc ...)) + (syntax (dom-kwd ...)) + (syntax ((args ... keyword-formal-parameters ...) (rng-ctc (val (dom-ctc args) ... keyword-call/ctc ...)))) + #f))]))))])) ;; ->/proc/main : syntax -> (values syntax[contract-record] syntax[args/lambda-body] syntax[names]) (define-for-syntax (->/proc/main stx) - (let-values ([(dom-names rng-names dom-ctcs rng-ctcs inner-args/body use-any?) (->-helper stx)]) + (let-values ([(dom-names rng-names kwd-names dom-ctcs rng-ctcs kwd-ctcs kwds inner-args/body use-any?) (->-helper stx)]) (with-syntax ([(args body) inner-args/body]) (with-syntax ([(dom-names ...) dom-names] [(rng-names ...) rng-names] + [(kwd-names ...) kwd-names] [(dom-ctcs ...) dom-ctcs] [(rng-ctcs ...) rng-ctcs] + [(kwd-ctcs ...) kwd-ctcs] + [(kwds ...) kwds] [inner-lambda (add-name-prop (syntax-local-infer-name stx) (syntax (lambda args body)))] [use-any? use-any?]) (with-syntax ([outer-lambda - (let* ([lst (syntax->list #'args)] - [len (and lst (length lst))]) - (syntax - (lambda (chk dom-names ... rng-names ...) - (lambda (val) - (chk val) - inner-lambda))))]) + (syntax + (lambda (chk dom-names ... rng-names ... kwd-names ...) + (lambda (val) + (chk val) + inner-lambda)))]) (values (syntax (build--> '-> (list dom-ctcs ...) #f (list rng-ctcs ...) + (list kwd-ctcs ...) + '(kwds ...) use-any? outer-lambda)) inner-args/body @@ -237,6 +324,8 @@ Add both optional and mandatory keywords to opt-> and friends. (list doms ...) rst (list rngs ...) + '() + '() #f outer-lambda)) inner-args/body @@ -263,6 +352,8 @@ Add both optional and mandatory keywords to opt-> and friends. (list doms ...) rst (list any/c) + '() + '() #t outer-lambda)) inner-args/body @@ -364,7 +455,7 @@ Add both optional and mandatory keywords to opt-> and friends. (dom-len (length dom-vars)) ((next-rng ...) next-rngs)) (syntax (begin - (check-procedure val dom-len src-info pos orig-str) + (check-procedure val dom-len '() #| mandatory-keywords |# src-info pos orig-str) (λ (dom-arg ...) (let-values ([(rng-arg ...) (val next-dom ...)]) (values next-rng ...)))))) @@ -412,7 +503,7 @@ Add both optional and mandatory keywords to opt-> and friends. ((next-dom ...) next-doms) (dom-len (length dom-vars))) (syntax (begin - (check-procedure val dom-len src-info pos orig-str) + (check-procedure val dom-len '() #|mandatory-keywords|# src-info pos orig-str) (λ (dom-arg ...) (val next-dom ...))))) lifts-doms @@ -424,10 +515,16 @@ Add both optional and mandatory keywords to opt-> and friends. (syntax-case* stx (-> values any) module-or-top-identifier=? [(-> dom ... (values rng ...)) - (opt/arrow-ctc (syntax->list (syntax (dom ...))) - (syntax->list (syntax (rng ...))))] + (if (ormap (λ (x) (keyword? (syntax-e x))) (syntax->list #'(dom ...))) + (opt/unknown opt/i opt/info stx) ;; give up if there is a mandatory keyword + (opt/arrow-ctc (syntax->list (syntax (dom ...))) + (syntax->list (syntax (rng ...)))))] [(-> dom ... any) - (opt/arrow-any-ctc (syntax->list (syntax (dom ...))))] + (if (ormap (λ (x) (keyword? (syntax-e x))) (syntax->list #'(dom ...))) + (opt/unknown opt/i opt/info stx) ;; give up if there is a mandatory keyword + (opt/arrow-any-ctc (syntax->list (syntax (dom ...)))))] [(-> dom ... rng) - (opt/arrow-ctc (syntax->list (syntax (dom ...))) - (list #'rng))])) + (if (ormap (λ (x) (keyword? (syntax-e x))) (syntax->list #'(dom ...))) + (opt/unknown opt/i opt/info stx) ;; give up if there is a mandatory keyword + (opt/arrow-ctc (syntax->list (syntax (dom ...))) + (list #'rng)))])) diff --git a/collects/tests/mzscheme/contract-test.ss b/collects/tests/mzscheme/contract-test.ss index 7ed3e5a..14cb8f0 100644 --- a/collects/tests/mzscheme/contract-test.ss +++ b/collects/tests/mzscheme/contract-test.ss @@ -428,12 +428,154 @@ 1)) (test/pos-blame - 'contract-arrow-keyword + 'contract-arrow-keyword1 + '(contract (-> integer? any) + (λ (x #:y y) x) + 'pos + 'neg)) + + (test/pos-blame + 'contract-arrow-keyword1b + '(contract (-> integer? #:y integer? any) + (λ (x) x) + 'pos + 'neg)) + + (test/spec-passed + 'contract-arrow-keyword2 + '(contract (-> integer? #:y boolean? any) + (λ (x #:y y) x) + 'pos + 'neg)) + + (test/spec-passed + 'contract-arrow-keyword2b + '(contract (-> #:x boolean? #:y boolean? any) + (λ (#:x x #:y y) x) + 'pos + 'neg)) + + (test/spec-passed + 'contract-arrow-keyword2c + '(contract (-> #:y boolean? #:x boolean? any) + (λ (#:x x #:y y) x) + 'pos + 'neg)) + + (test/spec-passed + 'contract-arrow-keyword2d + '(contract (-> #:y boolean? #:x boolean? any) + (λ (#:y y #:x x) x) + 'pos + 'neg)) + + (test/spec-passed + 'contract-arrow-keyword2e + '(contract (-> #:x boolean? #:y boolean? any) + (λ (#:y y #:x x) x) + 'pos + 'neg)) + + (test/neg-blame + 'contract-arrow-keyword3 + '((contract (-> integer? #:y boolean? any) + (λ (x #:y y) x) + 'pos + 'neg) + 1 #:y 1)) + + (test/neg-blame + 'contract-arrow-keyword4 + '((contract (-> integer? #:y boolean? any) + (λ (x #:y y) x) + 'pos + 'neg) + #t #:y #t)) + + (test/spec-passed + 'contract-arrow-keyword5 + '((contract (-> integer? #:y boolean? any) + (λ (x #:y y) x) + 'pos + 'neg) + 1 #:y #t)) + + (test/pos-blame + 'contract-arrow-keyword6 '(contract (-> integer? integer?) (λ (x #:y y) x) 'pos 'neg)) + (test/spec-passed + 'contract-arrow-keyword7 + '(contract (-> integer? #:y boolean? integer?) + (λ (x #:y y) x) + 'pos + 'neg)) + + (test/neg-blame + 'contract-arrow-keyword8 + '((contract (-> integer? #:y boolean? integer?) + (λ (x #:y y) x) + 'pos + 'neg) + 1 #:y 1)) + + (test/neg-blame + 'contract-arrow-keyword9 + '((contract (-> integer? #:y boolean? integer?) + (λ (x #:y y) x) + 'pos + 'neg) + #t #:y #t)) + + (test/spec-passed + 'contract-arrow-keyword10 + '((contract (-> integer? #:y boolean? integer?) + (λ (x #:y y) x) + 'pos + 'neg) + 1 #:y #t)) + + (test/pos-blame + 'contract-arrow-keyword11 + '(contract (-> integer? (values integer? integer?)) + (λ (x #:y y) x) + 'pos + 'neg)) + + (test/spec-passed + 'contract-arrow-keyword12 + '(contract (-> integer? #:y boolean? (values integer? integer?)) + (λ (x #:y y) x) + 'pos + 'neg)) + + (test/neg-blame + 'contract-arrow-keyword13 + '((contract (-> integer? #:y boolean? (values integer? integer?)) + (λ (x #:y y) x) + 'pos + 'neg) + 1 #:y 1)) + + (test/neg-blame + 'contract-arrow-keyword14 + '((contract (-> integer? #:y boolean? (values integer? integer?)) + (λ (x #:y y) x) + 'pos + 'neg) + #t #:y #t)) + + (test/spec-passed + 'contract-arrow-keyword15 + '((contract (-> integer? #:y boolean? (values integer? integer?)) + (λ (x #:y y) (values x x)) + 'pos + 'neg) + 1 #:y #t)) + (test/pos-blame 'contract-d1 '(contract (integer? . ->d . (lambda (x) (lambda (y) (= x y))))