Attempt at adding ->im; will be reverted.

`->i` already supports method contracts (for use wihin `object-contract`,
whose `->i` support is tested, but undocumented), which would make `->im`
possible.

Unfortunately, that support is very incomplete, missing support for using
`this` in contracts, making this `->im` (or the undocumented `->i` +
`object-contract` combo) basically useless.

Once/if that is added, then this commit would enable `->im`. Until then,
it's mostly useful for future reference (hence will be reverted).

In the meantime, it's possible to use `->i` within class/object contracts
with an explicit `this` argument, so nothing critical is lost, just a tiny
shortcut.
This commit is contained in:
Vincent St-Amour 2016-03-30 16:40:58 -05:00
parent 05292b7e69
commit 7c458d10d7
4 changed files with 111 additions and 7 deletions

View File

@ -2071,16 +2071,28 @@ domain, where the first (implicit) argument is contracted with
@racket[any/c]. This contract is useful for writing simpler method @racket[any/c]. This contract is useful for writing simpler method
contracts when no properties of @racket[this] need to be checked.} contracts when no properties of @racket[this] need to be checked.}
@deftogether[[
@defform[(->im maybe-chaperone
(mandatory-dependent-dom ...)
(optional-dependent-dom ...)
dependent-rest
pre-cond
dep-range
post-condition)]
@defform[(->dm (mandatory-dependent-dom ...) @defform[(->dm (mandatory-dependent-dom ...)
(optional-dependent-dom ...) (optional-dependent-dom ...)
dependent-rest dependent-rest
pre-cond pre-cond
dep-range)]{ dep-range)]
Similar to @racket[->d], except that the mandatory domain of the resulting contract ]]{
Similar to @racket[->i] and @racket[->d], except that the mandatory domain of the resulting contract
contains one more element than the stated domain, where the first (implicit) argument is contracted contains one more element than the stated domain, where the first (implicit) argument is contracted
with @racket[any/c]. In addition, @racket[this] is appropriately bound in the body of the contract. with @racket[any/c]. In addition, @racket[this] is appropriately bound in the body of the contract.
This contract is useful for writing simpler method contracts when no properties This contract is useful for writing simpler method contracts when no properties
of @racket[this] need to be checked.} of @racket[this] need to be checked.
@history[#:changed "6.4.0.15" @elem{Added @racket[->im].}]
}
@defform/subs[ @defform/subs[
#:literals (field) #:literals (field)

View File

@ -1847,7 +1847,7 @@
'neg)) 'neg))
(test/pos-blame (test/pos-blame
'->dm-first-order-1 '->dm-first-order-2
'(contract (class/c [pop (->dm () () #:pre-cond (not (send this empty?)) [_ number?])] '(contract (class/c [pop (->dm () () #:pre-cond (not (send this empty?)) [_ number?])]
[push (->dm ([arg number?]) () [_ void?] #:post-cond (not (send this empty?)))] [push (->dm ([arg number?]) () [_ void?] #:post-cond (not (send this empty?)))]
[empty? (->m boolean?)]) [empty? (->m boolean?)])
@ -1918,6 +1918,91 @@
[o (new stack%)]) [o (new stack%)])
(send o pop))) (send o pop)))
(test/spec-passed
'->im-first-order-1
'(contract (class/c [pop (->im () #:pre () (not (send this empty?)) [_ number?])]
[push (->im ([arg number?]) [_ void?] #:post () (not (send this empty?)))]
[empty? (->m boolean?)])
(class object% (super-new)
(define stack null)
(define/public (empty?) (null? stack))
(define/public (push v) (set! stack (cons v stack)))
(define/public (pop) (let ([res (car stack)]) (set! stack (cdr stack)) res)))
'pos
'neg))
(test/pos-blame
'->im-first-order-2
'(contract (class/c [pop (->im () #:pre () (not (send this empty?)) [_ number?])]
[push (->im ([arg number?]) [_ void?] #:post () (not (send this empty?)))]
[empty? (->m boolean?)])
(class object% (super-new)
(define stack null)
(define/public (empty?) (null? stack))
(define/public (push v) (set! stack (cons v stack)))
(define/public (pop v) (let ([res (car stack)]) (set! stack (cdr stack)) res)))
'pos
'neg))
(test/spec-passed
'->im-higher-order-1
'(let* ([stack% (contract (class/c
[pop (->im () #:pre () (not (send this empty?)) [_ number?])]
[push (->im ([arg number?]) [_ void?]
#:post () (not (send this empty?)))]
[empty? (->m boolean?)])
(class object% (super-new)
(define stack null)
(define/public (empty?) (null? stack))
(define/public (push v) (set! stack (cons v stack)))
(define/public (pop)
(let ([res (car stack)]) (set! stack (cdr stack)) res)))
'pos
'neg)]
[o (new stack%)])
(send o push 4)
(send o empty?)
(send o pop)))
(test/pos-blame
'->im-higher-order-2
'(let* ([stack% (contract (class/c
[pop (->im () #:pre () (not (send this empty?)) [_ number?])]
[push (->im ([arg number?]) [_ void?]
#:post () (not (send this empty?)))]
[empty? (->m boolean?)])
(class object% (super-new)
(define stack null)
(define/public (empty?) (null? stack))
(define/public (push v) (void))
(define/public (pop)
(define res (car stack))
(set! stack (cdr stack))
res))
'pos
'neg)]
[o (new stack%)])
(send o push 4)
(send o empty?)
(send o pop)))
(test/neg-blame
'->im-higher-order-3
'(let* ([stack% (contract
(class/c
[pop (->im () #:pre () (not (send this empty?)) [_ number?])]
[push (->im ([arg number?]) [_ void?] #:post () (not (send this empty?)))]
[empty? (->m boolean?)])
(class object% (super-new)
(define stack null)
(define/public (empty?) (null? stack))
(define/public (push v) (set! stack (cons v stack)))
(define/public (pop) (let ([res (car stack)]) (set! stack (cdr stack)) res)))
'pos
'neg)]
[o (new stack%)])
(send o pop)))
(test/spec-passed (test/spec-passed
'case->m-first-order-1 'case->m-first-order-1
'(contract (class/c [m (case->m (-> number? number?) (-> number? number? number?))]) '(contract (class/c [m (case->m (-> number? number?) (-> number? number? number?))])

View File

@ -10,11 +10,12 @@
"../contract/combinator.rkt" "../contract/combinator.rkt"
(only-in "../contract/private/arrow-val-first.rkt" ->-internal ->*-internal) (only-in "../contract/private/arrow-val-first.rkt" ->-internal ->*-internal)
(only-in "../contract/private/case-arrow.rkt" case->-internal) (only-in "../contract/private/case-arrow.rkt" case->-internal)
(only-in "../contract/private/arr-i.rkt" ->i-internal)
(only-in "../contract/private/arr-d.rkt" ->d-internal)) (only-in "../contract/private/arr-d.rkt" ->d-internal))
(provide make-class/c class/c-late-neg-proj (provide make-class/c class/c-late-neg-proj
blame-add-method-context blame-add-field-context blame-add-init-context blame-add-method-context blame-add-field-context blame-add-init-context
class/c ->m ->*m ->dm case->m object/c instanceof/c class/c ->m ->*m ->im ->dm case->m object/c instanceof/c
make-wrapper-object make-wrapper-object
check-object-contract check-object-contract
(for-syntax parse-class/c-specs) (for-syntax parse-class/c-specs)
@ -44,6 +45,12 @@
(case->-internal (syntax/loc stx (case->m . args)) (case->-internal (syntax/loc stx (case->m . args))
#|method?|# #t)])) #|method?|# #t)]))
(define-syntax (->im stx)
(syntax-case stx ()
[(_ . args)
(->i-internal (syntax/loc stx (->im . args))
#|method?|# #t)]))
(define-syntax (->dm stx) (define-syntax (->dm stx)
(syntax-case stx () (syntax-case stx ()
[(_ . args) [(_ . args)

View File

@ -64,7 +64,7 @@
method-in-interface? interface->method-names class->interface class-info method-in-interface? interface->method-names class->interface class-info
(struct-out exn:fail:object) (struct-out exn:fail:object)
make-primitive-class make-primitive-class
class/c ->m ->*m ->dm case->m object/c instanceof/c class/c ->m ->*m ->im ->dm case->m object/c instanceof/c
dynamic-object/c dynamic-object/c
class-seal class-unseal class-seal class-unseal