mostly finished the contract library changes

svn: r8195
This commit is contained in:
Robby Findler 2008-01-03 18:10:43 +00:00
parent cbcb5bf57b
commit 3cf6ed4673
11 changed files with 853 additions and 2368 deletions

View File

@ -81,6 +81,20 @@
set-modified set-filename
get-file put-file
get-max-undo-history)
(rename-super [super-on-char on-char])
(define time 0)
(define count 0)
(override* [on-char
(λ (evt)
(let-values ([(results cpu real gc)
(time-apply (λ () (super-on-char evt)) '())])
(set! time (+ real time))
(set! count (+ count 1))
(when (= count 20)
(printf "time ~s\n" time)
(set! count 0)
(set! time 0))
(apply values results)))])
(define canvases null)
(define active-canvas #f)
(define auto-set-wrap? #f)

View File

@ -338,7 +338,8 @@
(let ([cls (make-wrapper-class 'wrapper-class
'(method-name ...)
(list methods ...)
'(field-name ...))])
'(field-name ...)
#t)])
(make-proj-contract
`(object-contract
,(build-compound-type-name 'method-name method-ctc-var) ...

View File

@ -22,7 +22,11 @@ differences from v3:
(except-out (all-from-out "private/contract-ds.ss")
lazy-depth-to-look)
(all-from-out "private/contract-arrow.ss")
(except-out (all-from-out "private/contract-arrow.ss")
making-a-method
procedure-accepts-and-more?
check-procedure
check-procedure/more)
(except-out (all-from-out "private/contract.ss")
check-between/c
check-unary-between/c))

View File

@ -3363,8 +3363,9 @@
;; make-wrapper-class : symbol
;; (listof symbol)
;; (listof (selector -> method-func-spec[object args -> result]))
;; method-spec [depends on the boolean what it is]
;; (listof symbol)
;; boolean
;; -> class
;; the resulting class is the "proxy" class for the contracted version of an
;; object with contracts on the method-ids.
@ -3379,7 +3380,7 @@
;; The class accepts one initialization argument per method and
;; one init arg per field (in that order) using the make-object style
;; initialization.
(define (make-wrapper-class class-name method-ids methods field-ids)
(define (make-wrapper-class class-name method-ids methods field-ids old-style?)
(let* ([supers (vector object% #f)]
[method-ht (make-hash-table)]
[method-count (length method-ids)]
@ -3403,7 +3404,9 @@
(list->vector (map (lambda (x) 'final) method-ids))
'dont-use-me!
(+ 1 field-count method-count)
(if old-style?
(+ field-count method-count 1)
field-count)
field-ht
field-ids
@ -3423,7 +3426,9 @@
(make-struct-type 'wrapper-object
struct:wrapper-object
0
(+ (length field-ids) (length method-ids))
(if old-style?
(+ (length field-ids) (length method-ids))
(length field-ids))
undefined
(list (cons prop:object cls))
insp)])
@ -3435,11 +3440,8 @@
(let ([init
(lambda (o continue-make-super c inited? named-args leftover-args)
;; leftover args will contain:
;; the original object,
;; all of the contract-ized versions of the methods,
;; and all of the contract-ized versions of the fields
;; just fill them into `o'.
;; leftover args will contain the original object and new field values
;; fill the original object in and then fill in the fields.
(set-wrapper-object-wrapped! o (car leftover-args))
(let loop ([leftover-args (cdr leftover-args)]
[i 0])
@ -3450,27 +3452,24 @@
(continue-make-super o c inited? '() '() '()))])
(set-class-init! cls init))
;; fill in the methods vector
(let loop ([i 0]
[methods methods])
(when (< i method-count)
(vector-set! methods-vec i ((car methods) field-ref))
(loop (+ i 1)
(cdr methods))))
;; fill in the methods-ht
;; fill in the methods vector & methods-ht
(let loop ([i 0]
[methods methods]
[method-ids method-ids])
(when (< i method-count)
(vector-set! methods-vec i (if old-style?
((car methods) field-ref)
(car methods)))
(hash-table-put! method-ht (car method-ids) i)
(loop (+ i 1)
(cdr methods)
(cdr method-ids))))
;; fill in the fields-ht
(let loop ([i 0]
[field-ids field-ids])
(when (< i field-count)
(hash-table-put! field-ht (car field-ids) (cons cls (+ i method-count)))
(hash-table-put! field-ht (car field-ids) (cons cls i))
(loop (+ i 1)
(cdr field-ids))))
@ -3655,7 +3654,8 @@
(provide (protect-out make-wrapper-class
wrapper-object-wrapped
extract-vtable
extract-method-ht)
extract-method-ht
get-field/proc)
(rename-out [_class class]) class* class/derived
define-serializable-class define-serializable-class*

View File

@ -1,234 +0,0 @@
#lang scheme/base
(provide (all-defined-out))
(require "contract-guts.ss")
(define empty-case-lambda/c
(flat-named-contract '(case->)
(λ (x) (and (procedure? x) (null? (procedure-arity x))))))
;; ----------------------------------------
;; Checks and error functions used in macro expansions
;; procedure-accepts-and-more? : procedure number -> boolean
;; returns #t if val accepts dom-length arguments and
;; any number of arguments more than dom-length.
;; returns #f otherwise.
(define (procedure-accepts-and-more? val dom-length)
(let ([arity (procedure-arity val)])
(cond
[(number? arity) #f]
[(arity-at-least? arity)
(<= (arity-at-least-value arity) dom-length)]
[else
(let ([min-at-least (let loop ([ars arity]
[acc #f])
(cond
[(null? ars) acc]
[else (let ([ar (car ars)])
(cond
[(arity-at-least? ar)
(if (and acc
(< acc (arity-at-least-value ar)))
(loop (cdr ars) acc)
(loop (cdr ars) (arity-at-least-value ar)))]
[(number? ar)
(loop (cdr ars) acc)]))]))])
(and min-at-least
(begin
(let loop ([counts (sort (filter number? arity) >=)])
(unless (null? counts)
(let ([count (car counts)])
(cond
[(= (+ count 1) min-at-least)
(set! min-at-least count)
(loop (cdr counts))]
[(< count min-at-least)
(void)]
[else (loop (cdr counts))]))))
(<= min-at-least dom-length))))])))
(define (check->* f arity-count)
(unless (procedure? f)
(error 'object-contract "expected last argument of ->d* to be a procedure, got ~e" f))
(unless (and (procedure-arity-includes? f arity-count)
(no-mandatory-keywords? f))
(error 'object-contract
"expected last argument of ->d* to be a procedure that accepts ~a arguments, got ~e"
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)))
(define (check->*/more f arity-count)
(unless (procedure? f)
(error 'object-contract "expected last argument of ->d* to be a procedure, got ~e" f))
(unless (procedure-accepts-and-more? f arity-count)
(error 'object-contract
"expected last argument of ->d* to be a procedure that accepts ~a argument~a and arbitrarily many more, got ~e"
arity-count
(if (= 1 arity-count) "" "s")
f)))
(define (check-pre-expr->pp/h val pre-expr src-info blame orig-str)
(unless pre-expr
(raise-contract-error val
src-info
blame
orig-str
"pre-condition expression failure")))
(define (check-post-expr->pp/h val post-expr src-info blame orig-str)
(unless post-expr
(raise-contract-error val
src-info
blame
orig-str
"post-condition expression failure")))
(define (check-procedure val dom-length optionals mandatory-kwds optional-keywords src-info blame orig-str)
(unless (and (procedure? val)
(procedure-arity-includes?/optionals val dom-length optionals)
(keywords-match mandatory-kwds optional-keywords val))
(raise-contract-error
val
src-info
blame
orig-str
"expected a procedure that accepts ~a arguments~a, given: ~e"
dom-length
(keyword-error-text mandatory-kwds)
val)))
(define (procedure-arity-includes?/optionals f base optionals)
(cond
[(zero? optionals) (procedure-arity-includes? f base)]
[else (and (procedure-arity-includes? f (+ base optionals))
(procedure-arity-includes?/optionals f base (- optionals 1)))]))
(define (keywords-match mandatory-kwds optional-kwds val)
(let-values ([(proc-mandatory proc-all) (procedure-keywords val)])
(and (equal? proc-mandatory mandatory-kwds)
(andmap (λ (kwd) (and (member kwd proc-all)
(not (member kwd proc-mandatory))))
optional-kwds))))
(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)
(no-mandatory-keywords? val)))
(define ((check-procedure/more? arity) val)
(and (procedure? val)
(procedure-accepts-and-more? val arity)))
(define (check-procedure/kind val arity kind-of-thing src-info blame orig-str)
(unless (procedure? val)
(raise-contract-error val
src-info
blame
orig-str
"expected a procedure, got ~e"
val))
(unless (procedure-arity-includes? val arity)
(raise-contract-error val
src-info
blame
orig-str
"expected a ~a of arity ~a (not arity ~a), got ~e"
kind-of-thing
arity
(procedure-arity val)
val)))
(define (check-procedure/more/kind val arity kind-of-thing src-info blame orig-str)
(unless (procedure? val)
(raise-contract-error val
src-info
blame
orig-str
"expected a procedure, got ~e"
val))
(unless (procedure-accepts-and-more? val arity)
(raise-contract-error val
src-info
blame
orig-str
"expected a ~a that accepts ~a arguments and aribtrarily more (not arity ~a), got ~e"
kind-of-thing
arity
(procedure-arity val)
val)))
(define (check-procedure/more val dom-length mandatory-kwds optional-kwds src-info blame orig-str)
(unless (and (procedure? val)
(procedure-accepts-and-more? val dom-length)
(keywords-match mandatory-kwds optional-kwds val))
(raise-contract-error
val
src-info
blame
orig-str
"expected a procedure that accepts ~a arguments and and arbitrarily more~a, given: ~e"
dom-length
(keyword-error-text mandatory-kwds)
val)))
(define (check-rng-procedure who rng-x arity)
(unless (and (procedure? rng-x)
(procedure-arity-includes? rng-x arity))
(error who "expected range position to be a procedure that accepts ~a arguments, given: ~e"
arity
rng-x)))
(define (check-rng-procedure/more rng-mk-x arity)
(unless (and (procedure? rng-mk-x)
(procedure-accepts-and-more? rng-mk-x arity))
(error '->d* "expected range position to be a procedure that accepts ~a arguments and arbitrarily many more, given: ~e"
arity
rng-mk-x)))
(define (check-rng-lengths results rng-contracts)
(unless (= (length results) (length rng-contracts))
(error '->d*
"expected range contract contructor and function to have the same number of values, given: ~a and ~a respectively"
(length results) (length rng-contracts))))
#|
test cases for procedure-accepts-and-more?
(and (procedure-accepts-and-more? (lambda (x . y) 1) 3)
(procedure-accepts-and-more? (lambda (x . y) 1) 2)
(procedure-accepts-and-more? (lambda (x . y) 1) 1)
(not (procedure-accepts-and-more? (lambda (x . y) 1) 0))
(procedure-accepts-and-more? (case-lambda [(x . y) 1] [(y) 1]) 3)
(procedure-accepts-and-more? (case-lambda [(x . y) 1] [(y) 1]) 2)
(procedure-accepts-and-more? (case-lambda [(x . y) 1] [(y) 1]) 1)
(not (procedure-accepts-and-more? (case-lambda [(x . y) 1] [(y) 1]) 0))
(procedure-accepts-and-more? (case-lambda [(x y . z) 1] [(x) 1]) 2)
(procedure-accepts-and-more? (case-lambda [(x y . z) 1] [(x) 1]) 1)
(not (procedure-accepts-and-more? (case-lambda [(x y . z) 1] [(x) 1]) 0)))
|#

File diff suppressed because it is too large Load Diff

View File

@ -8,14 +8,15 @@ v4 done:
- rewrote ->* using new notation
- rewrote ->d using new notation
- rewrote case->
- rewrote object-contract
v4 todo:
- rewrite object-contract to use new function combinators.
- add case-> to object-contract
- remove opt-> opt->* ->pp ->pp-rest ->r ->d*
- improve the generation of wrappers to avoid 'apply' and to make keywords work.
- remove extra checks from contract-arr-checks.ss (after object-contract is done).
- test object-contract with keywords (both optional and mandatory)
- change mzlib/contract to rewrite into scheme/contract (maybe?)
@ -23,15 +24,16 @@ v4 todo:
. multiple identical keywords syntax error, sort-keywords
. split-doms
- note timing/size tests at the end of the file.
|#
(require "contract-guts.ss"
"contract-arr-checks.ss"
"contract-opt.ss")
"contract-opt.ss"
scheme/stxparam)
(require (for-syntax scheme/base)
(for-syntax "contract-opt-guts.ss")
(for-syntax "contract-helpers.ss")
(for-syntax "contract-arr-obj-helpers.ss")
(for-syntax syntax/stx)
(for-syntax syntax/name))
@ -40,7 +42,13 @@ v4 todo:
->d
case->
unconstrained-domain->
the-unsupplied-arg)
the-unsupplied-arg
making-a-method
procedure-accepts-and-more?
check-procedure
check-procedure/more)
(define-syntax-parameter making-a-method #f)
(define-syntax (unconstrained-domain-> stx)
(syntax-case stx ()
@ -136,9 +144,10 @@ v4 todo:
[partial-optional-kwds (map (λ (kwd) (kwd neg-blame pos-blame src-info orig-str))
optional-kwds-proj)])
(apply func
(λ (val) (if has-rest?
(check-procedure/more val dom-length mandatory-keywords optional-keywords src-info pos-blame orig-str)
(check-procedure val dom-length optionals-length mandatory-keywords optional-keywords src-info pos-blame orig-str)))
(λ (val mtd?)
(if has-rest?
(check-procedure/more val mtd? dom-length mandatory-keywords optional-keywords src-info pos-blame orig-str)
(check-procedure val mtd? dom-length optionals-length mandatory-keywords optional-keywords src-info pos-blame orig-str)))
(append partial-doms partial-optional-doms
partial-mandatory-kwds partial-optional-kwds
partial-ranges)))))))
@ -198,7 +207,7 @@ v4 todo:
(apply build-compound-type-name (append doms/c (apply append (map list kwds kwds/c))))
(apply build-compound-type-name (append optional-doms/c (apply append (map list optional-kwds optional-kwds/c))))
(if doms-rest
(list doms-rest range)
(list '#:rest doms-rest range)
(list range))))]
[else
(let ([rng-name
@ -279,7 +288,11 @@ v4 todo:
(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 ...)))])
[(dom-ctc ...) (generate-temporaries (syntax (doms ...)))]
[(this-parameter ...)
(if (syntax-parameter-value #'making-a-method)
(generate-temporaries '(this))
'())])
(syntax-case* #'last-one (-> any values) module-or-top-identifier=?
[any
(with-syntax ([(ignored) (generate-temporaries (syntax (rng)))])
@ -290,7 +303,8 @@ v4 todo:
(syntax (any/c))
(syntax (dom-kwd-ctc ...))
(syntax (dom-kwd ...))
(syntax ((args ... keyword-formal-parameters ...) (val (dom-ctc args) ... keyword-call/ctc ...)))
(syntax ((this-parameter ... args ... keyword-formal-parameters ...)
(val this-parameter ... (dom-ctc args) ... keyword-call/ctc ...)))
#t))]
[(values rngs ...)
(with-syntax ([(rng-x ...) (generate-temporaries (syntax (rngs ...)))]
@ -302,8 +316,8 @@ v4 todo:
(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 ...)])
(syntax ((this-parameter ... args ... keyword-formal-parameters ...)
(let-values ([(rng-x ...) (val this-parameter ... (dom-ctc args) ... keyword-call/ctc ...)])
(values (rng-ctc rng-x) ...))))
#f))]
[rng
@ -315,9 +329,15 @@ v4 todo:
(syntax (rng))
(syntax (dom-kwd-ctc ...))
(syntax (dom-kwd ...))
(syntax ((args ... keyword-formal-parameters ...) (rng-ctc (val (dom-ctc args) ... keyword-call/ctc ...))))
(syntax ((this-parameter ... args ... keyword-formal-parameters ...)
(rng-ctc (val this-parameter ... (dom-ctc args) ... keyword-call/ctc ...))))
#f))]))))]))
(define-for-syntax (maybe-a-method/name stx)
(if (syntax-parameter-value #'making-a-method)
(syntax-property stx 'method-arity-error #t)
stx))
;; ->/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 kwd-names dom-ctcs rng-ctcs kwd-ctcs kwds inner-args/body use-any?) (->-helper stx)])
@ -330,16 +350,16 @@ v4 todo:
[(kwd-ctcs ...) kwd-ctcs]
[(kwds ...) kwds]
[inner-lambda
(add-name-prop
(syntax-local-infer-name stx)
(syntax (lambda args body)))]
(maybe-a-method/name
(add-name-prop
(syntax-local-infer-name stx)
(syntax (lambda args body))))]
[use-any? use-any?])
(with-syntax ([outer-lambda
(syntax
(lambda (chk dom-names ... kwd-names ... rng-names ...)
(lambda (val)
(chk val)
inner-lambda)))])
#`(lambda (chk dom-names ... kwd-names ... rng-names ...)
(lambda (val)
(chk val #,(syntax-parameter-value #'making-a-method))
inner-lambda))])
(values
(syntax
(build--> '->
@ -352,8 +372,7 @@ v4 todo:
(define-syntax (-> stx)
(let-values ([(stx _1 _2) (->/proc/main stx)])
stx))
#`(syntax-parameterize ((making-a-method #f)) #,stx)))
;;
;; arrow opter
@ -426,7 +445,7 @@ v4 todo:
(dom-len (length dom-vars))
((next-rng ...) next-rngs))
(syntax (begin
(check-procedure val dom-len 0 '() '() #| keywords |# src-info pos orig-str)
(check-procedure val #f dom-len 0 '() '() #| keywords |# src-info pos orig-str)
(λ (dom-arg ...)
(let-values ([(rng-arg ...) (val next-dom ...)])
(values next-rng ...))))))
@ -474,7 +493,7 @@ v4 todo:
((next-dom ...) next-doms)
(dom-len (length dom-vars)))
(syntax (begin
(check-procedure val dom-len 0 '() '() #|keywords|# src-info pos orig-str)
(check-procedure val #f dom-len 0 '() '() #|keywords|# src-info pos orig-str)
(λ (dom-arg ...)
(val next-dom ...)))))
lifts-doms
@ -572,14 +591,18 @@ v4 todo:
;; rng-ctc (or/c #f syntax) -- #f means `any', syntax is a sequence of result values
(syntax-case #'rst (any values)
[(any) (values #f #f)]
[(rest-expr any) (values #'rest-expr #f)]
[(#:rest rest-expr any) (values #'rest-expr #f)]
[((values res-ctc ...)) (values #f #'(res-ctc ...))]
[(rest-expr (values res-ctc ...)) (values #'rest-expr #'(res-ctc ...))]
[(#:rest rest-expr (values res-ctc ...)) (values #'rest-expr #'(res-ctc ...))]
[(res-ctc) (values #f #'(res-ctc))]
[(rest-expr res-ctc) (values #'rest-expr #'(res-ctc))]
[(#:rest rest-expr res-ctc) (values #'rest-expr #'(res-ctc))]
[_ (raise-syntax-error #f "bad syntax" stx)])])
(with-syntax ([(rng-proj ...) (generate-temporaries (or rng-ctc '()))]
[(rng ...) (generate-temporaries (or rng-ctc '()))])
[(rng ...) (generate-temporaries (or rng-ctc '()))]
[(this-parameter ...)
(if (syntax-parameter-value #'making-a-method)
(generate-temporaries '(this))
'())])
#`(build-->
'->*
(list mandatory-dom ...)
@ -603,10 +626,11 @@ v4 todo:
optional-dom-kwd-proj ...
rng-proj ...)
(λ (f)
(chk f)
(chk f #,(syntax-parameter-value #'making-a-method))
#,(add-name-prop
(syntax-local-infer-name stx)
#`(λ (mandatory-dom-arg ...
#`(λ (this-parameter ...
mandatory-dom-arg ...
[optional-dom-arg unspecified-dom] ...
mandatory-dom-kwd/var-seq ...
optional-dom-kwd/var-seq ...
@ -625,15 +649,16 @@ v4 todo:
opt-args
(cons (rev-optional-dom-proj rev-optional-dom-arg) opt-args))]
...)
#,(let ([call (if (null? (syntax->list #'(rev-sorted-dom-kwd ...)))
#'(apply f (mandatory-dom-proj mandatory-dom-arg) ... opt-args)
#'(keyword-apply f kwds kwd-args (mandatory-dom-proj mandatory-dom-arg) ... opt-args))])
#,(let ([call
(if (null? (syntax->list #'(rev-sorted-dom-kwd ...)))
#'(apply f this-parameter ... (mandatory-dom-proj mandatory-dom-arg) ... opt-args)
#'(keyword-apply f this-parameter ... kwds kwd-args (mandatory-dom-proj mandatory-dom-arg) ... opt-args))])
(if rng-ctc
#`(let-values ([(rng ...) #,call])
(values (rng-proj rng) ...))
call))))))))))))))]))
(define-syntax (->* stx) (->*/proc/main stx))
(define-syntax (->* stx) #`(syntax-parameterize ((making-a-method #f)) #,(->*/proc/main stx)))
@ -656,10 +681,16 @@ v4 todo:
(define-for-syntax (parse-leftover stx leftover)
(let*-values ([(id/rest-id leftover)
(syntax-case leftover ()
[(id rest-expr . leftover)
[(#:rest id rest-expr . leftover)
(and (identifier? #'id)
(not (keyword? (syntax-e #'rest-expr))))
(values #'(id rest-expr) #'leftover)]
[(#:rest id rest-expr . leftover)
(begin
(unless (identifier? #'id)
(raise-syntax-error #f "expected an identifier" stx #'id))
(when (keyword? (syntax-e #'rest-expr))
(raise-syntax-error #f "expected an expression, not a keyword" stx #'rest-expr)))]
[_ (values #f leftover)])]
[(pre-cond leftover)
(syntax-case leftover ()
@ -670,7 +701,7 @@ v4 todo:
(syntax-case leftover ()
[(range . leftover) (values #'range #'leftover)]
[_
(raise-syntax-error #f "bad syntax" stx)])]
(raise-syntax-error #f "expected a range expression, but found nothing" stx)])]
[(post-cond leftover)
(syntax-case leftover ()
[(#:post-cond post-cond . leftover)
@ -722,10 +753,15 @@ v4 todo:
stx
(syntax->list
#'((optional-kwd optional-kwd-id) ...
(mandatory-kwd mandatory-kwd-id) ...)))])
(mandatory-kwd mandatory-kwd-id) ...)))]
[(this-parameter ...)
(if (syntax-parameter-value #'making-a-method)
(list (datum->syntax stx 'this #f))
'())])
(let-values ([(id/rest pre-cond range post-cond) (parse-leftover stx #'leftover)])
(with-syntax ([(dom-params ...)
#`(mandatory-regular-id ...
#`(this-parameter ...
mandatory-regular-id ...
optional-regular-id ...
#,@(if id/rest
(with-syntax ([(id rst-ctc) id/rest])
@ -738,49 +774,59 @@ v4 todo:
[(values [id ctc] ... x . y) (raise-syntax-error #f "expected binding pair" stx #'x)]
[any #'(() #f)]
[[id ctc] #'((id) (ctc))]
[x (raise-syntax-error #f "expected binding pair or any" stx #'x)])])
[x (raise-syntax-error #f "expected binding pair or any" stx #'x)])]
[mtd? (syntax-parameter-value #'making-a-method)])
(let ([dup (check-duplicate-identifier (syntax->list #'(dom-params ... rng-params ...)))])
(when dup
(raise-syntax-error #f "duplicate identifier" stx dup)))
#`(build-->d (list (λ (dom-params ...) mandatory-doms) ...)
(list (λ (dom-params ...) optional-doms) ...)
(list (λ (dom-params ...) mandatory-kwd-dom) ...)
(list (λ (dom-params ...) optional-kwd-dom) ...)
#,(if id/rest
(with-syntax ([(id rst-ctc) id/rest])
#`(λ (dom-params ...) rst-ctc))
#f)
#,(if pre-cond
#`(λ (dom-params ...) #,pre-cond)
#f)
#,(syntax-case #'rng-ctcs ()
[#f #f]
[(ctc ...) #'(list (λ (rng-params ... dom-params ...) ctc) ...)])
#,(if post-cond
#`(λ (rng-params ... dom-params ...) #,post-cond)
#f)
'(mandatory-kwd ...)
'(optional-kwd ...)
(λ (f)
#,(add-name-prop
(syntax-local-infer-name stx)
#`(λ args (apply f args))))))))))]))
#`(syntax-parameterize
((making-a-method #f))
(build-->d mtd?
(list (λ (dom-params ...) mandatory-doms) ...)
(list (λ (dom-params ...) optional-doms) ...)
(list (λ (dom-params ...) mandatory-kwd-dom) ...)
(list (λ (dom-params ...) optional-kwd-dom) ...)
#,(if id/rest
(with-syntax ([(id rst-ctc) id/rest])
#`(λ (dom-params ...) rst-ctc))
#f)
#,(if pre-cond
#`(λ (dom-params ...) #,pre-cond)
#f)
#,(syntax-case #'rng-ctcs ()
[#f #f]
[(ctc ...) #'(list (λ (rng-params ... dom-params ...) ctc) ...)])
#,(if post-cond
#`(λ (rng-params ... dom-params ...) #,post-cond)
#f)
'(mandatory-kwd ...)
'(optional-kwd ...)
(λ (f)
#,(add-name-prop
(syntax-local-infer-name stx)
#`(λ args (apply f args)))))))))))]))
(define (->d-proj ->d-stct)
(let ([non-kwd-ctc-count (+ (length (->d-mandatory-dom-ctcs ->d-stct))
(length (->d-optional-dom-ctcs ->d-stct)))])
(length (->d-optional-dom-ctcs ->d-stct))
(if (->d-mtd? ->d-stct) 1 0))])
(λ (pos-blame neg-blame src-info orig-str)
(λ (val)
(check-procedure val
(->d-mtd? ->d-stct)
(length (->d-mandatory-dom-ctcs ->d-stct)) ;dom-length
(length (->d-optional-dom-ctcs ->d-stct)) ; optionals-length
(->d-mandatory-keywords ->d-stct)
(->d-optional-keywords ->d-stct)
src-info pos-blame orig-str)
(let ([kwd-proc
(λ (kwd-args kwd-arg-vals . orig-args)
(let* ([dep-pre-args
(build-dep-ctc-args non-kwd-ctc-count orig-args (->d-rest-ctc ->d-stct)
(λ (kwd-args kwd-arg-vals . raw-orig-args)
(let* ([orig-args (if (->d-mtd? ->d-stct)
(cdr raw-orig-args)
raw-orig-args)]
[this (and (->d-mtd? ->d-stct) (car raw-orig-args))]
[dep-pre-args
(build-dep-ctc-args non-kwd-ctc-count raw-orig-args (->d-rest-ctc ->d-stct)
(->d-keywords ->d-stct) kwd-args kwd-arg-vals)]
[thnk
(λ ()
@ -808,34 +854,41 @@ v4 todo:
(loop (cdr all-kwds) (cdr kwd-ctcs) (cdr building-kwd-args) (cdr building-kwd-arg-vals)))
(loop (cdr all-kwds) (cdr kwd-ctcs) building-kwd-args building-kwd-arg-vals))]))
;; contracted ordinary arguments
(let loop ([args orig-args]
[non-kwd-ctcs (append (->d-mandatory-dom-ctcs ->d-stct)
(->d-optional-dom-ctcs ->d-stct))])
(cond
[(null? args)
(if (->d-rest-ctc ->d-stct)
(invoke-dep-ctc (->d-rest-ctc ->d-stct) dep-pre-args '() neg-blame pos-blame src-info orig-str)
'())]
[(null? non-kwd-ctcs)
(if (->d-rest-ctc ->d-stct)
(invoke-dep-ctc (->d-rest-ctc ->d-stct) dep-pre-args args neg-blame pos-blame src-info orig-str)
;; ran out of arguments, but don't have a rest parameter.
;; procedure-reduce-arity (or whatever the new thing is
;; going to be called) should ensure this doesn't happen.
(error 'shouldnt\ happen))]
[else (cons (invoke-dep-ctc (car non-kwd-ctcs) dep-pre-args (car args) neg-blame pos-blame src-info orig-str)
(loop (cdr args)
(cdr non-kwd-ctcs)))]))))])
(append
;; this parameter (if necc.)
(if (->d-mtd? ->d-stct)
(list (car raw-orig-args))
'())
;; contracted ordinary arguments
(let loop ([args orig-args]
[non-kwd-ctcs (append (->d-mandatory-dom-ctcs ->d-stct)
(->d-optional-dom-ctcs ->d-stct))])
(cond
[(null? args)
(if (->d-rest-ctc ->d-stct)
(invoke-dep-ctc (->d-rest-ctc ->d-stct) dep-pre-args '() neg-blame pos-blame src-info orig-str)
'())]
[(null? non-kwd-ctcs)
(if (->d-rest-ctc ->d-stct)
(invoke-dep-ctc (->d-rest-ctc ->d-stct) dep-pre-args args neg-blame pos-blame src-info orig-str)
;; ran out of arguments, but don't have a rest parameter.
;; procedure-reduce-arity (or whatever the new thing is
;; going to be called) should ensure this doesn't happen.
(error 'shouldnt\ happen))]
[else (cons (invoke-dep-ctc (car non-kwd-ctcs) dep-pre-args (car args) neg-blame pos-blame src-info orig-str)
(loop (cdr args)
(cdr non-kwd-ctcs)))])))))])
(if (->d-range ->d-stct)
(call-with-values
thnk
(λ orig-results
(let* ([range-count (length (->d-range ->d-stct))]
[post-args (append orig-results orig-args)]
[post-args (append orig-results raw-orig-args)]
[post-non-kwd-arg-count (+ non-kwd-ctc-count range-count)]
[dep-post-args (build-dep-ctc-args post-non-kwd-arg-count post-args (->d-rest-ctc ->d-stct)
[dep-post-args (build-dep-ctc-args post-non-kwd-arg-count
post-args (->d-rest-ctc ->d-stct)
(->d-keywords ->d-stct) kwd-args kwd-arg-vals)])
(when (->d-post-cond ->d-stct)
(unless (apply (->d-post-cond ->d-stct) dep-post-args)
@ -877,7 +930,7 @@ v4 todo:
(define (build-dep-ctc-args non-kwd-ctc-count args rest-arg? all-kwds supplied-kwds supplied-args)
(append
;; ordinary args
;; ordinary args (possibly including `this' as the first element)
(let loop ([count non-kwd-ctc-count]
[args args])
(cond
@ -903,7 +956,8 @@ v4 todo:
(define-struct unsupplied-arg ())
(define the-unsupplied-arg (make-unsupplied-arg))
(define (build-->d mandatory-dom-ctcs optional-dom-ctcs
(define (build-->d mtd?
mandatory-dom-ctcs optional-dom-ctcs
mandatory-kwd-dom-ctcs optional-kwd-dom-ctcs
rest-ctc pre-cond range post-cond
mandatory-kwds optional-kwds
@ -913,7 +967,8 @@ v4 todo:
(append mandatory-kwds optional-kwds)
(append mandatory-kwd-dom-ctcs optional-kwd-dom-ctcs))
(λ (x y) (keyword<? (car x) (car y))))])
(make-->d mandatory-dom-ctcs optional-dom-ctcs
(make-->d mtd?
mandatory-dom-ctcs optional-dom-ctcs
(map cdr kwd/ctc-pairs)
rest-ctc pre-cond range post-cond
(map car kwd/ctc-pairs)
@ -921,7 +976,8 @@ v4 todo:
optional-kwds
name-wrapper)))
(define-struct/prop ->d (mandatory-dom-ctcs ;; (listof (-> ??? ctc))
(define-struct/prop ->d (mtd? ;; boolean; indicates if this is a contract on a method, for error reporing purposes.
mandatory-dom-ctcs ;; (listof (-> ??? ctc))
optional-dom-ctcs ;; (listof (-> ??? ctc))
keyword-ctcs ;; (listof (-> ??? ctc))
rest-ctc ;; (or/c false/c (-> ??? ctc))
@ -955,7 +1011,7 @@ v4 todo:
(,@(map (λ (x) `(,(next-id) ...)) (->d-optional-dom-ctcs ctc))
,@(apply append (map (λ (kwd) (list kwd `(,(next-id) ...))) (->d-optional-keywords ctc))))
,@(if (->d-rest-ctc ctc)
(list (next-id) '...)
(list '#:rest (next-id) '...)
'())
,@(if (->d-pre-cond ctc)
(list '#:pre-cond '...)
@ -1018,14 +1074,18 @@ v4 todo:
[(rst-formal) (generate-temporaries '(rest-param))]
[(rng-id ...) (if rng
(generate-temporaries rng)
'())])
'())]
[(this-parameter ...)
(if (syntax-parameter-value #'making-a-method)
(generate-temporaries '(this))
'())])
#`(#,doms
#,rst
#,(if rng #`(list #,@rng) #f)
#,(length (syntax->list doms)) ;; spec
(dom-proj-x ... #,@(if rst #'(rst-proj-x) #'()))
(rng-proj-x ...)
(dom-formals ... . #,(if rst #'rst-formal '()))
(this-parameter ... dom-formals ... . #,(if rst #'rst-formal '()))
#,(cond
[rng
(with-syntax ([(rng-exp ...) #'((rng-proj-x rng-id) ...)])
@ -1033,14 +1093,14 @@ v4 todo:
(car (syntax->list #'(rng-exp ...)))
#`(values rng-exp ...))])
(if rst
#`(let-values ([(rng-id ...) (apply f (dom-proj-x dom-formals) ... (rst-proj-x rst-formal))])
#`(let-values ([(rng-id ...) (apply f this-parameter ... (dom-proj-x dom-formals) ... (rst-proj-x rst-formal))])
rng)
#`(let-values ([(rng-id ...) (f (dom-proj-x dom-formals) ...)])
#`(let-values ([(rng-id ...) (f this-parameter ... (dom-proj-x dom-formals) ...)])
rng))))]
[rst
#`(apply f (dom-proj-x dom-formals) ... (rst-proj-x rst-formal))]
#`(apply f this-parameter ... (dom-proj-x dom-formals) ... (rst-proj-x rst-formal))]
[else
#`(f (dom-proj-x dom-formals) ...)]))))))
#`(f this-parameter ... (dom-proj-x dom-formals) ...)]))))))
(define-syntax (case-> stx)
(syntax-case stx ()
@ -1055,17 +1115,19 @@ v4 todo:
formals
body) ...)
(map (λ (x) (parse-out-case stx x)) (syntax->list #'(cases ...)))])
#`(build-case-> (list (list dom-proj ...) ...)
(list rst-proj ...)
(list rng-proj ...)
'(spec ...)
(λ (chk
#,@(apply append (map syntax->list (syntax->list #'((dom-proj-x ...) ...))))
#,@(apply append (map syntax->list (syntax->list #'((rng-proj-x ...) ...)))))
(λ (f)
(chk f)
(case-lambda
[formals body] ...))))))]))
#`(syntax-parameterize
((making-a-method #f))
(build-case-> (list (list dom-proj ...) ...)
(list rst-proj ...)
(list rng-proj ...)
'(spec ...)
(λ (chk
#,@(apply append (map syntax->list (syntax->list #'((dom-proj-x ...) ...))))
#,@(apply append (map syntax->list (syntax->list #'((rng-proj-x ...) ...)))))
(λ (f)
(chk f #,(syntax-parameter-value #'making-a-method))
(case-lambda
[formals body] ...)))))))]))
;; dom-ctcs : (listof (listof contract))
;; rst-ctcs : (listof contract)
@ -1084,7 +1146,7 @@ v4 todo:
(let ([projs (append (map (λ (f) (f neg-blame pos-blame src-info orig-str)) dom-ctcs)
(map (λ (f) (f pos-blame neg-blame src-info orig-str)) rng-ctcs))]
[chk
(λ (val)
(λ (val mtd?)
(cond
[(null? specs)
(unless (procedure? val)
@ -1097,8 +1159,8 @@ v4 todo:
(for-each
(λ (dom-length has-rest?)
(if has-rest?
(check-procedure/more val dom-length '() '() src-info pos-blame orig-str)
(check-procedure val dom-length 0 '() '() src-info pos-blame orig-str)))
(check-procedure/more val mtd? dom-length '() '() src-info pos-blame orig-str)
(check-procedure val mtd? dom-length 0 '() '() src-info pos-blame orig-str)))
specs rst-ctcs)]))])
(apply (case->-wrapper ctc)
chk
@ -1123,7 +1185,7 @@ v4 todo:
(case->-dom-ctcs ctc)
(case->-rst-ctcs ctc)
(case->-rng-ctcs ctc)))))
(first-order-prop (λ (ctc) #f))
(first-order-prop (λ (ctc) (λ (val) #f)))
(stronger-prop (λ (this that) #f))))
(define (build-case-> dom-ctcs rst-ctcs rng-ctcs specs wrapper)
@ -1143,3 +1205,203 @@ v4 todo:
(case->-rst-ctcs ctc))))
(define (get-case->-rng-ctcs ctc) (apply append (case->-rng-ctcs ctc)))
;
;
;
; ;;;; ;;;;
; ;;;; ;;;;
; ;;;;;;; ;;; ;;; ;;; ;;; ;;;;; ;;;; ;;; ;;; ;;;;; ;;;; ;;; ;;;;;
; ;;;;;;;; ;;;;;;; ;;;;;;; ;;;;;; ;;;;;;;;; ;;;;; ;;;;;; ;;;; ;;; ;;;;;;
; ;;;; ;;;; ;; ;;;; ;; ;;;;;;; ;;;; ;;;; ;;;; ;; ;;;;;;; ;;;;;;; ;;;;
; ;;;;;;; ;;;; ;;;; ;;;; ;;;; ;;;; ;;;;;;; ;;;; ;;;;;;; ;;;;
; ;; ;;;; ;;;; ;;;; ;;;;;;; ;;;; ;;;; ;;;;; ;;;;;;; ;;;; ;;; ;;;;
; ;;;;;;;; ;;;; ;;;; ;;;;;; ;;;; ;;;; ;;;;;; ;;;;;; ;;;; ;;; ;;;;;;
; ;; ;;;; ;;;; ;;;; ;;;;; ;;;; ;;;; ;;;; ;;;;; ;;;; ;;; ;;;;;
;
;
;
;; ----------------------------------------
;; Checks and error functions used in macro expansions
;; procedure-accepts-and-more? : procedure number -> boolean
;; returns #t if val accepts dom-length arguments and
;; any number of arguments more than dom-length.
;; returns #f otherwise.
(define (procedure-accepts-and-more? val dom-length)
(let ([arity (procedure-arity val)])
(cond
[(number? arity) #f]
[(arity-at-least? arity)
(<= (arity-at-least-value arity) dom-length)]
[else
(let ([min-at-least (let loop ([ars arity]
[acc #f])
(cond
[(null? ars) acc]
[else (let ([ar (car ars)])
(cond
[(arity-at-least? ar)
(if (and acc
(< acc (arity-at-least-value ar)))
(loop (cdr ars) acc)
(loop (cdr ars) (arity-at-least-value ar)))]
[(number? ar)
(loop (cdr ars) acc)]))]))])
(and min-at-least
(begin
(let loop ([counts (sort (filter number? arity) >=)])
(unless (null? counts)
(let ([count (car counts)])
(cond
[(= (+ count 1) min-at-least)
(set! min-at-least count)
(loop (cdr counts))]
[(< count min-at-least)
(void)]
[else (loop (cdr counts))]))))
(<= min-at-least dom-length))))])))
(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)))
(define (check-procedure val mtd? dom-length optionals mandatory-kwds optional-keywords src-info blame orig-str)
(unless (and (procedure? val)
(procedure-arity-includes?/optionals val (if mtd? (+ dom-length 1) dom-length) optionals)
(keywords-match mandatory-kwds optional-keywords val))
(raise-contract-error
val
src-info
blame
orig-str
"expected a ~a that accepts ~a arguments~a, given: ~e"
(if mtd? "method" "procedure")
dom-length
(keyword-error-text mandatory-kwds)
val)))
(define (procedure-arity-includes?/optionals f base optionals)
(cond
[(zero? optionals) (procedure-arity-includes? f base)]
[else (and (procedure-arity-includes? f (+ base optionals))
(procedure-arity-includes?/optionals f base (- optionals 1)))]))
(define (keywords-match mandatory-kwds optional-kwds val)
(let-values ([(proc-mandatory proc-all) (procedure-keywords val)])
(and (equal? proc-mandatory mandatory-kwds)
(andmap (λ (kwd) (and (member kwd proc-all)
(not (member kwd proc-mandatory))))
optional-kwds))))
(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/more val mtd? dom-length mandatory-kwds optional-kwds src-info blame orig-str)
(unless (and (procedure? val)
(procedure-accepts-and-more? val (if mtd? (+ dom-length 1) dom-length))
(keywords-match mandatory-kwds optional-kwds val))
(raise-contract-error
val
src-info
blame
orig-str
"expected a ~a that accepts ~a arguments and and arbitrarily more~a, given: ~e"
(if mtd? "method" "procedure")
dom-length
(keyword-error-text mandatory-kwds)
val)))
;; timing & size tests
#;
(begin
(require (prefix-in mz: mzlib/contract))
(define (time-test f)
(time
(let loop ([n 2000])
(unless (zero? n)
(f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1)
(f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1)
(f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1)
(f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1)
(f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1)
(f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1)
(f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1)
(f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1) (f 1)
(loop (- n 1))))))
(define (size stx)
(let ([sp (open-output-string)])
(write (compile stx) sp)
(close-output-port sp)
(string-length (get-output-string sp))))
'raw
(size #'(λ (x) x))
(time-test (λ (x) x))
'->
(size #'(-> number? number?))
(time-test (contract (-> number? number?) (λ (x) x) 'pos 'neg))
'mz:->
(size #'(mz:-> number? number?))
(time-test (contract (mz:-> number? number?) (λ (x) x) 'pos 'neg))
'->*
(size #'(->* (number?) () number?))
(time-test (contract (->* (number?) () number?) (λ (x) x) 'pos 'neg))
'mz:->*
(size #'(mz:->* (number?) any/c (number?)))
(time-test (contract (mz:->* (number?) any/c (number?)) (λ (x . y) x) 'pos 'neg))
'case->
(size #'(case-> (-> number? number?)))
(time-test (contract (case-> (-> number? number?)) (λ (x) x) 'pos 'neg))
'mz:case->
(size #'(mz:case-> (-> number? number?)))
(time-test (contract (mz:case-> (-> number? number?)) (λ (x) x) 'pos 'neg))
'->d
(size #'(->d ([x number?]) () [r number?]))
(time-test (contract (->d ([x number?]) () [r number?]) (λ (x) x) 'pos 'neg))
'mz:->r
(size #'(mz:->r ([x number?]) number?))
(time-test (contract (mz:->r ([x number?]) number?) (λ (x) x) 'pos 'neg))
'object-contract
(size #'(object-contract [m (-> number? number?)]))
(time-test
(let ([o (contract (object-contract [m (-> number? number?)])
(new (class object% (define/public (m x) x) (super-new)))
'pos
'neg)])
(λ (x) (send o m x))))
'mz:object-contract
(size #'(mz:object-contract [m (mz:-> number? number?)]))
(time-test
(let ([o (contract (mz:object-contract [m (mz:-> number? number?)])
(new (class object% (define/public (m x) x) (super-new)))
'pos
'neg)])
(λ (x) (send o m x)))))

View File

@ -2,11 +2,9 @@
(require "contract-arrow.ss"
"contract-guts.ss"
"class-internal.ss"
"contract-arr-checks.ss")
scheme/stxparam)
(require (for-syntax scheme/base
"contract-helpers.ss"
"contract-arr-obj-helpers.ss"))
(require (for-syntax scheme/base))
(provide mixin-contract
make-mixin-contract
@ -15,396 +13,127 @@
implementation?/c
object-contract)
(define-syntax object-contract
(let ()
(define (obj->/proc stx) (make-/proc #t ->/h stx))
(define (obj->*/proc stx) (make-/proc #t ->*/h stx))
(define (obj->d/proc stx) (make-/proc #t ->d/h stx))
(define (obj->d*/proc stx) (make-/proc #t ->d*/h stx))
(define (obj->r/proc stx) (make-/proc #t ->r/h stx))
(define (obj->pp/proc stx) (make-/proc #t ->pp/h stx))
(define (obj->pp-rest/proc stx) (make-/proc #t ->pp-rest/h stx))
(define (obj-case->/proc stx) (make-case->/proc #t stx stx select/h))
;; WARNING: select/h is copied from contract-arrow.ss. I'm not sure how
;; I can avoid this duplication -robby
(define (select/h stx err-name ctxt-stx)
(syntax-case stx (-> ->* ->d ->d* ->r ->pp ->pp-rest)
[(-> . args) ->/h]
[(->* . args) ->*/h]
[(->d . args) ->d/h]
[(->d* . args) ->d*/h]
[(->r . args) ->r/h]
[(->pp . args) ->pp/h]
[(->pp-rest . args) ->pp-rest/h]
[(xxx . args) (raise-syntax-error err-name "unknown arrow constructor" ctxt-stx (syntax xxx))]
[_ (raise-syntax-error err-name "malformed arrow clause" ctxt-stx stx)]))
(define (obj-opt->/proc stx) (make-opt->/proc #t stx select/h #'case-> #'->))
(define (obj-opt->*/proc stx) (make-opt->*/proc #t stx stx select/h #'case-> #'->))
(λ (stx)
;; name : syntax
;; ctc-stx : syntax[evals to a contract]
;; mtd-arg-stx : syntax[list of arg-specs] (ie, for use in a case-lambda)
(define-struct mtd (name ctc-stx mtd-arg-stx))
;; name : syntax
;; ctc-stx : syntax[evals to a contract]
(define-struct fld (name ctc-stx))
;; expand-field/mtd-spec : stx -> (union mtd fld)
(define (expand-field/mtd-spec f/m-stx)
(syntax-case f/m-stx (field)
[(field field-name ctc)
(identifier? (syntax field-name))
(make-fld (syntax field-name) (syntax ctc))]
[(field field-name ctc)
(raise-syntax-error 'object-contract "expected name of field" stx (syntax field-name))]
[(mtd-name ctc)
(identifier? (syntax mtd-name))
(let-values ([(ctc-stx proc-stx) (expand-mtd-contract (syntax ctc))])
(make-mtd (syntax mtd-name)
ctc-stx
proc-stx))]
[(mtd-name ctc)
(raise-syntax-error 'object-contract "expected name of method" stx (syntax mtd-name))]
[_ (raise-syntax-error 'object-contract "expected field or method clause" stx f/m-stx)]))
;; expand-mtd-contract : syntax -> (values syntax[expanded ctc] syntax[mtd-arg])
(define (expand-mtd-contract mtd-stx)
(syntax-case mtd-stx (case-> opt-> opt->*)
[(case-> cases ...)
(let loop ([cases (syntax->list (syntax (cases ...)))]
[ctc-stxs null]
[args-stxs null])
(cond
[(null? cases)
(values
(with-syntax ([(x ...) (reverse ctc-stxs)])
(obj-case->/proc (syntax (case-> x ...))))
(with-syntax ([(x ...) (apply append (map syntax->list (reverse args-stxs)))])
(syntax (x ...))))]
[else
(let-values ([(trans ctc-stx mtd-args) (expand-mtd-arrow (car cases))])
(loop (cdr cases)
(cons ctc-stx ctc-stxs)
(cons mtd-args args-stxs)))]))]
[(opt->* (req-contracts ...) (opt-contracts ...) (res-contracts ...))
(values
(obj-opt->*/proc (syntax (opt->* (any/c req-contracts ...) (opt-contracts ...) (res-contracts ...))))
(generate-opt->vars (syntax (req-contracts ...))
(syntax (opt-contracts ...))))]
[(opt->* (req-contracts ...) (opt-contracts ...) any)
(values
(obj-opt->*/proc (syntax (opt->* (any/c req-contracts ...) (opt-contracts ...) any)))
(generate-opt->vars (syntax (req-contracts ...))
(syntax (opt-contracts ...))))]
[(opt-> (req-contracts ...) (opt-contracts ...) res-contract)
(values
(obj-opt->/proc (syntax (opt-> (any/c req-contracts ...) (opt-contracts ...) res-contract)))
(generate-opt->vars (syntax (req-contracts ...))
(syntax (opt-contracts ...))))]
[else
(let-values ([(x y z) (expand-mtd-arrow mtd-stx)])
(values (x y) z))]))
;; generate-opt->vars : syntax[requried contracts] syntax[optional contracts] -> syntax[list of arg specs]
(define (generate-opt->vars req-stx opt-stx)
(with-syntax ([(req-vars ...) (generate-temporaries req-stx)]
[(ths) (generate-temporaries (syntax (ths)))])
(let loop ([opt-vars (generate-temporaries opt-stx)])
(cond
[(null? opt-vars) (list (syntax (ths req-vars ...)))]
[else (with-syntax ([(opt-vars ...) opt-vars]
[(rests ...) (loop (cdr opt-vars))])
(syntax ((ths req-vars ... opt-vars ...)
rests ...)))]))))
;; expand-mtd-arrow : stx -> (values (syntax[ctc] -> syntax[expanded ctc]) syntax[ctc] syntax[mtd-arg])
(define (expand-mtd-arrow mtd-stx)
(syntax-case mtd-stx (-> ->* ->d ->d* ->r ->pp ->pp-rest)
[(->) (raise-syntax-error 'object-contract "-> must have arguments" stx mtd-stx)]
[(-> args ...)
;; this case cheats a little bit --
;; (args ...) contains the right number of arguments
;; to the method because it also contains one arg for the result! urgh.
(with-syntax ([(arg-vars ...) (generate-temporaries (syntax (args ...)))])
(values obj->/proc
(syntax (-> any/c args ...))
(syntax ((arg-vars ...)))))]
[(->* (doms ...) (rngs ...))
(with-syntax ([(args-vars ...) (generate-temporaries (syntax (doms ...)))]
[(this-var) (generate-temporaries (syntax (this-var)))])
(values obj->*/proc
(syntax (->* (any/c doms ...) (rngs ...)))
(syntax ((this-var args-vars ...)))))]
[(->* (doms ...) rst (rngs ...))
(with-syntax ([(args-vars ...) (generate-temporaries (syntax (doms ...)))]
[(rst-var) (generate-temporaries (syntax (rst)))]
[(this-var) (generate-temporaries (syntax (this-var)))])
(values obj->*/proc
(syntax (->* (any/c doms ...) rst (rngs ...)))
(syntax ((this-var args-vars ... . rst-var)))))]
[(->* x ...)
(raise-syntax-error 'object-contract "malformed ->*" stx mtd-stx)]
[(->d) (raise-syntax-error 'object-contract "->d must have arguments" stx mtd-stx)]
[(->d doms ... rng-proc)
(let ([doms-val (syntax->list (syntax (doms ...)))])
(values
obj->d/proc
(with-syntax ([(arg-vars ...) (generate-temporaries doms-val)]
[arity-count (length doms-val)])
(syntax
(->d any/c doms ...
(let ([f rng-proc])
(check->* f arity-count)
(lambda (_this-var arg-vars ...)
(f arg-vars ...))))))
(with-syntax ([(args-vars ...) (generate-temporaries doms-val)])
(syntax ((this-var args-vars ...))))))]
[(->d* (doms ...) rng-proc)
(values
obj->d*/proc
(let ([doms-val (syntax->list (syntax (doms ...)))])
(with-syntax ([(arg-vars ...) (generate-temporaries doms-val)]
[arity-count (length doms-val)])
(syntax (->d* (any/c doms ...)
(let ([f rng-proc])
(check->* f arity-count)
(lambda (_this-var arg-vars ...)
(f arg-vars ...)))))))
(with-syntax ([(args-vars ...) (generate-temporaries (syntax (doms ...)))]
[(this-var) (generate-temporaries (syntax (this-var)))])
(syntax ((this-var args-vars ...)))))]
[(->d* (doms ...) rst-ctc rng-proc)
(let ([doms-val (syntax->list (syntax (doms ...)))])
(values
obj->d*/proc
(with-syntax ([(arg-vars ...) (generate-temporaries doms-val)]
[(rest-var) (generate-temporaries (syntax (rst-ctc)))]
[arity-count (length doms-val)])
(syntax (->d* (any/c doms ...)
rst-ctc
(let ([f rng-proc])
(check->*/more f arity-count)
(lambda (_this-var arg-vars ... . rest-var)
(apply f arg-vars ... rest-var))))))
(with-syntax ([(args-vars ...) (generate-temporaries (syntax (doms ...)))]
[(rst-var) (generate-temporaries (syntax (rst-ctc)))]
[(this-var) (generate-temporaries (syntax (this-var)))])
(syntax ((this-var args-vars ... . rst-var))))))]
[(->d* x ...)
(raise-syntax-error 'object-contract "malformed ->d* method contract" stx mtd-stx)]
[(->r ([x dom] ...) rng)
(andmap identifier? (syntax->list (syntax (x ...))))
(with-syntax ([(arg-vars ...) (generate-temporaries (syntax (x ...)))]
[(this-var) (generate-temporaries (syntax (this-var)))]
[this (datum->syntax mtd-stx 'this)])
(values
obj->r/proc
(syntax (->r ([this any/c] [x dom] ...) rng))
(syntax ((this-var arg-vars ...)))))]
[(->r ([x dom] ...) rest-x rest-dom rng)
(andmap identifier? (syntax->list (syntax (x ...))))
(with-syntax ([(arg-vars ...) (generate-temporaries (syntax (x ...)))]
[(this-var) (generate-temporaries (syntax (this-var)))]
[this (datum->syntax mtd-stx 'this)])
(values
obj->r/proc
(syntax (->r ([this any/c] [x dom] ...) rest-x rest-dom rng))
(syntax ((this-var arg-vars ... . rest-var)))))]
[(->r . x)
(raise-syntax-error 'object-contract "malformed ->r declaration")]
[(->pp ([x dom] ...) . other-stuff)
(andmap identifier? (syntax->list (syntax (x ...))))
(with-syntax ([(arg-vars ...) (generate-temporaries (syntax (x ...)))]
[(this-var) (generate-temporaries (syntax (this-var)))]
[this (datum->syntax mtd-stx 'this)])
(values
obj->pp/proc
(syntax (->pp ([this any/c] [x dom] ...) . other-stuff))
(syntax ((this-var arg-vars ...)))))]
[(->pp . x)
(raise-syntax-error 'object-contract "malformed ->pp declaration")]
[(->pp-rest ([x dom] ...) rest-id . other-stuff)
(and (identifier? (syntax id))
(andmap identifier? (syntax->list (syntax (x ...)))))
(with-syntax ([(arg-vars ...) (generate-temporaries (syntax (x ...)))]
[(this-var) (generate-temporaries (syntax (this-var)))]
[this (datum->syntax mtd-stx 'this)])
(values
obj->pp-rest/proc
(syntax (->pp ([this any/c] [x dom] ...) rest-id . other-stuff))
(syntax ((this-var arg-vars ... . rest-id)))))]
[(->pp-rest . x)
(raise-syntax-error 'object-contract "malformed ->pp-rest declaration")]
[else (raise-syntax-error 'object-contract "unknown method contract syntax" stx mtd-stx)]))
;; build-methods-stx : syntax[list of lambda arg specs] -> syntax[method realized as proc]
(define (build-methods-stx mtds)
(define (last-pair l)
(cond
[(not (pair? (cdr l))) l]
[else (last-pair (cdr l))]))
(let loop ([arg-spec-stxss (map mtd-mtd-arg-stx mtds)]
[names (map mtd-name mtds)]
[i 0])
(cond
[(null? arg-spec-stxss) null]
[else (let ([arg-spec-stxs (car arg-spec-stxss)])
(with-syntax ([(cases ...)
(map (lambda (arg-spec-stx)
(with-syntax ([i i])
(syntax-case arg-spec-stx ()
[(this rest-ids ...)
(syntax
((this rest-ids ...)
((field-ref this i) (wrapper-object-wrapped this) rest-ids ...)))]
[else
(let-values ([(this rest-ids last-var)
(let ([lst (syntax->improper-list arg-spec-stx)])
(values (car lst)
(all-but-last (cdr lst))
(cdr (last-pair lst))))])
(with-syntax ([this this]
[(rest-ids ...) rest-ids]
[last-var last-var])
(syntax
((this rest-ids ... . last-var)
(apply (field-ref this i)
(wrapper-object-wrapped this)
rest-ids ...
last-var)))))])))
(syntax->list arg-spec-stxs))]
[name (string->symbol (format "~a method" (syntax->datum (car names))))])
(with-syntax ([proc (syntax-property (syntax (case-lambda cases ...)) 'method-arity-error #t)])
(cons (syntax (lambda (field-ref) (let ([name proc]) name)))
(loop (cdr arg-spec-stxss)
(cdr names)
(+ i 1))))))])))
(define (syntax->improper-list stx)
(define (se->il se)
(cond
[(pair? se) (sp->il se)]
[else se]))
(define (stx->il stx)
(se->il (syntax-e stx)))
(define (sp->il p)
(cond
[(null? (cdr p)) p]
[(pair? (cdr p)) (cons (car p) (sp->il (cdr p)))]
[(syntax? (cdr p))
(let ([un (syntax-e (cdr p))])
(if (pair? un)
(cons (car p) (sp->il un))
p))]))
(stx->il stx))
(syntax-case stx ()
[(_ field/mtd-specs ...)
(let* ([mtd/flds (map expand-field/mtd-spec (syntax->list (syntax (field/mtd-specs ...))))]
[mtds (filter mtd? mtd/flds)]
[flds (filter fld? mtd/flds)])
(with-syntax ([(method-ctc-stx ...) (map mtd-ctc-stx mtds)]
[(method-name ...) (map mtd-name mtds)]
[(method-ctc-var ...) (generate-temporaries mtds)]
[(method-var ...) (generate-temporaries mtds)]
[(method/app-var ...) (generate-temporaries mtds)]
[(methods ...) (build-methods-stx mtds)]
[(field-ctc-stx ...) (map fld-ctc-stx flds)]
[(field-name ...) (map fld-name flds)]
[(field-ctc-var ...) (generate-temporaries flds)]
[(field-var ...) (generate-temporaries flds)]
[(field/app-var ...) (generate-temporaries flds)])
(syntax
(let ([method-ctc-var method-ctc-stx]
...
[field-ctc-var (coerce-contract 'object-contract field-ctc-stx)]
...)
(let ([method-var (contract-proc method-ctc-var)]
...
[field-var (contract-proc field-ctc-var)]
...)
(let ([cls (make-wrapper-class 'wrapper-class
'(method-name ...)
(list methods ...)
'(field-name ...))])
(make-proj-contract
`(object-contract
,(build-compound-type-name 'method-name method-ctc-var) ...
,(build-compound-type-name 'field 'field-name field-ctc-var) ...)
(lambda (pos-blame neg-blame src-info orig-str)
(let ([method/app-var (method-var pos-blame neg-blame src-info orig-str)]
...
[field/app-var (field-var pos-blame neg-blame src-info orig-str)]
...)
(let ([field-names-list '(field-name ...)])
(lambda (val)
(check-object val src-info pos-blame orig-str)
(let ([val-mtd-names
(interface->method-names
(object-interface
val))])
(void)
(check-method val 'method-name val-mtd-names src-info pos-blame orig-str)
...)
(unless (field-bound? field-name val)
(field-error val 'field-name src-info pos-blame orig-str)) ...
(let ([vtable (extract-vtable val)]
[method-ht (extract-method-ht val)])
(make-object cls
val
(method/app-var (vector-ref vtable (hash-table-get method-ht 'method-name))) ...
(field/app-var (get-field field-name val)) ...
))))))
#f)))))))]))))
;; example of how one contract is constructed
#;
(let* ([cm (syntax-parameterize ((making-a-method #t)) (-> any/c integer? integer?))]
[cf (-> integer? integer?)]
[m-proj (((proj-get cm) cm) 'pos 'neg #'here "whatever")]
[f-proj (((proj-get cf) cf) 'pos 'neg #'here "whatever")]
[cls (make-wrapper-class 'wrapper-class
'(m)
(list
(m-proj (λ (this x) (send (wrapper-object-wrapped this) m x))))
'(f)
#f)]
[o (new (class object%
(field [f (λ (x) x)])
(define/public (m x) x)
(super-new)))]
[wo (make-object cls o (f-proj (get-field/proc 'f o)))])
((get-field/proc 'f wo) #f))
(define-for-syntax (parse-object-contract stx args)
(let loop ([args (syntax->list args)]
[mtds '()]
[flds '()])
(cond
[(null? args) (list mtds flds)]
[else (syntax-case (car args) (field)
[(field id ctc)
(identifier? #'id)
(loop (cdr args) mtds (cons #'(id ctc) flds))]
[(field . rst)
(raise-syntax-error #f "malformed field specification" stx (car args))]
[(id ctc)
(identifier? #'id)
(loop (cdr args) (cons #`(id ctc) mtds) flds)]
[_
(raise-syntax-error #f "malformed object-contract clause" stx (car args))])])))
(define (check-object val src-info blame orig-str)
(unless (object? val)
(raise-contract-error val
src-info
blame
orig-str
"expected an object, got ~e"
val)))
(define-struct/prop object-contract (methods method-ctcs method-wrappers fields field-ctcs)
((proj-prop
(λ (ctc)
(let ([meth-names (object-contract-methods ctc)]
[meth-param-projs (map (λ (x) ((proj-get x) x)) (object-contract-method-ctcs ctc))]
[ctc-field-names (object-contract-fields ctc)]
[field-param-projs (map (λ (x) ((proj-get x) x)) (object-contract-field-ctcs ctc))])
(λ (pos-blame neg-blame src-info orig-str)
(let* ([meth-projs (map (λ (x) (x pos-blame neg-blame src-info orig-str))
meth-param-projs)]
[meths (map (λ (p x) (p x)) meth-projs (object-contract-method-wrappers ctc))]
[cls (make-wrapper-class 'wrapper-class meth-names meths ctc-field-names #f)]
[field-projs (map (λ (x) (x pos-blame neg-blame src-info orig-str)) field-param-projs)])
(λ (val)
(unless (object? val)
(raise-contract-error val src-info pos-blame orig-str
"expected an object, got ~e"
val))
(let ([objs-mtds (interface->method-names (object-interface val))]
[vtable (extract-vtable val)]
[method-ht (extract-method-ht val)])
(for-each (λ (m proj)
(let ([index (hash-table-get method-ht m #f)])
(unless index
(raise-contract-error val src-info pos-blame orig-str
"expected an object with method ~s"
m))
;; verify the first-order properties by apply the projection and
;; throwing the result away. Without this, the contract wrappers
;; just check the first-order properties of the wrappers, which is
;; the wrong thing.
(proj (vector-ref vtable index))))
meth-names
meth-projs))
(let ([fields (field-names val)])
(for-each (λ (f)
(unless (memq f fields)
(raise-contract-error val src-info pos-blame orig-str
"expected an object with field ~s"
f)))
ctc-field-names))
(define (check-method val method-name val-mtd-names src-info blame orig-str)
(unless (memq method-name val-mtd-names)
(raise-contract-error val
src-info
blame
orig-str
"expected an object with method ~s"
method-name)))
(apply make-object cls val
(map (λ (field proj) (proj (get-field/proc field val)))
ctc-field-names field-projs))))))))
(name-prop (λ (ctc) `(object-contract ,@(map (λ (fld ctc) (build-compound-type-name 'field fld ctc))
(object-contract-fields ctc)
(object-contract-field-ctcs ctc))
,@(map (λ (mtd ctc) (build-compound-type-name mtd ctc))
(object-contract-methods ctc)
(object-contract-method-ctcs ctc)))))
(first-order-prop (λ (ctc) (λ (val) #f)))
(stronger-prop (λ (this that) #f))))
(define (field-error val field-name src-info blame orig-str)
(raise-contract-error val
src-info
blame
orig-str
"expected an object with field ~s"
field-name))
(define-syntax (object-contract stx)
(syntax-case stx ()
[(_ spec ...)
(with-syntax ([(((method-id method-ctc) ...)
((field-id field-ctc) ...))
(parse-object-contract stx #'(spec ...))])
(with-syntax ([(method-name ...) (map (λ (x) (string->symbol (format "~a method" (syntax-e x))))
(syntax->list #'(method-id ...)))])
#'(build-object-contract '(method-id ...)
(syntax-parameterize ((making-a-method #t)) (list (let ([method-name method-ctc]) method-name) ...))
(list (λ (this . x) (send (wrapper-object-wrapped this) method-id . x)) ...)
'(field-id ...)
(list field-ctc ...))))]))
(define (build-object-contract methods method-ctcs wrappers fields field-ctcs)
(make-object-contract methods
(map (λ (x) (coerce-contract 'object-contract x)) method-ctcs)
wrappers
fields
(map (λ (x) (coerce-contract 'object-contract x)) field-ctcs)))
(define-syntax (old->d stx) (make-/proc #f ->d/h stx)) ;; just here for now so the mixin contracts work.
(define (make-mixin-contract . %/<%>s)
((and/c (flat-contract class?)
(apply and/c (map sub/impl?/c %/<%>s)))
. old->d .
subclass?/c))
(->d ([c% (and/c (flat-contract class?)
(apply and/c (map sub/impl?/c %/<%>s)))])
()
[res (subclass?/c c%)]))
(define (subclass?/c %)
(unless (class? %)
@ -442,4 +171,4 @@
[else `(is-a?/c unknown<%>)])
(lambda (x) (is-a? x <%>)))))
(define mixin-contract (class? . old->d . subclass?/c))
(define mixin-contract (->d ([c% class?]) () [res (subclass?/c c%)]))

View File

@ -1358,7 +1358,7 @@ resulting trait is the same as for @scheme[trait-sum], otherwise the
@section{Object and Class Contracts}
@defform/subs[
#:literals (field opt-> opt->* case-> -> ->* ->d ->d* ->r ->pp ->pp-rest)
#:literals (field -> ->* ->d)
(object-contract member-spec ...)
@ -1367,49 +1367,42 @@ resulting trait is the same as for @scheme[trait-sum], otherwise the
(field field-id contract-expr)]
[method-contract
(opt-> (required-contract-expr ...)
(optional-contract-expr ...)
any)
(opt-> (required-contract-expr ...)
(optional-contract-expr ...)
result-contract-expr)
(opt->* (required-contract-expr ...)
(optional-contract-expr ...)
(result-contract-expr ...))
(case-> arrow-contract ...)
arrow-contract]
(-> dom ... range)
(->* (mandatory-dom ...)
(optional-dom ...)
rest
range)
(->d (mandatory-dependent-dom ...)
(optional-dependent-dom ...)
dependent-rest
pre-cond
dep-range)]
[arrow-contract
(-> expr ... res-expr)
(-> expr ... (values res-expr ...))
(->* (expr ...) (res-expr ...))
(->* (expr ...) rest-expr (res-expr ...))
(->d expr ... res-proc-expr)
(->d* (expr ...) res-proc-expr)
(->d* (expr ...) rest-expr res-gen-expr)
(->r ((id expr) ...) expr)
(->r ((id expr) ...) id expr expr)
(->pp ((id expr) ...) pre-expr
res-expr res-id post-expr)
(->pp ((id expr) ...) pre-expr any)
(->pp ((id expr) ...) pre-expr
(values (id expr) ...) post-expr)
(->pp-rest ((id expr) ...) id expr pre-expr
res-expr res-id post-expr)
(->pp-rest ((id expr) ...) id expr pre-expr any)
(->pp-rest ((id expr) ...) id expr pre-expr
(values (id expr) ...) post-expr)])]{
[dom dom-expr (code:line keyword dom-expr)]
[range range-expr (values range-expr ...) any]
[mandatory-dom dom-expr (code:line keyword dom-expr)]
[optional-dom dom-expr (code:line keyword dom-expr)]
[rest (code:line) (code:line #:rest rest-expr)]
[mandatory-dependent-dom [id dom-expr] (code:line keyword [id dom-expr])]
[optional-dependent-dom [id dom-expr] (code:line keyword [id dom-expr])]
[dependent-rest (code:line) (code:line #:rest id rest-expr)]
[pre-cond (code:line) (code:line #:pre-cond boolean-expr)]
[dep-range any
(code:line [id range-expr] post-cond)
(code:line (values [id range-expr] ...) post-cond)]
[post-cond (code:line) (code:line #:post-cond boolean-expr)]
)]{
Produces a contract for an object.
Each of the contracts for a method has the same semantics as the
corresponding function contract, but the syntax of the method contract
must be written directly in the body of the object-contract---much
like the way that methods in class definitions use the same syntax as
regular function definitions, but cannot be arbitrary procedures. The
only exception is that the @scheme[->r], @scheme[->pp], and
@scheme[->pp-rest] contracts implicitly bind @scheme[this] to the
object itself.}
Each of the contracts for a method has the same semantics as
the corresponding function contract, but the syntax of the
method contract must be written directly in the body of the
object-contract---much like the way that methods in class
definitions use the same syntax as regular function
definitions, but cannot be arbitrary procedures. The only
exception is that @scheme[->d] contracts implicitly bind
@scheme[this] to the object itself.}
@defthing[mixin-contract contract?]{

View File

@ -290,6 +290,12 @@ The @scheme[any] form can only be used in a result position of
contracts like @scheme[->]. Using @scheme[any] elsewhere is a syntax
error.}
@defform[(promise/c expr)]{
Constructs a contract on a promise. The contract does not force the
promise, but when the promise is forced, the contract checks that the
result value meets the contract produced by @scheme[expr].}
@; ------------------------------------------------------------------------
@section{Function Contracts}
@ -308,7 +314,11 @@ because it requires delaying the evaluation of the contract
expressions for the domain and range until the function
itself is called or returns.
The @scheme[case->] contract ...
The @scheme[case->] contract is a specialized contract,
designed to match @scheme[case-lambda] and
@scheme[unconstrained-domain->] allows range checking
without requiring that the domain have any particular shape
(see below for an exmaple use).
@defform*/subs[#:literals (any values)
[(-> dom ... range)]
@ -359,10 +369,10 @@ each values must match its respective contract.}
@defform*/subs[#:literals (any)
[(->* (mandatory-dom ...) (optional-dom ...) rest-expr range)
(->* (mandatory-dom ...) (optional-dom ...) range)]
[(->* (mandatory-dom ...) (optional-dom ...) rest range)]
([mandatory-dom dom-expr (code:line keyword dom-expr)]
[optional-dom dom-expr (code:line keyword dom-expr)]
[rest (code:line) (code:line #:rest rest-expr)]
[range range-expr (values range-expr ...) any])]{
The @scheme[->*] contract combinator produces contracts for
@ -388,12 +398,12 @@ symbols, and that return a symbol.
@defform*/subs[#:literals (any values)
[(->d (mandatory-dependent-dom ...)
(optional-dependent-dom ...)
rest
dependent-rest
pre-cond
dep-range)]
([mandatory-dependent-dom [id dom-expr] (code:line keyword [id dom-expr])]
[optional-dependent-dom [id dom-expr] (code:line keyword [id dom-expr])]
[rest (code:line) (code:line id rest-expr)]
[dependent-rest (code:line) (code:line #:rest id rest-expr)]
[pre-cond (code:line) (code:line #:pre-cond boolean-expr)]
[dep-range any
(code:line [id range-expr] post-cond)
@ -477,12 +487,6 @@ be blamed using the above contract:
]}
@defform[(promise/c expr)]{
Constructs a contract on a promise. The contract does not force the
promise, but when the promise is forced, the contract checks that the
result value meets the contract produced by @scheme[expr].}
@; ------------------------------------------------------------------------
@section{Lazy Data-structure Contracts}

File diff suppressed because it is too large Load Diff