Skip to content

Commit ed6ab18

Browse files
committed
Revert "Merge pull request #1240 from danabr/auto-cast-ret-val-to-interface"
This reverts commit 50d947f, reversing changes made to d44f1da.
1 parent 0f5f0ba commit ed6ab18

13 files changed

+23
-141
lines changed

CHANGELOG.md

-5
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
2121
details about the cause of the failure
2222
- `clr.AddReference` no longer adds ".dll" implicitly
2323
- `PyIter(PyObject)` constructor replaced with static `PyIter.GetIter(PyObject)` method
24-
- BREAKING: Return values from .NET methods that return an interface are now automatically
25-
wrapped in that interface. This is a breaking change for users that rely on being
26-
able to access members that are part of the implementation class, but not the
27-
interface. Use the new __implementation__ or __raw_implementation__ properties to
28-
if you need to "downcast" to the implementation class.
2924
- BREAKING: Parameters marked with `ParameterAttributes.Out` are no longer returned in addition
3025
to the regular method return value (unless they are passed with `ref` or `out` keyword).
3126
- BREAKING: Drop support for the long-deprecated CLR.* prefix.

src/runtime/arrayobject.cs

+1-6
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,8 @@ static NewReference NewInstance(Type elementType, BorrowedReference arrayPyType,
137137
public new static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
138138
{
139139
var obj = (CLRObject)GetManagedObject(ob);
140-
var arrObj = (ArrayObject)GetManagedObjectType(ob);
141-
if (!arrObj.type.Valid)
142-
{
143-
return Exceptions.RaiseTypeError(arrObj.type.DeletedMessage);
144-
}
145140
var items = obj.inst as Array;
146-
Type itemType = arrObj.type.Value.GetElementType();
141+
Type itemType = obj.inst.GetType().GetElementType();
147142
int rank = items.Rank;
148143
int index;
149144
object value;

src/runtime/converter.cs

-15
Original file line numberDiff line numberDiff line change
@@ -207,21 +207,6 @@ internal static IntPtr ToPython(object value, Type type)
207207
}
208208
}
209209

210-
if (type.IsInterface)
211-
{
212-
var ifaceObj = (InterfaceObject)ClassManager.GetClass(type);
213-
return ifaceObj.WrapObject(value);
214-
}
215-
216-
// We need to special case interface array handling to ensure we
217-
// produce the correct type. Value may be an array of some concrete
218-
// type (FooImpl[]), but we want access to go via the interface type
219-
// (IFoo[]).
220-
if (type.IsArray && type.GetElementType().IsInterface)
221-
{
222-
return CLRObject.GetInstHandle(value, type);
223-
}
224-
225210
// it the type is a python subclass of a managed type then return the
226211
// underlying python object rather than construct a new wrapper object.
227212
var pyderived = value as IPythonDerivedType;

src/runtime/interfaceobject.cs

+1-37
Original file line numberDiff line numberDiff line change
@@ -76,43 +76,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
7676
return IntPtr.Zero;
7777
}
7878

79-
return self.WrapObject(obj);
80-
}
81-
82-
/// <summary>
83-
/// Wrap the given object in an interface object, so that only methods
84-
/// of the interface are available.
85-
/// </summary>
86-
public IntPtr WrapObject(object impl)
87-
{
88-
var objPtr = CLRObject.GetInstHandle(impl, pyHandle);
89-
return objPtr;
90-
}
91-
92-
/// <summary>
93-
/// Expose the wrapped implementation through attributes in both
94-
/// converted/encoded (__implementation__) and raw (__raw_implementation__) form.
95-
/// </summary>
96-
public static IntPtr tp_getattro(IntPtr ob, IntPtr key)
97-
{
98-
var clrObj = (CLRObject)GetManagedObject(ob);
99-
100-
if (!Runtime.PyString_Check(key))
101-
{
102-
return Exceptions.RaiseTypeError("string expected");
103-
}
104-
105-
string name = Runtime.GetManagedString(key);
106-
if (name == "__implementation__")
107-
{
108-
return Converter.ToPython(clrObj.inst);
109-
}
110-
else if (name == "__raw_implementation__")
111-
{
112-
return CLRObject.GetInstHandle(clrObj.inst);
113-
}
114-
115-
return Runtime.PyObject_GenericGetAttr(ob, key);
79+
return CLRObject.GetInstHandle(obj, self.pyHandle);
11680
}
11781
}
11882
}

src/runtime/managedtype.cs

-19
Original file line numberDiff line numberDiff line change
@@ -109,25 +109,6 @@ internal static ManagedType GetManagedObject(IntPtr ob)
109109
return null;
110110
}
111111

