@@ -8,7 +8,7 @@ use super::{
88#[ cfg( feature = "jit" ) ]
99use crate :: common:: lock:: OnceCell ;
1010use crate :: common:: lock:: PyMutex ;
11- use crate :: convert:: ToPyObject ;
11+ use crate :: convert:: { ToPyObject , TryFromObject } ;
1212use crate :: function:: ArgMapping ;
1313use crate :: object:: { Traverse , TraverseFn } ;
1414use crate :: {
@@ -31,6 +31,7 @@ use rustpython_jit::CompiledCode;
3131pub struct PyFunction {
3232 code : PyRef < PyCode > ,
3333 globals : PyDictRef ,
34+ builtins : PyObjectRef ,
3435 closure : Option < PyTupleTyped < PyCellRef > > ,
3536 defaults_and_kwdefaults : PyMutex < ( Option < PyTupleRef > , Option < PyDictRef > ) > ,
3637 name : PyMutex < PyStrRef > ,
@@ -53,6 +54,7 @@ unsafe impl Traverse for PyFunction {
5354
5455impl PyFunction {
5556 #[ allow( clippy:: too_many_arguments) ]
57+ #[ inline]
5658 pub ( crate ) fn new (
5759 code : PyRef < PyCode > ,
5860 globals : PyDictRef ,
@@ -62,24 +64,42 @@ impl PyFunction {
6264 qualname : PyStrRef ,
6365 type_params : PyTupleRef ,
6466 annotations : PyDictRef ,
65- module : PyObjectRef ,
6667 doc : PyObjectRef ,
67- ) -> Self {
68+ vm : & VirtualMachine ,
69+ ) -> PyResult < Self > {
6870 let name = PyMutex :: new ( code. obj_name . to_owned ( ) ) ;
69- PyFunction {
71+ let module = vm. unwrap_or_none ( globals. get_item_opt ( identifier ! ( vm, __name__) , vm) ?) ;
72+ let builtins = globals. get_item ( "__builtins__" , vm) . unwrap_or_else ( |_| {
73+ // If not in globals, inherit from current execution context
74+ if let Some ( frame) = vm. current_frame ( ) {
75+ frame. builtins . clone ( ) . into ( )
76+ } else {
77+ vm. builtins . clone ( ) . into ( )
78+ }
79+ } ) ;
80+
81+ let func = PyFunction {
7082 code,
7183 globals,
84+ builtins,
7285 closure,
7386 defaults_and_kwdefaults : PyMutex :: new ( ( defaults, kw_only_defaults) ) ,
7487 name,
7588 qualname : PyMutex :: new ( qualname) ,
7689 type_params : PyMutex :: new ( type_params) ,
77- #[ cfg( feature = "jit" ) ]
78- jitted_code : OnceCell :: new ( ) ,
7990 annotations : PyMutex :: new ( annotations) ,
8091 module : PyMutex :: new ( module) ,
8192 doc : PyMutex :: new ( doc) ,
82- }
93+ #[ cfg( feature = "jit" ) ]
94+ jitted_code : OnceCell :: new ( ) ,
95+ } ;
96+
97+ // let name = qualname.as_str().split('.').next_back().unwrap();
98+ // func.set_attr(identifier!(vm, __name__), vm.new_pyobj(name), vm)?;
99+ // func.set_attr(identifier!(vm, __qualname__), qualname, vm)?;
100+ // func.set_attr(identifier!(vm, __doc__), doc, vm)?;
101+
102+ Ok ( func)
83103 }
84104
85105 fn fill_locals_from_args (
@@ -362,7 +382,7 @@ impl PyPayload for PyFunction {
362382}
363383
364384#[ pyclass(
365- with( GetDescriptor , Callable , Representable ) ,
385+ with( GetDescriptor , Callable , Representable , Constructor ) ,
366386 flags( HAS_DICT , METHOD_DESCRIPTOR )
367387) ]
368388impl PyFunction {
@@ -409,12 +429,7 @@ impl PyFunction {
409429 #[ pymember( magic) ]
410430 fn builtins ( vm : & VirtualMachine , zelf : PyObjectRef ) -> PyResult {
411431 let zelf = Self :: _as_pyref ( & zelf, vm) ?;
412- // Get __builtins__ from the function's globals dict
413- let builtins = zelf
414- . globals
415- . get_item ( "__builtins__" , vm)
416- . unwrap_or_else ( |_| vm. builtins . clone ( ) . into ( ) ) ;
417- Ok ( builtins)
432+ Ok ( zelf. builtins . clone ( ) )
418433 }
419434
420435 #[ pygetset( magic) ]
@@ -566,6 +581,81 @@ impl Representable for PyFunction {
566581 }
567582}
568583
584+ #[ derive( FromArgs ) ]
585+ pub struct PyFunctionNewArgs {
586+ #[ pyarg( positional) ]
587+ code : PyRef < PyCode > ,
588+ #[ pyarg( positional) ]
589+ globals : PyDictRef ,
590+ #[ pyarg( any, optional) ]
591+ name : OptionalArg < PyStrRef > ,
592+ #[ pyarg( any, optional) ]
593+ defaults : OptionalArg < PyTupleRef > ,
594+ #[ pyarg( any, optional) ]
595+ closure : OptionalArg < PyTupleRef > ,
596+ #[ pyarg( any, optional) ]
597+ kwdefaults : OptionalArg < PyDictRef > ,
598+ }
599+
600+ impl Constructor for PyFunction {
601+ type Args = PyFunctionNewArgs ;
602+
603+ fn py_new ( cls : PyTypeRef , args : Self :: Args , vm : & VirtualMachine ) -> PyResult {
604+ // Handle closure - must be a tuple of cells
605+ let closure = if let Some ( closure_tuple) = args. closure . into_option ( ) {
606+ // Check that closure length matches code's free variables
607+ if closure_tuple. len ( ) != args. code . freevars . len ( ) {
608+ return Err ( vm. new_value_error ( format ! (
609+ "{} requires closure of length {}, not {}" ,
610+ args. code. obj_name,
611+ args. code. freevars. len( ) ,
612+ closure_tuple. len( )
613+ ) ) ) ;
614+ }
615+
616+ // Validate that all items are cells and create typed tuple
617+ let typed_closure =
618+ PyTupleTyped :: < PyCellRef > :: try_from_object ( vm, closure_tuple. into ( ) ) ?;
619+ Some ( typed_closure)
620+ } else if !args. code . freevars . is_empty ( ) {
621+ return Err ( vm. new_type_error ( "arg 5 (closure) must be tuple" . to_owned ( ) ) ) ;
622+ } else {
623+ None
624+ } ;
625+
626+ // Get function name - use provided name or default to code object name
627+ let name = args
628+ . name
629+ . into_option ( )
630+ . unwrap_or_else ( || PyStr :: from ( args. code . obj_name . as_str ( ) ) . into_ref ( & vm. ctx ) ) ;
631+
632+ // Get qualname - for now just use the name
633+ let qualname = name. clone ( ) ;
634+
635+ // Create empty type_params and annotations
636+ let type_params = vm. ctx . new_tuple ( vec ! [ ] ) ;
637+ let annotations = vm. ctx . new_dict ( ) ;
638+
639+ // Get doc from code object - for now just use None
640+ let doc = vm. ctx . none ( ) ;
641+
642+ let func = PyFunction :: new (
643+ args. code ,
644+ args. globals ,
645+ closure,
646+ args. defaults . into_option ( ) ,
647+ args. kwdefaults . into_option ( ) ,
648+ qualname,
649+ type_params,
650+ annotations,
651+ doc,
652+ vm,
653+ ) ?;
654+
655+ func. into_ref_with_type ( vm, cls) . map ( Into :: into)
656+ }
657+ }
658+
569659#[ pyclass( module = false , name = "method" , traverse) ]
570660#[ derive( Debug ) ]
571661pub struct PyBoundMethod {
0 commit comments