Skip to content

DLR-based overload resolution #1278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
trivial DLR-based instance method binding
  • Loading branch information
lostmsu committed Nov 12, 2020
commit 97b82b1c5b149f0ed25165cb12d9f9d5d8210eab
25 changes: 14 additions & 11 deletions src/runtime/Python.Runtime.15.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.CSharp">
<Version>4.7.0</Version>
</PackageReference>
<PackageReference Include="System.Security.Permissions" Version="4.4.0" />
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
</ItemGroup>
Expand All @@ -143,20 +146,20 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<None Update="intern_.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>intern_.cs</LastGenOutput>
</None>
<ItemGroup>
<None Update="intern_.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>intern_.cs</LastGenOutput>
</None>
</ItemGroup>


<ItemGroup>
<Compile Update="intern_.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>intern_.tt</DependentUpon>
</Compile>
<ItemGroup>
<Compile Update="intern_.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>intern_.tt</DependentUpon>
</Compile>
</ItemGroup>

<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
Expand Down
1 change: 1 addition & 0 deletions src/runtime/Python.Runtime.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
<Compile Include="assemblymanager.cs" />
<Compile Include="BorrowedReference.cs" />
<Compile Include="bufferinterface.cs" />
<Compile Include="callsitebinder.cs" />
<Compile Include="classderived.cs" />
<Compile Include="classbase.cs" />
<Compile Include="classmanager.cs" />
Expand Down
60 changes: 60 additions & 0 deletions src/runtime/callsitebinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;

using Microsoft.CSharp.RuntimeBinder;

using CSharpBinder = Microsoft.CSharp.RuntimeBinder.Binder;

namespace Python.Runtime
{
public class PythonNetCallSiteBinder : CallSiteBinder
{
readonly CallSiteBinder voidBinder;
readonly CallSiteBinder resultBinder;

PythonNetCallSiteBinder(string methodName,
IEnumerable<Type> typeArguments,
Type context,
IEnumerable<CSharpArgumentInfo> argumentInfo)
{
this.voidBinder = CSharpBinder.InvokeMember(CSharpBinderFlags.ResultDiscarded,
methodName,
typeArguments: typeArguments,
context: context,
argumentInfo
);
this.resultBinder = CSharpBinder.InvokeMember(CSharpBinderFlags.None,
methodName,
typeArguments: typeArguments,
context: context,
argumentInfo
);
}

public override Expression Bind(object[] args,
ReadOnlyCollection<ParameterExpression> parameters,
LabelTarget returnLabel)
{
var result = this.resultBinder.Bind(args, parameters, returnLabel);
if (result.Type == typeof(void))
{
var voidExpr = this.voidBinder.Bind(args, parameters, returnLabel);
return Expression.Block(
voidExpr,
Expression.Return(returnLabel, Expression.Constant(null))
);
}

return result;
}

public static PythonNetCallSiteBinder InvokeMember(string methodName,
IEnumerable<Type> typeArguments,
Type context,
IEnumerable<CSharpArgumentInfo> argumentInfo)
=> new PythonNetCallSiteBinder(methodName, typeArguments, context, argumentInfo);
}
}
44 changes: 20 additions & 24 deletions src/runtime/classbase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,10 @@ protected override void OnLoad(InterDomainContext context)
/// <summary>
/// Implements __getitem__ for reflected classes and value types.
/// </summary>
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
public static IntPtr mp_subscript(IntPtr obRaw, IntPtr idx)
{
IntPtr tp = Runtime.PyObject_TYPE(ob);
var ob = new BorrowedReference(obRaw);
var tp = Runtime.PyObject_Type(ob);
var cls = (ClassBase)GetManagedObject(tp);

if (cls.indexer == null || !cls.indexer.CanGet)
Expand All @@ -361,40 +362,35 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
// Arg may be a tuple in the case of an indexer with multiple
// parameters. If so, use it directly, else make a new tuple
// with the index arg (method binders expect arg tuples).
IntPtr args = idx;
var free = false;

if (!Runtime.PyTuple_Check(idx))
{
args = Runtime.PyTuple_New(1);
Runtime.XIncref(idx);
Runtime.PyTuple_SetItem(args, 0, idx);
free = true;
}

IntPtr value;

try
if (Runtime.PyTuple_Check(idx))
{
value = cls.indexer.GetItem(ob, args);
return cls.indexer.GetItem(ob, new BorrowedReference(idx));
}
finally
else
{
if (free)
var args = NewReference.DangerousFromPointer(Runtime.PyTuple_New(1));
try
{
Runtime.XDecref(args);
Runtime.XIncref(idx);
Runtime.PyTuple_SetItem(args, 0, idx);
return cls.indexer.GetItem(ob, args);
}
finally
{
args.Dispose();
}
}
return value;
}


