expander: fix problems with cross-phase persistence

This commit is contained in:
Matthew Flatt 2018-02-26 20:29:22 -07:00
parent 9fec456335
commit 586feb6df0
6 changed files with 1598 additions and 1330 deletions

View File

@ -1170,7 +1170,8 @@ and only if no module-level binding is @racket[set!]ed.
boolean
identifier
string
bytes]
bytes
()]
]
This grammar applies after @tech{expansion}, but because a @tech{cross-phase persistent}

View File

@ -53,6 +53,17 @@
(check-cross-phase #f '(define-values (x) (#%variable-reference)))
(check-cross-phase #f '(define-values (x) (lambda () (#%variable-reference))))
(check-cross-phase #f '(define-values (x) (lambda () (if #f (#%variable-reference) 10))))
(check-cross-phase #f '(define-values (x) (lambda () (if #f 10 (#%variable-reference)))))
(check-cross-phase #f '(define-values (x) (lambda () (if (#%variable-reference) #f 10))))
(check-cross-phase #f '(define-values (x) (lambda () (with-continuation-mark (set! x x) 1 2))))
(check-cross-phase #f '(define-values (x) (lambda () (with-continuation-mark 1 (set! x x) 2))))
(check-cross-phase #f '(define-values (x) (lambda () (with-continuation-mark 1 2 (set! x x)))))
(check-cross-phase #f '(define-values (x) (lambda () (begin 1 2 (set! x x)))))
(check-cross-phase #f '(define-values (x) (lambda () (begin0 1 2 (set! x x)))))
(check-cross-phase #f '(define-values (x) (lambda () (let-values ([q (set! x x)]) q))))
(check-cross-phase #f '(define-values (x) (lambda () (let-values ([q 'ok]) (set! x x)))))
(check-cross-phase #f '(define-values (x) (lambda () (letrec-values ([q (set! x x)]) q))))
(check-cross-phase #f '(define-values (x) (lambda () (letrec-values ([q 'ok]) (set! x x)))))
(check-cross-phase #f '(define-values (x) (#%variable-reference x)))
(check-cross-phase #f '(#%require racket/base))
(check-cross-phase #f '(define-values (x) (gensym 1)))

View File

@ -15,53 +15,103 @@
(provide check-cross-phase-persistent-form)
(define (check-cross-phase-persistent-form bodys)
(check-body bodys))
(define (check-cross-phase-persistent-form bodys self-mpi)
(define (check-body bodys)
(for ([body (in-list bodys)])
(define p (if (expanded+parsed? body)
(expanded+parsed-parsed body)
body))
(define (check-body bodys)
(for ([body (in-list bodys)])
(define p (if (expanded+parsed? body)
(expanded+parsed-parsed body)
body))
(cond
[(parsed-define-values? p)
(check-expr (parsed-define-values-rhs p) (length (parsed-define-values-syms p)) p)]
[(or (parsed-#%declare? p)
(parsed-module? p)
(syntax? p)) ;; remaining unparsed forms, such as `#%require` and `#%provide`, are ok
(void)]
[else
(disallow p)])))
(define (check-expr e num-results enclosing)
(cond
[(parsed-define-values? p)
(check-expr (parsed-define-values-rhs p) (length (parsed-define-values-syms p)) p)]
[(or (parsed-#%declare? p)
(parsed-module? p)
(syntax? p)) ;; remaining unparsed forms, such as `#%require` and `#%provide`, are ok
(void)]
[else
(disallow p)])))
[(parsed-lambda? e)
(check-count 1 num-results enclosing)
(check-no-disallowed-expr e)]
[(parsed-case-lambda? e)
(check-count 1 num-results enclosing)
(check-no-disallowed-expr e)]
[(parsed-quote? e)
(check-datum (parsed-quote-datum e) e)
(check-count 1 num-results enclosing)]
[(parsed-app? e)
(define rands (parsed-app-rands e))
(for ([rand (in-list rands)])
(check-expr rand 1 e))
(case (cross-phase-primitive-name (parsed-app-rator e))
[(cons list)
(check-count 1 num-results enclosing)]
[(make-struct-type)
(check-count 5 num-results enclosing)]
[(make-struct-type-property)
(check-count 3 num-results enclosing)]
[(gensym)
(unless (or (= 0 (length rands))
(and (= 1 (length rands))
(quoted-string? (car rands))))
(disallow e))]
[(string->uninterned-symbol)
(unless (and (= 1 (length rands))
(quoted-string? (car rands)))
(disallow e))]
[else (disallow e)])]
[else (check-no-disallowed-expr e)]))
(define (check-expr e num-results enclosing)
(cond
[(or (parsed-lambda? e)
(parsed-case-lambda? e))
(check-count 1 num-results enclosing)]
[(parsed-quote? e)
(check-datum (parsed-quote-datum e) e)
(check-count 1 num-results enclosing)]
[(parsed-app? e)
(define rands (parsed-app-rands e))
(for ([rand (in-list rands)])
(check-expr rand 1 e))
(case (cross-phase-primitive-name (parsed-app-rator e))
[(cons list)
(check-count 1 num-results enclosing)]
[(make-struct-type)
(check-count 5 num-results enclosing)]
[(make-struct-type-property)
(check-count 3 num-results enclosing)]
[(gensym)
(unless (or (= 0 (length rands))
(and (= 1 (length rands))
(quoted-string? (car rands))))
(disallow e))]
[(string->uninterned-symbol)
(unless (and (= 1 (length rands))
(quoted-string? (car rands)))
(disallow e))]
[else (disallow e)])]))
(define (check-no-disallowed-expr e)
(cond
[(parsed-lambda? e)
(check-body-no-disallowed-expr (parsed-lambda-body e))]
[(parsed-case-lambda? e)
(for ([clause (in-list (parsed-case-lambda-clauses e))])
(check-body-no-disallowed-expr (cadr clause)))]
[(parsed-app? e)
(check-no-disallowed-expr (parsed-app-rator e))
(for ([e (in-list (parsed-app-rands e))])
(check-no-disallowed-expr e))]
[(parsed-if? e)
(check-no-disallowed-expr (parsed-if-tst e))
(check-no-disallowed-expr (parsed-if-thn e))
(check-no-disallowed-expr (parsed-if-els e))]
[(parsed-set!? e)
(define id (parsed-set!-id e))
(define normal-b (parsed-id-binding id))
(when (or (not normal-b)
(parsed-top-id? id)
(eq? (module-binding-module normal-b) self-mpi))
(disallow e))
(check-no-disallowed-expr (parsed-set!-rhs e))]
[(parsed-with-continuation-mark? e)
(check-no-disallowed-expr (parsed-with-continuation-mark-key e))
(check-no-disallowed-expr (parsed-with-continuation-mark-val e))
(check-no-disallowed-expr (parsed-with-continuation-mark-body e))]
[(parsed-begin? e)
(check-body-no-disallowed-expr (parsed-begin-body e))]
[(parsed-begin0? e)
(check-body-no-disallowed-expr (parsed-begin0-body e))]
[(parsed-let_-values? e)
(for ([clause (in-list (parsed-let_-values-clauses e))])
(check-no-disallowed-expr (cadr clause)))
(check-body-no-disallowed-expr (parsed-let_-values-body e))]
[(or (parsed-quote-syntax? e)
(parsed-#%variable-reference? e))
(disallow e)]
;; Other forms have no subexpressions
[else (void)]))
(define (check-body-no-disallowed-expr l)
(for ([e (in-list l)])
(check-no-disallowed-expr e)))
(check-body bodys))
(define (check-count is-num expected-num enclosing)
(unless (= is-num expected-num)
@ -69,9 +119,9 @@
(define (check-datum d e)
(cond
[(or (number? d) (boolean? d) (symbol? d) (string? d) (bytes? d))
(void)]
[else (disallow e)]))
[(or (number? d) (boolean? d) (symbol? d) (string? d) (bytes? d) (null? d))
(void)]
[else (disallow e)]))
(define (quoted-string? e)
(and (parsed-quote? e)
@ -79,12 +129,12 @@
(define (cross-phase-primitive-name id)
(cond
[(parsed-id? id)
(define b (parsed-id-binding id))
(and (module-binding? b)
(eq? runtime-module-name (module-path-index-resolve (module-binding-module b)))
(module-binding-sym b))]
[else #f]))
[(parsed-id? id)
(define b (parsed-id-binding id))
(and (module-binding? b)
(eq? runtime-module-name (module-path-index-resolve (module-binding-module b)))
(module-binding-sym b))]
[else #f]))
(define (disallow body)
(raise-syntax-error 'module

View File

@ -389,7 +389,7 @@
(raise-syntax-error #f "cannot be cross-phase persistent due to required modules"
rebuild-s
(hash-ref declared-keywords '#:cross-phase-persistent)))
(check-cross-phase-persistent-form fully-expanded-bodys-except-post-submodules))
(check-cross-phase-persistent-form fully-expanded-bodys-except-post-submodules self))
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Pass 4: expand `module*` submodules

View File

@ -81,7 +81,8 @@
(define-values (m-ns already?)
(cond
[attach-this-instance?
[(or attach-this-instance?
(module-cross-phase-persistent? m))
(define m-ns (namespace->module-namespace src-namespace mod-name phase))
(unless m-ns
(raise-arguments-error who

File diff suppressed because it is too large Load Diff