112-
/// <summary>
113-
/// Given a Python object, return the associated managed object type or null.
114-
/// </summary>
115-
internal static ManagedType GetManagedObjectType(IntPtr ob)
116-
{
117-
if (ob != IntPtr.Zero)
118-
{
119-
IntPtr tp = Runtime.PyObject_TYPE(ob);
120-
var flags = Util.ReadCLong(tp, TypeOffset.tp_flags);
121-
if ((flags & TypeFlags.Managed) != 0)
122-
{
123-
tp = Marshal.ReadIntPtr(tp, TypeOffset.magic());
124-
var gc = (GCHandle)tp;
125-
return (ManagedType)gc.Target;
126-
}
127-
}
128-
return null;
129-
}
130-
131112

132113
internal static ManagedType GetManagedObjectErr(IntPtr ob)
133114
{

src/runtime/typemanager.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,10 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
251251
InitializeSlot(type, TypeOffset.mp_length, mp_length_slot.Method, slotsHolder);
252252
}
253253

254-
if (!typeof(IEnumerable).IsAssignableFrom(clrType) &&
255-
!typeof(IEnumerator).IsAssignableFrom(clrType))
254+
// we want to do this after the slot stuff above in case the class itself implements a slot method
255+
InitializeSlots(type, impl.GetType());
256+
257+
if (!clrType.GetInterfaces().Any(ifc => ifc == typeof(IEnumerable) || ifc == typeof(IEnumerator)))
256258
{
257259
// The tp_iter slot should only be set for enumerable types.
258260
Marshal.WriteIntPtr(type, TypeOffset.tp_iter, IntPtr.Zero);

src/testing/interfacetest.cs

+1-21
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ internal interface IInternalInterface
1111
{
1212
}
1313

14+
1415
public interface ISayHello1
1516
{
1617
string SayHello();
@@ -42,27 +43,6 @@ string ISayHello2.SayHello()
4243
return "hello 2";
4344
}
4445

45-
public ISayHello1 GetISayHello1()
46-
{
47-
return this;
48-
}
49-
50-
public void GetISayHello2(out ISayHello2 hello2)
51-
{
52-
hello2 = this;
53-
}
54-
55-
public ISayHello1 GetNoSayHello(out ISayHello2 hello2)
56-
{
57-
hello2 = null;
58-
return null;
59-
}
60-
61-
public ISayHello1 [] GetISayHello1Array()
62-
{
63-
return new[] { this };
64-
}
65-
6646
public interface IPublic
6747
{
6848
}

src/testing/subclasstest.cs

+3-14
Original file line numberDiff line numberDiff line change
@@ -89,24 +89,13 @@ public static string test_bar(IInterfaceTest x, string s, int i)
8989
}
9090

9191
// test instances can be constructed in managed code
92-
public static SubClassTest create_instance(Type t)
93-
{
94-
return (SubClassTest)t.GetConstructor(new Type[] { }).Invoke(new object[] { });
95-
}
96-
97-
public static IInterfaceTest create_instance_interface(Type t)
92+
public static IInterfaceTest create_instance(Type t)
9893
{
9994
return (IInterfaceTest)t.GetConstructor(new Type[] { }).Invoke(new object[] { });
10095
}
10196

102-
// test instances pass through managed code unchanged ...
103-
public static SubClassTest pass_through(SubClassTest s)
104-
{
105-
return s;
106-
}
107-
108-
// ... but the return type is an interface type, objects get wrapped
109-
public static IInterfaceTest pass_through_interface(IInterfaceTest s)
97+
// test instances pass through managed code unchanged
98+
public static IInterfaceTest pass_through(IInterfaceTest s)
11099
{
111100
return s;
112101
}

tests/test_array.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1334,10 +1334,9 @@ def test_special_array_creation():
13341334
assert value[1].__class__ == inst.__class__
13351335
assert value.Length == 2
13361336

1337-
iface_class = ISayHello1(inst).__class__
13381337
value = Array[ISayHello1]([inst, inst])
1339-
assert value[0].__class__ == iface_class
1340-
assert value[1].__class__ == iface_class
1338+
assert value[0].__class__ == inst.__class__
1339+
assert value[1].__class__ == inst.__class__
13411340
assert value.Length == 2
13421341

13431342
inst = System.Exception("badness")

tests/test_generic.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ def test_generic_method_type_handling():
318318
assert_generic_method_by_type(ShortEnum, ShortEnum.Zero)
319319
assert_generic_method_by_type(System.Object, InterfaceTest())
320320
assert_generic_method_by_type(InterfaceTest, InterfaceTest(), 1)
321+
assert_generic_method_by_type(ISayHello1, InterfaceTest(), 1)
321322

322323

