Skip to content

Commit

Permalink
Fixes issue Sigil#53 by fiddling with assignability check
Browse files Browse the repository at this point in the history
Closes PR #2

Co-authored-by: chaplin89 <chaplin89@gmail.com>
  • Loading branch information
arlm and weddingmm committed Jul 10, 2019
1 parent 7445894 commit b07ea41
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 4 deletions.
12 changes: 8 additions & 4 deletions Sigil/Impl/ExtensionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,12 @@ public static bool IsAssignableFrom(TypeOnStack type1, TypeOnStack type2)
if (type1.IsPointer && type2 == TypeOnStack.Get<NativeIntType>()) return true;
if (type2.IsPointer && type1 == TypeOnStack.Get<NativeIntType>()) return true;

if ((type1.IsPointer || type1.IsReference) && !(type2.IsPointer || type2.IsReference)) return false;
if ((type2.IsPointer || type2.IsReference) && !(type1.IsPointer || type1.IsReference)) return false;
// it's possible to assign a struct* to an interface or object
if(!(type2.IsPointerToValueType && (type1.IsInterface || type1.Type.Equals(typeof(object)))))
{
if((type1.IsPointer || type1.IsReference) && !(type2.IsPointer || type2.IsReference)) return false;
if((type2.IsPointer || type2.IsReference) && !(type1.IsPointer || type1.IsReference)) return false;
}

if (type1.IsPointer || type1.IsReference)
{
Expand Down Expand Up @@ -172,7 +176,7 @@ private static bool ReallyIsAssignableFrom(Type t1, Type t2)
if (t1 == typeof(object) && !TypeHelpers.IsValueType(t2)) return true;

// you have to box in this case
if (t1 == typeof(object) && TypeHelpers.IsValueType(t2)) return false;
if((t1 == typeof(object) || TypeHelpers.IsInterface(t1)) && TypeHelpers.IsValueType(t2)) return false;

var t1Bases = GetBases(t1);
var t2Bases = GetBases(t2);
Expand All @@ -181,7 +185,7 @@ private static bool ReallyIsAssignableFrom(Type t1, Type t2)

if (TypeHelpers.IsInterface(t1))
{
var t2Interfaces = (LinqArray<Type>)t2.GetInterfaces();
var t2Interfaces = t2.IsPointer ? (LinqArray<Type>)t2.GetElementType().GetInterfaces() : (LinqArray<Type>)t2.GetInterfaces();

return t2Interfaces.Any(t2i => TypeOnStack.Get(t1).IsAssignableFrom(TypeOnStack.Get(t2i)));
}
Expand Down
14 changes: 14 additions & 0 deletions Sigil/Impl/TypeOnStack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,27 @@ public static TypeOnStack Get(Type t)
public Type Type { get; private set; }

public bool IsReference { get { return Type.IsByRef; } }

public bool IsPointer { get { return Type.IsPointer; } }

public bool IsArray { get { return Type.IsArray; } }

#if NETSTANDARD1_5
public bool IsPointerToValueType { get { return Type.IsPointer && Type.GetElementType().GetTypeInfo().IsValueType; } }
#else
public bool IsPointerToValueType { get { return Type.IsPointer && Type.GetElementType().IsValueType; } }
#endif

public bool IsInterface { get { return TypeHelpers.IsInterface(Type); } }

public bool HasAttachedMethodInfo { get; private set; }

public CallingConventions CallingConvention { get; private set; }

public Type InstanceType { get; private set; }

public Type ReturnType { get; private set; }

public Type[] ParameterTypes { get; private set; }

public bool IsMarkable { get { return UsedBy != null; } }
Expand Down
38 changes: 38 additions & 0 deletions SigilTests/Calls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,44 @@ public void ValueTypeCall()
Assert.IsFalse(d1(null));
}

[Test]
public void CallInterfaceMethodOnValueTypeAddress()
{
// Issue #53. dispatch interface method to address of value type using constrained callvirt

var equals = typeof(IEquatable<int>).GetMethod("Equals");
var e1 = Emit<Func<int, bool>>.NewDynamicMethod();
e1.LoadArgumentAddress(0);
e1.LoadConstant(1);
e1.CallVirtual(equals, typeof(int));
e1.Return();

var d1 = e1.CreateDelegate();

Assert.IsTrue(d1(1));
Assert.IsFalse(d1(2));
}

[Test]
public void CallObjectMethodOnValueTypeAddress()
{
// Issue #53. dispatch object method to address of value type using constrained callvirt

var equals = typeof(object).GetMethod("Equals", new[] { typeof(object) });
var e1 = Emit<Func<int, bool>>.NewDynamicMethod();
e1.LoadArgumentAddress(0);
e1.LoadConstant(1);
e1.Box<int>();
e1.CallVirtual(equals, typeof(int));
e1.Return();

var d1 = e1.CreateDelegate();

Assert.IsTrue(d1(1));
Assert.IsFalse(d1(2));
}


[Test]
public void MultipleTailcalls()
{
Expand Down

0 comments on commit b07ea41

Please sign in to comment.