@@ -342,15 +342,34 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
342342 bool paramsArray ;
343343 int kwargsMatched ;
344344 int defaultsNeeded ;
345-
345+ bool isOperator = OperatorMethod . IsOperatorMethod ( mi ) ; // e.g. op_Addition is defined for OperableObject
346346 if ( ! MatchesArgumentCount ( pynargs , pi , kwargDict , out paramsArray , out defaultArgList , out kwargsMatched , out defaultsNeeded ) )
347347 {
348- continue ;
348+ if ( isOperator )
349+ {
350+ defaultArgList = null ;
351+ }
352+ else { continue ; }
349353 }
350354 var outs = 0 ;
355+ int clrnargs = pi . Length ;
356+ isOperator = isOperator && pynargs == clrnargs - 1 ; // Handle mismatched arg numbers due to Python operator being bound.
351357 var margs = TryConvertArguments ( pi , paramsArray , args , pynargs , kwargDict , defaultArgList ,
352- needsResolution : _methods . Length > 1 ,
358+ needsResolution : _methods . Length > 1 , // If there's more than one possible match.
359+ isOperator : isOperator ,
353360 outs : out outs ) ;
361+ if ( isOperator )
362+ {
363+ if ( inst != IntPtr . Zero )
364+ {
365+ var co = ManagedType . GetManagedObject ( inst ) as CLRObject ;
366+ if ( co == null )
367+ {
368+ break ;
369+ }
370+ margs [ 0 ] = co . inst ;
371+ }
372+ }
354373
355374 if ( margs == null )
356375 {
@@ -474,13 +493,15 @@ static IntPtr HandleParamsArray(IntPtr args, int arrayStart, int pyArgCount, out
474493 /// <param name="kwargDict">Dictionary of keyword argument name to python object pointer</param>
475494 /// <param name="defaultArgList">A list of default values for omitted parameters</param>
476495 /// <param name="needsResolution"><c>true</c>, if overloading resolution is required</param>
496+ /// <param name="isOperator"><c>true</c>, if is operator method</param>
477497 /// <param name="outs">Returns number of output parameters</param>
478498 /// <returns>An array of .NET arguments, that can be passed to a method.</returns>
479499 static object [ ] TryConvertArguments ( ParameterInfo [ ] pi , bool paramsArray ,
480500 IntPtr args , int pyArgCount ,
481501 Dictionary < string , IntPtr > kwargDict ,
482502 ArrayList defaultArgList ,
483503 bool needsResolution ,
504+ bool isOperator ,
484505 out int outs )
485506 {
486507 outs = 0 ;
@@ -519,6 +540,12 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
519540 op = Runtime . PyTuple_GetItem ( args , paramIndex ) ;
520541 }
521542 }
543+ if ( isOperator && paramIndex == 0 )
544+ {
545+ // After we've obtained the first argument from Python, we need to skip the first argument of the CLR
546+ // because operator method is a bound method in Python
547+ paramIndex ++ ; // Leave the first .NET param as null (margs).
548+ }
522549
523550 bool isOut ;
524551 if ( ! TryConvertArgument ( op , parameter . ParameterType , needsResolution , out margs [ paramIndex ] , out isOut ) )
@@ -543,6 +570,15 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
543570 return margs ;
544571 }
545572
573+ /// <summary>
574+ /// Try to convert a Python argument object to a managed CLR type.
575+ /// </summary>
576+ /// <param name="op">Pointer to the object at a particular parameter.</param>
577+ /// <param name="parameterType">That parameter's managed type.</param>
578+ /// <param name="needsResolution">There are multiple overloading methods that need resolution.</param>
579+ /// <param name="arg">Converted argument.</param>
580+ /// <param name="isOut">Whether the CLR type is passed by reference.</param>
581+ /// <returns></returns>
546582 static bool TryConvertArgument ( IntPtr op , Type parameterType , bool needsResolution ,
547583 out object arg , out bool isOut )
548584 {
@@ -633,7 +669,17 @@ static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument, bool
633669
634670 return clrtype ;
635671 }
636-
672+ /// <summary>
673+ /// Check whether the number of Python and .NET arguments match, and compute additional arg information.
674+ /// </summary>
675+ /// <param name="positionalArgumentCount">Number of positional args passed from Python.</param>
676+ /// <param name="parameters">Parameters of the specified .NET method.</param>
677+ /// <param name="kwargDict">Keyword args passed from Python.</param>
678+ /// <param name="paramsArray">True if the final param of the .NET method is an array (`params` keyword).</param>
679+ /// <param name="defaultArgList">List of default values for arguments.</param>
680+ /// <param name="kwargsMatched">Number of kwargs from Python that are also present in the .NET method.</param>
681+ /// <param name="defaultsNeeded">Number of non-null defaultsArgs.</param>
682+ /// <returns></returns>
637683 static bool MatchesArgumentCount ( int positionalArgumentCount , ParameterInfo [ ] parameters ,
638684 Dictionary < string , IntPtr > kwargDict ,
639685 out bool paramsArray ,
0 commit comments