@@ -350,9 +350,20 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
350350 var outs = 0 ;
351351 int clrnargs = pi . Length ;
352352 isOperator = isOperator && pynargs == clrnargs - 1 ; // Handle mismatched arg numbers due to Python operator being bound.
353+ // Preprocessing pi to remove either the first or second argument.
354+ bool isForward = isOperator && OperatorMethod . IsForward ( ( MethodInfo ) mi ) ; // Only cast if isOperator.
355+ if ( isOperator && isForward ) {
356+ // The first Python arg is the right operand, while the bound instance is the left.
357+ // We need to skip the first (left operand) CLR argument.
358+ pi = pi . Skip ( 1 ) . Take ( 1 ) . ToArray ( ) ;
359+ }
360+ else if ( isOperator && ! isForward ) {
361+ // The first Python arg is the left operand.
362+ // We need to take the first CLR argument.
363+ pi = pi . Take ( 1 ) . ToArray ( ) ;
364+ }
353365 var margs = TryConvertArguments ( pi , paramsArray , args , pynargs , kwargDict , defaultArgList ,
354366 needsResolution : _methods . Length > 1 , // If there's more than one possible match.
355- isOperator : isOperator ,
356367 outs : out outs ) ;
357368 if ( margs == null )
358369 {
@@ -364,7 +375,15 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
364375 {
365376 if ( ManagedType . GetManagedObject ( inst ) is CLRObject co )
366377 {
367- margs [ 0 ] = co . inst ;
378+ // Postprocessing to extend margs.
379+ var margsTemp = new object [ 2 ] ;
380+ // If forward, the bound instance is the left operand.
381+ int boundOperandIndex = isForward ? 0 : 1 ;
382+ // If forward, the passed instance is the right operand.
383+ int passedOperandIndex = isForward ? 1 : 0 ;
384+ margsTemp [ boundOperandIndex ] = co . inst ;
385+ margsTemp [ passedOperandIndex ] = margs [ 0 ] ;
386+ margs = margsTemp ;
368387 }
369388 else { break ; }
370389 }
@@ -488,15 +507,13 @@ static IntPtr HandleParamsArray(IntPtr args, int arrayStart, int pyArgCount, out
488507 /// <param name="kwargDict">Dictionary of keyword argument name to python object pointer</param>
489508 /// <param name="defaultArgList">A list of default values for omitted parameters</param>
490509 /// <param name="needsResolution"><c>true</c>, if overloading resolution is required</param>
491- /// <param name="isOperator"><c>true</c>, if is operator method</param>
492510 /// <param name="outs">Returns number of output parameters</param>
493511 /// <returns>An array of .NET arguments, that can be passed to a method.</returns>
494512 static object [ ] TryConvertArguments ( ParameterInfo [ ] pi , bool paramsArray ,
495513 IntPtr args , int pyArgCount ,
496514 Dictionary < string , IntPtr > kwargDict ,
497515 ArrayList defaultArgList ,
498516 bool needsResolution ,
499- bool isOperator ,
500517 out int outs )
501518 {
502519 outs = 0 ;
@@ -535,13 +552,6 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
535552 op = Runtime . PyTuple_GetItem ( args , paramIndex ) ;
536553 }
537554 }
538- if ( isOperator && paramIndex == 0 )
539- {
540- // After we've obtained the first argument from Python, we need to skip the first argument of the CLR
541- // because operator method is a bound method in Python
542- paramIndex ++ ; // Leave the first .NET param as null (margs).
543- parameter = pi [ paramIndex ] ;
544- }
545555
546556 bool isOut ;
547557 if ( ! TryConvertArgument ( op , parameter . ParameterType , needsResolution , out margs [ paramIndex ] , out isOut ) )
0 commit comments