/// <summary>
/// Implements __setitem__ for reflected classes and value types.
/// </summary>
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
public static int mp_ass_subscript(IntPtr obRaw, IntPtr idx, IntPtr v)
{
IntPtr tp = Runtime.PyObject_TYPE(ob);
var ob = new BorrowedReference(obRaw);
BorrowedReference tp = Runtime.PyObject_Type(ob);
var cls = (ClassBase)GetManagedObject(tp);

if (cls.indexer == null || !cls.indexer.CanSet)
Expand Down Expand Up @@ -422,7 +418,7 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args);
var numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
var temp = i + numOfDefaultArgs;
IntPtr real = Runtime.PyTuple_New(temp + 1);
var real = NewReference.DangerousFromPointer(Runtime.PyTuple_New(temp + 1));
for (var n = 0; n < i; n++)
{
IntPtr item = Runtime.PyTuple_GetItem(args, n);
Expand Down Expand Up @@ -451,7 +447,7 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v)
}
finally
{
Runtime.XDecref(real);
real.Dispose();

if (free)
{
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/classderived.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ internal ClassDerivedObject(Type tp) : base(tp)
var cls = GetManagedObject(tp) as ClassDerivedObject;

// call the managed constructor
object obj = cls.binder.InvokeRaw(IntPtr.Zero, args, kw);
object obj = cls.binder.InvokeRaw(IntPtr.Zero, new BorrowedReference(args), kw);
if (obj == null)
{
return IntPtr.Zero;
Expand Down
5 changes: 3 additions & 2 deletions src/runtime/classobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ internal IntPtr GetDocString()
/// <summary>
/// Implements __new__ for reflected classes and value types.
/// </summary>
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
public static IntPtr tp_new(IntPtr tp, IntPtr rawArgs, IntPtr kw)
{
var args = new BorrowedReference(rawArgs);
var self = GetManagedObject(tp) as ClassObject;

// Sanity check: this ensures a graceful error if someone does
Expand All @@ -74,7 +75,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
return IntPtr.Zero;
}

IntPtr op = Runtime.PyTuple_GetItem(args, 0);
BorrowedReference op = Runtime.PyTuple_GetItem(args, 0);
object result;

if (!Converter.ToManaged(op, type, out result, true))
Expand Down
6 changes: 3 additions & 3 deletions src/runtime/constructorbinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal ConstructorBinder(Type containingType)
/// object - the reason is that only the caller knows the correct
/// Python type to use when wrapping the result (may be a subclass).
/// </summary>
internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw)
internal object InvokeRaw(IntPtr inst, BorrowedReference args, IntPtr kw)
{
return InvokeRaw(inst, args, kw, null);
}
Expand All @@ -49,7 +49,7 @@ internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw)
/// Binding binding = this.Bind(inst, args, kw, info);
/// to take advantage of Bind()'s ability to use a single MethodBase (CI or MI).
/// </remarks>
internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info)
internal object InvokeRaw(IntPtr inst, BorrowedReference args, IntPtr kw, MethodBase info)
{
object result;

Expand Down Expand Up @@ -78,7 +78,7 @@ internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info)
return result;
}

Binding binding = Bind(inst, args, kw, info);
Binding binding = Bind(inst, args.DangerousGetAddress(), kw, info);

if (binding == null)
{
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/constructorbinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw)
}*/
// Bind using ConstructorBinder.Bind and invoke the ctor providing a null instancePtr
// which will fire self.ctorInfo using ConstructorInfo.Invoke().
object obj = self.ctorBinder.InvokeRaw(IntPtr.Zero, args, kw, self.ctorInfo);
object obj = self.ctorBinder.InvokeRaw(IntPtr.Zero, new BorrowedReference(args), kw, self.ctorInfo);
if (obj == null)
{
// XXX set an error
Expand Down
7 changes: 4 additions & 3 deletions src/runtime/delegateobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
/// <summary>
/// Implements __call__ for reflected delegate types.
/// </summary>
public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)
public static IntPtr tp_call(IntPtr obRaw, IntPtr args, IntPtr kw)
{
var ob = new BorrowedReference(obRaw);
// TODO: add fast type check!
IntPtr pytype = Runtime.PyObject_TYPE(ob);
BorrowedReference pytype = Runtime.PyObject_Type(ob);
var self = (DelegateObject)GetManagedObject(pytype);
var o = GetManagedObject(ob) as CLRObject;

Expand All @@ -90,7 +91,7 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)
{
return Exceptions.RaiseTypeError("invalid argument");
}
return self.binder.Invoke(ob, args, kw);
return self.binder.Invoke(ob, new BorrowedReference(args), new BorrowedReference(kw));
}


Expand Down
8 changes: 4 additions & 4 deletions src/runtime/indexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ public void AddProperty(PropertyInfo pi)
}
}

internal IntPtr GetItem(IntPtr inst, IntPtr args)
internal IntPtr GetItem(BorrowedReference inst, BorrowedReference args)
{
return GetterBinder.Invoke(inst, args, IntPtr.Zero);
return GetterBinder.Invoke(inst, args, BorrowedReference.Null);
}


internal void SetItem(IntPtr inst, IntPtr args)
internal void SetItem(BorrowedReference inst, BorrowedReference args)
{
SetterBinder.Invoke(inst, args, IntPtr.Zero);
SetterBinder.Invoke(inst, args, BorrowedReference.Null);
}

internal bool NeedsDefaultArgs(IntPtr args)
Expand Down
Loading