Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

class breaks scopes for splicing internal bodies #2578

Open
LiberalArtist opened this issue Apr 3, 2019 · 3 comments
Open

class breaks scopes for splicing internal bodies #2578

LiberalArtist opened this issue Apr 3, 2019 · 3 comments

Comments

@LiberalArtist
Copy link
Contributor

The following program should work, but doesn't:

#lang racket

(require racket/stxparam
         racket/splicing)

(define-rename-transformer-parameter arg
  (make-rename-transformer #'fail-when-out-of-context))

(define-syntax (fail-when-out-of-context stx)
  (raise-syntax-error #f "not allowed" stx))

(class object%
  (init x)
  (splicing-syntax-parameterize ([arg (make-rename-transformer #'x)])
    (define a-field arg))
  (define/public (get) a-field))

;; identifier used out of context: #<syntax:unsaved-editor:15:20 x>
@LiberalArtist
Copy link
Contributor Author

From @lexi-lambda on Slack:

Peeking at the class form source code and at its expansion in the macro stepper, it looks like what’s going on is that class doesn’t actually expand expressions itself: it expands to some code with the unexpanded expressions left behind and lets the macroexpander do the work. So when you write

(class object%
  (super-new)
  (init [lexical 1])
  (define-syntax indirect (make-variable-like-transformer #'lexical))
  (printf indirect))

it gets turned into something like

(define-syntax indirect (make-variable-like-transformer #'lexical))
(letrec-syntaxes+values ([(lexical) (make-init-redirect #'lexical2)])
                        ([(lexical2) unsafe-undefined])
  (begin
    (super-new)
    (set! lexical2 (extract-args init-args 'lexical))
    (printf indirect)))

Notice that the define-syntax ends up getting moved outside the letrec+syntaxes+values where lexical is rebound.

I think the right fix is to change class so that it expands expressions in the same context it expands everything else, but an easy quick fix that should solve your problem would be to move the define-syntax inside the letrec-syntaxes+values so that things get bound properly.

@LiberalArtist
Copy link
Contributor Author

This issue seems closely related to #1898, but they aren't quite the same: this issue doesn't only affect keywords that are restricted to the top level of class bodies.

@lexi-lambda
Copy link
Member

lexi-lambda commented Apr 4, 2019

Here’s a simpler test case:

#lang racket
(class object%
  (init [(internal external)])
  (define-syntax renamed-internal
    (make-rename-transformer #'internal))
  (define field renamed-internal))
$ racket class-macro-internal.rkt
identifier used out of context: #<syntax:class-macro-internal.rkt:6:16 internal>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants