Version: 4.2.1

7.4 Identifier used out of context

Looks like this:

compile: identifier used out of context in: stuff

This occurs when a syntax template contains a reference to a locally-scoped name and the resulting syntax is later interpreted in a context outside of the scope of that name. The following examples illustrate how that can happen.

Usually the cause of this problem is a macro that has a local binding and a syntax template that refers to that local binding. Referring to such a local binding is illegal. Here’s a simple example:

  > (define stuff 10)
  > (define-syntax (m stx)
      (syntax-case stx ()
        [(m e)
         (let ([stuff 'some-stuff])
           #'(+ e stuff))]))
  > (m 7)

  eval:3:0: compile: identifier used out of context in: stuff

The reference to stuff in the syntax template refers to the nearest enclosing binding of stuff, which is inside the macro. When (m 7) is expanded, it produces (+ 7 stuff). The new occurrence of stuff is outside of the scope of the stuff binding it refers to, and the macro expander raises an “identifier used out of context” error.

The problem is not simply a phase mismatch, although in the previous example the local binding was at phase 1 and the reference was compiled at phase 0. Here is an example where the binding and reference are at the same phase:

  > (define-syntax (def stx)
      (syntax-case stx ()
        [(m x)
         (let ([stuff 10])
           #'(define-syntax x stuff))]))
  > (def y)

  eval:2:0: compile: identifier used out of context in: stuff

The binding of stuff is at phase 1. The reference to stuff is at phase 1. But it’s still out of context.

The problem is not even because the binding only exists for the duration of the macro’s activation. Here’s an example of a local binding that outlives the macro transformation step; the macro’s output is still illegal.

  > (define-syntax def
      (let ([stuff 10])
        (lambda (stx)
          (syntax-case stx ()
            [(m x)
             (let ([stuff 10])
               #'(define-syntax x stuff))]))))
  > (def y)

  eval:2:0: compile: identifier used out of context in: stuff

It is possible to trigger an “out of context” error by using eval also:

  > (let ([stuff 10])
      (eval #'(+ stuff 7)))

  eval:2:0: compile: identifier used out of context in: stuff

This code fails because eval interprets its argument as top-level code, so even though the call occurs inside of the stuff binding, the syntax is interpreted effectively outside of it.