|
12 | 12 | ;;
|
13 | 13 | ;; - their implementations (under the same names) are defined at phase
|
14 | 14 | ;; 0 using `define` in the main module
|
15 |
| -;; |
| 15 | +;; |
16 | 16 | ;; - the `forms` submodule uses `lazy-require` to load the
|
17 | 17 | ;; implementations of the forms
|
18 | 18 |
|
19 | 19 |
|
20 | 20 | (provide require/opaque-type require-typed-struct-legacy require-typed-struct
|
21 | 21 | require/typed-legacy require/typed require/typed/provide
|
22 | 22 | require-typed-struct/provide core-cast make-predicate define-predicate
|
| 23 | + make-positive-predicate define-positive-predicate |
23 | 24 | require-typed-signature)
|
24 | 25 |
|
25 | 26 | (module forms racket/base
|
26 | 27 | (require (for-syntax racket/lazy-require racket/base))
|
27 |
| - (begin-for-syntax |
| 28 | + (begin-for-syntax |
28 | 29 | (lazy-require [(submod "..")
|
29 | 30 | (require/opaque-type
|
30 | 31 | require-typed-signature
|
31 | 32 | require-typed-struct-legacy
|
32 | 33 | require-typed-struct
|
33 | 34 | require/typed-legacy require/typed require/typed/provide
|
34 |
| - require-typed-struct/provide core-cast make-predicate define-predicate)])) |
| 35 | + require-typed-struct/provide core-cast make-predicate define-predicate |
| 36 | + make-positive-predicate define-positive-predicate)])) |
35 | 37 | (define-syntax (def stx)
|
36 | 38 | (syntax-case stx ()
|
37 | 39 | [(_ id ...)
|
|
43 | 45 | require-typed-struct-legacy
|
44 | 46 | require-typed-struct
|
45 | 47 | require/typed-legacy require/typed require/typed/provide
|
46 |
| - require-typed-struct/provide make-predicate define-predicate) |
| 48 | + require-typed-struct/provide make-predicate define-predicate |
| 49 | + make-positive-predicate define-positive-predicate) |
47 | 50 |
|
48 | 51 | ;; Expand `cast` to a `core-cast` with an extra `#%expression` in order
|
49 | 52 | ;; to prevent the contract generation pass from executing too early
|
|
204 | 207 | ;; define `cnt*` to be fixed up later by the module type-checking
|
205 | 208 | (define cnt*
|
206 | 209 | (syntax-local-lift-expression
|
207 |
| - (make-contract-def-rhs #'ty #f (attribute parent)))) |
| 210 | + (make-contract-def-rhs #'ty #f #f (attribute parent)))) |
208 | 211 | (quasisyntax/loc stx
|
209 | 212 | (begin
|
210 | 213 | ;; register the identifier so that it has a binding (for top-level)
|
|
269 | 272 | ;; Conversion of types to contracts
|
270 | 273 | ;; define-predicate
|
271 | 274 | ;; make-predicate
|
| 275 | +;; define-positive-predicate |
| 276 | +;; make-positive-predicate |
272 | 277 | ;; cast
|
273 | 278 |
|
274 | 279 | ;; Helpers to construct syntax for contract definitions
|
275 |
| -;; make-contract-def-rhs : Type-Stx Boolean Boolean -> Syntax |
276 |
| -(define (make-contract-def-rhs type flat? maker?) |
277 |
| - (define contract-def `#s(contract-def ,type ,flat? ,maker? untyped)) |
| 280 | +;; make-contract-def-rhs : Type-Stx Boolean Boolean Boolean -> Syntax |
| 281 | +;; The exact? argument determines whether the contract must decide |
| 282 | +;; exactly whether the value has the type. |
| 283 | +;; - flat? true and exact? true must generate (-> Any Boolean : type) |
| 284 | +;; - flat? true and exact? false can generate (-> Any Boolean : #:+ type) |
| 285 | +(define (make-contract-def-rhs type flat? exact? maker?) |
| 286 | + (define contract-def `#s(contract-def ,type ,flat? ,exact? ,maker? untyped)) |
278 | 287 | (contract-def-property #'#f (λ () contract-def)))
|
279 | 288 |
|
280 | 289 | ;; make-contract-def-rhs/from-typed : Id Boolean Boolean -> Syntax
|
|
291 | 300 | (if types
|
292 | 301 | #`(U #,@types)
|
293 | 302 | #f)))
|
294 |
| - `#s(contract-def ,type-stx ,flat? ,maker? typed)))) |
| 303 | + `#s(contract-def ,type-stx ,flat? #f ,maker? typed)))) |
295 | 304 |
|
296 | 305 |
|
297 | 306 | (define (define-predicate stx)
|
|
312 | 321 | (define (make-predicate stx)
|
313 | 322 | (syntax-parse stx
|
314 | 323 | [(_ ty:expr)
|
| 324 | + ; passing #t for exact? makes it produce a warning on Opaque types |
315 | 325 | (define name (syntax-local-lift-expression
|
316 |
| - (make-contract-def-rhs #'ty #t #f))) |
| 326 | + (make-contract-def-rhs #'ty #t #t #f))) |
317 | 327 | (define (check-valid-type _)
|
318 | 328 | (define type (parse-type #'ty))
|
319 | 329 | (define vars (fv type))
|
|
325 | 335 | #`(#,(external-check-property #'#%expression check-valid-type)
|
326 | 336 | #,(ignore-some/expr #`(flat-contract-predicate #,name) #'(Any -> Boolean : ty)))]))
|
327 | 337 |
|
| 338 | + |
| 339 | +(define (define-positive-predicate stx) |
| 340 | + (syntax-parse stx |
| 341 | + [(_ name:id ty:expr) |
| 342 | + #`(begin |
| 343 | + ;; We want the value bound to name to have a nice object name. Using the built in mechanism |
| 344 | + ;; of define has better performance than procedure-rename. |
| 345 | + #,(ignore |
| 346 | + (syntax/loc stx |
| 347 | + (define name |
| 348 | + (let ([pred (make-positive-predicate ty)]) |
| 349 | + (lambda (x) (pred x)))))) |
| 350 | + ;; not a require, this is just the unchecked declaration syntax |
| 351 | + #,(internal (syntax/loc stx (require/typed-internal name (Any -> Boolean : #:+ ty)))))])) |
| 352 | + |
| 353 | + |
| 354 | +(define (make-positive-predicate stx) |
| 355 | + (syntax-parse stx |
| 356 | + [(_ ty:expr) |
| 357 | + ; passing #f for exact? makes it work with Opaque types without warning |
| 358 | + (define name (syntax-local-lift-expression |
| 359 | + (make-contract-def-rhs #'ty #t #f #f))) |
| 360 | + (define (check-valid-type _) |
| 361 | + (define type (parse-type #'ty)) |
| 362 | + (define vars (fv type)) |
| 363 | + ;; If there was an error don't create another one |
| 364 | + (unless (or (Error? type) (null? vars)) |
| 365 | + (tc-error/delayed |
| 366 | + "Type ~a could not be converted to a predicate because it contains free variables." |
| 367 | + type))) |
| 368 | + #`(#,(external-check-property #'#%expression check-valid-type) |
| 369 | + #,(ignore-some/expr #`(flat-contract-predicate #,name) #'(Any -> Boolean : #:+ ty)))])) |
| 370 | + |
| 371 | + |
| 372 | + |
328 | 373 | ;; wrapped above in the `forms` submodule
|
329 | 374 | (define (core-cast stx)
|
330 | 375 | (syntax-parse stx
|
|
349 | 394 | #'v]
|
350 | 395 | [else
|
351 | 396 | (define new-ty-ctc (syntax-local-lift-expression
|
352 |
| - (make-contract-def-rhs #'ty #f #f))) |
| 397 | + (make-contract-def-rhs #'ty #f #f #f))) |
353 | 398 | (define existing-ty-id new-ty-ctc)
|
354 | 399 | (define existing-ty-ctc (syntax-local-lift-expression
|
355 | 400 | (make-contract-def-rhs/from-typed existing-ty-id #f #f)))
|
|
397 | 442 | #,@(if (eq? (syntax-local-context) 'top-level)
|
398 | 443 | (list #'(define-syntaxes (hidden) (values)))
|
399 | 444 | null)
|
400 |
| - #,(internal #'(require/typed-internal hidden (Any -> Boolean : (Opaque pred)))) |
| 445 | + #,(internal #'(require/typed-internal hidden (Any -> Boolean : #:+ (Opaque pred)))) |
401 | 446 | #,(if (attribute ne)
|
402 | 447 | (internal (syntax/loc stx (define-type-alias-internal ty (Opaque pred))))
|
403 | 448 | (syntax/loc stx (define-type-alias ty (Opaque pred))))
|
|
0 commit comments