@@ -396,164 +396,73 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
396396 }
397397
398398
399- for ( int index = 0 ; index < argMatchedMethods . Count ; index ++ )
400- {
401- var testMatch = argMatchedMethods [ index ] ;
402- if ( testMatch . DefaultsNeeded == fewestDefaultsRequired && testMatch . KwargsMatched == bestKwargMatchCount )
403- {
404- bestCount ++ ;
405- if ( bestMatchIndex == - 1 )
406- bestMatchIndex = index ;
407- }
408- }
409-
410- if ( bestCount > 1 && fewestDefaultsRequired > 0 )
411- {
412- // Best effort for determining method to match on gives multiple possible
413- // matches and we need at least one default argument - bail from this point
414- StringBuilder stringBuilder = new StringBuilder ( "Not enough arguments provided to disambiguate the method. Found:" ) ;
415- foreach ( var matchedMethod in argMatchedMethods )
416- {
417- stringBuilder . AppendLine ( ) ;
418- stringBuilder . Append ( matchedMethod . Method . ToString ( ) ) ;
419- }
420- Exceptions . SetError ( Exceptions . TypeError , stringBuilder . ToString ( ) ) ;
421- return null ;
422- }
423-
424- // If we're here either:
425- // (a) There is only one best match
426- // (b) There are multiple best matches but none of them require
427- // default arguments
428- // in the case of (a) we're done by default. For (b) regardless of which
429- // method we choose, all arguments are specified _and_ can be converted
430- // from python to C# so picking any will suffice
431- MatchedMethod bestMatch = argMatchedMethods [ bestMatchIndex ] ;
432- var margs = bestMatch . ManagedArgs ;
433- var outs = bestMatch . Outs ;
434- var mi = bestMatch . Method ;
435-
436- object target = null ;
437- if ( ! mi . IsStatic && inst != IntPtr . Zero )
438- {
439- //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
440- // InvalidCastException: Unable to cast object of type
441- // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
442- var co = ManagedType . GetManagedObject ( inst ) as CLRObject ;
443-
444- // Sanity check: this ensures a graceful exit if someone does
445- // something intentionally wrong like call a non-static method
446- // on the class rather than on an instance of the class.
447- // XXX maybe better to do this before all the other rigmarole.
448- if ( co == null )
449- {
450- Exceptions . SetError ( Exceptions . TypeError , "Invoked a non-static method with an invalid instance" ) ;
451- return null ;
452- }
453- target = co . inst ;
454- }
455-
456- return new Binding ( mi , target , margs , outs ) ;
457- }
458- else if ( isGeneric && info == null && methodinfo != null )
459- {
460- // We weren't able to find a matching method but at least one
461- // is a generic method and info is null. That happens when a generic
462- // method was not called using the [] syntax. Let's introspect the
463- // type of the arguments and use it to construct the correct method.
464- Type [ ] types = Runtime . PythonArgsToTypeArray ( args , true ) ;
465- MethodInfo mi = MatchParameters ( methodinfo , types ) ;
466- if ( mi != null )
467- {
468- return Bind ( inst , args , kw , mi , null ) ;
469- }
470- }
471- if ( mismatchedMethods . Count > 0 )
472- {
473- var aggregateException = GetAggregateException ( mismatchedMethods ) ;
474- Exceptions . SetError ( aggregateException ) ;
475- }
476- return null ;
477- }
478-
479- static AggregateException GetAggregateException ( IEnumerable < MismatchedMethod > mismatchedMethods )
480- {
481- return new AggregateException ( mismatchedMethods . Select ( m => new ArgumentException ( $ "{ m . Exception . Message } in method { m . Method } ", m . Exception ) ) ) ;
482- }
483-
484- static IntPtr HandleParamsArray ( IntPtr args , int arrayStart , int pyArgCount , out bool isNewReference )
485- {
486- isNewReference = false ;
487- IntPtr op ;
488- // for a params method, we may have a sequence or single/multiple items
489- // here we look to see if the item at the paramIndex is there or not
490- // and then if it is a sequence itself.
491- if ( ( pyArgCount - arrayStart ) == 1 )
492- {
493- // we only have one argument left, so we need to check it
494- // to see if it is a sequence or a single item
495- IntPtr item = Runtime . PyTuple_GetItem ( args , arrayStart ) ;
496- if ( ! Runtime . PyString_Check ( item ) && Runtime . PySequence_Check ( item ) )
497- {
498- // it's a sequence (and not a string), so we use it as the op
499- op = item ;
500- }
501- else
502- {
503- isNewReference = true ;
504- op = Runtime . PyTuple_GetSlice ( args , arrayStart , pyArgCount ) ;
505- }
506- }
507- else
508- {
509- isNewReference = true ;
510- op = Runtime . PyTuple_GetSlice ( args , arrayStart , pyArgCount ) ;
511- }
512- return op ;
513- }
514-
515- /// <summary>
516- /// Attempts to convert Python positional argument tuple and keyword argument table
517- /// into an array of managed objects, that can be passed to a method.
518- /// If unsuccessful, returns null and may set a Python error.
519- /// </summary>
520- /// <param name="pi">Information about expected parameters</param>
521- /// <param name="paramsArray"><c>true</c>, if the last parameter is a params array.</param>
522- /// <param name="args">A pointer to the Python argument tuple</param>
523- /// <param name="pyArgCount">Number of arguments, passed by Python</param>
524- /// <param name="kwargDict">Dictionary of keyword argument name to python object pointer</param>
525- /// <param name="defaultArgList">A list of default values for omitted parameters</param>
526- /// <param name="needsResolution"><c>true</c>, if overloading resolution is required</param>
527- /// <param name="outs">Returns number of output parameters</param>
528- /// <returns>If successful, an array of .NET arguments that can be passed to the method. Otherwise null.</returns>
529- static object [ ] TryConvertArguments ( ParameterInfo [ ] pi , bool paramsArray ,
530- IntPtr args , int pyArgCount ,
531- Dictionary < string , IntPtr > kwargDict ,
532- ArrayList defaultArgList ,
533- bool needsResolution ,
534- out int outs ,
535- out bool usedImplicitConversion )
536- {
537- usedImplicitConversion = false ;
538- outs = 0 ;
539- var margs = new object [ pi . Length ] ;
540- int arrayStart = paramsArray ? pi . Length - 1 : - 1 ;
541-
542- for ( int paramIndex = 0 ; paramIndex < pi . Length ; paramIndex ++ )
543- {
544- var parameter = pi [ paramIndex ] ;
545- bool hasNamedParam = kwargDict . ContainsKey ( parameter . Name ) ;
546- bool isNewReference = false ;
547-
548- if ( paramIndex >= pyArgCount && ! ( hasNamedParam || ( paramsArray && paramIndex == arrayStart ) ) )
549- {
550- if ( defaultArgList != null )
551- {
552- margs [ paramIndex ] = defaultArgList [ paramIndex - pyArgCount ] ;
553- }
554-
555- continue ;
556- }
399+ if ( clrtype != null )
400+ {
401+ var typematch = false ;
402+ if ( ( pi [ n ] . ParameterType != typeof ( object ) ) && ( pi [ n ] . ParameterType != clrtype ) )
403+ {
404+ IntPtr pytype = Converter . GetPythonTypeByAlias ( pi [ n ] . ParameterType ) ;
405+ pyoptype = Runtime . PyObject_Type ( op ) ;
406+ Exceptions . Clear ( ) ;
407+ if ( pyoptype != IntPtr . Zero )
408+ {
409+ if ( pytype != pyoptype )
410+ {
411+ typematch = false ;
412+ }
413+ else
414+ {
415+ typematch = true ;
416+ clrtype = pi [ n ] . ParameterType ;
417+ }
418+ }
419+ if ( ! typematch )
420+ {
421+ // this takes care of nullables
422+ var underlyingType = Nullable . GetUnderlyingType ( pi [ n ] . ParameterType ) ;
423+ if ( underlyingType == null )
424+ {
425+ underlyingType = pi [ n ] . ParameterType ;
426+ }
427+ // this takes care of enum values
428+ TypeCode argtypecode = Type . GetTypeCode ( underlyingType ) ;
429+ TypeCode paramtypecode = Type . GetTypeCode ( clrtype ) ;
430+ if ( argtypecode == paramtypecode )
431+ {
432+ typematch = true ;
433+ clrtype = pi [ n ] . ParameterType ;
434+ }
435+ // accepts non-decimal numbers in decimal parameters
436+ if ( underlyingType == typeof ( decimal ) )
437+ {
438+ clrtype = pi [ n ] . ParameterType ;
439+ typematch = Converter . ToManaged ( op , clrtype , out arg , false ) ;
440+ }
441+ // this takes care of implicit conversions
442+ var opImplicit = pi [ n ] . ParameterType . GetMethod ( "op_Implicit" , new [ ] { clrtype } ) ;
443+ if ( opImplicit != null )
444+ {
445+ usedImplicitConversion = typematch = opImplicit . ReturnType == pi [ n ] . ParameterType ;
446+ clrtype = pi [ n ] . ParameterType ;
447+ }
448+ }
449+ Runtime . XDecref ( pyoptype ) ;
450+ if ( ! typematch )
451+ {
452+ margs = null ;
453+ break ;
454+ }
455+ }
456+ else
457+ {
458+ typematch = true ;
459+ clrtype = pi [ n ] . ParameterType ;
460+ }
461+ }
462+ else
463+ {
464+ clrtype = pi [ n ] . ParameterType ;
465+ }
557466
558467 if ( pi [ n ] . IsOut || clrtype . IsByRef )
559468 {
0 commit comments