📄 convert.cs
字号:
//// conversion.cs: various routines for implementing conversions.//// Authors:// Miguel de Icaza (miguel@ximian.com)// Ravi Pratap (ravi@ximian.com)//// (C) 2001, 2002, 2003 Ximian, Inc.//namespace Mono.CSharp { using System; using System.Collections; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; // // A container class for all the conversion operations // public class Convert { // // This is used to prettify the code: a null argument is allowed // for ImplicitStandardConversion as long as it is known that // no anonymous method will play a role. // // FIXME: renamed from `const' to `static' to allow bootstraping from older // versions of the compiler that could not cope with this construct. // public static EmitContext ConstantEC = null; static EmptyExpression MyEmptyExpr; static public Expression ImplicitReferenceConversion (Expression expr, Type target_type) { Type expr_type = expr.Type; if (expr_type == null && expr.eclass == ExprClass.MethodGroup){ // if we are a method group, emit a warning expr.Emit (null); } if (expr_type == TypeManager.void_type) return null; // // notice that it is possible to write "ValueType v = 1", the ValueType here // is an abstract class, and not really a value type, so we apply the same rules. // if (target_type == TypeManager.object_type) { // // A pointer type cannot be converted to object // if (expr_type.IsPointer) return null; if (expr_type.IsValueType) return new BoxedCast (expr, target_type); if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){ if (expr_type == TypeManager.anonymous_method_type) return null; return new EmptyCast (expr, target_type); } return null; } else if (target_type == TypeManager.value_type) { if (expr_type.IsValueType) return new BoxedCast (expr, target_type); if (expr_type == TypeManager.null_type) return new NullCast ((Constant)expr, target_type); return null; } else if (expr_type.IsSubclassOf (target_type)) { // // Special case: enumeration to System.Enum. // System.Enum is not a value type, it is a class, so we need // a boxing conversion // if (expr_type.IsEnum) return new BoxedCast (expr, target_type); return new EmptyCast (expr, target_type); } // This code is kind of mirrored inside ImplicitStandardConversionExists // with the small distinction that we only probe there // // Always ensure that the code here and there is in sync // from the null type to any reference-type. if (expr_type == TypeManager.null_type){ if (target_type.IsPointer) return new EmptyCast (NullPointer.Null, target_type); if (!target_type.IsValueType) { if (expr is Constant) return new NullCast ((Constant)expr, target_type); // I found only one case when it happens -- Foo () ? null : null; Report.Warning (-100, 1, expr.Location, "The result of the expression is always `null'"); return new NullCast (new NullLiteral (expr.Location), target_type); } } // from any class-type S to any interface-type T. if (target_type.IsInterface) { if (target_type != TypeManager.iconvertible_type && expr_type.IsValueType && (expr is Constant) && !(expr is IntLiteral || expr is BoolLiteral || expr is FloatLiteral || expr is DoubleLiteral || expr is LongLiteral || expr is CharLiteral || expr is StringLiteral || expr is DecimalLiteral || expr is UIntLiteral || expr is ULongLiteral)) { return null; } if (TypeManager.ImplementsInterface (expr_type, target_type)){ if (expr_type.IsClass) return new EmptyCast (expr, target_type); else if (expr_type.IsValueType) return new BoxedCast (expr, target_type); else return new EmptyCast (expr, target_type); } } // from any interface type S to interface-type T. if (expr_type.IsInterface && target_type.IsInterface) { if (TypeManager.ImplementsInterface (expr_type, target_type)) return new EmptyCast (expr, target_type); else return null; } // from an array-type S to an array-type of type T if (expr_type.IsArray && target_type.IsArray) { if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) { Type expr_element_type = TypeManager.GetElementType (expr_type); if (MyEmptyExpr == null) MyEmptyExpr = new EmptyExpression (); MyEmptyExpr.SetType (expr_element_type); Type target_element_type = TypeManager.GetElementType (target_type); if (!expr_element_type.IsValueType && !target_element_type.IsValueType) if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr, target_element_type)) return new EmptyCast (expr, target_type); } } // from an array-type to System.Array if (expr_type.IsArray && target_type == TypeManager.array_type) return new EmptyCast (expr, target_type); // from any delegate type to System.Delegate if ((expr_type == TypeManager.delegate_type || expr_type.IsSubclassOf (TypeManager.delegate_type)) && target_type == TypeManager.delegate_type) return new EmptyCast (expr, target_type); // from any array-type or delegate type into System.ICloneable. if (expr_type.IsArray || expr_type == TypeManager.delegate_type || expr_type.IsSubclassOf (TypeManager.delegate_type)) if (target_type == TypeManager.icloneable_type) return new EmptyCast (expr, target_type); return null; } // // Tests whether an implicit reference conversion exists between expr_type // and target_type // static bool ImplicitReferenceConversionExists (Expression expr, Type target_type) { if (target_type.IsValueType) return false; Type expr_type = expr.Type; // // This is the boxed case. // if (target_type == TypeManager.object_type) { if (expr_type.IsClass || expr_type.IsValueType || expr_type.IsInterface || expr_type == TypeManager.enum_type) if (target_type != TypeManager.anonymous_method_type) return true; return false; } else if (expr_type.IsSubclassOf (target_type)) return true; // Please remember that all code below actually comes // from ImplicitReferenceConversion so make sure code remains in sync // from any class-type S to any interface-type T. if (target_type.IsInterface) { if (target_type != TypeManager.iconvertible_type && expr_type.IsValueType && (expr is Constant) && !(expr is IntLiteral || expr is BoolLiteral || expr is FloatLiteral || expr is DoubleLiteral || expr is LongLiteral || expr is CharLiteral || expr is StringLiteral || expr is DecimalLiteral || expr is UIntLiteral || expr is ULongLiteral)) { return false; } if (TypeManager.ImplementsInterface (expr_type, target_type)) return true; } // from any interface type S to interface-type T. if (expr_type.IsInterface && target_type.IsInterface) if (TypeManager.ImplementsInterface (expr_type, target_type)) return true; // from an array-type S to an array-type of type T if (expr_type.IsArray && target_type.IsArray) { if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) { Type expr_element_type = expr_type.GetElementType (); if (MyEmptyExpr == null) MyEmptyExpr = new EmptyExpression (); MyEmptyExpr.SetType (expr_element_type); Type target_element_type = TypeManager.GetElementType (target_type); if (!expr_element_type.IsValueType && !target_element_type.IsValueType) if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr, target_element_type)) return true; } } // from an array-type to System.Array if (expr_type.IsArray && (target_type == TypeManager.array_type)) return true; // from any delegate type to System.Delegate if ((expr_type == TypeManager.delegate_type || expr_type.IsSubclassOf (TypeManager.delegate_type)) && target_type == TypeManager.delegate_type) if (target_type.IsAssignableFrom (expr_type)) return true; // from any array-type or delegate type into System.ICloneable. if (expr_type.IsArray || expr_type == TypeManager.delegate_type || expr_type.IsSubclassOf (TypeManager.delegate_type)) if (target_type == TypeManager.icloneable_type) return true; // from the null type to any reference-type. if (expr_type == TypeManager.null_type){ if (target_type.IsPointer) return true; if (!target_type.IsValueType) return true; } return false; } /// <summary> /// Implicit Numeric Conversions. /// /// expr is the expression to convert, returns a new expression of type /// target_type or null if an implicit conversion is not possible. /// </summary> static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr, Type target_type) { Type expr_type = expr.Type; // // Attempt to do the implicit constant expression conversions if (expr is Constant){ if (expr is IntConstant){ Expression e; e = TryImplicitIntConversion (target_type, (IntConstant) expr); if (e != null) return e; } else if (expr is LongConstant && target_type == TypeManager.uint64_type){ // // Try the implicit constant expression conversion // from long to ulong, instead of a nice routine, // we just inline it // long v = ((LongConstant) expr).Value; if (v >= 0) return new ULongConstant ((ulong) v, expr.Location); } } Type real_target_type = target_type; if (expr_type == TypeManager.sbyte_type){ // // From sbyte to short, int, long, float, double, decimal // if (real_target_type == TypeManager.int32_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); if (real_target_type == TypeManager.int64_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); if (real_target_type == TypeManager.double_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); if (real_target_type == TypeManager.short_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); if (real_target_type == TypeManager.decimal_type) return new CastToDecimal (expr); } else if (expr_type == TypeManager.byte_type){ // // From byte to short, ushort, int, uint, long, ulong, float, double, decimal // if ((real_target_type == TypeManager.short_type) || (real_target_type == TypeManager.ushort_type) || (real_target_type == TypeManager.int32_type) || (real_target_type == TypeManager.uint32_type)) return new EmptyCast (expr, target_type); if (real_target_type == TypeManager.uint64_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); if (real_target_type == TypeManager.int64_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); if (real_target_type == TypeManager.double_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); if (real_target_type == TypeManager.decimal_type) return new CastToDecimal (expr); } else if (expr_type == TypeManager.short_type){ // // From short to int, long, float, double, decimal // if (real_target_type == TypeManager.int32_type) return new EmptyCast (expr, target_type); if (real_target_type == TypeManager.int64_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); if (real_target_type == TypeManager.double_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); if (real_target_type == TypeManager.decimal_type) return new CastToDecimal (expr); } else if (expr_type == TypeManager.ushort_type){ // // From ushort to int, uint, long, ulong, float, double, decimal // if (real_target_type == TypeManager.uint32_type) return new EmptyCast (expr, target_type); if (real_target_type == TypeManager.uint64_type)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -