Skip to content

Commit 58d5df0

Browse files
Martin-MolineroC-SELLERS
authored andcommitted
MethodBinder implicit resolution
1 parent bf1755d commit 58d5df0

File tree

7 files changed

+148
-123
lines changed

7 files changed

+148
-123
lines changed

src/embed_tests/TestMethodBinder.cs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,40 +43,39 @@ public void Dispose()
4343
[Test]
4444
public void ImplicitConversionToString()
4545
{
46-
var data = (string)module.TestA();
47-
// we assert implicit conversion took place
48-
Assert.AreEqual("OnlyString impl: implicit to string", data);
49-
}
46+
// we assert implicit conversion took place
47+
Assert.AreEqual("OnlyString impl: implicit to string", data);
48+
}
5049

5150
[Test]
5251
public void ImplicitConversionToClass()
5352
{
5453
var data = (string)module.TestB();
55-
// we assert implicit conversion took place
56-
Assert.AreEqual("OnlyClass impl", data);
57-
}
54+
// we assert implicit conversion took place
55+
Assert.AreEqual("OnlyClass impl", data);
56+
}
5857

5958
[Test]
6059
public void WillAvoidUsingImplicitConversionIfPossible_String()
6160
{
6261
var data = (string)module.TestC();
63-
// we assert no implicit conversion took place
64-
Assert.AreEqual("string impl: input string", data);
65-
}
62+
// we assert no implicit conversion took place
63+
Assert.AreEqual("string impl: input string", data);
64+
}
6665

6766
[Test]
6867
public void WillAvoidUsingImplicitConversionIfPossible_Class()
6968
{
7069
var data = (string)module.TestD();
71-
// we assert no implicit conversion took place
72-
Assert.AreEqual("TestImplicitConversion impl", data);
70+
// we assert no implicit conversion took place
71+
Assert.AreEqual("TestImplicitConversion impl", data);
7372

7473
}
7574

7675
[Test]
7776
public void ArrayLength()
7877
{
79-
var array = new[] { "pepe", "pinocho" };
78+
var array = new[] { "pepe", "pinocho" };
8079
var data = (bool)module.TestE(array);
8180

8281
// Assert it is true

src/runtime/classobject.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ internal ClassObject(Type tp) : base(tp)
3333
/// </summary>
3434
internal NewReference GetDocString()
3535
{
36-
MethodBase[] methods = binder.GetMethods();
36+
var methods = binder.GetMethods();
3737
var str = "";
38-
foreach (MethodBase t in methods)
38+
foreach (var t in methods)
3939
{
4040
if (str.Length > 0)
4141
{
4242
str += Environment.NewLine;
4343
}
44-
str += t.ToString();
44+
str += t.MethodBase.ToString();
4545
}
4646
return NewReference.DangerousFromPointer(Runtime.PyString_FromString(str));
4747
}

src/runtime/constructorbinding.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,16 +126,17 @@ public static IntPtr tp_repr(IntPtr ob)
126126
Runtime.XIncref(self.repr);
127127
return self.repr;
128128
}
129-
MethodBase[] methods = self.ctorBinder.GetMethods();
129+
var methods = self.ctorBinder.GetMethods();
130130

131131
if (!self.type.Valid)
132132
{
133133
return Exceptions.RaiseTypeError(self.type.DeletedMessage);
134134
}
135135
string name = self.type.Value.FullName;
136136
var doc = "";
137-
foreach (MethodBase t in methods)
137+
foreach (var methodInformation in methods)
138138
{
139+
var t = methodInformation.MethodBase;
139140
if (doc.Length > 0)
140141
{
141142
doc += "\n";

src/runtime/converter.cs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,12 @@ internal static IntPtr ToPythonImplicit(object value)
390390
}
391391

392392

393+
internal static bool ToManaged(IntPtr value, Type type,
394+
out object result, bool setError)
395+
{
396+
var usedImplicit = false;
397+
return ToManaged(value, type, out result, setError, out usedImplicit);
398+
}
393399
/// <summary>
394400
/// Return a managed object for the given Python object, taking funny
395401
/// byref types into account.
@@ -400,21 +406,26 @@ internal static IntPtr ToPythonImplicit(object value)
400406
/// <param name="setError">If true, call <c>Exceptions.SetError</c> with the reason for failure.</param>
401407
/// <returns>True on success</returns>
402408
internal static bool ToManaged(IntPtr value, Type type,
403-
out object result, bool setError)
409+
out object result, bool setError, out bool usedImplicit)
404410
{
405411
if (type.IsByRef)
406412
{
407413
type = type.GetElementType();
408414
}
409-
return Converter.ToManagedValue(value, type, out result, setError);
415+
return Converter.ToManagedValue(value, type, out result, setError, out usedImplicit);
410416
}
411417

