@@ -8,7 +8,7 @@ use super::{
8
8
#[ cfg( feature = "jit" ) ]
9
9
use crate :: common:: lock:: OnceCell ;
10
10
use crate :: common:: lock:: PyMutex ;
11
- use crate :: convert:: ToPyObject ;
11
+ use crate :: convert:: { ToPyObject , TryFromObject } ;
12
12
use crate :: function:: ArgMapping ;
13
13
use crate :: object:: { Traverse , TraverseFn } ;
14
14
use crate :: {
@@ -31,6 +31,7 @@ use rustpython_jit::CompiledCode;
31
31
pub struct PyFunction {
32
32
code : PyRef < PyCode > ,
33
33
globals : PyDictRef ,
34
+ builtins : PyObjectRef ,
34
35
closure : Option < PyTupleTyped < PyCellRef > > ,
35
36
defaults_and_kwdefaults : PyMutex < ( Option < PyTupleRef > , Option < PyDictRef > ) > ,
36
37
name : PyMutex < PyStrRef > ,
@@ -53,6 +54,7 @@ unsafe impl Traverse for PyFunction {
53
54
54
55
impl PyFunction {
55
56
#[ allow( clippy:: too_many_arguments) ]
57
+ #[ inline]
56
58
pub ( crate ) fn new (
57
59
code : PyRef < PyCode > ,
58
60
globals : PyDictRef ,
@@ -62,24 +64,42 @@ impl PyFunction {
62
64
qualname : PyStrRef ,
63
65
type_params : PyTupleRef ,
64
66
annotations : PyDictRef ,
65
- module : PyObjectRef ,
66
67
doc : PyObjectRef ,
67
- ) -> Self {
68
+ vm : & VirtualMachine ,
69
+ ) -> PyResult < Self > {
68
70
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 {
70
82
code,
71
83
globals,
84
+ builtins,
72
85
closure,
73
86
defaults_and_kwdefaults : PyMutex :: new ( ( defaults, kw_only_defaults) ) ,
74
87
name,
75
88
qualname : PyMutex :: new ( qualname) ,
76
89
type_params : PyMutex :: new ( type_params) ,
77
- #[ cfg( feature = "jit" ) ]
78
- jitted_code : OnceCell :: new ( ) ,
79
90
annotations : PyMutex :: new ( annotations) ,
80
91
module : PyMutex :: new ( module) ,
81
92
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)
83
103
}
84
104
85
105
fn fill_locals_from_args (
@@ -362,7 +382,7 @@ impl PyPayload for PyFunction {
362
382
}
363
383
364
384
#[ pyclass(
365
- with( GetDescriptor , Callable , Representable ) ,
385
+ with( GetDescriptor , Callable , Representable , Constructor ) ,
366
386
flags( HAS_DICT , METHOD_DESCRIPTOR )
367
387
) ]
368
388
impl PyFunction {
@@ -406,6 +426,12 @@ impl PyFunction {
406
426
Ok ( vm. unwrap_or_none ( zelf. closure . clone ( ) . map ( |x| x. to_pyobject ( vm) ) ) )
407
427
}
408
428
429
+ #[ pymember( magic) ]
430
+ fn builtins ( vm : & VirtualMachine , zelf : PyObjectRef ) -> PyResult {
431
+ let zelf = Self :: _as_pyref ( & zelf, vm) ?;
432
+ Ok ( zelf. builtins . clone ( ) )
433
+ }
434
+
409
435
#[ pygetset( magic) ]
410
436
fn name ( & self ) -> PyStrRef {
411
437
self . name . lock ( ) . clone ( )
@@ -555,6 +581,81 @@ impl Representable for PyFunction {
555
581
}
556
582
}
557
583
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
+
558
659
#[ pyclass( module = false , name = "method" , traverse) ]
559
660
#[ derive( Debug ) ]
560
661
pub struct PyBoundMethod {
0 commit comments