mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Accept __index__-conforming objects for compile() flags / optimize (#7728)
CPython's compile() (Python/Python-ast.c) accepts any object with __index__ for the flags and optimize arguments. RustPython's CompileArgs typed both fields as OptionalArg<PyIntRef>, so a class with only __index__ raised 'TypeError: Expected type int but X found' during arg binding. bpo-36907's regression test (test_call.test_fastcall_clearing_dict) exercises exactly this: an IntWithDict.__index__ that mutates self.kwargs mid-call. CPython parses both args via __index__ and doesn't crash even when the kwargs dict is cleared between binding and use. Switch flags and optimize to OptionalArg<ArgPrimitiveIndex<i32>>, the same helper already used by range, slice, bytes.__mul__, hex, oct, etc. ArgPrimitiveIndex calls try_index (= __index__ protocol) and converts to the requested primitive in one step, so the three call sites in compile() simplify from .map_or(Ok(d), |v| v.try_to_primitive(vm))? to .map_or(d, |v| v.value). Unmasks test_call.FastCallTests.test_fastcall_clearing_dict.
This commit is contained in:
1
Lib/test/test_call.py
vendored
1
Lib/test/test_call.py
vendored
@@ -585,7 +585,6 @@ class FastCallTests(unittest.TestCase):
|
||||
result = _testcapi.pyobject_vectorcall(func, args, kwnames)
|
||||
self.check_result(result, expected)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; TypeError: Expected type 'int' but 'IntWithDict' found.
|
||||
def test_fastcall_clearing_dict(self):
|
||||
# Test bpo-36907: the point of the test is just checking that this
|
||||
# does not crash.
|
||||
|
||||
@@ -21,8 +21,8 @@ mod builtins {
|
||||
common::hash::PyHash,
|
||||
function::{
|
||||
ArgBytesLike, ArgCallable, ArgIndex, ArgIntoBool, ArgIterable, ArgMapping,
|
||||
ArgStrOrBytesLike, Either, FsPath, FuncArgs, KwArgs, OptionalArg, OptionalOption,
|
||||
PosArgs,
|
||||
ArgPrimitiveIndex, ArgStrOrBytesLike, Either, FsPath, FuncArgs, KwArgs, OptionalArg,
|
||||
OptionalOption, PosArgs,
|
||||
},
|
||||
protocol::{PyIter, PyIterReturn},
|
||||
py_io,
|
||||
@@ -99,12 +99,15 @@ mod builtins {
|
||||
source: PyObjectRef,
|
||||
filename: FsPath,
|
||||
mode: PyUtf8StrRef,
|
||||
// CPython parity: flags / optimize accept any object with __index__,
|
||||
// not just exact int. Matches the behavior of `int(x)` arg conversion
|
||||
// used by Python/Python-ast.c::compile.
|
||||
#[pyarg(any, optional)]
|
||||
flags: OptionalArg<PyIntRef>,
|
||||
flags: OptionalArg<ArgPrimitiveIndex<i32>>,
|
||||
#[pyarg(any, optional)]
|
||||
dont_inherit: OptionalArg<bool>,
|
||||
#[pyarg(any, optional)]
|
||||
optimize: OptionalArg<PyIntRef>,
|
||||
optimize: OptionalArg<ArgPrimitiveIndex<i32>>,
|
||||
#[pyarg(any, optional)]
|
||||
_feature_version: OptionalArg<i32>,
|
||||
}
|
||||
@@ -264,7 +267,7 @@ mod builtins {
|
||||
|
||||
let mode_str = args.mode.as_str();
|
||||
|
||||
let optimize: i32 = args.optimize.map_or(Ok(-1), |v| v.try_to_primitive(vm))?;
|
||||
let optimize: i32 = args.optimize.map_or(-1, |v| v.value);
|
||||
let optimize: u8 = if optimize == -1 {
|
||||
vm.state.config.settings.optimize
|
||||
} else {
|
||||
@@ -277,7 +280,7 @@ mod builtins {
|
||||
.source
|
||||
.fast_isinstance(&_ast::NodeAst::make_static_type())
|
||||
{
|
||||
let flags: i32 = args.flags.map_or(Ok(0), |v| v.try_to_primitive(vm))?;
|
||||
let flags: i32 = args.flags.map_or(0, |v| v.value);
|
||||
let is_ast_only = !(flags & _ast::PY_CF_ONLY_AST).is_zero();
|
||||
|
||||
// func_type mode requires PyCF_ONLY_AST
|
||||
@@ -342,7 +345,7 @@ mod builtins {
|
||||
let source = decode_source_bytes(&source, &args.filename.to_string_lossy(), vm)?;
|
||||
let source = source.as_str();
|
||||
|
||||
let flags = args.flags.map_or(Ok(0), |v| v.try_to_primitive(vm))?;
|
||||
let flags: i32 = args.flags.map_or(0, |v| v.value);
|
||||
|
||||
if !(flags & !_ast::PY_COMPILE_FLAGS_MASK).is_zero() {
|
||||
return Err(vm.new_value_error("compile() unrecognized flags"));
|
||||
|
||||
Reference in New Issue
Block a user