Summary
Exported syntaxes are not fully hygienic
Metadata
- Id: 80700a387c732f1060e3ccdec6663c79548c2dea
- Trac id: 1832
- Type: defect
- Reporter: joe
- Owner:
- Cc:
- Status: new
- Component: compiler
- Estimated difficulty: hard
- Resolution:
- Priority: major
- Milestone: someday
- Version: 5.3.0
- Changetime: 2025-11-03 06:45:56 UTC
- Created: 2024-02-22 21:44:24 UTC
- Keywords: syntax hygiene modules
Attachments
- 80700a387c732f1060e3ccdec6663c79548c2dea/attachments/mwe-ok.scm
- 80700a387c732f1060e3ccdec6663c79548c2dea/attachments/define-alist.scm
- 80700a387c732f1060e3ccdec6663c79548c2dea/attachments/mwe-ko-one.scm
- 80700a387c732f1060e3ccdec6663c79548c2dea/attachments/mwe-ko-common.scm
- 80700a387c732f1060e3ccdec6663c79548c2dea/attachments/mwe-ko-run.scm
- 80700a387c732f1060e3ccdec6663c79548c2dea/attachments/mwe-ko-two.scm
Description
Modules exporting syntaxes generated by syntaxes are not fully hygienic as the serialization into module-name.import.scm uses strip-syntax on module's sexports.
Minimal (Working) Example
Attached as follows:
mwe-ok.scm - single file where the macros show expected behavior
mwe-ko-common.scm - module with the macro generating macros mwe-ko-one.scm - first macro generated by the macro from common module mwe-ko-two.scm - second macro generated by the macro from module "one" mw-ko-run.scm - should behave like mwe-ok.scm, shows binding collisions
How to run
Reference (working) module:
csi -q -b mwe.ok.scm
Multiple modules with problems:
csc -P -J mwe-ko-common.scm csc -P -J mwe-ko-one.scm csc -P -J mwe-ko-two.scm csi -q -b mwe-ko-run.scm
Changes and comments
[2024-02-22 21:44:47 UTC] joe attached mwe-ok.scm (description=Working example.)
[2024-02-22 21:45:21 UTC] joe attached mwe-ko-common.scm (description=Non-working example, module with base syntax.)
[2024-02-22 21:45:47 UTC] joe attached mwe-ko-one.scm (description=Non-working example, module with first generated syntax.)
[2024-02-22 21:46:04 UTC] joe attached mwe-ko-two.scm (description=Non-working example, module with second generated syntax.)
[2024-02-22 21:46:23 UTC] joe attached mwe-ko-run.scm (description=Non-working example, main module to run.)
[2024-04-03 09:53:14 UTC] sjamaan wrote:
The problem is clearly strip-syntax - that should not be used. It's used because we don't want to emit gensymed names, as those won't be resolvable when loading the import library (that's a different compilation pass, which doesn't have the same aliases database).
A potential solution might involve something akin to `canonicalize-expression` on the syntax form, leaving any unresolved symbols as is (so keeping the gensymed aliases in place). There'd still be a risk of capture since those names won't be gensymed anymore, but it'd be less likely since they'd still be obfuscated.
I think if this works, we won't need the eval for the `module-import-forms` anymore either, as everything will be fully resolved.
Finally, I think we'd do well to simplify this example a bit. The code is quite hard to follow.
[2024-04-03 10:16:14 UTC] sjamaan wrote:
Replying to sjamaan: > A potential solution might involve something akin to `canonicalize-expression` on the syntax form
Hm, after thinking about this some more, I believe this would require teaching the compiler about `syntax-rules` and how to canonicalize its "templates".
Somehow that "feels" Very Wrong - we don't want to have to special case something like this. Users should be able to add their own expanders without requiring a special case for it.
[2025-11-03 06:44:13 UTC] sjamaan attached define-alist.scm (description=define-alist-macro doesn't work the same when compiled and interpreted)
[2025-11-03 06:45:56 UTC] sjamaan wrote:
Added a new example which breaks similarly. The code is a bit simpler than the initial example, so it's worth adding.
If you put the code in a module and compile the module with `-s`, then import it in the interpreter, the resulting expansion is different.