racket / r6rs

Other
6 stars 10 forks source link

Identifier incorrectly allowed to be "both defined and imported" #8

Open LiberalArtist opened 2 years ago

LiberalArtist commented 2 years ago

R6RS §7.1 says:

An identifier can be imported with the same local name from two or more libraries or for two levels from the same library only if the binding exported by each library is the same (i.e., the binding is defined in one library, and it arrives through the imports only by exporting and re-exporting). Otherwise, no identifier can be imported multiple times, defined multiple times, or both defined and imported.

Racket's R6RS language currently fails to enforce this requirement.

Consider the following library, saved in a file bug.sls:

#!r6rs
(library (bug)
  (export)
  (import (rnrs base))
  (define + 'plus))

Racket allows this library, but it is rejected (at least) by Chez Scheme (both upstream and Racket's variant):

philip@bastet:~/code/tmp$ racket bug.sls 
philip@bastet:~/code/tmp$ scheme bug.sls 
Chez Scheme Version 9.5.8
Copyright 1984-2022 Cisco Systems, Inc.

Exception: multiple definitions for + in body (library (bug) (export) (import (rnrs base)) (define + (quote plus))) at line 2, char 1 of bug.sls
philip@bastet:~/code/tmp$ guix shell --pure --container chez-scheme-for-racket -- scheme bug.sls
Chez Scheme Version 9.5.7.6
Copyright 1984-2021 Cisco Systems, Inc.

Exception: multiple definitions for + in body (library (bug) (export) (import (rnrs base)) (define + (quote plus))) at line 2, char 1 of bug.sls
LiberalArtist commented 2 years ago

It looks like https://github.com/racket/racket/commit/163b9dda74a60bad759fefa8bd46a61441f8b926 might be a simple way to fix this.

LiberalArtist commented 2 months ago

I think this incorrectly-accepted program illustrates the same bug, but I am not sure that (#%declare #:require=define) would be enough to fix it:

#!r6rs
(library (conflict)
  (export let)
  (import (for (only (rnrs base) define-syntax lambda) run)
          (for (rnrs base) expand) ; should require (except (rnrs base) let)
          (for (rnrs syntax-case) expand))
  (define-syntax let
    (lambda (stx)
      (syntax-case stx ()
        [(_ id rhs body0 body ...)
         #'((lambda (id) body0 body ...) rhs)]))))