323324
def test_correct_overload_selection():
@@ -546,11 +547,10 @@ def test_method_overload_selection_with_generic_types():
546547
value = MethodTest.Overloaded.__overloads__[vtype](input_)
547548
assert value.value.__class__ == inst.__class__
548549

549-
iface_class = ISayHello1(inst).__class__
550550
vtype = GenericWrapper[ISayHello1]
551551
input_ = vtype(inst)
552552
value = MethodTest.Overloaded.__overloads__[vtype](input_)
553-
assert value.value.__class__ == iface_class
553+
assert value.value.__class__ == inst.__class__
554554

555555
vtype = System.Array[GenericWrapper[int]]
556556
input_ = vtype([GenericWrapper[int](0), GenericWrapper[int](1)])
@@ -725,12 +725,11 @@ def test_overload_selection_with_arrays_of_generic_types():
725725
assert value[0].value.__class__ == inst.__class__
726726
assert value.Length == 2
727727

728-
iface_class = ISayHello1(inst).__class__
729728
gtype = GenericWrapper[ISayHello1]
730729
vtype = System.Array[gtype]
731730
input_ = vtype([gtype(inst), gtype(inst)])
732731
value = MethodTest.Overloaded.__overloads__[vtype](input_)
733-
assert value[0].value.__class__ == iface_class
732+
assert value[0].value.__class__ == inst.__class__
734733
assert value.Length == 2
735734

736735

tests/test_interface.py

-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ def test_explicit_cast_to_interface():
6161
assert hasattr(i1, 'SayHello')
6262
assert i1.SayHello() == 'hello 1'
6363
assert not hasattr(i1, 'HelloProperty')
64-
assert i1.__implementation__ == ob
65-
assert i1.__raw_implementation__ == ob
6664

6765
i2 = Test.ISayHello2(ob)
6866
assert type(i2).__name__ == 'ISayHello2'

tests/test_method.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -564,10 +564,8 @@ def test_explicit_overload_selection():
564564
value = MethodTest.Overloaded.__overloads__[InterfaceTest](inst)
565565
assert value.__class__ == inst.__class__
566566

567-
iface_class = ISayHello1(InterfaceTest()).__class__
568567
value = MethodTest.Overloaded.__overloads__[ISayHello1](inst)
569-
assert value.__class__ != inst.__class__
570-
assert value.__class__ == iface_class
568+
assert value.__class__ == inst.__class__
571569

572570
atype = Array[System.Object]
573571
value = MethodTest.Overloaded.__overloads__[str, int, atype](
@@ -720,12 +718,11 @@ def test_overload_selection_with_array_types():
720718
assert value[0].__class__ == inst.__class__
721719
assert value[1].__class__ == inst.__class__
722720

723-
iface_class = ISayHello1(inst).__class__
724721
vtype = Array[ISayHello1]
725722
input_ = vtype([inst, inst])
726723
value = MethodTest.Overloaded.__overloads__[vtype](input_)
727-
assert value[0].__class__ == iface_class
728-
assert value[1].__class__ == iface_class
724+
assert value[0].__class__ == inst.__class__
725+
assert value[1].__class__ == inst.__class__
729726

730727

731728
def test_explicit_overload_selection_failure():

tests/test_subclass.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,8 @@ def test_interface():
112112
assert ob.bar("bar", 2) == "bar/bar"
113113
assert FunctionsTest.test_bar(ob, "bar", 2) == "bar/bar"
114114

115-
# pass_through will convert from InterfaceTestClass -> IInterfaceTest,
116-
# causing a new wrapper object to be created. Hence id will differ.
117-
x = FunctionsTest.pass_through_interface(ob)
118-
assert id(x) != id(ob)
115+
x = FunctionsTest.pass_through(ob)
116+
assert id(x) == id(ob)
119117

120118

121119
def test_derived_class():
@@ -188,14 +186,14 @@ def test_create_instance():
188186
assert id(x) == id(ob)
189187

190188
InterfaceTestClass = interface_test_class_fixture(test_create_instance.__name__)
191-
ob2 = FunctionsTest.create_instance_interface(InterfaceTestClass)
189+
ob2 = FunctionsTest.create_instance(InterfaceTestClass)
192190
assert ob2.foo() == "InterfaceTestClass"
193191
assert FunctionsTest.test_foo(ob2) == "InterfaceTestClass"
194192
assert ob2.bar("bar", 2) == "bar/bar"
195193
assert FunctionsTest.test_bar(ob2, "bar", 2) == "bar/bar"
196194

197-
y = FunctionsTest.pass_through_interface(ob2)
198-
assert id(y) != id(ob2)
195+
y = FunctionsTest.pass_through(ob2)
196+
assert id(y) == id(ob2)
199197

200198

201199
def test_events():

0 commit comments

Comments
 (0)