Skip to content

Commit 52d4632

Browse files
authored
make_closure (#5955)
1 parent e21ec55 commit 52d4632

File tree

1 file changed

+95
-105
lines changed

1 file changed

+95
-105
lines changed

compiler/codegen/src/compile.rs

Lines changed: 95 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,86 @@ 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(
1985+
/// Loads closure variables if needed and creates a function object
1986+
// = compiler_make_closure
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 idx = if let SymbolScope::Free = symbol.scope {
2032+
idx + parent_code.metadata.cellvars.len()
2033+
} else {
2034+
idx
2035+
};
2036+
2037+
emit!(self, Instruction::LoadClosure(idx.to_u32()));
2038+
}
2039+
2040+
// Build tuple of closure variables
2041+
emit!(
20032042
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
2043+
Instruction::BuildTuple {
2044+
size: code.freevars.len().to_u32(),
20152045
}
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();
2024-
}
2025-
emit!(self, Instruction::LoadClosure(idx.to_u32()))
2046+
);
2047+
2048+
flags |= bytecode::MakeFunctionFlags::CLOSURE;
20262049
}
2027-
emit!(
2028-
self,
2029-
Instruction::BuildTuple {
2030-
size: code.freevars.len().to_u32(),
2031-
}
2032-
);
2033-
true
2050+
2051+
// Load code object
2052+
self.emit_load_const(ConstantData::Code {
2053+
code: Box::new(code),
2054+
});
2055+
2056+
// Load qualified name
2057+
self.emit_load_const(ConstantData::Str {
2058+
value: qualname.into(),
2059+
});
2060+
2061+
// Make function with proper flags
2062+
emit!(self, Instruction::MakeFunction(flags));
2063+
2064+
Ok(())
20342065
}
20352066

20362067
// Python/compile.c find_ann
@@ -2230,15 +2261,8 @@ impl Compiler<'_> {
22302261
emit!(self, Instruction::LoadNameAny(dot_type_params));
22312262
func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
22322263

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

22442268
// Compile original bases
@@ -2287,34 +2311,19 @@ impl Compiler<'_> {
22872311
let type_params_code = self.exit_scope();
22882312

22892313
// 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-
);
2314+
let type_params_name = format!("<generic parameters of {name}>");
2315+
self.make_closure(
2316+
type_params_code,
2317+
&type_params_name,
2318+
bytecode::MakeFunctionFlags::empty(),
2319+
)?;
23032320
emit!(self, Instruction::CallFunctionPositional { nargs: 0 });
23042321
} else {
23052322
// Non-generic class: standard path
23062323
emit!(self, Instruction::LoadBuildClass);
23072324

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

23202329
let call = if let Some(arguments) = arguments {
@@ -4026,7 +4035,7 @@ impl Compiler<'_> {
40264035
let prev_ctx = self.ctx;
40274036

40284037
let name = "<lambda>".to_owned();
4029-
let mut func_flags = self
4038+
let func_flags = self
40304039
.enter_function(&name, parameters.as_deref().unwrap_or(&Default::default()))?;
40314040

40324041
// Set qualname for lambda
@@ -4046,15 +4055,9 @@ impl Compiler<'_> {
40464055
self.compile_expression(body)?;
40474056
self.emit_return_value();
40484057
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));
4058+
4059+
// Create lambda function with closure
4060+
self.make_closure(code, &name, func_flags)?;
40584061

40594062
self.ctx = prev_ctx;
40604063
}
@@ -4598,21 +4601,8 @@ impl Compiler<'_> {
45984601

45994602
self.ctx = prev_ctx;
46004603

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

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

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy