Skip to content

Commit 270df4b

Browse files
committed
ZeroArg
1 parent f688879 commit 270df4b

File tree

2 files changed

+47
-18
lines changed

2 files changed

+47
-18
lines changed

crates/codegen/src/compile.rs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ enum SuperCallType<'a> {
8484
self_arg: &'a Expr,
8585
},
8686
/// super() - implicit 0-argument form (uses __class__ cell)
87-
/// TODO: Enable after fixing __class__ cell handling in nested classes
88-
#[allow(dead_code)]
8987
ZeroArg,
9088
}
9189

@@ -715,14 +713,20 @@ impl Compiler {
715713
return None;
716714
}
717715

718-
// 6. "super" must be GlobalImplicit (not redefined locally)
716+
// 6. "super" must be GlobalImplicit (not redefined locally or at module level)
719717
let table = self.current_symbol_table();
720-
if let Some(symbol) = table.lookup("super") {
721-
if symbol.scope != SymbolScope::GlobalImplicit {
722-
return None;
723-
}
724-
} else {
725-
// super not found in symbol table - assume it's a global builtin
718+
if let Some(symbol) = table.lookup("super")
719+
&& symbol.scope != SymbolScope::GlobalImplicit
720+
{
721+
return None;
722+
}
723+
// Also check top-level scope to detect module-level shadowing.
724+
// Only block if super is actually *bound* at module level (not just used).
725+
if let Some(top_table) = self.symbol_table_stack.first()
726+
&& let Some(sym) = top_table.lookup("super")
727+
&& sym.scope != SymbolScope::GlobalImplicit
728+
{
729+
return None;
726730
}
727731

728732
// 7. Check argument pattern
@@ -743,10 +747,26 @@ impl Compiler {
743747
}
744748
0 => {
745749
// 0-arg: super() - need __class__ cell and first parameter
746-
// TODO: 0-arg super() optimization is disabled due to __class__ cell issues
747-
// The __class__ cell handling in nested class definitions needs more work.
748-
// For now, fall back to regular super() call.
749-
None
750+
// Enclosing function should have at least one positional argument
751+
let info = self.code_stack.last()?;
752+
if info.metadata.argcount == 0 && info.metadata.posonlyargcount == 0 {
753+
return None;
754+
}
755+
756+
// Check if __class__ is available as a cell/free variable
757+
// The scope must be Free (from enclosing class) or have FREE_CLASS flag
758+
if let Some(symbol) = table.lookup("__class__") {
759+
if symbol.scope != SymbolScope::Free
760+
&& !symbol.flags.contains(SymbolFlags::FREE_CLASS)
761+
{
762+
return None;
763+
}
764+
} else {
765+
// __class__ not in symbol table, optimization not possible
766+
return None;
767+
}
768+
769+
Some(SuperCallType::ZeroArg)
750770
}
751771
_ => None, // 1 or 3+ args - not optimizable
752772
}
@@ -3494,12 +3514,14 @@ impl Compiler {
34943514
/// Determines if a variable should be CELL or FREE type
34953515
// = get_ref_type
34963516
fn get_ref_type(&self, name: &str) -> Result<SymbolScope, CodegenErrorType> {
3517+
let table = self.symbol_table_stack.last().unwrap();
3518+
34973519
// Special handling for __class__ and __classdict__ in class scope
3498-
if self.ctx.in_class && (name == "__class__" || name == "__classdict__") {
3520+
// This should only apply when we're actually IN a class body,
3521+
// not when we're in a method nested inside a class.
3522+
if table.typ == CompilerScope::Class && (name == "__class__" || name == "__classdict__") {
34993523
return Ok(SymbolScope::Cell);
35003524
}
3501-
3502-
let table = self.symbol_table_stack.last().unwrap();
35033525
match table.lookup(name) {
35043526
Some(symbol) => match symbol.scope {
35053527
SymbolScope::Cell => Ok(SymbolScope::Cell),

crates/compiler-core/src/bytecode/instruction.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
Arg, BinaryOperator, BorrowedConstant, BuildSliceArgCount, ComparisonOperator, Constant,
77
ConvertValueOparg, InstrDisplayContext, IntrinsicFunction1, IntrinsicFunction2, Invert,
88
Label, MakeFunctionFlags, NameIdx, OpArg, RaiseKind, UnpackExArgs, decode_load_attr_arg,
9+
decode_load_super_attr_arg,
910
},
1011
marshal::MarshalError,
1112
};
@@ -244,7 +245,10 @@ pub enum Instruction {
244245
arg: Arg<u32>,
245246
} = 149,
246247
// ===== LOAD_SUPER_* Pseudo Opcodes (136-138) =====
247-
// These are converted to LoadSuperAttr during bytecode finalization
248+
// These are converted to LoadSuperAttr during bytecode finalization.
249+
// "Zero" variants are for 0-arg super() calls (has_class=false).
250+
// Non-"Zero" variants are for 2-arg super(cls, self) calls (has_class=true).
251+
/// 2-arg super(cls, self).method() - has_class=true, load_method=true
248252
LoadSuperMethod {
249253
idx: Arg<NameIdx>,
250254
} = 136, // CPython uses pseudo-op 260
@@ -349,6 +353,10 @@ impl TryFrom<u8> for Instruction {
349353
u8::from(Self::JumpIfNotExcMatch(Arg::marker())),
350354
u8::from(Self::SetExcInfo),
351355
u8::from(Self::Subscript),
356+
// LOAD_SUPER_* pseudo opcodes (136-138)
357+
u8::from(Self::LoadSuperMethod { idx: Arg::marker() }),
358+
u8::from(Self::LoadZeroSuperAttr { idx: Arg::marker() }),
359+
u8::from(Self::LoadZeroSuperMethod { idx: Arg::marker() }),
352360
];
353361

354362
// Pseudo opcodes (252-255)
@@ -632,7 +640,6 @@ impl Instruction {
632640
Self::LoadFromDictOrGlobals(_) => 0,
633641
Self::SetUpdate { .. } => 0,
634642
Self::MakeCell(_) => 0,
635-
Self::LoadSuperAttr { .. } => 0,
636643
Self::StoreFastStoreFast { .. } => 0,
637644
Self::PopJumpIfNone { .. } => 0,
638645
Self::PopJumpIfNotNone { .. } => 0,

0 commit comments

Comments
 (0)