@@ -369,6 +369,41 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
369369 return null ;
370370 }
371371
372+ static IntPtr HandleParamsArray ( IntPtr args , int arrayStart , int pyArgCount , out bool isNewReference )
373+ {
374+ isNewReference = false ;
375+ IntPtr op ;
376+ // for a params method, we may have a sequence or single/multiple items
377+ // here we look to see if the item at the paramIndex is there or not
378+ // and then if it is a sequence itself.
379+ if ( ( pyArgCount - arrayStart ) == 1 )
380+ {
381+ // we only have one argument left, so we need to check it
382+ // to see if it is a sequence or a single item
383+ IntPtr item = Runtime . PyTuple_GetItem ( args , arrayStart ) ;
384+ if ( ! Runtime . PyString_Check ( item ) && Runtime . PySequence_Check ( item ) )
385+ {
386+ // it's a sequence (and not a string), so we use it as the op
387+ op = item ;
388+ }
389+ else
390+ {
391+ isNewReference = true ;
392+ op = Runtime . PyTuple_GetSlice ( args , arrayStart , pyArgCount ) ;
393+ if ( item != IntPtr . Zero )
394+ {
395+ Runtime . XDecref ( item ) ;
396+ }
397+ }
398+ }
399+ else
400+ {
401+ isNewReference = true ;
402+ op = Runtime . PyTuple_GetSlice ( args , arrayStart , pyArgCount ) ;
403+ }
404+ return op ;
405+ }
406+
372407 /// <summary>
373408 /// Attempts to convert Python positional argument tuple and keyword argument table
374409 /// into an array of managed objects, that can be passed to a method.
@@ -397,8 +432,9 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
397432 {
398433 var parameter = pi [ paramIndex ] ;
399434 bool hasNamedParam = kwargDict . ContainsKey ( parameter . Name ) ;
435+ bool isNewReference = false ;
400436
401- if ( paramIndex >= pyArgCount && ! hasNamedParam )
437+ if ( paramIndex >= pyArgCount && ! ( hasNamedParam || ( paramsArray && paramIndex == arrayStart ) ) )
402438 {
403439 if ( defaultArgList != null )
404440 {
@@ -415,11 +451,14 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
415451 }
416452 else
417453 {
418- op = ( arrayStart == paramIndex )
419- // map remaining Python arguments to a tuple since
420- // the managed function accepts it - hopefully :]
421- ? Runtime . PyTuple_GetSlice ( args , arrayStart , pyArgCount )
422- : Runtime . PyTuple_GetItem ( args , paramIndex ) ;
454+ if ( arrayStart == paramIndex )
455+ {
456+ op = HandleParamsArray ( args , arrayStart , pyArgCount , out isNewReference ) ;
457+ }
458+ else
459+ {
460+ op = Runtime . PyTuple_GetItem ( args , paramIndex ) ;
461+ }
423462 }
424463
425464 bool isOut ;
@@ -428,7 +467,7 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
428467 return null ;
429468 }
430469
431- if ( arrayStart == paramIndex )
470+ if ( isNewReference )
432471 {
433472 // TODO: is this a bug? Should this happen even if the conversion fails?
434473 // GetSlice() creates a new reference but GetItem()
@@ -543,7 +582,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
543582 {
544583 defaultArgList = null ;
545584 var match = false ;
546- paramsArray = false ;
585+ paramsArray = parameters . Length > 0 ? Attribute . IsDefined ( parameters [ parameters . Length - 1 ] , typeof ( ParamArrayAttribute ) ) : false ;
547586
548587 if ( positionalArgumentCount == parameters . Length )
549588 {
@@ -572,7 +611,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
572611 // to be passed in as the parameter value
573612 defaultArgList . Add ( parameters [ v ] . GetDefaultValue ( ) ) ;
574613 }
575- else
614+ else if ( ! paramsArray )
576615 {
577616 match = false ;
578617 }
0 commit comments