expander: fix problems with syntax-local-make-definition-context

Allow `syntax-local-make-definition-context` in places where the
created scope is not accumulated for stripping from `quote-syntax`.
Refine the docs to clarify those situtations.

A test for the repair exposed a problem with use-site scopes
and `quote-syntax`, so fix that, too.

Closes #2062
This commit is contained in:
Matthew Flatt 2018-05-06 16:22:40 -06:00
parent f9821f9f15
commit c927a004d2
9 changed files with 4645 additions and 4514 deletions

View File

@ -498,6 +498,12 @@ argument to ensure the necessary @tech{use-site scopes} are added to macros expa
Otherwise, expansion of nested definitions can be inconsistent with the expansion of definitions in Otherwise, expansion of nested definitions can be inconsistent with the expansion of definitions in
the surrounding context. the surrounding context.
The scope associated with a new definition context is pruned from
@racket[quote-syntax] forms only when it is created during the dynamic
extent of a @tech{syntax transformer} application or in a
@racket[begin-for-syntax] form (potentially nested) within a module
being expanded.
@transform-time[] @transform-time[]
@history[#:changed "6.3" @elem{Added the @racket[add-scope?] argument, @history[#:changed "6.3" @elem{Added the @racket[add-scope?] argument,

View File

@ -519,6 +519,69 @@
(provide v)) (provide v))
(test 1 dynamic-require ''uses-internal-definition-context-around-id 'v) (test 1 dynamic-require ''uses-internal-definition-context-around-id 'v)
;; Make sure `syntax-local-make-definition-context` can be called
;; at unusual times, where the scope that is otherwise captured
;; for `quote-syntax` isn't or can't be recorded
(let-syntax ([x (syntax-local-make-definition-context)])
(void))
(module makes-definition-context-at-compile-time-begin racket
(begin-for-syntax
(syntax-local-make-definition-context)))
(require 'makes-definition-context-at-compile-time-begin)
(module create-definition-context-during-visit racket/base
(require (for-syntax racket/base))
(provide (for-syntax ds))
;; won't be stipped for `quote-syntax`
(define-for-syntax ds (syntax-local-make-definition-context)))
(module create-definition-context-during-expand racket/base
(require (for-syntax racket/base)
'create-definition-context-during-visit)
(provide results
get-results)
;; will be stipped for `quote-syntax`
(define-for-syntax ds2 (syntax-local-make-definition-context))
(define-syntax (m stx)
(syntax-case stx ()
[(_ body)
(internal-definition-context-introduce ds #'body)]))
(define-syntax (m2 stx)
(syntax-case stx ()
[(_ body)
(internal-definition-context-introduce ds2 #'body)]))
(define-syntax (m3 stx)
(syntax-case stx ()
[(_ body)
(let ([ds3 (syntax-local-make-definition-context)])
(internal-definition-context-introduce ds3 #'body))]))
(define results
(list
(bound-identifier=? (m #'x)
#'x)
(bound-identifier=? (m2 #'x)
#'x)
(bound-identifier=? (m3 #'x)
#'x)))
(define (get-results)
(list
(bound-identifier=? (m #'x)
#'x)
(bound-identifier=? (m2 #'x)
#'x)
(bound-identifier=? (m3 #'x)
#'x))))
(test '(#f #t #t) dynamic-require ''create-definition-context-during-expand 'results)
(test '(#f #t #t) (dynamic-require ''create-definition-context-during-expand 'get-results))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module local-expand-begin-for-syntax-test racket/base (module local-expand-begin-for-syntax-test racket/base
@ -1509,6 +1572,22 @@
(eval-syntax #'a) (eval-syntax #'a)
(eval-syntax (expand-syntax #'b)))]))) (eval-syntax (expand-syntax #'b)))])))
;; ----------------------------------------
;; Basic use-site scope example
(module define-n-as-ten-not-five racket/base
(define x 10)
(define-syntax-rule (use-x misc-id)
(let ([misc-id 5])
x))
(define n (use-x x))
(provide n))
(test 10 dynamic-require ''define-n-as-ten-not-five 'n)
;; ---------------------------------------- ;; ----------------------------------------
;; Check that use-site scopes are not pruned too eagerly ;; Check that use-site scopes are not pruned too eagerly
;; (based on examples from Brian Mastenbrook) ;; (based on examples from Brian Mastenbrook)

View File

@ -234,7 +234,6 @@
(define-values (require-lifts lifts exp-s) (define-values (require-lifts lifts exp-s)
(expand-capturing-lifts s (struct*-copy expand-context tl-ctx (expand-capturing-lifts s (struct*-copy expand-context tl-ctx
[only-immediate? #t] [only-immediate? #t]
[def-ctx-scopes (box null)] ; discarding is ok
[phase phase] [phase phase]
[namespace ns]))) [namespace ns])))
(define disarmed-exp-s (raw:syntax-disarm exp-s)) (define disarmed-exp-s (raw:syntax-disarm exp-s))

View File

@ -90,7 +90,7 @@
empty-env empty-env
push-scope ; post-expansion-scope-action push-scope ; post-expansion-scope-action
null ; scopes null ; scopes
#f ; def-ctx-scopes #f ; def-ctx-scopes [=> don't record scopes to be stipped for `quote-syntax`]
(root-expand-context-frame-id root-ctx) ; binding-layer (root-expand-context-frame-id root-ctx) ; binding-layer
null ; reference-records null ; reference-records
#f ; only-immediate? #f ; only-immediate?

View File

@ -55,8 +55,8 @@
(gensym))) (gensym)))
(define sc (new-scope 'intdef)) (define sc (new-scope 'intdef))
(define def-ctx-scopes (expand-context-def-ctx-scopes ctx)) (define def-ctx-scopes (expand-context-def-ctx-scopes ctx))
(unless def-ctx-scopes (error "internal error: no box to accumulate definition-context scopes")) (when def-ctx-scopes
(set-box! def-ctx-scopes (cons sc (unbox def-ctx-scopes))) (set-box! def-ctx-scopes (cons sc (unbox def-ctx-scopes))))
(internal-definition-context frame-id sc add-scope? (box null) parent-ctx)) (internal-definition-context frame-id sc add-scope? (box null) parent-ctx))
;; syntax-local-bind-syntaxes ;; syntax-local-bind-syntaxes

View File

@ -454,7 +454,9 @@
`(,(m-local 'quote-syntax) ,(m-local 'datum) ,(m-kw 'kw))))] `(,(m-local 'quote-syntax) ,(m-local 'datum) ,(m-kw 'kw))))]
[else [else
;; otherwise, prune scopes up to transformer boundary: ;; otherwise, prune scopes up to transformer boundary:
(define datum-s (remove-scopes (m 'datum) (expand-context-scopes ctx))) (define use-site-scopes (root-expand-context-use-site-scopes ctx))
(define datum-s (remove-scopes (remove-scopes (m 'datum) (expand-context-scopes ctx))
(if use-site-scopes (unbox use-site-scopes) '())))
(if (and (expand-context-to-parsed? ctx) (if (and (expand-context-to-parsed? ctx)
(free-id-set-empty? (expand-context-stops ctx))) (free-id-set-empty? (expand-context-stops ctx)))
(parsed-quote-syntax (keep-properties-only~ s) datum-s) (parsed-quote-syntax (keep-properties-only~ s) datum-s)

View File

@ -360,7 +360,7 @@
[to-module-lifts (make-to-module-lift-context phase [to-module-lifts (make-to-module-lift-context phase
#:shared-module-ends module-ends #:shared-module-ends module-ends
#:end-as-expressions? #t)])) #:end-as-expressions? #t)]))
(finish-expanding-body-expressons partially-expanded-bodys (finish-expanding-body-expressons partially-expanded-bodys
#:phase phase #:phase phase
#:ctx body-ctx #:ctx body-ctx
@ -502,7 +502,8 @@
;; Expand the body ;; Expand the body
(define expanded-mb (performance-region (define expanded-mb (performance-region
['expand 'module-begin] ['expand 'module-begin]
(expand mb (accumulate-def-ctx-scopes mb-ctx mb-def-ctx-scopes)))) (expand mb (struct*-copy expand-context (accumulate-def-ctx-scopes mb-ctx mb-def-ctx-scopes)
[def-ctx-scopes #f]))))
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Assemble the `module` result ;; Assemble the `module` result

View File

@ -156,7 +156,7 @@
;; Discarding definition-context scopes is ok, ;; Discarding definition-context scopes is ok,
;; because the scopes won't be captured by ;; because the scopes won't be captured by
;; any `quote-syntax`: ;; any `quote-syntax`:
[def-ctx-scopes (box null)]))) [def-ctx-scopes #f])))
(unless (and (pair? (syntax-e exp-spec)) (unless (and (pair? (syntax-e exp-spec))
(identifier? (car (syntax-e exp-spec))) (identifier? (car (syntax-e exp-spec)))
(eq? 'begin (core-form-sym exp-spec at-phase))) (eq? 'begin (core-form-sym exp-spec at-phase)))

File diff suppressed because it is too large Load Diff