Skip to content

Commit acbea17

Browse files
committed
make_closure
1 parent e75aebb commit acbea17

File tree

1 file changed

+97
-105
lines changed

1 file changed

+97
-105
lines changed

compiler/codegen/src/compile.rs

Lines changed: 97 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,88 @@ 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 '{}'",
2003+
var
2004+
))));
2005+
}
2006+
};
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
2015+
}
2016+
_ => {
2017+
return Err(self.error(CodegenErrorType::SyntaxError(format!(
2018+
"compiler_make_closure: invalid scope for '{}'",
2019+
var
2020+
))));
2021+
}
2022+
};
2023+
2024+
let idx = match vars.get_index_of(var) {
2025+
Some(i) => i,
2026+
None => {
2027+
return Err(self.error(CodegenErrorType::SyntaxError(format!(
2028+
"compiler_make_closure: cannot find '{}' in parent vars",
2029+
var
2030+
))));
2031+
}
2032+
};
2033+
2034+
let mut idx = idx;
2035+
if let SymbolScope::Free = symbol.scope {
2036+
idx += parent_code.metadata.cellvars.len();
20152037
}
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();
2038+
2039+
emit!(self, Instruction::LoadClosure(idx.to_u32()));
20242040
}
2025-
emit!(self, Instruction::LoadClosure(idx.to_u32()))
2041+
2042+
// Build tuple of closure variables
2043+
emit!(
2044+
self,
2045+
Instruction::BuildTuple {
2046+
size: code.freevars.len().to_u32(),
2047+
}
2048+
);
2049+
2050+
flags |= bytecode::MakeFunctionFlags::CLOSURE;
20262051
}
2027-
emit!(
2028-
self,
2029-
Instruction::BuildTuple {
2030-
size: code.freevars.len().to_u32(),
2031-
}
2032-
);
2033-
true
2052+
2053+
// Load code object
2054+
self.emit_load_const(ConstantData::Code {
2055+
code: Box::new(code),
2056+
});
2057+
2058+
// Load qualified name
2059+
self.emit_load_const(ConstantData::Str {
2060+
value: qualname.into(),
2061+
});
2062+
2063+
// Make function with proper flags
2064+
emit!(self, Instruction::MakeFunction(flags));
2065+
2066+
Ok(())
20342067
}
20352068

20362069
// Python/compile.c find_ann
@@ -2230,15 +2263,8 @@ impl Compiler<'_> {
22302263
emit!(self, Instruction::LoadNameAny(dot_type_params));
22312264
func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
22322265

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));
2266+
// Create class function with closure
2267+
self.make_closure(class_code, name, func_flags)?;
22422268
self.emit_load_const(ConstantData::Str { value: name.into() });
22432269

22442270
// Compile original bases
@@ -2287,34 +2313,19 @@ impl Compiler<'_> {
22872313
let type_params_code = self.exit_scope();
22882314

22892315
// 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-
);
2316+
let type_params_name = format!("<generic parameters of {name}>");
2317+
self.make_closure(
2318+
type_params_code,
2319+
&type_params_name,
2320+
bytecode::MakeFunctionFlags::empty(),
2321+
)?;
23032322
emit!(self, Instruction::CallFunctionPositional { nargs: 0 });
23042323
} else {
23052324
// Non-generic class: standard path
23062325
emit!(self, Instruction::LoadBuildClass);
23072326

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));
2327+
// Create class function with closure
2328+
self.make_closure(class_code, name, bytecode::MakeFunctionFlags::empty())?;
23182329
self.emit_load_const(ConstantData::Str { value: name.into() });
23192330

23202331
let call = if let Some(arguments) = arguments {
@@ -4026,7 +4037,7 @@ impl Compiler<'_> {
40264037
let prev_ctx = self.ctx;
40274038

40284039
let name = "<lambda>".to_owned();
4029-
let mut func_flags = self
4040+
let func_flags = self
40304041
.enter_function(&name, parameters.as_deref().unwrap_or(&Default::default()))?;
40314042

40324043
// Set qualname for lambda
@@ -4046,15 +4057,9 @@ impl Compiler<'_> {
40464057
self.compile_expression(body)?;
40474058
self.emit_return_value();
40484059
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));
4060+
4061+
// Create lambda function with closure
4062+
self.make_closure(code, &name, func_flags)?;
40584063

40594064
self.ctx = prev_ctx;
40604065
}
@@ -4598,21 +4603,8 @@ impl Compiler<'_> {
45984603

45994604
self.ctx = prev_ctx;
46004605

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));
4606+
// Create comprehension function with closure
4607+
self.make_closure(code, &name, bytecode::MakeFunctionFlags::empty())?;
46164608

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

0 commit comments

Comments
 (0)