fix a bug with closures

This commit is contained in:
Shunsuke Shibayama 2022-11-04 21:42:37 +09:00
parent a28ca96d80
commit f15305c287
2 changed files with 25 additions and 12 deletions

View file

@ -480,10 +480,15 @@ impl CodeGenerator {
}
Some(StoreLoadKind::Deref) => {
self.mut_cur_block_codeobj().freevars.push(name.clone());
// TODO: in 3.11 freevars are unified with varnames
if self.py_version.minor >= Some(11) {
// in 3.11 freevars are unified with varnames
self.mut_cur_block_codeobj().varnames.push(name);
Name::deref(self.cur_block_codeobj().varnames.len() - 1)
} else {
// cellvarsのpushはrec_search()で行われる
Name::deref(self.cur_block_codeobj().freevars.len() - 1)
}
}
None => {
// new variable
if current_is_toplevel {
@ -2473,6 +2478,7 @@ impl CodeGenerator {
}
let freevars_len = self.cur_block_codeobj().freevars.len();
if freevars_len > 0 {
self.mut_cur_block_codeobj().flags += CodeObjFlags::Nested as u32;
self.edit_code(idx_copy_free_vars + 1, freevars_len);
} else if self.py_version.minor >= Some(11) {
self.edit_code(idx_copy_free_vars, CommonOpcode::NOP as usize);

View file

@ -5,6 +5,8 @@ use std::io::{BufReader, Read, Write as _};
use std::path::Path;
use erg_common::impl_display_from_debug;
#[allow(unused_imports)]
use erg_common::log;
use erg_common::opcode::CommonOpcode;
use erg_common::opcode308::Opcode308;
use erg_common::opcode310::Opcode310;
@ -32,12 +34,13 @@ pub fn consts_into_bytes(consts: Vec<ValueObj>, python_ver: PythonVersion) -> Ve
tuple
}
/// Kind can be multiple (e.g. Local + Cell = 0x60)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum LocalKind {
pub enum FastKind {
Local = 0x20,
Free = 0x40,
Cell = 0x80,
Cell = 0x40,
Free = 0x80,
}
/// Bit masks for CodeObj.flags
@ -192,7 +195,7 @@ impl Default for CodeObj {
kwonlyargcount: 0,
nlocals: 0,
stacksize: 2, // Seems to be the default in CPython, but not sure why
flags: CodeObjFlags::NoFree as u32,
flags: 0, //CodeObjFlags::NoFree as u32,
code: Vec::new(),
consts: Vec::new(),
names: Vec::new(),
@ -223,7 +226,7 @@ impl CodeObj {
kwonlyargcount: 0,
nlocals: params.len() as u32,
stacksize: 2, // Seems to be the default in CPython, but not sure why
flags: CodeObjFlags::NoFree as u32,
flags: 0, // CodeObjFlags::NoFree as u32,
code: Vec::with_capacity(8),
consts: Vec::with_capacity(4),
names: Vec::with_capacity(3),
@ -350,10 +353,14 @@ impl CodeObj {
python_ver: PythonVersion,
) {
if python_ver.minor >= Some(11) {
let varnames = varnames
.into_iter()
.filter(|n| !freevars.contains(n) && !cellvars.contains(n))
.collect::<Vec<_>>();
let localspluskinds = [
vec![LocalKind::Local as u8; varnames.len()],
vec![LocalKind::Free as u8; freevars.len()],
vec![LocalKind::Cell as u8; cellvars.len()],
vec![FastKind::Local as u8; varnames.len()],
vec![FastKind::Free as u8; freevars.len()],
vec![FastKind::Cell as u8 + FastKind::Local as u8; cellvars.len()],
]
.concat();
let localsplusnames = [varnames, freevars, cellvars].concat();
@ -577,7 +584,7 @@ impl CodeObj {
write!(
instrs,
"{arg} ({})",
self.freevars.get(*arg as usize).unwrap()
self.varnames.get(*arg as usize).unwrap()
)
.unwrap();
}