Skip to content

Commit 1630c71

Browse files
committed
make_closure
1 parent ac20b00 commit 1630c71

File tree

1 file changed

+94
-105
lines changed

1 file changed

+94
-105
lines changed

compiler/codegen/src/compile.rs

Lines changed: 94 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,24 +1959,13 @@ impl Compiler<'_> {
19591959
);
19601960
}
19611961

1962-
if self.build_closure(&code) {
1963-
func_flags |= bytecode::MakeFunctionFlags::CLOSURE;
1964-
}
1965-
19661962
// Pop the special type params symbol table
19671963
if type_params.is_some() {
19681964
self.pop_symbol_table();
19691965
}
19701966

1971-
self.emit_load_const(ConstantData::Code {
1972-
code: Box::new(code),
1973-
});
1974-
self.emit_load_const(ConstantData::Str {
1975-
value: qualname.into(),
1976-
});
1977-
1978-
// Turn code object into function object:
1979-
emit!(self, Instruction::MakeFunction(func_flags));
1967+
// Create function with closure
1968+
self.make_closure(code, &qualname, func_flags)?;
19801969

19811970
if let Some(value) = doc_str {
19821971
emit!(self, Instruction::Duplicate);
@@ -1993,44 +1982,85 @@ impl Compiler<'_> {
19931982
self.store_name(name)
19941983
}
19951984

