Make static contracts catch simple parametric contract errors.
This commit is contained in:
parent
6deb1e3193
commit
497a7faa83
|
@ -250,7 +250,7 @@
|
||||||
(let ((temporaries (generate-temporaries vs-nm)))
|
(let ((temporaries (generate-temporaries vs-nm)))
|
||||||
(define rv (for/fold ((rv recursive-values)) ((temp temporaries)
|
(define rv (for/fold ((rv recursive-values)) ((temp temporaries)
|
||||||
(v-nm vs-nm))
|
(v-nm vs-nm))
|
||||||
(hash-set rv v-nm (same (impersonator/sc temp)))))
|
(hash-set rv v-nm (same (parametric-var/sc temp)))))
|
||||||
(parametric->/sc temporaries
|
(parametric->/sc temporaries
|
||||||
(t->sc b #:recursive-values rv)))))]
|
(t->sc b #:recursive-values rv)))))]
|
||||||
[(Mu: n b)
|
[(Mu: n b)
|
||||||
|
|
|
@ -2,17 +2,23 @@
|
||||||
|
|
||||||
;; Static contract for parametric->/c.
|
;; Static contract for parametric->/c.
|
||||||
|
|
||||||
(require "../structures.rkt" "../constraints.rkt"
|
(require
|
||||||
racket/list racket/match
|
"../structures.rkt"
|
||||||
unstable/contract
|
"../constraints.rkt"
|
||||||
(except-in racket/contract recursive-contract)
|
"../terminal.rkt"
|
||||||
(for-template racket/base racket/contract/parametric)
|
racket/list racket/match
|
||||||
(for-syntax racket/base syntax/parse))
|
unstable/contract
|
||||||
|
(except-in racket/contract recursive-contract)
|
||||||
|
(for-template racket/base racket/contract/parametric)
|
||||||
|
(for-syntax racket/base syntax/parse))
|
||||||
|
|
||||||
(provide
|
(provide
|
||||||
(contract-out
|
(contract-out
|
||||||
[parametric->/sc ((listof identifier?) static-contract? . -> . static-contract?)])
|
[parametric->/sc ((listof identifier?) static-contract? . -> . static-contract?)]
|
||||||
parametric->/sc:)
|
[parametric-var/sc (identifier? . -> . static-contract?)])
|
||||||
|
parametric->/sc:
|
||||||
|
(rename-out
|
||||||
|
[parametric-var/sc parametric-var/sc:]))
|
||||||
|
|
||||||
|
|
||||||
(struct parametric-combinator combinator (vars)
|
(struct parametric-combinator combinator (vars)
|
||||||
|
@ -44,3 +50,6 @@
|
||||||
(syntax-parser
|
(syntax-parser
|
||||||
[(_ vars body)
|
[(_ vars body)
|
||||||
#'(parametric-combinator (list body) vars)]))
|
#'(parametric-combinator (list body) vars)]))
|
||||||
|
|
||||||
|
(define-terminal-sc parametric-var/sc (id) #:impersonator
|
||||||
|
id)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
racket/sequence
|
racket/sequence
|
||||||
(for-template racket/base (prefix-in c: racket/contract))
|
(for-template racket/base (prefix-in c: racket/contract))
|
||||||
"kinds.rkt"
|
"kinds.rkt"
|
||||||
|
"parametric-check.rkt"
|
||||||
"structures.rkt"
|
"structures.rkt"
|
||||||
"constraints.rkt"
|
"constraints.rkt"
|
||||||
"equations.rkt")
|
"equations.rkt")
|
||||||
|
@ -29,11 +30,13 @@
|
||||||
;; kind is the greatest kind of contract that is supported, if a greater kind would be produced the
|
;; kind is the greatest kind of contract that is supported, if a greater kind would be produced the
|
||||||
;; fail procedure is called.
|
;; fail procedure is called.
|
||||||
(define (instantiate sc fail [kind 'impersonator])
|
(define (instantiate sc fail [kind 'impersonator])
|
||||||
(with-handlers [(exn:fail:constraint-failure?
|
(if (parametric-check sc)
|
||||||
(lambda (exn) (fail #:reason (exn:fail:constraint-failure-reason exn))))]
|
(fail #:reason "multiple parametric contracts are not supported")
|
||||||
(instantiate/inner sc
|
(with-handlers [(exn:fail:constraint-failure?
|
||||||
(compute-recursive-kinds
|
(lambda (exn) (fail #:reason (exn:fail:constraint-failure-reason exn))))]
|
||||||
(contract-restrict-recursive-values (compute-constraints sc kind))))))
|
(instantiate/inner sc
|
||||||
|
(compute-recursive-kinds
|
||||||
|
(contract-restrict-recursive-values (compute-constraints sc kind)))))))
|
||||||
|
|
||||||
(define (compute-constraints sc max-kind)
|
(define (compute-constraints sc max-kind)
|
||||||
(define (recur sc)
|
(define (recur sc)
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
(require
|
||||||
|
racket/match
|
||||||
|
racket/contract
|
||||||
|
(except-in "structures.rkt" recursive-contract)
|
||||||
|
"combinators/parametric.rkt"
|
||||||
|
"combinators/structural.rkt")
|
||||||
|
|
||||||
|
(provide
|
||||||
|
(contract-out
|
||||||
|
[parametric-check (static-contract? . -> . boolean?)]))
|
||||||
|
|
||||||
|
(define (parametric-check sc)
|
||||||
|
(let/ec exit
|
||||||
|
(define (recur sc variance)
|
||||||
|
(match sc
|
||||||
|
[(or/sc: elems ...) (=> continue)
|
||||||
|
(match elems
|
||||||
|
[(list-no-order (parametric-var/sc: _) (parametric-var/sc: _) others ...)
|
||||||
|
(exit #t)]
|
||||||
|
[else (continue)])]
|
||||||
|
[else
|
||||||
|
(sc-traverse sc recur)]))
|
||||||
|
(recur sc 'covariant)
|
||||||
|
#f))
|
|
@ -41,10 +41,8 @@
|
||||||
|
|
||||||
;; Polydotted functions should work
|
;; Polydotted functions should work
|
||||||
(t/fail (-polydots (a) (->... (list) (a a) -Symbol))
|
(t/fail (-polydots (a) (->... (list) (a a) -Symbol))
|
||||||
"not supported for this type")
|
"not supported for this type")))
|
||||||
|
|
||||||
;; These should fail
|
|
||||||
(t (-> (-poly (a b) (-> (Un a b) (Un a b))) Univ))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,6 +71,10 @@
|
||||||
|
|
||||||
(t/fail ((-poly (a) (-vec a)) . -> . -Symbol)
|
(t/fail ((-poly (a) (-vec a)) . -> . -Symbol)
|
||||||
"cannot generate contract for non-function polymorphic type")
|
"cannot generate contract for non-function polymorphic type")
|
||||||
|
(t/fail (-> (-poly (a b) (-> (Un a b) (Un a b))) Univ)
|
||||||
|
"multiple parametric contracts are not supported")
|
||||||
|
|
||||||
|
|
||||||
(t/fail
|
(t/fail
|
||||||
(make-Function
|
(make-Function
|
||||||
(list (make-arr* (list) -Boolean #:kws (list (make-Keyword '#:key Univ #f)))
|
(list (make-arr* (list) -Boolean #:kws (list (make-Keyword '#:key Univ #f)))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user