@@ -69,13 +69,65 @@ impl Callable for PyNativeFunction {
6969 #[ inline]
7070 fn call ( zelf : & Py < Self > , mut args : FuncArgs , vm : & VirtualMachine ) -> PyResult {
7171 if let Some ( z) = & zelf. zelf {
72- args. prepend_arg ( z. clone ( ) ) ;
72+ // STATIC methods store the class in zelf for qualname/repr purposes,
73+ // but should not prepend it to args (the Rust function doesn't expect it).
74+ if !zelf. value . flags . contains ( PyMethodFlags :: STATIC ) {
75+ args. prepend_arg ( z. clone ( ) ) ;
76+ }
7377 }
7478 ( zelf. value . func ) ( vm, args)
7579 }
7680}
7781
78- #[ pyclass( with( Callable ) , flags( HAS_DICT , DISALLOW_INSTANTIATION ) ) ]
82+ // meth_richcompare in CPython
83+ impl Comparable for PyNativeFunction {
84+ fn cmp (
85+ zelf : & Py < Self > ,
86+ other : & PyObject ,
87+ op : PyComparisonOp ,
88+ _vm : & VirtualMachine ,
89+ ) -> PyResult < PyComparisonValue > {
90+ op. eq_only ( || {
91+ if let Some ( other) = other. downcast_ref :: < Self > ( ) {
92+ let eq = match ( zelf. zelf . as_ref ( ) , other. zelf . as_ref ( ) ) {
93+ ( Some ( z) , Some ( o) ) => z. is ( o) ,
94+ ( None , None ) => true ,
95+ _ => false ,
96+ } ;
97+ let eq = eq && core:: ptr:: eq ( zelf. value , other. value ) ;
98+ Ok ( eq. into ( ) )
99+ } else {
100+ Ok ( PyComparisonValue :: NotImplemented )
101+ }
102+ } )
103+ }
104+ }
105+
106+ // meth_repr in CPython
107+ impl Representable for PyNativeFunction {
108+ #[ inline]
109+ fn repr_str ( zelf : & Py < Self > , vm : & VirtualMachine ) -> PyResult < String > {
110+ if let Some ( bound) = zelf
111+ . zelf
112+ . as_ref ( )
113+ . filter ( |b| !b. class ( ) . is ( vm. ctx . types . module_type ) )
114+ {
115+ Ok ( format ! (
116+ "<built-in method {} of {} object at {:#x}>" ,
117+ zelf. value. name,
118+ bound. class( ) . name( ) ,
119+ bound. get_id( )
120+ ) )
121+ } else {
122+ Ok ( format ! ( "<built-in function {}>" , zelf. value. name) )
123+ }
124+ }
125+ }
126+
127+ #[ pyclass(
128+ with( Callable , Comparable , Representable ) ,
129+ flags( HAS_DICT , DISALLOW_INSTANTIATION )
130+ ) ]
79131impl PyNativeFunction {
80132 #[ pygetset]
81133 fn __module__ ( zelf : NativeFunctionOrMethod ) -> Option < & ' static PyStrInterned > {
@@ -87,20 +139,19 @@ impl PyNativeFunction {
87139 zelf. 0 . value . name
88140 }
89141
142+ // meth_get__qualname__ in CPython
90143 #[ pygetset]
91144 fn __qualname__ ( zelf : NativeFunctionOrMethod , vm : & VirtualMachine ) -> PyResult < PyStrRef > {
92145 let zelf = zelf. 0 ;
93- let flags = zelf. value . flags ;
94- // if flags.contains(PyMethodFlags::CLASS) || flags.contains(PyMethodFlags::STATIC) {
95146 let qualname = if let Some ( bound) = & zelf. zelf {
96- let prefix = if flags. contains ( PyMethodFlags :: CLASS ) {
97- bound
98- . get_attr ( "__qualname__" , vm)
99- . unwrap ( )
100- . str ( vm)
101- . unwrap ( )
102- . to_string ( )
147+ if bound. class ( ) . is ( vm. ctx . types . module_type ) {
148+ return Ok ( vm. ctx . intern_str ( zelf. value . name ) . to_owned ( ) ) ;
149+ }
150+ let prefix = if bound. class ( ) . is ( vm. ctx . types . type_type ) {
151+ // m_self is a type: use PyType_GetQualName(m_self)
152+ bound. get_attr ( "__qualname__" , vm) ?. str ( vm) ?. to_string ( )
103153 } else {
154+ // m_self is an instance: use Py_TYPE(m_self).__qualname__
104155 bound. class ( ) . name ( ) . to_string ( )
105156 } ;
106157 vm. ctx . new_str ( format ! ( "{}.{}" , prefix, & zelf. value. name) )
@@ -115,15 +166,23 @@ impl PyNativeFunction {
115166 zelf. 0 . value . doc
116167 }
117168
169+ // meth_get__self__ in CPython
118170 #[ pygetset]
119- fn __self__ ( _zelf : PyObjectRef , vm : & VirtualMachine ) -> PyObjectRef {
120- vm. ctx . none ( )
171+ fn __self__ ( zelf : NativeFunctionOrMethod , vm : & VirtualMachine ) -> PyObjectRef {
172+ zelf . 0 . zelf . clone ( ) . unwrap_or_else ( || vm. ctx . none ( ) )
121173 }
122174
175+ // meth_reduce in CPython
123176 #[ pymethod]
124- const fn __reduce__ ( & self ) -> & ' static str {
125- // TODO: return (getattr, (self.object, self.name)) if this is a method
126- self . value . name
177+ fn __reduce__ ( zelf : NativeFunctionOrMethod , vm : & VirtualMachine ) -> PyResult {
178+ let zelf = zelf. 0 ;
179+ if zelf. zelf . is_none ( ) || zelf. module . is_some ( ) {
180+ Ok ( vm. ctx . new_str ( zelf. value . name ) . into ( ) )
181+ } else {
182+ let getattr = vm. builtins . get_attr ( "getattr" , vm) ?;
183+ let target = zelf. zelf . clone ( ) . unwrap ( ) ;
184+ Ok ( vm. new_tuple ( ( getattr, ( target, zelf. value . name ) ) ) . into ( ) )
185+ }
127186 }
128187
129188 #[ pymethod]
@@ -139,14 +198,7 @@ impl PyNativeFunction {
139198 }
140199}
141200
142- impl Representable for PyNativeFunction {
143- #[ inline]
144- fn repr_str ( zelf : & Py < Self > , _vm : & VirtualMachine ) -> PyResult < String > {
145- Ok ( format ! ( "<built-in function {}>" , zelf. value. name) )
146- }
147- }
148-
149- // `PyCMethodObject` in CPython
201+ // PyCMethodObject in CPython
150202// repr(C) ensures `func` is at offset 0, allowing safe cast from PyNativeMethod to PyNativeFunction
151203#[ repr( C ) ]
152204#[ pyclass( name = "builtin_function_or_method" , module = false , base = PyNativeFunction , ctx = "builtin_function_or_method_type" ) ]
@@ -155,14 +207,11 @@ pub struct PyNativeMethod {
155207 pub ( crate ) class : & ' static Py < PyType > , // TODO: the actual life is &'self
156208}
157209
158- #[ pyclass(
159- with( Callable , Comparable , Representable ) ,
160- flags( HAS_DICT , DISALLOW_INSTANTIATION )
161- ) ]
162- impl PyNativeMethod {
163- // __qualname__, __self__, and __reduce__ are inherited from PyNativeFunction
164- // via NativeFunctionOrMethod wrapper since we share the same Python type.
165- }
210+ // All Python-visible behavior (getters, slots) is registered by PyNativeFunction::extend_class.
211+ // PyNativeMethod only extends the Rust-side struct with the defining class reference.
212+ // The func field at offset 0 (#[repr(C)]) allows NativeFunctionOrMethod to read it safely.
213+ #[ pyclass( flags( HAS_DICT , DISALLOW_INSTANTIATION ) ) ]
214+ impl PyNativeMethod { }
166215
167216impl fmt:: Debug for PyNativeMethod {
168217 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
@@ -175,55 +224,8 @@ impl fmt::Debug for PyNativeMethod {
175224 }
176225}
177226
178- impl Comparable for PyNativeMethod {
179- fn cmp (
180- zelf : & Py < Self > ,
181- other : & PyObject ,
182- op : PyComparisonOp ,
183- _vm : & VirtualMachine ,
184- ) -> PyResult < PyComparisonValue > {
185- op. eq_only ( || {
186- if let Some ( other) = other. downcast_ref :: < Self > ( ) {
187- let eq = match ( zelf. func . zelf . as_ref ( ) , other. func . zelf . as_ref ( ) ) {
188- ( Some ( z) , Some ( o) ) => z. is ( o) ,
189- ( None , None ) => true ,
190- _ => false ,
191- } ;
192- let eq = eq && core:: ptr:: eq ( zelf. func . value , other. func . value ) ;
193- Ok ( eq. into ( ) )
194- } else {
195- Ok ( PyComparisonValue :: NotImplemented )
196- }
197- } )
198- }
199- }
200-
201- impl Callable for PyNativeMethod {
202- type Args = FuncArgs ;
203-
204- #[ inline]
205- fn call ( zelf : & Py < Self > , mut args : FuncArgs , vm : & VirtualMachine ) -> PyResult {
206- if let Some ( zelf) = & zelf. func . zelf {
207- args. prepend_arg ( zelf. clone ( ) ) ;
208- }
209- ( zelf. func . value . func ) ( vm, args)
210- }
211- }
212-
213- impl Representable for PyNativeMethod {
214- #[ inline]
215- fn repr_str ( zelf : & Py < Self > , _vm : & VirtualMachine ) -> PyResult < String > {
216- Ok ( format ! (
217- "<built-in method {} of {} object at ...>" ,
218- & zelf. func. value. name,
219- zelf. class. name( )
220- ) )
221- }
222- }
223-
224227pub fn init ( context : & Context ) {
225228 PyNativeFunction :: extend_class ( context, context. types . builtin_function_or_method_type ) ;
226- PyNativeMethod :: extend_class ( context, context. types . builtin_function_or_method_type ) ;
227229}
228230
229231/// Wrapper that provides access to the common PyNativeFunction data
0 commit comments