typed-racket/typed-racket-test/succeed/pr241-variation-5.rkt
2015-12-31 14:21:21 -05:00

350 lines
13 KiB
Racket

#lang racket/base
;; Check that any-wrap/c handles all base types
;; We do this by:
;; - enumerating the base types from `base-env/base-types.rkt`
;; - for each type:
;; - define a value
;; - typecheck the value
;; - wrap the value as 'Any', check failure / use in untyped code
(require
(for-syntax racket/base)
racket/require)
;; When #t, print a warning if some base-types do not have tests
(define-for-syntax WARN-MISSING #t)
;; `known-base-types` is a list of triples:
;; [TYPE VALUE USE]
;; TYPE is a base type exported by Typed Racket
;; VALUE is an expression with type TYPE
;; USE is an untyped function of 1 argument, or #f.
;; If a function, a test will apply (USE (contract VALUE any-wrap/c)).
;; If #f, a test will assert that (contract VALUE any-wrap/c) fails.
;; These USE functions should exercise specific functionality
;; and not be dummy functions like (lambda (x) x).
(define-for-syntax known-base-types '(
;; --- TODO missing value for these types
;[Read-Table (or (current-readtable) (error 'noo)) #f]
;[Internal-Definition-Context (syntax-local-make-definition-context) #f]
;[Place (place hi (void)) place-kill]
;; --- Types that should NOT be passes as 'Any' are marked with #f
[Async-ChannelTop (make-async-channel) #f]
[ClassTop object% #f]
[Compiled-Expression (compile-syntax #'#t) #f]
[Continuation-Mark-KeyTop (make-continuation-mark-key) #f]
[Continuation-Mark-Set (current-continuation-marks) #f]
[Custodian (current-custodian) #f]
[Identifier (syntax exit) #f]
[MPairTop (mcons 1 1) #f]
[Namespace (make-empty-namespace) #f]
[Parameterization (current-parameterization) #f]
[Prompt-TagTop (make-continuation-prompt-tag) #f]
[Security-Guard (current-security-guard) #f]
[Special-Comment (make-special-comment 'hi) #f]
[Struct-Type-Property (let-values ([(n g s) (make-struct-type-property 'foo)]) n) #f]
[Syntax (syntax 'B) #f]
[Syntax-E (syntax-e (syntax 'A)) #f]
[Thread-CellTop (make-thread-cell 'X) #f]
[UnitTop (unit (import) (export)) #f]
[Variable-Reference (let ([x 4]) (#%variable-reference x)) #f]
[Weak-BoxTop (make-weak-box 3) #f]
;; -- Normal base types
[Subprocess
(let*-values ([(sp _out _in _err) (subprocess #f #f #f ".")])
(close-output-port _in)
(close-input-port _out)
(close-input-port _err)
sp)
choice-evt]
[Single-Flonum-Complex 1f0+1f0i add1]
[ExtFlonum-Zero 0.0t0 extflround]
[ExtFlonum-Negative-Zero -0.0t0 extflround]
[ExtFlonum-Positive-Zero +0.0t0 extflround]
[Complex 0 add1]
[Number 0 add1]
[Inexact-Complex (let ([n (exact->inexact 1/3+1/3i)]) (if (not (real? n)) n (error 'pr241 "Failed to make Inexact-Complex"))) zero?]
[Float-Complex 1.0+1i add1]
[Exact-Number 0 add1]
[Real 0 add1]
[Nonpositive-Real 0 add1]
[Negative-Real -1 add1]
[Nonnegative-Real 0 add1]
[Positive-Real 1 add1]
[Real-Zero 0 add1]
[Inexact-Real (exact->inexact 1/3) add1]
[Single-Flonum 1.0f0 add1]
[Nonpositive-Inexact-Real (- (exact->inexact 1/3)) add1]
[Nonpositive-Single-Flonum -1.0f0 add1]
[Negative-Inexact-Real -1.0f0 add1]
[Negative-Single-Flonum -1.0f0 add1]
[Positive-Single-Flonum +1.0f0 add1]
[Nonnegative-Inexact-Real (exact->inexact 1/3) add1]
[Nonnegative-Single-Flonum 1.0f0 add1]
[Positive-Inexact-Real 1.0f0 add1]
[Inexact-Real-Nan +nan.0 zero?]
[Inexact-Real-Zero 0.0 add1]
[Inexact-Real-Negative-Zero -0.0 add1]
[Inexact-Real-Positive-Zero 0.0 add1]
[Single-Flonum-Nan +nan.f add1]
[Single-Flonum-Zero 0f0 add1]
[Single-Flonum-Negative-Zero -0f0 add1]
[Single-Flonum-Positive-Zero 0f0 add1]
[Float 1.0 add1]
[Flonum 1.0 add1]
[Nonpositive-Float -1.0 add1]
[Nonpositive-Flonum -1.0 add1]
[Negative-Float -1.0 add1]
[Negative-Flonum -1.0 add1]
[Nonnegative-Float 1.0 add1]
[Nonnegative-Flonum 1.0 add1]
[Positive-Float 1.0 add1]
[Positive-Flonum 1.0 add1]
[Float-Nan +nan.0 add1]
[Flonum-Nan +nan.0 add1]
[Float-Zero 0.0 add1]
[Flonum-Zero 0.0 add1]
[Float-Negative-Zero -0.0 add1]
[Flonum-Negative-Zero -0.0 add1]
[Float-Positive-Zero 0.0 add1]
[Flonum-Positive-Zero 0.0 add1]
[Exact-Rational 1/3 add1]
[Nonpositive-Exact-Rational 0/1 add1]
[Negative-Exact-Rational -3/2 add1]
[Nonnegative-Exact-Rational 1 add1]
[Positive-Exact-Rational 4/3 add1]
[Integer 0 add1]
[Nonpositive-Integer 0 add1]
[Negative-Integer -2 add1]
[Exact-Nonnegative-Integer 0 add1]
[Nonnegative-Integer 0 add1]
[Natural 62 add1]
[Exact-Positive-Integer 6 add1]
[Positive-Integer 6 add1]
[Fixnum 9 add1]
[Negative-Fixnum -3 add1]
[Nonpositive-Fixnum -4 add1]
[Nonnegative-Fixnum 4 add1]
[Positive-Fixnum 2 add1]
[Index 3 add1]
[Positive-Index 3 add1]
[Byte 0 add1]
[Positive-Byte 1 add1]
[Zero 0 add1]
[One 1 add1]
[ExtFlonum pi.t extflround]
[Nonpositive-ExtFlonum (->extfl -1) extflround]
[Negative-ExtFlonum (->extfl -1) extflround]
[Nonnegative-ExtFlonum (->extfl 1) extflround]
[Positive-ExtFlonum (->extfl 1) extflround]
[ExtFlonum-Nan +nan.t (lambda (n) (extfl= n n))]
[Any 'a boolean?]
[Boolean #f not]
[BoxTop (box 5) boolean?]
[Byte-PRegexp (byte-pregexp #"\\d\\d") (lambda (p) (regexp-match? p "013a"))]
[Byte-Regexp (byte-regexp #"hi$") (lambda (p) (regexp-match? p "hi"))]
[Bytes #"hello" bytes-length]
[Bytes-Converter (or (bytes-open-converter "UTF-8" "UTF-8") (error 'pr241 "Failed to make bytes converter")) bytes-close-converter]
[ChannelTop (make-channel) channel-try-get]
[Char #\space char->integer]
[Datum 'A (lambda (x) (datum->syntax #f x))]
[EOF eof eof-object?]
[ExtFlVector (extflvector pi.t) extflvector-length]
[FSemaphore (make-fsemaphore 0) fsemaphore-post]
[False #f not]
[FlVector (flvector 1.14 2.14 3.14) flvector-length]
[FxVector (fxvector 1) fxvector-length]
[HashTableTop (hash) (lambda (h) (hash-ref h 'a #f))]
[Impersonator-Property (let-values ([(i i? i-val) (make-impersonator-property 'i)]) i) (lambda (i) (impersonate-procedure (lambda () (void)) #f i 2))]
[Input-Port (current-input-port) port?]
[Inspector (current-inspector) (lambda (i) (parameterize ([current-inspector i]) (void)))]
[Keyword (string->keyword "hi") keyword->string]
[Log-Level 'info symbol->string]
[Log-Receiver (make-log-receiver (current-logger) 'info) choice-evt]
[Logger (current-logger) (lambda (l) (log-level? l 'info))]
[Module-Path "hello.rkt" module-path?]
[Null '() length]
[Output-Port (current-output-port) port?]
[PRegexp #px"\\d\\d" (lambda (p) (regexp-match? p "013a"))]
[Path (current-directory) path->string]
[Path-For-Some-System (current-directory) path->string]
[Path-String "foo/bar" relative-path?]
[Place-Channel (let-values ([(p1 p2) (place-channel)]) p1) choice-evt]
[Port (current-input-port) port?]
[Pretty-Print-Style-Table (pretty-print-current-style-table) (lambda (x) (pretty-print-extend-style-table x '() '()))]
[Procedure (lambda (x) x) (lambda (f) (procedure-arity-includes? f 1))]
[Pseudo-Random-Generator (current-pseudo-random-generator) pseudo-random-generator->vector]
[Regexp #rx"hi$" (lambda (p) (regexp-match? p "hi"))]
[Resolved-Module-Path (make-resolved-module-path (current-directory)) resolved-module-path-name]
[Semaphore (make-semaphore) semaphore-post]
[Sexp (syntax->datum (syntax 'foo)) (lambda (x) x)]
[String "yolo" string->symbol]
[Symbol 'a symbol->string]
[TCP-Listener (tcp-listen 0) choice-evt]
[Thread (thread (lambda () (void))) choice-evt]
[Thread-Group (current-thread-group) make-thread-group]
[True #t not]
[UDP-Socket (udp-open-socket) udp-close]
[VectorTop (vector 1 2 3) (lambda (x) (vector-ref x 0))]
[Void (void) void?]
[Will-Executor (make-will-executor) choice-evt]
))
(define-values-for-syntax (base-untyped* base-typed*)
(for/fold ([u* '()] [t* '()])
([tvf (in-list known-base-types)])
(unless (and (list? tvf) (= 3 (length tvf)))
(error 'pr241 "Expected (TYPE VAL FUN)"))
(with-syntax ([type (car tvf)]
[val (cadr tvf)]
[use (caddr tvf)]
[pos-blame 'pr241-test]
[neg-blame 'known-base-types]
[id (gensym (car tvf))])
;; Wrap value in contract, pass it to `use` or assert a wrap failure
;; Ignore the result
(define u-stx
(if (eq? #f (caddr tvf))
#'(with-handlers ([exn:fail:contract? (lambda (e) (void))])
(contract any-wrap/c val 'pos-blame 'neg-blame)
(error 'pr241 (format "Higher-Order value '~a' incorrectly allowed as Any" val)))
#'((lambda any* (void))
(use (contract any-wrap/c val 'pos-blame 'neg-blame)))))
;; Bind the value to a typed identifier
(define t-stx
#'(begin (: id type) (define id val)))
(values
(cons u-stx u*)
(cons t-stx t*)))))
;; `known-polymorphic-types` is a list of 4-lists:
;; [TYPE-TAG TYPE VALUE USE]
;; TYPE-TAG is a polymorphic type exported by Typed Racket
;; TYPE is an instantiation of TYPE-TAG
;; VALUE is an expression with type TYPE
;; USE is the same as for `known-base-types`
(define-for-syntax known-poly-types '(
;; --- Higher-Order polymorphic types
[Async-Channelof (Async-Channelof Any) (make-async-channel) #f]
[Continuation-Mark-Keyof (Continuation-Mark-Keyof Any) (make-continuation-mark-key 'X) #f]
[Custodian-Boxof (Custodian-Boxof Integer) (make-custodian-box (current-custodian) 1) #f]
[Ephemeronof (Ephemeronof Integer) (make-ephemeron 'key 4) #f]
[Evtof (Evtof String) never-evt choice-evt]
[Futureof (Futureof Integer) (future (lambda () 4)) #f]
[MPairof (MPairof Integer String) (mcons 4 "ad") #f]
[MListof (MListof Integer) (mcons 4 '()) #f]
[Prompt-Tagof (Prompt-Tagof Any Any) (make-continuation-prompt-tag) #f]
[Syntaxof (Syntaxof Integer) #'1 #f]
[Thread-Cellof (Thread-Cellof Integer) (make-thread-cell 1) #f]
[Weak-Boxof (Weak-Boxof Integer) (make-weak-box 1) #f]
;; -- Wrappable polymorphic types
[Boxof (Boxof Integer) (box 3) (lambda (v) (add1 (unbox v)))]
[Channelof (Channelof Integer) (make-channel) channel-try-get]
[HashTable (HashTable Symbol String) (hash) (lambda (h) (hash-ref h 'a #f))]
[Listof (Listof Integer) (list 1) (lambda (xs) (add1 (car xs)))]
[Option (Option Integer) 1 add1]
[Pair (Pair Integer Boolean) (cons 1 #t) (lambda (v) (add1 (car v)))]
[Pairof (Pairof Integer Boolean) (cons 1 #f) (lambda (v) (add1 (car v)))]
[Promise (Promise Integer) (delay 3) force]
[Sequenceof (Sequenceof Natural) '(1 2 3) sequence->list]
[Setof (Setof Integer) (set) set-empty?]
[Sexpof (Sexpof Integer) (syntax->datum #'(1 2 3)) (lambda (xs) (add1 (car xs)))]
[Vectorof (Vectorof Integer) (vector 1) (lambda (v) (add1 (vector-ref v 0)))]
))
;; We don't have values to test these types with, but trust they're wrapped correctly
(define-for-syntax whitelist '(
(Undefined . #f)
(Nothing . #f)
(Struct-TypeTop . #f)
(Module-Path-Index . #f)
(Compiled-Module-Expression . #f)
(Namespace-Anchor . #f)
))
(define-values-for-syntax (poly-untyped* poly-typed*)
(for/fold ([u* '()] [t* '()])
([gtvf (in-list known-poly-types)])
(unless (and (list? gtvf) (= 4 (length gtvf)))
(error 'pr241 "Expected (TYPE-TAG TYPE VAL FUN)"))
(with-syntax ([_tag (car gtvf)] ;; Unused here
[type (cadr gtvf)]
[val (caddr gtvf)]
[use (cadddr gtvf)]
[pos-blame 'pr241-test]
[neg-blame 'known-poly-types]
[id (gensym (car gtvf))])
;; Wrap value in contract, pass it to `use` or assert a wrap failure
;; Ignore the result
(define u-stx
(if (eq? #f (cadddr gtvf))
#'(with-handlers ([exn:fail:contract? (lambda (e) (void))])
(contract any-wrap/c val 'pos-blame 'neg-blame)
(error 'pr241 (format "Higher-Order value '~a' incorrectly allowed as Any" val)))
#'((lambda any* (void))
(use (contract any-wrap/c val 'pos-blame 'neg-blame)))))
;; Bind the value to a typed identifier
(define t-stx
#'(begin (: id type) (define id val)))
(values
(cons u-stx u*)
(cons t-stx t*)))))
(define-syntax (known-types->tests stx)
;; Put the `use-` list in an untyped module,
;; put the `declare-` list in a typed module.
#`(begin
(module check-uses racket
(require
racket/async-channel
racket/flonum
racket/extflonum
racket/fixnum
typed-racket/utils/any-wrap)
#,@base-untyped*
#,@poly-untyped*
(printf "Successfully used ~a wrapped values\n"
#,(+ (length base-untyped*) (length poly-untyped*))))
(module check-types typed/racket
(require
racket/flonum
racket/fixnum
racket/extflonum)
(require/typed racket/base
[variable-reference->module-path-index (-> Any Module-Path-Index)])
(require/typed racket/async-channel
[make-async-channel (-> (Async-Channelof Any))])
#,@base-typed*
#,@poly-typed*
(printf "Successfully typechecked ~a identifiers\n"
#,(+ (length base-typed*) (length poly-typed*))))))
(define-for-syntax (known-string? str)
(define s (string->symbol str))
(member* s known-base-types known-poly-types whitelist))
(define-for-syntax (member* s . x**)
(for*/or ([x* (in-list x**)]
[x (in-list x*)])
(eq? s (car x))))
(require
(filtered-in
(if WARN-MISSING
(lambda (str)
(when (not (known-string? str)) (printf "WARNING: Missing test for base type '~a'\n" str))
#f)
(lambda (str) #f))
typed-racket/base-env/base-types))
(known-types->tests)
(require
'check-uses
'check-types)