diff --git a/pkgs/racket-test-core/tests/racket/module.rktl b/pkgs/racket-test-core/tests/racket/module.rktl index 541ba61d8a..0233b98026 100644 --- a/pkgs/racket-test-core/tests/racket/module.rktl +++ b/pkgs/racket-test-core/tests/racket/module.rktl @@ -3117,6 +3117,32 @@ case of module-leve bindings; it doesn't cover local bindings. (test 0 length vals) (test 1 length stxes))) +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Check that a `local-expand`-triggered lazy instantiation does not +;; re-enter an instantiation that is already in progress + +(module uses-local-expand-at-phase-1-instantiation racket/base + (require (for-syntax racket/base + (for-syntax racket/base))) + (provide (for-syntax true)) + (struct Π- (X)) + (begin-for-syntax + (define TY/internal+ (local-expand #'Π- 'expression null)) + (define true (lambda (x) #t)))) + +(module imports-uses-local-expand-at-phase-1-instantiation racket/base + (require (for-syntax racket/base) + 'uses-local-expand-at-phase-1-instantiation) + (provide #%module-begin) + (define-for-syntax predicate true)) + +(module lang-is-imports-uses-local-expand 'imports-uses-local-expand-at-phase-1-instantiation) + +(let () + ;; important that both of these are in the same top-level evaluation: + (test (void) namespace-require ''lang-is-imports-uses-local-expand) + (test #t namespace? (module->namespace ''lang-is-imports-uses-local-expand))) + ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (report-errs) diff --git a/racket/src/expander/namespace/module.rkt b/racket/src/expander/namespace/module.rkt index 0fd46499ba..fcf469db54 100644 --- a/racket/src/expander/namespace/module.rkt +++ b/racket/src/expander/namespace/module.rkt @@ -139,7 +139,7 @@ (struct module-instance (namespace module ; can be #f for the module being expanded [shifted-requires #:mutable] ; computed on demand; shifted from `module-requires` - phase-level-to-state ; phase-level -> #f, 'available, or 'started + phase-level-to-state ; phase-level -> #f, 'available, 'trying-to-start, or 'started [made-available? #:mutable] ; no #f in `phase-level-to-state`? [attached? #:mutable] ; whether the instance has been attached elsewhere data-box) ; for use by module implementation @@ -417,7 +417,9 @@ (define instance-phase (namespace-0-phase m-ns)) (define run-phase-level (phase- run-phase instance-phase)) (unless (and (or skip-run? - (eq? 'started (small-hash-ref (module-instance-phase-level-to-state mi) run-phase-level #f))) + (let ([v (small-hash-ref (module-instance-phase-level-to-state mi) run-phase-level #f)]) + (or (eq? 'started v) + (eq? 'trying-to-start v)))) (or (not otherwise-available?) (module-instance-made-available? mi))) ;; Something to do... @@ -430,7 +432,14 @@ (when (hash-ref seen mi #f) (error 'require "import cycle detected during module instantiation")) - + + (unless (or skip-run? + (eq? (small-hash-ref (module-instance-phase-level-to-state mi) run-phase-level #f) 'started)) + ;; In case instantiating imported modules does something that triggers + ;; a force of available modules, make sure we don't try to instantiate + ;; while we're in the process of instantiating: + (small-hash-set! (module-instance-phase-level-to-state mi) run-phase-level 'trying-to-start)) + ;; If we haven't shifted required mpis already, do that (unless (module-instance-shifted-requires mi) (set-module-instance-shifted-requires! diff --git a/racket/src/racket/src/startup.inc b/racket/src/racket/src/startup.inc index 069ab2a6a2..b1d3bd0f4a 100644 --- a/racket/src/racket/src/startup.inc +++ b/racket/src/racket/src/startup.inc @@ -14212,12 +14212,13 @@ static const char *startup_source = "(if(if(let-values(((or-part_0) skip-run?_0))" "(if or-part_0" " or-part_0" -"(eq?" -" 'started" +"(let-values(((v_0)" "(small-hash-ref" "(module-instance-phase-level-to-state mi_0)" " run-phase-level_0" -" #f))))" +" #f)))" +"(let-values(((or-part_1)(eq? 'started v_0)))" +"(if or-part_1 or-part_1(eq? 'trying-to-start v_0))))))" "(let-values(((or-part_0)(not otherwise-available?_0)))" "(if or-part_0 or-part_0(module-instance-made-available? mi_0)))" " #f)" @@ -14244,6 +14245,21 @@ static const char *startup_source = " 'require" " \"import cycle detected during module instantiation\"))" "(void))" +"(if(let-values(((or-part_0) skip-run?_0))" +"(if or-part_0" +" or-part_0" +"(eq?" +"(small-hash-ref" +"(module-instance-phase-level-to-state mi_0)" +" run-phase-level_0" +" #f)" +" 'started)))" +"(void)" +"(let-values()" +"(small-hash-set!" +"(module-instance-phase-level-to-state mi_0)" +" run-phase-level_0" +" 'trying-to-start)))" "(if(module-instance-shifted-requires mi_0)" "(void)" "(let-values()"