diff --git a/collects/scribblings/reference/eval-model.scrbl b/collects/scribblings/reference/eval-model.scrbl index a74b795636..a5bd07c8b1 100644 --- a/collects/scribblings/reference/eval-model.scrbl +++ b/collects/scribblings/reference/eval-model.scrbl @@ -629,7 +629,7 @@ is specified as @tech{phaseless} (such as @racketmodname[racket/kernel]). @;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@subsection[#:tag "module-redeclare"]{Module Re-declarations} +@subsection[#:tag "module-redeclare"]{Module Redeclarations} @section-index["modules" "re-define"] @@ -642,9 +642,17 @@ module body. If a new variable definition has a counterpart in the old declaration, it effectively assigns to the old variable. If a module is @tech{instantiate}d in any @tech{phase}s before it is -re-declared, each re-declaration of the module is immediately +redeclared, each redeclaration of the module is immediately @tech{instantiate}d in the same @tech{phase}s. +If the current @tech{inspector} does not manage a module's declaration +inspector (see @secref["modprotect"]), then the module cannot be +redeclared. Similarly, a @tech{phaseless} module cannot be redeclared. +Even if redeclrection succeeds, instantiation of a module that is +previously instantiated may fail if instantiation for the +redeclaration attempts to modify variables that are constant (see +@racket[compile-enforce-module-constants]). + @;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @subsection[#:tag "submodules"]{Submodules} diff --git a/collects/scribblings/reference/syntax-model.scrbl b/collects/scribblings/reference/syntax-model.scrbl index 999964399b..03a2a913f3 100644 --- a/collects/scribblings/reference/syntax-model.scrbl +++ b/collects/scribblings/reference/syntax-model.scrbl @@ -992,8 +992,9 @@ to syntax transformers, via @racket[syntax-local-name]. @section[#:tag "phaseless-grammar"]{Phaseless Module Declarations} A module is @tech{phaseless} only if it fits the following grammar, -which uses non-terminals from @secref["fully-expanded"], and only if -it includes no uses of @racket[quote-syntax] or @racket[#%variable-reference]: +which uses non-terminals from @secref["fully-expanded"], only if +it includes no uses of @racket[quote-syntax] or @racket[#%variable-reference], +and only if no module-level binding is @racket[set!]ed. @racketgrammar*[ #:literals (module module* #%plain-module-begin begin #%provide diff --git a/collects/tests/racket/phaseless.rkt b/collects/tests/racket/phaseless.rkt index 870d14091a..e8d32fef73 100644 --- a/collects/tests/racket/phaseless.rkt +++ b/collects/tests/racket/phaseless.rkt @@ -9,7 +9,7 @@ (define i (open-input-bytes (get-output-bytes o))) (define e (zo-parse i)) (unless (equal? is? (and (memq 'phaseless (mod-flags (compilation-top-code e))) #t)) - (error 'phaseless "failed: ~s ~s\n" is? form)))) + (error 'phaseless "failed: ~s ~s" is? form)))) (check-phaseless #t '(define-values (x) 5)) (check-phaseless #t '(define-values (x) '5)) @@ -35,6 +35,7 @@ (check-phaseless #f '(define-values (x) #(x))) (check-phaseless #f '(define-values (x) '(x))) +(check-phaseless #f '(define-values (x) (lambda () (set! x 8)))) (check-phaseless #f '(define-values (x) (quote-syntax x))) (check-phaseless #f '(define-values (x) (lambda () (quote-syntax x)))) (check-phaseless #f '(define-values (x) (#%variable-reference))) @@ -74,5 +75,22 @@ (check-attach namespace-attach-module) (check-attach namespace-attach-module-declaration)) +;; Check disallowing redeclaration: +(parameterize ([current-namespace (make-base-namespace)]) + (parameterize ([compile-enforce-module-constants #f]) + (eval `(module m racket/kernel + (#%provide x) + (define-values (x) 5))) + (compile `(module m racket/kernel + (#%provide x) + (define-values (x) 6))) + (unless (void? + (with-handlers ([exn:fail? void]) + (eval `(module m racket/kernel + (#%provide x) + (define-values (x) 6))) + 'ok)) + (error 'phaseless "redeclaration should have been disallowed")))) + (displayln "All tests passed.") diff --git a/src/racket/src/compile.c b/src/racket/src/compile.c index 7f8edace8e..6eb2aafa89 100644 --- a/src/racket/src/compile.c +++ b/src/racket/src/compile.c @@ -1203,6 +1203,7 @@ set_syntax (Scheme_Object *form, Scheme_Comp_Env *env, Scheme_Compile_Info *rec, var = scheme_register_toplevel_in_prefix(var, env, rec, drec, 0, NULL); if (env->genv->module) SCHEME_TOPLEVEL_FLAGS(var) |= SCHEME_TOPLEVEL_MUTATED; + env->prefix->non_phaseless = 1; } scheme_compile_rec_done_local(rec, drec); diff --git a/src/racket/src/module.c b/src/racket/src/module.c index 40c74142a4..3e58f6ccbe 100644 --- a/src/racket/src/module.c +++ b/src/racket/src/module.c @@ -6272,7 +6272,7 @@ static Scheme_Object *do_module_execute(Scheme_Object *data, Scheme_Env *genv, Scheme_Object *prefix, Scheme_Object *supermodule) { - Scheme_Module *m; + Scheme_Module *m, *old_m; Scheme_Env *env; Scheme_Env *old_menv; Scheme_Config *config; @@ -6366,13 +6366,26 @@ static Scheme_Object *do_module_execute(Scheme_Object *data, Scheme_Env *genv, if (old_menv) { if (scheme_module_protected_wrt(old_menv->guard_insp, insp) || old_menv->attached) { scheme_contract_error("module->namespace", - "current code inspector cannot re-declare module", + "current code inspector cannot redeclare module", "module name", 1, m->modname, NULL); return NULL; } } + if (old_menv) + old_m = old_menv->module; + else + old_m = (Scheme_Module *)scheme_hash_get(env->module_registry->loaded, m->modname); + + if (old_m && old_m->phaseless) { + scheme_contract_error("module->namespace", + "cannot redeclare phaseless module", + "module name", 1, m->modname, + NULL); + return NULL; + } + if (!set_in_pre) { /* execute pre-submodules: */ execute_submodules(m, 1, genv, set_cache, set_in_pre, prefix); @@ -7117,7 +7130,7 @@ static Scheme_Object *do_module(Scheme_Object *form, Scheme_Comp_Env *env, m->tt_requires = scheme_null; m->dt_requires = scheme_null; - if (iim && iim->phaseless) + if (iim && iim->phaseless && rec[drec].comp) m->phaseless = scheme_true; if (iidx) {