Add `typecheck-fail' form for explicit type errors.
This commit is contained in:
parent
fb02a0a5cd
commit
706198c059
14
collects/tests/typed-racket/fail/explicit-fail.rkt
Normal file
14
collects/tests/typed-racket/fail/explicit-fail.rkt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#;
|
||||||
|
(exn-fail "incomplete coverage; missing coverage of Negative-Integer")
|
||||||
|
#lang typed/racket
|
||||||
|
|
||||||
|
(define-syntax (cond* stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ x clause ...)
|
||||||
|
#`(cond clause ... [else (typecheck-fail #,stx "incomplete coverage" #:covered-id x)])]))
|
||||||
|
|
||||||
|
(: f : (U String Integer) -> Boolean)
|
||||||
|
(define (f x)
|
||||||
|
(cond* x
|
||||||
|
[(string? x) #t]
|
||||||
|
[(exact-nonnegative-integer? x) #f]))
|
|
@ -822,3 +822,14 @@ This file defines two sorts of primitives. All of them are provided into any mod
|
||||||
(cond c.cond-clause
|
(cond c.cond-clause
|
||||||
...
|
...
|
||||||
[else body ...]))]))
|
[else body ...]))]))
|
||||||
|
|
||||||
|
(define-syntax (typecheck-fail stx)
|
||||||
|
(syntax-parse stx
|
||||||
|
[(_ orig msg:str #:covered-id var:id)
|
||||||
|
#'(quote-syntax (typecheck-fail-internal orig msg var))]
|
||||||
|
[(_ orig msg:str)
|
||||||
|
#'(quote-syntax (typecheck-fail-internal orig msg #f))]
|
||||||
|
[(_ orig #:covered-id var:id)
|
||||||
|
#'(quote-syntax (typecheck-fail-internal orig "Incomplete case coverage" var))]
|
||||||
|
[(_ orig)
|
||||||
|
#'(quote-syntax (typecheck-fail-internal orig "Incomplete case coverage" #f))]))
|
||||||
|
|
|
@ -43,4 +43,31 @@ program errors. These assertions behave like @racket[assert].
|
||||||
@defproc[(index? [v any/c]) boolean?]{A predicate for the @racket[Index]
|
@defproc[(index? [v any/c]) boolean?]{A predicate for the @racket[Index]
|
||||||
type.}
|
type.}
|
||||||
|
|
||||||
|
@defform*/subs[[(typecheck-fail orig-stx maybe-msg maybe-id)]
|
||||||
|
([maybe-msg code:blank (code:line msg-string)]
|
||||||
|
[maybe-id code:blank (code:line #:covered-id id)])]{
|
||||||
|
Explicitly produce a type error, with the source location or
|
||||||
|
@racket[orig-stx]. If @racket[msg-string] is present, it must be a literal string, it is used as
|
||||||
|
the error message, otherwise the error message
|
||||||
|
@racket["Incomplete case coverage"] is used.
|
||||||
|
If @racket[id] is present and has
|
||||||
|
type @racket[T], then the message @racket["missing coverage of T"] is added to
|
||||||
|
the error message.
|
||||||
|
|
||||||
|
@examples[#:eval the-top-eval #:escape UNSYNTAX
|
||||||
|
(define-syntax (cond* stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ x clause ...)
|
||||||
|
#`(cond clause ... [else (typecheck-fail #,stx "incomplete coverage"
|
||||||
|
#:covered-id x)])]))
|
||||||
|
|
||||||
|
(define: (f [x : (U String Integer)]) : Boolean
|
||||||
|
(cond* x
|
||||||
|
[(string? x) #t]
|
||||||
|
[(exact-nonnegative-integer? x) #f]))
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@(close-eval the-eval)
|
@(close-eval the-eval)
|
||||||
|
@(close-eval the-top-eval)
|
||||||
|
|
|
@ -17,5 +17,6 @@
|
||||||
define-typed-struct/exec-internal
|
define-typed-struct/exec-internal
|
||||||
assert-predicate-internal
|
assert-predicate-internal
|
||||||
declare-refinement-internal
|
declare-refinement-internal
|
||||||
:-internal)
|
:-internal
|
||||||
|
typecheck-fail-internal)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
racket/private/class-internal
|
racket/private/class-internal
|
||||||
(except-in syntax/parse id)
|
(except-in syntax/parse id)
|
||||||
unstable/function #;unstable/debug
|
unstable/function #;unstable/debug
|
||||||
(only-in srfi/1 split-at))
|
(only-in srfi/1 split-at)
|
||||||
|
(for-template "internal-forms.rkt"))
|
||||||
|
|
||||||
(require (for-template scheme/base racket/private/class-internal))
|
(require (for-template scheme/base racket/private/class-internal))
|
||||||
|
|
||||||
|
@ -229,6 +230,15 @@
|
||||||
(add-typeof-expr form t)
|
(add-typeof-expr form t)
|
||||||
t)]))))
|
t)]))))
|
||||||
|
|
||||||
|
(define (explicit-fail stx msg var)
|
||||||
|
(cond [(and (identifier? var) (lookup-type/lexical var #:fail (λ _ #f)))
|
||||||
|
=>
|
||||||
|
(λ (t)
|
||||||
|
(tc-error/expr #:return (ret (Un)) #:stx stx
|
||||||
|
(string-append (syntax-e msg) "; missing coverage of ~a")
|
||||||
|
t))]
|
||||||
|
[else (tc-error/expr #:return (ret (Un)) #:stx stx (syntax-e msg))]))
|
||||||
|
|
||||||
;; tc-expr/check : syntax tc-results -> tc-results
|
;; tc-expr/check : syntax tc-results -> tc-results
|
||||||
(define/cond-contract (tc-expr/check/internal form expected)
|
(define/cond-contract (tc-expr/check/internal form expected)
|
||||||
(--> syntax? tc-results? tc-results?)
|
(--> syntax? tc-results? tc-results?)
|
||||||
|
@ -255,6 +265,9 @@
|
||||||
(unless ty
|
(unless ty
|
||||||
(int-err "internal error: ignore-some"))
|
(int-err "internal error: ignore-some"))
|
||||||
(check-below ty expected))]
|
(check-below ty expected))]
|
||||||
|
;; explicit failure
|
||||||
|
[(quote-syntax ((~literal typecheck-fail-internal) stx msg:str var))
|
||||||
|
(explicit-fail #'stx #'msg #'var)]
|
||||||
;; data
|
;; data
|
||||||
[(quote #f) (ret (-val #f) false-filter)]
|
[(quote #f) (ret (-val #f) false-filter)]
|
||||||
[(quote #t) (ret (-val #t) true-filter)]
|
[(quote #t) (ret (-val #t) true-filter)]
|
||||||
|
@ -349,7 +362,9 @@
|
||||||
(unless ty
|
(unless ty
|
||||||
(int-err "internal error: ignore-some"))
|
(int-err "internal error: ignore-some"))
|
||||||
ty)]
|
ty)]
|
||||||
|
;; explicit failure
|
||||||
|
[(quote-syntax ((~literal typecheck-fail-internal) stx msg var))
|
||||||
|
(explicit-fail #'stx #'msg #'var)]
|
||||||
;; data
|
;; data
|
||||||
[(quote #f) (ret (-val #f) false-filter)]
|
[(quote #f) (ret (-val #f) false-filter)]
|
||||||
[(quote #t) (ret (-val #t) true-filter)]
|
[(quote #t) (ret (-val #t) true-filter)]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user