make contract-stronger? return #f for impersonator contracts that don't implement stronger

This commit is contained in:
Daniel Feltey 2017-09-29 15:03:30 -05:00
parent 39dea70732
commit ed5911e531
3 changed files with 36 additions and 15 deletions

View File

@ -101,14 +101,14 @@ Contracts in Racket are subdivided into three different categories:
that the value had before being wrapped by the contract that the value had before being wrapped by the contract
are preserved by the contract wrapper. are preserved by the contract wrapper.
All @tech{flat contracts} are also @tech{chaperone contracts} (but All @tech{flat contracts} may be used where @tech{chaperone contracts} are expected
not vice-versa).} (but not vice-versa).}
@item{@deftech{Impersonator @tech{contracts}} do not provide any @item{@deftech{Impersonator @tech{contracts}} do not provide any
guarantees about values they check. Impersonator contracts guarantees about values they check. Impersonator contracts
may hide properties of values, or even make them completely may hide properties of values, or even make them completely
opaque (e.g, @racket[new-∀/c]). opaque (e.g, @racket[new-∀/c]).
All @tech{contracts} are impersonator contracts.}] All @tech{contracts} may be used where impersonator contracts are expected.}]
For more about this hierarchy, see the section ``@secref["chaperones"]'' For more about this hierarchy, see the section ``@secref["chaperones"]''
as well as a research paper @cite{Strickland12} on chaperones, impersonators, as well as a research paper @cite{Strickland12} on chaperones, impersonators,
@ -2231,7 +2231,10 @@ The @racket[stronger] argument is used to implement @racket[contract-stronger?].
first argument is always the contract itself and the second argument is whatever first argument is always the contract itself and the second argument is whatever
was passed as the second argument to @racket[contract-stronger?]. If no was passed as the second argument to @racket[contract-stronger?]. If no
@racket[stronger] argument is supplied, then a default that compares its arguments @racket[stronger] argument is supplied, then a default that compares its arguments
with @racket[equal?] is used. with @racket[equal?] is used for @tech{flat contracts} and @tech{chaperone contracts}.
For @tech{impersonator contracts} constructed with @racket[make-contract] that do not
supply the @racket[stronger] argument, @racket[contract-stronger?] returns @racket[#f].
The @racket[is-list-contract?] argument is used by the @racket[list-contract?] predicate The @racket[is-list-contract?] argument is used by the @racket[list-contract?] predicate
to determine if this is a contract that accepts only @racket[list?] values. to determine if this is a contract that accepts only @racket[list?] values.
@ -2957,8 +2960,9 @@ are below):
Returns @racket[#t] if the contract @racket[c1] accepts either fewer Returns @racket[#t] if the contract @racket[c1] accepts either fewer
or the same number of values as @racket[c2] does. or the same number of values as @racket[c2] does.
Contracts that are the same (i.e., where @racket[c1] is @racket[equal?] @tech{Chaperone contracts} and @tech{flat contracts} that are the same
to @racket[c2]) are considered to always be stronger than each other. (i.e., where @racket[c1] is @racket[equal?] to @racket[c2]) are
considered to always be stronger than each other.
This function is conservative, so it may return @racket[#f] when This function is conservative, so it may return @racket[#f] when
@racket[c1] does, in fact, accept fewer values. @racket[c1] does, in fact, accept fewer values.

View File

@ -687,4 +687,24 @@
(define one (mk 1)) (define one (mk 1))
(define two (mk 2)) (define two (mk 2))
(,test #f contract-stronger? one two) (,test #f contract-stronger? one two)
(,test #t contract-stronger? two one)))) (,test #t contract-stronger? two one)))
(contract-eval
`(define imp-ctc
(make-contract
#:late-neg-projection (λ (blame) (λ (val neg) (add1 val))))))
(contract-eval
`(define imp-struct-ctc
(let ()
(struct imp-ctc-struct ()
#:property prop:contract
(build-contract-property
#:late-neg-projection
(λ (ctc)
(λ (blame)
(λ (val neg)
(add1 val))))))
(imp-ctc-struct))))
(ctest #f contract-stronger? imp-ctc imp-ctc)
(ctest #f contract-stronger? imp-struct-ctc imp-struct-ctc))

View File

@ -118,7 +118,10 @@
(define trail (make-parameter #f)) (define trail (make-parameter #f))
(define (contract-struct-stronger? a b) (define (contract-struct-stronger? a b)
(cond (cond
[(equal? a b) #t] [(and (equal? a b)
(or (flat-contract-struct? a)
(chaperone-contract-struct? a)))
#t]
[else [else
(define prop (contract-struct-property a)) (define prop (contract-struct-property a))
(define stronger? (contract-property-stronger prop)) (define stronger? (contract-property-stronger prop))
@ -494,7 +497,7 @@
(late-neg-first-order-projection name first-order)] (late-neg-first-order-projection name first-order)]
[else #f])] [else #f])]
[else late-neg-projection]) [else late-neg-projection])
(or stronger as-strong?) (or stronger weakest)
generate exercise generate exercise
(and list-contract? #t))) (and list-contract? #t)))
@ -510,12 +513,6 @@
name name
v))))) v)))))
(define (as-strong? a b)
(define late-neg-a (contract-struct-late-neg-projection a))
(define late-neg-b (contract-struct-late-neg-projection b))
(and late-neg-a late-neg-b
(procedure-closure-contents-eq? late-neg-a late-neg-b)))
(define make-contract (define make-contract
(procedure-rename (procedure-rename
(build-contract make-make-contract 'anonymous-contract 'make-contract #f) (build-contract make-make-contract 'anonymous-contract 'make-contract #f)