1996-
fn build_closure(&mut self, code: &CodeObject) -> bool {
1997-
if code.freevars.is_empty() {
1998-
return false;
1999-
}
2000-
for var in &*code.freevars {
2001-
let table = self.symbol_table_stack.last().unwrap();
2002-
let symbol = unwrap_internal(
2003-
self,
2004-
table
2005-
.lookup(var)
2006-
.ok_or_else(|| InternalError::MissingSymbol(var.to_owned())),
2007-
);
2008-
let parent_code = self.code_stack.last().unwrap();
2009-
let vars = match symbol.scope {
2010-
SymbolScope::Free => &parent_code.metadata.freevars,
2011-
SymbolScope::Cell => &parent_code.metadata.cellvars,
2012-
SymbolScope::TypeParams => &parent_code.metadata.cellvars,
2013-
_ if symbol.flags.contains(SymbolFlags::FREE_CLASS) => {
2014-
&parent_code.metadata.freevars
1985+
/// Implementation of CPython's compiler_make_closure
1986+
/// Loads closure variables if needed and creates a function object
1987+
fn make_closure(
1988+
&mut self,
1989+
code: CodeObject,
1990+
qualname: &str,
1991+
mut flags: bytecode::MakeFunctionFlags,
1992+
) -> CompileResult<()> {
1993+
// Handle free variables (closure)
1994+
if !code.freevars.is_empty() {
1995+
// Build closure tuple by loading free variables
1996+
for var in &*code.freevars {
1997+
let table = self.symbol_table_stack.last().unwrap();
1998+
let symbol = match table.lookup(var) {
1999+
Some(s) => s,
2000+
None => {
2001+
return Err(self.error(CodegenErrorType::SyntaxError(format!(
2002+
"compiler_make_closure: cannot find symbol '{var}'",
2003+
))));
2004+
}
2005+
};
2006+
2007+
let parent_code = self.code_stack.last().unwrap();
2008+
let vars = match symbol.scope {
2009+
SymbolScope::Free => &parent_code.metadata.freevars,
2010+
SymbolScope::Cell => &parent_code.metadata.cellvars,
2011+
SymbolScope::TypeParams => &parent_code.metadata.cellvars,
2012+
_ if symbol.flags.contains(SymbolFlags::FREE_CLASS) => {
2013+
&parent_code.metadata.freevars
2014+
}
2015+
_ => {
2016+
return Err(self.error(CodegenErrorType::SyntaxError(format!(
2017+
"compiler_make_closure: invalid scope for '{var}'",
2018+
))));
2019+
}
2020+
};
2021+
2022+
let idx = match vars.get_index_of(var) {
2023+
Some(i) => i,
2024+
None => {
2025+
return Err(self.error(CodegenErrorType::SyntaxError(format!(
2026+
"compiler_make_closure: cannot find '{var}' in parent vars",
2027+
))));
2028+
}
2029+
};
2030+
2031+
let mut idx = idx;
2032+
if let SymbolScope::Free = symbol.scope {
2033+
idx += parent_code.metadata.cellvars.len();
20152034
}
2016-
x => unreachable!(
2017-
"var {} in a {:?} should be free or cell but it's {:?}",
2018-
var, table.typ, x
2019-
),
2020-
};
2021-
let mut idx = vars.get_index_of(var).unwrap();
2022-
if let SymbolScope::Free = symbol.scope {
2023-
idx += parent_code.metadata.cellvars.len();
2035+
2036+
emit!(self, Instruction::LoadClosure(idx.to_u32()));
20242037
}
2025-
emit!(self, Instruction::LoadClosure(idx.to_u32()))
2038+
2039+
// Build tuple of closure variables
2040+
emit!(
2041+
self,
2042+
Instruction::BuildTuple {
2043+
size: code.freevars.len().to_u32(),
2044+
}
2045+
);
2046+
2047+
flags |= bytecode::MakeFunctionFlags::CLOSURE;
20262048
}
2027-
emit!(
2028-
self,
2029-
Instruction::BuildTuple {
2030-
size: code.freevars.len().to_u32(),
2031-
}
2032-
);
2033-
true
2049+
2050+
// Load code object
2051+
self.emit_load_const(ConstantData::Code {
2052+
code: Box::new(code),
2053+
});
2054+
2055+
// Load qualified name
2056+
self.emit_load_const(ConstantData::Str {
2057+
value: qualname.into(),
2058+
});
2059+
2060+
// Make function with proper flags
2061+
emit!(self, Instruction::MakeFunction(flags));
2062+
2063+
Ok(())
20342064
}
20352065

20362066
// Python/compile.c find_ann
@@ -2230,15 +2260,8 @@ impl Compiler<'_> {
22302260
emit!(self, Instruction::LoadNameAny(dot_type_params));
22312261
func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
22322262

2233-
if self.build_closure(&class_code) {
2234-
func_flags |= bytecode::MakeFunctionFlags::CLOSURE;
2235-
}
2236-
2237-
self.emit_load_const(ConstantData::Code {
2238-
code: Box::new(class_code),
2239-
});
2240-
self.emit_load_const(ConstantData::Str { value: name.into() });
2241-
emit!(self, Instruction::MakeFunction(func_flags));
2263+
// Create class function with closure
2264+
self.make_closure(class_code, name, func_flags)?;
22422265
self.emit_load_const(ConstantData::Str { value: name.into() });
22432266

22442267
// Compile original bases
@@ -2287,34 +2310,19 @@ impl Compiler<'_> {
22872310
let type_params_code = self.exit_scope();
22882311

22892312
// Execute the type params function
2290-
if self.build_closure(&type_params_code) {
2291-
// Should not need closure
2292-
}
2293-
self.emit_load_const(ConstantData::Code {
2294-
code: Box::new(type_params_code),
2295-
});
2296-
self.emit_load_const(ConstantData::Str {
2297-
value: format!("<generic parameters of {name}>").into(),
2298-
});
2299-
emit!(
2300-
self,
2301-
Instruction::MakeFunction(bytecode::MakeFunctionFlags::empty())
2302-
);
2313+
let type_params_name = format!("<generic parameters of {name}>");
2314+
self.make_closure(
2315+
type_params_code,
2316+
&type_params_name,
2317+
bytecode::MakeFunctionFlags::empty(),
2318+
)?;
23032319
emit!(self, Instruction::CallFunctionPositional { nargs: 0 });
23042320
} else {
23052321
// Non-generic class: standard path
23062322
emit!(self, Instruction::LoadBuildClass);
23072323

2308-
let mut func_flags = bytecode::MakeFunctionFlags::empty();
2309-
if self.build_closure(&class_code) {
2310-
func_flags |= bytecode::MakeFunctionFlags::CLOSURE;
2311-
}
2312-
2313-
self.emit_load_const(ConstantData::Code {
2314-
code: Box::new(class_code),
2315-
});
2316-
self.emit_load_const(ConstantData::Str { value: name.into() });
2317-
emit!(self, Instruction::MakeFunction(func_flags));
2324+
// Create class function with closure
2325+
self.make_closure(class_code, name, bytecode::MakeFunctionFlags::empty())?;
23182326
self.emit_load_const(ConstantData::Str { value: name.into() });
23192327

23202328
let call = if let Some(arguments) = arguments {
@@ -4026,7 +4034,7 @@ impl Compiler<'_> {
40264034
let prev_ctx = self.ctx;
40274035

40284036
let name = "<lambda>".to_owned();
4029-
let mut func_flags = self
4037+
let func_flags = self
40304038
.enter_function(&name, parameters.as_deref().unwrap_or(&Default::default()))?;
40314039

40324040
// Set qualname for lambda
@@ -4046,15 +4054,9 @@ impl Compiler<'_> {
40464054
self.compile_expression(body)?;
40474055
self.emit_return_value();
40484056
let code = self.exit_scope();
4049-
if self.build_closure(&code) {
4050-
func_flags |= bytecode::MakeFunctionFlags::CLOSURE;
4051-
}
4052-
self.emit_load_const(ConstantData::Code {
4053-
code: Box::new(code),
4054-
});
4055-
self.emit_load_const(ConstantData::Str { value: name.into() });
4056-
// Turn code object into function object:
4057-
emit!(self, Instruction::MakeFunction(func_flags));
4057+
4058+
// Create lambda function with closure
4059+
self.make_closure(code, &name, func_flags)?;
40584060

40594061
self.ctx = prev_ctx;
40604062
}
@@ -4598,21 +4600,8 @@ impl Compiler<'_> {
45984600

45994601
self.ctx = prev_ctx;
46004602

4601-
let mut func_flags = bytecode::MakeFunctionFlags::empty();
4602-
if self.build_closure(&code) {
4603-
func_flags |= bytecode::MakeFunctionFlags::CLOSURE;
4604-
}
4605-
4606-
// List comprehension code:
4607-
self.emit_load_const(ConstantData::Code {
4608-
code: Box::new(code),
4609-
});
4610-
4611-
// List comprehension function name:
4612-
self.emit_load_const(ConstantData::Str { value: name.into() });
4613-
4614-
// Turn code object into function object:
4615-
emit!(self, Instruction::MakeFunction(func_flags));
4603+
// Create comprehension function with closure
4604+
self.make_closure(code, name, bytecode::MakeFunctionFlags::empty())?;
46164605

46174606
// Evaluate iterated item:
46184607
self.compile_expression(&generators[0].iter)?;

0 commit comments

Comments
 (0)