private static void EmitNullableToNullableConversion(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked) { Label labIfNull = default(Label); Label labEnd = default(Label); LocalBuilder locFrom = null; LocalBuilder locTo = null; locFrom = ilGenerator.DeclareLocal(typeFrom); ilGenerator.Emit(OpCodes.Stloc, locFrom); locTo = ilGenerator.DeclareLocal(typeTo); // test for null ilGenerator.Emit(OpCodes.Ldloca, locFrom); ilGenerator.EmitHasValue(typeFrom); labIfNull = ilGenerator.DefineLabel(); ilGenerator.Emit(OpCodes.Brfalse_S, labIfNull); ilGenerator.Emit(OpCodes.Ldloca, locFrom); ilGenerator.EmitGetValueOrDefault(typeFrom); Type nnTypeFrom = TypeInfoUtils.GetNonNullableType(typeFrom); Type nnTypeTo = TypeInfoUtils.GetNonNullableType(typeTo); ilGenerator.EmitConvertToType(nnTypeFrom, nnTypeTo, isChecked); // construct result type ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo }); ilGenerator.Emit(OpCodes.Newobj, ci); ilGenerator.Emit(OpCodes.Stloc, locTo); labEnd = ilGenerator.DefineLabel(); ilGenerator.Emit(OpCodes.Br_S, labEnd); // if null then create a default one ilGenerator.MarkLabel(labIfNull); ilGenerator.Emit(OpCodes.Ldloca, locTo); ilGenerator.Emit(OpCodes.Initobj, typeTo); ilGenerator.MarkLabel(labEnd); ilGenerator.Emit(OpCodes.Ldloc, locTo); }
public static void EmitConvertToType(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked = true) { if (ilGenerator == null) { throw new ArgumentNullException(nameof(ilGenerator)); } if (typeFrom == null) { throw new ArgumentNullException(nameof(typeFrom)); } if (typeTo == null) { throw new ArgumentNullException(nameof(typeTo)); } var typeFromInfo = typeFrom; var typeToInfo = typeTo; var nnExprType = typeFromInfo.GetNonNullableType(); var nnType = typeToInfo.GetNonNullableType(); if (TypeInfoUtils.AreEquivalent(typeFromInfo, typeToInfo)) { return; } if (typeFromInfo.IsInterface || // interface cast typeToInfo.IsInterface || typeFrom == typeof(object) || // boxing cast typeTo == typeof(object) || typeFrom == typeof(System.Enum) || typeFrom == typeof(System.ValueType) || TypeInfoUtils.IsLegalExplicitVariantDelegateConversion(typeFromInfo, typeToInfo)) { ilGenerator.EmitCastToType(typeFromInfo, typeToInfo); } else if (typeFromInfo.IsNullableType() || typeToInfo.IsNullableType()) { ilGenerator.EmitNullableConversion(typeFromInfo, typeToInfo, isChecked); } else if (!(typeFromInfo.IsConvertible() && typeToInfo.IsConvertible()) // primitive runtime conversion && (nnExprType.IsAssignableFrom(nnType) || // down cast nnType.IsAssignableFrom(nnExprType))) // up cast { ilGenerator.EmitCastToType(typeFromInfo, typeToInfo); } else if (typeFromInfo.IsArray && typeToInfo.IsArray) { // See DevDiv Bugs #94657. ilGenerator.EmitCastToType(typeFromInfo, typeToInfo); } else { ilGenerator.EmitNumericConversion(typeFromInfo, typeToInfo, isChecked); } }
private static void EmitNullableToNonNullableStructConversion(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked) { LocalBuilder locFrom = null; locFrom = ilGenerator.DeclareLocal(typeFrom); ilGenerator.Emit(OpCodes.Stloc, locFrom); ilGenerator.Emit(OpCodes.Ldloca, locFrom); ilGenerator.EmitGetValue(typeFrom); Type nnTypeFrom = TypeInfoUtils.GetNonNullableType(typeFrom); ilGenerator.EmitConvertToType(nnTypeFrom, typeTo, isChecked); }
private static void EmitNonNullableToNullableConversion(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked) { LocalBuilder locTo = null; locTo = ilGenerator.DeclareLocal(typeTo); Type nnTypeTo = TypeInfoUtils.GetNonNullableType(typeTo); ilGenerator.EmitConvertToType(typeFrom, nnTypeTo, isChecked); ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo }); ilGenerator.Emit(OpCodes.Newobj, ci); ilGenerator.Emit(OpCodes.Stloc, locTo); ilGenerator.Emit(OpCodes.Ldloc, locTo); }
private static void EmitNullableConversion(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked) { bool isTypeFromNullable = TypeInfoUtils.IsNullableType(typeFrom); bool isTypeToNullable = TypeInfoUtils.IsNullableType(typeTo); if (isTypeFromNullable && isTypeToNullable) { ilGenerator.EmitNullableToNullableConversion(typeFrom, typeTo, isChecked); } else if (isTypeFromNullable) { ilGenerator.EmitNullableToNonNullableConversion(typeFrom, typeTo, isChecked); } else { ilGenerator.EmitNonNullableToNullableConversion(typeFrom, typeTo, isChecked); } }
internal static bool HasReferenceConversion(Type source, Type dest) { // void -> void conversion is handled elsewhere // (it's an identity conversion) // All other void conversions are disallowed. if (source == typeof(void) || dest == typeof(void)) { return(false); } var nnSourceType = TypeInfoUtils.GetNonNullableType(source); var nnDestType = TypeInfoUtils.GetNonNullableType(dest); // Down conversion if (nnSourceType.IsAssignableFrom(nnDestType)) { return(true); } // Up conversion if (nnDestType.IsAssignableFrom(nnSourceType)) { return(true); } // Interface conversion if (source.IsInterface || dest.IsInterface) { return(true); } // Variant delegate conversion if (IsLegalExplicitVariantDelegateConversion(source, dest)) { return(true); } // Object conversion if (source == typeof(object) || dest == typeof(object)) { return(true); } return(false); }
private static void EmitNumericConversion(this ILGenerator ilGenerator, Type typeFrom, Type typeTo, bool isChecked) { bool isFromUnsigned = TypeInfoUtils.IsUnsigned(typeFrom); bool isFromFloatingPoint = TypeInfoUtils.IsFloatingPoint(typeFrom); if (typeTo == typeof(Single)) { if (isFromUnsigned) { ilGenerator.Emit(OpCodes.Conv_R_Un); } ilGenerator.Emit(OpCodes.Conv_R4); } else if (typeTo == typeof(Double)) { if (isFromUnsigned) { ilGenerator.Emit(OpCodes.Conv_R_Un); } ilGenerator.Emit(OpCodes.Conv_R8); } else { TypeCode tc = Type.GetTypeCode(typeTo); if (isChecked) { // Overflow checking needs to know if the source value on the IL stack is unsigned or not. if (isFromUnsigned) { switch (tc) { case TypeCode.SByte: ilGenerator.Emit(OpCodes.Conv_Ovf_I1_Un); break; case TypeCode.Int16: ilGenerator.Emit(OpCodes.Conv_Ovf_I2_Un); break; case TypeCode.Int32: ilGenerator.Emit(OpCodes.Conv_Ovf_I4_Un); break; case TypeCode.Int64: ilGenerator.Emit(OpCodes.Conv_Ovf_I8_Un); break; case TypeCode.Byte: ilGenerator.Emit(OpCodes.Conv_Ovf_U1_Un); break; case TypeCode.UInt16: case TypeCode.Char: ilGenerator.Emit(OpCodes.Conv_Ovf_U2_Un); break; case TypeCode.UInt32: ilGenerator.Emit(OpCodes.Conv_Ovf_U4_Un); break; case TypeCode.UInt64: ilGenerator.Emit(OpCodes.Conv_Ovf_U8_Un); break; default: throw new InvalidCastException(); } } else { switch (tc) { case TypeCode.SByte: ilGenerator.Emit(OpCodes.Conv_Ovf_I1); break; case TypeCode.Int16: ilGenerator.Emit(OpCodes.Conv_Ovf_I2); break; case TypeCode.Int32: ilGenerator.Emit(OpCodes.Conv_Ovf_I4); break; case TypeCode.Int64: ilGenerator.Emit(OpCodes.Conv_Ovf_I8); break; case TypeCode.Byte: ilGenerator.Emit(OpCodes.Conv_Ovf_U1); break; case TypeCode.UInt16: case TypeCode.Char: ilGenerator.Emit(OpCodes.Conv_Ovf_U2); break; case TypeCode.UInt32: ilGenerator.Emit(OpCodes.Conv_Ovf_U4); break; case TypeCode.UInt64: ilGenerator.Emit(OpCodes.Conv_Ovf_U8); break; default: throw new InvalidCastException(); } } } else { switch (tc) { case TypeCode.SByte: ilGenerator.Emit(OpCodes.Conv_I1); break; case TypeCode.Byte: ilGenerator.Emit(OpCodes.Conv_U1); break; case TypeCode.Int16: ilGenerator.Emit(OpCodes.Conv_I2); break; case TypeCode.UInt16: case TypeCode.Char: ilGenerator.Emit(OpCodes.Conv_U2); break; case TypeCode.Int32: ilGenerator.Emit(OpCodes.Conv_I4); break; case TypeCode.UInt32: ilGenerator.Emit(OpCodes.Conv_U4); break; case TypeCode.Int64: if (isFromUnsigned) { ilGenerator.Emit(OpCodes.Conv_U8); } else { ilGenerator.Emit(OpCodes.Conv_I8); } break; case TypeCode.UInt64: if (isFromUnsigned || isFromFloatingPoint) { ilGenerator.Emit(OpCodes.Conv_U8); } else { ilGenerator.Emit(OpCodes.Conv_I8); } break; default: throw new InvalidCastException(); } } } }