Skip to content

Commit dbc89a4

Browse files
committed
Return eleements of interface arrays as interface objects
Even when a method is declared to return an array of interfaces, the CLR may use an array of the concrete type. Keep track of the intended type in `ArrayObject` so that elements of the array can be properly wrapped in `InterfaceObject` when accessed.
1 parent 010c290 commit dbc89a4

File tree

5 files changed

+43
-2
lines changed

5 files changed

+43
-2
lines changed

src/runtime/arrayobject.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
4343
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
4444
{
4545
var obj = (CLRObject)GetManagedObject(ob);
46+
var arrObj = (ArrayObject)GetManagedObjectType(ob);
4647
var items = obj.inst as Array;
47-
Type itemType = obj.inst.GetType().GetElementType();
48+
Type itemType = arrObj.type.GetElementType();
4849
int rank = items.Rank;
4950
int index;
5051
object value;

src/runtime/converter.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,15 @@ internal static IntPtr ToPython(object value, Type type)
179179
return CLRObject.GetInstHandle(value, ifaceObj.pyHandle);
180180
}
181181

182+
// We need to special case interface array handling to ensure we
183+
// produce the correct type. Value may be an array of some concrete
184+
// type (FooImpl[]), but we want access to go via the interface type
185+
// (IFoo[]).
186+
if (type.IsArray && type.GetElementType().IsInterface)
187+
{
188+
return CLRObject.GetInstHandle(value, type);
189+
}
190+
182191
// it the type is a python subclass of a managed type then return the
183192
// underlying python object rather than construct a new wrapper object.
184193
var pyderived = value as IPythonDerivedType;
@@ -188,7 +197,6 @@ internal static IntPtr ToPython(object value, Type type)
188197
return ClassDerivedObject.ToPython(pyderived);
189198
}
190199

191-
192200
// hmm - from Python, we almost never care what the declared
193201
// type is. we'd rather have the object bound to the actual
194202
// implementing class.

src/runtime/managedtype.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,25 @@ internal static ManagedType GetManagedObject(IntPtr ob)
4545
return null;
4646
}
4747

48+
/// <summary>
49+
/// Given a Python object, return the associated managed object type or null.
50+
/// </summary>
51+
internal static ManagedType GetManagedObjectType(IntPtr ob)
52+
{
53+
if (ob != IntPtr.Zero)
54+
{
55+
IntPtr tp = Runtime.PyObject_TYPE(ob);
56+
var flags = Util.ReadCLong(tp, TypeOffset.tp_flags);
57+
if ((flags & TypeFlags.Managed) != 0)
58+
{
59+
tp = Marshal.ReadIntPtr(tp, TypeOffset.magic());
60+
var gc = (GCHandle)tp;
61+
return (ManagedType)gc.Target;
62+
}
63+
}
64+
return null;
65+
}
66+
4867

4968
internal static ManagedType GetManagedObjectErr(IntPtr ob)
5069
{

src/testing/interfacetest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ public ISayHello1 GetNoSayHello(out ISayHello2 hello2)
5858
return null;
5959
}
6060

61+
public ISayHello1 [] GetISayHello1Array()
62+
{
63+
return new[] { this };
64+
}
65+
6166
public interface IPublic
6267
{
6368
}

src/tests/test_interface.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,11 @@ def test_null_interface_object_returned():
9999
hello1, hello2 = ob.GetNoSayHello(None)
100100
assert hello1 is None
101101
assert hello2 is None
102+
103+
def test_interface_array_returned():
104+
"""Test interface type used for methods returning interface arrays"""
105+
from Python.Test import InterfaceTest
106+
107+
ob = InterfaceTest()
108+
hellos = ob.GetISayHello1Array()
109+
assert type(hellos[0]).__name__ == 'ISayHello1'

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy