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) => { Some(StoreLoadKind::Deref) => {
self.mut_cur_block_codeobj().freevars.push(name.clone()); 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()で行われる // cellvarsのpushはrec_search()で行われる
Name::deref(self.cur_block_codeobj().freevars.len() - 1) Name::deref(self.cur_block_codeobj().freevars.len() - 1)
} }
}
None => { None => {
// new variable // new variable
if current_is_toplevel { if current_is_toplevel {
@ -2473,6 +2478,7 @@ impl CodeGenerator {
} }
let freevars_len = self.cur_block_codeobj().freevars.len(); let freevars_len = self.cur_block_codeobj().freevars.len();
if freevars_len > 0 { if freevars_len > 0 {
self.mut_cur_block_codeobj().flags += CodeObjFlags::Nested as u32;
self.edit_code(idx_copy_free_vars + 1, freevars_len); self.edit_code(idx_copy_free_vars + 1, freevars_len);
} else if self.py_version.minor >= Some(11) { } else if self.py_version.minor >= Some(11) {
self.edit_code(idx_copy_free_vars, CommonOpcode::NOP as usize); 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 std::path::Path;
use erg_common::impl_display_from_debug; use erg_common::impl_display_from_debug;
#[allow(unused_imports)]
use erg_common::log;
use erg_common::opcode::CommonOpcode; use erg_common::opcode::CommonOpcode;
use erg_common::opcode308::Opcode308; use erg_common::opcode308::Opcode308;
use erg_common::opcode310::Opcode310; use erg_common::opcode310::Opcode310;
@ -32,12 +34,13 @@ pub fn consts_into_bytes(consts: Vec<ValueObj>, python_ver: PythonVersion) -> Ve
tuple tuple
} }
/// Kind can be multiple (e.g. Local + Cell = 0x60)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)] #[repr(u8)]
pub enum LocalKind { pub enum FastKind {
Local = 0x20, Local = 0x20,
Free = 0x40, Cell = 0x40,
Cell = 0x80, Free = 0x80,
} }
/// Bit masks for CodeObj.flags /// Bit masks for CodeObj.flags
@ -192,7 +195,7 @@ impl Default for CodeObj {
kwonlyargcount: 0, kwonlyargcount: 0,
nlocals: 0, nlocals: 0,
stacksize: 2, // Seems to be the default in CPython, but not sure why 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(), code: Vec::new(),
consts: Vec::new(), consts: Vec::new(),
names: Vec::new(), names: Vec::new(),
@ -223,7 +226,7 @@ impl CodeObj {
kwonlyargcount: 0, kwonlyargcount: 0,
nlocals: params.len() as u32, nlocals: params.len() as u32,
stacksize: 2, // Seems to be the default in CPython, but not sure why 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), code: Vec::with_capacity(8),
consts: Vec::with_capacity(4), consts: Vec::with_capacity(4),
names: Vec::with_capacity(3), names: Vec::with_capacity(3),
@ -350,10 +353,14 @@ impl CodeObj {
python_ver: PythonVersion, python_ver: PythonVersion,
) { ) {
if python_ver.minor >= Some(11) { if python_ver.minor >= Some(11) {
let varnames = varnames
.into_iter()
.filter(|n| !freevars.contains(n) && !cellvars.contains(n))
.collect::<Vec<_>>();
let localspluskinds = [ let localspluskinds = [
vec![LocalKind::Local as u8; varnames.len()], vec![FastKind::Local as u8; varnames.len()],
vec![LocalKind::Free as u8; freevars.len()], vec![FastKind::Free as u8; freevars.len()],
vec![LocalKind::Cell as u8; cellvars.len()], vec![FastKind::Cell as u8 + FastKind::Local as u8; cellvars.len()],
] ]
.concat(); .concat();
let localsplusnames = [varnames, freevars, cellvars].concat(); let localsplusnames = [varnames, freevars, cellvars].concat();
@ -577,7 +584,7 @@ impl CodeObj {
write!( write!(
instrs, instrs,
"{arg} ({})", "{arg} ({})",
self.freevars.get(*arg as usize).unwrap() self.varnames.get(*arg as usize).unwrap()
) )
.unwrap(); .unwrap();
} }