From: jpbruyere Date: Tue, 31 Jan 2017 15:00:58 +0000 (+0100) Subject: handle object origType in emitConvert(origType, dstType) X-Git-Tag: v0.9.5-beta~254 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=bb0d50d696c91264601d836d79a76406ca6d9af3;p=jp%2Fcrow.git handle object origType in emitConvert(origType, dstType) --- diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index 31b29fb2..987e0f47 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -475,16 +475,61 @@ namespace Crow il.MarkLabel (endConvert); }else if (origType.IsValueType) { if (destType != origType) { - il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (destType)); + MethodInfo miIO = getImplicitOp (origType, destType); + if (miIO != null) { + System.Reflection.Emit.Label emitCreateDefault = il.DefineLabel (); + System.Reflection.Emit.Label emitContinue = il.DefineLabel (); + LocalBuilder lbStruct = il.DeclareLocal (origType); + il.Emit (OpCodes.Dup); + il.Emit (OpCodes.Brfalse, emitCreateDefault); + il.Emit (OpCodes.Unbox_Any, origType); + il.Emit (OpCodes.Br, emitContinue); + il.MarkLabel (emitCreateDefault); + il.Emit (OpCodes.Pop);//pop null value + il.Emit (OpCodes.Ldloca, lbStruct); + il.Emit (OpCodes.Initobj, origType); + il.Emit (OpCodes.Ldloc, lbStruct); + il.MarkLabel (emitContinue); + il.Emit (OpCodes.Call, miIO); + }else + il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (destType)); }else il.Emit (OpCodes.Unbox_Any, destType);//TODO:double check this } else { - if (origType.IsAssignableFrom(destType)) + if (destType.IsAssignableFrom(origType)) il.Emit (OpCodes.Castclass, destType); else { - MethodInfo miIO = getImplicitOp (origType, destType); - if (miIO != null) - il.Emit (OpCodes.Callvirt, miIO); + //implicit conversion can't be defined from or to object base class, + //so we will check if object underlying type is one of the implicit converter of destType + if (origType == TObject) {//test all implicit converter to destType on obj + System.Reflection.Emit.Label emitTestNextImpOp; + System.Reflection.Emit.Label emitImpOpFound = il.DefineLabel (); + foreach (MethodInfo mi in destType.GetMethods(BindingFlags.Public|BindingFlags.Static)) { + if (mi.Name == "op_Implicit") { + if (mi.GetParameters () [0].ParameterType == destType) + continue; + emitTestNextImpOp = il.DefineLabel (); + il.Emit (OpCodes.Dup); + il.Emit (OpCodes.Isinst, mi.GetParameters () [0].ParameterType); + il.Emit (OpCodes.Brfalse, emitTestNextImpOp); + if (mi.GetParameters () [0].ParameterType.IsValueType) + il.Emit (OpCodes.Unbox_Any, mi.GetParameters () [0].ParameterType); + else + il.Emit (OpCodes.Isinst, mi.GetParameters () [0].ParameterType); + + il.Emit (OpCodes.Call, mi); + il.Emit (OpCodes.Br, emitImpOpFound); + + il.MarkLabel (emitTestNextImpOp); + } + } + //il.Emit (OpCodes.Br, emitImpOpNotFound); + il.MarkLabel (emitImpOpFound); + } else {//search both orig and dest types for implicit operators + MethodInfo miIO = getImplicitOp (origType, destType); + if (miIO != null) + il.Emit (OpCodes.Call, miIO); + } } } }