Skip to content

Commit

Permalink
MethodBinder implicit resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin-Molinero authored and C-SELLERS committed Feb 15, 2021
1 parent bf1755d commit 58d5df0
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 123 deletions.
25 changes: 12 additions & 13 deletions src/embed_tests/TestMethodBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,40 +43,39 @@ public void Dispose()
[Test]
public void ImplicitConversionToString()
{
var data = (string)module.TestA();
// we assert implicit conversion took place
Assert.AreEqual("OnlyString impl: implicit to string", data);
}
// we assert implicit conversion took place
Assert.AreEqual("OnlyString impl: implicit to string", data);
}

[Test]
public void ImplicitConversionToClass()
{
var data = (string)module.TestB();
// we assert implicit conversion took place
Assert.AreEqual("OnlyClass impl", data);
}
// we assert implicit conversion took place
Assert.AreEqual("OnlyClass impl", data);
}

[Test]
public void WillAvoidUsingImplicitConversionIfPossible_String()
{
var data = (string)module.TestC();
// we assert no implicit conversion took place
Assert.AreEqual("string impl: input string", data);
}
// we assert no implicit conversion took place
Assert.AreEqual("string impl: input string", data);
}

[Test]
public void WillAvoidUsingImplicitConversionIfPossible_Class()
{
var data = (string)module.TestD();
// we assert no implicit conversion took place
Assert.AreEqual("TestImplicitConversion impl", data);
// we assert no implicit conversion took place
Assert.AreEqual("TestImplicitConversion impl", data);

}

[Test]
public void ArrayLength()
{
var array = new[] { "pepe", "pinocho" };
var array = new[] { "pepe", "pinocho" };
var data = (bool)module.TestE(array);

// Assert it is true
Expand Down
6 changes: 3 additions & 3 deletions src/runtime/classobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ internal ClassObject(Type tp) : base(tp)
/// </summary>
internal NewReference GetDocString()
{
MethodBase[] methods = binder.GetMethods();
var methods = binder.GetMethods();
var str = "";
foreach (MethodBase t in methods)
foreach (var t in methods)
{
if (str.Length > 0)
{
str += Environment.NewLine;
}
str += t.ToString();
str += t.MethodBase.ToString();
}
return NewReference.DangerousFromPointer(Runtime.PyString_FromString(str));
}
Expand Down
5 changes: 3 additions & 2 deletions src/runtime/constructorbinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,17 @@ public static IntPtr tp_repr(IntPtr ob)
Runtime.XIncref(self.repr);
return self.repr;
}
MethodBase[] methods = self.ctorBinder.GetMethods();
var methods = self.ctorBinder.GetMethods();

if (!self.type.Valid)
{
return Exceptions.RaiseTypeError(self.type.DeletedMessage);
}
string name = self.type.Value.FullName;
var doc = "";
foreach (MethodBase t in methods)
foreach (var methodInformation in methods)
{
var t = methodInformation.MethodBase;
if (doc.Length > 0)
{
doc += "\n";
Expand Down
51 changes: 44 additions & 7 deletions src/runtime/converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,12 @@ internal static IntPtr ToPythonImplicit(object value)
}


internal static bool ToManaged(IntPtr value, Type type,
out object result, bool setError)
{
var usedImplicit = false;
return ToManaged(value, type, out result, setError, out usedImplicit);
}
/// <summary>
/// Return a managed object for the given Python object, taking funny
/// byref types into account.
Expand All @@ -400,21 +406,26 @@ internal static IntPtr ToPythonImplicit(object value)
/// <param name="setError">If true, call <c>Exceptions.SetError</c> with the reason for failure.</param>
/// <returns>True on success</returns>
internal static bool ToManaged(IntPtr value, Type type,
out object result, bool setError)
out object result, bool setError, out bool usedImplicit)
{
if (type.IsByRef)
{
type = type.GetElementType();
}
return Converter.ToManagedValue(value, type, out result, setError);
return Converter.ToManagedValue(value, type, out result, setError, out usedImplicit);
}

internal static bool ToManagedValue(BorrowedReference value, Type obType,
out object result, bool setError)
=> ToManagedValue(value.DangerousGetAddress(), obType, out result, setError);
{
var usedImplicit = false;
return ToManagedValue(value.DangerousGetAddress(), obType, out result, setError, out usedImplicit);
}

internal static bool ToManagedValue(IntPtr value, Type obType,
out object result, bool setError)
out object result, bool setError, out bool usedImplicit)
{
usedImplicit = false;
if (obType == typeof(PyObject))
{
Runtime.XIncref(value); // PyObject() assumes ownership
Expand Down Expand Up @@ -446,6 +457,18 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
result = tmp;
return true;
}
else
{
var type = tmp.GetType();
// check implicit conversions that receive tmp type and return obType
var conversionMethod = type.GetMethod("op_Implicit", new[] { type });
if (conversionMethod != null && conversionMethod.ReturnType == obType)
{
result = conversionMethod.Invoke(null, new[] { tmp });
usedImplicit = true;
return true;
}
}
if (setError)
{
string typeString = tmp is null ? "null" : tmp.GetType().ToString();
Expand Down Expand Up @@ -599,7 +622,7 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
var underlyingType = Nullable.GetUnderlyingType(obType);
if (underlyingType != null)
{
return ToManagedValue(value, underlyingType, out result, setError);
return ToManagedValue(value, underlyingType, out result, setError, out usedImplicit);
}

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

var opImplicit = obType.GetMethod("op_Implicit", new[] { obType });
if (opImplicit != null)
{
if (ToManagedValue(value, opImplicit.ReturnType, out result, setError, out usedImplicit))
{
opImplicit = obType.GetMethod("op_Implicit", new[] { result.GetType() });
if (opImplicit != null)
{
result = opImplicit.Invoke(null, new[] { result });
}
return opImplicit != null;
}
}

return ToPrimitive(value, obType, out result, setError);
}

Expand Down Expand Up @@ -1046,12 +1083,12 @@ private static IList MakeList(IntPtr value, IntPtr IterObject, Type obType, Type
}

IntPtr item;

var usedImplicit = false;
while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero)
{
object obj;

if (!Converter.ToManaged(item, elementType, out obj, setError))
if (!Converter.ToManaged(item, elementType, out obj, setError, out usedImplicit))
{
Runtime.XDecref(item);
return null;
Expand Down
10 changes: 5 additions & 5 deletions src/runtime/indexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ internal void SetItem(IntPtr inst, IntPtr args)
internal bool NeedsDefaultArgs(IntPtr args)
{
var pynargs = Runtime.PyTuple_Size(args);
MethodBase[] methods = SetterBinder.GetMethods();
if (methods.Length == 0)
var methods = SetterBinder.GetMethods();
if (methods.Count == 0)
{
return false;
}

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

// Get the default arg tuple
MethodBase[] methods = SetterBinder.GetMethods();
MethodBase mi = methods[0];
var methods = SetterBinder.GetMethods();
var mi = methods[0].MethodBase.UnsafeValue;
ParameterInfo[] pi = mi.GetParameters();
int clrnargs = pi.Length - 1;
IntPtr defaultArgs = Runtime.PyTuple_New(clrnargs - pynargs);
Expand Down
Loading

0 comments on commit 58d5df0

Please sign in to comment.