Skip to content

Commit e9a57d1

Browse files
correct builtins type under function (#6745)
* correct buitins type * Auto-format: ruff format --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 380fa39 commit e9a57d1

File tree

2 files changed

+27
-10
lines changed

2 files changed

+27
-10
lines changed

crates/vm/src/builtins/function.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
mod jit;
33

44
use super::{
5-
PyAsyncGen, PyCode, PyCoroutine, PyDictRef, PyGenerator, PyStr, PyStrRef, PyTuple, PyTupleRef,
6-
PyType,
5+
PyAsyncGen, PyCode, PyCoroutine, PyDictRef, PyGenerator, PyModule, PyStr, PyStrRef, PyTuple,
6+
PyTupleRef, PyType,
77
};
88
#[cfg(feature = "jit")]
99
use crate::common::lock::OnceCell;
@@ -67,9 +67,15 @@ impl PyFunction {
6767
if let Some(frame) = vm.current_frame() {
6868
frame.builtins.clone().into()
6969
} else {
70-
vm.builtins.clone().into()
70+
vm.builtins.dict().into()
7171
}
7272
});
73+
// If builtins is a module, use its __dict__ instead
74+
let builtins = if let Some(module) = builtins.downcast_ref::<PyModule>() {
75+
module.dict().into()
76+
} else {
77+
builtins
78+
};
7379

7480
let qualname = vm.ctx.new_str(code.qualname.as_str());
7581
let func = Self {
@@ -679,19 +685,19 @@ pub struct PyFunctionNewArgs {
679685
#[pyarg(any, optional)]
680686
name: OptionalArg<PyStrRef>,
681687
#[pyarg(any, optional)]
682-
defaults: OptionalArg<PyTupleRef>,
688+
argdefs: Option<PyTupleRef>,
683689
#[pyarg(any, optional)]
684-
closure: OptionalArg<PyTupleRef>,
690+
closure: Option<PyTupleRef>,
685691
#[pyarg(any, optional)]
686-
kwdefaults: OptionalArg<PyDictRef>,
692+
kwdefaults: Option<PyDictRef>,
687693
}
688694

689695
impl Constructor for PyFunction {
690696
type Args = PyFunctionNewArgs;
691697

692698
fn py_new(_cls: &Py<PyType>, args: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
693699
// Handle closure - must be a tuple of cells
694-
let closure = if let Some(closure_tuple) = args.closure.into_option() {
700+
let closure = if let Some(closure_tuple) = args.closure {
695701
// Check that closure length matches code's free variables
696702
if closure_tuple.len() != args.code.freevars.len() {
697703
return Err(vm.new_value_error(format!(
@@ -722,10 +728,10 @@ impl Constructor for PyFunction {
722728
if let Some(closure_tuple) = closure {
723729
func.closure = Some(closure_tuple);
724730
}
725-
if let Some(defaults) = args.defaults.into_option() {
726-
func.defaults_and_kwdefaults.lock().0 = Some(defaults);
731+
if let Some(argdefs) = args.argdefs {
732+
func.defaults_and_kwdefaults.lock().0 = Some(argdefs);
727733
}
728-
if let Some(kwdefaults) = args.kwdefaults.into_option() {
734+
if let Some(kwdefaults) = args.kwdefaults {
729735
func.defaults_and_kwdefaults.lock().1 = Some(kwdefaults);
730736
}
731737

extra_tests/snippets/builtins_module.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@
2222
exec("", namespace)
2323
assert namespace["__builtins__"] == __builtins__.__dict__
2424

25+
26+
# function.__builtins__ should be a dict, not a module
27+
# See: https://docs.python.org/3/reference/datamodel.html
28+
def test_func():
29+
pass
30+
31+
32+
assert isinstance(test_func.__builtins__, dict), (
33+
f"function.__builtins__ should be dict, got {type(test_func.__builtins__)}"
34+
)
35+
2536
# with assert_raises(NameError):
2637
# exec('print(__builtins__)', {'__builtins__': {}})
2738

0 commit comments

Comments
 (0)