@@ -184,15 +184,43 @@ STATIC const qstr binary_op_method_name[] = {
184184 [MP_BINARY_OP_EXCEPTION_MATCH ] = MP_QSTR_ , // not implemented, used to make sure array has full size
185185};
186186
187+ // Given a member that was extracted from an instance, convert it correctly
188+ // and put the result in the dest[] array for a possible method call.
189+ // Conversion means dealing with static/class methods, callables, and values.
190+ // see http://docs.python.org/3.3/howto/descriptor.html
191+ STATIC void class_convert_return_attr (mp_obj_t self , mp_obj_t member , mp_obj_t * dest ) {
192+ if (MP_OBJ_IS_TYPE (member , & mp_type_staticmethod )) {
193+ // return just the function
194+ dest [0 ] = ((mp_obj_static_class_method_t * )member )-> fun ;
195+ } else if (MP_OBJ_IS_TYPE (member , & mp_type_classmethod )) {
196+ // return a bound method, with self being the type of this object
197+ dest [0 ] = ((mp_obj_static_class_method_t * )member )-> fun ;
198+ dest [1 ] = mp_obj_get_type (self );
199+ } else if (mp_obj_is_callable (member )) {
200+ // return a bound method, with self being this object
201+ dest [0 ] = member ;
202+ dest [1 ] = self ;
203+ } else {
204+ // class member is a value, so just return that value
205+ dest [0 ] = member ;
206+ }
207+ }
208+
187209STATIC mp_obj_t class_binary_op (int op , mp_obj_t lhs_in , mp_obj_t rhs_in ) {
210+ // Note: For ducktyping, CPython does not look in the instance members or use
211+ // __getattr__ or __getattribute__. It only looks in the class dictionary.
188212 mp_obj_class_t * lhs = lhs_in ;
189213 qstr op_name = binary_op_method_name [op ];
190214 if (op_name == 0 ) {
191215 return MP_OBJ_NULL ;
192216 }
193217 mp_obj_t member = mp_obj_class_lookup (lhs -> base .type , op_name );
194218 if (member != MP_OBJ_NULL ) {
195- return mp_call_function_2 (member , lhs_in , rhs_in );
219+ mp_obj_t dest [3 ];
220+ dest [1 ] = MP_OBJ_NULL ;
221+ class_convert_return_attr (lhs_in , member , dest );
222+ dest [2 ] = rhs_in ;
223+ return mp_call_method_n_kw (1 , 0 , dest );
196224 } else {
197225 return MP_OBJ_NULL ;
198226 }
@@ -209,24 +237,7 @@ STATIC void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
209237 }
210238 mp_obj_t member = mp_obj_class_lookup (self -> base .type , attr );
211239 if (member != MP_OBJ_NULL ) {
212- // check if the methods are functions, static or class methods
213- // see http://docs.python.org/3.3/howto/descriptor.html
214- // TODO check that this is the correct place to have this logic
215- if (MP_OBJ_IS_TYPE (member , & mp_type_staticmethod )) {
216- // return just the function
217- dest [0 ] = ((mp_obj_static_class_method_t * )member )-> fun ;
218- } else if (MP_OBJ_IS_TYPE (member , & mp_type_classmethod )) {
219- // return a bound method, with self being the type of this object
220- dest [0 ] = ((mp_obj_static_class_method_t * )member )-> fun ;
221- dest [1 ] = mp_obj_get_type (self_in );
222- } else if (mp_obj_is_callable (member )) {
223- // return a bound method, with self being this object
224- dest [0 ] = member ;
225- dest [1 ] = self_in ;
226- } else {
227- // class member is a value, so just return that value
228- dest [0 ] = member ;
229- }
240+ class_convert_return_attr (self_in , member , dest );
230241 return ;
231242 }
232243
@@ -432,25 +443,7 @@ STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
432443 assert (MP_OBJ_IS_TYPE (items [i ], & mp_type_type ));
433444 mp_obj_t member = mp_obj_class_lookup ((mp_obj_type_t * )items [i ], attr );
434445 if (member != MP_OBJ_NULL ) {
435- // XXX this and the code in class_load_attr need to be factored out
436- // check if the methods are functions, static or class methods
437- // see http://docs.python.org/3.3/howto/descriptor.html
438- // TODO check that this is the correct place to have this logic
439- if (MP_OBJ_IS_TYPE (member , & mp_type_staticmethod )) {
440- // return just the function
441- dest [0 ] = ((mp_obj_static_class_method_t * )member )-> fun ;
442- } else if (MP_OBJ_IS_TYPE (member , & mp_type_classmethod )) {
443- // return a bound method, with self being the type of this object
444- dest [0 ] = ((mp_obj_static_class_method_t * )member )-> fun ;
445- dest [1 ] = mp_obj_get_type (self -> obj );
446- } if (mp_obj_is_callable (member )) {
447- // return a bound method, with self being this object
448- dest [0 ] = member ;
449- dest [1 ] = self -> obj ;
450- } else {
451- // class member is a value, so just return that value
452- dest [0 ] = member ;
453- }
446+ class_convert_return_attr (self , member , dest );
454447 return ;
455448 }
456449 }
0 commit comments