From 0f73870a1b82bf9252b0a4f52693dd19c343ce1e Mon Sep 17 00:00:00 2001 From: Robby Findler Date: Tue, 8 Mar 2016 21:15:43 -0600 Subject: [PATCH] fix keyword argument order bug in ->i the bug required all mandatory arguments to manifest closes PR 15267 --- .../tests/racket/contract/arrow-i.rkt | 8 ++ .../racket/contract/private/arr-i.rkt | 80 +++++++++---------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/pkgs/racket-test/tests/racket/contract/arrow-i.rkt b/pkgs/racket-test/tests/racket/contract/arrow-i.rkt index 405068d110..a6571eb41a 100644 --- a/pkgs/racket-test/tests/racket/contract/arrow-i.rkt +++ b/pkgs/racket-test/tests/racket/contract/arrow-i.rkt @@ -928,6 +928,14 @@ 'pos 'neg) 3 2 1) 3) + + (test/spec-passed/result + '->i54 + '((contract (->i (#:one [one any/c] #:two [two any/c] #:three [three any/c]) any) + (λ (#:one one #:two two #:three three) (list one two three)) + 'pos 'neg) + #:one 1 #:two 2 #:three 3) + '(1 2 3)) (test/pos-blame '->i-arity1 diff --git a/racket/collects/racket/contract/private/arr-i.rkt b/racket/collects/racket/contract/private/arr-i.rkt index 14078a6243..5470e974ef 100644 --- a/racket/collects/racket/contract/private/arr-i.rkt +++ b/racket/collects/racket/contract/private/arr-i.rkt @@ -480,31 +480,33 @@ evaluted left-to-right.) (define-for-syntax (args/vars->arg-checker result-checkers args rst vars this-param) (let ([opts? (ormap arg-optional? args)] [this-params (if this-param (list this-param) '())]) + + (define arg->var (make-hash)) + (define kwd-args (filter arg-kwd args)) + (define non-kwd-args (filter (λ (x) (not (arg-kwd x))) args)) + + (for ([arg (in-list args)] + [var (in-vector vars)]) + (hash-set! arg->var arg var)) + + (define sorted-kwd/arg-pairs + (sort + (map (λ (arg) (cons (arg-kwd arg) (hash-ref arg->var arg))) kwd-args) + (λ (x y) (keywordvar arg)) non-kwd-args)) (cond [(and opts? (ormap arg-kwd args)) - (let* ([arg->var (make-hash)] - [kwd-args (filter arg-kwd args)] - [non-kwd-args (filter (λ (x) (not (arg-kwd x))) args)]) - - (for ([arg (in-list args)] - [var (in-vector vars)]) - (hash-set! arg->var arg var)) - - (let ([sorted-kwd/arg-pairs - (sort - (map (λ (arg) (cons (arg-kwd arg) (hash-ref arg->var arg))) kwd-args) - (λ (x y) (keywordvar arg)) non-kwd-args))))] + ;; has both optional and keyword args + #`(keyword-return/no-unsupplied + #,(if (null? result-checkers) #f (car result-checkers)) + '#,(map car sorted-kwd/arg-pairs) + (list #,@keyword-arguments) + #,(if rst + #'rest-args + #''()) + #,@this-params + #,@regular-arguments)] [opts? ;; has optional args, but no keyword args #`(return/no-unsupplied #,(if (null? result-checkers) #f (car result-checkers)) @@ -516,27 +518,17 @@ evaluted left-to-right.) (all-but-last (vector->list vars)) (vector->list vars)))] [else - (let*-values ([(rev-regs rev-kwds) - (for/fold ([regs null] - [kwds null]) - ([arg (in-list args)] - [i (in-naturals)]) - (if (arg-kwd arg) - (values regs (cons (vector-ref vars i) kwds)) - (values (cons (vector-ref vars i) regs) kwds)))] - [(regular-arguments keyword-arguments) - (values (reverse rev-regs) (reverse rev-kwds))]) - (cond - [(and (null? keyword-arguments) rst) - #`(apply values #,@result-checkers #,@this-params #,@regular-arguments rest-args)] - [(null? keyword-arguments) - #`(values #,@result-checkers #,@this-params #,@regular-arguments)] - [rst - #`(apply values #,@result-checkers (list #,@keyword-arguments) - #,@this-params #,@regular-arguments rest-args)] - [else - #`(values #,@result-checkers (list #,@keyword-arguments) - #,@this-params #,@regular-arguments)]))]))) + (cond + [(and (null? keyword-arguments) rst) + #`(apply values #,@result-checkers #,@this-params #,@regular-arguments rest-args)] + [(null? keyword-arguments) + #`(values #,@result-checkers #,@this-params #,@regular-arguments)] + [rst + #`(apply values #,@result-checkers (list #,@keyword-arguments) + #,@this-params #,@regular-arguments rest-args)] + [else + #`(values #,@result-checkers (list #,@keyword-arguments) + #,@this-params #,@regular-arguments)])]))) (define (return/no-unsupplied res-checker rest-args . args) (if res-checker