From ae7ff9c4814f193dd2b4e014ceb6803e73adc4d1 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" <69878+youknowone@users.noreply.github.com> Date: Tue, 5 May 2026 16:22:55 +0900 Subject: [PATCH] codegen: module seed CodeInfo emits empty flags (#7782) CPython convention: top-level module / interactive / expression code does not carry CO_NEWLOCALS or CO_OPTIMIZED. The per-scope mapping at enter_scope::CompilerScope::Module already returns empty flags, but Compiler::new seeded the root CodeInfo with CodeFlags::NEWLOCALS, forcing module code into the NEWLOCALS arm of frame.rs:725-731 so locals were allocated as a fresh empty dict instead of being bound to globals (the correct semantics for exec(code, globals)). Restore the seed to empty() so it matches the per-scope mapping and CPython's compiler_enter_scope for module scope. --- crates/codegen/src/compile.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index debec3acd..c3ec99be7 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -505,7 +505,15 @@ impl Compiler { fn new(opts: CompileOpts, source_file: SourceFile, code_name: String) -> Self { let module_code = ir::CodeInfo { - flags: bytecode::CodeFlags::NEWLOCALS, + // CPython convention: top-level module / interactive / + // expression code does not carry CO_NEWLOCALS or CO_OPTIMIZED. + // (See `Python/compile.c compiler_enter_scope` for module + // scope.) This matches the per-scope mapping at + // enter_scope::CompilerScope::Module below, which also returns + // empty flags. frame.rs:725-731 then binds locals to globals + // for module/REPL frames whose `scope.locals` is None — the + // correct semantics for `exec(code, globals)` and module init. + flags: bytecode::CodeFlags::empty(), source_path: source_file.name().to_owned(), private: None, blocks: vec![ir::Block::default()],