Make optimize for static contracts have saner interface.
original commit: 6cfb035b3f5aab1e17a93d4cfab98d29cfef760a
This commit is contained in:
parent
be2c246d1f
commit
9c6d897d02
|
@ -156,7 +156,8 @@
|
|||
(instantiate
|
||||
(optimize
|
||||
(type->static-contract ty #:typed-side typed-side fail)
|
||||
(if typed-side 'covariant 'contravariant))
|
||||
#:trusted-positive typed-side
|
||||
#:trusted-negative (not typed-side))
|
||||
fail
|
||||
kind)))
|
||||
|
||||
|
|
|
@ -105,9 +105,11 @@
|
|||
(merge-restricts* 'kind.category-stx (sc.->restricts v recur)))]
|
||||
#:methods gen:equal+hash
|
||||
[(define (equal-proc a b recur)
|
||||
(for/and ([sub-a (in-list (combinator-args a))]
|
||||
[sub-b (in-list (combinator-args b))])
|
||||
(recur sub-a sub-b)))
|
||||
(and (recur (length (combinator-args a))
|
||||
(length (combinator-args b)))
|
||||
(for/and ([sub-a (in-list (combinator-args a))]
|
||||
[sub-b (in-list (combinator-args b))])
|
||||
(recur sub-a sub-b))))
|
||||
(define (hash-proc v recur)
|
||||
(+ (recur 'sc.name)
|
||||
(for/sum ((sub (in-list (combinator-args v))))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#lang racket/base
|
||||
|
||||
;; Functionalityt otoptimize a static contract to provide faster checking.
|
||||
;; Also supports droping one side's obligations.
|
||||
;; Functionality to optimize a static contract to provide faster checking.
|
||||
;; Also supports droping checks on either side.
|
||||
|
||||
(require "combinators.rkt"
|
||||
"structures.rkt"
|
||||
|
@ -12,12 +12,15 @@
|
|||
|
||||
|
||||
|
||||
(provide
|
||||
(provide
|
||||
(contract-out
|
||||
[optimize (static-contract? (or/c 'covariant 'contravariant 'invariant ) . -> . static-contract?)]))
|
||||
[optimize ((static-contract?) (#:trusted-positive boolean? #:trusted-negative boolean?)
|
||||
. ->* . static-contract?)]))
|
||||
|
||||
(define (none/sc-reduce sc)
|
||||
;; Reduce a static contract to a smaller simpler one that protects in the same way
|
||||
(define (reduce sc)
|
||||
(match sc
|
||||
;; none/sc cases
|
||||
[(listof/sc: (none/sc:)) empty-list/sc]
|
||||
[(list/sc: sc1 ... (none/sc:) sc2 ...) none/sc]
|
||||
[(vectorof/sc: (none/sc:)) empty-vector/sc]
|
||||
|
@ -28,11 +31,8 @@
|
|||
[(promise/sc: (none/sc:)) none/sc]
|
||||
[(hash/sc: (none/sc:) value/sc) empty-hash/sc]
|
||||
[(hash/sc: key/sc (none/sc:)) empty-hash/sc]
|
||||
[else sc]))
|
||||
|
||||
|
||||
(define (any/sc-reduce sc)
|
||||
(match sc
|
||||
;; any/sc cases
|
||||
[(listof/sc: (any/sc:)) list?/sc]
|
||||
[(list/sc: (and scs (any/sc:)) ...) (list-length/sc (length scs))]
|
||||
[(vectorof/sc: (any/sc:)) vector?/sc]
|
||||
|
@ -42,88 +42,80 @@
|
|||
[(syntax/sc: (any/sc:)) syntax?/sc]
|
||||
[(promise/sc: (any/sc:)) promise?/sc]
|
||||
[(hash/sc: (any/sc:) (any/sc:)) hash?/sc]
|
||||
|
||||
;; or/sc cases
|
||||
[(or/sc: scs ...)
|
||||
(match scs
|
||||
[(list) none/sc]
|
||||
[(list sc) sc]
|
||||
[(? (λ (l) (member any/sc l))) any/sc]
|
||||
[(? (λ (l) (member none/sc l)))
|
||||
(apply or/sc (remove* (list none/sc) scs))]
|
||||
[else sc])]
|
||||
|
||||
;; and/sc cases
|
||||
[(and/sc: scs ...)
|
||||
(match scs
|
||||
[(list) any/sc]
|
||||
[(list sc) sc]
|
||||
[(? (λ (l) (member none/sc l))) none/sc]
|
||||
[(? (λ (l) (member any/sc l)))
|
||||
(apply and/sc (remove* (list any/sc) scs))]
|
||||
[else sc])]
|
||||
|
||||
|
||||
|
||||
[else sc]))
|
||||
|
||||
|
||||
(define (covariant-any/sc-reduce sc)
|
||||
;; Reduce a static contract assuming that we trusted the current positive side
|
||||
(define (trusted-side-reduce sc)
|
||||
(match sc
|
||||
[(->/sc: mand-args opt-args mand-kw-args opt-kw-args rest-arg (list (any/sc:) ...))
|
||||
(function/sc mand-args opt-args mand-kw-args opt-kw-args rest-arg #f)]
|
||||
[(arr/sc: args rest (list (any/sc:) ...))
|
||||
(arr/sc args rest #f)]
|
||||
[else sc]))
|
||||
|
||||
(define (covariant-none/sc-reduce sc)
|
||||
(match sc
|
||||
[(none/sc:) any/sc]
|
||||
[else sc]))
|
||||
|
||||
(define (or/sc-reduce sc)
|
||||
(match sc
|
||||
[(or/sc:) none/sc]
|
||||
[(or/sc: sc) sc]
|
||||
[(or/sc: sc1 ... (any/sc:) sc2 ...)
|
||||
any/sc]
|
||||
[(or/sc: sc1 ... (none/sc:) sc2 ...)
|
||||
(or/sc-reduce (apply or/sc (append sc1 sc2)))]
|
||||
[else sc]))
|
||||
|
||||
(define (and/sc-reduce sc)
|
||||
(match sc
|
||||
[(and/sc:) any/sc]
|
||||
[(and/sc: sc) sc]
|
||||
[(and/sc: sc1 ... (none/sc:) sc2 ...)
|
||||
none/sc]
|
||||
[(and/sc: sc1 ... (any/sc:) sc2 ...)
|
||||
(and/sc-reduce (apply and/sc (append sc1 sc2)))]
|
||||
[else sc]))
|
||||
|
||||
|
||||
|
||||
(define (covariant-flat-reduce sc)
|
||||
(match sc
|
||||
[(? flat/sc?) any/sc]
|
||||
[(none/sc:) any/sc]
|
||||
[sc sc]))
|
||||
[else sc]))
|
||||
|
||||
(define (invert-variance v)
|
||||
|
||||
|
||||
(define (invert-side v)
|
||||
(case v
|
||||
[(covariant) 'contravariant]
|
||||
[(contravariant) 'covariant]
|
||||
[(invariant) 'invariant]))
|
||||
[(positive) 'negative]
|
||||
[(negative) 'positive]
|
||||
[(both) 'both]))
|
||||
|
||||
(define (combine-variance var1 var2)
|
||||
(case var1
|
||||
[(covariant) var2]
|
||||
[(contravariant) (invert-variance var2)]
|
||||
[(invariant) 'invariant]))
|
||||
(define (combine-variance side var)
|
||||
(case var
|
||||
[(covariant) side]
|
||||
[(contravariant) (invert-side side)]
|
||||
[(invariant) 'both]))
|
||||
|
||||
;; If the variance is 'covariant, drops the parts ensuring that server behaves
|
||||
;; If the variance is 'contrvariant, drops the parts ensuring that client behaves
|
||||
;; If the variance is 'invariant, only optimizes the contract.
|
||||
(define (optimize sc variance)
|
||||
(define (single-step sc variance)
|
||||
(define ((maybe/co reduce) sc)
|
||||
(case variance
|
||||
[(covariant) (reduce sc)]
|
||||
[(contravariant invariant) sc]
|
||||
[else (error 'maybe/co "Bad variance ~a" variance)]))
|
||||
;; If we trust a specific side then we drop all contracts protecting that side.
|
||||
(define (optimize sc #:trusted-positive [trusted-positive #f] #:trusted-negative [trusted-negative #f])
|
||||
;; single-step: reduce and trusted-side-reduce if appropriate
|
||||
(define (single-step sc side)
|
||||
(define trusted
|
||||
(case side
|
||||
[(positive) trusted-positive]
|
||||
[(negative) trusted-negative]
|
||||
[(both) (and trusted-positive trusted-negative)]))
|
||||
|
||||
((compose
|
||||
(maybe/co covariant-flat-reduce)
|
||||
(maybe/co covariant-any/sc-reduce)
|
||||
(maybe/co covariant-none/sc-reduce)
|
||||
and/sc-reduce
|
||||
or/sc-reduce
|
||||
none/sc-reduce
|
||||
any/sc-reduce)
|
||||
sc))
|
||||
(reduce
|
||||
(if trusted
|
||||
(trusted-side-reduce sc)
|
||||
sc)))
|
||||
|
||||
;; full-pass: single-step at every static contract subpart
|
||||
(define (full-pass sc)
|
||||
(define ((recur current-variance) sc variance)
|
||||
(define new-variance (combine-variance current-variance variance))
|
||||
(single-step (sc-map sc (recur new-variance)) new-variance))
|
||||
((recur variance) sc 'covariant))
|
||||
(define ((recur side) sc variance)
|
||||
(define new-side (combine-variance side variance))
|
||||
(single-step (sc-map sc (recur new-side)) new-side))
|
||||
((recur 'positive) sc 'covariant))
|
||||
|
||||
;; Do full passes until we reach a fix point
|
||||
(let loop ((sc sc))
|
||||
(define new-sc (full-pass sc))
|
||||
(if (equal? sc new-sc)
|
||||
|
|
|
@ -16,7 +16,11 @@
|
|||
(list (make-check-info 'original argument)
|
||||
(make-check-expected expected))
|
||||
(lambda ()
|
||||
(let ([opt (optimize argument variance)])
|
||||
(define trusted-positive (equal? variance 'covariant))
|
||||
(define trusted-negative (equal? variance 'contravariant))
|
||||
(let ([opt (optimize argument
|
||||
#:trusted-positive trusted-positive
|
||||
#:trusted-negative trusted-negative)])
|
||||
(with-check-info* (list (make-check-actual opt))
|
||||
(lambda ()
|
||||
(unless (equal? opt expected)
|
||||
|
|
Loading…
Reference in New Issue
Block a user