bugGuile - Bugs: bug #31472, Probable psyntax bug with multiple...

 
 

bug #31472: Probable psyntax bug with multiple defininitions in the macro expansion

Submitted by:  Andreas Rottmann <rottmann>
Submitted on:  Tue 26 Oct 2010 08:42:27 PM UTC  
 
Category:  None Severity:  3 - Normal
Item Group:  None Status:  Fixed
Privacy:  Public Assigned to:  None
Open/Closed:  Closed

Add a New Comment (Rich Markup)
   

You are not logged in

Please log in, so followups can be emailed to you.

 

Mon 07 Nov 2011 11:12:44 AM UTC, comment #4: 

I believe I have fixed this bug in `master'.  References to toplevel definitions are now scoped appropriately, and macro-introduced definitions are given reproducibly-derived hygienic names.  Please send a new mail to bug-guile with a test case if you find more problems.

Regards,

Andy

Andy Wingo <wingo>
Project Administrator
Thu 09 Jun 2011 04:48:42 PM UTC, comment #3: 

I'm trying to understand useful ideoms where this is useful.

One main is to store a state, t, shared by different users
that are published in an interface. This can be solved by,

(library
 (temporaries-bug)
 (export foo1 foo2)
 (import (rnrs))

 (define-syntax define-foo
   (lambda (x)
     (syntax-case x ()
       ((_ name)
(identifier? #'name)
#'(begin
    (define (name) #t)
    (let ((t '(foo name)))
      (set! name (lambda () t))))))))

 (define-foo foo1)
 (define-foo foo2))

Any more ideoms?

/Stefan

Stefan Israelsson Tampe <tampe>
Project Member
Sat 21 May 2011 01:46:44 PM UTC, comment #2: 

Hello guilers,

I want to note some problems that I suspect are caused by this bug. In
this example it looks like (define-foo foo1) and (define-foo foo2) use
the same identifier for `t' (the latter definition overrides the
first):

GNU Guile 2.0.1.79-a02a
Copyright (C) 1995-2011 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (library (temporaries-bug)
                       (export foo1 foo2)
                       (import (rnrs))

                       (define-syntax define-foo
                         (lambda (x)
                           (syntax-case x ()
                             ((_ name)
                              (identifier? #'name)
                              #'(begin
                                  (define t '(foo name))
                                  (define (name) t))))))

                       (define-foo foo1)
                       (define-foo foo2))
scheme@(temporaries-bug)> ,m (guile-user)
scheme@(guile-user)> (import (temporaries-bug))
scheme@(guile-user)> (foo1)
$1 = (foo foo2)
scheme@(guile-user)> (foo2)
$2 = (foo foo2)

One can workaround this issue by using generate-temporaries. But that
doesn't work when (name) is syntax. Here I expect the library to
export syntax that can be used as (foo3), which would evaluate to the
list (foo foo3):

scheme@(guile-user)> (library (temporaries2-bug)
                       (export foo3 foo4)
                       (import (rnrs))

                       (define-syntax define-foo
                         (lambda (x)
                           (syntax-case x ()
                             ((_ name)
                              (identifier? #'name)
                              (with-syntax (((t) (generate-temporaries #'(name))))
                                #'(begin
                                    (define t '(foo name))
                                    (define-syntax name
                                      (lambda (x)
                                        (syntax-case x ()
                                          ((_) #'t))))))))))

                       (define-foo foo3)
                       (define-foo foo4))
scheme@(temporaries2-bug)> ,m (guile-user)
scheme@(guile-user)> (import (temporaries2-bug))
scheme@(guile-user)> (foo3)
;;; <stdin>:7:0: warning: possibly unbound variable `#{ g238}#'
<unnamed port>:6:0: In procedure #<procedure 1e50a00 at <current input>:7:0 ()>:
<unnamed port>:6:0: In procedure module-lookup: Unbound variable: #{ g238}#

Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
scheme@(guile-user) [1]>

Göran Weinholt <weinholt>
Sun 27 Feb 2011 12:33:49 PM UTC, comment #1: 

Hi Andreas,

I have thought about this one a fair amount this weekend.  The issues are twofold.  One, as you note, the modules are getting resolved wrongly -- the expansion makes the procedure scope "t" in the macro's module, not the expansion module.  The question is, what should happen?

According to all the hygiene folk I hear from, the (define t #(1 2 3)) shouldn't actually create a binding for "t" in any module.

A simpler case is the following:

  (define-syntax define-x
    (syntax-rules ()
       ((_) (define x 0))))

The issue is, what should happen when you (define-x) ?  Should you later -- in the REPL, say -- be able to access a binding named "x" in the current module?

Hygiene people say no.  Hygiene people say that since the identifier "x" was introduced by the macro, it should be visible only within the macro --- and since it's not used elsewhere in the macro, effectively it's invisible.  Though you can't really know its extent of course.  And, in Guile, if we were to gensym a name for it -- a wild thing to think about doing, serializing a useless (define x_21234113132 0) into a .go file -- it would still take up "space" in the module (and the .go file), every time you (define-x) you would be adding useless, inaccessible bindings to your image.  It doesn't seem like a great idea.

So, unless I misunderstand the issues or am overlooking a solution, I think that Guile will continue to bind "t" in the expanding module, as indeed happens in this macro.

The second problem thus "resolved", we need to make the procedure in the expansion scope its "t" according to the "t" it introduces.  This only happens when expanding a toplevel sequence -- chi-top-sequence, in psyntax.scm.  I have recently refactored that procedure to be able to know what bindings it introduces before going to expand the expressions.  So your mission, should you choose to accept it, is to distructively mutate the toplevel ribcage before going in to expand the sub-expressions in chi-top-sequence.

Good luck!

Andy

Andy Wingo <wingo>
Project Administrator
Tue 26 Oct 2010 08:42:27 PM UTC, original submission:  

Given the following library:

(library (unbound-bug)
  (export define-foo)
  (import (rnrs))

  (define-syntax define-foo
    (lambda (x)
      (syntax-case x ()
        ((_ name)
         (identifier? #'name)
         #'(begin
             (define t '#(1 2 3))
             (define (name) t)))))))

I get this (what I deem faulty) behavior:

scheme@(guile-user)> (import (unbound-bug))
scheme@(guile-user)> (define-foo bar)
scheme@(guile-user)> (bar)
<unnamed port>:2:1: In procedure module-lookup:
<unnamed port>:2:1: Unbound variable: t

Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
scheme@(guile-user) [1]>

If one modifies the original macro slightly, it works as expected:

  (define-syntax define-foo
    (lambda (x)
      (syntax-case x ()
        ((_ name)
         (identifier? #'name)
         (with-syntax ((t (datum->syntax #'name 't)))
           #'(begin
               (define t '#(1 2 3))
               (define (name) t))))))))

scheme@(guile-user)> (define-foo bar)                                                         
scheme@(guile-user)> (bar)
$1 = #(1 2 3)

Also (with the original macro), this works:

scheme@(guile-user)> (let () (define-foo bar) (bar))                                          
$1 = #(1 2 3)

Andreas Rottmann <rottmann>
Project Member

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by tampe (Posted a comment)
  • -email is unavailable- added by weinholt (Posted a comment)
  • -email is unavailable- added by wingo (Posted a comment)
  • -email is unavailable- added by rottmann (Submitted the item)
  •  

    Do you think this task is very important?
    If so, you can add your encouragement to it.
    This task has 0 encouragements so far.

    Only logged-in users can vote.

     

     

     

    Follow 2 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2011-11-07 wingo StatusNone => Fixed
        Open/ClosedOpen => Closed

    Back to the top


    Powered by Savane 3.7