412418
internal static bool ToManagedValue(BorrowedReference value, Type obType,
413419
out object result, bool setError)
414-
=> ToManagedValue(value.DangerousGetAddress(), obType, out result, setError);
420+
{
421+
var usedImplicit = false;
422+
return ToManagedValue(value.DangerousGetAddress(), obType, out result, setError, out usedImplicit);
423+
}
424+
415425
internal static bool ToManagedValue(IntPtr value, Type obType,
416-
out object result, bool setError)
426+
out object result, bool setError, out bool usedImplicit)
417427
{
428+
usedImplicit = false;
418429
if (obType == typeof(PyObject))
419430
{
420431
Runtime.XIncref(value); // PyObject() assumes ownership
@@ -446,6 +457,18 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
446457
result = tmp;
447458
return true;
448459
}
460+
else
461+
{
462+
var type = tmp.GetType();
463+
// check implicit conversions that receive tmp type and return obType
464+
var conversionMethod = type.GetMethod("op_Implicit", new[] { type });
465+
if (conversionMethod != null && conversionMethod.ReturnType == obType)
466+
{
467+
result = conversionMethod.Invoke(null, new[] { tmp });
468+
usedImplicit = true;
469+
return true;
470+
}
471+
}
449472
if (setError)
450473
{
451474
string typeString = tmp is null ? "null" : tmp.GetType().ToString();
@@ -599,7 +622,7 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
599622
var underlyingType = Nullable.GetUnderlyingType(obType);
600623
if (underlyingType != null)
601624
{
602-
return ToManagedValue(value, underlyingType, out result, setError);
625+
return ToManagedValue(value, underlyingType, out result, setError, out usedImplicit);
603626
}
604627

605628
TypeCode typeCode = Type.GetTypeCode(obType);
@@ -612,6 +635,20 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
612635
}
613636
}
614637

638+
var opImplicit = obType.GetMethod("op_Implicit", new[] { obType });
639+
if (opImplicit != null)
640+
{
641+
if (ToManagedValue(value, opImplicit.ReturnType, out result, setError, out usedImplicit))
642+
{
643+
opImplicit = obType.GetMethod("op_Implicit", new[] { result.GetType() });
644+
if (opImplicit != null)
645+
{
646+
result = opImplicit.Invoke(null, new[] { result });
647+
}
648+
return opImplicit != null;
649+
}
650+
}
651+
615652
return ToPrimitive(value, obType, out result, setError);
616653
}
617654

@@ -1046,12 +1083,12 @@ private static IList MakeList(IntPtr value, IntPtr IterObject, Type obType, Type
10461083
}
10471084

10481085
IntPtr item;
1049-
1086+
var usedImplicit = false;
10501087
while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero)
10511088
{
10521089
object obj;
10531090

1054-
if (!Converter.ToManaged(item, elementType, out obj, setError))
1091+
if (!Converter.ToManaged(item, elementType, out obj, setError, out usedImplicit))
10551092
{
10561093
Runtime.XDecref(item);
10571094
return null;

src/runtime/indexer.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,13 @@ internal void SetItem(IntPtr inst, IntPtr args)
5858
internal bool NeedsDefaultArgs(IntPtr args)
5959
{
6060
var pynargs = Runtime.PyTuple_Size(args);
61-
MethodBase[] methods = SetterBinder.GetMethods();
62-
if (methods.Length == 0)
61+
var methods = SetterBinder.GetMethods();
62+
if (methods.Count == 0)
6363
{
6464
return false;
6565
}
6666

67-
MethodBase mi = methods[0];
67+
var mi = methods[0].MethodBase.UnsafeValue;
6868
ParameterInfo[] pi = mi.GetParameters();
6969
// need to subtract one for the value
7070
int clrnargs = pi.Length - 1;
@@ -99,8 +99,8 @@ internal IntPtr GetDefaultArgs(IntPtr args)
9999
var pynargs = Runtime.PyTuple_Size(args);
100100

101101
// Get the default arg tuple
102-
MethodBase[] methods = SetterBinder.GetMethods();
103-
MethodBase mi = methods[0];
102+
var methods = SetterBinder.GetMethods();
103+
var mi = methods[0].MethodBase.UnsafeValue;
104104
ParameterInfo[] pi = mi.GetParameters();
105105
int clrnargs = pi.Length - 1;
106106
IntPtr defaultArgs = Runtime.PyTuple_New(clrnargs - pynargs);

0 commit comments

Comments
 (0)